diff --git a/README.md b/README.md
index 27ad839..39e3440 100755
--- a/README.md
+++ b/README.md
@@ -30,6 +30,7 @@ To use this product, please configure your findbugs-maven-plugin like below.
## 0.0.3
- added UnexpectedAccessDetector
+- added UndocumentedSuppressFBWarningsDetector
## 0.0.2
diff --git a/src/main/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressFBWarningsDetector.java b/src/main/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressFBWarningsDetector.java
new file mode 100644
index 0000000..14e9294
--- /dev/null
+++ b/src/main/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressFBWarningsDetector.java
@@ -0,0 +1,57 @@
+package jp.co.worksap.oss.findbugs.findbugs;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.apache.bcel.classfile.ElementValue;
+
+import com.google.common.collect.Sets;
+
+import edu.umd.cs.findbugs.BugInstance;
+import edu.umd.cs.findbugs.BugReporter;
+import edu.umd.cs.findbugs.BytecodeScanningDetector;
+import edu.umd.cs.findbugs.internalAnnotations.DottedClassName;
+
+/**
+ *
A detector to ensure that FindBugs' SuppressWarnings annotation has justification.
+ * @see edu.umd.cs.findbugs.annotations.SuppressWarnings
+ * @see edu.umd.cs.findbugs.annotations.SuppressFBWarnings
+ * @author Kengo TODA (toda_k@worksap.co.jp)
+ */
+public class UndocumentedSuppressFBWarningsDetector extends BytecodeScanningDetector {
+ private static final Set TARGET_ANNOTATIONS = Collections.unmodifiableSet(Sets.newHashSet(
+ "edu.umd.cs.findbugs.annotations.SuppressWarnings",
+ "edu.umd.cs.findbugs.annotations.SuppressFBWarnings"
+ ));
+
+ @Nonnull
+ private final BugReporter bugReporter;
+
+ public UndocumentedSuppressFBWarningsDetector(BugReporter bugReporter) {
+ this.bugReporter = checkNotNull(bugReporter);
+ }
+
+ @Override
+ public void visitAnnotation(@DottedClassName String annotationClass,
+ Map map, boolean runtimeVisible) {
+ if (! TARGET_ANNOTATIONS.contains(annotationClass)) {
+ return;
+ }
+
+ final ElementValue reason = map.get("justification");
+ if (reason == null || reason.stringifyValue().trim().isEmpty()) {
+ BugInstance bugInstance = new BugInstance("FINDBUGS_UNDOCUMENTED_SUPPRESS_WARNINGS",
+ HIGH_PRIORITY).addClass(this);
+ if (visitingMethod()) {
+ bugInstance.addMethod(this).addSourceLine(this);
+ }
+ bugReporter.reportBug(bugInstance);
+ }
+ }
+
+}
diff --git a/src/main/meta/bugrank.txt b/src/main/meta/bugrank.txt
index cef2572..3a8eb57 100755
--- a/src/main/meta/bugrank.txt
+++ b/src/main/meta/bugrank.txt
@@ -13,3 +13,4 @@
0 BugPattern USE_COLUMN_DEFINITION
0 BugPattern NULLABLE_PRIMITIVE
0 BugPattern GUAVA_UNEXPECTED_ACCESS_TO_VISIBLE_FOR_TESTING
+0 BugPattern FINDBUGS_UNDOCUMENTED_SUPPRESS_WARNINGS
diff --git a/src/main/meta/findbugs.xml b/src/main/meta/findbugs.xml
index a7885f7..5569f15 100755
--- a/src/main/meta/findbugs.xml
+++ b/src/main/meta/findbugs.xml
@@ -69,4 +69,9 @@
+
+
+
diff --git a/src/main/meta/messages.xml b/src/main/meta/messages.xml
index a39bac3..cdc8df8 100755
--- a/src/main/meta/messages.xml
+++ b/src/main/meta/messages.xml
@@ -287,9 +287,29 @@
+
+
+ This detector will find suppressed FindBugs warning which has no justification about why it is suppressed.
+
+
+
+
+ To tell why this FindBugs warning is suppressed, put justification as a parameter.
+
+
+ To tell why this FindBugs warning is suppressed, put justification as a parameter.
+
+
+ To tell why this FindBugs warning is suppressed, put justification as a parameter.
+ ]]>
+
+
+
SYS
JSR305
JPA
JUnit
Google Guava
+ FindBugs
\ No newline at end of file
diff --git a/src/test/java/jp/co/worksap/oss/findbugs/findbugs/DocumentedSuppressFBWarnings.java b/src/test/java/jp/co/worksap/oss/findbugs/findbugs/DocumentedSuppressFBWarnings.java
new file mode 100644
index 0000000..11f4b37
--- /dev/null
+++ b/src/test/java/jp/co/worksap/oss/findbugs/findbugs/DocumentedSuppressFBWarnings.java
@@ -0,0 +1,9 @@
+package jp.co.worksap.oss.findbugs.findbugs;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+public class DocumentedSuppressFBWarnings {
+ @SuppressFBWarnings(justification = "only for unit test.")
+ public void method() {
+ }
+}
diff --git a/src/test/java/jp/co/worksap/oss/findbugs/findbugs/DocumentedSuppressWarnings.java b/src/test/java/jp/co/worksap/oss/findbugs/findbugs/DocumentedSuppressWarnings.java
new file mode 100644
index 0000000..0c8af59
--- /dev/null
+++ b/src/test/java/jp/co/worksap/oss/findbugs/findbugs/DocumentedSuppressWarnings.java
@@ -0,0 +1,8 @@
+package jp.co.worksap.oss.findbugs.findbugs;
+
+import edu.umd.cs.findbugs.annotations.SuppressWarnings;
+
+@SuppressWarnings(justification = "only for unit test.")
+public class DocumentedSuppressWarnings {
+
+}
diff --git a/src/test/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressFBWarnings.java b/src/test/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressFBWarnings.java
new file mode 100644
index 0000000..fde0dff
--- /dev/null
+++ b/src/test/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressFBWarnings.java
@@ -0,0 +1,9 @@
+package jp.co.worksap.oss.findbugs.findbugs;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+public class UndocumentedSuppressFBWarnings {
+ @SuppressFBWarnings
+ public void method() {
+ }
+}
diff --git a/src/test/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressFBWarningsDetectorTest.java b/src/test/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressFBWarningsDetectorTest.java
new file mode 100644
index 0000000..5db2427
--- /dev/null
+++ b/src/test/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressFBWarningsDetectorTest.java
@@ -0,0 +1,33 @@
+package jp.co.worksap.oss.findbugs.findbugs;
+
+import static com.youdevise.fbplugins.tdd4fb.DetectorAssert.*;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import edu.umd.cs.findbugs.BugReporter;
+
+public class UndocumentedSuppressFBWarningsDetectorTest {
+
+ private UndocumentedSuppressFBWarningsDetector detector;
+ private BugReporter bugReporter;
+
+ @Before
+ public void setup() {
+ bugReporter = bugReporterForTesting();
+ detector = new UndocumentedSuppressFBWarningsDetector(bugReporter);
+ }
+
+ @Test
+ public void testDocumentedClasses() throws Exception {
+ assertNoBugsReported(DocumentedSuppressWarnings.class, detector, bugReporter);
+ assertNoBugsReported(DocumentedSuppressFBWarnings.class, detector, bugReporter);
+ }
+
+ @Test
+ public void testUndocumentedClasses() throws Exception {
+ assertBugReported(UndocumentedSuppressWarnings.class, detector, bugReporter, ofType("FINDBUGS_UNDOCUMENTED_SUPPRESS_WARNINGS"));
+ assertBugReported(UndocumentedSuppressFBWarnings.class, detector, bugReporter, ofType("FINDBUGS_UNDOCUMENTED_SUPPRESS_WARNINGS"));
+ }
+
+}
diff --git a/src/test/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressWarnings.java b/src/test/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressWarnings.java
new file mode 100644
index 0000000..c56072b
--- /dev/null
+++ b/src/test/java/jp/co/worksap/oss/findbugs/findbugs/UndocumentedSuppressWarnings.java
@@ -0,0 +1,8 @@
+package jp.co.worksap.oss.findbugs.findbugs;
+
+import edu.umd.cs.findbugs.annotations.SuppressWarnings;
+
+@SuppressWarnings
+public class UndocumentedSuppressWarnings {
+
+}