Introduce PyOverridingReferenceResolveProvider and PythonOverridingBuiltinReferenceResolveProvider as its implementation to handle implicit __class__

This commit is contained in:
Semyon Proshev
2016-11-15 16:08:29 +03:00
parent 1264bb0655
commit a04e558a43
4 changed files with 98 additions and 21 deletions
@@ -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 {
}
@@ -689,6 +689,7 @@
<typeProvider implementation="com.jetbrains.python.debugger.PyCallSignatureTypeProvider"/>
<pyReferenceResolveProvider implementation="com.jetbrains.python.psi.resolve.PythonBuiltinReferenceResolveProvider"/>
<pyReferenceResolveProvider implementation="com.jetbrains.python.psi.resolve.PythonOverridingBuiltinReferenceResolveProvider"/>
<!-- NumPy -->
<pyModuleMembersProvider implementation="com.jetbrains.numpy.codeInsight.NumpyModuleMembersProvider"/>
@@ -223,6 +223,11 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
*/
@NotNull
protected List<RatedResolveResult> 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;
@@ -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<RatedResolveResult> 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();
}
}