From 2548e359d3502b2772e91484ad327bc51594e6d4 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 28 Aug 2012 18:32:47 +0400 Subject: [PATCH 01/24] Fixed unused imports that are used for declaring types in docstrings (PY-7315) --- .../DocStringReferenceProvider.java | 6 ++- .../documentation/DocStringTypeReference.java | 44 +++++++++++----- .../PyUnresolvedReferencesInspection.java | 4 ++ .../python/psi/types/PyTypeParser.java | 50 ++++++++++++------- .../importUsedInDocString.py | 7 +++ .../PyUnresolvedReferencesInspectionTest.java | 5 ++ 6 files changed, 83 insertions(+), 33 deletions(-) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/importUsedInDocString.py diff --git a/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java b/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java index 87bd5e09efe3..7210f6493bbc 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java +++ b/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java @@ -8,6 +8,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ProcessingContext; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.PyDocStringOwner; +import com.jetbrains.python.psi.PyImportElement; import com.jetbrains.python.psi.PyStringLiteralExpression; import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl; import com.jetbrains.python.psi.types.PyType; @@ -85,7 +86,7 @@ public class DocStringReferenceProvider extends PsiReferenceProvider { final PyTypeParser.ParseResult parseResult = PyTypeParser.parse(anchor, s.toString()); final Map types = parseResult.getTypes(); if (types.isEmpty()) { - result.add(new DocStringTypeReference(anchor, s.getTextRange().shiftRight(offset), s.getTextRange().shiftRight(offset), null)); + result.add(new DocStringTypeReference(anchor, s.getTextRange().shiftRight(offset), s.getTextRange().shiftRight(offset), null, null)); } offset = s.getTextRange().getStartOffset() + offset; final Map fullRanges = parseResult.getFullRanges(); @@ -93,7 +94,8 @@ public class DocStringReferenceProvider extends PsiReferenceProvider { final PyType t = pair.getValue(); final TextRange range = pair.getKey().shiftRight(offset); final TextRange fullRange = fullRanges.containsKey(t) ? fullRanges.get(t).shiftRight(offset) : range; - result.add(new DocStringTypeReference(anchor, range, fullRange, t)); + final PyImportElement importElement = parseResult.getImports().get(t); + result.add(new DocStringTypeReference(anchor, range, fullRange, t, importElement)); } return result; } diff --git a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java index f783e274219b..dd96cd82d34a 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java +++ b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java @@ -6,27 +6,33 @@ import com.intellij.psi.*; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.PyImportedModule; import com.jetbrains.python.psi.impl.PyQualifiedName; +import com.jetbrains.python.psi.impl.ResolveResultList; +import com.jetbrains.python.psi.resolve.ImportedResolveResult; import com.jetbrains.python.psi.resolve.QualifiedNameFinder; +import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.types.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** * User : catherine */ -public class DocStringTypeReference extends PsiReferenceBase { - private PyType myType; - private TextRange myFullRange; +public class DocStringTypeReference extends PsiPolyVariantReferenceBase { + @Nullable private PyType myType; + @NotNull private TextRange myFullRange; + @Nullable private final PyImportElement myImportElement; - public DocStringTypeReference(PsiElement element, TextRange range, TextRange fullRange, @Nullable PyType type) { + public DocStringTypeReference(PsiElement element, TextRange range, @NotNull TextRange fullRange, @Nullable PyType type, + @Nullable PyImportElement importElement) { super(element, range); myFullRange = fullRange; myType = type; + myImportElement = importElement; } @Override @@ -49,7 +55,7 @@ public class DocStringTypeReference extends PsiReferenceBase { } public boolean isSoft() { - return true; + return false; } @Override @@ -68,16 +74,28 @@ public class DocStringTypeReference extends PsiReferenceBase { return super.isReferenceTo(element); } - @Nullable - public PsiElement resolve() { + @NotNull + @Override + public ResolveResult[] multiResolve(boolean incompleteCode) { + PsiElement result = null; + final ResolveResultList results = new ResolveResultList(); if (myType instanceof PyClassType) { - return ((PyClassType)myType).getPyClass(); + result = ((PyClassType)myType).getPyClass(); } - if (myType instanceof PyImportedModuleType) { - final PyImportedModule module = ((PyImportedModuleType)myType).getImportedModule(); - return module.resolve(); + else if (myType instanceof PyImportedModuleType) { + result = ((PyImportedModuleType)myType).getImportedModule().resolve(); } - return null; + if (result != null) { + if (myImportElement != null) { + results.add(new ImportedResolveResult(result, + RatedResolveResult.RATE_NORMAL, + Collections.singletonList(myImportElement))); + } + else { + results.poke(result, RatedResolveResult.RATE_NORMAL); + } + } + return results.toArray(new ResolveResult[0]); } @NotNull diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index 219e21aa3459..03dab57430dc 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -39,6 +39,7 @@ import com.jetbrains.python.codeInsight.imports.OptimizeImportsQuickFix; import com.jetbrains.python.codeInsight.imports.PythonReferenceImporter; import com.jetbrains.python.console.PydevConsoleRunner; import com.jetbrains.python.documentation.DocStringParameterReference; +import com.jetbrains.python.documentation.DocStringTypeReference; import com.jetbrains.python.packaging.PyPIPackageUtil; import com.jetbrains.python.packaging.PyPackageManager; import com.jetbrains.python.packaging.PyRequirement; @@ -366,6 +367,9 @@ public class PyUnresolvedReferencesInspection extends PyInspection { private void registerUnresolvedReferenceProblem(@NotNull PyElement node, @NotNull PsiReference reference, @NotNull HighlightSeverity severity) { + if (reference instanceof DocStringTypeReference) { + return; + } String description = null; final String text = reference.getElement().getText(); TextRange rangeInElement = reference.getRangeInElement(); diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java index df2ab49529a9..8636c8dfbd9c 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java @@ -40,19 +40,23 @@ public class PyTypeParser { public static ParseResult parse(@Nullable PsiElement anchor, @NotNull String type) { final Map types = new HashMap(); final Map fullRanges = new HashMap(); - final PyType t = parse(anchor, type, types, fullRanges, 0); - return new ParseResult(t, types, fullRanges); + final Map imports = new HashMap(); + final PyType t = parse(anchor, type, types, fullRanges, imports, 0); + return new ParseResult(t, types, fullRanges, imports); } public static class ParseResult { @Nullable private PyType myType; @NotNull private Map myTypes; @NotNull private Map myFullRanges; + @NotNull private final Map myImports; - ParseResult(@Nullable PyType type, @NotNull Map types, @NotNull Map fullRanges) { + ParseResult(@Nullable PyType type, @NotNull Map types, @NotNull Map fullRanges, + @NotNull Map imports) { myType = type; myTypes = types; myFullRanges = fullRanges; + myImports = imports; } @Nullable @@ -69,11 +73,16 @@ public class PyTypeParser { public Map getFullRanges() { return myFullRanges; } + + @NotNull + public Map getImports() { + return myImports; + } } @Nullable private static PyType parse(@Nullable PsiElement anchor, @NotNull String type, @NotNull Map types, - @NotNull Map fullRanges, int offset) { + @NotNull Map fullRanges, @NotNull Map imports, int offset) { if (anchor == null || !anchor.isValid()) { return null; } @@ -87,10 +96,10 @@ public class PyTypeParser { return t; } if (type.startsWith("(") && type.endsWith(")")) { - return parseTupleType(anchor, type.substring(1, type.length() - 1), types, fullRanges, offset + 1); + return parseTupleType(anchor, type.substring(1, type.length() - 1), types, fullRanges, imports, offset + 1); } if (type.contains(" or ")) { - return parseUnionType(anchor, type, types, fullRanges, offset); + return parseUnionType(anchor, type, types, fullRanges, imports, offset); } final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(anchor); if (type.equals("unknown")) { @@ -132,7 +141,7 @@ public class PyTypeParser { return t; } if (type.startsWith("dict from")) { - return parseDictFromToType(anchor, type, types, fullRanges, offset); + return parseDictFromToType(anchor, type, types, fullRanges, imports, offset); } if (type.equals("integer") || (type.equals("long") && LanguageLevel.forElement(anchor).isPy3K())) { final PyType t = builtinCache.getIntType(); @@ -144,8 +153,8 @@ public class PyTypeParser { } final Matcher m = PARAMETRIZED_CLASS.matcher(type); if (m.matches()) { - final PyType objType = parseObjectType(anchor, m.group(1), builtinCache, types, fullRanges, offset + m.start(1)); - final PyType elementType = parse(anchor, m.group(2), types, fullRanges, offset + m.start(2)); + final PyType objType = parseObjectType(anchor, m.group(1), builtinCache, types, fullRanges, imports, offset + m.start(1)); + final PyType elementType = parse(anchor, m.group(2), types, fullRanges, imports, offset + m.start(2)); if (objType != null) { if (objType instanceof PyClassType && elementType != null) { return new PyCollectionTypeImpl(((PyClassType)objType).getPyClass(), false, elementType); @@ -153,12 +162,13 @@ public class PyTypeParser { return objType; } } - return parseObjectType(anchor, type, builtinCache, types, fullRanges, offset); + return parseObjectType(anchor, type, builtinCache, types, fullRanges, imports, offset); } @Nullable private static PyType parseObjectType(@NotNull PsiElement anchor, @NotNull String type, @NotNull PyBuiltinCache builtinCache, - @NotNull Map types, @NotNull Map fullRanges, int offset) { + @NotNull Map types, @NotNull Map fullRanges, + @NotNull Map imports, int offset) { final TextRange whole = new TextRange(offset, offset + type.length()); final PyClassType classType = builtinCache.getObjectType(type); if (classType != null) { @@ -187,6 +197,7 @@ public class PyTypeParser { final PyType pyType = getTypeFromQName(anchor, qName, whole, unusedRanges, fullRanges, offset); if (pyType != null) { types.put(whole, pyType); + imports.put(pyType, element); return pyType; } } @@ -268,24 +279,26 @@ public class PyTypeParser { @Nullable private static PyType parseTupleType(@NotNull PsiElement anchor, @NotNull String elementTypeNames, @NotNull Map types, - @NotNull Map fullRanges, int offset) { + @NotNull Map fullRanges, @NotNull Map imports, + int offset) { final List ranges = splitRanges(elementTypeNames, ","); final List elementTypes = new ArrayList(); for (TextRange range : ranges) { - elementTypes.add(parse(anchor, range.substring(elementTypeNames), types, fullRanges, offset + range.getStartOffset())); + elementTypes.add(parse(anchor, range.substring(elementTypeNames), types, fullRanges, imports, offset + range.getStartOffset())); } return PyTupleType.create(anchor, elementTypes.toArray(new PyType[elementTypes.size()])); } @Nullable private static PyType parseDictFromToType(@NotNull PsiElement anchor, @NotNull String type, @NotNull Map types, - @NotNull Map fullRanges, int offset) { + @NotNull Map fullRanges, @NotNull Map imports, + int offset) { final Matcher m = DICT_TYPE.matcher(type); PyClassType dict = PyBuiltinCache.getInstance(anchor).getDictType(); if (dict != null) { if (m.matches()) { - PyType from = parse(anchor, m.group(1), types, fullRanges, offset + m.start(1)); - PyType to = parse(anchor, m.group(2), types, fullRanges, offset + m.start(2)); + PyType from = parse(anchor, m.group(1), types, fullRanges, imports, offset + m.start(1)); + PyType to = parse(anchor, m.group(2), types, fullRanges, imports, offset + m.start(2)); final PyType p = PyTupleType.create(anchor, new PyType[] {from, to}); return new PyCollectionTypeImpl(dict.getPyClass(), false, p); } @@ -296,11 +309,12 @@ public class PyTypeParser { @Nullable private static PyType parseUnionType(@NotNull PsiElement anchor, @NotNull String type, @NotNull Map types, - @NotNull Map fullRanges, int offset) { + @NotNull Map fullRanges, @NotNull Map imports, + int offset) { final List ranges = splitRanges(type, " or "); PyType result = null; for (TextRange range : ranges) { - final PyType t = parse(anchor, range.substring(type), types, fullRanges, offset + range.getStartOffset()); + final PyType t = parse(anchor, range.substring(type), types, fullRanges, imports, offset + range.getStartOffset()); result = (result == null) ? t : PyUnionType.union(result, t); } return result; diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/importUsedInDocString.py b/python/testData/inspections/PyUnresolvedReferencesInspection/importUsedInDocString.py new file mode 100644 index 000000000000..af34c174f899 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/importUsedInDocString.py @@ -0,0 +1,7 @@ +from datetime import timedelta #pass + +def f(d): + """ + :type d: timedelta or int + """ + pass diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 49d530b3777f..a5bbed89e7b9 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -185,6 +185,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + // PY-7315 + public void testImportUsedInDocString() { + doTest(); + } + private void doTest() { myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py"); myFixture.enableInspections(PyUnresolvedReferencesInspection.class); From c5945dd05ff74dab3102233b70e79fb3149547f0 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 28 Aug 2012 18:34:13 +0400 Subject: [PATCH 02/24] Nullable --- .../jetbrains/python/documentation/DocStringTypeReference.java | 1 + 1 file changed, 1 insertion(+) diff --git a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java index dd96cd82d34a..c005ced7c2b8 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java +++ b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java @@ -35,6 +35,7 @@ public class DocStringTypeReference extends PsiPolyVariantReferenceBase Date: Tue, 28 Aug 2012 16:44:53 +0200 Subject: [PATCH 03/24] pull up getReference(PyResolveContext) to PyQualifiedReference interface --- .../jetbrains/python/psi/PyQualifiedExpression.java | 6 ++++++ .../jetbrains/python/psi/PyReferenceExpression.java | 3 --- .../python/psi/impl/PyTargetExpressionImpl.java | 10 ++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java index 4c90d5077308..1a2ed465955e 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java @@ -1,6 +1,9 @@ package com.jetbrains.python.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiPolyVariantReference; +import com.jetbrains.python.psi.resolve.PyResolveContext; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -27,4 +30,7 @@ public interface PyQualifiedExpression extends PyExpression { */ @Nullable ASTNode getNameElement(); + + @NotNull + PsiPolyVariantReference getReference(PyResolveContext resolveContext); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java index 1dbfa329f11d..c2a6a3597836 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java @@ -30,7 +30,4 @@ public interface PyReferenceExpression extends PyQualifiedExpression, PyReferenc @NotNull PsiPolyVariantReference getReference(); - - @NotNull - PsiPolyVariantReference getReference(PyResolveContext resolveContext); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index eafcb179fd1f..0a227454c8c1 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -5,6 +5,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; import com.intellij.psi.ResolveResult; import com.intellij.psi.search.GlobalSearchScope; @@ -481,10 +482,15 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl Date: Tue, 28 Aug 2012 16:58:50 +0200 Subject: [PATCH 04/24] a better fix for renaming reassigned things (PY-3698) --- .../codeInsight/PyTargetElementEvaluator.java | 17 ++++++++++------- .../rename/renameReassignedParameter.py | 6 ++++++ .../rename/renameReassignedParameter_after.py | 6 ++++++ .../python/refactoring/PyRenameTest.java | 4 ++++ 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 python/testData/refactoring/rename/renameReassignedParameter.py create mode 100644 python/testData/refactoring/rename/renameReassignedParameter_after.py diff --git a/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java b/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java index 75056b874fce..3f8a7b6ad37a 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java +++ b/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java @@ -6,9 +6,10 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; +import com.jetbrains.python.psi.PyQualifiedExpression; import com.jetbrains.python.psi.PyReferenceExpression; +import com.jetbrains.python.psi.PyTargetExpression; import com.jetbrains.python.psi.resolve.PyResolveContext; -import com.jetbrains.python.psi.resolve.QualifiedResolveResult; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -29,12 +30,14 @@ public class PyTargetElementEvaluator implements TargetElementEvaluator { } final PsiElement element = ref.getElement(); PsiElement result = ref.resolve(); - if (result instanceof PyReferenceExpression && - PsiTreeUtil.getParentOfType(element, ScopeOwner.class) == PsiTreeUtil.getParentOfType(result, ScopeOwner.class)) { - QualifiedResolveResult resolveResult = ((PyReferenceExpression)result).followAssignmentsChain(PyResolveContext.noImplicits()); - PsiElement finalResult = resolveResult.getElement(); - if (PsiTreeUtil.getParentOfType(element, ScopeOwner.class) == PsiTreeUtil.getParentOfType(finalResult, ScopeOwner.class)) { - return finalResult; + while (result instanceof PyReferenceExpression || result instanceof PyTargetExpression) { + PsiElement nextResult = ((PyQualifiedExpression) result).getReference(PyResolveContext.noImplicits()).resolve(); + if (nextResult != null && nextResult != result && PsiTreeUtil.getParentOfType(element, ScopeOwner.class) == + PsiTreeUtil.getParentOfType(result, ScopeOwner.class)) { + result = nextResult; + } + else { + break; } } return result; diff --git a/python/testData/refactoring/rename/renameReassignedParameter.py b/python/testData/refactoring/rename/renameReassignedParameter.py new file mode 100644 index 000000000000..0bcbbb4fb5ef --- /dev/null +++ b/python/testData/refactoring/rename/renameReassignedParameter.py @@ -0,0 +1,6 @@ +def cover(a, lab=1): + item = a + lab + lab = 1 + if a > 1: + lab = cover(item, lab) + return lab \ No newline at end of file diff --git a/python/testData/refactoring/rename/renameReassignedParameter_after.py b/python/testData/refactoring/rename/renameReassignedParameter_after.py new file mode 100644 index 000000000000..cb790d291974 --- /dev/null +++ b/python/testData/refactoring/rename/renameReassignedParameter_after.py @@ -0,0 +1,6 @@ +def cover(a, bar=1): + item = a + bar + bar = 1 + if a > 1: + bar = cover(item, bar) + return bar \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java index 58cf712cfcec..a250d6f73199 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java @@ -91,6 +91,10 @@ public class PyRenameTest extends PyTestCase { doTest("bar"); } + public void testRenameReassignedParameter() { // PY-3698 + doTest("bar"); + } + public void testRenameProperty() { // PY-5948 setLanguageLevel(LanguageLevel.PYTHON26); try { From 4273a29f3550886f5bcf8b52a1031e1fe2d8fd8c Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Tue, 28 Aug 2012 17:38:30 +0200 Subject: [PATCH 05/24] one more original element issue in completion (PY-7327); cleanup --- .../src/com/jetbrains/python/psi/PyUtil.java | 33 +++++-------------- .../impl/references/PyQualifiedReference.java | 2 +- .../testData/completion/dunderClass.after.py | 4 +++ python/testData/completion/dunderClass.py | 4 +++ .../python/PythonCompletionTest.java | 4 +++ 5 files changed, 21 insertions(+), 26 deletions(-) create mode 100644 python/testData/completion/dunderClass.after.py create mode 100644 python/testData/completion/dunderClass.py diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 7cd8ea4f44bc..d9875cf384ad 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -361,23 +361,6 @@ public class PyUtil { return superClasses; } - /** - * Finds the first identifier AST node under target element, and returns its text. - * - * @param target - * @return identifier text, or null. - */ - public static - @Nullable - String getIdentifier(PsiElement target) { - ASTNode node = target.getNode(); - if (node != null) { - ASTNode ident_node = node.findChildByType(PyTokenTypes.IDENTIFIER); - if (ident_node != null) return ident_node.getText(); - } - return null; - } - // TODO: move to a more proper place? @@ -392,16 +375,16 @@ public class PyUtil { if (ref != null) { PyExpression qualifier = ref.getQualifier(); if (qualifier != null) { - String attr_name = getIdentifier(ref); - if ("__class__".equals(attr_name)) { - PyType qual_type = context.getType(qualifier); - if (qual_type instanceof PyClassType) { - return new PyClassTypeImpl(((PyClassType)qual_type).getPyClass(), true); // always as class, never instance + String attr_name = ref.getReferencedName(); + if (PyNames.CLASS.equals(attr_name)) { + PyType qualifierType = context.getType(qualifier); + if (qualifierType instanceof PyClassType) { + return new PyClassTypeImpl(((PyClassType)qualifierType).getPyClass(), true); // always as class, never instance } } - else if ("__dict__".equals(attr_name)) { - PyType qual_type = context.getType(qualifier); - if (qual_type instanceof PyClassType && ((PyClassType)qual_type).isDefinition()) { + else if (PyNames.DICT.equals(attr_name)) { + PyType qualifierType = context.getType(qualifier); + if (qualifierType instanceof PyClassType && ((PyClassType)qualifierType).isDefinition()) { return PyBuiltinCache.getInstance(ref).getDictType(); } } diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java index 87f8239ca70e..a626ffbf1fab 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java @@ -238,7 +238,7 @@ public class PyQualifiedReference extends PyReferenceImpl { @NotNull @Override public Object[] getVariants() { - PyExpression qualifier = myElement.getQualifier(); + PyExpression qualifier = CompletionUtil.getOriginalOrSelf(myElement.getQualifier()); assert qualifier != null; final PyQualifiedExpression element = CompletionUtil.getOriginalOrSelf(myElement); diff --git a/python/testData/completion/dunderClass.after.py b/python/testData/completion/dunderClass.after.py new file mode 100644 index 000000000000..aaaffce5f04b --- /dev/null +++ b/python/testData/completion/dunderClass.after.py @@ -0,0 +1,4 @@ +class Foo(object): + xyzzy = 3 + def fun(self): + a = self.__class__.xyzzy \ No newline at end of file diff --git a/python/testData/completion/dunderClass.py b/python/testData/completion/dunderClass.py new file mode 100644 index 000000000000..4d1a9136ac59 --- /dev/null +++ b/python/testData/completion/dunderClass.py @@ -0,0 +1,4 @@ +class Foo(object): + xyzzy = 3 + def fun(self): + a = self.__class__.x \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index c2c0c3442a11..1b16add43383 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -591,6 +591,10 @@ public class PythonCompletionTest extends PyTestCase { doTest(); } + public void testDunderClass() { // PY-7327 + doTest(); + } + public void testAsInWith() { // PY-3701 setLanguageLevel(LanguageLevel.PYTHON27); assertTrue(doTestByText("with foo ").contains("as")); From 387174914333a9961270218062a46b822f71b8f5 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Tue, 28 Aug 2012 20:46:36 +0400 Subject: [PATCH 06/24] Icons classes generated for every plugin. Those aren't used yet though --- python/helpers/icons/PythonHelpersIcons.java | 14 ++++++++++++++ python/python-helpers.iml | 1 + python/rest/src/icons/RestIcons.java | 13 +++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 python/helpers/icons/PythonHelpersIcons.java create mode 100644 python/rest/src/icons/RestIcons.java diff --git a/python/helpers/icons/PythonHelpersIcons.java b/python/helpers/icons/PythonHelpersIcons.java new file mode 100644 index 000000000000..c80728d8bc73 --- /dev/null +++ b/python/helpers/icons/PythonHelpersIcons.java @@ -0,0 +1,14 @@ +package icons; + +import com.intellij.openapi.util.IconLoader; + +import javax.swing.*; + +/** + * NOTE THIS FILE IS AUTO-GENERATED by the build/scripts/icons.gant + * Don't repeat mistakes of others ;-) + */ +public class PythonHelpersIcons { + public static final Icon Keybd_closed = IconLoader.getIcon("/coverage/htmlfiles/keybd_closed.png"); // 35x12 + public static final Icon Keybd_open = IconLoader.getIcon("/coverage/htmlfiles/keybd_open.png"); // 35x12 +} diff --git a/python/python-helpers.iml b/python/python-helpers.iml index 880a7f9e4113..9d65a5f9a331 100644 --- a/python/python-helpers.iml +++ b/python/python-helpers.iml @@ -7,6 +7,7 @@ + diff --git a/python/rest/src/icons/RestIcons.java b/python/rest/src/icons/RestIcons.java new file mode 100644 index 000000000000..37a8509d1aee --- /dev/null +++ b/python/rest/src/icons/RestIcons.java @@ -0,0 +1,13 @@ +package icons; + +import com.intellij.openapi.util.IconLoader; + +import javax.swing.*; + +/** + * NOTE THIS FILE IS AUTO-GENERATED by the build/scripts/icons.gant + * Don't repeat mistakes of others ;-) + */ +public class RestIcons { + public static final Icon Rst = IconLoader.getIcon("/com/jetbrains/rest/res/rst.png"); // 16x16 +} From 1b709d340714bf967d6d0d7d45d71c008c258022 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Tue, 28 Aug 2012 19:05:58 +0200 Subject: [PATCH 07/24] correct context for completion of 'as' keyword in 'with' (PY-3701) --- .../PyKeywordCompletionContributor.java | 14 +++++++------ .../python/PythonCompletionTest.java | 2 +- .../codeInsight/PyCompletionPatternsTest.java | 20 +++++++++++++------ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java index 7d750beaf938..6888b023c0a8 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java @@ -6,6 +6,7 @@ import com.intellij.codeInsight.lookup.TailTypeDecorator; import com.intellij.lang.ASTNode; import com.intellij.openapi.editor.Document; import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PatternCondition; import com.intellij.patterns.PsiElementPattern; import com.intellij.patterns.StandardPatterns; import com.intellij.psi.*; @@ -229,12 +230,13 @@ public class PyKeywordCompletionContributor extends CompletionContributor { psiElement().withElementType(PyTokenTypes.DOT)) ).inside(PyFromImportStatement.class); - private static final PsiElementPattern.Capture IN_WITH_AFTER_REF = - psiElement().afterLeaf(psiElement() - .withElementType(PyTokenTypes.IDENTIFIER) - .inside(PyReferenceExpression.class) - .inside(PyWithStatement.class) - ); + public static final ElementPattern IN_WITH_AFTER_REF = + psiElement().afterLeaf(psiElement().inside(psiElement(PyWithItem.class).with(new PatternCondition("withoutAsKeyword") { + @Override + public boolean accepts(@NotNull PyWithItem item, ProcessingContext context) { + return item.getNode().findChildByType(PyTokenTypes.AS_KEYWORD) == null; + } + }))); private static final PsiElementPattern.Capture IN_EXCEPT_AFTER_REF = psiElement().afterLeaf(psiElement() diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index 1b16add43383..d19648feefbf 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -597,7 +597,7 @@ public class PythonCompletionTest extends PyTestCase { public void testAsInWith() { // PY-3701 setLanguageLevel(LanguageLevel.PYTHON27); - assertTrue(doTestByText("with foo ").contains("as")); + assertTrue(doTestByText("with open(foo) ").contains("as")); } public void testAsInExcept() { // PY-1846 diff --git a/python/testSrc/com/jetbrains/python/codeInsight/PyCompletionPatternsTest.java b/python/testSrc/com/jetbrains/python/codeInsight/PyCompletionPatternsTest.java index 1e8b95982010..539f6451c727 100644 --- a/python/testSrc/com/jetbrains/python/codeInsight/PyCompletionPatternsTest.java +++ b/python/testSrc/com/jetbrains/python/codeInsight/PyCompletionPatternsTest.java @@ -1,25 +1,33 @@ package com.jetbrains.python.codeInsight; +import com.intellij.patterns.ElementPattern; import com.intellij.psi.PsiElement; import com.jetbrains.python.PythonFileType; import com.jetbrains.python.codeInsight.completion.PyKeywordCompletionContributor; import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.psi.LanguageLevel; /** * @author yole */ public class PyCompletionPatternsTest extends PyTestCase { public void testInFromImportAfterRef() { - String text = "from . im"; - myFixture.configureByText(PythonFileType.INSTANCE, text); - PsiElement element = myFixture.getFile().findElementAt(text.length() - 1); - assertTrue(PyKeywordCompletionContributor.IN_FROM_IMPORT_AFTER_REF.accepts(element)); + assertTrue(doTest("from . im", PyKeywordCompletionContributor.IN_FROM_IMPORT_AFTER_REF)); } public void testAfterQualifier() { - String text = "from . im"; + assertFalse(doTest("from . im", PyKeywordCompletionContributor.AFTER_QUALIFIER)); + } + + public void testWith() { + setLanguageLevel(LanguageLevel.PYTHON27); + assertTrue(doTest("with open(foo) ", PyKeywordCompletionContributor.IN_WITH_AFTER_REF)); + assertFalse(doTest("with open(foo) as ", PyKeywordCompletionContributor.IN_WITH_AFTER_REF)); + } + + private boolean doTest(final String text, final ElementPattern ref) { myFixture.configureByText(PythonFileType.INSTANCE, text); PsiElement element = myFixture.getFile().findElementAt(text.length() - 1); - assertFalse(PyKeywordCompletionContributor.AFTER_QUALIFIER.accepts(element)); + return ref.accepts(element); } } From 4f39f761dc3fd2c41e771669230f649d8a47d01e Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Tue, 28 Aug 2012 19:20:13 +0200 Subject: [PATCH 08/24] Fixed false positive 'Element is not closed' in Django (PY-2837). --- python/src/META-INF/python-plugin-common.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index f4f140dcd059..3920ee02cd5c 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -455,6 +455,7 @@ + From 75f6672dd80be01dc7dbaab8965e9a0b61f653de Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Tue, 28 Aug 2012 20:09:47 +0200 Subject: [PATCH 09/24] more references highlighted as warnings rather than errors (PY-7253) --- .../python/psi/WeakFileReference.java | 44 +++++++++++++++++++ .../TemplateFileReference.java | 17 +++---- 2 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 python/openapi/src/com/jetbrains/python/psi/WeakFileReference.java diff --git a/python/openapi/src/com/jetbrains/python/psi/WeakFileReference.java b/python/openapi/src/com/jetbrains/python/psi/WeakFileReference.java new file mode 100644 index 000000000000..985835e36731 --- /dev/null +++ b/python/openapi/src/com/jetbrains/python/psi/WeakFileReference.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.psi; + +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet; +import com.jetbrains.python.psi.types.TypeEvalContext; +import org.jetbrains.annotations.Nullable; + +/** + * @author yole + */ +public class WeakFileReference extends FileReference implements PsiReferenceEx { + public WeakFileReference(FileReferenceSet fileReferenceSet, TextRange range, int index, String text) { + super(fileReferenceSet, range, index, text); + } + + @Nullable + @Override + public HighlightSeverity getUnresolvedHighlightSeverity(TypeEvalContext context) { + return HighlightSeverity.WARNING; + } + + @Nullable + @Override + public String getUnresolvedDescription() { + return null; + } +} diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateFileReference.java b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateFileReference.java index 3fb97fc94b8e..c924421a2f6c 100644 --- a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateFileReference.java +++ b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateFileReference.java @@ -15,7 +15,6 @@ */ package com.jetbrains.python.templateLanguages; -import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; @@ -26,10 +25,12 @@ import com.intellij.psi.ElementManipulators; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileSystemItem; -import com.intellij.psi.impl.source.resolve.reference.impl.providers.*; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceHelper; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceHelperRegistrar; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.PsiFileSystemItemUtil; import com.intellij.util.IncorrectOperationException; -import com.jetbrains.python.psi.PsiReferenceEx; -import com.jetbrains.python.psi.types.TypeEvalContext; +import com.jetbrains.python.psi.WeakFileReference; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,7 +39,7 @@ import java.util.Collection; /** * @author yole */ -public class TemplateFileReference extends FileReference implements PsiReferenceEx { +public class TemplateFileReference extends WeakFileReference { @NotNull private final FileReferenceSet myReferenceSet; public TemplateFileReference(@NotNull FileReferenceSet fileReferenceSet, TextRange range, int index, String text) { @@ -46,12 +47,6 @@ public class TemplateFileReference extends FileReference implements PsiReference myReferenceSet = fileReferenceSet; } - @Nullable - @Override - public HighlightSeverity getUnresolvedHighlightSeverity(TypeEvalContext context) { - return HighlightSeverity.WARNING; - } - @Nullable @Override public String getUnresolvedDescription() { From 754e30a9b0493765b4d81945aedcb7b31e4eadac Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Tue, 28 Aug 2012 22:40:02 +0200 Subject: [PATCH 10/24] Fixed filtering in TreeClassChooserDialog (IDEA-90723). --- .../python/debugger/PyClassTreeChooserDialog.java | 2 +- .../python/debugger/PyExceptionBreakpointType.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java b/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java index 3bdadd9d57c4..7cbdf33be403 100644 --- a/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java +++ b/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java @@ -20,7 +20,7 @@ public class PyClassTreeChooserDialog extends AbstractTreeClassChooserDialog classFilter, @Nullable PyClass initialClass) { + @Nullable Filter classFilter, @Nullable PyClass initialClass) { super(title, project, scope, classFilter, initialClass); } diff --git a/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointType.java b/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointType.java index e6be68ed9596..97129dba2ace 100644 --- a/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointType.java +++ b/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointType.java @@ -82,10 +82,16 @@ public class PyExceptionBreakpointType return null; } - private static class PyExceptionCachingFilter implements AbstractTreeClassChooserDialog.Filter { + private static class PyExceptionCachingFilter implements AbstractTreeClassChooserDialog.Filter { private final HashMap, Boolean>> processedElements = Maps.newHashMap(); - public boolean isAccepted(@NotNull final PyClass pyClass) { + public boolean isAccepted(@NotNull final Object element) { + if (!(element instanceof PyClass)) { + return false; + } + + PyClass pyClass = (PyClass)element; + final VirtualFile virtualFile = pyClass.getContainingFile().getVirtualFile(); if (virtualFile == null) { return false; From 433442393f935ce079c8138e5c4a24fdf60bab00 Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 29 Aug 2012 09:34:58 +0400 Subject: [PATCH 11/24] compilation fixed --- .../python/debugger/PyClassTreeChooserDialog.java | 8 +++----- .../python/debugger/PyExceptionBreakpointType.java | 10 ++-------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java b/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java index 7cbdf33be403..b681d334cfea 100644 --- a/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java +++ b/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java @@ -17,11 +17,9 @@ import java.util.List; * @author traff */ public class PyClassTreeChooserDialog extends AbstractTreeClassChooserDialog{ - public PyClassTreeChooserDialog(String title, - Project project, - GlobalSearchScope scope, - @Nullable Filter classFilter, @Nullable PyClass initialClass) { - super(title, project, scope, classFilter, initialClass); + public PyClassTreeChooserDialog(String title, Project project, GlobalSearchScope scope, @Nullable Filter classFilter, + @Nullable PyClass initialClass) { + super(title, project, scope, PyClass.class, classFilter, initialClass); } @NotNull diff --git a/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointType.java b/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointType.java index 97129dba2ace..e6be68ed9596 100644 --- a/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointType.java +++ b/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointType.java @@ -82,16 +82,10 @@ public class PyExceptionBreakpointType return null; } - private static class PyExceptionCachingFilter implements AbstractTreeClassChooserDialog.Filter { + private static class PyExceptionCachingFilter implements AbstractTreeClassChooserDialog.Filter { private final HashMap, Boolean>> processedElements = Maps.newHashMap(); - public boolean isAccepted(@NotNull final Object element) { - if (!(element instanceof PyClass)) { - return false; - } - - PyClass pyClass = (PyClass)element; - + public boolean isAccepted(@NotNull final PyClass pyClass) { final VirtualFile virtualFile = pyClass.getContainingFile().getVirtualFile(); if (virtualFile == null) { return false; From 79e0105bf9d8282e73937742a2e8d5e873f1a5b8 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 29 Aug 2012 17:06:17 +0400 Subject: [PATCH 12/24] Fixed find usages of namespace packages and imported elements (PY-7348) --- .../PyFindUsagesHandlerFactory.java | 23 +++++++++++++--- .../findUsages/PyModuleFindUsagesHandler.java | 3 +-- .../python/psi/impl/PyImportElementImpl.java | 7 +---- .../python/psi/impl/PyImportedModule.java | 4 ++- .../psi/impl/references/PyReferenceImpl.java | 21 ++++++++++++--- .../findUsages/NamespacePackageUsages/a.py | 3 +++ .../findUsages/NamespacePackageUsages/b.py | 1 + .../NamespacePackageUsages/nspkg1/m1.py | 0 .../jetbrains/python/PyFindUsagesTest.java | 26 +++++++++++++++++++ .../python/PyMultiFileResolveTest.java | 11 ++------ 10 files changed, 73 insertions(+), 26 deletions(-) create mode 100644 python/testData/findUsages/NamespacePackageUsages/a.py create mode 100644 python/testData/findUsages/NamespacePackageUsages/b.py create mode 100644 python/testData/findUsages/NamespacePackageUsages/nspkg1/m1.py diff --git a/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java b/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java index 934cdab8df82..622c87e3bdb5 100644 --- a/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java +++ b/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java @@ -4,12 +4,16 @@ import com.intellij.find.findUsages.FindUsagesHandler; import com.intellij.find.findUsages.FindUsagesHandlerFactory; import com.intellij.openapi.ui.Messages; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFileSystemItem; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.PyUtil; +import com.jetbrains.python.psi.impl.PyImportedModule; import com.jetbrains.python.psi.search.PySuperMethodsSearch; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -22,14 +26,22 @@ public class PyFindUsagesHandlerFactory extends FindUsagesHandlerFactory { @Override public boolean canFindUsages(@NotNull PsiElement element) { return element instanceof PyClass || - (element instanceof PyFile && PyNames.INIT_DOT_PY.equals(((PyFile) element).getName())) || + (element instanceof PyFile && PyUtil.isPackage((PyFile)element)) || + element instanceof PyImportedModule || element instanceof PyFunction; } + @Nullable @Override public FindUsagesHandler createFindUsagesHandler(@NotNull PsiElement element, boolean forHighlightUsages) { - if (element instanceof PyFile) { - return new PyModuleFindUsagesHandler((PyFile) element); + if (element instanceof PyImportedModule) { + final PsiElement resolved = ((PyImportedModule)element).resolve(); + if (resolved != null) { + element = resolved; + } + } + if (element instanceof PsiFileSystemItem) { + return new PyModuleFindUsagesHandler((PsiFileSystemItem)element); } if (element instanceof PyFunction) { if (!forHighlightUsages) { @@ -60,7 +72,10 @@ public class PyFindUsagesHandlerFactory extends FindUsagesHandlerFactory { } return new PyFunctionFindUsagesHandler(element); } - return new PyClassFindUsagesHandler((PyClass)element); + if (element instanceof PyClass) { + return new PyClassFindUsagesHandler((PyClass)element); + } + return null; } private static boolean isInClassobj(PyFunction fun) { diff --git a/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java b/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java index 61955046dc30..9441948095bb 100644 --- a/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java +++ b/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java @@ -8,7 +8,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFileSystemItem; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; -import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyUtil; import org.jetbrains.annotations.NotNull; @@ -18,7 +17,7 @@ import org.jetbrains.annotations.NotNull; public class PyModuleFindUsagesHandler extends FindUsagesHandler { private final PsiFileSystemItem myElement; - protected PyModuleFindUsagesHandler(@NotNull PyFile file) { + protected PyModuleFindUsagesHandler(@NotNull PsiFileSystemItem file) { super(file); final PsiElement e = PyUtil.turnInitIntoDir(file); myElement = e instanceof PsiFileSystemItem ? (PsiFileSystemItem)e : file; diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java index a82c317016ac..4a387ce3392b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java @@ -4,7 +4,6 @@ import com.intellij.lang.ASTNode; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.stubs.IStubElementType; @@ -202,11 +201,7 @@ public class PyImportElementImpl extends PyBaseElementImpl } if (qName.getComponentCount() == 1) { if (resolveImportElement) { - final PsiElement element = ResolveImportUtil.resolveImportElement(this, PyQualifiedName.fromComponents(name)); - if (element instanceof PsiDirectory) { - return createImportedModule(name); - } - return element; + return ResolveImportUtil.resolveImportElement(this, PyQualifiedName.fromComponents(name)); } return this; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java b/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java index 1716ce244be2..38b8ade0769b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java @@ -134,7 +134,9 @@ public class PyImportedModule extends LightElement implements NameDefiner { @Nullable private static PsiElement resolve(PyImportElement importElement, @NotNull final PyQualifiedName prefix) { - return PyUtil.turnDirIntoInit(ResolveImportUtil.resolveImportElement(importElement, prefix)); + final PsiElement resolved = ResolveImportUtil.resolveImportElement(importElement, prefix); + final PsiElement packageInit = PyUtil.turnDirIntoInit(resolved); + return packageInit != null ? packageInit : resolved; } public boolean isAncestorOf(PyImportedModule other) { diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java index 18a343707758..c1225399e0b8 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -241,7 +241,10 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference for (PsiElement hit : processor.getDefiners()) { ret.poke(hit, getRate(hit)); } - uexpr = PyUtil.turnDirIntoInit(uexpr); // an import statement may have returned a dir + final PsiElement packageInit = PyUtil.turnDirIntoInit(uexpr); + if (packageInit != null) { + uexpr = packageInit; // an import statement may have returned a dir + } } else if (!processor.getDefiners().isEmpty()) { ret.add(new ImportedResolveResult(null, RatedResolveResult.RATE_LOW, processor.getDefiners())); @@ -396,9 +399,19 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference if (resolveResult instanceof PyImportedModule) { resolveResult = resolveResult.getNavigationElement(); } - if (element instanceof PsiDirectory && resolveResult instanceof PyFile && - PyNames.INIT_DOT_PY.equals(((PyFile)resolveResult).getName()) && ((PyFile)resolveResult).getContainingDirectory() == element) { - return true; + if (element instanceof PsiDirectory) { + if (resolveResult instanceof PyFile) { + final PyFile file = (PyFile)resolveResult; + if (PyUtil.isPackage(file) && file.getContainingDirectory() == element) { + return true; + } + } + else if (resolveResult instanceof PsiDirectory) { + final PsiDirectory directory = (PsiDirectory)resolveResult; + if (PyUtil.isPackage(directory) && directory == element) { + return true; + } + } } return resolveResult == element; } diff --git a/python/testData/findUsages/NamespacePackageUsages/a.py b/python/testData/findUsages/NamespacePackageUsages/a.py new file mode 100644 index 000000000000..79cdd72a726c --- /dev/null +++ b/python/testData/findUsages/NamespacePackageUsages/a.py @@ -0,0 +1,3 @@ +import nspkg1.m1 + +print(nspkg1) \ No newline at end of file diff --git a/python/testData/findUsages/NamespacePackageUsages/b.py b/python/testData/findUsages/NamespacePackageUsages/b.py new file mode 100644 index 000000000000..9b2491c9488f --- /dev/null +++ b/python/testData/findUsages/NamespacePackageUsages/b.py @@ -0,0 +1 @@ +import nspkg1 \ No newline at end of file diff --git a/python/testData/findUsages/NamespacePackageUsages/nspkg1/m1.py b/python/testData/findUsages/NamespacePackageUsages/nspkg1/m1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java b/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java index 3dad95b96527..956b7867b150 100644 --- a/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java +++ b/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java @@ -1,7 +1,11 @@ package com.jetbrains.python; +import com.intellij.codeInsight.TargetElementUtilBase; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; import com.intellij.usageView.UsageInfo; import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.psi.LanguageLevel; import java.util.*; @@ -111,4 +115,26 @@ public class PyFindUsagesTest extends PyTestCase { "testMethod = staticmethod(testMethod)", "testMethod = staticmethod(testMethod)"); } + + // PY-7348 + public void testNamespacePackageUsages() { + setLanguageLevel(LanguageLevel.PYTHON33); + try { + final Collection usages = findMultiFileUsages("a.py"); + assertEquals(3, usages.size()); + } finally { + setLanguageLevel(null); + } + } + + private Collection findMultiFileUsages(String filename) { + final String testName = getTestName(false); + myFixture.copyDirectoryToProject("findUsages/" + testName, ""); + PsiDocumentManager.getInstance(myFixture.getProject()).commitAllDocuments(); + myFixture.configureFromTempProjectFile(filename); + final int flags = TargetElementUtilBase.ELEMENT_NAME_ACCEPTED | TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED; + final PsiElement element = TargetElementUtilBase.findTargetElement(myFixture.getEditor(), flags); + assertNotNull(element); + return myFixture.findUsages(element); + } } diff --git a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java index 68440e23bb0e..d55cf9c6a58b 100644 --- a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java @@ -9,7 +9,6 @@ import com.jetbrains.cython.psi.CythonFunction; import com.jetbrains.cython.psi.CythonVariable; import com.jetbrains.python.fixtures.PyResolveTestCase; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.PyImportedModule; /** * @author yole @@ -364,10 +363,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase { // PY-2813 public void testNamespacePackage() { - final PsiElement element = doResolve(); - assertInstanceOf(element, PyImportedModule.class); - final PyImportedModule module = (PyImportedModule)element; - assertEquals("p1", module.getImportedPrefix().toString()); + assertResolvesTo(PsiDirectory.class, "p1"); } // PY-2813 @@ -408,10 +404,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase { public void testPython33NamespacePackage() { setLanguageLevel(LanguageLevel.PYTHON33); try { - final PsiElement element = doResolve(); - assertInstanceOf(element, PyImportedModule.class); - final PyImportedModule module = (PyImportedModule)element; - assertEquals("p1", module.getImportedPrefix().toString()); + assertResolvesTo(PsiDirectory.class, "p1"); } finally { setLanguageLevel(null); } From 648008c38daa1ad63c627c675723b7c1a3cc1703 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 29 Aug 2012 15:55:07 +0200 Subject: [PATCH 13/24] to enable user editing, store stdlib properties files outside of jar --- .../codeInsight/stdlib => helpers}/StdlibTypes2.properties | 0 .../codeInsight/stdlib => helpers}/StdlibTypes3.properties | 0 .../python/codeInsight/stdlib/PyStdlibTypeProvider.java | 4 +++- 3 files changed, 3 insertions(+), 1 deletion(-) rename python/{src/com/jetbrains/python/codeInsight/stdlib => helpers}/StdlibTypes2.properties (100%) rename python/{src/com/jetbrains/python/codeInsight/stdlib => helpers}/StdlibTypes3.properties (100%) diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes2.properties b/python/helpers/StdlibTypes2.properties similarity index 100% rename from python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes2.properties rename to python/helpers/StdlibTypes2.properties diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes3.properties b/python/helpers/StdlibTypes3.properties similarity index 100% rename from python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes3.properties rename to python/helpers/StdlibTypes3.properties diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index 1bcda3178fcf..4e03bd564f9e 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -5,6 +5,7 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.jetbrains.python.PyNames; +import com.jetbrains.python.PythonHelpersLocator; import com.jetbrains.python.documentation.StructuredDocString; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; @@ -15,6 +16,7 @@ import com.jetbrains.python.psi.types.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Map; @@ -249,7 +251,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { final String name = level.isPy3K() ? "StdlibTypes3" : "StdlibTypes2"; if (result.isEmpty()) { try { - final InputStream s = getClass().getResourceAsStream(String.format("%s.properties", name)); + final InputStream s = new FileInputStream(PythonHelpersLocator.getHelperFile(String.format("%s.properties", name))); try { result.load(s); } From 4ecfdfcdc0a6ca88a5aabcf6acb300622b6bbda3 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 29 Aug 2012 18:13:13 +0400 Subject: [PATCH 14/24] More diagnostics for PIEAE in parsing types from docstrings for EA-38697 --- .../jetbrains/python/psi/types/PyTypeParser.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java index 8636c8dfbd9c..cbf8b5f28891 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java @@ -180,6 +180,7 @@ public class PyTypeParser { final PyClass aClass = ((PyFile)anchorFile).findTopLevelClass(type); if (aClass != null) { final PyType t = new PyClassTypeImpl(aClass, false); + t.assertValid("PyFile.findTopLevelClass()"); types.put(whole, t); return t; } @@ -210,6 +211,7 @@ public class PyTypeParser { final Collection classes = PyClassNameIndex.find(type, anchor.getProject(), true); if (classes.size() == 1) { final PyType t = new PyClassTypeImpl(classes.iterator().next(), false); + t.assertValid("PyClassNameIndex.find().iterator().next()"); types.put(whole, t); return t; } @@ -248,9 +250,12 @@ public class PyTypeParser { if (t instanceof PyClassType) { t = ((PyClassType)t).toInstance(); } - types.put(classRange.shiftRight(offset), t); - fullRanges.put(t, whole); - return t; + if (t != null) { + t.assertValid("PyImportedModuleType.resolveMember()"); + types.put(classRange.shiftRight(offset), t); + fullRanges.put(t, whole); + return t; + } } } } @@ -258,6 +263,7 @@ public class PyTypeParser { for (PyClass aClass : classes) { if (qName.equals(aClass.getQualifiedName())) { final PyType t = new PyClassTypeImpl(aClass, false); + t.assertValid("PyClassNameIndex.find()"); types.put(classRange.shiftRight(offset), t); fullRanges.put(t, whole); return t; @@ -268,6 +274,7 @@ public class PyTypeParser { final String name = aClass.getQualifiedName(); if (name != null && name.startsWith("_")) { final PyType t = new PyClassTypeImpl(aClass, false); + t.assertValid("PyClassNameIndex.find() for _foo"); types.put(classRange.shiftRight(offset), t); fullRanges.put(t, whole); return t; From 69ca3b7d91d8ae0b55f1bb75dd69be9f56c55f6f Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 29 Aug 2012 19:57:39 +0200 Subject: [PATCH 15/24] avoid completing statements in function name (PY-5567) --- .../completion/PyKeywordCompletionContributor.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java index 6888b023c0a8..ac303b484ffb 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java @@ -51,12 +51,12 @@ public class PyKeywordCompletionContributor extends CompletionContributor { final ASTNode ctxNode = context.getNode(); if (ctxNode != null && PyTokenTypes.STRING_NODES.contains(ctxNode.getElementType())) return false; // no sense inside string PsiElement p = (PsiElement)element; - int first_offset = p.getTextOffset(); + int firstOffset = p.getTextRange().getStartOffset(); // we must be a stmt ourselves, not a part of another stmt // try to climb to the stmt level with the same offset while (true) { if (p == null) return false; - if (p.getTextOffset() != first_offset) return false; + if (p.getTextRange().getStartOffset() != firstOffset) return false; if (p instanceof PyStatement) break; p = p.getParent(); } @@ -73,7 +73,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor { PsiDocumentManager docMgr = PsiDocumentManager.getInstance(p.getProject()); Document doc = docMgr.getDocument(p.getContainingFile().getOriginalFile()); if (doc != null) { - if (doc.getLineNumber(prev.getTextRange().getEndOffset()) == doc.getLineNumber(first_offset)) { + if (doc.getLineNumber(prev.getTextRange().getEndOffset()) == doc.getLineNumber(firstOffset)) { return false; // same line } } @@ -215,6 +215,9 @@ public class PyKeywordCompletionContributor extends CompletionContributor { private static final PsiElementPattern.Capture IN_STRING_LITERAL = psiElement().inside(PyStringLiteralExpression.class); + private static final PsiElementPattern.Capture IN_FUNCTION_HEADER = + psiElement().inside(PyFunction.class).andNot(psiElement().inside(PyStatementList.class)); + public static final PsiElementPattern.Capture AFTER_QUALIFIER = psiElement().afterLeaf(psiElement().withText(".").inside(PyReferenceExpression.class)); @@ -511,6 +514,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor { .andNot(IN_COMMENT) .andNot(IN_IMPORT_STMT) .andNot(IN_PARAM_LIST) + .andNot(IN_FUNCTION_HEADER) .andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL) , new PyKeywordCompletionProvider("not", "lambda") @@ -526,6 +530,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor { .andNot(IN_IMPORT_STMT) .and(NOT_PARAMETER_OR_DEFAULT_VALUE) .andNot(AFTER_QUALIFIER) + .andNot(IN_FUNCTION_HEADER) , new PyKeywordCompletionProvider(TailType.NONE, "True", "False", "None") ); From 5992da665fee3bcfb3b439144d65e3de9e043239 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 29 Aug 2012 20:24:16 +0200 Subject: [PATCH 16/24] allow specifying local paths in Settings | External Documentation (PY-7335) --- .../documentation/PythonDocumentationProvider.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index 25623b87c981..12b81ea4f41d 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -36,6 +36,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.HashMap; @@ -385,16 +386,22 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i } private static boolean pageExists(String url) { + if (new File(url).exists()) { + return true; + } HttpClient client = new HttpClient(); client.setTimeout(5 * 1000); client.setConnectionTimeout(5 * 1000); - HeadMethod method = new HeadMethod(url); try { + HeadMethod method = new HeadMethod(url); int rc = client.executeMethod(method); if (rc == 404) { return false; } } + catch (IllegalArgumentException e) { + return false; + } catch (IOException ignored) { } return true; From a2eb93c0c8cb72f7888ad2912a79fb791aab11a4 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 29 Aug 2012 20:40:47 +0200 Subject: [PATCH 17/24] don't jump to function when looking for rename target (PY-7342) --- .../python/codeInsight/PyTargetElementEvaluator.java | 6 ++++-- .../testData/refactoring/rename/renameShadowingVariable.py | 3 +++ .../refactoring/rename/renameShadowingVariable_after.py | 3 +++ .../com/jetbrains/python/refactoring/PyRenameTest.java | 4 ++++ 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 python/testData/refactoring/rename/renameShadowingVariable.py create mode 100644 python/testData/refactoring/rename/renameShadowingVariable_after.py diff --git a/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java b/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java index 3f8a7b6ad37a..3c24ee89fe3e 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java +++ b/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java @@ -6,6 +6,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; +import com.jetbrains.python.psi.PyParameter; import com.jetbrains.python.psi.PyQualifiedExpression; import com.jetbrains.python.psi.PyReferenceExpression; import com.jetbrains.python.psi.PyTargetExpression; @@ -32,8 +33,9 @@ public class PyTargetElementEvaluator implements TargetElementEvaluator { PsiElement result = ref.resolve(); while (result instanceof PyReferenceExpression || result instanceof PyTargetExpression) { PsiElement nextResult = ((PyQualifiedExpression) result).getReference(PyResolveContext.noImplicits()).resolve(); - if (nextResult != null && nextResult != result && PsiTreeUtil.getParentOfType(element, ScopeOwner.class) == - PsiTreeUtil.getParentOfType(result, ScopeOwner.class)) { + if (nextResult != null && nextResult != result && + PsiTreeUtil.getParentOfType(element, ScopeOwner.class) == PsiTreeUtil.getParentOfType(result, ScopeOwner.class) && + (nextResult instanceof PyReferenceExpression || nextResult instanceof PyTargetExpression || nextResult instanceof PyParameter)) { result = nextResult; } else { diff --git a/python/testData/refactoring/rename/renameShadowingVariable.py b/python/testData/refactoring/rename/renameShadowingVariable.py new file mode 100644 index 000000000000..bc7946d9ec3c --- /dev/null +++ b/python/testData/refactoring/rename/renameShadowingVariable.py @@ -0,0 +1,3 @@ +def lab(): pass +lab = 1 +print(lab) diff --git a/python/testData/refactoring/rename/renameShadowingVariable_after.py b/python/testData/refactoring/rename/renameShadowingVariable_after.py new file mode 100644 index 000000000000..1f26476ab745 --- /dev/null +++ b/python/testData/refactoring/rename/renameShadowingVariable_after.py @@ -0,0 +1,3 @@ +def lab(): pass +bar = 1 +print(bar) diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java index a250d6f73199..ca5e06eb7be7 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java @@ -95,6 +95,10 @@ public class PyRenameTest extends PyTestCase { doTest("bar"); } + public void testRenameShadowingVariable() { // PY-7342 + doTest("bar"); + } + public void testRenameProperty() { // PY-5948 setLanguageLevel(LanguageLevel.PYTHON26); try { From 4b46f3aa8607c3e3c3064f1928ba6ef5022d111d Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Wed, 29 Aug 2012 16:10:59 +0200 Subject: [PATCH 18/24] Fixed NPE. --- python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java b/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java index 64b22c1785ae..ccbf403fdc40 100644 --- a/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java +++ b/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java @@ -199,7 +199,7 @@ public class PySkeletonGenerator { return new ListBinariesResult(generatorVersion, binaries); } - public boolean deleteOrLog(File item) { + public boolean deleteOrLog(@NotNull File item) { boolean deleted = item.delete(); if (!deleted) LOG.warn("Failed to delete skeleton file " + item.getAbsolutePath()); return deleted; From 347588680e2c7addf56d8f9a22bde8cd16610e8c Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Wed, 29 Aug 2012 16:18:10 +0200 Subject: [PATCH 19/24] Fixed CME. --- .../src/com/jetbrains/python/debugger/PyDebugProcess.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index 2210d8a59b32..46cdc7480740 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -38,10 +38,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.net.ServerSocket; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import static javax.swing.SwingUtilities.invokeLater; @@ -61,7 +58,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr private final Map> myRegisteredExceptionBreakpoints = new ConcurrentHashMap>(); - private final List mySuspendedThreads = Lists.newArrayList(); + private final List mySuspendedThreads = Collections.synchronizedList(Lists.newArrayList()); private final Map myStackFrameCache = Maps.newHashMap(); private final Map myNewVariableValue = Maps.newHashMap(); From f6b5bea310a509c14779101b3ae5122ae4c4e1ed Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Wed, 29 Aug 2012 19:48:30 +0200 Subject: [PATCH 20/24] Fixed IOOBE. --- .../python/buildout/BuildoutFacet.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/python/src/com/jetbrains/python/buildout/BuildoutFacet.java b/python/src/com/jetbrains/python/buildout/BuildoutFacet.java index de5a2ddab2bc..fecbb9ffa70e 100644 --- a/python/src/com/jetbrains/python/buildout/BuildoutFacet.java +++ b/python/src/com/jetbrains/python/buildout/BuildoutFacet.java @@ -97,6 +97,7 @@ public class BuildoutFacet extends Facet implements /** * Generates a sys.path[0:0] = [...] with paths that buildout script wants. + * * @param module to get a buildout facet from * @return the statement, or null if there's no buildout facet. */ @@ -158,7 +159,7 @@ public class BuildoutFacet extends Facet implements } return paths; } - catch(IOException e) { + catch (IOException e) { LOG.info(e); return null; } @@ -208,18 +209,20 @@ public class BuildoutFacet extends Facet implements String text = VfsUtil.loadText(vFile); String[] lines = LineTokenizer.tokenize(text, false); int index = 0; - while(index < lines.length && !lines [index].startsWith("def addsitepackages(")) + while (index < lines.length && !lines[index].startsWith("def addsitepackages(")) { index++; - while(index < lines.length && !lines [index].trim().startsWith("buildout_paths = [")) + } + while (index < lines.length && !lines[index].trim().startsWith("buildout_paths = [")) { index++; + } index++; - while(index < lines.length && !lines [index].trim().equals("]")) { - String line = lines [index].trim(); + while (index < lines.length && !lines[index].trim().equals("]")) { + String line = lines[index].trim(); if (line.endsWith(",")) { - line = line.substring(0, line.length()-1); + line = line.substring(0, line.length() - 1); } if (line.startsWith("'") && line.endsWith("'")) { - result.add(StringUtil.unescapeStringCharacters(line.substring(1, line.length()-1))); + result.add(StringUtil.unescapeStringCharacters(line.substring(1, line.length() - 1))); } index++; } @@ -243,10 +246,12 @@ public class BuildoutFacet extends Facet implements // alter execution script ParamsGroup script_params = params.getParamsGroup(PythonCommandLineState.GROUP_SCRIPT); assert script_params != null; - String normal_script = script_params.getParameters().get(0); // expect DjangoUtil.MANAGE_FILE - String engulfer_path = PythonHelpersLocator.getHelperPath("pycharm/buildout_engulfer.py"); - new_env.put("PYCHARM_ENGULF_SCRIPT", getConfiguration().getScriptName()); - script_params.getParametersList().replaceOrPrepend(normal_script, engulfer_path); + if (script_params.getParameters().size() > 0) { + String normal_script = script_params.getParameters().get(0); // expect DjangoUtil.MANAGE_FILE + String engulfer_path = PythonHelpersLocator.getHelperPath("pycharm/buildout_engulfer.py"); + new_env.put("PYCHARM_ENGULF_SCRIPT", getConfiguration().getScriptName()); + script_params.getParametersList().replaceOrPrepend(normal_script, engulfer_path); + } // add pycharm helpers to pythonpath so that fixGetpass is importable PythonEnvUtil.addToPythonPath(new_env, PythonHelpersLocator.getHelpersRoot().getAbsolutePath()); @@ -280,7 +285,7 @@ public class BuildoutFacet extends Facet implements String text = FileUtil.loadFile(cfg); final PsiFile configFile = PsiFileFactory .getInstance(getModule().getProject()).createFileFromText("buildout.cfg", - BuildoutCfgLanguage.INSTANCE, text); + BuildoutCfgLanguage.INSTANCE, text); if (configFile != null && configFile instanceof BuildoutCfgFile) { return (BuildoutCfgFile)configFile; } @@ -290,7 +295,7 @@ public class BuildoutFacet extends Facet implements } return null; } - + public static List getScripts(@Nullable BuildoutFacet buildoutFacet, final VirtualFile baseDir) { File rootPath = null; if (buildoutFacet != null) { From 97b7eb7f5cddc76c6c8ec8e71f4483f5358fb1da Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Wed, 29 Aug 2012 21:02:20 +0200 Subject: [PATCH 21/24] Fixed IOOBE(EA-38501). --- .../debugger/PyDebuggerEditorsProvider.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/python/src/com/jetbrains/python/debugger/PyDebuggerEditorsProvider.java b/python/src/com/jetbrains/python/debugger/PyDebuggerEditorsProvider.java index ba1fc8754f5d..e1b47b2285fa 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebuggerEditorsProvider.java +++ b/python/src/com/jetbrains/python/debugger/PyDebuggerEditorsProvider.java @@ -46,15 +46,17 @@ public class PyDebuggerEditorsProvider extends XDebuggerEditorsProvider { final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); if (psiFile != null) { int offset = sourcePosition.getOffset(); - final int lineEndOffset = document.getLineEndOffset(document.getLineNumber(offset)); - do { - PsiElement element = psiFile.findElementAt(offset); - if (element != null && !(element instanceof PsiWhiteSpace || element instanceof PsiComment)) { - return PyPsiUtils.getStatement(element); + if (offset >= 0 && offset < document.getTextLength()) { + final int lineEndOffset = document.getLineEndOffset(document.getLineNumber(offset)); + do { + PsiElement element = psiFile.findElementAt(offset); + if (element != null && !(element instanceof PsiWhiteSpace || element instanceof PsiComment)) { + return PyPsiUtils.getStatement(element); + } + offset = element.getTextRange().getEndOffset() + 1; } - offset = element.getTextRange().getEndOffset() + 1; + while (offset < lineEndOffset); } - while (offset < lineEndOffset); } } return null; From 1d7e20946dea141a1f57609db4ed3d76bebf1ebc Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Wed, 29 Aug 2012 21:06:51 +0200 Subject: [PATCH 22/24] Fixed CCE (EA-38206). --- .../jetbrains/python/debugger/PySignatureCacheManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java b/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java index 009811ab0b2d..ac51515a5e33 100644 --- a/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java +++ b/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java @@ -141,7 +141,7 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { try { data = CALL_SIGNATURES_ATTRIBUTE.readAttributeBytes(file); } - catch (IOException e) { + catch (Exception e) { data = null; } From ec23357a572798bb948fb75535a54669a4f39215 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Wed, 29 Aug 2012 21:10:03 +0200 Subject: [PATCH 23/24] Don't log interruption here, as it happens and it's ok (EA-36726). --- .../com/jetbrains/python/console/PydevConsoleCommunication.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java index 61e65cae5f51..e7dbfd93992b 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java @@ -221,7 +221,7 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl lock.wait(10); } catch (InterruptedException e) { - LOG.error(e); + //pass } } } From cfbe5ac14e2b92458cbddf381dfce78d32c28488 Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 30 Aug 2012 10:47:50 +0400 Subject: [PATCH 24/24] redundant imports removed --- .../buildout/config/BuildoutCfgProblemFileHighlightFilter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/python/src/com/jetbrains/python/buildout/config/BuildoutCfgProblemFileHighlightFilter.java b/python/src/com/jetbrains/python/buildout/config/BuildoutCfgProblemFileHighlightFilter.java index 41b1afb7455b..ae20d7b4f65a 100644 --- a/python/src/com/jetbrains/python/buildout/config/BuildoutCfgProblemFileHighlightFilter.java +++ b/python/src/com/jetbrains/python/buildout/config/BuildoutCfgProblemFileHighlightFilter.java @@ -1,7 +1,6 @@ package com.jetbrains.python.buildout.config; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile;