mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Better error messages for checking structural types
The new error message mentions the attributes that the actual type is misssing instead of just telling what the expected and actual types are.
This commit is contained in:
@@ -15,13 +15,16 @@
|
||||
*/
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession;
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.hash.LinkedHashMap;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.documentation.PythonDocumentationProvider;
|
||||
@@ -32,6 +35,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author vlan
|
||||
@@ -126,7 +130,27 @@ public class PyTypeCheckerInspection extends PyInspection {
|
||||
}
|
||||
}
|
||||
final String actualName = PythonDocumentationProvider.getTypeName(actual, context);
|
||||
final String msg = String.format("Expected type %s, got '%s' instead", quotedExpectedName, actualName);
|
||||
String msg= String.format("Expected type %s, got '%s' instead", quotedExpectedName, actualName);
|
||||
if (expected instanceof PyStructuralType) {
|
||||
final Set<String> expectedAttributes = ((PyStructuralType)expected).getAttributeNames();
|
||||
final Set<String> actualAttributes = getAttributes(actual);
|
||||
if (actualAttributes != null) {
|
||||
final Sets.SetView<String> missingAttributes = Sets.difference(expectedAttributes, actualAttributes);
|
||||
if (missingAttributes.size() == 1) {
|
||||
msg = String.format("Type '%s' doesn't have expected attribute '%s'", actualName, missingAttributes.iterator().next());
|
||||
}
|
||||
else {
|
||||
msg = String.format("Type '%s' doesn't have expected attributes %s",
|
||||
actualName,
|
||||
StringUtil.join(missingAttributes, new Function<String, String>() {
|
||||
@Override
|
||||
public String fun(String s) {
|
||||
return String.format("'%s'", s);
|
||||
}
|
||||
}, ", "));
|
||||
}
|
||||
}
|
||||
}
|
||||
registerProblem(node, msg, highlightType);
|
||||
return msg;
|
||||
}
|
||||
@@ -135,6 +159,17 @@ public class PyTypeCheckerInspection extends PyInspection {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Set<String> getAttributes(@NotNull PyType type) {
|
||||
if (type instanceof PyStructuralType) {
|
||||
return ((PyStructuralType)type).getAttributeNames();
|
||||
}
|
||||
else if (type instanceof PyClassType) {
|
||||
return PyTypeChecker.getClassAttributes(((PyClassType)type).getPyClass(), true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inspectionFinished(@NotNull LocalInspectionToolSession session, @NotNull ProblemsHolder problemsHolder) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
|
||||
@@ -205,7 +205,7 @@ public class PyTypeChecker {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<String> getClassAttributes(@NotNull PyClass cls, boolean inherited) {
|
||||
public static Set<String> getClassAttributes(@NotNull PyClass cls, boolean inherited) {
|
||||
final Set<String> attributes = new HashSet<String>();
|
||||
for (PyFunction function : cls.getMethods(false)) {
|
||||
attributes.add(function.getName());
|
||||
|
||||
@@ -12,5 +12,5 @@ def test(x):
|
||||
g(x)
|
||||
|
||||
z = 'foo'
|
||||
f(<warning descr="Expected type '{foo, bar}', got 'str' instead">z</warning>)
|
||||
f(<warning descr="Type 'str' doesn't have expected attributes 'foo', 'bar'">z</warning>)
|
||||
g(z)
|
||||
|
||||
+1
-1
@@ -18,4 +18,4 @@ class E(object):
|
||||
|
||||
f(C())
|
||||
f(D())
|
||||
f(<warning descr="Expected type '{foo}', got 'E' instead">E()</warning>)
|
||||
f(<warning descr="Type 'E' doesn't have expected attribute 'foo'">E()</warning>)
|
||||
|
||||
+1
-1
@@ -7,4 +7,4 @@ def g(x):
|
||||
|
||||
|
||||
def test():
|
||||
f(<warning descr="Expected type '{foo, bar}', got 'str' instead">'string'</warning>)
|
||||
f(<warning descr="Type 'str' doesn't have expected attributes 'foo', 'bar'">'string'</warning>)
|
||||
|
||||
Reference in New Issue
Block a user