Merge branch 'python-fixes'

This commit is contained in:
Andrey Vlasovskikh
2012-02-03 16:47:03 +04:00
20 changed files with 178 additions and 71 deletions
@@ -197,6 +197,9 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
@Nullable
private static String getQualifiedName(@NotNull PyFunction f, @Nullable PsiElement callSite) {
if (!f.isValid()) {
return null;
}
String result = f.getName();
final PyClass c = f.getContainingClass();
final VirtualFile vfile = f.getContainingFile().getVirtualFile();
@@ -40,8 +40,9 @@ import com.jetbrains.python.console.PydevConsoleRunner;
import com.jetbrains.python.documentation.DocStringParameterReference;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.references.PyImportReference;
import com.jetbrains.python.psi.impl.PyImportStatementNavigator;
import com.jetbrains.python.psi.impl.PyImportedModule;
import com.jetbrains.python.psi.impl.references.PyImportReference;
import com.jetbrains.python.psi.impl.references.PyOperatorReference;
import com.jetbrains.python.psi.resolve.ImportedResolveResult;
import com.jetbrains.python.psi.resolve.PyResolveContext;
@@ -452,11 +453,16 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
private static boolean ignoreUnresolvedMemberForType(PyType qtype, PsiReference reference, String refText) {
if (qtype instanceof PyNoneType || qtype instanceof PyTypeReference ||
(qtype instanceof PyUnionType && ((PyUnionType)qtype).isWeak()) ||
(qtype instanceof PyImportedModuleType)) {
(qtype instanceof PyUnionType && ((PyUnionType)qtype).isWeak())) {
// this almost always means that we don't know the type, so don't show an error in this case
return true;
}
if (qtype instanceof PyImportedModuleType) {
PyImportedModule module = ((PyImportedModuleType)qtype).getImportedModule();
if (module.resolve() == null) {
return true;
}
}
if (qtype instanceof PyClassType) {
PyClass cls = ((PyClassType)qtype).getPyClass();
if (cls != null) {
@@ -18,6 +18,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.PsiManager;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFile;
@@ -287,7 +288,7 @@ public class PyBuiltinCache {
@Nullable
public PyClassType getOldstyleClassobjType() {
return getObjectType("___Classobj");
return getObjectType(PyNames.FAKE_OLD_BASE);
}
@Nullable
@@ -638,6 +638,9 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
@Nullable
private Property scanProperties(@Nullable String name, @Nullable Processor<Property> filter, boolean inherited) {
if (!isValid()) {
return null;
}
LanguageLevel level = LanguageLevel.getDefault();
// 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;
@@ -83,18 +83,20 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
@Override
public Icon getIcon(int flags) {
final Property property = getProperty();
if (property != null) {
if (property.getGetter().valueOrNull() == this) {
return PROPERTY_GETTER;
if (isValid()) {
final Property property = getProperty();
if (property != null) {
if (property.getGetter().valueOrNull() == this) {
return PROPERTY_GETTER;
}
if (property.getSetter().valueOrNull() == this) {
return PROPERTY_SETTER;
}
if (property.getDeleter().valueOrNull() == this) {
return PROPERTY_DELETER;
}
return PlatformIcons.PROPERTY_ICON;
}
if (property.getSetter().valueOrNull() == this) {
return PROPERTY_SETTER;
}
if (property.getDeleter().valueOrNull() == this) {
return PROPERTY_DELETER;
}
return PlatformIcons.PROPERTY_ICON;
}
return PlatformIcons.METHOD_ICON;
}
@@ -108,6 +108,17 @@ public class PyImportedModule extends LightElement implements NameDefiner {
return super.getNavigationElement();
}
@Nullable
public PyFile resolve() {
if (myImportElement != null) {
final PsiElement result = PyUtil.turnDirIntoInit(ResolveImportUtil.resolveImportElement(myImportElement, myImportedPrefix));
if (result instanceof PyFile) {
return (PyFile)result;
}
}
return null;
}
@Nullable
private static PsiElement resolve(PyImportElement importElement, final PyQualifiedName prefix) {
return PyUtil.turnDirIntoInit(ResolveImportUtil.resolveImportElement(importElement, prefix));
@@ -335,12 +335,14 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
@Nullable
public PyExpression findAssignedValue() {
PyAssignmentStatement assignment = PsiTreeUtil.getParentOfType(this, PyAssignmentStatement.class);
if (assignment != null) {
List<Pair<PyExpression, PyExpression>> mapping = assignment.getTargetsToValuesMapping();
for (Pair<PyExpression, PyExpression> pair : mapping) {
PyExpression assigned_to = pair.getFirst();
if (assigned_to == this) return pair.getSecond();
if (isValid()) {
PyAssignmentStatement assignment = PsiTreeUtil.getParentOfType(this, PyAssignmentStatement.class);
if (assignment != null) {
List<Pair<PyExpression, PyExpression>> mapping = assignment.getTargetsToValuesMapping();
for (Pair<PyExpression, PyExpression> pair : mapping) {
PyExpression assigned_to = pair.getFirst();
if (assigned_to == this) return pair.getSecond();
}
}
}
return null;
@@ -256,6 +256,14 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType {
addInheritedMembers(prefix, location, context, ret);
if (!myClass.isNewStyleClass()) {
final PyBuiltinCache cache = PyBuiltinCache.getInstance(myClass);
final PyClassType classobjType = cache.getOldstyleClassobjType();
if (classobjType != null) {
ret.addAll(Arrays.asList(classobjType.getCompletionVariants(prefix, location, context)));
}
}
if (isDefinition() && myClass.isNewStyleClass()) {
PyClassType typeType = PyBuiltinCache.getInstance(myClass).getObjectType("type");
if (typeType != null) {
@@ -385,7 +393,7 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType {
public String toString() {
return (isValid() ? "" : "[INVALID] ") + "PyClassType: " + getClassQName();
}
public boolean isValid() {
return myClass == null || myClass.isValid();
}
@@ -2,18 +2,17 @@ package com.jetbrains.python.psi.types;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.psi.PsiElement;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.psi.AccessDirection;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyImportElement;
import com.jetbrains.python.psi.impl.PyFileImpl;
import com.jetbrains.python.psi.impl.PyImportedModule;
import com.jetbrains.python.psi.impl.PyQualifiedName;
import com.jetbrains.python.psi.impl.ResolveResultList;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@@ -22,19 +21,23 @@ import java.util.List;
* @author yole
*/
public class PyImportedModuleType implements PyType {
private PyImportedModule myImportedModule;
@NotNull private PyImportedModule myImportedModule;
public PyImportedModuleType(PyImportedModule importedModule) {
public PyImportedModuleType(@NotNull PyImportedModule importedModule) {
myImportedModule = importedModule;
}
@NotNull
@Nullable
@Override
public List<? extends RatedResolveResult> resolveMember(String name,
PyExpression location,
AccessDirection direction,
PyResolveContext resolveContext) {
final PsiElement element = myImportedModule.getElementNamed(name);
return ResolveResultList.to(element);
final PyFile file = myImportedModule.resolve();
if (file != null) {
return new PyModuleType(file).resolveMember(name, location, direction, resolveContext);
}
return null;
}
public Object[] getCompletionVariants(String completionPrefix, PyExpression location, ProcessingContext context) {
@@ -63,6 +66,7 @@ public class PyImportedModuleType implements PyType {
return false; // no module can be imported from builtins
}
@NotNull
public PyImportedModule getImportedModule() {
return myImportedModule;
}
@@ -5,13 +5,17 @@ import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyDynamicMember;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyQualifiedName;
import com.jetbrains.python.psi.impl.ResolveResultList;
@@ -42,6 +46,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje
}
@Nullable
@Override
public List<? extends RatedResolveResult> resolveMember(final String name,
@Nullable PyExpression location,
AccessDirection direction,
@@ -57,36 +62,70 @@ public class PyModuleType implements PyType { // Modules don't descend from obje
return ResolveResultList.to(attribute);
}
if (location != null && isPackage(myModule)) {
final PsiFile file = location.getContainingFile();
if (file instanceof PyFile) {
final PyQualifiedName packageQName = ResolveImportUtil.findCanonicalImportPath(myModule, location);
if (packageQName != null) {
final List<PyImportElement> imports = ((PyFile)file).getImportTargets();
for (PyImportElement importElement : imports) {
final PyStatement stmt = importElement.getContainingImportStatement();
PyQualifiedName importedQName = null;
if (stmt instanceof PyFromImportStatement) {
importedQName = ((PyFromImportStatement)stmt).getImportSourceQName();
}
else if (stmt instanceof PyImportStatement) {
importedQName = importElement.getImportedQName();
}
final PyQualifiedName submoduleQName = packageQName.append(name);
if (importedQName != null && importedQName.matchesPrefix(submoduleQName)) {
final PsiElement submodule = ResolveImportUtil.resolveChild(myModule, name, myModule, null, null, false, true);
if (submodule != null) {
final ResolveResultList results = new ResolveResultList();
results.poke(submodule, RatedResolveResult.RATE_NORMAL);
results.add(new ImportedResolveResult(submodule, RatedResolveResult.RATE_LOW,
Collections.<PsiElement>singletonList(importElement)));
return results;
}
}
return resolveImplicitPackageMember(name, location);
}
return null;
}
@Nullable
private List<? extends RatedResolveResult> resolveImplicitPackageMember(@NotNull String name, @NotNull PyExpression location) {
final ScopeOwner owner = ScopeUtil.getScopeOwner(location);
final PyQualifiedName packageQName = ResolveImportUtil.findCanonicalImportPath(myModule, location);
if (owner != null && packageQName != null) {
for (PyImportElement importElement : getVisibleImports(owner)) {
final PyStatement stmt = importElement.getContainingImportStatement();
PyQualifiedName importedQName = null;
PyQualifiedName implicitSubmoduleQName = null;
if (stmt instanceof PyFromImportStatement) {
final PyFromImportStatement fromImportStatement = (PyFromImportStatement)stmt;
importedQName = fromImportStatement.getImportSourceQName();
final String visibleName = importElement.getVisibleName();
if (importedQName != null) {
implicitSubmoduleQName = importedQName.append(visibleName);
}
}
else if (stmt instanceof PyImportStatement) {
importedQName = importElement.getImportedQName();
}
final PyQualifiedName resolvedQName = packageQName.append(name);
if ((importedQName != null && importedQName.matchesPrefix(resolvedQName)) ||
(implicitSubmoduleQName != null && implicitSubmoduleQName.equals(resolvedQName))) {
final PsiElement submodule = ResolveImportUtil.resolveChild(myModule, name, myModule, null, null, false, true);
if (submodule != null) {
final ResolveResultList results = new ResolveResultList();
results.add(new ImportedResolveResult(submodule, RatedResolveResult.RATE_NORMAL,
Collections.<PsiElement>singletonList(importElement)));
return results;
}
}
}
}
return Collections.emptyList();
return null;
}
@NotNull
private static List<PyImportElement> getVisibleImports(@NotNull ScopeOwner owner) {
final List<PyImportElement> visibleImports = new ArrayList<PyImportElement>();
PyResolveUtil.scopeCrawlUp(new PsiScopeProcessor() {
@Override
public boolean execute(PsiElement element, ResolveState state) {
if (element instanceof PyImportElement) {
visibleImports.add((PyImportElement)element);
}
return true;
}
@Nullable
@Override
public <T> T getHint(Key<T> hintKey) {
return null;
}
@Override
public void handleEvent(Event event, @Nullable Object associated) {
}
}, owner, null);
return visibleImports;
}
private static boolean isPackage(@NotNull PyFile file) {
@@ -495,7 +495,7 @@ public class PythonSdkType extends SdkType {
}
// Add folders from sys.path
final List<String> paths = getSysPath(bin_path);
if ((paths != null) && paths.size() > 0) {
if (paths.size() > 0) {
// add every path as root.
for (String path : paths) {
if (!path.contains(sep)) continue; // TODO: interpret possible 'special' paths reasonably
@@ -575,14 +575,12 @@ public class PythonSdkType extends SdkType {
return PathManager.getSystemPath() + File.separator + SKELETON_DIR_NAME;
}
@Nullable
@NotNull
public static List<String> getSysPath(String bin_path) {
String working_dir = new File(bin_path).getParent();
Application application = ApplicationManager.getApplication();
if (application != null && !application.isUnitTestMode()) {
final List<String> paths = getSysPathsFromScript(bin_path);
if (paths == null) throw new InvalidSdkException("Failed to determine Python's sys.path value");
return paths;
return getSysPathsFromScript(bin_path);
}
else { // mock sdk
List<String> ret = new ArrayList<String>(1);
@@ -591,8 +589,7 @@ public class PythonSdkType extends SdkType {
}
}
@Nullable
@NotNull
protected static List<String> getSysPathsFromScript(String bin_path) {
String scriptFile = PythonHelpersLocator.getHelperPath("syspath.py");
// to handle the situation when PYTHONPATH contains ., we need to run the syspath script in the
@@ -603,7 +600,12 @@ public class PythonSdkType extends SdkType {
new String[]{bin_path, scriptFile},
add_environment, MINUTE
);
return run_result.checkSuccess(LOG) ? run_result.getStdoutLines() : null;
if (!run_result.checkSuccess(LOG)) {
throw new InvalidSdkException(String.format("Failed to determine Python's sys.path value:\nSTDOUT: %s\nSTDERR: %s",
run_result.getStdout(),
run_result.getStderr()));
}
return run_result.getStdoutLines();
}
// Returns a piece of env good as additional env for getProcessOutput.
@@ -0,0 +1,4 @@
class C:
pass
c = C()
c.__class__
@@ -0,0 +1,4 @@
class C:
pass
c = C()
c.__cla<caret>
@@ -0,0 +1 @@
a1 = 42
@@ -0,0 +1 @@
a2 = -1
@@ -0,0 +1,3 @@
import p1.m1
print(p1.<warning descr="Cannot find reference 'm2' in 'imported module p1'">m2</warning>.a2)
@@ -189,7 +189,9 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
assertResolvesTo(PyFunction.class, "do_stuff");
}
public void testReimportExported() {
// PY-1153
// TODO: This case requires collecting transitive imports in all imported submodules
public void _testReimportExported() {
assertResolvesTo(PyFunction.class, "dostuff");
}
@@ -487,23 +487,23 @@ public class PythonCompletionTest extends PyTestCase {
public void testImportKeyword() {
doTest();
}
public void testAssignedNearby() {
doTest();
}
public void testDunderAll() {
doMultiFileTest();
}
public void testAsName() {
doMultiFileTest();
}
public void testKeywordArgumentsForImplicitCall() {
doTest();
}
public void testTypeMembers() { // PY-5311
myFixture.configureByText(PythonFileType.INSTANCE, "a = 'string'\n" +
"a.<caret>");
@@ -512,8 +512,12 @@ public class PythonCompletionTest extends PyTestCase {
final List<String> strings = myFixture.getLookupElementStrings();
assertFalse(strings.contains("mro"));
}
public void testDunderAllReference() { // PY-5502
doTest();
}
public void testOldStyleClassAttributes() {
doTest();
}
}
@@ -24,4 +24,11 @@ public class PyUnusedImportTest extends PyTestCase {
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
myFixture.testHighlighting(true, false, false, "test1.py");
}
// PY-5621
public void testUnusedSubmodule() {
myFixture.copyDirectoryToProject("inspections/unusedImport/unusedSubmodule", "");
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
myFixture.testHighlighting(true, false, false, "test1.py");
}
}