]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-1845: Create a new Sonar rule to check method complexity
authorGodin <mandrikov@gmail.com>
Sun, 14 Nov 2010 02:51:28 +0000 (02:51 +0000)
committerGodin <mandrikov@gmail.com>
Sun, 14 Nov 2010 02:51:28 +0000 (02:51 +0000)
plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/ClassComplexityCheck.java [new file with mode: 0644]
plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/ComplexityCheck.java [deleted file]
plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/MethodComplexityCheck.java [new file with mode: 0644]
plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/visitor/MethodVisitor.java
plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidRuleRepository.java
plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ChecksBridge.java
plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/ClassComplexityCheckTest.java [new file with mode: 0644]
plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/ComplexityCheckTest.java [deleted file]
plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/MethodComplexityCheckTest.java [new file with mode: 0644]
sonar-squid/src/main/java/org/sonar/squid/api/CheckMessage.java

diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/ClassComplexityCheck.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/ClassComplexityCheck.java
new file mode 100644 (file)
index 0000000..4025278
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.check;
+
+import java.util.List;
+
+import org.sonar.check.IsoCategory;
+import org.sonar.check.Rule;
+import org.sonar.check.RuleProperty;
+import org.sonar.java.ast.visitor.ClassVisitor;
+import org.sonar.squid.api.CheckMessage;
+import org.sonar.squid.api.SourceCode;
+import org.sonar.squid.api.SourceFile;
+import org.sonar.squid.measures.Metric;
+
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+
+@Rule(key = "ClassComplexityCheck", isoCategory = IsoCategory.Maintainability)
+public class ClassComplexityCheck extends JavaAstCheck {
+
+  @RuleProperty
+  private Integer threshold;
+
+  @Override
+  public List<Integer> getWantedTokens() {
+    return ClassVisitor.wantedTokens;
+  }
+
+  @Override
+  public void leaveToken(DetailAST ast) {
+    SourceCode currentResource = peekSourceCode();
+    int complexity = calculateComplexity(currentResource);
+    if (complexity > threshold) {
+      CheckMessage message = new CheckMessage(this, "Class complexity exceeds " + threshold + ".");
+      message.setLine(ast.getLineNo());
+      message.setCost(complexity - threshold);
+      SourceFile sourceFile = currentResource.getParent(SourceFile.class);
+      sourceFile.log(message);
+    }
+  }
+
+  private int calculateComplexity(SourceCode sourceCode) {
+    int result = 0;
+    if (sourceCode.getChildren() != null) {
+      for (SourceCode child : sourceCode.getChildren()) {
+        result += calculateComplexity(child);
+      }
+    }
+    result += sourceCode.getInt(Metric.COMPLEXITY);
+    return result;
+  }
+
+  public void setThreshold(int threshold) {
+    this.threshold = threshold;
+  }
+
+}
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/ComplexityCheck.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/ComplexityCheck.java
deleted file mode 100644 (file)
index e2936cf..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.check;
-
-import java.util.List;
-
-import org.sonar.check.IsoCategory;
-import org.sonar.check.Rule;
-import org.sonar.check.RuleProperty;
-import org.sonar.java.ast.visitor.ClassVisitor;
-import org.sonar.squid.api.CheckMessage;
-import org.sonar.squid.api.SourceCode;
-import org.sonar.squid.api.SourceFile;
-import org.sonar.squid.measures.Metric;
-
-import com.puppycrawl.tools.checkstyle.api.DetailAST;
-
-@Rule(key = "ComplexityCheck", isoCategory = IsoCategory.Maintainability)
-public class ComplexityCheck extends JavaAstCheck {
-
-  @RuleProperty
-  private Integer threshold;
-
-  @Override
-  public List<Integer> getWantedTokens() {
-    return ClassVisitor.wantedTokens;
-  }
-
-  @Override
-  public void leaveToken(DetailAST ast) {
-    SourceCode currentResource = peekSourceCode();
-    int complexity = calculateComplexity(currentResource);
-    if (complexity > threshold) {
-      CheckMessage message = new CheckMessage(this, "Complexity exceeds " + threshold + ".");
-      message.setLine(ast.getLineNo());
-      SourceFile sourceFile = currentResource.getParent(SourceFile.class);
-      sourceFile.log(message);
-    }
-  }
-
-  private int calculateComplexity(SourceCode sourceCode) {
-    int result = 0;
-    if (sourceCode.getChildren() != null) {
-      for (SourceCode child : sourceCode.getChildren()) {
-        result += calculateComplexity(child);
-      }
-    }
-    result += sourceCode.getInt(Metric.COMPLEXITY);
-    return result;
-  }
-
-  public void setThreshold(int threshold) {
-    this.threshold = threshold;
-  }
-
-}
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/MethodComplexityCheck.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/MethodComplexityCheck.java
new file mode 100644 (file)
index 0000000..072d19b
--- /dev/null
@@ -0,0 +1,44 @@
+package org.sonar.java.ast.check;
+
+import java.util.List;
+
+import org.sonar.check.IsoCategory;
+import org.sonar.check.Rule;
+import org.sonar.check.RuleProperty;
+import org.sonar.java.ast.visitor.MethodVisitor;
+import org.sonar.squid.api.CheckMessage;
+import org.sonar.squid.api.SourceCode;
+import org.sonar.squid.api.SourceFile;
+import org.sonar.squid.measures.Metric;
+
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+
+@Rule(key = "MethodComplexityCheck", isoCategory = IsoCategory.Maintainability)
+public class MethodComplexityCheck extends JavaAstCheck {
+
+  @RuleProperty
+  private Integer threshold;
+
+  @Override
+  public List<Integer> getWantedTokens() {
+    return MethodVisitor.wantedTokens;
+  }
+
+  @Override
+  public void leaveToken(DetailAST ast) {
+    SourceCode currentResource = peekSourceCode();
+    int complexity = currentResource.getInt(Metric.COMPLEXITY) + currentResource.getInt(Metric.BRANCHES) + 1;
+    if (complexity > threshold) {
+      CheckMessage message = new CheckMessage(this, "Method complexity exceeds " + threshold + ".");
+      message.setLine(ast.getLineNo());
+      message.setCost(complexity - threshold);
+      SourceFile sourceFile = currentResource.getParent(SourceFile.class);
+      sourceFile.log(message);
+    }
+  }
+
+  public void setThreshold(int threshold) {
+    this.threshold = threshold;
+  }
+
+}
index 480c346bf66c817b2a2fbb8439315440c7b4fbd2..afe8e9d366c20f56c04f6e5a2a8649ccdb12a4bd 100644 (file)
@@ -41,7 +41,7 @@ public class MethodVisitor extends JavaAstVisitor {
 
   private static final String CONSTRUCTOR = "<init>";
 
-  private static final List<Integer> wantedTokens = Arrays.asList(TokenTypes.CTOR_DEF, TokenTypes.METHOD_DEF);
+  public static final List<Integer> wantedTokens = Arrays.asList(TokenTypes.CTOR_DEF, TokenTypes.METHOD_DEF);
   private static final Map<Integer, JvmJavaType> tokenJavaTypeMapping = new HashMap<Integer, JvmJavaType>();
 
   static {
index b9c1473b86a4ee6ce04fea9d7ff600794a6238a8..9c4ae500f29d629c4c9a150b5e998b12c19b79a4 100644 (file)
@@ -28,8 +28,9 @@ import org.sonar.api.rules.AnnotationRuleParser;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleRepository;
 import org.sonar.java.ast.check.BreakCheck;
-import org.sonar.java.ast.check.ComplexityCheck;
+import org.sonar.java.ast.check.ClassComplexityCheck;
 import org.sonar.java.ast.check.ContinueCheck;
+import org.sonar.java.ast.check.MethodComplexityCheck;
 import org.sonar.java.ast.check.UndocumentedApiCheck;
 import org.sonar.java.bytecode.check.ArchitectureCheck;
 import org.sonar.java.bytecode.check.CallToDeprecatedMethodCheck;
@@ -57,6 +58,6 @@ public final class SquidRuleRepository extends RuleRepository {
         (Class) CallToDeprecatedMethodCheck.class, UnusedPrivateMethodCheck.class, UnusedProtectedMethodCheck.class,
         ArchitectureCheck.class, DITCheck.class,
         // AST checks
-        UndocumentedApiCheck.class, ContinueCheck.class, BreakCheck.class, ComplexityCheck.class);
+        UndocumentedApiCheck.class, ContinueCheck.class, BreakCheck.class, ClassComplexityCheck.class, MethodComplexityCheck.class);
   }
 }
