From e410437db4ad779e779619ac3bea979c079b4e00 Mon Sep 17 00:00:00 2001 From: Godin Date: Sun, 14 Nov 2010 02:51:28 +0000 Subject: [PATCH] SONAR-1845: Create a new Sonar rule to check method complexity --- ...tyCheck.java => ClassComplexityCheck.java} | 7 +-- .../java/ast/check/MethodComplexityCheck.java | 44 +++++++++++++++++++ .../sonar/java/ast/visitor/MethodVisitor.java | 2 +- .../plugins/squid/SquidRuleRepository.java | 5 ++- .../plugins/squid/bridges/ChecksBridge.java | 7 +-- ...est.java => ClassComplexityCheckTest.java} | 4 +- .../ast/check/MethodComplexityCheckTest.java | 35 +++++++++++++++ .../org/sonar/squid/api/CheckMessage.java | 9 ++++ 8 files changed, 102 insertions(+), 11 deletions(-) rename plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/{ComplexityCheck.java => ClassComplexityCheck.java} (88%) create mode 100644 plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/MethodComplexityCheck.java rename plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/{ComplexityCheckTest.java => ClassComplexityCheckTest.java} (95%) create mode 100644 plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/MethodComplexityCheckTest.java 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/ClassComplexityCheck.java similarity index 88% rename from plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/ComplexityCheck.java rename to plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/ClassComplexityCheck.java index e2936cf0102..4025278c654 100644 --- 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/ClassComplexityCheck.java @@ -33,8 +33,8 @@ import org.sonar.squid.measures.Metric; import com.puppycrawl.tools.checkstyle.api.DetailAST; -@Rule(key = "ComplexityCheck", isoCategory = IsoCategory.Maintainability) -public class ComplexityCheck extends JavaAstCheck { +@Rule(key = "ClassComplexityCheck", isoCategory = IsoCategory.Maintainability) +public class ClassComplexityCheck extends JavaAstCheck { @RuleProperty private Integer threshold; @@ -49,8 +49,9 @@ public class ComplexityCheck extends JavaAstCheck { SourceCode currentResource = peekSourceCode(); int complexity = calculateComplexity(currentResource); if (complexity > threshold) { - CheckMessage message = new CheckMessage(this, "Complexity exceeds " + 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); } 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 index 00000000000..072d19baf6d --- /dev/null +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/ast/check/MethodComplexityCheck.java @@ -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 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; + } + +} 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 480c346bf66..afe8e9d366c 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 @@ -41,7 +41,7 @@ public class MethodVisitor extends JavaAstVisitor { private static final String CONSTRUCTOR = ""; - private static final List wantedTokens = Arrays.asList(TokenTypes.CTOR_DEF, TokenTypes.METHOD_DEF); + public static final List wantedTokens = Arrays.asList(TokenTypes.CTOR_DEF, TokenTypes.METHOD_DEF); private static final Map tokenJavaTypeMapping = new HashMap(); static { diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidRuleRepository.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidRuleRepository.java index b9c1473b86a..9c4ae500f29 100644 --- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidRuleRepository.java +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidRuleRepository.java @@ -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); } } diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ChecksBridge.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ChecksBridge.java index 0d083d2a77f..60530fc5fd9 100644 --- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ChecksBridge.java +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ChecksBridge.java @@ -19,15 +19,15 @@ */ 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/ComplexityCheckTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/ClassComplexityCheckTest.java similarity index 95% rename from plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/ComplexityCheckTest.java rename to plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/ClassComplexityCheckTest.java index 0c4c8a04d7d..39692969332 100644 --- 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/ClassComplexityCheckTest.java @@ -32,14 +32,14 @@ import org.sonar.squid.Squid; import org.sonar.squid.api.CheckMessage; import org.sonar.squid.api.SourceFile; -public class ComplexityCheckTest { +public class ClassComplexityCheckTest { private Squid squid; @Before public void setUp() { squid = new Squid(new JavaSquidConfiguration()); - ComplexityCheck check = new ComplexityCheck(); + ClassComplexityCheck check = new ClassComplexityCheck(); check.setThreshold(5); squid.registerVisitor(check); JavaAstScanner scanner = squid.register(JavaAstScanner.class); 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 index 00000000000..5f8a73396bd --- /dev/null +++ b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/ast/check/MethodComplexityCheckTest.java @@ -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)); + } +} diff --git a/sonar-squid/src/main/java/org/sonar/squid/api/CheckMessage.java b/sonar-squid/src/main/java/org/sonar/squid/api/CheckMessage.java index 425b26af8be..e9caeb3e2af 100644 --- a/sonar-squid/src/main/java/org/sonar/squid/api/CheckMessage.java +++ b/sonar-squid/src/main/java/org/sonar/squid/api/CheckMessage.java @@ -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; } -- 2.39.5