diff --git a/python/psi-api/src/com/jetbrains/python/psi/resolve/PyReferenceResolveProvider.java b/python/psi-api/src/com/jetbrains/python/psi/resolve/PyReferenceResolveProvider.java new file mode 100644 index 000000000000..19d04337b385 --- /dev/null +++ b/python/psi-api/src/com/jetbrains/python/psi/resolve/PyReferenceResolveProvider.java @@ -0,0 +1,23 @@ +package com.jetbrains.python.psi.resolve; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiElement; +import com.jetbrains.python.psi.PyQualifiedExpression; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * + * User : ktisha + */ +public interface PyReferenceResolveProvider { + ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyReferenceResolveProvider"); + + /** + * Allows to provide a custom resolve result for qualified expression + */ + @NotNull + List resolveName(@NotNull final PyQualifiedExpression element, + @NotNull final List definers); +} diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 7d31ba833638..2a88146d268c 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -838,6 +838,7 @@ + @@ -864,6 +865,7 @@ + @@ -893,6 +895,7 @@ + @@ -911,6 +914,10 @@ + + + + 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 b50b16e490ac..331be3200c82 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -6,6 +6,7 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.lang.ASTNode; import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; @@ -16,8 +17,9 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.PlatformIcons; import com.intellij.util.ProcessingContext; import com.jetbrains.cython.CythonLanguageDialect; -import com.jetbrains.cython.CythonResolveUtil; -import com.jetbrains.cython.psi.*; +import com.jetbrains.cython.psi.CythonIncludeStatement; +import com.jetbrains.cython.psi.CythonNamedElement; +import com.jetbrains.cython.psi.CythonVariable; import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction; @@ -248,8 +250,9 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference PsiElement realContext, PsiElement roof) { ResolveResultList ret = new ResolveResultList(); PsiElement uexpr = processor.getResult(); + final List definers = processor.getDefiners(); if (uexpr != null) { - if (processor.getDefiners().isEmpty()) { + if (definers.isEmpty()) { final ScopeOwner originalOwner = ScopeUtil.getScopeOwner(realContext); final ScopeOwner owner = ScopeUtil.getScopeOwner(uexpr); if (owner != null) { @@ -284,7 +287,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference } } // sort what we got - for (PsiElement hit : processor.getDefiners()) { + for (PsiElement hit : definers) { ret.poke(hit, getRate(hit)); } final PsiElement packageInit = PyUtil.turnDirIntoInit(uexpr); @@ -292,46 +295,30 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference uexpr = packageInit; // an import statement may have returned a dir } } - else if (!processor.getDefiners().isEmpty()) { - ret.add(new ImportedResolveResult(null, RatedResolveResult.RATE_LOW, processor.getDefiners())); + else if (!definers.isEmpty()) { + ret.add(new ImportedResolveResult(null, RatedResolveResult.RATE_LOW, definers)); } - PyBuiltinCache builtins_cache = PyBuiltinCache.getInstance(realContext); + PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(realContext); if (uexpr == null) { // ...as a part of current module String name = myElement.getName(); if (PyModuleType.MODULE_MEMBERS.contains(name)) { - PyType otype = builtins_cache.getObjectType(); // "object" as a closest kin to "module" - if (otype != null && name != null) { - ret.addAll(otype.resolveMember(name, null, AccessDirection.READ, myContext)); - } - } - } - if (uexpr == null) { - // ...as a builtin symbol - PyFile bfile = builtins_cache.getBuiltinsFile(); - if (bfile != null && !PyUtil.isClassPrivateName(referencedName)) { - uexpr = bfile.getElementNamed(referencedName); - if (uexpr == null && "__builtins__".equals(referencedName)) { - uexpr = bfile; // resolve __builtins__ reference - } - } - } - if (uexpr == null && CythonLanguageDialect.isInsideCythonFile(realContext)) { - final CythonFile implicit = CythonResolveUtil.findImplicitDefinitionFile(realContext); - if (implicit != null) { - uexpr = implicit.getElementNamed(referencedName); - } - final ScopeOwner owner = PsiTreeUtil.getParentOfType(myElement, ScopeOwner.class); - if (owner instanceof CythonFile) { - final PsiElement resolved = ((CythonFile)owner).getElementNamed(referencedName); - if ((resolved instanceof CythonFunction && ((CythonFunction)resolved).isCythonLevel()) || - resolved instanceof CythonFile) { - ret.poke(resolved, getRate(resolved)); + PyType objectType = builtinCache.getObjectType(); // "object" as a closest kin to "module" + if (objectType != null && name != null) { + ret.addAll(objectType.resolveMember(name, null, AccessDirection.READ, myContext)); } } } if (uexpr != null) { - ret.add(new ImportedResolveResult(uexpr, getRate(uexpr), processor.getDefiners())); + ret.add(new ImportedResolveResult(uexpr, getRate(uexpr), definers)); + } + else { + for (PyReferenceResolveProvider provider : Extensions.getExtensions(PyReferenceResolveProvider.EP_NAME)) { + final List results = provider.resolveName(myElement, definers); + for (RatedResolveResult res : results) { + ret.add(res); + } + } } return ret; @@ -379,7 +366,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference // NOTE: very crude - private static int getRate(PsiElement elt) { + public static int getRate(PsiElement elt) { int rate; if (CythonLanguageDialect.isInsideCythonFile(elt) && elt instanceof CythonIncludeStatement) { rate = RatedResolveResult.RATE_LOW; diff --git a/python/src/com/jetbrains/python/psi/resolve/PythonBuiltinReferenceResolveProvider.java b/python/src/com/jetbrains/python/psi/resolve/PythonBuiltinReferenceResolveProvider.java new file mode 100644 index 000000000000..817a8f3eb1ab --- /dev/null +++ b/python/src/com/jetbrains/python/psi/resolve/PythonBuiltinReferenceResolveProvider.java @@ -0,0 +1,39 @@ +package com.jetbrains.python.psi.resolve; + +import com.intellij.psi.PsiElement; +import com.jetbrains.python.psi.PyFile; +import com.jetbrains.python.psi.PyQualifiedExpression; +import com.jetbrains.python.psi.PyUtil; +import com.jetbrains.python.psi.impl.PyBuiltinCache; +import com.jetbrains.python.psi.impl.PyPsiUtils; +import com.jetbrains.python.psi.impl.references.PyReferenceImpl; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * User : ktisha + */ +public class PythonBuiltinReferenceResolveProvider implements PyReferenceResolveProvider { + @NotNull + @Override + public List resolveName(@NotNull PyQualifiedExpression element, + @NotNull List definers) { + final List result = new ArrayList(); + final PsiElement realContext = PyPsiUtils.getRealContext(element); + final String referencedName = element.getReferencedName(); + final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(realContext); + // ...as a builtin symbol + final PyFile bfile = builtinCache.getBuiltinsFile(); + if (bfile != null && !PyUtil.isClassPrivateName(referencedName)) { + PsiElement resultElement = bfile.getElementNamed(referencedName); + if (resultElement == null && "__builtins__".equals(referencedName)) { + resultElement = bfile; // resolve __builtins__ reference + } + if (resultElement != null) + result.add(new ImportedResolveResult(resultElement, PyReferenceImpl.getRate(resultElement), definers)); + } + return result; + } +}