index 0d083d2a77fca7ce2f67deeeed79cbc0181e9190..60530fc5fd983f88fc0c8eb287b5c011a1fe34ea 100644 (file)
  */
 package org.sonar.plugins.squid.bridges;
 
+import java.util.Locale;
+import java.util.Set;
+
 import org.sonar.api.resources.Resource;
 import org.sonar.api.rules.ActiveRule;
 import org.sonar.api.rules.Violation;
 import org.sonar.squid.api.CheckMessage;
 import org.sonar.squid.api.SourceFile;
 
-import java.util.Locale;
-import java.util.Set;
-
 public class ChecksBridge extends Bridge {
 
   protected ChecksBridge() {
@@ -43,6 +43,7 @@ public class ChecksBridge extends Bridge {
         Violation violation = Violation.create(rule, sonarFile);
         violation.setLineId(checkMessage.getLine());
         violation.setMessage(checkMessage.getText(Locale.ENGLISH));
+        violation.setCost(checkMessage.getCost());
         context.saveViolation(violation);
       }
     }
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/ClassComplexityCheckTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/ClassComplexityCheckTest.java
new file mode 100644 (file)
index 0000000..3969296
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.check;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.sonar.java.ast.SquidTestUtils.getFile;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.java.ast.JavaAstScanner;
+import org.sonar.java.squid.JavaSquidConfiguration;
+import org.sonar.squid.Squid;
+import org.sonar.squid.api.CheckMessage;
+import org.sonar.squid.api.SourceFile;
+
+public class ClassComplexityCheckTest {
+
+  private Squid squid;
+
+  @Before
+  public void setUp() {
+    squid = new Squid(new JavaSquidConfiguration());
+    ClassComplexityCheck check = new ClassComplexityCheck();
+    check.setThreshold(5);
+    squid.registerVisitor(check);
+    JavaAstScanner scanner = squid.register(JavaAstScanner.class);
+    scanner.scanFile(getFile("/metrics/branches/NoBranches.java"));
+    scanner.scanFile(getFile("/metrics/branches/ComplexBranches.java"));
+  }
+
+  @Test
+  public void testComplexityExceedsThreshold() {
+    SourceFile file = (SourceFile) squid.search("ComplexBranches.java");
+    assertThat(file.getCheckMessages().size(), is(1));
+    CheckMessage message = file.getCheckMessages().iterator().next();
+    assertThat(message.getLine(), is(3));
+  }
+
+  @Test
+  public void testComplexityNotExceedsThreshold() {
+    SourceFile file = (SourceFile) squid.search("NoBranches.java");
+    assertThat(file.getCheckMessages().size(), is(0));
+  }
+
+}
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/ComplexityCheckTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/ComplexityCheckTest.java
deleted file mode 100644 (file)
index 0c4c8a0..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.check;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-import static org.sonar.java.ast.SquidTestUtils.getFile;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.java.ast.JavaAstScanner;
-import org.sonar.java.squid.JavaSquidConfiguration;
-import org.sonar.squid.Squid;
-import org.sonar.squid.api.CheckMessage;
-import org.sonar.squid.api.SourceFile;
-
-public class ComplexityCheckTest {
-
-  private Squid squid;
-
-  @Before
-  public void setUp() {
-    squid = new Squid(new JavaSquidConfiguration());
-    ComplexityCheck check = new ComplexityCheck();
-    check.setThreshold(5);
-    squid.registerVisitor(check);
-    JavaAstScanner scanner = squid.register(JavaAstScanner.class);
-    scanner.scanFile(getFile("/metrics/branches/NoBranches.java"));
-    scanner.scanFile(getFile("/metrics/branches/ComplexBranches.java"));
-  }
-
-  @Test
-  public void testComplexityExceedsThreshold() {
-    SourceFile file = (SourceFile) squid.search("ComplexBranches.java");
-    assertThat(file.getCheckMessages().size(), is(1));
-    CheckMessage message = file.getCheckMessages().iterator().next();
-    assertThat(message.getLine(), is(3));
-  }
-
-  @Test
-  public void testComplexityNotExceedsThreshold() {
-    SourceFile file = (SourceFile) squid.search("NoBranches.java");
-    assertThat(file.getCheckMessages().size(), is(0));
-  }
-
-}
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/MethodComplexityCheckTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/MethodComplexityCheckTest.java
new file mode 100644 (file)
index 0000000..5f8a733
--- /dev/null
@@ -0,0 +1,35 @@
+package org.sonar.java.ast.check;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.sonar.java.ast.SquidTestUtils.getFile;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.java.ast.JavaAstScanner;
+import org.sonar.java.squid.JavaSquidConfiguration;
+import org.sonar.squid.Squid;
+import org.sonar.squid.api.CheckMessage;
+import org.sonar.squid.api.SourceFile;
+
+public class MethodComplexityCheckTest {
+  private Squid squid;
+
+  @Before
+  public void setUp() {
+    squid = new Squid(new JavaSquidConfiguration());
+    MethodComplexityCheck check = new MethodComplexityCheck();
+    check.setThreshold(5);
+    squid.registerVisitor(check);
+    JavaAstScanner scanner = squid.register(JavaAstScanner.class);
+    scanner.scanFile(getFile("/metrics/branches/ComplexBranches.java"));
+  }
+
+  @Test
+  public void testMethodComplexityExceedsThreshold() {
+    SourceFile file = (SourceFile) squid.search("ComplexBranches.java");
+    assertThat(file.getCheckMessages().size(), is(1));
+    CheckMessage message = file.getCheckMessages().iterator().next();
+    assertThat(message.getLine(), is(10));
+  }
+}
index 425b26af8be212f5b291ab4aac1c1313e85fa165..e9caeb3e2afa0876137979286542d74ef9bf7b6e 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.check.Message;
 public class CheckMessage implements Message {
 
   private Integer line;
+  private Double cost;
   private SourceCode sourceCode;
   private CodeCheck codeCheck;
   private String defaultMessage;
@@ -55,6 +56,14 @@ public class CheckMessage implements Message {
     return line;
   }
 
+  public void setCost(double cost) {
+    this.cost = cost;
+  }
+
+  public Double getCost() {
+    return cost;
+  }
+
   public CodeCheck getChecker() {
     return codeCheck;
   }