aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/ClassVisitor.java2
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/MethodVisitor.java1
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/SuppressWarningsAnnotationUtils.java80
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/NoSonarFilterLoader.java27
-rw-r--r--plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/visitor/ClassVisitorTest.java9
-rw-r--r--plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/visitor/MethodVisitorTest.java22
-rw-r--r--plugins/sonar-squid-java-plugin/test-resources/rules/ClassWithSuppressWarningsAnnotation.java42
-rw-r--r--sonar-squid/src/main/java/org/sonar/squid/api/SourceClass.java13
-rw-r--r--sonar-squid/src/main/java/org/sonar/squid/api/SourceMethod.java13
9 files changed, 208 insertions, 1 deletions
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/ClassVisitor.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/ClassVisitor.java
index 993af7f8468..4995f90c4b0 100644
--- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/ClassVisitor.java
+++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/ClassVisitor.java
@@ -57,6 +57,7 @@ public class ClassVisitor extends JavaAstVisitor {
if (isAbstract(ast)) {
unit.setMeasure(Metric.ABSTRACT_CLASSES, 1);
}
+ unit.setSuppressWarnings(SuppressWarningsAnnotationUtils.isSuppressAllWarnings(ast));
}
@Override
@@ -86,4 +87,5 @@ public class ClassVisitor extends JavaAstVisitor {
static SourceClass createSourceClass(SourceClass parentClass, String innerClassName) {
return new SourceClass(parentClass.getKey() + "$" + innerClassName, innerClassName);
}
+
}
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/MethodVisitor.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/MethodVisitor.java
index afe8e9d366c..e1e08dcccab 100644
--- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/MethodVisitor.java
+++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/MethodVisitor.java
@@ -70,6 +70,7 @@ public class MethodVisitor extends JavaAstVisitor {
if (isConstructor) {
sourceMethod.setMeasure(Metric.CONSTRUCTORS, 1);
}
+ sourceMethod.setSuppressWarnings(SuppressWarningsAnnotationUtils.isSuppressAllWarnings(ast));
addSourceCode(sourceMethod);
}
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/SuppressWarningsAnnotationUtils.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/SuppressWarningsAnnotationUtils.java
new file mode 100644
index 00000000000..f35441b34a1
--- /dev/null
+++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/SuppressWarningsAnnotationUtils.java
@@ -0,0 +1,80 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+
+package org.sonar.java.ast.visitor;
+
+import com.puppycrawl.tools.checkstyle.api.AnnotationUtility;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+
+/**
+ * Inspired by {@link com.puppycrawl.tools.checkstyle.checks.annotation.SuppressWarningsCheck}
+ */
+public final class SuppressWarningsAnnotationUtils {
+
+ private final static String SUPPRESS_WARNINGS_ANNOTATION_NAME = "SuppressWarnings";
+ private final static String SUPPRESS_WARNINGS_ANNOTATION_FQ_NAME = "java.lang." + SUPPRESS_WARNINGS_ANNOTATION_NAME;
+ private final static String VALUE = "\"all\"";
+
+ public static boolean isSuppressAllWarnings(DetailAST ast) {
+ DetailAST suppressWarningsAnnotation = getSuppressWarningsAnnotation(ast);
+ if (suppressWarningsAnnotation != null) {
+ DetailAST warningHolder = findWarningsHolder(suppressWarningsAnnotation);
+ for (DetailAST warning = warningHolder.findFirstToken(TokenTypes.EXPR); warning != null; warning = warning.getNextSibling()) {
+ if (warning.getType() == TokenTypes.EXPR) {
+ DetailAST fChild = warning.getFirstChild();
+ if (fChild.getType() == TokenTypes.STRING_LITERAL) {
+ String text = warning.getFirstChild().getText();
+ if (VALUE.equals(text)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private static DetailAST findWarningsHolder(DetailAST aAnnotation) {
+ DetailAST annValuePair = aAnnotation.findFirstToken(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR);
+ DetailAST annArrayInit;
+ if (annValuePair != null) {
+ annArrayInit = annValuePair.findFirstToken(TokenTypes.ANNOTATION_ARRAY_INIT);
+ } else {
+ annArrayInit = aAnnotation.findFirstToken(TokenTypes.ANNOTATION_ARRAY_INIT);
+ }
+ if (annArrayInit != null) {
+ return annArrayInit;
+ }
+ return aAnnotation;
+ }
+
+ private static DetailAST getSuppressWarningsAnnotation(DetailAST ast) {
+ DetailAST annotation = AnnotationUtility.getAnnotation(ast, SUPPRESS_WARNINGS_ANNOTATION_NAME);
+ if (annotation == null) {
+ annotation = AnnotationUtility.getAnnotation(ast, SUPPRESS_WARNINGS_ANNOTATION_FQ_NAME);
+ }
+ return annotation;
+ }
+
+ private SuppressWarningsAnnotationUtils() {
+ }
+
+}
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/NoSonarFilterLoader.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/NoSonarFilterLoader.java
index c727a8db0b0..1fd831fc4c2 100644
--- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/NoSonarFilterLoader.java
+++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/NoSonarFilterLoader.java
@@ -19,9 +19,16 @@
*/
package org.sonar.plugins.squid.bridges;
+import java.util.HashSet;
+import java.util.Set;
+
import org.sonar.api.checks.NoSonarFilter;
import org.sonar.api.resources.Resource;
+import org.sonar.squid.api.SourceClass;
+import org.sonar.squid.api.SourceCode;
import org.sonar.squid.api.SourceFile;
+import org.sonar.squid.api.SourceMethod;
+import org.sonar.squid.indexer.QueryByParent;
public class NoSonarFilterLoader extends Bridge {
private NoSonarFilter noSonarFilter;
@@ -34,7 +41,25 @@ public class NoSonarFilterLoader extends Bridge {
@Override
public void onFile(SourceFile squidFile, Resource sonarFile) {
if (noSonarFilter != null) {
- noSonarFilter.addResource(sonarFile, squidFile.getNoSonarTagLines());
+ // lines with NOSONAR tag
+ Set<Integer> ignoredLines = new HashSet<Integer>(squidFile.getNoSonarTagLines());
+ // classes and methods with annotaion SuppressWarnings
+ for (SourceCode sourceCode : squid.search(new QueryByParent(squidFile))) {
+ if (sourceCode instanceof SourceMethod && ((SourceMethod) sourceCode).isSuppressWarnings()) {
+ visitLines(sourceCode, ignoredLines);
+ }
+ if (sourceCode instanceof SourceClass && ((SourceClass) sourceCode).isSuppressWarnings()) {
+ visitLines(sourceCode, ignoredLines);
+ }
+ }
+
+ noSonarFilter.addResource(sonarFile, ignoredLines);
+ }
+ }
+
+ private static void visitLines(SourceCode sourceCode, Set<Integer> ignoredLines) {
+ for (int line = sourceCode.getStartAtLine(); line <= sourceCode.getEndAtLine(); line++) {
+ ignoredLines.add(line);
}
}
}
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/visitor/ClassVisitorTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/visitor/ClassVisitorTest.java
index bef90bb87fa..421fae7069f 100644
--- a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/visitor/ClassVisitorTest.java
+++ b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/visitor/ClassVisitorTest.java
@@ -19,8 +19,10 @@
*/
package org.sonar.java.ast.visitor;
+import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.sonar.java.ast.SquidTestUtils.getFile;
@@ -121,6 +123,13 @@ public class ClassVisitorTest {
}
@Test
+ public void detectSuppressWarningsAnnotation() {
+ squid.register(JavaAstScanner.class).scanFile(getFile("/rules/ClassWithSuppressWarningsAnnotation.java"));
+ SourceClass sourceClass = (SourceClass) squid.search("ClassWithSuppressWarningsAnnotation");
+ assertThat(sourceClass.isSuppressWarnings(), is(true));
+ }
+
+ @Test
public void testCreateSquidClassFromPackage() {
SourceClass squidClass = ClassVisitor.createSourceClass(new SourcePackage("org/sonar"), "Squid");
assertEquals("org/sonar/Squid", squidClass.getKey());
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/visitor/MethodVisitorTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/visitor/MethodVisitorTest.java
index 622c4afdf71..52f955842f4 100644
--- a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/visitor/MethodVisitorTest.java
+++ b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/visitor/MethodVisitorTest.java
@@ -19,8 +19,10 @@
*/
package org.sonar.java.ast.visitor;
+import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
import static org.sonar.java.ast.SquidTestUtils.getFile;
import org.junit.Before;
@@ -89,4 +91,24 @@ public class MethodVisitorTest {
SourceCode source = squid.decorateSourceCodeTreeWith(Metric.values());
assertEquals(2, source.getInt(Metric.CONSTRUCTORS));
}
+
+ @Test
+ public void detectSuppressWarningsAnnotation() {
+ squid.register(JavaAstScanner.class).scanFile(getFile("/rules/ClassWithSuppressWarningsAnnotation.java"));
+
+ assertThat(getMethod("ClassWithSuppressWarningsAnnotation#fullyQualifiedName()V").isSuppressWarnings(), is(true));
+ assertThat(getMethod("ClassWithSuppressWarningsAnnotation#singleValue()V").isSuppressWarnings(), is(true));
+ assertThat(getMethod("ClassWithSuppressWarningsAnnotation#arrayWithSingleValue()V").isSuppressWarnings(), is(true));
+ assertThat(getMethod("ClassWithSuppressWarningsAnnotation#arrayWithMultipleValues()V").isSuppressWarnings(), is(true));
+ assertThat(getMethod("ClassWithSuppressWarningsAnnotation$1#methodInAnonymousInnerClass()V").isSuppressWarnings(), is(true));
+
+ assertThat(getMethod("ClassWithSuppressWarningsAnnotation#notHandled()V").isSuppressWarnings(), is(false));
+ assertThat(getMethod("ClassWithSuppressWarningsAnnotation#notHandled2()V").isSuppressWarnings(), is(false));
+ assertThat(getMethod("ClassWithSuppressWarningsAnnotation#notHandled3()V").isSuppressWarnings(), is(false));
+ }
+
+ private SourceMethod getMethod(String key) {
+ return (SourceMethod) squid.search(key);
+ }
+
}
diff --git a/plugins/sonar-squid-java-plugin/test-resources/rules/ClassWithSuppressWarningsAnnotation.java b/plugins/sonar-squid-java-plugin/test-resources/rules/ClassWithSuppressWarningsAnnotation.java
new file mode 100644
index 00000000000..b91bb86843b
--- /dev/null
+++ b/plugins/sonar-squid-java-plugin/test-resources/rules/ClassWithSuppressWarningsAnnotation.java
@@ -0,0 +1,42 @@
+@SuppressWarnings("all")
+class ClassWithSuppressWarningsAnnotation {
+
+ @java.lang.SuppressWarnings("all")
+ public void fullyQualifiedName() {
+ }
+
+ @SuppressWarnings("all")
+ public void singleValue() {
+ }
+
+ @SuppressWarnings(value = { "all" })
+ public void arrayWithSingleValue() {
+ }
+
+ @SuppressWarnings(value = { "null", "all" })
+ public void arrayWithMultipleValues() {
+ }
+
+ public void doJob() {
+ Object o = new Object() {
+ @SuppressWarnings("all")
+ public void methodInAnonymousInnerClass() {
+ }
+ };
+ }
+
+ // Currently Sonar is unable to properly handle following cases
+
+ @SuppressWarnings("a" + "ll")
+ public void notHandled() {
+ }
+
+ @SuppressWarnings(false ? "null" : "all")
+ public void notHandled2() {
+ }
+
+ private static final String SUPPRESS = "all";
+ @SuppressWarnings(SUPPRESS)
+ public void notHandled3() {
+ }
+}
diff --git a/sonar-squid/src/main/java/org/sonar/squid/api/SourceClass.java b/sonar-squid/src/main/java/org/sonar/squid/api/SourceClass.java
index 20287f283f1..1be1ceef863 100644
--- a/sonar-squid/src/main/java/org/sonar/squid/api/SourceClass.java
+++ b/sonar-squid/src/main/java/org/sonar/squid/api/SourceClass.java
@@ -21,6 +21,11 @@ package org.sonar.squid.api;
public class SourceClass extends SourceCode {
+ /**
+ * This is used only for Java for now, but can be used for other languages. So maybe we should push it down to SourceCode.
+ */
+ private boolean suppressWarnings = false;
+
public SourceClass(String key) {
super(key);
}
@@ -28,4 +33,12 @@ public class SourceClass extends SourceCode {
public SourceClass(String key, String className) {
super(key, className);
}
+
+ public void setSuppressWarnings(boolean suppressWarnings) {
+ this.suppressWarnings = suppressWarnings;
+ }
+
+ public boolean isSuppressWarnings() {
+ return suppressWarnings;
+ }
}
diff --git a/sonar-squid/src/main/java/org/sonar/squid/api/SourceMethod.java b/sonar-squid/src/main/java/org/sonar/squid/api/SourceMethod.java
index 0378f655da4..60eab9faf2a 100644
--- a/sonar-squid/src/main/java/org/sonar/squid/api/SourceMethod.java
+++ b/sonar-squid/src/main/java/org/sonar/squid/api/SourceMethod.java
@@ -23,6 +23,11 @@ import org.sonar.squid.measures.Metric;
public class SourceMethod extends SourceCode {
+ /**
+ * This is used only for Java for now, but can be used for other languages. So maybe we should push it down to SourceCode.
+ */
+ private boolean suppressWarnings = false;
+
public SourceMethod(String key) {
super(key);
}
@@ -35,4 +40,12 @@ public class SourceMethod extends SourceCode {
public boolean isAccessor() {
return getInt(Metric.ACCESSORS) != 0;
}
+
+ public void setSuppressWarnings(boolean suppressWarnings) {
+ this.suppressWarnings = suppressWarnings;
+ }
+
+ public boolean isSuppressWarnings() {
+ return suppressWarnings;
+ }
}