From 8870abb7e9c92d504cc22bfc8aeb8041868bda36 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 7 Mar 2014 18:40:17 +0400 Subject: [PATCH 1/3] Get Python language level from PsiElements where possible instead VirtualFiles --- .../ConvertFormatOperatorToMethodIntention.java | 12 +++++------- .../inspections/PyPropertyDefinitionInspection.java | 11 ++--------- .../PyRaisingNewStyleClassInspection.java | 7 +------ .../PyTupleAssignmentBalanceInspection.java | 4 +--- .../inspections/quickfix/AddFunctionQuickFix.java | 2 +- .../com/jetbrains/python/psi/impl/PyClassImpl.java | 5 +---- .../python/validation/UnsupportedFeatures.java | 13 +------------ 7 files changed, 12 insertions(+), 42 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java index 47c543e5a2a4..e183aae203d4 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java @@ -22,7 +22,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiWhiteSpace; @@ -35,7 +34,10 @@ import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.impl.PyPsiUtils; import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl; -import com.jetbrains.python.psi.types.*; +import com.jetbrains.python.psi.types.PyClassType; +import com.jetbrains.python.psi.types.PyType; +import com.jetbrains.python.psi.types.PyTypeChecker; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -230,11 +232,7 @@ public class ConvertFormatOperatorToMethodIntention extends BaseIntentionAction if (binaryExpression == null) { return false; } - final VirtualFile virtualFile = binaryExpression.getContainingFile().getVirtualFile(); - if (virtualFile == null) { - return false; - } - final LanguageLevel languageLevel = LanguageLevel.forFile(virtualFile); + final LanguageLevel languageLevel = LanguageLevel.forElement(binaryExpression); if (languageLevel.isOlderThan(LanguageLevel.PYTHON26)) { return false; } diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index 27fff5602374..728ee806cd70 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -21,19 +21,18 @@ import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiElementFilter; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.QualifiedName; import com.intellij.util.Processor; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.inspections.quickfix.RenameParameterQuickFix; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; -import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.psi.types.PyClassType; import com.jetbrains.python.psi.types.PyNoneType; import com.jetbrains.python.psi.types.PyType; @@ -79,13 +78,7 @@ public class PyPropertyDefinitionInspection extends PyInspection { super(holder, session); PsiFile psiFile = session.getFile(); // save us continuous checks for level, module, stc - LanguageLevel level = null; - if (psiFile != null) { - VirtualFile vfile = psiFile.getVirtualFile(); - if (vfile != null) level = LanguageLevel.forFile(vfile); - } - if (level == null) level = LanguageLevel.getDefault(); - myLevel = level; + myLevel = LanguageLevel.forElement(psiFile); // string classes final List string_classes = new ArrayList(2); final PyBuiltinCache builtins = PyBuiltinCache.getInstance(psiFile); diff --git a/python/src/com/jetbrains/python/inspections/PyRaisingNewStyleClassInspection.java b/python/src/com/jetbrains/python/inspections/PyRaisingNewStyleClassInspection.java index 40adf777e664..8ff86e966db1 100644 --- a/python/src/com/jetbrains/python/inspections/PyRaisingNewStyleClassInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyRaisingNewStyleClassInspection.java @@ -17,7 +17,6 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.jetbrains.python.PyBundle; @@ -52,11 +51,7 @@ public class PyRaisingNewStyleClassInspection extends PyInspection { @Override public void visitPyRaiseStatement(PyRaiseStatement node) { - final VirtualFile virtualFile = node.getContainingFile().getVirtualFile(); - if (virtualFile == null) { - return; - } - if (LanguageLevel.forFile(virtualFile).isAtLeast(LanguageLevel.PYTHON25)) { + if (LanguageLevel.forElement(node).isAtLeast(LanguageLevel.PYTHON25)) { return; } final PyExpression[] expressions = node.getExpressions(); diff --git a/python/src/com/jetbrains/python/inspections/PyTupleAssignmentBalanceInspection.java b/python/src/com/jetbrains/python/inspections/PyTupleAssignmentBalanceInspection.java index fab0efbac0d4..18e2409ff970 100644 --- a/python/src/com/jetbrains/python/inspections/PyTupleAssignmentBalanceInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTupleAssignmentBalanceInspection.java @@ -17,7 +17,6 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElementVisitor; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.*; @@ -67,8 +66,7 @@ public class PyTupleAssignmentBalanceInspection extends PyInspection { PyExpression[] elements = ((PyTupleExpression) lhsExpression).getElements(); boolean containsStarExpression = false; - VirtualFile virtualFile = node.getContainingFile().getVirtualFile(); - if (virtualFile != null && LanguageLevel.forFile(virtualFile).isPy3K()) { + if (LanguageLevel.forElement(node).isPy3K()) { for (PyExpression target: elements) { if (target instanceof PyStarExpression) { if (containsStarExpression) { diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddFunctionQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddFunctionQuickFix.java index 4d71b425f040..d27ea683cba5 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/AddFunctionQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/AddFunctionQuickFix.java @@ -102,7 +102,7 @@ public class AddFunctionQuickFix implements LocalQuickFix { } } // else: no arglist, use empty args - PyFunction function = builder.buildFunction(project, LanguageLevel.forFile(myPyFile.getVirtualFile())); + PyFunction function = builder.buildFunction(project, myPyFile.getLanguageLevel()); // add to the bottom function = (PyFunction) myPyFile.add(function); diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index eaa480be1ac7..4dfbb5c01c87 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -663,10 +663,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement // EA-32381: A tree-based instance may not have a parent element somehow, so getContainingFile() may be not appropriate final PsiFile file = getParentByStub() != null ? getContainingFile() : null; if (file != null) { - final VirtualFile vfile = file.getVirtualFile(); - if (vfile != null) { - level = LanguageLevel.forFile(vfile); - } + level = LanguageLevel.forElement(file); } final boolean useAdvancedSyntax = level.isAtLeast(LanguageLevel.PYTHON26); final Property local = processPropertiesInClass(name, filter, useAdvancedSyntax); diff --git a/python/src/com/jetbrains/python/validation/UnsupportedFeatures.java b/python/src/com/jetbrains/python/validation/UnsupportedFeatures.java index 69b5f8b8684a..94a0f37428a0 100644 --- a/python/src/com/jetbrains/python/validation/UnsupportedFeatures.java +++ b/python/src/com/jetbrains/python/validation/UnsupportedFeatures.java @@ -23,11 +23,9 @@ import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ex.ProblemDescriptorImpl; import com.intellij.codeInspection.ex.QuickFixWrapper; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.psi.PyElement; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -44,7 +42,7 @@ public class UnsupportedFeatures extends CompatibilityVisitor { @Override public void visitPyElement(PyElement node) { - setVersionsToProcess(Arrays.asList(getLanguageLevel(node))); + setVersionsToProcess(Arrays.asList(LanguageLevel.forElement(node))); } @Override @@ -70,15 +68,6 @@ public class UnsupportedFeatures extends CompatibilityVisitor { getHolder().createWarningAnnotation(range, message); } - @NotNull - private static LanguageLevel getLanguageLevel(PyElement node) { - VirtualFile virtualFile = node.getContainingFile().getVirtualFile(); - if (virtualFile != null) { - return LanguageLevel.forFile(virtualFile); - } - return LanguageLevel.getDefault(); - } - private static IntentionAction createIntention(PsiElement node, String message, LocalQuickFix fix) { return createIntention(node, node.getTextRange(), message, fix); } From e36425ec851742ed27313fc4de735f46039bc6e7 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 7 Mar 2014 18:44:42 +0400 Subject: [PATCH 2/3] Moved LanguageLevel.forFile() to PyUtil.getLanguageLevelForVirtualFile() --- .../jetbrains/python/psi/LanguageLevel.java | 31 ---------------- .../PySyntaxHighlighterFactory.java | 3 +- .../src/com/jetbrains/python/psi/PyUtil.java | 37 ++++++++++++++++++- .../jetbrains/python/psi/impl/PyFileImpl.java | 2 +- 4 files changed, 39 insertions(+), 34 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/LanguageLevel.java b/python/psi-api/src/com/jetbrains/python/psi/LanguageLevel.java index 77e18da6fbaa..a09562d709a5 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/LanguageLevel.java +++ b/python/psi-api/src/com/jetbrains/python/psi/LanguageLevel.java @@ -15,10 +15,7 @@ */ package com.jetbrains.python.psi; -import com.intellij.injected.editor.VirtualFileWindow; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Key; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; @@ -131,34 +128,6 @@ public enum LanguageLevel { public static final Key KEY = new Key("python.language.level"); - @NotNull - public static LanguageLevel forFile(@NotNull VirtualFile virtualFile) { - if (virtualFile instanceof VirtualFileWindow) - virtualFile = ((VirtualFileWindow)virtualFile).getDelegate(); - - // Most of the cases should be handled by this one, PyLanguageLevelPusher pushes folders only - final VirtualFile folder = virtualFile.getParent(); - if (folder != null) { - final LanguageLevel level = folder.getUserData(KEY); - if (level != null) return level; - } - else { - // However this allows us to setup language level per file manually - // in case when it is LightVirtualFile - final LanguageLevel level = virtualFile.getUserData(KEY); - if (level != null) return level; - - if (ApplicationManager.getApplication().isUnitTestMode()) { - final LanguageLevel languageLevel = FORCE_LANGUAGE_LEVEL; - if (languageLevel != null) { - return languageLevel; - } - } - } - - return getDefault(); - } - @NotNull public static LanguageLevel forElement(@NotNull PsiElement element) { final PsiFile containingFile = element.getContainingFile(); diff --git a/python/src/com/jetbrains/python/highlighting/PySyntaxHighlighterFactory.java b/python/src/com/jetbrains/python/highlighting/PySyntaxHighlighterFactory.java index 8e9a13190bf5..999cf3092f91 100644 --- a/python/src/com/jetbrains/python/highlighting/PySyntaxHighlighterFactory.java +++ b/python/src/com/jetbrains/python/highlighting/PySyntaxHighlighterFactory.java @@ -24,6 +24,7 @@ import com.jetbrains.python.console.parsing.PyConsoleHighlightingLexer; import com.jetbrains.python.console.PydevConsoleRunner; import com.jetbrains.python.lexer.PythonHighlightingLexer; import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.psi.PyUtil; import org.jetbrains.annotations.NotNull; /** @@ -52,7 +53,7 @@ public class PySyntaxHighlighterFactory extends SyntaxHighlighterFactory { @NotNull public SyntaxHighlighter getSyntaxHighlighter(final Project project, final VirtualFile virtualFile) { - LanguageLevel languageLevel = virtualFile != null ? LanguageLevel.forFile(virtualFile) : LanguageLevel.getDefault(); + LanguageLevel languageLevel = virtualFile != null ? PyUtil.getLanguageLevelForVirtualFile(virtualFile) : LanguageLevel.getDefault(); if (virtualFile != null && PydevConsoleRunner.isInPydevConsole(virtualFile)) { return myConsoleMap.get(languageLevel); } diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 97b380b4f381..d049757effee 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -23,8 +23,10 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; +import com.intellij.injected.editor.VirtualFileWindow; import com.intellij.lang.ASTFactory; import com.intellij.lang.ASTNode; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; @@ -733,6 +735,39 @@ public class PyUtil { return pyClass.findMethodByName(PyNames.INIT, false); } + /** + * Returns Python language level for a virtual file. + * + * @see {@link LanguageLevel#forElement} + */ + @NotNull + public static LanguageLevel getLanguageLevelForVirtualFile(@NotNull VirtualFile virtualFile) { + if (virtualFile instanceof VirtualFileWindow) + virtualFile = ((VirtualFileWindow)virtualFile).getDelegate(); + + // Most of the cases should be handled by this one, PyLanguageLevelPusher pushes folders only + final VirtualFile folder = virtualFile.getParent(); + if (folder != null) { + final LanguageLevel level = folder.getUserData(LanguageLevel.KEY); + if (level != null) return level; + } + else { + // However this allows us to setup language level per file manually + // in case when it is LightVirtualFile + final LanguageLevel level = virtualFile.getUserData(LanguageLevel.KEY); + if (level != null) return level; + + if (ApplicationManager.getApplication().isUnitTestMode()) { + final LanguageLevel languageLevel = LanguageLevel.FORCE_LANGUAGE_LEVEL; + if (languageLevel != null) { + return languageLevel; + } + } + } + + return LanguageLevel.getDefault(); + } + public static class KnownDecoratorProviderHolder { public static PyKnownDecoratorProvider[] KNOWN_DECORATOR_PROVIDERS = Extensions.getExtensions(PyKnownDecoratorProvider.EP_NAME); @@ -797,7 +832,7 @@ public class PyUtil { if (turnDirIntoInit(directory) != null) { return true; } - if (LanguageLevel.forFile(directory.getVirtualFile()).isAtLeast(LanguageLevel.PYTHON33)) { + if (getLanguageLevelForVirtualFile(directory.getVirtualFile()).isAtLeast(LanguageLevel.PYTHON33)) { return true; } return hasNamespacePackageFile(directory); diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java index c1aa84c0268b..8cbc6e12b2d2 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java @@ -294,7 +294,7 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { if (virtualFile == null) { virtualFile = getViewProvider().getVirtualFile(); } - return LanguageLevel.forFile(virtualFile); + return PyUtil.getLanguageLevelForVirtualFile(virtualFile); } public Icon getIcon(int flags) { From 05289e4da0d7738a4a815f99153103d3b8142d8b Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 12 Mar 2014 12:58:59 +0400 Subject: [PATCH 3/3] Guess Python language level from SDKs of opened projects if it's not available for PSI elements --- .../userSkeletons/PyUserSkeletonsUtil.java | 2 +- .../PySyntaxHighlighterFactory.java | 13 ++++----- .../src/com/jetbrains/python/psi/PyUtil.java | 29 +++++++++++++++---- .../jetbrains/python/psi/impl/PyFileImpl.java | 2 +- .../python/psi/impl/PyImportedModule.java | 2 +- .../psi/impl/references/PyReferenceImpl.java | 2 +- .../python/psi/resolve/ResolveImportUtil.java | 6 ++-- .../python/psi/types/PyTypeParser.java | 2 +- 8 files changed, 38 insertions(+), 20 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java index ea6db0746ff2..ef13600bfa43 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java @@ -129,7 +129,7 @@ public class PyUserSkeletonsUtil { final PsiDirectory psiDirectory = PsiManager.getInstance(project).findDirectory(directory); PsiElement fileSkeleton = new QualifiedNameResolverImpl(qName).resolveModuleAt(psiDirectory); if (fileSkeleton instanceof PsiDirectory) { - fileSkeleton = PyUtil.getPackageElement((PsiDirectory)fileSkeleton); + fileSkeleton = PyUtil.getPackageElement((PsiDirectory)fileSkeleton, foothold); } if (fileSkeleton instanceof PyFile) { cache.put(cacheQName, Collections.singletonList(fileSkeleton)); diff --git a/python/src/com/jetbrains/python/highlighting/PySyntaxHighlighterFactory.java b/python/src/com/jetbrains/python/highlighting/PySyntaxHighlighterFactory.java index 999cf3092f91..98fbd69a1efe 100644 --- a/python/src/com/jetbrains/python/highlighting/PySyntaxHighlighterFactory.java +++ b/python/src/com/jetbrains/python/highlighting/PySyntaxHighlighterFactory.java @@ -21,11 +21,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.FactoryMap; import com.jetbrains.python.console.parsing.PyConsoleHighlightingLexer; -import com.jetbrains.python.console.PydevConsoleRunner; import com.jetbrains.python.lexer.PythonHighlightingLexer; import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.psi.PyUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author yole @@ -52,11 +52,10 @@ public class PySyntaxHighlighterFactory extends SyntaxHighlighterFactory { }; @NotNull - public SyntaxHighlighter getSyntaxHighlighter(final Project project, final VirtualFile virtualFile) { - LanguageLevel languageLevel = virtualFile != null ? PyUtil.getLanguageLevelForVirtualFile(virtualFile) : LanguageLevel.getDefault(); - if (virtualFile != null && PydevConsoleRunner.isInPydevConsole(virtualFile)) { - return myConsoleMap.get(languageLevel); - } - return myMap.get(languageLevel); + public SyntaxHighlighter getSyntaxHighlighter(@Nullable final Project project, @Nullable final VirtualFile virtualFile) { + final LanguageLevel level = project != null && virtualFile != null ? + PyUtil.getLanguageLevelForVirtualFile(project, virtualFile) : + LanguageLevel.getDefault(); + return myMap.get(level); } } diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index d049757effee..2c06bfdc9b07 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -30,8 +30,10 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.Balloon; @@ -68,6 +70,7 @@ import com.jetbrains.python.psi.types.*; import com.jetbrains.python.refactoring.classes.PyDependenciesComparator; import com.jetbrains.python.refactoring.classes.extractSuperclass.PyExtractSuperclassHelper; import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo; +import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -741,7 +744,8 @@ public class PyUtil { * @see {@link LanguageLevel#forElement} */ @NotNull - public static LanguageLevel getLanguageLevelForVirtualFile(@NotNull VirtualFile virtualFile) { + public static LanguageLevel getLanguageLevelForVirtualFile(@NotNull Project project, + @NotNull VirtualFile virtualFile) { if (virtualFile instanceof VirtualFileWindow) virtualFile = ((VirtualFileWindow)virtualFile).getDelegate(); @@ -764,7 +768,19 @@ public class PyUtil { } } } + return guessLanguageLevel(project); + } + private static LanguageLevel guessLanguageLevel(@NotNull Project project) { + final ModuleManager moduleManager = ModuleManager.getInstance(project); + if (moduleManager != null) { + for (Module projectModule : moduleManager.getModules()) { + final Sdk sdk = PythonSdkType.findPythonSdk(projectModule); + if (sdk != null) { + return PythonSdkType.getLanguageLevelForSdk(sdk); + } + } + } return LanguageLevel.getDefault(); } @@ -828,11 +844,14 @@ public class PyUtil { return target; } - public static boolean isPackage(@NotNull PsiDirectory directory) { + public static boolean isPackage(@NotNull PsiDirectory directory, @Nullable PsiElement anchor) { if (turnDirIntoInit(directory) != null) { return true; } - if (getLanguageLevelForVirtualFile(directory.getVirtualFile()).isAtLeast(LanguageLevel.PYTHON33)) { + final LanguageLevel level = anchor != null ? + LanguageLevel.forElement(anchor) : + getLanguageLevelForVirtualFile(directory.getProject(), directory.getVirtualFile()); + if (level.isAtLeast(LanguageLevel.PYTHON33)) { return true; } return hasNamespacePackageFile(directory); @@ -843,8 +862,8 @@ public class PyUtil { } @Nullable - public static PsiElement getPackageElement(@NotNull PsiDirectory directory) { - if (isPackage(directory)) { + public static PsiElement getPackageElement(@NotNull PsiDirectory directory, @Nullable PsiElement anchor) { + if (isPackage(directory, anchor)) { final PsiElement init = turnDirIntoInit(directory); if (init != null) { return init; diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java index 8cbc6e12b2d2..4976dd02b811 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java @@ -294,7 +294,7 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { if (virtualFile == null) { virtualFile = getViewProvider().getVirtualFile(); } - return PyUtil.getLanguageLevelForVirtualFile(virtualFile); + return PyUtil.getLanguageLevelForVirtualFile(getProject(), virtualFile); } public Icon getIcon(int flags) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java b/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java index d0358885a8fb..cba0bf2bcf99 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java @@ -143,7 +143,7 @@ public class PyImportedModule extends LightElement implements NameDefiner { element = ResolveImportUtil.resolveModuleInRoots(getImportedPrefix(), getContainingFile()); } if (element instanceof PsiDirectory) { - return PyUtil.getPackageElement((PsiDirectory)element); + return PyUtil.getPackageElement((PsiDirectory)element, this); } return element; } 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 df4fb34c39ce..c66cf5fe57db 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -427,7 +427,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference } else if (resolveResult instanceof PsiDirectory) { final PsiDirectory directory = (PsiDirectory)resolveResult; - if (PyUtil.isPackage(directory) && directory == element) { + if (PyUtil.isPackage(directory, null) && directory == element) { return true; } } diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 6a80851cea1b..2f866a24d8af 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -132,7 +132,7 @@ public class ResolveImportUtil { throw new PsiInvalidElementAccessException(candidate, "Got an invalid candidate from resolveImportSourceCandidates(): " + candidate.getClass()); } if (candidate instanceof PsiDirectory) { - candidate = PyUtil.getPackageElement((PsiDirectory)candidate); + candidate = PyUtil.getPackageElement((PsiDirectory)candidate, importStatement); } PsiElement result = resolveChild(candidate, name, file, false, true); if (result != null) { @@ -326,7 +326,7 @@ public class ResolveImportUtil { if (referencedName == null) return null; final PsiDirectory subdir = dir.findSubdirectory(referencedName); - if (subdir != null && (!checkForPackage || PyUtil.isPackage(subdir))) { + if (subdir != null && (!checkForPackage || PyUtil.isPackage(subdir, containingFile))) { return subdir; } @@ -358,7 +358,7 @@ public class ResolveImportUtil { ResolveResultList ret = new ResolveResultList(); for (PsiElement target : targets) { if (target instanceof PsiDirectory) { - target = PyUtil.getPackageElement((PsiDirectory)target); + target = PyUtil.getPackageElement((PsiDirectory)target, null); } if (target != null) { // Ignore non-package dirs, worthless int rate = RatedResolveResult.RATE_HIGH; diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java index e064ac31b83f..9e1923218494 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java @@ -450,7 +450,7 @@ public class PyTypeParser { break; } if (module instanceof PsiDirectory) { - module = PyUtil.getPackageElement((PsiDirectory)module); + module = PyUtil.getPackageElement((PsiDirectory)module, myAnchor); } if (module instanceof PyTypedElement) { final PyType moduleType = context.getType((PyTypedElement)module);