From a04e558a4323e2a0859504e7d78ac90e6282808f Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Thu, 27 Oct 2016 20:01:16 +0300 Subject: [PATCH] Introduce PyOverridingReferenceResolveProvider and PythonOverridingBuiltinReferenceResolveProvider as its implementation to handle implicit __class__ --- .../PyOverridingReferenceResolveProvider.java | 19 +++++++ python/src/META-INF/python-core-common.xml | 1 + .../psi/impl/references/PyReferenceImpl.java | 43 +++++++------- ...ridingBuiltinReferenceResolveProvider.java | 56 +++++++++++++++++++ 4 files changed, 98 insertions(+), 21 deletions(-) create mode 100644 python/psi-api/src/com/jetbrains/python/psi/resolve/PyOverridingReferenceResolveProvider.java create mode 100644 python/src/com/jetbrains/python/psi/resolve/PythonOverridingBuiltinReferenceResolveProvider.java diff --git a/python/psi-api/src/com/jetbrains/python/psi/resolve/PyOverridingReferenceResolveProvider.java b/python/psi-api/src/com/jetbrains/python/psi/resolve/PyOverridingReferenceResolveProvider.java new file mode 100644 index 000000000000..c8e9948c4c05 --- /dev/null +++ b/python/psi-api/src/com/jetbrains/python/psi/resolve/PyOverridingReferenceResolveProvider.java @@ -0,0 +1,19 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.psi.resolve; + +public interface PyOverridingReferenceResolveProvider extends PyReferenceResolveProvider { +} \ No newline at end of file diff --git a/python/src/META-INF/python-core-common.xml b/python/src/META-INF/python-core-common.xml index e0cd72c5a26c..22eaa4acff34 100644 --- a/python/src/META-INF/python-core-common.xml +++ b/python/src/META-INF/python-core-common.xml @@ -689,6 +689,7 @@ + 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 d56fcd837910..bca772752ed3 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -223,6 +223,11 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference */ @NotNull protected List resolveInner() { + final ResolveResultList overriddenRet = resolveByOverridingReferenceResolveProviders(); + if (!overriddenRet.isEmpty()) { + return overriddenRet; + } + final ResolveResultList ret = new ResolveResultList(); final String referencedName = myElement.getReferencedName(); @@ -235,27 +240,6 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference } } - // resolve implicit __class__ inside class function - if (myElement instanceof PyReferenceExpression && - PyNames.__CLASS__.equals(referencedName) && - LanguageLevel.forElement(myElement).isAtLeast(LanguageLevel.PYTHON30)) { - final PyFunction containingFunction = PsiTreeUtil.getParentOfType(myElement, PyFunction.class); - - if (containingFunction != null) { - final PyClass containingClass = containingFunction.getContainingClass(); - - if (containingClass != null) { - final PyResolveProcessor processor = new PyResolveProcessor(referencedName); - PyResolveUtil.scopeCrawlUp(processor, myElement, referencedName, containingFunction); - - if (processor.getElements().isEmpty()) { - ret.add(new RatedResolveResult(RatedResolveResult.RATE_NORMAL, containingClass)); - return ret; - } - } - } - } - // here we have an unqualified expr. it may be defined: // ...in current file final PyResolveProcessor processor = new PyResolveProcessor(referencedName); @@ -359,11 +343,28 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference return true; } + @NotNull + private ResolveResultList resolveByOverridingReferenceResolveProviders() { + final ResolveResultList results = new ResolveResultList(); + final TypeEvalContext context = myContext.getTypeEvalContext(); + + Arrays + .stream(Extensions.getExtensions(PyReferenceResolveProvider.EP_NAME)) + .filter(PyOverridingReferenceResolveProvider.class::isInstance) + .map(provider -> provider.resolveName(myElement, context)) + .forEach(results::addAll); + + return results; + } + @NotNull private ResolveResultList resolveByReferenceResolveProviders() { final ResolveResultList results = new ResolveResultList(); final TypeEvalContext context = myContext.getTypeEvalContext(); for (PyReferenceResolveProvider provider : Extensions.getExtensions(PyReferenceResolveProvider.EP_NAME)) { + if (provider instanceof PyOverridingReferenceResolveProvider) { + continue; + } results.addAll(provider.resolveName(myElement, context)); } return results; diff --git a/python/src/com/jetbrains/python/psi/resolve/PythonOverridingBuiltinReferenceResolveProvider.java b/python/src/com/jetbrains/python/psi/resolve/PythonOverridingBuiltinReferenceResolveProvider.java new file mode 100644 index 000000000000..e176d30d4937 --- /dev/null +++ b/python/src/com/jetbrains/python/psi/resolve/PythonOverridingBuiltinReferenceResolveProvider.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.psi.resolve; + +import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.PyNames; +import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.types.TypeEvalContext; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +public class PythonOverridingBuiltinReferenceResolveProvider implements PyOverridingReferenceResolveProvider { + + @NotNull + @Override + public List resolveName(@NotNull PyQualifiedExpression element, @NotNull TypeEvalContext context) { + final String referencedName = element.getReferencedName(); + + // resolve implicit __class__ inside class function + if (element instanceof PyReferenceExpression && + PyNames.__CLASS__.equals(referencedName) && + LanguageLevel.forElement(element).isAtLeast(LanguageLevel.PYTHON30)) { + final PyFunction containingFunction = PsiTreeUtil.getParentOfType(element, PyFunction.class); + + if (containingFunction != null) { + final PyClass containingClass = containingFunction.getContainingClass(); + + if (containingClass != null) { + final PyResolveProcessor processor = new PyResolveProcessor(referencedName); + PyResolveUtil.scopeCrawlUp(processor, element, referencedName, containingFunction); + + if (processor.getElements().isEmpty()) { + return Collections.singletonList(new RatedResolveResult(RatedResolveResult.RATE_NORMAL, containingClass)); + } + } + } + } + + return Collections.emptyList(); + } +}