Moved isResolvedToSeveralMethods() to PyTypeChecker

This commit is contained in:
Andrey Vlasovskikh
2013-02-04 16:20:04 +04:00
parent 31c3b75e64
commit 1469a3d7d1
2 changed files with 47 additions and 43 deletions
@@ -10,13 +10,14 @@ import com.intellij.psi.PsiElementVisitor;
import com.intellij.util.containers.hash.LinkedHashMap;
import com.jetbrains.python.documentation.PythonDocumentationProvider;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.types.*;
import com.jetbrains.python.psi.types.PyGenericType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.PyTypeChecker;
import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
/**
@@ -44,11 +45,7 @@ public class PyTypeCheckerInspection extends PyInspection {
public void visitPyCallExpression(PyCallExpression node) {
final PyExpression callee = node.getCallee();
if (callee instanceof PyQualifiedExpression) {
final PyQualifiedExpression qualified = (PyQualifiedExpression)callee;
if (isResolvedToSeveralMethods(qualified)) {
return;
}
checkCallSite(qualified);
checkCallSite((PyQualifiedExpression)callee);
}
}
@@ -63,40 +60,6 @@ public class PyTypeCheckerInspection extends PyInspection {
checkCallSite(node);
}
/**
* Hack for skipping type checking for method calls of union members if there are several call alternatives.
*
* TODO: Multi-resolve callees when analysing calls. This requires multi-resolving in followAssignmentsChain.
*/
private boolean isResolvedToSeveralMethods(@NotNull PyQualifiedExpression callee) {
final PyExpression qualifier = callee.getQualifier();
if (qualifier != null) {
final PyType qualifierType = qualifier.getType(myTypeEvalContext);
if (qualifierType instanceof PyUnionType) {
final PyUnionType unionType = (PyUnionType)qualifierType;
final String name = callee.getName();
int sameNameCount = 0;
for (PyType member : unionType.getMembers()) {
if (member != null) {
final List<? extends RatedResolveResult> results = member.resolveMember(name, callee, AccessDirection.READ,
resolveWithoutImplicits());
if (results != null && !results.isEmpty()) {
sameNameCount++;
}
}
}
if (sameNameCount > 1) {
return true;
}
}
final PyExpression qualifierExpr = qualifier instanceof PyCallExpression ? ((PyCallExpression)qualifier).getCallee() : qualifier;
if (qualifierExpr instanceof PyQualifiedExpression) {
return isResolvedToSeveralMethods((PyQualifiedExpression)qualifierExpr);
}
}
return false;
}
private void checkCallSite(@Nullable PyQualifiedExpression callSite) {
final Map<PyGenericType, PyType> substitutions = new LinkedHashMap<PyGenericType, PyType>();
final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, myTypeEvalContext);
@@ -9,6 +9,7 @@ import com.jetbrains.python.codeInsight.stdlib.PyStdlibTypeProvider;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -319,6 +320,13 @@ public class PyTypeChecker {
@Nullable
public static AnalyzeCallResults analyzeCall(@NotNull PyCallExpression call, @NotNull TypeEvalContext context) {
final PyExpression callee = call.getCallee();
if (callee instanceof PyQualifiedExpression) {
final PyQualifiedExpression qualified = (PyQualifiedExpression)callee;
if (isResolvedToSeveralMethods(qualified, context)) {
return null;
}
}
final PyArgumentList args = call.getArgumentList();
if (args != null) {
final CallArgumentsMapping mapping = args.analyzeCall(PyResolveContext.noImplicits().withTypeEvalContext(context));
@@ -327,7 +335,6 @@ public class PyTypeChecker {
if (markedCallee != null) {
final Callable callable = markedCallee.getCallable();
if (callable instanceof PyFunction) {
final PyExpression callee = call.getCallee();
final PyExpression receiver = callee instanceof PyQualifiedExpression ? ((PyQualifiedExpression)callee).getQualifier() : null;
return new AnalyzeCallResults(callable, receiver, arguments);
}
@@ -464,6 +471,40 @@ public class PyTypeChecker {
return type.equals(builtinCache.getClassMethodType()) || type.equals(builtinCache.getStaticMethodType());
}
/**
* Hack for skipping type checking for method calls of union members if there are several call alternatives.
*
* TODO: Multi-resolve callees when analysing calls. This requires multi-resolving in followAssignmentsChain.
*/
public static boolean isResolvedToSeveralMethods(@NotNull PyQualifiedExpression callee, @NotNull TypeEvalContext context) {
final PyExpression qualifier = callee.getQualifier();
if (qualifier != null) {
final PyType qualifierType = qualifier.getType(context);
if (qualifierType instanceof PyUnionType) {
final PyUnionType unionType = (PyUnionType)qualifierType;
final String name = callee.getName();
int sameNameCount = 0;
for (PyType member : unionType.getMembers()) {
if (member != null) {
final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
final List<? extends RatedResolveResult> results = member.resolveMember(name, callee, AccessDirection.READ, resolveContext);
if (results != null && !results.isEmpty()) {
sameNameCount++;
}
}
}
if (sameNameCount > 1) {
return true;
}
}
final PyExpression qualifierExpr = qualifier instanceof PyCallExpression ? ((PyCallExpression)qualifier).getCallee() : qualifier;
if (qualifierExpr instanceof PyQualifiedExpression) {
return isResolvedToSeveralMethods((PyQualifiedExpression)qualifierExpr, context);
}
}
return false;
}
public static class AnalyzeCallResults {
@NotNull private final Callable myCallable;
@Nullable private final PyExpression myReceiver;