Moved Cython-specific inspection checks to CythonInspectionExtension

This commit is contained in:
Andrey Vlasovskikh
2013-08-29 17:50:59 +04:00
parent 2e88c54614
commit 4c7704c222
6 changed files with 60 additions and 30 deletions
@@ -2,7 +2,13 @@ package com.jetbrains.python.inspections;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.jetbrains.python.psi.PyDocStringOwner;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyQualifiedExpression;
import com.jetbrains.python.psi.types.PyType;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -23,4 +29,20 @@ public abstract class PyInspectionExtension {
public List<String> getFunctionParametersFromUsage(PsiElement elt) {
return null;
}
public boolean ignoreMethodParameters(@NotNull PyFunction function) {
return false;
}
public boolean ignorePackageNameInRequirements(@NotNull PyQualifiedExpression importedExpression) {
return false;
}
public boolean ignoreUnresolvedReference(@NotNull PyElement node, @NotNull PsiReference reference) {
return false;
}
public boolean ignoreUnresolvedMember(@NotNull PyType type, @NotNull String name) {
return false;
}
}
@@ -973,6 +973,7 @@
<visitorFilter language="Cython" implementationClass="com.jetbrains.cython.CythonVisitorFilter"/>
<pyModuleMembersProvider implementation="com.jetbrains.cython.CythonModuleMembersProvider"/>
<pyReferenceResolveProvider implementation="com.jetbrains.cython.CythonReferenceResolveProvider"/>
<inspectionExtension implementation="com.jetbrains.cython.CythonInspectionExtension"/>
<!-- Mako -->
<dialectsTokenSetContributor implementation="com.jetbrains.mako.MakoTokenSetContributor"/>
@@ -5,10 +5,10 @@ import com.intellij.codeInspection.LocalInspectionToolSession;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.jetbrains.cython.psi.CythonClass;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.inspections.quickfix.AddSelfQuickFix;
@@ -66,18 +66,19 @@ public class PyMethodParametersInspection extends PyInspection {
return ret;
}
@Override
public void visitPyFunction(final PyFunction node) {
for (PyInspectionExtension extension : Extensions.getExtensions(PyInspectionExtension.EP_NAME)) {
if (extension.ignoreMethodParameters(node)) {
return;
}
}
// maybe it's a zope interface?
PsiElement zope_interface = findZopeInterface(node);
final PyClass cls = node.getContainingClass();
if (zope_interface instanceof PyClass) {
if (cls != null && cls.isSubclass((PyClass) zope_interface)) return; // it can have any params
}
if (cls instanceof CythonClass && ((CythonClass)cls).isCppClass()) {
return;
}
// analyze function itself
PyUtil.MethodFlags flags = PyUtil.MethodFlags.of(node);
if (flags != null) {
@@ -6,6 +6,7 @@ import com.intellij.codeInspection.ui.ListEditForm;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
@@ -21,8 +22,6 @@ import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.util.Function;
import com.jetbrains.cython.psi.CythonCImportStatement;
import com.jetbrains.cython.psi.CythonFromCImportStatement;
import com.jetbrains.python.codeInsight.stdlib.PyStdlibUtil;
import com.jetbrains.python.packaging.*;
import com.jetbrains.python.packaging.ui.PyChooseRequirementsDialog;
@@ -111,9 +110,6 @@ public class PyPackageRequirementsInspection extends PyInspection {
@Override
public void visitPyFromImportStatement(PyFromImportStatement node) {
if (node instanceof CythonFromCImportStatement) {
return;
}
final PyReferenceExpression expr = node.getImportSource();
if (expr != null) {
checkPackageNameInRequirements(expr);
@@ -122,9 +118,6 @@ public class PyPackageRequirementsInspection extends PyInspection {
@Override
public void visitPyImportStatement(PyImportStatement node) {
if (node instanceof CythonCImportStatement) {
return;
}
for (PyImportElement element : node.getImportElements()) {
final PyReferenceExpression expr = element.getImportReferenceExpression();
if (expr != null) {
@@ -134,6 +127,11 @@ public class PyPackageRequirementsInspection extends PyInspection {
}
private void checkPackageNameInRequirements(@NotNull PyQualifiedExpression importedExpression) {
for (PyInspectionExtension extension : Extensions.getExtensions(PyInspectionExtension.EP_NAME)) {
if (extension.ignorePackageNameInRequirements(importedExpression)) {
return;
}
}
final List<PyExpression> expressions = PyResolveUtil.unwindQualifiers(importedExpression);
if (!expressions.isEmpty()) {
final PyExpression packageReferenceExpression = expressions.get(0);
@@ -15,9 +15,6 @@ import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Consumer;
import com.jetbrains.cython.psi.CythonFile;
import com.jetbrains.cython.types.CythonBuiltinType;
import com.jetbrains.cython.types.CythonType;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
@@ -233,9 +230,6 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
public void visitPyElement(final PyElement node) {
super.visitPyElement(node);
final PsiFile file = node.getContainingFile();
if (file instanceof CythonFile && ((CythonFile)file).isIncludeFile()) {
return;
}
final InjectedLanguageManager injectedLanguageManager =
InjectedLanguageManager.getInstance(node.getProject());
if (injectedLanguageManager.isInjectedFragment(file)) {
@@ -325,7 +319,16 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
unresolved = (target == null);
}
if (unresolved) {
registerUnresolvedReferenceProblem(node, reference, severity);
boolean ignoreUnresolved = false;
for (PyInspectionExtension extension : Extensions.getExtensions(PyInspectionExtension.EP_NAME)) {
if (extension.ignoreUnresolvedReference(node, reference)) {
ignoreUnresolved = true;
break;
}
}
if (!ignoreUnresolved) {
registerUnresolvedReferenceProblem(node, reference, severity);
}
// don't highlight unresolved imports as unused
if (node.getParent() instanceof PyImportElement) {
myAllImports.remove(node.getParent());
@@ -477,7 +480,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
if (qualifier != null) {
PyType qtype = myTypeEvalContext.getType(qualifier);
if (qtype != null) {
if (ignoreUnresolvedMemberForType(qtype, reference, ref_text)) {
if (ignoreUnresolvedMemberForType(qtype, reference, refname)) {
return;
}
addCreateMemberFromUsageFixes(qtype, reference, ref_text, actions);
@@ -628,7 +631,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
return null;
}
private boolean ignoreUnresolvedMemberForType(@NotNull PyType qtype, PsiReference reference, String refText) {
private boolean ignoreUnresolvedMemberForType(@NotNull PyType qtype, PsiReference reference, String name) {
if (qtype instanceof PyNoneType || PyTypeChecker.isUnknown(qtype)) {
// this almost always means that we don't know the type, so don't show an error in this case
return true;
@@ -644,7 +647,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
if (overridesGetAttr(cls, myTypeEvalContext)) {
return true;
}
if (cls.findProperty(refText) != null) {
if (cls.findProperty(name) != null) {
return true;
}
if (PyUtil.hasUnresolvedAncestors(cls, myTypeEvalContext)) {
@@ -653,11 +656,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
if (isDecoratedAsDynamic(cls, true)) {
return true;
}
if (hasUnresolvedDynamicMember((PyClassType)qtype, reference, refText)) return true;
}
if (qtype instanceof CythonBuiltinType ||
(qtype instanceof CythonType && reference instanceof PyOperatorReference)) {
return true;
if (hasUnresolvedDynamicMember((PyClassType)qtype, reference, name)) return true;
}
if (qtype instanceof PyFunctionType) {
final Callable callable = ((PyFunctionType)qtype).getCallable();
@@ -665,16 +664,21 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
return true;
}
}
for (PyInspectionExtension extension : Extensions.getExtensions(PyInspectionExtension.EP_NAME)) {
if (extension.ignoreUnresolvedMember(qtype, name)) {
return true;
}
}
return false;
}
private static boolean hasUnresolvedDynamicMember(@NotNull final PyClassType qtype,
PsiReference reference,
@NotNull final String refText) {
@NotNull final String name) {
for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) {
final Collection<PyDynamicMember> resolveResult = provider.getMembers(qtype, reference.getElement());
for (PyDynamicMember member : resolveResult) {
if (member.getName().equals(refText)) return true;
if (member.getName().equals(name)) return true;
}
}
return false;
@@ -817,6 +817,10 @@ public class PyUtil {
return name.startsWith("__") && !name.endsWith("__");
}
public static boolean isSpecialName(@NotNull String name) {
return name.length() > 4 && name.startsWith("__") && name.endsWith("__");
}
public static boolean isPythonIdentifier(@NotNull String name) {
return PyNames.isIdentifier(name);
}