From 92ea4119eca205f2decaaf22edb9eb37fc576057 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 1 Aug 2012 13:58:20 +0400 Subject: [PATCH 1/6] Removed unused code --- .../python/psi/impl/PyClassImpl.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index e184ee2f41b0..3e0197025ddb 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -2,7 +2,6 @@ package com.jetbrains.python.psi.impl; import com.intellij.codeInsight.completion.CompletionUtil; import com.intellij.lang.ASTNode; -import com.intellij.openapi.util.Key; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -899,27 +898,6 @@ public class PyClassImpl extends PyPresentableElementImpl implement } } } - else if (anchor != null) { - PyResolveUtil.scopeCrawlUp(new PsiScopeProcessor() { - @Override - public boolean execute(@NotNull PsiElement element, ResolveState state) { - if (element instanceof PyAssignmentStatement) { - collectNewTargets(result, (PyAssignmentStatement)element); - } - return true; - } - - @Nullable - @Override - public T getHint(@NotNull Key hintKey) { - return null; - } - - @Override - public void handleEvent(Event event, @Nullable Object associated) { - } - }, anchor, null, method); - } else { final PyStatementList statementList = method.getStatementList(); if (statementList != null) { From e9486b3d563116c8410a750b7a0257cbd6fa2062 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 1 Aug 2012 17:42:56 +0400 Subject: [PATCH 2/6] Fixed false positive in unreachable code inspection for 'break' inside 'else' in nested for loop (PY-6062) --- .../python/psi/impl/PyBreakStatementImpl.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyBreakStatementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBreakStatementImpl.java index c63d9fe14fa6..947c165ce927 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBreakStatementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBreakStatementImpl.java @@ -1,10 +1,10 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; -import com.jetbrains.python.psi.PyBreakStatement; -import com.jetbrains.python.psi.PyElementVisitor; -import com.jetbrains.python.psi.PyLoopStatement; +import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -22,6 +22,19 @@ public class PyBreakStatementImpl extends PyElementImpl implements PyBreakStatem @Nullable public PyLoopStatement getLoopStatement() { - return PsiTreeUtil.getParentOfType(this, PyLoopStatement.class); + return getLoopStatement(this); + } + + @Nullable + private static PyLoopStatement getLoopStatement(@NotNull PsiElement element) { + final PyLoopStatement loop = PsiTreeUtil.getParentOfType(element, PyLoopStatement.class); + if (loop instanceof PyForStatement) { + final PyForStatement forLoop = (PyForStatement)loop; + final PyElsePart elsePart = forLoop.getElsePart(); + if (PsiTreeUtil.isAncestor(elsePart, element, true)) { + return getLoopStatement(loop); + } + } + return loop; } } From dcc91730f139e7b1ea27b79c01afc87e6c5116ab Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 2 Aug 2012 13:56:58 +0400 Subject: [PATCH 3/6] Cleanup --- .../python/psi/impl/PyClassImpl.java | 14 +++++----- .../python/psi/types/PyClassType.java | 26 ++++++++----------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 3e0197025ddb..402a22dd51b4 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -869,12 +869,12 @@ public class PyClassImpl extends PyPresentableElementImpl implement // __init__ takes priority over all other methods PyFunctionImpl initMethod = (PyFunctionImpl)findMethodByName(PyNames.INIT, false); if (initMethod != null) { - collectInstanceAttributes(initMethod, result, null); + collectInstanceAttributes(initMethod, result); } final PyFunction[] methods = getMethods(); for (PyFunction method : methods) { if (!PyNames.INIT.equals(method.getName())) { - collectInstanceAttributes(method, result, null); + collectInstanceAttributes(method, result); } } @@ -882,9 +882,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement return new ArrayList(expressions); } - private static void collectInstanceAttributes(@NotNull PyFunction method, - @NotNull final Map result, - @Nullable PsiElement anchor) { + private static void collectInstanceAttributes(@NotNull PyFunction method, @NotNull final Map result) { final PyParameter[] params = method.getParameterList().getParameters(); if (params.length == 0) { return; @@ -969,7 +967,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement processor.execute(this, ResolveState.initial()); } - public boolean processClassLevelDeclarations(PsiScopeProcessor processor) { + public boolean processClassLevelDeclarations(@NotNull PsiScopeProcessor processor) { final PyClassStub stub = getStub(); if (stub != null) { final List children = stub.getChildrenStubs(); @@ -985,12 +983,12 @@ public class PyClassImpl extends PyPresentableElementImpl implement return true; } - public boolean processInstanceLevelDeclarations(PsiScopeProcessor processor, @Nullable PyExpression location) { + public boolean processInstanceLevelDeclarations(@NotNull PsiScopeProcessor processor, @Nullable PyExpression location) { Map declarationsInMethod = new HashMap(); PyFunction instanceMethod = PsiTreeUtil.getParentOfType(location, PyFunction.class); final PyClass containingClass = instanceMethod != null ? instanceMethod.getContainingClass() : null; if (instanceMethod != null && containingClass != null && CompletionUtil.getOriginalElement(containingClass) == this) { - collectInstanceAttributes(instanceMethod, declarationsInMethod, location); + collectInstanceAttributes(instanceMethod, declarationsInMethod); for (PyTargetExpression targetExpression : declarationsInMethod.values()) { if (!processor.execute(targetExpression, ResolveState.initial())) { return false; diff --git a/python/src/com/jetbrains/python/psi/types/PyClassType.java b/python/src/com/jetbrains/python/psi/types/PyClassType.java index e73bac12ed7b..9b46b1658247 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassType.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassType.java @@ -112,10 +112,10 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { } @Nullable - private List doResolveMember(String name, - PyExpression location, - AccessDirection direction, - PyResolveContext resolveContext) { + private List doResolveMember(@NotNull String name, + @Nullable PyExpression location, + @NotNull AccessDirection direction, + @NotNull PyResolveContext resolveContext) { if (myClass == null) { return null; } @@ -159,7 +159,7 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { } } - PsiElement classMember = resolveClassMember(this, name, location); + PsiElement classMember = resolveClassMember(myClass, name, location); if (classMember != null) { return ResolveResultList.to(classMember); } @@ -167,7 +167,7 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { for (PyClassRef superClass : myClass.iterateAncestors()) { final PyClass pyClass = superClass.getPyClass(); if (pyClass != null) { - PsiElement superMember = resolveClassMember(new PyClassType(pyClass, isDefinition()), name, null); + PsiElement superMember = resolveClassMember(pyClass, name, null); if (superMember != null) { return ResolveResultList.to(superMember); } @@ -243,8 +243,8 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { } @Nullable - private static PsiElement resolveClassMember(PyClassType aClass, String name, @Nullable PyExpression location) { - PsiElement result = resolveInner(aClass.getPyClass(), name, location); + private static PsiElement resolveClassMember(@NotNull PyClass cls, @NotNull String name, @Nullable PyExpression location) { + PsiElement result = resolveInner(cls, name, location); if (result != null) { return result; } @@ -263,12 +263,12 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { } @Nullable - private static PsiElement resolveInner(PyClass aClass, String name, @Nullable PyExpression location) { + private static PsiElement resolveInner(@NotNull PyClass cls, @NotNull String name, @Nullable PyExpression location) { ResolveProcessor processor = new ResolveProcessor(name); - ((PyClassImpl)aClass).processDeclarations(processor, location); // our members are strictly within us. + ((PyClassImpl)cls).processDeclarations(processor, location); // our members are strictly within us. final PsiElement resolveResult = processor.getResult(); //final PsiElement resolveResult = PyResolveUtil.treeWalkUp(new PyResolveUtil.ResolveProcessor(name), myClass, null, null); - if (resolveResult != null && resolveResult != aClass) { + if (resolveResult != null && resolveResult != cls) { return resolveResult; } return null; @@ -477,8 +477,4 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { public boolean isValid() { return myClass == null || myClass.isValid(); } - - public static PyClassType fromClassName(String typeName, Project project) { - return new PyClassType(project, typeName, false); - } } From 3cf5776291b538c3cd8b22c88d8d82563ec5d3db Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 2 Aug 2012 18:55:29 +0400 Subject: [PATCH 4/6] Fixed resolve for class and instance attributes with the same name (PY-7040) --- .../src/com/jetbrains/python/psi/PyClass.java | 4 ++ .../python/psi/impl/PyClassImpl.java | 8 +-- .../psi/impl/references/PyReferenceImpl.java | 60 +++++++++++-------- .../python/psi/types/PyClassType.java | 33 +++++----- .../jetbrains/python/PyFindUsagesTest.java | 2 +- .../com/jetbrains/python/PyTypeTest.java | 11 ++++ 6 files changed, 70 insertions(+), 48 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/PyClass.java b/python/src/com/jetbrains/python/psi/PyClass.java index 7b4d5723b406..a6f74c55a253 100644 --- a/python/src/com/jetbrains/python/psi/PyClass.java +++ b/python/src/com/jetbrains/python/psi/PyClass.java @@ -4,6 +4,7 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.StubBasedPsiElement; +import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.util.ArrayFactory; import com.intellij.util.Processor; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; @@ -161,4 +162,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine @Nullable String getDocStringValue(); + + boolean processClassLevelDeclarations(@NotNull PsiScopeProcessor processor); + boolean processInstanceLevelDeclarations(@NotNull PsiScopeProcessor processor, @Nullable PyExpression location); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 402a22dd51b4..684efcb4d99e 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -961,12 +961,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement return false; } - public void processDeclarations(@NotNull PsiScopeProcessor processor, @Nullable PyExpression location) { - if (!processClassLevelDeclarations(processor)) return; - if (!processInstanceLevelDeclarations(processor, location)) return; - processor.execute(this, ResolveState.initial()); - } - + @Override public boolean processClassLevelDeclarations(@NotNull PsiScopeProcessor processor) { final PyClassStub stub = getStub(); if (stub != null) { @@ -983,6 +978,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement return true; } + @Override public boolean processInstanceLevelDeclarations(@NotNull PsiScopeProcessor processor, @Nullable PyExpression location) { Map declarationsInMethod = new HashMap(); PyFunction instanceMethod = PsiTreeUtil.getParentOfType(location, PyFunction.class); 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 7369d4aa42ef..efea18425acb 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -402,35 +402,45 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference } if (element instanceof PsiNamedElement) { final String elementName = ((PsiNamedElement)element).getName(); - if ((Comparing.equal(myElement.getReferencedName(), elementName) || PyNames.INIT.equals(elementName)) && !haveQualifiers(element)) { - // Global elements may in fact be resolved to their outer declarations - if (isGlobal(element, elementName)) { - element = transitiveResolve(element); - } - final ScopeOwner ourScopeOwner = ScopeUtil.getScopeOwner(getElement()); - final ScopeOwner theirScopeOwner = ScopeUtil.getScopeOwner(element); - // TODO: Cython-dependent code without CythonLanguageDialect.isInsideCythonFile() check - if (element instanceof PyParameter || element instanceof PyTargetExpression || element instanceof CythonVariable) { - // Check if the reference is in the same or inner scope of the element scope, not shadowed by an intermediate declaration - if (resolvesToSameLocal(element, elementName, ourScopeOwner, theirScopeOwner)) { + if ((Comparing.equal(myElement.getReferencedName(), elementName) || PyNames.INIT.equals(elementName))) { + if (!haveQualifiers(element)) { + // Global elements may in fact be resolved to their outer declarations + if (isGlobal(element, elementName)) { + element = transitiveResolve(element); + } + final ScopeOwner ourScopeOwner = ScopeUtil.getScopeOwner(getElement()); + final ScopeOwner theirScopeOwner = ScopeUtil.getScopeOwner(element); + // TODO: Cython-dependent code without CythonLanguageDialect.isInsideCythonFile() check + if (element instanceof PyParameter || element instanceof PyTargetExpression || element instanceof CythonVariable) { + // Check if the reference is in the same or inner scope of the element scope, not shadowed by an intermediate declaration + if (resolvesToSameLocal(element, elementName, ourScopeOwner, theirScopeOwner)) { + return true; + } + } + + final PsiElement resolveResult = (isGlobal(getElement(), elementName)) ? transitiveResolve(getElement()) : resolve(); + if (resolveResult == element) { + return true; + } + + if (!haveQualifiers(element) && ourScopeOwner != null && theirScopeOwner != null) { + if (resolvesToSameGlobal(element, elementName, ourScopeOwner, theirScopeOwner, resolveResult)) return true; + } + + if (resolvesToWrapper(element, resolveResult)) { return true; } } - - final PsiElement resolveResult = (isGlobal(getElement(), elementName)) ? transitiveResolve(getElement()) : resolve(); - if (resolveResult == element) { - return true; + if (element instanceof PyExpression) { + final PyExpression expr = (PyExpression)element; + if (PyUtil.isClassAttribute(myElement) && (PyUtil.isClassAttribute(expr) || PyUtil.isInstanceAttribute(expr))) { + final PyClass c1 = PsiTreeUtil.getParentOfType(element, PyClass.class); + final PyClass c2 = PsiTreeUtil.getParentOfType(myElement, PyClass.class); + if (c1 != null && c2 != null && (c1.isSubclass(c2) || c2.isSubclass(c1))) { + return true; + } + } } - - if (!haveQualifiers(element) && ourScopeOwner != null && theirScopeOwner != null) { - if (resolvesToSameGlobal(element, elementName, ourScopeOwner, theirScopeOwner, resolveResult)) return true; - } - - if (resolvesToWrapper(element, resolveResult)) { - return true; - } - - return false; // TODO: handle multi-resolve } } return false; diff --git a/python/src/com/jetbrains/python/psi/types/PyClassType.java b/python/src/com/jetbrains/python/psi/types/PyClassType.java index 9b46b1658247..487ad3fd8989 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassType.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassType.java @@ -19,7 +19,6 @@ import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.PyDynamicMember; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; -import com.jetbrains.python.psi.impl.PyClassImpl; import com.jetbrains.python.psi.impl.PyTypeProvider; import com.jetbrains.python.psi.impl.ResolveResultList; import com.jetbrains.python.psi.resolve.*; @@ -159,7 +158,7 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { } } - PsiElement classMember = resolveClassMember(myClass, name, location); + PsiElement classMember = resolveClassMember(myClass, myIsDefinition, name, location); if (classMember != null) { return ResolveResultList.to(classMember); } @@ -167,7 +166,7 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { for (PyClassRef superClass : myClass.iterateAncestors()) { final PyClass pyClass = superClass.getPyClass(); if (pyClass != null) { - PsiElement superMember = resolveClassMember(pyClass, name, null); + PsiElement superMember = resolveClassMember(pyClass, myIsDefinition, name, null); if (superMember != null) { return ResolveResultList.to(superMember); } @@ -243,15 +242,17 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { } @Nullable - private static PsiElement resolveClassMember(@NotNull PyClass cls, @NotNull String name, @Nullable PyExpression location) { - PsiElement result = resolveInner(cls, name, location); + private static PsiElement resolveClassMember(@NotNull PyClass cls, + boolean isDefinition, + @NotNull String name, + @Nullable PyExpression location) { + PsiElement result = resolveInner(cls, isDefinition, name, location); if (result != null) { return result; } return null; } - @Nullable private static PsiElement resolveByMembersProviders(PyClassType aClass, String name) { for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { @@ -263,15 +264,15 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { } @Nullable - private static PsiElement resolveInner(@NotNull PyClass cls, @NotNull String name, @Nullable PyExpression location) { - ResolveProcessor processor = new ResolveProcessor(name); - ((PyClassImpl)cls).processDeclarations(processor, location); // our members are strictly within us. - final PsiElement resolveResult = processor.getResult(); - //final PsiElement resolveResult = PyResolveUtil.treeWalkUp(new PyResolveUtil.ResolveProcessor(name), myClass, null, null); - if (resolveResult != null && resolveResult != cls) { - return resolveResult; + private static PsiElement resolveInner(@NotNull PyClass cls, boolean isDefinition, @NotNull String name, @Nullable PyExpression location) { + final ResolveProcessor processor = new ResolveProcessor(name); + if (!isDefinition) { + if (!cls.processInstanceLevelDeclarations(processor, location)) { + return processor.getResult(); + } } - return null; + cls.processClassLevelDeclarations(processor); + return processor.getResult(); } private static Key> CTX_VISITED = Key.create("PyClassType.Visited"); @@ -350,13 +351,13 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType { if (suppressParentheses) { processor.suppressParentheses(); } - ((PyClassImpl)myClass).processClassLevelDeclarations(processor); + myClass.processClassLevelDeclarations(processor); List slots = myClass.isNewStyleClass() ? myClass.getSlots() : null; if (slots != null) { processor.setAllowedNames(slots); } - ((PyClassImpl)myClass).processInstanceLevelDeclarations(processor, expressionHook); + myClass.processInstanceLevelDeclarations(processor, expressionHook); for (LookupElement le : processor.getResultList()) { String name = le.getLookupString(); diff --git a/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java b/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java index d277f3757cb5..3dad95b96527 100644 --- a/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java +++ b/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java @@ -102,7 +102,7 @@ public class PyFindUsagesTest extends PyTestCase { public void testReassignedClassAttribute() { // PY-4338 final Collection usages = myFixture.testFindUsages("findUsages/ReassignedClassAttribute.py"); - assertEquals(5, usages.size()); + assertEquals(6, usages.size()); } public void testWrappedMethod() { // PY-5458 diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java index c62fa668b56c..c732e24cd134 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java @@ -419,6 +419,17 @@ public class PyTypeTest extends PyTestCase { assertNull(type); } + // PY-7040 + public void testInstanceAndClassAttribute() { + doTest("int", + "class C(object):\n" + + " foo = 'str1'\n" + + "\n" + + " def __init__(self):\n" + + " self.foo = 3\n" + + " expr = self.foo\n"); + } + private PyExpression parseExpr(String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); return myFixture.findElementByText("expr", PyExpression.class); From 9570c470b4e618b6ca804a489f58a47e8893737b Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 2 Aug 2012 19:38:27 +0400 Subject: [PATCH 5/6] Fixed IntellijIdeaRulezzz in completion of assignment to instance attribute (PY-7102) --- .../python/psi/impl/references/PyQualifiedReference.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 dccce365d14b..0beb54f45418 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java @@ -241,6 +241,7 @@ public class PyQualifiedReference extends PyReferenceImpl { public Object[] getVariants() { PyExpression qualifier = myElement.getQualifier(); assert qualifier != null; + final PyQualifiedExpression element = CompletionUtil.getOriginalOrSelf(myElement); PyType qualifierType = qualifier.getType(TypeEvalContext.slow()); ProcessingContext ctx = new ProcessingContext(); @@ -270,11 +271,11 @@ public class PyQualifiedReference extends PyReferenceImpl { namesAlready.add(targetExpr.getName()); } } - Collections.addAll(variants, qualifierType.getCompletionVariants(myElement.getName(), myElement, ctx)); + Collections.addAll(variants, qualifierType.getCompletionVariants(element.getName(), element, ctx)); return variants.toArray(); } else { - return qualifierType.getCompletionVariants(myElement.getName(), myElement, ctx); + return qualifierType.getCompletionVariants(element.getName(), element, ctx); } } return getUntypedVariants(); From c06c0b4b32f222c0157d33c3d8c60d7a286332e3 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 2 Aug 2012 20:59:21 +0400 Subject: [PATCH 6/6] Fixed parsing '-' in package names inside requirement URLs (PY-7034) --- .../python/packaging/PyRequirement.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/python/src/com/jetbrains/python/packaging/PyRequirement.java b/python/src/com/jetbrains/python/packaging/PyRequirement.java index da00cd36a72e..95462203829a 100644 --- a/python/src/com/jetbrains/python/packaging/PyRequirement.java +++ b/python/src/com/jetbrains/python/packaging/PyRequirement.java @@ -23,7 +23,6 @@ public class PyRequirement { private static final Pattern VERSION_SPEC = Pattern.compile("\\s*(<=?|>=?|==|!=)\\s*((\\w|[-.])+)"); private static final Pattern EDITABLE_EGG = Pattern.compile("\\s*(-e)?\\s*([^#]*)#egg=(.*)"); private static final Pattern RECURSIVE_REQUIREMENT = Pattern.compile("\\s*-r\\s+(.*)"); - private static final Pattern NAME_VERSION = Pattern.compile("\\s*(\\w(\\w|[.])*)-((\\w|[-.])+)"); public enum Relation { LT("<"), @@ -392,20 +391,23 @@ public class PyRequirement { if (url == null) { return null; } - final Matcher nameVersionMatcher = NAME_VERSION.matcher(egg); - if (nameVersionMatcher.matches()) { - final String name = normalizeName(nameVersionMatcher.group(1)); - final String version = normalizeVersion(nameVersionMatcher.group(3)); - return new PyRequirement(name, version, url, editable); - } - else { - final Matcher nameMatcher = NAME.matcher(egg); - if (!nameMatcher.matches()) { - return null; + boolean isName = true; + final List nameParts = new ArrayList(); + final List versionParts = new ArrayList(); + for (String part : StringUtil.split(egg, "-")) { + if (part.matches("[0-9].*") || "dev".equals(part)) { + isName = false; + } + if (isName) { + nameParts.add(part); + } + else { + versionParts.add(part); } - final String name = normalizeName(nameMatcher.group(1)); - return new PyRequirement(name, null, url, editable); } + final String name = normalizeName(StringUtil.join(nameParts, "-")); + final String version = !versionParts.isEmpty() ? normalizeVersion(StringUtil.join(versionParts, "-")) : null; + return new PyRequirement(name, version, url, editable); } @NotNull