mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
* @author dcheryasov
|
||||
*/
|
||||
public interface Callable extends PyTypedElement {
|
||||
public interface Callable extends PyTypedElement, PyQualifiedNameOwner {
|
||||
|
||||
/**
|
||||
* @return a list of parameters passed to this callable, possibly empty.
|
||||
@@ -29,12 +29,4 @@ public interface Callable extends PyTypedElement {
|
||||
*/
|
||||
@Nullable
|
||||
PyFunction asMethod();
|
||||
|
||||
/**
|
||||
* Returns the qualified name of the function.
|
||||
*
|
||||
* @return the qualified name of the function, or null for a lambda expression.
|
||||
*/
|
||||
@Nullable
|
||||
String getQualifiedName();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import com.jetbrains.python.toolbox.Maybe;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -51,4 +53,9 @@ public interface Property {
|
||||
@NotNull
|
||||
Maybe<Callable> getByDirection(@NotNull AccessDirection direction);
|
||||
|
||||
/**
|
||||
* Get the return type of the property getter.
|
||||
*/
|
||||
@Nullable
|
||||
PyType getType(@NotNull TypeEvalContext context);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
* Represents a class declaration in source.
|
||||
*/
|
||||
public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefiner, PyDocStringOwner, StubBasedPsiElement<PyClassStub>,
|
||||
ScopeOwner, PyDecoratable, PyTypedElement {
|
||||
ScopeOwner, PyDecoratable, PyTypedElement, PyQualifiedNameOwner {
|
||||
ArrayFactory<PyClass> ARRAY_FACTORY = new ArrayFactory<PyClass>() {
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -149,9 +149,6 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine
|
||||
|
||||
boolean isSubclass(@NotNull String superClassQName);
|
||||
|
||||
@Nullable
|
||||
String getQualifiedName();
|
||||
|
||||
/**
|
||||
* Returns the list of names in the class' __slots__ attribute, or null if the class
|
||||
* does not define such an attribute.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Base class for elements that have a qualified name (classes and functions).
|
||||
*
|
||||
* @author yole
|
||||
*/
|
||||
public interface PyQualifiedNameOwner extends PyElement {
|
||||
/**
|
||||
* Returns the qualified name of the element.
|
||||
*
|
||||
* @return the qualified name of the element, or null if the element doesn't have a name (for example, it is a lambda expression) or
|
||||
* is contained inside an element that doesn't have a qualified name.
|
||||
*/
|
||||
@Nullable
|
||||
String getQualifiedName();
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package com.jetbrains.python.psi.types;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.StubBasedPsiElement;
|
||||
import com.jetbrains.python.psi.PyTypedElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -158,8 +157,8 @@ public class TypeEvalContext {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean maySwitchToAST(@NotNull StubBasedPsiElement element) {
|
||||
return myAllowStubToAST || (element.getStub() == null && (myOrigin == null || myOrigin == element.getContainingFile()));
|
||||
public boolean maySwitchToAST(@NotNull PsiElement element) {
|
||||
return myAllowStubToAST || myOrigin == element.getContainingFile();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -95,9 +95,6 @@ public class RestConfigurationEditor extends SettingsEditor<RestRunConfiguration
|
||||
return myMainPanel;
|
||||
}
|
||||
|
||||
protected void disposeEditor() {
|
||||
}
|
||||
|
||||
public void setOpenInBrowserVisible(boolean visible) {
|
||||
myOpenInBrowser.setVisible(visible);
|
||||
}
|
||||
|
||||
@@ -680,6 +680,10 @@
|
||||
|
||||
<renamePsiElementProcessor implementation="com.jetbrains.django.refactoring.DjangoStaticPrefixRenameProcessor"/>
|
||||
|
||||
<usageTargetProvider implementation="com.jetbrains.django.refactoring.DjangoUsageTargetProvider"/>
|
||||
<findUsagesHandlerFactory implementation="com.jetbrains.django.refactoring.DjangoFindUsagesHandlerFactory"/>
|
||||
<referencesSearch implementation="com.jetbrains.django.refactoring.DjangoParameterReferenceSearcher"/>
|
||||
|
||||
<!-- App Engine -->
|
||||
<facetType implementation="com.jetbrains.appengine.facet.AppEngineFacetType"/>
|
||||
<framework.detector implementation="com.jetbrains.appengine.facet.AppEngineFrameworkDetector"/>
|
||||
|
||||
@@ -3,13 +3,10 @@ package com.jetbrains.python;
|
||||
import com.intellij.navigation.GotoClassContributor;
|
||||
import com.intellij.navigation.NavigationItem;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubs.StubIndex;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.jetbrains.python.psi.PyClass;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import com.jetbrains.python.psi.impl.PyPresentableElementImpl;
|
||||
import com.jetbrains.python.psi.PyQualifiedNameOwner;
|
||||
import com.jetbrains.python.psi.search.PyProjectScopeBuilder;
|
||||
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
|
||||
import com.jetbrains.python.psi.stubs.PyFunctionNameIndex;
|
||||
@@ -50,17 +47,8 @@ public class PyGotoSymbolContributor implements GotoClassContributor {
|
||||
|
||||
@Override
|
||||
public String getQualifiedName(NavigationItem item) {
|
||||
if (item instanceof PyClass) {
|
||||
return ((PyClass) item).getQualifiedName();
|
||||
}
|
||||
if (item instanceof PyFunction) {
|
||||
PyFunction function = (PyFunction) item;
|
||||
final PyClass containingClass = function.getContainingClass();
|
||||
if (containingClass != null) {
|
||||
return containingClass.getQualifiedName() + "." + function.getName();
|
||||
}
|
||||
PsiFile file = function.getContainingFile();
|
||||
return PyPresentableElementImpl.getPackageForFile(file) + "." + function.getName();
|
||||
if (item instanceof PyQualifiedNameOwner) {
|
||||
return ((PyQualifiedNameOwner) item).getQualifiedName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+32
-6
@@ -42,20 +42,31 @@ public class PyClassNameCompletionContributor extends CompletionContributor {
|
||||
if (parent instanceof PyReferenceExpression && ((PyReferenceExpression)parent).getQualifier() != null) {
|
||||
return;
|
||||
}
|
||||
if (parent instanceof PyStringLiteralExpression) {
|
||||
String prefix = parent.getText().substring(0, parameters.getOffset() - parent.getTextRange().getStartOffset());
|
||||
if (prefix.contains(".")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final FileViewProvider provider = element.getContainingFile().getViewProvider();
|
||||
if (provider instanceof MultiplePsiFilesPerDocumentFileViewProvider) return;
|
||||
if (PsiTreeUtil.getParentOfType(element, PyImportStatementBase.class) != null) {
|
||||
return;
|
||||
}
|
||||
final PsiFile originalFile = parameters.getOriginalFile();
|
||||
addVariantsFromIndex(result, originalFile, PyClassNameIndex.KEY, IMPORTING_INSERT_HANDLER, Conditions.<PyClass>alwaysTrue());
|
||||
addVariantsFromIndex(result, originalFile, PyFunctionNameIndex.KEY, FUNCTION_INSERT_HANDLER, IS_TOPLEVEL);
|
||||
addVariantsFromIndex(result, originalFile, PyVariableNameIndex.KEY, IMPORTING_INSERT_HANDLER, IS_TOPLEVEL);
|
||||
addVariantsFromModules(result, originalFile);
|
||||
addVariantsFromIndex(result, originalFile, PyClassNameIndex.KEY,
|
||||
parent instanceof PyStringLiteralExpression ? STRING_LITERAL_INSERT_HANDLER : IMPORTING_INSERT_HANDLER,
|
||||
Conditions.<PyClass>alwaysTrue());
|
||||
addVariantsFromIndex(result, originalFile, PyFunctionNameIndex.KEY,
|
||||
parent instanceof PyStringLiteralExpression ? STRING_LITERAL_INSERT_HANDLER : FUNCTION_INSERT_HANDLER, IS_TOPLEVEL);
|
||||
addVariantsFromIndex(result, originalFile, PyVariableNameIndex.KEY,
|
||||
parent instanceof PyStringLiteralExpression ? STRING_LITERAL_INSERT_HANDLER : IMPORTING_INSERT_HANDLER,
|
||||
IS_TOPLEVEL);
|
||||
addVariantsFromModules(result, originalFile, parent instanceof PyStringLiteralExpression);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addVariantsFromModules(CompletionResultSet result, PsiFile targetFile) {
|
||||
private static void addVariantsFromModules(CompletionResultSet result, PsiFile targetFile, boolean inStringLiteral) {
|
||||
Collection<VirtualFile> files = FileTypeIndex.getFiles(PythonFileType.INSTANCE, PyProjectScopeBuilder.excludeSdkTestsScope(targetFile));
|
||||
for (VirtualFile file : files) {
|
||||
PsiFile pyFile = targetFile.getManager().findFile(file);
|
||||
@@ -64,7 +75,7 @@ public class PyClassNameCompletionContributor extends CompletionContributor {
|
||||
if (PythonReferenceImporter.isImportableModule(targetFile, importable)) {
|
||||
LookupElementBuilder element = PyModuleType.buildFileLookupElement(importable, null);
|
||||
if (element != null) {
|
||||
result.addElement(element.withInsertHandler(IMPORTING_INSERT_HANDLER));
|
||||
result.addElement(element.withInsertHandler(inStringLiteral ? STRING_LITERAL_INSERT_HANDLER : IMPORTING_INSERT_HANDLER));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,6 +124,21 @@ public class PyClassNameCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
};
|
||||
|
||||
private static final InsertHandler<LookupElement> STRING_LITERAL_INSERT_HANDLER = new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
PsiElement element = item.getPsiElement();
|
||||
if (element instanceof PyQualifiedNameOwner) {
|
||||
String qName = ((PyQualifiedNameOwner) element).getQualifiedName();
|
||||
String name = ((PyQualifiedNameOwner) element).getName();
|
||||
if (qName != null && name != null) {
|
||||
String qNamePrefix = qName.substring(0, qName.length()-name.length());
|
||||
context.getDocument().insertString(context.getStartOffset(), qNamePrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static void addImportForLookupElement(final InsertionContext context, final LookupElement item, final int tailOffset) {
|
||||
PsiDocumentManager manager = PsiDocumentManager.getInstance(context.getProject());
|
||||
Document document = manager.getDocument(context.getFile());
|
||||
|
||||
@@ -66,7 +66,8 @@ public class PyBlockEvaluator {
|
||||
if (currentValue instanceof Map) {
|
||||
Object mapKey = prepareEvaluator().evaluate(indexExpression);
|
||||
if (mapKey != null) {
|
||||
((Map)currentValue).put(mapKey, prepareEvaluator().evaluate(node.getAssignedValue()));
|
||||
Object value = myEvaluateCollectionItems ? prepareEvaluator().evaluate(node.getAssignedValue()) : node.getAssignedValue();
|
||||
((Map)currentValue).put(mapKey, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,6 +691,24 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
mySite = site;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Maybe<Callable> getGetter() {
|
||||
return filterNonStubExpression(myGetter);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Maybe<Callable> getSetter() {
|
||||
return filterNonStubExpression(mySetter);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Maybe<Callable> getDeleter() {
|
||||
return filterNonStubExpression(myDeleter);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
@@ -704,15 +722,29 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
public Maybe<Callable> getByDirection(@NotNull AccessDirection direction) {
|
||||
switch (direction) {
|
||||
case READ:
|
||||
return myGetter;
|
||||
return getGetter();
|
||||
case WRITE:
|
||||
return mySetter;
|
||||
return getSetter();
|
||||
case DELETE:
|
||||
return myDeleter;
|
||||
return getDeleter();
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown direction " + PyUtil.nvl(direction));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PyType getType(@NotNull TypeEvalContext context) {
|
||||
final Callable callable = myGetter.valueOrNull();
|
||||
if (callable != null) {
|
||||
// Ignore return types of non stub-based elements if we are not allowed to use AST
|
||||
if (!(callable instanceof StubBasedPsiElement) && !context.maySwitchToAST(callable)) {
|
||||
return null;
|
||||
}
|
||||
return callable.getReturnType(context, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Maybe<Callable> translate(@Nullable PyExpression expr) {
|
||||
@@ -733,6 +765,17 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
return NONE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Maybe<Callable> filterNonStubExpression(@NotNull Maybe<Callable> maybeCallable) {
|
||||
final Callable callable = maybeCallable.valueOrNull();
|
||||
if (callable != null) {
|
||||
if (!(callable instanceof StubBasedPsiElement)) {
|
||||
return UNKNOWN_CALL;
|
||||
}
|
||||
}
|
||||
return maybeCallable;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "property(" + myGetter + ", " + mySetter + ", " + myDeleter + ", " + myDoc + ")";
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.jetbrains.python.psi.impl.references.PyReferenceImpl;
|
||||
import com.jetbrains.python.psi.resolve.*;
|
||||
import com.jetbrains.python.psi.types.*;
|
||||
import com.jetbrains.python.refactoring.PyDefUseUtil;
|
||||
import com.jetbrains.python.toolbox.Maybe;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -269,10 +268,13 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
|
||||
if (classType.isDefinition()) {
|
||||
return Ref.<PyType>create(PyBuiltinCache.getInstance(pyClass).getObjectType(PyNames.PROPERTY));
|
||||
}
|
||||
final Maybe<Callable> accessor = property.getByDirection(AccessDirection.of(this));
|
||||
final Callable callable = accessor.valueOrNull();
|
||||
final PyType type = (callable != null) ? callable.getReturnType(context, this) : null;
|
||||
return Ref.create(type);
|
||||
if (AccessDirection.of(this) == AccessDirection.READ) {
|
||||
final PyType type = property.getType(context);
|
||||
if (type != null) {
|
||||
return Ref.create(type);
|
||||
}
|
||||
}
|
||||
return Ref.create();
|
||||
}
|
||||
}
|
||||
else if (qualifierType instanceof PyUnionType) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
@@ -24,6 +26,7 @@ import org.intellij.lang.regexp.psi.RegExpGroup;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -304,6 +307,29 @@ public class PyStringLiteralExpressionImpl extends PyElementImpl implements PySt
|
||||
return ReferenceProvidersRegistry.getReferencesFromProviders(this, PsiReferenceService.Hints.NO_HINTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemPresentation getPresentation() {
|
||||
return new ItemPresentation() {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
return getStringValue();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getLocationString() {
|
||||
return "(" + PyPresentableElementImpl.getPackageForFile(getContainingFile()) + ")";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Icon getIcon(boolean unused) {
|
||||
return AllIcons.Nodes.Variable;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public PsiLanguageInjectionHost updateText(@NotNull String text) {
|
||||
// TODO is this the correct implementation? most likely not
|
||||
ASTNode valueNode = getNode().getFirstChildNode();
|
||||
|
||||
@@ -92,9 +92,6 @@ public class PyTestConfigurationEditor extends SettingsEditor<PyTestRunConfigura
|
||||
return myRootPanel;
|
||||
}
|
||||
|
||||
protected void disposeEditor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getAnchor() {
|
||||
return anchor;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
class Shazam:
|
||||
pass
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
x = 'mypackage.Shazam'
|
||||
@@ -0,0 +1 @@
|
||||
x = 'Shaz<caret>'
|
||||
@@ -0,0 +1,3 @@
|
||||
class Shazam:
|
||||
pass
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
x = 'mypackage.<caret>'
|
||||
@@ -19,6 +19,6 @@ class A(object):
|
||||
|
||||
v1 = property(getter, setter)
|
||||
v2 = property(fset=setter, fdel=deleter, fget=getter, doc="doc of v2")
|
||||
v3 = property(lambda self: self._v, None, (deleter))
|
||||
v3 = property(lambda self: 0, None, (deleter))
|
||||
v4 = otherworldly # NOTE: not supported yet
|
||||
v5 = property(v5getter, v5setter)
|
||||
|
||||
@@ -68,6 +68,13 @@ public class PyBlockEvaluatorTest extends PyTestCase {
|
||||
assertEquals("c", map.get("b"));
|
||||
}
|
||||
|
||||
public void testDictAssignNoEvaluate() {
|
||||
PyBlockEvaluator eval = doEvaluate("a={}\na['b']='c'", true);
|
||||
Map map = (Map) eval.getValue("a");
|
||||
assertEquals(1, map.size());
|
||||
assertTrue(map.get("b") instanceof PyStringLiteralExpression);
|
||||
}
|
||||
|
||||
public void testDictUpdate() {
|
||||
PyBlockEvaluator eval = doEvaluate("a={}\na.update({'b': 'c'})");
|
||||
Map map = (Map) eval.getValue("a");
|
||||
|
||||
@@ -42,6 +42,9 @@ public class PyClassNameCompletionTest extends PyTestCase {
|
||||
doTestWithoutFromImport();
|
||||
}
|
||||
|
||||
public void testStringLiteral() { // PY-10526
|
||||
doTest();
|
||||
}
|
||||
private void doTestWithoutFromImport() {
|
||||
final PyCodeInsightSettings settings = PyCodeInsightSettings.getInstance();
|
||||
boolean oldValue = settings.PREFER_FROM_IMPORT;
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.jetbrains.python;
|
||||
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import com.jetbrains.python.toolbox.Maybe;
|
||||
|
||||
public class PyClassicPropertyTest extends PyTestCase {
|
||||
@@ -78,6 +80,9 @@ public class PyClassicPropertyTest extends PyTestCase {
|
||||
accessor = p.getGetter();
|
||||
assertFalse(accessor.isDefined());
|
||||
|
||||
final PyType codeInsightType = p.getType(TypeEvalContext.codeInsightFallback());
|
||||
assertNull(codeInsightType);
|
||||
|
||||
accessor = p.getSetter();
|
||||
assertTrue(accessor.isDefined());
|
||||
assertNull(accessor.value());
|
||||
|
||||
Reference in New Issue
Block a user