mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'python-fixes'
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user