diff --git a/python/build/plugin-list.txt b/python/build/plugin-list.txt index f2b7f745fa40..ba236d36d374 100644 --- a/python/build/plugin-list.txt +++ b/python/build/plugin-list.txt @@ -49,3 +49,4 @@ pycharm-flask pycharm-numpy textmate restClient +puppet diff --git a/python/build/pycharm_build.gant b/python/build/pycharm_build.gant index e79ce5e2e7ca..e7800220bb48 100644 --- a/python/build/pycharm_build.gant +++ b/python/build/pycharm_build.gant @@ -179,6 +179,7 @@ private layoutPlugins(layouts) { include(name: "joni.jar") } } + layouts.layoutPlugin("puppet") } layouts.layoutPlugins() diff --git a/python/rest/resources/META-INF/plugin.xml b/python/rest/resources/META-INF/plugin.xml index d1aef1edb89a..656f4da72986 100644 --- a/python/rest/resources/META-INF/plugin.xml +++ b/python/rest/resources/META-INF/plugin.xml @@ -3,8 +3,8 @@ org.jetbrains.plugins.rest This plugin enables support for reStructuredText files (*.rst) JetBrains - 122.SNAPSHOT - + 126.SNAPSHOT + com.intellij.modules.lang diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index e3f137ad6ddb..83a8d36a4e72 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -319,6 +319,7 @@ + diff --git a/python/src/com/jetbrains/python/codeInsight/testIntegration/PyTestFinder.java b/python/src/com/jetbrains/python/codeInsight/testIntegration/PyTestFinder.java index 1ec7b07be12e..88abc81cf1e4 100644 --- a/python/src/com/jetbrains/python/codeInsight/testIntegration/PyTestFinder.java +++ b/python/src/com/jetbrains/python/codeInsight/testIntegration/PyTestFinder.java @@ -21,7 +21,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.regex.Pattern; /** * User : catherine @@ -37,19 +36,18 @@ public class PyTestFinder implements TestFinder { PyDocStringOwner source = findSourceElement(element); if (source == null) return Collections.emptySet(); - String klassName = source.getName(); - Pattern pattern = Pattern.compile(".*" + klassName + ".*"); + String sourceName = source.getName(); List> classesWithProximities = new ArrayList>(); if (source instanceof PyClass) { Collection names = PyClassNameIndex.allKeys(element.getProject()); for (String eachName : names) { - if (pattern.matcher(eachName).matches()) { + if (eachName.contains(sourceName)) { for (PyClass eachClass : PyClassNameIndex.find(eachName, element.getProject(), GlobalSearchScope.projectScope(element.getProject()))) { if (PythonUnitTestUtil.isTestCaseClass(eachClass) || PythonDocTestUtil.isDocTestClass(eachClass)) { classesWithProximities.add( - new Pair(eachClass, TestFinderHelper.calcTestNameProximity(klassName, eachName))); + new Pair(eachClass, TestFinderHelper.calcTestNameProximity(sourceName, eachName))); } } } @@ -58,12 +56,12 @@ public class PyTestFinder implements TestFinder { else { Collection names = PyFunctionNameIndex.allKeys(element.getProject()); for (String eachName : names) { - if (pattern.matcher(eachName).matches()) { + if (eachName.contains(sourceName)) { for (PyFunction eachFunction : PyFunctionNameIndex.find(eachName, element.getProject(), GlobalSearchScope.projectScope(element.getProject()))) { if (PythonUnitTestUtil.isTestCaseFunction( eachFunction) || PythonDocTestUtil.isDocTestFunction(eachFunction)) { classesWithProximities.add( - new Pair(eachFunction, TestFinderHelper.calcTestNameProximity(klassName, eachName))); + new Pair(eachFunction, TestFinderHelper.calcTestNameProximity(sourceName, eachName))); } } } diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java index b55852641e6d..4ddbb6ce2e16 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java @@ -41,10 +41,9 @@ import com.intellij.psi.impl.source.tree.FileElement; import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.IJSwingUtilities; -import com.intellij.util.io.IOUtil; import com.intellij.util.net.NetUtils; import com.intellij.util.ui.UIUtil; -import com.jetbrains.django.run.Runner; +import com.jetbrains.django.run.ProcessRunner; import com.intellij.remotesdk.RemoteSdkData; import com.intellij.remotesdk.RemoteSshProcess; import com.jetbrains.python.PythonHelpersLocator; @@ -247,7 +246,7 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory remotePorts = getRemotePortsFromProcess(remoteProcess); diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationEntryEditor.form b/python/src/com/jetbrains/python/documentation/PythonDocumentationEntryEditor.form index 2525a95b1a82..efb3316f1401 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationEntryEditor.form +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationEntryEditor.form @@ -36,7 +36,7 @@ - + diff --git a/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java b/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java index 150afaf00188..c492a80438f8 100644 --- a/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java @@ -49,11 +49,7 @@ public class PyCallingNonCallableInspection extends PyInspection { final PyExpression callee = decorator.getCallee(); checkCallable(decorator, callee, null); if (decorator.hasArgumentList()) { - final Callable callable = decorator.resolveCalleeFunction(resolveWithoutImplicits()); - if (callable != null) { - final PyReferenceExpression callSite = callee instanceof PyReferenceExpression ? (PyReferenceExpression)callee : null; - checkCallable(decorator, null, callable.getReturnType(myTypeEvalContext, callSite)); - } + checkCallable(decorator, decorator, null); } } } diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java new file mode 100644 index 000000000000..a4c6be4edb59 --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java @@ -0,0 +1,68 @@ +package com.jetbrains.python.inspections; + +import com.intellij.codeInspection.LocalInspectionToolSession; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.PsiNameIdentifierOwner; +import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.impl.PyBuiltinCache; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Warns about shadowing built-in names. + * + * TODO: Merge into PyRedeclarationInspection and detect all shadowed names + * + * @author vlan + */ +public class PyShadowingBuiltinsInspection extends PyInspection { + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, + boolean isOnTheFly, + @NotNull LocalInspectionToolSession session) { + return new Visitor(holder, session); + } + + private static class Visitor extends PyInspectionVisitor { + public Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session) { + super(holder, session); + } + + @Override + public void visitPyClass(@NotNull PyClass node) { + processElement(node); + } + + @Override + public void visitPyFunction(@NotNull PyFunction node) { + if (node.getContainingClass() == null) { + processElement(node); + } + } + + @Override + public void visitPyNamedParameter(@NotNull PyNamedParameter node) { + processElement(node); + } + + @Override + public void visitPyTargetExpression(@NotNull PyTargetExpression node) { + processElement(node); + } + + private void processElement(@NotNull PsiNameIdentifierOwner element) { + final String name = element.getName(); + if (name != null) { + final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(element); + final PsiElement builtin = builtinCache.getByName(name); + if (builtin != null && !PyUtil.inSameFile(builtin, element)) { + final PsiElement identifier = element.getNameIdentifier(); + registerProblem(identifier != null ? identifier : element, "Shadows a built-in with the same name"); + } + } + } + } +} diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index 0da76c514fce..8be02c241f58 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -64,7 +64,7 @@ public class PyTypeCheckerInspection extends PyInspection { final Map substitutions = new LinkedHashMap(); final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, myTypeEvalContext); if (results != null) { - substitutions.putAll(PyTypeChecker.collectCallGenerics(results.getFunction(), results.getReceiver(), myTypeEvalContext)); + substitutions.putAll(PyTypeChecker.collectCallGenerics(results.getCallable(), results.getReceiver(), myTypeEvalContext)); for (Map.Entry entry : results.getArguments().entrySet()) { final PyNamedParameter p = entry.getValue(); if (p.isPositionalContainer() || p.isKeywordContainer()) { diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index bb7993ec14fb..b12c5a4371fe 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -672,8 +672,8 @@ public class PyUnresolvedReferencesInspection extends PyInspection { return true; } if (qtype instanceof PyFunctionType) { - final PyFunction function = ((PyFunctionType)qtype).getFunction(); - if (function.getDecoratorList() != null) { + final Callable callable = ((PyFunctionType)qtype).getCallable(); + if (callable instanceof PyFunction && ((PyFunction)callable).getDecoratorList() != null) { return true; } } diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java index 5f1bd463deb6..d14376d3707f 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java @@ -30,6 +30,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.events.VFileEvent; +import com.intellij.remotesdk.RemoteCredentials; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.SystemProperties; @@ -627,7 +628,7 @@ public class PyPackageManagerImpl extends PyPackageManager { private String getHelperPath(String helper) { String helperPath; final SdkAdditionalData sdkData = mySdk.getSdkAdditionalData(); - if (sdkData instanceof RemoteSdkData) { + if (sdkData instanceof RemoteCredentials) { final RemoteSdkData remoteSdkData = (RemoteSdkData)sdkData; helperPath = new RemoteFile(remoteSdkData.getHelpersPath(), helper).getPath(); @@ -644,7 +645,7 @@ public class PyPackageManagerImpl extends PyPackageManager { @Nullable String workingDir) throws PyExternalProcessException { final SdkAdditionalData sdkData = mySdk.getSdkAdditionalData(); - if (sdkData instanceof RemoteSdkData) { //remote interpreter + if (sdkData instanceof RemoteCredentials) { //remote interpreter final RemoteSdkData remoteSdkData = (RemoteSdkData)sdkData; final PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance(); if (manager != null) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java index 86623f87eb9f..1b5e21df8f3a 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java @@ -111,7 +111,7 @@ public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExp public PyType getType(@NotNull TypeEvalContext context) { final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCall(this, context); if (results != null) { - final PyType type = results.getFunction().getReturnType(context, this); + final PyType type = results.getCallable().getReturnType(context, this); if (!PyTypeChecker.isUnknown(type) && !(type instanceof PyNoneType)) { return type; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java index 944a95fdaa67..11f4d999e220 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java @@ -347,7 +347,7 @@ public class PyBuiltinCache { return true; } else if (type instanceof PyFunctionType) { - return ((PyFunctionType)type).getFunction().isValid(); + return ((PyFunctionType)type).getCallable().isValid(); } return true; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index 9a4741a072b0..aea70b28e570 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -1,13 +1,17 @@ package com.jetbrains.python.psi.impl; +import com.intellij.codeInsight.completion.CompletionUtil; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.ResolveResult; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.QualifiedResolveResult; import com.jetbrains.python.psi.types.*; +import com.jetbrains.python.toolbox.Maybe; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -337,4 +341,199 @@ public class PyCallExpressionHelper { } return null; } + + public static PyType getCallType(@NotNull PyCallExpression call, @NotNull TypeEvalContext context) { + if (!TypeEvalStack.mayEvaluate(call)) { + return null; + } + try { + PyExpression callee = call.getCallee(); + if (callee instanceof PyReferenceExpression) { + // hardwired special cases + if (PyNames.SUPER.equals(callee.getText())) { + final Maybe superCallType = getSuperCallType(call, context); + if (superCallType.isDefined()) { + return superCallType.value(); + } + } + if ("type".equals(callee.getText())) { + final PyExpression[] args = call.getArguments(); + if (args.length == 1) { + final PyExpression arg = args[0]; + final PyType argType = arg.getType(context); + if (argType instanceof PyClassType) { + final PyClassType classType = (PyClassType)argType; + if (!classType.isDefinition()) { + final PyClass cls = classType.getPyClass(); + return cls.getType(context); + } + } + else { + return null; + } + } + } + // normal cases + final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); + ResolveResult[] targets = ((PyReferenceExpression)callee).getReference(resolveContext).multiResolve(false); + if (targets.length > 0) { + PsiElement target = targets[0].getElement(); + if (target == null) { + return null; + } + PyClass cls = null; + PyFunction init = null; + if (target instanceof PyClass) { + cls = (PyClass)target; + init = cls.findInitOrNew(true); + } + else if (target instanceof PyFunction) { + final PyFunction f = (PyFunction)target; + if (PyNames.INIT.equals(f.getName())) { + init = f; + cls = f.getContainingClass(); + } + } + if (init != null) { + final PyType t = init.getReturnType(context, (PyReferenceExpression)callee); + if (cls != null) { + if (init.getContainingClass() != cls) { + if (t instanceof PyCollectionType) { + final PyType elementType = ((PyCollectionType)t).getElementType(context); + return new PyCollectionTypeImpl(cls, false, elementType); + } + return new PyClassTypeImpl(cls, false); + } + } + if (t != null && !(t instanceof PyNoneType)) { + if (t instanceof PyTypeReference) { + PyType resolved = ((PyTypeReference)t).resolve(callee, context); + if (resolved == null && cls != null) { + return PyUnionType.createWeakType(new PyClassTypeImpl(cls, false)); + } + } + return t; + } + } + if (cls != null) { + return new PyClassTypeImpl(cls, false); + } + final PyType providedType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(target, context, call); + if (providedType != null) { + if (providedType instanceof PyClassType) { + return ((PyClassType)providedType).toInstance(); + } + return providedType; + } + if (target instanceof Callable) { + final Callable callable = (Callable)target; + PyType returnType = callable.getReturnType(context, (PyReferenceExpression)callee); + if (returnType != null) { + return returnType; + } + return new PyReturnTypeReference(callable); + } + } + } + if (callee == null) { + return null; + } + else { + final PyType type = context.getType(callee); + if (type instanceof PyCallableType) { + final PyQualifiedExpression callSite = callee instanceof PyQualifiedExpression ? (PyQualifiedExpression)callee : null; + return ((PyCallableType) type).getCallType(context, callSite); + } + return null; + } + } + finally { + TypeEvalStack.evaluated(call); + } + } + + @NotNull + private static Maybe getSuperCallType(@NotNull PyCallExpression call, TypeEvalContext context) { + final PyExpression callee = call.getCallee(); + if (callee instanceof PyReferenceExpression) { + PsiElement must_be_super_init = ((PyReferenceExpression)callee).getReference().resolve(); + if (must_be_super_init instanceof PyFunction) { + PyClass must_be_super = ((PyFunction)must_be_super_init).getContainingClass(); + if (must_be_super == PyBuiltinCache.getInstance(call).getClass(PyNames.SUPER)) { + PyArgumentList arglist = call.getArgumentList(); + if (arglist != null) { + final PyClass containingClass = PsiTreeUtil.getParentOfType(call, PyClass.class); + PyExpression[] args = arglist.getArguments(); + if (args.length > 1) { + PyExpression first_arg = args[0]; + if (first_arg instanceof PyReferenceExpression) { + final PyReferenceExpression firstArgRef = (PyReferenceExpression)first_arg; + final PyExpression qualifier = firstArgRef.getQualifier(); + if (qualifier != null && PyNames.CLASS.equals(firstArgRef.getReferencedName())) { + final PsiReference qRef = qualifier.getReference(); + final PsiElement element = qRef == null ? null : qRef.resolve(); + if (element instanceof PyParameter) { + final PyParameterList parameterList = PsiTreeUtil.getParentOfType(element, PyParameterList.class); + if (parameterList != null && element == parameterList.getParameters()[0]) { + return new Maybe(getSuperCallTypeForArguments(context, containingClass, args[1])); + } + } + } + PsiElement possible_class = firstArgRef.getReference().resolve(); + if (possible_class instanceof PyClass && ((PyClass)possible_class).isNewStyleClass()) { + final PyClass first_class = (PyClass)possible_class; + return new Maybe(getSuperCallTypeForArguments(context, first_class, args[1])); + } + } + } + else if (((PyFile)call.getContainingFile()).getLanguageLevel().isPy3K() && containingClass != null) { + return new Maybe(getSuperClassUnionType(containingClass)); + } + } + } + } + } + return new Maybe(); + } + + @Nullable + private static PyType getSuperCallTypeForArguments(TypeEvalContext context, PyClass firstClass, PyExpression second_arg) { + // check 2nd argument, too; it should be an instance + if (second_arg != null) { + PyType second_type = context.getType(second_arg); + if (second_type instanceof PyClassType) { + // imitate isinstance(second_arg, possible_class) + PyClass secondClass = ((PyClassType)second_type).getPyClass(); + if (CompletionUtil.getOriginalOrSelf(firstClass) == secondClass) { + return getSuperClassUnionType(firstClass); + } + if (secondClass.isSubclass(firstClass)) { + final Iterator iterator = firstClass.iterateAncestorClasses().iterator(); + if (iterator.hasNext()) { + return new PyClassTypeImpl(iterator.next(), false); // super(Foo, self) has type of Foo, modulo __get__() + } + } + } + } + return null; + } + + @Nullable + private static PyType getSuperClassUnionType(@NotNull PyClass pyClass) { + // TODO: this is closer to being correct than simply taking first superclass type but still not entirely correct; + // super can also delegate to sibling types + // TODO handle __mro__ here + final PyClass[] supers = pyClass.getSuperClasses(); + if (supers.length > 0) { + if (supers.length == 1) { + return new PyClassTypeImpl(supers[0], false); + } + List superTypes = new ArrayList(); + for (PyClass aSuper : supers) { + superTypes.add(new PyClassTypeImpl(aSuper, false)); + } + return PyUnionType.union(superTypes); + } + return null; + } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java index c67fdbb1efa6..b8d0fcb1cb0f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java @@ -1,23 +1,14 @@ package com.jetbrains.python.psi.impl; -import com.intellij.codeInsight.completion.CompletionUtil; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiReference; -import com.intellij.psi.ResolveResult; import com.intellij.psi.util.PsiTreeUtil; -import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.types.*; -import com.jetbrains.python.toolbox.Maybe; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - /** * @author yole */ @@ -97,194 +88,6 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress } public PyType getType(@NotNull TypeEvalContext context) { - if (!TypeEvalStack.mayEvaluate(this)) { - return null; - } - try { - PyExpression callee = getCallee(); - if (callee instanceof PyReferenceExpression) { - // hardwired special cases - if (PyNames.SUPER.equals(callee.getText())) { - final Maybe superCallType = getSuperCallType(callee, context); - if (superCallType.isDefined()) { - return superCallType.value(); - } - } - if ("type".equals(callee.getText())) { - final PyExpression[] args = getArguments(); - if (args.length == 1) { - final PyExpression arg = args[0]; - final PyType argType = arg.getType(context); - if (argType instanceof PyClassType) { - final PyClassType classType = (PyClassType)argType; - if (!classType.isDefinition()) { - final PyClass cls = classType.getPyClass(); - return cls.getType(context); - } - } - else { - return null; - } - } - } - // normal cases - final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); - ResolveResult[] targets = ((PyReferenceExpression)callee).getReference(resolveContext).multiResolve(false); - if (targets.length > 0) { - PsiElement target = targets[0].getElement(); - if (target == null) { - return null; - } - PyClass cls = null; - PyFunction init = null; - if (target instanceof PyClass) { - cls = (PyClass)target; - init = cls.findInitOrNew(true); - } - else if (target instanceof PyFunction) { - final PyFunction f = (PyFunction)target; - if (PyNames.INIT.equals(f.getName())) { - init = f; - cls = f.getContainingClass(); - } - } - if (init != null) { - final PyType t = init.getReturnType(context, (PyReferenceExpression)callee); - if (cls != null) { - if (init.getContainingClass() != cls) { - if (t instanceof PyCollectionType) { - final PyType elementType = ((PyCollectionType)t).getElementType(context); - return new PyCollectionTypeImpl(cls, false, elementType); - } - return new PyClassTypeImpl(cls, false); - } - } - if (t != null && !(t instanceof PyNoneType)) { - if (t instanceof PyTypeReference) { - PyType resolved = ((PyTypeReference)t).resolve(callee, context); - if (resolved == null && cls != null) { - return PyUnionType.createWeakType(new PyClassTypeImpl(cls, false)); - } - } - return t; - } - } - if (cls != null) { - return new PyClassTypeImpl(cls, false); - } - final PyType providedType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(target, context, this); - if (providedType != null) { - if (providedType instanceof PyClassType) { - return ((PyClassType)providedType).toInstance(); - } - return providedType; - } - if (target instanceof Callable) { - final Callable callable = (Callable)target; - PyType returnType = callable.getReturnType(context, (PyReferenceExpression)callee); - if (returnType != null) { - return returnType; - } - return new PyReturnTypeReference(callable); - } - } - } - if (callee == null) { - return null; - } - else { - final PyType type = context.getType(callee); - if (type instanceof PyCallableType) { - final PyQualifiedExpression callSite = callee instanceof PyQualifiedExpression ? (PyQualifiedExpression)callee : null; - return ((PyCallableType) type).getCallType(context, callSite); - } - return null; - } - } - finally { - TypeEvalStack.evaluated(this); - } - } - - @NotNull - private Maybe getSuperCallType(PyExpression callee, TypeEvalContext context) { - PsiElement must_be_super_init = ((PyReferenceExpression)callee).getReference().resolve(); - if (must_be_super_init instanceof PyFunction) { - PyClass must_be_super = ((PyFunction)must_be_super_init).getContainingClass(); - if (must_be_super == PyBuiltinCache.getInstance(this).getClass(PyNames.SUPER)) { - PyArgumentList arglist = getArgumentList(); - if (arglist != null) { - final PyClass containingClass = PsiTreeUtil.getParentOfType(this, PyClass.class); - PyExpression[] args = arglist.getArguments(); - if (args.length > 1) { - PyExpression first_arg = args[0]; - if (first_arg instanceof PyReferenceExpression) { - final PyReferenceExpression firstArgRef = (PyReferenceExpression)first_arg; - final PyExpression qualifier = firstArgRef.getQualifier(); - if (qualifier != null && PyNames.CLASS.equals(firstArgRef.getReferencedName())) { - final PsiReference qRef = qualifier.getReference(); - final PsiElement element = qRef == null ? null : qRef.resolve(); - if (element instanceof PyParameter) { - final PyParameterList parameterList = PsiTreeUtil.getParentOfType(element, PyParameterList.class); - if (parameterList != null && element == parameterList.getParameters()[0]) { - return new Maybe(getSuperCallType(context, containingClass, args[1])); - } - } - } - PsiElement possible_class = firstArgRef.getReference().resolve(); - if (possible_class instanceof PyClass && ((PyClass)possible_class).isNewStyleClass()) { - final PyClass first_class = (PyClass)possible_class; - return new Maybe(getSuperCallType(context, first_class, args[1])); - } - } - } - else if (((PyFile)getContainingFile()).getLanguageLevel().isPy3K() && containingClass != null) { - return new Maybe(getSuperClassUnionType(containingClass)); - } - } - } - } - return new Maybe(); - } - - @Nullable - private static PyType getSuperCallType(TypeEvalContext context, PyClass firstClass, PyExpression second_arg) { - // check 2nd argument, too; it should be an instance - if (second_arg != null) { - PyType second_type = context.getType(second_arg); - if (second_type instanceof PyClassType) { - // imitate isinstance(second_arg, possible_class) - PyClass secondClass = ((PyClassType)second_type).getPyClass(); - if (CompletionUtil.getOriginalOrSelf(firstClass) == secondClass) { - return getSuperClassUnionType(firstClass); - } - if (secondClass.isSubclass(firstClass)) { - final Iterator iterator = firstClass.iterateAncestorClasses().iterator(); - if (iterator.hasNext()) { - return new PyClassTypeImpl(iterator.next(), false); // super(Foo, self) has type of Foo, modulo __get__() - } - } - } - } - return null; - } - - @Nullable - private static PyType getSuperClassUnionType(@NotNull PyClass pyClass) { - // TODO: this is closer to being correct than simply taking first superclass type but still not entirely correct; - // super can also delegate to sibling types - // TODO handle __mro__ here - final PyClass[] supers = pyClass.getSuperClasses(); - if (supers.length > 0) { - if (supers.length == 1) { - return new PyClassTypeImpl(supers[0], false); - } - List superTypes = new ArrayList(); - for (PyClass aSuper : supers) { - superTypes.add(new PyClassTypeImpl(aSuper, false)); - } - return PyUnionType.union(superTypes); - } - return null; + return PyCallExpressionHelper.getCallType(this, context); } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java index f26a3e48d8a7..b0c5d37004bd 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java @@ -166,8 +166,7 @@ public class PyDecoratorImpl extends StubBasedPsiElementBase im } } - // TODO: create a custom version of public PyType getType() public PyType getType(@NotNull TypeEvalContext context) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return PyCallExpressionHelper.getCallType(this, context); } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index ee02c122cd01..27380a9928fd 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -5,6 +5,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.types.PyFunctionType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; @@ -23,7 +24,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp } public PyType getType(@NotNull TypeEvalContext context) { - return null; + return new PyFunctionType(this); } @NotNull diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index 4db67f09ecf7..e66c3a7069bf 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -1,10 +1,7 @@ package com.jetbrains.python.psi.types; import com.intellij.util.ProcessingContext; -import com.jetbrains.python.psi.AccessDirection; -import com.jetbrains.python.psi.PyExpression; -import com.jetbrains.python.psi.PyFunction; -import com.jetbrains.python.psi.PyQualifiedExpression; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import org.jetbrains.annotations.NotNull; @@ -14,23 +11,21 @@ import java.util.Collections; import java.util.List; /** - * Type of a particular function that is represented as a {@link PyFunction} in the PSI tree. - * - * TODO: Maybe this class should extend PyClassType and have a Python mock class for type 'function' in the __builtins__. + * Type of a particular function that is represented as a {@link Callable} in the PSI tree. * * @author vlan */ public class PyFunctionType implements PyCallableType { - @NotNull private final PyFunction myFunction; + @NotNull private final Callable myCallable; - public PyFunctionType(@NotNull PyFunction function) { - myFunction = function; + public PyFunctionType(@NotNull Callable callable) { + myCallable = callable; } @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { - return myFunction.getReturnType(context, callSite); + return myCallable.getReturnType(context, callSite); } @Override @@ -61,7 +56,7 @@ public class PyFunctionType implements PyCallableType { } @NotNull - public PyFunction getFunction() { - return myFunction; + public Callable getCallable() { + return myCallable; } } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 64bc291843d6..1ca378328788 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -269,7 +269,7 @@ public class PyTypeChecker { } @NotNull - public static Map collectCallGenerics(@NotNull PyFunction function, @Nullable PyExpression receiver, + public static Map collectCallGenerics(@NotNull Callable callable, @Nullable PyExpression receiver, @NotNull TypeEvalContext context) { final Map substitutions = new LinkedHashMap(); // Collect generic params of object type @@ -279,7 +279,7 @@ public class PyTypeChecker { for (PyGenericType t : generics) { substitutions.put(t, t); } - final PyClass cls = function.getContainingClass(); + final PyClass cls = (callable instanceof PyFunction) ? ((PyFunction)callable).getContainingClass() : null; if (cls != null) { final PyFunction init = cls.findInitOrNew(true); // Unify generics in constructor @@ -346,17 +346,17 @@ public class PyTypeChecker { if (!(type instanceof PyFunctionType)) { return null; } - final PyFunction function = ((PyFunctionType)type).getFunction(); + final Callable callable = ((PyFunctionType)type).getCallable(); final boolean isRight = PyNames.isRightOperatorName(typedElement.getName()); final PyExpression arg = isRight ? expr.getLeftExpression() : expr.getRightExpression(); final PyExpression receiver = isRight ? expr.getRightExpression() : expr.getLeftExpression(); - final PyParameter[] parameters = function.getParameterList().getParameters(); + final PyParameter[] parameters = callable.getParameterList().getParameters(); if (parameters.length >= 2) { final PyNamedParameter param = parameters[1].getAsNamed(); if (arg != null && param != null) { final Map arguments = new LinkedHashMap(); arguments.put(arg, param); - final AnalyzeCallResults results = new AnalyzeCallResults(function, receiver, arguments); + final AnalyzeCallResults results = new AnalyzeCallResults(callable, receiver, arguments); if (firstResults == null) { firstResults = results; } @@ -382,8 +382,8 @@ public class PyTypeChecker { if (resolved instanceof PyTypedElement) { final PyType type = ((PyTypedElement)resolved).getType(context); if (type instanceof PyFunctionType) { - final PyFunction function = ((PyFunctionType)type).getFunction(); - final PyParameter[] parameters = function.getParameterList().getParameters(); + final Callable callable = ((PyFunctionType)type).getCallable(); + final PyParameter[] parameters = callable.getParameterList().getParameters(); if (parameters.length == 2) { final PyNamedParameter param = parameters[1].getAsNamed(); if (param != null) { @@ -391,7 +391,7 @@ public class PyTypeChecker { final PyExpression arg = expr.getIndexExpression(); if (arg != null) { arguments.put(arg, param); - return new AnalyzeCallResults(function, expr.getOperand(), arguments); + return new AnalyzeCallResults(callable, expr.getOperand(), arguments); } } } @@ -423,20 +423,20 @@ public class PyTypeChecker { } public static class AnalyzeCallResults { - @NotNull private final PyFunction myFunction; + @NotNull private final Callable myCallable; @Nullable private final PyExpression myReceiver; @NotNull private final Map myArguments; - public AnalyzeCallResults(@NotNull PyFunction function, @Nullable PyExpression receiver, + public AnalyzeCallResults(@NotNull Callable callable, @Nullable PyExpression receiver, @NotNull Map arguments) { - myFunction = function; + myCallable = callable; myReceiver = receiver; myArguments = arguments; } @NotNull - public PyFunction getFunction() { - return myFunction; + public Callable getCallable() { + return myCallable; } @Nullable diff --git a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java index da130ac8253f..a10ad75c16a6 100644 --- a/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java +++ b/python/src/com/jetbrains/python/remote/PythonRemoteInterpreterManager.java @@ -11,6 +11,7 @@ import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.remotesdk.RemoteCredentials; import com.intellij.remotesdk.RemoteInterpreterException; import com.intellij.remotesdk.RemoteSdkData; import com.intellij.remotesdk.RemoteSshProcess; diff --git a/python/src/com/jetbrains/python/sdk/PySdkUtil.java b/python/src/com/jetbrains/python/sdk/PySdkUtil.java index 1b3b6a0d2101..e046208c72c6 100644 --- a/python/src/com/jetbrains/python/sdk/PySdkUtil.java +++ b/python/src/com/jetbrains/python/sdk/PySdkUtil.java @@ -6,9 +6,9 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.remotesdk.RemoteCredentials; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashMap; -import com.intellij.remotesdk.RemoteSdkData; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -204,6 +204,6 @@ public class PySdkUtil { } public static boolean isRemote(@Nullable Sdk sdk) { - return sdk != null && sdk.getSdkAdditionalData() instanceof RemoteSdkData; + return sdk != null && sdk.getSdkAdditionalData() instanceof RemoteCredentials; } } diff --git a/python/testData/inspections/PyCallingNonCallableInspection/callableClassDecorator.py b/python/testData/inspections/PyCallingNonCallableInspection/callableClassDecorator.py new file mode 100644 index 000000000000..86aca9f75301 --- /dev/null +++ b/python/testData/inspections/PyCallingNonCallableInspection/callableClassDecorator.py @@ -0,0 +1,15 @@ +class D(object): + def __init__(self, attribute, value): + pass + + def __call__(self, cls): + return cls + + +@D("value", 42) +class C(object): + pass + + +a = C() +print(a.value) \ No newline at end of file diff --git a/python/testData/inspections/PyShadowingBuiltinsInspection/test.py b/python/testData/inspections/PyShadowingBuiltinsInspection/test.py new file mode 100644 index 000000000000..ca25df4a2a04 --- /dev/null +++ b/python/testData/inspections/PyShadowingBuiltinsInspection/test.py @@ -0,0 +1,23 @@ +import float +from foo import float +from bar import baz as float + +def test1(x, len, file=None): + foo = 2 + list = [] + for int in range(10): + print(int) + range = [] + return [int for int in range(10)] + + +def list(): + pass + + +class list(object): + def foo(self): + pass + + def list(self): + pass diff --git a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java index e67beab8c461..04e875dd6ac5 100644 --- a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java +++ b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java @@ -306,4 +306,9 @@ public class PythonInspectionsTest extends PyTestCase { public void testPyDecoratorInspection() { //PY-3348 doHighlightingTest(PyDecoratorInspection.class); } + + // PY-5807 + public void testPyShadowingBuiltinsInspection() { + doHighlightingTest(PyShadowingBuiltinsInspection.class); + } } diff --git a/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java index 8f8441c2367c..3c2cf2a1cf5e 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyCallingNonCallableInspectionTest.java @@ -59,6 +59,11 @@ public class PyCallingNonCallableInspectionTest extends PyTestCase { doTest(); } + // PY-5905 + public void testCallableClassDecorator() { + doTest(); + } + private void doTest() { setLanguageLevel(LanguageLevel.PYTHON27); try {