Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

implementing detectors using OpcodeStackDetector, unit tests pass

  • Loading branch information...
commit bb497cbec44c8c1052c6e994b97bc409ef6d2d9c 1 parent 9547df9
heuermh authored
View
55 src/main/java/uk/me/tom_fitzhenry/findbugs/guice/PublicImplementationClassConstructorDetector.java
@@ -1,22 +1,69 @@
package uk.me.tom_fitzhenry.findbugs.guice;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+
+import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
-import edu.umd.cs.findbugs.Detector;
+import edu.umd.cs.findbugs.OpcodeStack;
import edu.umd.cs.findbugs.ba.ClassContext;
+import edu.umd.cs.findbugs.ba.ch.Subtypes2;
+import edu.umd.cs.findbugs.classfile.ClassDescriptor;
+import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
-public final class PublicImplementationClassConstructorDetector implements Detector {
+public final class PublicImplementationClassConstructorDetector extends OpcodeStackDetector {
+ static final String MODULE_NAME = "com.google.inject.Module";
+ private final BugReporter bugReporter;
+ private boolean isModule = false;
public PublicImplementationClassConstructorDetector(final BugReporter bugReporter) {
- // empty
+ this.bugReporter = bugReporter;
}
@Override
public void visitClassContext(final ClassContext classContext) {
- // empty
+ if (isModule(classContext.getClassDescriptor())) {
+ isModule = true;
+ }
+ super.visitClassContext(classContext);
+ }
+
+ @Override
+ public void sawOpcode(final int seen) {
+ if (isModule) {
+ switch (seen) {
+ case INVOKEVIRTUAL:
+ case INVOKEINTERFACE:
+ if (isCallingTo()) {
+ OpcodeStack.Item stackItem = stack.getStackItem(0);
+ try {
+ String implementationClassName = (String) stackItem.getConstant();
+ Class<?> implementationClass = Class.forName(implementationClassName.replace("/", "."));
+ for (Constructor<?> constructor : implementationClass.getDeclaredConstructors()) {
+ if (Modifier.isPublic(constructor.getModifiers())) {
+ bugReporter.reportBug(new BugInstance(this, "GUICE_PUBLIC_IMPLEMENTATION_CLASS_CONSTRUCTOR", NORMAL_PRIORITY).addClassAndMethod(this));
+ }
+ }
+ }
+ catch (Exception e) {
+ // ignore
+ }
+ }
+ break;
+ }
+ }
}
@Override
public void report() {
// empty
}
+
+ private boolean isCallingTo() {
+ return getNameConstantOperand().equals("to");
+ }
+
+ static boolean isModule(final ClassDescriptor classDescriptor) {
+ return Subtypes2.instanceOf(classDescriptor, MODULE_NAME);
+ }
}
View
52 src/main/java/uk/me/tom_fitzhenry/findbugs/guice/PublicImplementationClassDetector.java
@@ -1,22 +1,66 @@
package uk.me.tom_fitzhenry.findbugs.guice;
+import java.lang.reflect.Modifier;
+
+import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
-import edu.umd.cs.findbugs.Detector;
+import edu.umd.cs.findbugs.OpcodeStack;
import edu.umd.cs.findbugs.ba.ClassContext;
+import edu.umd.cs.findbugs.ba.ch.Subtypes2;
+import edu.umd.cs.findbugs.classfile.ClassDescriptor;
+import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
-public final class PublicImplementationClassDetector implements Detector {
+public final class PublicImplementationClassDetector extends OpcodeStackDetector {
+ static final String MODULE_NAME = "com.google.inject.Module";
+ private final BugReporter bugReporter;
+ private boolean isModule = false;
public PublicImplementationClassDetector(final BugReporter bugReporter) {
- // empty
+ this.bugReporter = bugReporter;
}
@Override
public void visitClassContext(final ClassContext classContext) {
- // empty
+ if (isModule(classContext.getClassDescriptor())) {
+ isModule = true;
+ }
+ super.visitClassContext(classContext);
+ }
+
+ @Override
+ public void sawOpcode(final int seen) {
+ if (isModule) {
+ switch (seen) {
+ case INVOKEVIRTUAL:
+ case INVOKEINTERFACE:
+ if (isCallingTo()) {
+ OpcodeStack.Item stackItem = stack.getStackItem(0);
+ try {
+ String implementationClassName = (String) stackItem.getConstant();
+ Class<?> implementationClass = Class.forName(implementationClassName.replace("/", "."));
+ if (Modifier.isPublic(implementationClass.getModifiers())) {
+ bugReporter.reportBug(new BugInstance(this, "GUICE_PUBLIC_IMPLEMENTATION_CLASS", NORMAL_PRIORITY).addClassAndMethod(this));
+ }
+ }
+ catch (Exception e) {
+ // ignore
+ }
+ }
+ break;
+ }
+ }
}
@Override
public void report() {
// empty
}
+
+ private boolean isCallingTo() {
+ return getNameConstantOperand().equals("to");
+ }
+
+ static boolean isModule(final ClassDescriptor classDescriptor) {
+ return Subtypes2.instanceOf(classDescriptor, MODULE_NAME);
+ }
}
View
11 src/test/benchmarks/uk/me/tom_fitzhenry/findbugs/guice/benchmarks/AModuleWithoutBindings.java
@@ -0,0 +1,11 @@
+package uk.me.tom_fitzhenry.findbugs.guice.benchmarks;
+
+import com.google.inject.AbstractModule;
+
+public class AModuleWithoutBindings extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ // empty
+ }
+}
View
19 src/test/java/uk/me/tom_fitzhenry/findbugs/guice/PublicImplementationClassConstructorDetectorTest.java
@@ -9,6 +9,7 @@
import uk.me.tom_fitzhenry.findbugs.guice.benchmarks.AModuleThatBindsPackagePrivateImplementationClassPackagePrivateConstructor;
import uk.me.tom_fitzhenry.findbugs.guice.benchmarks.AModuleThatBindsPublicImplementationClass;
import uk.me.tom_fitzhenry.findbugs.guice.benchmarks.AModuleThatBindsPublicImplementationClassPackagePrivateConstructor;
+import uk.me.tom_fitzhenry.findbugs.guice.benchmarks.AModuleWithoutBindings;
import com.youdevise.fbplugins.tdd4fb.DetectorAssert;
@@ -25,23 +26,33 @@ public void setUp() {
bugReporter = DetectorAssert.bugReporterForTesting();
detector = new PublicImplementationClassConstructorDetector(bugReporter);
}
-
+
@Test
public void publicImplementationClassConstructorIsReported() throws Exception {
assertBugReportedAgainstClass(AModuleThatBindsPublicImplementationClass.class);
assertBugReportedAgainstClass(AModuleThatBindsPackagePrivateImplementationClass.class);
}
-
+
@Test
public void packagePrivateImplementationClassConstructorIsNotReported() throws Exception {
assertNoBugsReportedForClass(AModuleThatBindsPublicImplementationClassPackagePrivateConstructor.class);
assertNoBugsReportedForClass(AModuleThatBindsPackagePrivateImplementationClassPackagePrivateConstructor.class);
}
-
+
+ @Test
+ public void notModuleIsNotReported() throws Exception {
+ assertNoBugsReportedForClass(Object.class);
+ }
+
+ @Test
+ public void moduleWithoutBindingsIsNotReported() throws Exception {
+ assertNoBugsReportedForClass(AModuleWithoutBindings.class);
+ }
+
private void assertBugReportedAgainstClass(Class<?> classToTest) throws Exception {
DetectorAssert.assertBugReported(classToTest, detector, bugReporter, ofType("GUICE_PUBLIC_IMPLEMENTATION_CLASS_CONSTRUCTOR"));
}
-
+
private void assertNoBugsReportedForClass(Class<?> classToTest) throws Exception {
DetectorAssert.assertNoBugsReported(classToTest, detector, bugReporter);
}
View
23 src/test/java/uk/me/tom_fitzhenry/findbugs/guice/PublicImplementationClassDetectorTest.java
@@ -7,6 +7,7 @@
import uk.me.tom_fitzhenry.findbugs.guice.benchmarks.AModuleThatBindsPackagePrivateImplementationClass;
import uk.me.tom_fitzhenry.findbugs.guice.benchmarks.AModuleThatBindsPublicImplementationClass;
+import uk.me.tom_fitzhenry.findbugs.guice.benchmarks.AModuleWithoutBindings;
import com.youdevise.fbplugins.tdd4fb.DetectorAssert;
@@ -17,29 +18,39 @@
private BugReporter bugReporter;
private Detector detector;
-
+
@Before
public void setUp() {
bugReporter = DetectorAssert.bugReporterForTesting();
detector = new PublicImplementationClassDetector(bugReporter);
}
-
+
@Test
public void publicImplementationClassIsReported() throws Exception {
assertBugReportedAgainstClass(AModuleThatBindsPublicImplementationClass.class);
}
-
+
@Test
public void packagePrivateImplementationClassIsNotReported() throws Exception {
assertNoBugsReportedForClass(AModuleThatBindsPackagePrivateImplementationClass.class);
}
-
+
+ @Test
+ public void notModuleIsNotReported() throws Exception {
+ assertNoBugsReportedForClass(Object.class);
+ }
+
+ @Test
+ public void moduleWithoutBindingsIsNotReported() throws Exception {
+ assertNoBugsReportedForClass(AModuleWithoutBindings.class);
+ }
+
private void assertBugReportedAgainstClass(Class<?> classToTest) throws Exception {
DetectorAssert.assertBugReported(classToTest, detector, bugReporter, ofType("GUICE_PUBLIC_IMPLEMENTATION_CLASS"));
}
-
+
private void assertNoBugsReportedForClass(Class<?> classToTest) throws Exception {
DetectorAssert.assertNoBugsReported(classToTest, detector, bugReporter);
}
-
+
}
Please sign in to comment.
Something went wrong with that request. Please try again.