diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml
index d669cb89a7be..5e4a1951c0c7 100644
--- a/python/src/META-INF/python-core.xml
+++ b/python/src/META-INF/python-core.xml
@@ -281,74 +281,74 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -542,6 +542,7 @@
+
diff --git a/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java b/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java
index ca73f0d89cce..790ff7b0a21f 100644
--- a/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java
@@ -21,19 +21,16 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.codeInspection.LocalInspectionToolSession;
import com.intellij.codeInspection.ProblemsHolder;
-import com.intellij.codeInspection.SuppressQuickFix;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
-import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.documentation.DocStringUtil;
import com.jetbrains.python.inspections.quickfix.DocstringQuickFix;
-import com.jetbrains.python.inspections.quickfix.PySuppressInspectionFix;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.testing.PythonUnitTestUtil;
import com.jetbrains.python.toolbox.Substring;
@@ -229,19 +226,4 @@ public class PyDocstringInspection extends PyInspection {
return hasMissing ? missing : Collections.emptyList();
}
}
-
- @NotNull
- @Override
- public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
- List result = new ArrayList();
- if (element != null) {
- if (PsiTreeUtil.getParentOfType(element, PyFunction.class) != null) {
- result.add(new PySuppressInspectionFix(getShortName().replace("Inspection", ""), "Suppress for function", PyFunction.class));
- }
- if (PsiTreeUtil.getParentOfType(element, PyClass.class) != null) {
- result.add(new PySuppressInspectionFix(getShortName().replace("Inspection", ""), "Suppress for class", PyClass.class));
- }
- }
- return result.toArray(new SuppressQuickFix[result.size()]);
- }
}
diff --git a/python/src/com/jetbrains/python/inspections/PyInspection.java b/python/src/com/jetbrains/python/inspections/PyInspection.java
index 993dcdcb22f3..bbc064d5c89a 100644
--- a/python/src/com/jetbrains/python/inspections/PyInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyInspection.java
@@ -16,31 +16,26 @@
package com.jetbrains.python.inspections;
import com.intellij.codeInspection.LocalInspectionTool;
-import com.intellij.codeInspection.SuppressQuickFix;
-import com.intellij.codeInspection.SuppressionUtil;
-import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.PyBundle;
-import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
-import com.jetbrains.python.inspections.quickfix.PySuppressInspectionFix;
-import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.PyExpressionCodeFragment;
import com.jetbrains.python.psi.impl.PyFileImpl;
+import org.intellij.lang.annotations.Pattern;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @author yole
- */
public abstract class PyInspection extends LocalInspectionTool {
+ @Pattern(VALID_ID_PATTERN)
+ @NotNull
+ @Override
+ public String getID() {
+ //noinspection PatternValidation
+ return getShortName(super.getID());
+ }
+
@Nls
@NotNull
@Override
@@ -59,80 +54,20 @@ public abstract class PyInspection extends LocalInspectionTool {
return true;
}
- @NotNull
- @Override
- public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
- List result = new ArrayList();
- result.add(new PySuppressInspectionFix(getSuppressId(), "Suppress for statement", PyStatement.class) {
- @Override
- public PsiElement getContainer(PsiElement context) {
- if (PsiTreeUtil.getParentOfType(context, PyStatementList.class, false, ScopeOwner.class) != null ||
- PsiTreeUtil.getParentOfType(context, PyFunction.class, PyClass.class) == null) {
- return super.getContainer(context);
- }
- return null;
- }
- });
- result.add(new PySuppressInspectionFix(getSuppressId(), "Suppress for function", PyFunction.class));
- result.add(new PySuppressInspectionFix(getSuppressId(), "Suppress for class", PyClass.class));
- return result.toArray(new SuppressQuickFix[result.size()]);
- }
-
@Override
public boolean isSuppressedFor(@NotNull PsiElement element) {
final PsiFile file = element.getContainingFile();
- boolean isAccepted = true;
- if (file instanceof PyFileImpl) {
- isAccepted = ((PyFileImpl)file).isAcceptedFor(this.getClass());
+ if (file instanceof PyFileImpl && !((PyFileImpl)file).isAcceptedFor(this.getClass())) {
+ return true;
}
- return !isAccepted || isSuppressedForParent(element, PyStatement.class) ||
- isSuppressedForParent(element, PyFunction.class) ||
- isSuppressedForParent(element, PyClass.class) ||
- isSuppressForCodeFragment(element);
+ return isSuppressForCodeFragment(element) || super.isSuppressedFor(element);
}
- private boolean isSuppressForCodeFragment(PsiElement element) {
+ private boolean isSuppressForCodeFragment(@Nullable PsiElement element) {
return isSuppressForCodeFragment() && PsiTreeUtil.getParentOfType(element, PyExpressionCodeFragment.class) != null;
}
protected boolean isSuppressForCodeFragment() {
return false;
}
-
- private boolean isSuppressedForParent(PsiElement element, final Class extends PyElement> parentClass) {
- PyElement parent = PsiTreeUtil.getParentOfType(element, parentClass, false);
- if (parent == null) {
- return false;
- }
- return isSuppressedForElement(parent);
- }
-
- private boolean isSuppressedForElement(PyElement stmt) {
- PsiElement prevSibling = stmt.getPrevSibling();
- if (prevSibling == null) {
- final PsiElement parent = stmt.getParent();
- if (parent != null) {
- prevSibling = parent.getPrevSibling();
- }
- }
- while (prevSibling instanceof PsiComment || prevSibling instanceof PsiWhiteSpace) {
- if (prevSibling instanceof PsiComment && isSuppressedInComment(prevSibling.getText().substring(1).trim())) {
- return true;
- }
- prevSibling = prevSibling.getPrevSibling();
- }
- return false;
- }
-
- private static final Pattern SUPPRESS_PATTERN = Pattern.compile(SuppressionUtil.COMMON_SUPPRESS_REGEXP);
-
- private boolean isSuppressedInComment(String commentText) {
- Matcher m = SUPPRESS_PATTERN.matcher(commentText);
- return m.matches() && SuppressionUtil.isInspectionToolIdMentioned(m.group(1), getSuppressId());
- }
-
- @NotNull
- protected String getSuppressId() {
- return getShortName().replace("Inspection", "");
- }
}
diff --git a/python/src/com/jetbrains/python/inspections/PyInspectionsSuppressor.java b/python/src/com/jetbrains/python/inspections/PyInspectionsSuppressor.java
new file mode 100644
index 000000000000..545c1b37e46d
--- /dev/null
+++ b/python/src/com/jetbrains/python/inspections/PyInspectionsSuppressor.java
@@ -0,0 +1,88 @@
+package com.jetbrains.python.inspections;
+
+import com.intellij.codeInspection.InspectionSuppressor;
+import com.intellij.codeInspection.SuppressQuickFix;
+import com.intellij.codeInspection.SuppressionUtil;
+import com.intellij.psi.PsiComment;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.inspections.quickfix.PySuppressInspectionFix;
+import com.jetbrains.python.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PyInspectionsSuppressor implements InspectionSuppressor {
+ private static final Pattern SUPPRESS_PATTERN = Pattern.compile(SuppressionUtil.COMMON_SUPPRESS_REGEXP);
+ private static final String PY_DOCSTRING_INSPECTION_ID = new PyDocstringInspection().getID();
+
+ @NotNull
+ @Override
+ public SuppressQuickFix[] getSuppressActions(@Nullable PsiElement element, @NotNull String toolId) {
+ if (PY_DOCSTRING_INSPECTION_ID.equals(toolId)) {
+ return new SuppressQuickFix[]{
+ new PySuppressInspectionFix(toolId, "Suppress for function", PyFunction.class),
+ new PySuppressInspectionFix(toolId, "Suppress for class", PyClass.class)
+ };
+ }
+ else {
+ return new SuppressQuickFix[]{
+ new PySuppressInspectionFix(toolId, "Suppress for statement", PyStatement.class) {
+ @Override
+ public PsiElement getContainer(PsiElement context) {
+ if (PsiTreeUtil.getParentOfType(context, PyStatementList.class, false, ScopeOwner.class) != null ||
+ PsiTreeUtil.getParentOfType(context, PyFunction.class, PyClass.class) == null) {
+ return super.getContainer(context);
+ }
+ return null;
+ }
+ },
+ new PySuppressInspectionFix(toolId, "Suppress for function", PyFunction.class),
+ new PySuppressInspectionFix(toolId, "Suppress for class", PyClass.class)
+ };
+ }
+ }
+
+ @Override
+ public boolean isSuppressedFor(@NotNull PsiElement element, @NotNull String toolId) {
+ return isSuppressedForParent(element, PyStatement.class, toolId) ||
+ isSuppressedForParent(element, PyFunction.class, toolId) ||
+ isSuppressedForParent(element, PyClass.class, toolId);
+ }
+
+ private static boolean isSuppressedForParent(@NotNull PsiElement element,
+ @NotNull final Class extends PyElement> parentClass,
+ @NotNull String suppressId) {
+ PyElement parent = PsiTreeUtil.getParentOfType(element, parentClass, false);
+ if (parent == null) {
+ return false;
+ }
+ return isSuppressedForElement(parent, suppressId);
+ }
+
+ private static boolean isSuppressedForElement(@NotNull PyElement stmt, @NotNull String suppressId) {
+ PsiElement prevSibling = stmt.getPrevSibling();
+ if (prevSibling == null) {
+ final PsiElement parent = stmt.getParent();
+ if (parent != null) {
+ prevSibling = parent.getPrevSibling();
+ }
+ }
+ while (prevSibling instanceof PsiComment || prevSibling instanceof PsiWhiteSpace) {
+ if (prevSibling instanceof PsiComment && isSuppressedInComment(prevSibling.getText().substring(1).trim(), suppressId)) {
+ return true;
+ }
+ prevSibling = prevSibling.getPrevSibling();
+ }
+ return false;
+ }
+
+ private static boolean isSuppressedInComment(@NotNull String commentText, @NotNull String suppressId) {
+ Matcher m = SUPPRESS_PATTERN.matcher(commentText);
+ return m.matches() && SuppressionUtil.isInspectionToolIdMentioned(m.group(1), suppressId);
+ }
+}
diff --git a/python/testData/inspections/suppress/suppressInsideInjection.py b/python/testData/inspections/suppress/suppressInsideInjection.py
new file mode 100644
index 000000000000..a81f71a27282
--- /dev/null
+++ b/python/testData/inspections/suppress/suppressInsideInjection.py
@@ -0,0 +1,3 @@
+# language=Python
+print "# noinspection PyUnresolvedReferences\
+print xxx"
\ No newline at end of file
diff --git a/python/testData/inspections/suppress/suppressOutsideInjection.py b/python/testData/inspections/suppress/suppressOutsideInjection.py
new file mode 100644
index 000000000000..911cbc5dbd58
--- /dev/null
+++ b/python/testData/inspections/suppress/suppressOutsideInjection.py
@@ -0,0 +1,3 @@
+# noinspection PyUnresolvedReferences
+#language=Python
+print "print xxx"
\ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/PySuppressInspectionsTest.java b/python/testSrc/com/jetbrains/python/PySuppressInspectionsTest.java
index 1eab5f2ed627..0a049b9ce2e3 100644
--- a/python/testSrc/com/jetbrains/python/PySuppressInspectionsTest.java
+++ b/python/testSrc/com/jetbrains/python/PySuppressInspectionsTest.java
@@ -18,14 +18,11 @@ package com.jetbrains.python;
import com.intellij.codeInsight.intention.IntentionAction;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.inspections.PyInspection;
-import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection;
import com.jetbrains.python.inspections.PyUnusedLocalInspection;
+import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection;
import java.util.List;
-/**
- * @author yole
- */
public class PySuppressInspectionsTest extends PyTestCase {
public void testSuppressedForStatement() {
doTestHighlighting(PyUnresolvedReferencesInspection.class);
@@ -46,7 +43,15 @@ public class PySuppressInspectionsTest extends PyTestCase {
public void testSuppressForImport() { // PY-2240
doTestHighlighting(PyUnresolvedReferencesInspection.class);
}
+
+ public void testSuppressInsideInjection() {
+ doTestHighlighting(PyUnresolvedReferencesInspection.class);
+ }
+ public void testSuppressOutsideInjection() {
+ doTestHighlighting(PyUnresolvedReferencesInspection.class);
+ }
+
private void doTestHighlighting(final Class extends PyInspection> inspectionClass) {
myFixture.configureByFile("inspections/suppress/" + getTestName(true) + ".py");
myFixture.enableInspections(inspectionClass);