]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2038 LCOM4 value is incorrect when mixing getter/setter and direct field access
authorDinesh Bolkensteyn <dinesh@dinsoft.net>
Mon, 24 Oct 2011 13:38:20 +0000 (15:38 +0200)
committerDinesh Bolkensteyn <dinesh@dinsoft.net>
Mon, 24 Oct 2011 20:32:54 +0000 (22:32 +0200)
plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/asm/AsmMethod.java
plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/visitor/AccessorVisitor.java
plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/visitor/LCOM4Visitor.java
plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/visitor/AccessorVisitorTest.java
plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/visitor/LCOM4VisitorTest.java

index bce75c3bd76029a00944704e120cd0fc4aa360b8..5104162d148623eb024294b856fd14e029d5e850 100644 (file)
@@ -31,7 +31,7 @@ public class AsmMethod extends AsmResource {
   private boolean inherited = false;
   private boolean empty = false;
   private boolean bodyLoaded = true;
-  private boolean accessor = false;
+  private AsmField accessedField = null;
   private String signature;
   private AsmMethod implementationLinkage = null;
 
@@ -140,11 +140,15 @@ public class AsmMethod extends AsmResource {
   }
 
   public boolean isAccessor() {
-    return accessor;
+    return accessedField != null;
+  }
+  
+  public AsmField getAccessedField() {
+    return accessedField;
   }
 
-  public void setAccessor(boolean accessor) {
-    this.accessor = accessor;
+  public void setAccessedField(AsmField accessedField) {
+    this.accessedField = accessedField;
   }
 
   @Override
index 46b52d1b0239a9a8962fa2b3a0dc8bc665f8ad66..4dcbccc898f75e4a1b44c8d6a2dcbebe69a19252 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.java.bytecode.visitor;
 
 import org.sonar.java.bytecode.asm.AsmClass;
+import org.sonar.java.bytecode.asm.AsmField;
 import org.sonar.java.bytecode.asm.AsmMethod;
 
 public class AccessorVisitor extends BytecodeVisitor {
@@ -32,8 +33,9 @@ public class AccessorVisitor extends BytecodeVisitor {
 
   public void visitMethod(AsmMethod asmMethod) {
     String propertyName = extractPropertyNameFromMethodName(asmMethod);
-    if (propertyName != null && asmClass.getField(propertyName) != null) {
-      asmMethod.setAccessor(true);
+    AsmField accessedField = asmClass.getField(propertyName);
+    if (propertyName != null && accessedField != null) {
+      asmMethod.setAccessedField(accessedField);
     }
   }
 
index df49ca4e500c29bbb5d33546b118318386e5a15c..a3598b3da1222f08d24edb5ee36523ac37dac395 100644 (file)
@@ -50,13 +50,15 @@ public class LCOM4Visitor extends BytecodeVisitor {
 
   public void visitMethod(AsmMethod asmMethod) {
     if (isMethodElligibleForLCOM4Computation(asmMethod)) {
-      Set<AsmResource> block = getResourceBlockOrCreateIt(asmMethod);
+      ensureBlockIsCreated(asmMethod);
       for (AsmEdge edge : asmMethod.getOutgoingEdges()) {
         if (isCallToInternalFieldOrMethod(edge) && isNotCallToExcludedFieldFromLcom4Calculation(edge.getTo())) {
           AsmResource toResource = edge.getTo();
-          mergeAsmResourceToBlock(block, toResource);
+          linkAsmResources(asmMethod, toResource);
         }
       }
+    } else if (asmMethod.isAccessor()) {
+      linkAsmResources(asmMethod, asmMethod.getAccessedField());
     }
   }
 
@@ -87,19 +89,21 @@ public class LCOM4Visitor extends BytecodeVisitor {
       getSourceFile(asmClass).addData(Metric.LCOM4_BLOCKS, unrelatedBlocks);
     }
   }
-
-  private void mergeAsmResourceToBlock(Set<AsmResource> block, AsmResource toResource) {
-    if (block.contains(toResource)) {
+  
+  private void ensureBlockIsCreated(AsmResource resource) {
+    getOrCreateResourceBlock(resource);
+  }
+  
+  private void linkAsmResources(AsmResource resourceA, AsmResource resourceB) {
+    Set<AsmResource> blockA = getOrCreateResourceBlock(resourceA);
+    Set<AsmResource> blockB = getOrCreateResourceBlock(resourceB);
+    
+    if (blockA == blockB) {
       return;
     }
-    Set<AsmResource> otherBlock = getResourceBlock(toResource);
-    if (otherBlock == null) {
-      block.add(toResource);
-
-    } else {
-      block.addAll(otherBlock);
-      unrelatedBlocks.remove(otherBlock);
-    }
+    
+    blockA.addAll(blockB);
+    unrelatedBlocks.remove(blockB);
   }
 
   private boolean isCallToInternalFieldOrMethod(AsmEdge edge) {
@@ -107,23 +111,16 @@ public class LCOM4Visitor extends BytecodeVisitor {
         && (edge.getUsage() == SourceCodeEdgeUsage.CALLS_FIELD || edge.getUsage() == SourceCodeEdgeUsage.CALLS_METHOD);
   }
 
-  private Set<AsmResource> getResourceBlockOrCreateIt(AsmResource fromResource) {
-    Set<AsmResource> block = getResourceBlock(fromResource);
-    if (block != null) {
-      return block;
-    }
-    block = new HashSet<AsmResource>();
-    block.add(fromResource);
-    unrelatedBlocks.add(block);
-    return block;
-  }
-
-  private Set<AsmResource> getResourceBlock(AsmResource fromResource) {
+  private Set<AsmResource> getOrCreateResourceBlock(AsmResource fromResource) {
     for (Set<AsmResource> block : unrelatedBlocks) {
       if (block.contains(fromResource)) {
         return block;
       }
     }
-    return null;
+    
+    Set<AsmResource> block = new HashSet<AsmResource>();
+    block.add(fromResource);
+    unrelatedBlocks.add(block);
+    return block;
   }
 }
index 152589f1ee345bbfe5324dd09cf1ad1b2ef7c833..5ede45e3029d14ccaaf0dd3b1911396dea3e0976 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.java.bytecode.asm.AsmClassProvider;
 import org.sonar.java.bytecode.asm.AsmClassProviderImpl;
 import org.sonar.java.bytecode.asm.AsmMethod;
 
+import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.*;
 
 public class AccessorVisitorTest {
@@ -47,11 +48,21 @@ public class AccessorVisitorTest {
   }
 
   @Test
-  public void testAccessorMethods() {
+  public void testIsAccessor() {
     assertTrue(javaBean.getMethod("getName()Ljava/lang/String;").isAccessor());
     assertTrue(javaBean.getMethod("setName(Ljava/lang/String;)V").isAccessor());
     assertTrue(javaBean.getMethod("setFrench(Z)V").isAccessor());
     assertTrue(javaBean.getMethod("isFrench()Z").isAccessor());
     assertFalse(javaBean.getMethod("anotherMethod()V").isAccessor());
   }
+  
+  @Test
+  public void testAccessedField() {
+    assertThat(javaBean.getMethod("getName()Ljava/lang/String;").getAccessedField().getName(), is("name"));
+    assertThat(javaBean.getMethod("setName(Ljava/lang/String;)V").getAccessedField().getName(), is("name"));
+    assertThat(javaBean.getMethod("setFrench(Z)V").getAccessedField().getName(), is("french"));
+    assertThat(javaBean.getMethod("isFrench()Z").getAccessedField().getName(), is("french"));
+    assertNull(javaBean.getMethod("anotherMethod()V").getAccessedField());
+  }
+  
 }
index 4a9d2af770fed7f334cf4b29d175976d97bf56c1..adfa4ab7d246d903c2678f2145de5e05c58888d3 100644 (file)
@@ -54,5 +54,10 @@ public class LCOM4VisitorTest {
   public void testLCOM4Visitor() {
     assertThat(squid.search("LCOM4Exclusions").getInt(Metric.LCOM4), is(2));
   }
+  
+  @Test
+  public void testLCOM4AccessorMethodAndField() {
+    assertThat(squid.search("LCOM4AccessorMethodAndField").getInt(Metric.LCOM4), is(1));
+  }
 
 }