aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidPlugin.java5
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BridgeFactory.java6
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ResourceIndex.java2
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/decorators/ClassComplexityDistributionBuilder.java73
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/decorators/FunctionComplexityDistributionBuilder.java76
-rw-r--r--plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/SquidPluginTest.java2
-rw-r--r--plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/bridges/ClassComplexityDistributionBridgeTest.java41
-rw-r--r--plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/bridges/FunctionComplexityDistributionBridgeTest.java43
-rw-r--r--plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/decorators/ClassComplexityDistributionBuilderTest.java57
-rw-r--r--plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/decorators/FunctionComplexityDistributionBuilderTest.java55
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/DecoratorsSelector.java23
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/FormulaDecorator.java (renamed from sonar-plugin-api/src/main/java/org/sonar/api/batch/FormulaDecorator.java)28
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/DecoratorsSelectorTest.java36
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/FormulaDecoratorTest.java (renamed from sonar-plugin-api/src/test/java/org/sonar/api/batch/FormulaDecoratorTest.java)16
-rw-r--r--sonar-java-api/src/main/java/org/sonar/java/api/JavaClass.java4
-rw-r--r--sonar-java-api/src/main/java/org/sonar/java/api/JavaMethod.java41
-rw-r--r--sonar-java-api/src/test/java/org/sonar/java/api/JavaClassTest.java14
-rw-r--r--sonar-java-api/src/test/java/org/sonar/java/api/JavaMethodTest.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java14
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildDistributionFormula.java23
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/BlockUnit.java104
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildDistributionFormulaTest.java2
-rw-r--r--tests/integration/sonar-it-reference-plugin/src/main/java/itests/ExcludedResourceFilter.java13
-rw-r--r--tests/integration/sonar-it-reference-plugin/src/main/java/itests/ITestsPlugin.java1
-rw-r--r--tests/integration/tests/maven-projects/java-complexity/pom.xml8
-rw-r--r--tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/ContainsInnerClasses.java37
-rw-r--r--tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/ExcludedByFilter.java19
-rw-r--r--tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/Helloworld.java42
-rw-r--r--tests/integration/tests/src/test/java/org/sonar/tests/integration/JavaComplexityIT.java107
-rw-r--r--tests/integration/tests/src/test/java/org/sonar/tests/integration/Struts139IT.java18
30 files changed, 737 insertions, 175 deletions
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidPlugin.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidPlugin.java
index 856c3438fea..ea18236faef 100644
--- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidPlugin.java
+++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidPlugin.java
@@ -23,6 +23,8 @@ import org.sonar.api.CoreProperties;
import org.sonar.api.Plugin;
import org.sonar.api.Properties;
import org.sonar.api.Property;
+import org.sonar.plugins.squid.decorators.ClassComplexityDistributionBuilder;
+import org.sonar.plugins.squid.decorators.FunctionComplexityDistributionBuilder;
import java.util.Arrays;
import java.util.List;
@@ -58,7 +60,8 @@ public class SquidPlugin implements Plugin {
}
public List getExtensions() {
- return Arrays.asList(SquidSearchProxy.class, SquidSensor.class, SquidRuleRepository.class, JavaSourceImporter.class);
+ return Arrays.asList(SquidSearchProxy.class, SquidSensor.class, SquidRuleRepository.class, JavaSourceImporter.class,
+ ClassComplexityDistributionBuilder.class, FunctionComplexityDistributionBuilder.class);
}
@Override
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BridgeFactory.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BridgeFactory.java
index 05b8726e1b1..b621e87b230 100644
--- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BridgeFactory.java
+++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BridgeFactory.java
@@ -36,17 +36,17 @@ public final class BridgeFactory {
private static List<Bridge> create(NoSonarFilter noSonarFilter) {
return Arrays.asList(new CopyBasicMeasuresBridge(), new PackagesBridge(), new PublicUndocumentedApiBridge(),
- new ClassComplexityDistributionBridge(), new FunctionComplexityDistributionBridge(), new NoSonarFilterLoader(noSonarFilter),
+ new NoSonarFilterLoader(noSonarFilter),
new ChidamberKemererBridge(), new RobertCMartinBridge(), new ChidamberKemererDistributionBridge(), new DesignBridge(),
new Lcom4BlocksBridge(), new ChecksBridge());
}
public static List<Bridge> create(boolean bytecodeScanned, SensorContext context, CheckFactory checkFactory,
- ResourceIndex resourceIndex, Squid squid, NoSonarFilter noSonarFilter) {
+ ResourceIndex resourceIndex, Squid squid, NoSonarFilter noSonarFilter) {
List<Bridge> result = new ArrayList<Bridge>();
for (Bridge bridge : create(noSonarFilter)) {
bridge.setCheckFactory(checkFactory);
- if ( !bridge.needsBytecode() || bytecodeScanned) {
+ if (!bridge.needsBytecode() || bytecodeScanned) {
bridge.setContext(context);
bridge.setSquid(squid);
bridge.setResourceIndex(resourceIndex);
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ResourceIndex.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ResourceIndex.java
index f0720cdb7f8..105a33e6b2d 100644
--- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ResourceIndex.java
+++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ResourceIndex.java
@@ -31,6 +31,7 @@ import org.sonar.java.api.JavaMethod;
import org.sonar.squid.Squid;
import org.sonar.squid.api.*;
import org.sonar.squid.indexer.QueryByType;
+import org.sonar.squid.measures.Metric;
import java.util.Collection;
import java.util.HashMap;
@@ -93,6 +94,7 @@ public final class ResourceIndex extends HashMap<SourceCode, Resource> {
.setSignature(squidMethod.getName())
.setFromLine(squidMethod.getStartAtLine())
.setToLine(squidMethod.getEndAtLine())
+ .setAccessor(squidMethod.getInt(Metric.ACCESSORS)>0)
.create();
context.index(sonarMethod, sonarClass);
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/decorators/ClassComplexityDistributionBuilder.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/decorators/ClassComplexityDistributionBuilder.java
new file mode 100644
index 00000000000..f0a0636f19c
--- /dev/null
+++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/decorators/ClassComplexityDistributionBuilder.java
@@ -0,0 +1,73 @@
+/*
+ * 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.plugins.squid.decorators;
+
+import org.sonar.api.batch.Decorator;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.DependedUpon;
+import org.sonar.api.batch.DependsUpon;
+import org.sonar.api.measures.*;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.Scopes;
+
+/**
+ * @since 2.6
+ */
+public final class ClassComplexityDistributionBuilder implements Decorator {
+
+ public static final Number[] LIMITS = {0, 5, 10, 20, 30, 60, 90};
+
+ @DependsUpon
+ public Metric dependOnComplexity() {
+ return CoreMetrics.COMPLEXITY;
+ }
+
+ @DependedUpon
+ public Metric generatesFunctionComplexityDistribution() {
+ return CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION;
+ }
+
+ public void decorate(Resource resource, DecoratorContext context) {
+ if (shouldExecuteOn(resource, context)) {
+ RangeDistributionBuilder builder = new RangeDistributionBuilder(CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION, LIMITS);
+ for (DecoratorContext childContext : context.getChildren()) {
+ if (Scopes.isType(childContext.getResource())) {
+ Measure complexity = childContext.getMeasure(CoreMetrics.COMPLEXITY);
+ if (complexity != null) {
+ builder.add(complexity.getValue());
+ }
+ }
+ }
+ Measure measure = builder.build(true);
+ measure.setPersistenceMode(PersistenceMode.MEMORY);
+ context.saveMeasure(measure);
+ }
+ }
+
+ boolean shouldExecuteOn(Resource resource, DecoratorContext context) {
+ return Scopes.isFile(resource) && context.getMeasure(CoreMetrics.COMPLEXITY) != null;
+ }
+
+ public boolean shouldExecuteOnProject(Project project) {
+ return Java.KEY.equals(project.getLanguageKey());
+ }
+}
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/decorators/FunctionComplexityDistributionBuilder.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/decorators/FunctionComplexityDistributionBuilder.java
new file mode 100644
index 00000000000..75c5c28fd8e
--- /dev/null
+++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/decorators/FunctionComplexityDistributionBuilder.java
@@ -0,0 +1,76 @@
+/*
+ * 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.plugins.squid.decorators;
+
+import org.sonar.api.batch.Decorator;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.DependedUpon;
+import org.sonar.api.batch.DependsUpon;
+import org.sonar.api.measures.*;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.Scopes;
+import org.sonar.java.api.JavaMethod;
+
+/**
+ * @since 2.6
+ */
+public final class FunctionComplexityDistributionBuilder implements Decorator {
+
+ public static final Number[] LIMITS = {1, 2, 4, 6, 8, 10, 12};
+
+ @DependsUpon
+ public Metric dependOnComplexity() {
+ return CoreMetrics.COMPLEXITY;
+ }
+
+ @DependedUpon
+ public Metric generatesFunctionComplexityDistribution() {
+ return CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION;
+ }
+
+ public void decorate(Resource resource, DecoratorContext context) {
+ if (shouldExecuteOn(resource, context)) {
+ RangeDistributionBuilder builder = new RangeDistributionBuilder(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION, LIMITS);
+ for (DecoratorContext childContext : context.getChildren()) {
+ if (childContext.getResource() instanceof JavaMethod) {
+ JavaMethod javaMethod = (JavaMethod)childContext.getResource();
+ Measure complexity = childContext.getMeasure(CoreMetrics.COMPLEXITY);
+ if (!javaMethod.isAccessor() && complexity != null) {
+ builder.add(complexity.getValue());
+ }
+ }
+ }
+ Measure measure = builder.build(true);
+ measure.setPersistenceMode(PersistenceMode.MEMORY);
+ context.saveMeasure(measure);
+ }
+ }
+
+ boolean shouldExecuteOn(Resource resource, DecoratorContext context) {
+ return Scopes.isType(resource) && context.getMeasure(CoreMetrics.COMPLEXITY) != null;
+ }
+
+ public boolean shouldExecuteOnProject(Project project) {
+ return Java.KEY.equals(project.getLanguageKey());
+ }
+}
+
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/SquidPluginTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/SquidPluginTest.java
index 12a6cbed182..0387b501095 100644
--- a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/SquidPluginTest.java
+++ b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/SquidPluginTest.java
@@ -31,6 +31,6 @@ public class SquidPluginTest {
@Test
public void coverageForFun() {
assertThat(new SquidPlugin().getKey(), not(nullValue()));
- assertThat(new SquidPlugin().getExtensions().size(), is(4));
+ assertThat(new SquidPlugin().getExtensions().size(), is(6));
}
}
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/bridges/ClassComplexityDistributionBridgeTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/bridges/ClassComplexityDistributionBridgeTest.java
deleted file mode 100644
index 9e132df3471..00000000000
--- a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/bridges/ClassComplexityDistributionBridgeTest.java
+++ /dev/null
@@ -1,41 +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.plugins.squid.bridges;
-
-import org.junit.Test;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.never;
-import static org.mockito.Matchers.*;
-import org.sonar.api.resources.JavaFile;
-import org.sonar.api.resources.JavaPackage;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.test.IsMeasure;
-
-public class ClassComplexityDistributionBridgeTest extends BridgeTestCase {
-
- @Test
- public void classComplexityDistribution() {
- verify(context).saveMeasure(eq(new JavaPackage("org.apache.struts.config")), argThat(new IsMeasure(CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION, "0=10;5=3;10=2;20=1;30=4;60=4;90=1")));
- verify(context, never()).saveMeasure(eq(new JavaFile("org.apache.struts.config.ConfigRuleSet")), eq(new Measure(CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION, "equals() on measure only uses the metric")));
- verify(context, never()).saveMeasure(eq(project), eq(new Measure(CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION, "equals() on measure only uses the metric")));
- }
-}
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/bridges/FunctionComplexityDistributionBridgeTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/bridges/FunctionComplexityDistributionBridgeTest.java
deleted file mode 100644
index d5203779f6a..00000000000
--- a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/bridges/FunctionComplexityDistributionBridgeTest.java
+++ /dev/null
@@ -1,43 +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.plugins.squid.bridges;
-
-import org.junit.Test;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.resources.JavaFile;
-import org.sonar.api.resources.JavaPackage;
-import org.sonar.api.test.IsMeasure;
-
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-public class FunctionComplexityDistributionBridgeTest extends BridgeTestCase {
-
- @Test
- public void functionComplexityDistribution() {
- verify(context).saveMeasure(eq(new JavaPackage("org.apache.struts.config")), argThat(new IsMeasure(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION, "1=186;2=88;4=11;6=12;8=7;10=2;12=8")));
- verify(context, never()).saveMeasure(eq(new JavaFile("org.apache.struts.config.ConfigRuleSet")), eq(new Measure(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION, "equals() on measure only uses the metric")));
- verify(context, never()).saveMeasure(eq(project), eq(new Measure(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION, "equals() on measure only uses the metric")));
- }
-}
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/decorators/ClassComplexityDistributionBuilderTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/decorators/ClassComplexityDistributionBuilderTest.java
new file mode 100644
index 00000000000..477643076d1
--- /dev/null
+++ b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/decorators/ClassComplexityDistributionBuilderTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.plugins.squid.decorators;
+
+import org.junit.Test;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.resources.JavaPackage;
+import org.sonar.api.resources.Project;
+import org.sonar.java.api.JavaClass;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ClassComplexityDistributionBuilderTest {
+
+ @Test
+ public void shouldExecuteOnJavaProjectsOnly() throws Exception {
+ ClassComplexityDistributionBuilder builder = new ClassComplexityDistributionBuilder();
+ assertThat(builder.shouldExecuteOnProject(new Project("java").setLanguageKey(Java.KEY)), is(true));
+ assertThat(builder.shouldExecuteOnProject(new Project("php").setLanguageKey("php")), is(false));
+ }
+
+ @Test
+ public void shouldExecuteOnFilesOnly() throws Exception {
+ ClassComplexityDistributionBuilder builder = new ClassComplexityDistributionBuilder();
+ DecoratorContext context = mock(DecoratorContext.class);
+ when(context.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 20.0));
+
+ assertThat(builder.shouldExecuteOn(new JavaPackage("org.foo"), context), is(false));
+ assertThat(builder.shouldExecuteOn(new JavaFile("org.foo.Bar"), context), is(true));
+ assertThat(builder.shouldExecuteOn(JavaClass.create("org.foo.Bar"), context), is(false));
+ }
+
+}
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/decorators/FunctionComplexityDistributionBuilderTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/decorators/FunctionComplexityDistributionBuilderTest.java
new file mode 100644
index 00000000000..aa0efe31cac
--- /dev/null
+++ b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/plugins/squid/decorators/FunctionComplexityDistributionBuilderTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.plugins.squid.decorators;
+
+import org.junit.Test;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.resources.JavaPackage;
+import org.sonar.api.resources.Project;
+import org.sonar.java.api.JavaClass;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class FunctionComplexityDistributionBuilderTest {
+ @Test
+ public void shouldExecuteOnJavaProjectsOnly() throws Exception {
+ FunctionComplexityDistributionBuilder builder = new FunctionComplexityDistributionBuilder();
+ assertThat(builder.shouldExecuteOnProject(new Project("java").setLanguageKey(Java.KEY)), is(true));
+ assertThat(builder.shouldExecuteOnProject(new Project("php").setLanguageKey("php")), is(false));
+ }
+
+ @Test
+ public void shouldExecuteOnClassesOnly() throws Exception {
+ FunctionComplexityDistributionBuilder builder = new FunctionComplexityDistributionBuilder();
+ DecoratorContext context = mock(DecoratorContext.class);
+ when(context.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 20.0));
+
+ assertThat(builder.shouldExecuteOn(new JavaPackage("org.foo"), context), is(false));
+ assertThat(builder.shouldExecuteOn(new JavaFile("org.foo.Bar"), context), is(false));
+ assertThat(builder.shouldExecuteOn(JavaClass.create("org.foo.Bar"), context), is(true));
+ }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/DecoratorsSelector.java b/sonar-batch/src/main/java/org/sonar/batch/DecoratorsSelector.java
index 8f8c000099e..5aa54d0cfc4 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/DecoratorsSelector.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/DecoratorsSelector.java
@@ -19,15 +19,16 @@
*/
package org.sonar.batch;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
import org.sonar.api.batch.BatchExtensionDictionnary;
import org.sonar.api.batch.Decorator;
-import org.sonar.api.batch.FormulaDecorator;
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.Project;
import java.util.*;
-public class DecoratorsSelector {
+public final class DecoratorsSelector {
private BatchExtensionDictionnary dictionnary;
@@ -37,26 +38,26 @@ public class DecoratorsSelector {
public Collection<Decorator> select(Project project) {
List<Decorator> decorators = new ArrayList<Decorator>(dictionnary.select(Decorator.class, project, false));
- Set<Metric> coveredMetrics = getMetricsCoveredByPlugins(decorators);
+ SetMultimap<Metric, Decorator> decoratorsByGeneratedMetric = getDecoratorsByMetric(decorators);
for (Metric metric : dictionnary.select(Metric.class)) {
- if (metric.getFormula() != null && !coveredMetrics.contains(metric)) {
- decorators.add(new FormulaDecorator(metric));
+ if (metric.getFormula() != null) {
+ decorators.add(new FormulaDecorator(metric, decoratorsByGeneratedMetric.get(metric)));
}
}
return dictionnary.sort(decorators);
}
- private Set<Metric> getMetricsCoveredByPlugins(Collection<Decorator> pluginDecorators) {
- Set<Metric> coveredMetrics = new HashSet<Metric>();
- for (Decorator pluginDecorator : pluginDecorators) {
- List dependents = dictionnary.getDependents(pluginDecorator);
+ private SetMultimap<Metric, Decorator> getDecoratorsByMetric(Collection<Decorator> pluginDecorators) {
+ SetMultimap<Metric, Decorator> decoratorsByGeneratedMetric = HashMultimap.create();
+ for (Decorator decorator : pluginDecorators) {
+ List dependents = dictionnary.getDependents(decorator);
for (Object dependent : dependents) {
if (dependent instanceof Metric) {
- coveredMetrics.add((Metric) dependent);
+ decoratorsByGeneratedMetric.put((Metric) dependent, decorator);
}
}
}
- return coveredMetrics;
+ return decoratorsByGeneratedMetric;
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/FormulaDecorator.java b/sonar-batch/src/main/java/org/sonar/batch/FormulaDecorator.java
index a082bffc578..0c80290fb53 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/FormulaDecorator.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/FormulaDecorator.java
@@ -17,24 +17,29 @@
* License along with Sonar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
-package org.sonar.api.batch;
+package org.sonar.batch;
+import org.sonar.api.batch.*;
import org.sonar.api.measures.FormulaData;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
+import java.util.Set;
/**
* A pre-implementation of a decorator using a simple calculation formula
* @since 1.11
*/
-public class FormulaDecorator implements Decorator {
+public final class FormulaDecorator implements Decorator {
private Metric metric;
private DefaultFormulaContext formulaContext;
+ private Set<Decorator> executeAfterDecorators;
/**
* Creates a FormulaDecorator
@@ -43,12 +48,17 @@ public class FormulaDecorator implements Decorator {
*
* @throws IllegalArgumentException if no formula is associated to the metric
*/
- public FormulaDecorator(Metric metric) {
+ public FormulaDecorator(Metric metric, Set<Decorator> executeAfterDecorators) {
if (metric.getFormula() == null) {
throw new IllegalArgumentException("No formula defined on metric");
}
this.metric = metric;
this.formulaContext = new DefaultFormulaContext(metric);
+ this.executeAfterDecorators = executeAfterDecorators;
+ }
+
+ public FormulaDecorator(Metric metric) {
+ this(metric, Collections.<Decorator>emptySet());
}
/**
@@ -74,6 +84,11 @@ public class FormulaDecorator implements Decorator {
return metric.getFormula().dependsUponMetrics();
}
+ @DependsUpon
+ public Collection<Decorator> dependsUponDecorators() {
+ return executeAfterDecorators;
+ }
+
/**
* {@inheritDoc}
*/
@@ -98,13 +113,8 @@ public class FormulaDecorator implements Decorator {
if (o == null || getClass() != o.getClass()) {
return false;
}
-
FormulaDecorator that = (FormulaDecorator) o;
-
- if (metric != null ? !metric.equals(that.metric) : that.metric != null) {
- return false;
- }
- return true;
+ return !(metric != null ? !metric.equals(that.metric) : that.metric != null);
}
@Override
diff --git a/sonar-batch/src/test/java/org/sonar/batch/DecoratorsSelectorTest.java b/sonar-batch/src/test/java/org/sonar/batch/DecoratorsSelectorTest.java
index 90edc924f10..5439d9b12c4 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/DecoratorsSelectorTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/DecoratorsSelectorTest.java
@@ -19,13 +19,13 @@
*/
package org.sonar.batch;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
+import org.apache.commons.collections.CollectionUtils;
import org.junit.Test;
-import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
-import static org.mockito.Mockito.mock;
import org.picocontainer.containers.TransientPicoContainer;
-import org.sonar.api.batch.*;
+import org.sonar.api.batch.BatchExtensionDictionnary;
+import org.sonar.api.batch.Decorator;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.DependedUpon;
import org.sonar.api.measures.*;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
@@ -34,16 +34,20 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
+
public class DecoratorsSelectorTest {
private Metric withFormula1 = new Metric("metric1").setFormula(new FakeFormula());
private Metric withFormula2 = new Metric("metric2").setFormula(new FakeFormula());
- private Metric withoutFormula = new Metric("metric3");
+ private Metric withoutFormula3 = new Metric("metric3");
@Test
public void selectAndSortFormulas() {
Project project = new Project("key");
- BatchExtensionDictionnary dictionnary = newDictionnary(withFormula1, withoutFormula, withFormula2);
+ BatchExtensionDictionnary dictionnary = newDictionnary(withFormula1, withoutFormula3, withFormula2);
Collection<Decorator> decorators = new DecoratorsSelector(dictionnary).select(project);
assertThat(decorators.size(), is(2));
@@ -52,18 +56,22 @@ public class DecoratorsSelectorTest {
}
@Test
- public void pluginDecoratorsCanOverrideFormulas() {
+ public void decoratorsShouldBeExecutedBeforeFormulas() {
Project project = new Project("key");
- Decorator fakeDecorator = new FakeDecorator();
Decorator metric1Decorator = new Metric1Decorator();
- BatchExtensionDictionnary dictionnary = newDictionnary(fakeDecorator, metric1Decorator, withFormula1, withoutFormula, withFormula2);
+ BatchExtensionDictionnary dictionnary = newDictionnary(metric1Decorator, withFormula1);
Collection<Decorator> decorators = new DecoratorsSelector(dictionnary).select(project);
- assertThat(decorators.size(), is(3));
- assertThat(decorators, hasItem(fakeDecorator));
- assertThat(decorators, hasItem(metric1Decorator));
- assertThat(decorators, hasItem((Decorator) new FormulaDecorator(withFormula2)));
+ Decorator firstDecorator = (Decorator)CollectionUtils.get(decorators, 0);
+ Decorator secondDecorator = (Decorator)CollectionUtils.get(decorators, 1);
+
+ assertThat(firstDecorator, is(Metric1Decorator.class));
+ assertThat(secondDecorator, is(FormulaDecorator.class));
+
+ FormulaDecorator formulaDecorator = (FormulaDecorator) secondDecorator;
+ assertThat(formulaDecorator.dependsUponDecorators().size(), is(1));
+ assertThat(CollectionUtils.get(formulaDecorator.dependsUponDecorators(), 0), is((Object)firstDecorator));
}
private BatchExtensionDictionnary newDictionnary(Object... extensions) {
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/FormulaDecoratorTest.java b/sonar-batch/src/test/java/org/sonar/batch/FormulaDecoratorTest.java
index 50865b26ae0..b9e25d6bc4d 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/FormulaDecoratorTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/FormulaDecoratorTest.java
@@ -17,14 +17,10 @@
* License along with Sonar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
-package org.sonar.api.batch;
+package org.sonar.batch;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
import org.junit.Test;
-import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.*;
+import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.measures.*;
import org.sonar.api.test.IsMeasure;
@@ -32,6 +28,12 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.internal.matchers.IsCollectionContaining.hasItem;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.*;
+
public class FormulaDecoratorTest {
@Test
@@ -50,7 +52,7 @@ public class FormulaDecoratorTest {
return null;
}
};
- Metric metric = new Metric().setFormula(formula);
+ Metric metric = new Metric("ncloc").setFormula(formula);
List<Metric> dependencies = new FormulaDecorator(metric).dependsUponMetrics();
assertThat(dependencies, hasItem(CoreMetrics.COMPLEXITY));
assertThat(dependencies, hasItem(CoreMetrics.COVERAGE));
diff --git a/sonar-java-api/src/main/java/org/sonar/java/api/JavaClass.java b/sonar-java-api/src/main/java/org/sonar/java/api/JavaClass.java
index 563879e23bb..d482c3d8bb2 100644
--- a/sonar-java-api/src/main/java/org/sonar/java/api/JavaClass.java
+++ b/sonar-java-api/src/main/java/org/sonar/java/api/JavaClass.java
@@ -109,11 +109,11 @@ public final class JavaClass extends Resource {
return getName();
}
- public static JavaClass createRef(String name) {
+ public static JavaClass create(String name) {
return new JavaClass(name);
}
- public static JavaClass createRef(String packageName, String className) {
+ public static JavaClass create(String packageName, String className) {
if (StringUtils.isBlank(packageName)) {
return new JavaClass(className);
}
diff --git a/sonar-java-api/src/main/java/org/sonar/java/api/JavaMethod.java b/sonar-java-api/src/main/java/org/sonar/java/api/JavaMethod.java
index 743b3fa4069..ce7eb14fe8b 100644
--- a/sonar-java-api/src/main/java/org/sonar/java/api/JavaMethod.java
+++ b/sonar-java-api/src/main/java/org/sonar/java/api/JavaMethod.java
@@ -25,9 +25,8 @@ import org.sonar.api.resources.*;
/**
* @since 2.6
*/
-public final class JavaMethod extends Resource {
+public final class JavaMethod extends BlockUnit {
- public static final String SCOPE = Scopes.BLOCK_UNIT;
public static final String QUALIFIER = Qualifiers.METHOD;
public static final int UNKNOWN_LINE = -1;
@@ -37,17 +36,19 @@ public final class JavaMethod extends Resource {
private String className;
private int fromLine;
private int toLine;
+ private boolean isAccessor = false;
private JavaMethod(String className, String signature) {
- setKey(toKey(className, signature));
+ super(toKey(className, signature), QUALIFIER, Java.INSTANCE);
this.className = className;
this.signature = signature;
}
- private JavaMethod(String className, String signature, int fromLine, int toLine) {
+ private JavaMethod(String className, String signature, int fromLine, int toLine, boolean isAccessor) {
this(className, signature);
this.fromLine = fromLine;
this.toLine = toLine;
+ this.isAccessor = isAccessor;
}
public int getFromLine() {
@@ -66,6 +67,10 @@ public final class JavaMethod extends Resource {
return className;
}
+ public boolean isAccessor() {
+ return isAccessor;
+ }
+
@Override
public String getName() {
return signature;
@@ -82,31 +87,11 @@ public final class JavaMethod extends Resource {
}
@Override
- public Language getLanguage() {
- return Java.INSTANCE;
- }
-
- @Override
- public String getScope() {
- return SCOPE;
- }
-
- @Override
- public String getQualifier() {
- return QUALIFIER;
- }
-
- @Override
public Resource getParent() {
return null;
}
@Override
- public boolean matchFilePattern(String antPattern) {
- return false;
- }
-
- @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@@ -155,6 +140,7 @@ public final class JavaMethod extends Resource {
private String signature;
private int fromLine = UNKNOWN_LINE;
private int toLine = UNKNOWN_LINE;
+ private boolean isAccessor = false;
public Builder setKey(String key) {
String[] parts = splitClassAndMethodFromKey(key);
@@ -188,8 +174,13 @@ public final class JavaMethod extends Resource {
return this;
}
+ public Builder setAccessor(boolean accessor) {
+ isAccessor = accessor;
+ return this;
+ }
+
public JavaMethod create() {
- return new JavaMethod(className, signature, fromLine, toLine);
+ return new JavaMethod(className, signature, fromLine, toLine, isAccessor);
}
}
}
diff --git a/sonar-java-api/src/test/java/org/sonar/java/api/JavaClassTest.java b/sonar-java-api/src/test/java/org/sonar/java/api/JavaClassTest.java
index 869f60b3be5..92eba48740a 100644
--- a/sonar-java-api/src/test/java/org/sonar/java/api/JavaClassTest.java
+++ b/sonar-java-api/src/test/java/org/sonar/java/api/JavaClassTest.java
@@ -30,7 +30,7 @@ public class JavaClassTest {
@Test
public void shouldCreateReferenceFromName() {
- JavaClass javaClass = JavaClass.createRef("org.foo.Bar");
+ JavaClass javaClass = JavaClass.create("org.foo.Bar");
assertThat(javaClass.getClassName(), is("Bar"));
assertThat(javaClass.getKey(), is("org.foo.Bar"));
assertThat(javaClass.getLanguage(), is((Language)Java.INSTANCE));
@@ -40,7 +40,7 @@ public class JavaClassTest {
@Test
public void shouldCreateReferenceFromPackageAndClassname() {
- JavaClass javaClass = JavaClass.createRef("org.foo", "Bar");
+ JavaClass javaClass = JavaClass.create("org.foo", "Bar");
assertThat(javaClass.getClassName(), is("Bar"));
assertThat(javaClass.getKey(), is("org.foo.Bar"));
assertThat(javaClass.getLanguage(), is((Language)Java.INSTANCE));
@@ -50,25 +50,25 @@ public class JavaClassTest {
@Test
public void shouldGetPackageName() {
- JavaClass javaClass = JavaClass.createRef("org.foo.Bar");
+ JavaClass javaClass = JavaClass.create("org.foo.Bar");
assertThat(javaClass.getPackageName(), is("org.foo"));
- javaClass = JavaClass.createRef("Bar");
+ javaClass = JavaClass.create("Bar");
assertThat(javaClass.getPackageName(), is(""));
}
@Test
public void shouldGetClassName() {
- JavaClass javaClass = JavaClass.createRef("org.foo.Bar");
+ JavaClass javaClass = JavaClass.create("org.foo.Bar");
assertThat(javaClass.getClassName(), is("Bar"));
- javaClass = JavaClass.createRef("Bar");
+ javaClass = JavaClass.create("Bar");
assertThat(javaClass.getClassName(), is("Bar"));
}
@Test
public void shouldOverrideToString() {
- JavaClass javaClass = JavaClass.createRef("org.foo.Bar");
+ JavaClass javaClass = JavaClass.create("org.foo.Bar");
assertThat(javaClass.toString(), is("org.foo.Bar"));
}
diff --git a/sonar-java-api/src/test/java/org/sonar/java/api/JavaMethodTest.java b/sonar-java-api/src/test/java/org/sonar/java/api/JavaMethodTest.java
index bc6976aca25..fad1e992dfe 100644
--- a/sonar-java-api/src/test/java/org/sonar/java/api/JavaMethodTest.java
+++ b/sonar-java-api/src/test/java/org/sonar/java/api/JavaMethodTest.java
@@ -40,7 +40,7 @@ public class JavaMethodTest {
public void shouldCreateReferenceFromClassAndSignature() {
String className = "org.foo.Bar";
String signature = "hello(LString;)V";
- JavaMethod method = JavaMethod.createRef(JavaClass.createRef(className), signature);
+ JavaMethod method = JavaMethod.createRef(JavaClass.create(className), signature);
assertThat(method.getKey(), is(className + "#" + signature));
assertThat(method.getClassName(), is(className));
assertThat(method.getName(), is(signature));
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
index 35f270d3c4d..ab1c36d8c0a 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java
@@ -20,6 +20,7 @@
package org.sonar.api.measures;
import org.apache.commons.lang.StringUtils;
+import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.SonarException;
import java.lang.reflect.Field;
@@ -133,22 +134,22 @@ public final class CoreMetrics {
public static final String CLASS_COMPLEXITY_DISTRIBUTION_KEY = "class_complexity_distribution";
public static final Metric CLASS_COMPLEXITY_DISTRIBUTION = new Metric(CLASS_COMPLEXITY_DISTRIBUTION_KEY,
"Classes distribution /complexity", "Classes distribution /complexity", Metric.ValueType.DISTRIB, Metric.DIRECTION_NONE, true,
- DOMAIN_COMPLEXITY).setFormula(new SumChildDistributionFormula());
+ DOMAIN_COMPLEXITY).setFormula(new SumChildDistributionFormula().setMinimumScopeToPersist(Scopes.DIRECTORY));
public static final String FUNCTION_COMPLEXITY_DISTRIBUTION_KEY = "function_complexity_distribution";
public static final Metric FUNCTION_COMPLEXITY_DISTRIBUTION = new Metric(FUNCTION_COMPLEXITY_DISTRIBUTION_KEY,
"Functions distribution /complexity", "Functions distribution /complexity", Metric.ValueType.DISTRIB, Metric.DIRECTION_NONE, true,
- DOMAIN_COMPLEXITY).setFormula(new SumChildDistributionFormula());
+ DOMAIN_COMPLEXITY).setFormula(new SumChildDistributionFormula().setMinimumScopeToPersist(Scopes.DIRECTORY));
public static final String FILE_COMPLEXITY_DISTRIBUTION_KEY = "file_complexity_distribution";
public static final Metric FILE_COMPLEXITY_DISTRIBUTION = new Metric(FILE_COMPLEXITY_DISTRIBUTION_KEY, "Files distribution /complexity",
"Files distribution /complexity", Metric.ValueType.DISTRIB, Metric.DIRECTION_NONE, true, DOMAIN_COMPLEXITY)
- .setFormula(new SumChildDistributionFormula());
+ .setFormula(new SumChildDistributionFormula().setMinimumScopeToPersist(Scopes.DIRECTORY));
public static final String PARAGRAPH_COMPLEXITY_DISTRIBUTION_KEY = "paragraph_complexity_distribution";
public static final Metric PARAGRAPH_COMPLEXITY_DISTRIBUTION = new Metric(PARAGRAPH_COMPLEXITY_DISTRIBUTION_KEY,
"Paragraph distribution /complexity", "Paragraph distribution /complexity", Metric.ValueType.DISTRIB, Metric.DIRECTION_NONE, true,
- DOMAIN_COMPLEXITY).setFormula(new SumChildDistributionFormula());
+ DOMAIN_COMPLEXITY).setFormula(new SumChildDistributionFormula().setMinimumScopeToPersist(Scopes.DIRECTORY));
public static final String COMMENT_LINES_KEY = "comment_lines";
public static final Metric COMMENT_LINES = new Metric(COMMENT_LINES_KEY, "Comment lines", "Number of comment lines",
@@ -423,7 +424,8 @@ public final class CoreMetrics {
public static final String RFC_DISTRIBUTION_KEY = "rfc_distribution";
public static final Metric RFC_DISTRIBUTION = new Metric(RFC_DISTRIBUTION_KEY, "Class distribution /RFC", "Class distribution /RFC",
- Metric.ValueType.DISTRIB, Metric.DIRECTION_NONE, true, DOMAIN_DESIGN).setFormula(new SumChildDistributionFormula());
+ Metric.ValueType.DISTRIB, Metric.DIRECTION_NONE, true, DOMAIN_DESIGN)
+ .setFormula(new SumChildDistributionFormula().setMinimumScopeToPersist(Scopes.DIRECTORY));
public static final String LCOM4_KEY = "lcom4";
public static final Metric LCOM4 = new Metric(LCOM4_KEY, "LCOM4", "Lack of Cohesion of Methods", Metric.ValueType.FLOAT,
@@ -436,7 +438,7 @@ public final class CoreMetrics {
public static final String LCOM4_DISTRIBUTION_KEY = "lcom4_distribution";
public static final Metric LCOM4_DISTRIBUTION = new Metric(LCOM4_DISTRIBUTION_KEY, "Class distribution /LCOM4",
"Class distribution /LCOM4", Metric.ValueType.DISTRIB, Metric.DIRECTION_NONE, true, DOMAIN_DESIGN)
- .setFormula(new SumChildDistributionFormula());
+ .setFormula(new SumChildDistributionFormula().setMinimumScopeToPersist(Scopes.DIRECTORY));
public static final String SUSPECT_LCOM4_DENSITY_KEY = "suspect_lcom4_density";
public static final Metric SUSPECT_LCOM4_DENSITY = new Metric(SUSPECT_LCOM4_DENSITY_KEY, "Suspect LCOM4 density",
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildDistributionFormula.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildDistributionFormula.java
index 423d2df83e9..d80b78ddc12 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildDistributionFormula.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildDistributionFormula.java
@@ -19,9 +19,11 @@
*/
package org.sonar.api.measures;
-import java.util.List;
-import java.util.Collections;
+import org.sonar.api.resources.Scopes;
+
import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
/**
* @since 2.0
@@ -30,10 +32,21 @@ import java.util.Collection;
*/
public class SumChildDistributionFormula implements Formula {
+ private String minimumScopeToPersist= Scopes.FILE;
+
public List<Metric> dependsUponMetrics() {
return Collections.emptyList();
}
+ public String getMinimumScopeToPersist() {
+ return minimumScopeToPersist;
+ }
+
+ public SumChildDistributionFormula setMinimumScopeToPersist(String s) {
+ this.minimumScopeToPersist = s;
+ return this;
+ }
+
public Measure calculate(FormulaData data, FormulaContext context) {
Collection<Measure> measures = data.getChildrenMeasures(context.getTargetMetric());
if (measures == null || measures.isEmpty()) {
@@ -44,7 +57,11 @@ public class SumChildDistributionFormula implements Formula {
for (Measure measure : measures) {
distribution.add(measure);
}
- return distribution.build();
+ Measure measure = distribution.build();
+ if (!Scopes.isHigherThanOrEquals(context.getResource().getScope(), minimumScopeToPersist)) {
+ measure.setPersistenceMode(PersistenceMode.MEMORY);
+ }
+ return measure;
}
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/BlockUnit.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/BlockUnit.java
new file mode 100644
index 00000000000..ee6bbe1ac03
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/BlockUnit.java
@@ -0,0 +1,104 @@
+/*
+ * 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.api.resources;
+
+public class BlockUnit extends Resource {
+
+ public static final String SCOPE = Scopes.BLOCK_UNIT;
+
+ protected String qualifier;
+ protected Language language;
+
+ protected BlockUnit(String key, String qualifier, Language language) {
+ setKey(key);
+ this.qualifier = qualifier;
+ this.language = language;
+ }
+
+ @Override
+ public String getName() {
+ return getKey();
+ }
+
+ @Override
+ public String getLongName() {
+ return getKey();
+ }
+
+ @Override
+ public String getDescription() {
+ return null;
+ }
+
+ @Override
+ public final Language getLanguage() {
+ return language;
+ }
+
+ @Override
+ public final String getScope() {
+ return SCOPE;
+ }
+
+ @Override
+ public final String getQualifier() {
+ return qualifier;
+ }
+
+ @Override
+ public Resource getParent() {
+ return null;
+ }
+
+ @Override
+ public final boolean matchFilePattern(String antPattern) {
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ BlockUnit blockUnit = (BlockUnit) o;
+ if (!qualifier.equals(blockUnit.qualifier)) {
+ return false;
+ }
+ return getKey().equals(blockUnit.getKey());
+ }
+
+ @Override
+ public int hashCode() {
+ int result = super.hashCode();
+ result = 31 * result + getKey().hashCode();
+ result = 31 * result + qualifier.hashCode();
+ return result;
+ }
+
+ public static BlockUnit createMethod(String key, Language language) {
+ return new BlockUnit(key, Qualifiers.METHOD, language);
+ }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildDistributionFormulaTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildDistributionFormulaTest.java
index 9849c28d035..93d89b98abb 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildDistributionFormulaTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildDistributionFormulaTest.java
@@ -22,6 +22,7 @@ package org.sonar.api.measures;
import com.google.common.collect.Lists;
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.resources.File;
import java.util.Collections;
import java.util.List;
@@ -42,6 +43,7 @@ public class SumChildDistributionFormulaTest {
public void init() {
formula = new SumChildDistributionFormula();
context = mock(FormulaContext.class);
+ when(context.getResource()).thenReturn(new File("foo"));
data = mock(FormulaData.class);
}
diff --git a/tests/integration/sonar-it-reference-plugin/src/main/java/itests/ExcludedResourceFilter.java b/tests/integration/sonar-it-reference-plugin/src/main/java/itests/ExcludedResourceFilter.java
new file mode 100644
index 00000000000..4c045cdb3b9
--- /dev/null
+++ b/tests/integration/sonar-it-reference-plugin/src/main/java/itests/ExcludedResourceFilter.java
@@ -0,0 +1,13 @@
+package itests;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.batch.ResourceFilter;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.Scopes;
+
+public final class ExcludedResourceFilter implements ResourceFilter {
+
+ public boolean isIgnored(Resource resource) {
+ return Scopes.isFile(resource) && StringUtils.contains(resource.getName(), "ExcludedByFilter");
+ }
+}
diff --git a/tests/integration/sonar-it-reference-plugin/src/main/java/itests/ITestsPlugin.java b/tests/integration/sonar-it-reference-plugin/src/main/java/itests/ITestsPlugin.java
index 6df7c15befb..5fd5809f3b3 100644
--- a/tests/integration/sonar-it-reference-plugin/src/main/java/itests/ITestsPlugin.java
+++ b/tests/integration/sonar-it-reference-plugin/src/main/java/itests/ITestsPlugin.java
@@ -50,6 +50,7 @@ public class ITestsPlugin implements Plugin {
extensions.add(SampleSensor.class);
extensions.add(LanguageWithoutRulesEngine.class);
extensions.add(ServerSideExtensionUsingExternalDependency.class);
+ extensions.add(ExcludedResourceFilter.class);
// web
extensions.add(SampleResourceTab.class);
diff --git a/tests/integration/tests/maven-projects/java-complexity/pom.xml b/tests/integration/tests/maven-projects/java-complexity/pom.xml
new file mode 100644
index 00000000000..63afab1e8ab
--- /dev/null
+++ b/tests/integration/tests/maven-projects/java-complexity/pom.xml
@@ -0,0 +1,8 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.sonar.tests</groupId>
+ <artifactId>java-complexity</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <name>java-complexity</name>
+</project> \ No newline at end of file
diff --git a/tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/ContainsInnerClasses.java b/tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/ContainsInnerClasses.java
new file mode 100644
index 00000000000..9ed05abd626
--- /dev/null
+++ b/tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/ContainsInnerClasses.java
@@ -0,0 +1,37 @@
+package foo;
+
+
+public class ContainsInnerClasses {
+
+ // complexity: 1
+ public ContainsInnerClasses() {
+
+ }
+
+ // complexity: 3
+ public static class InnerClass {
+ private String field;
+
+ // complexity: 1
+ public InnerClass() {
+
+ }
+
+ // complexity: 2
+ public InnerClass(String s) {
+ if (s != null) {
+ field = s;
+ }
+ }
+ }
+}
+
+// complexity: 1
+class PackageClass {
+ private String field;
+
+ // complexity: 1
+ public PackageClass() {
+
+ }
+ }
diff --git a/tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/ExcludedByFilter.java b/tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/ExcludedByFilter.java
new file mode 100644
index 00000000000..b5193444cd6
--- /dev/null
+++ b/tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/ExcludedByFilter.java
@@ -0,0 +1,19 @@
+package foo;
+
+// this class is excluded by the resource filter defined in sonar-it-reference-plugin
+public class ExcludedByFilter {
+
+ public void say() {
+ int i=0;
+ if(i>5) {
+ System.out.println("say something");
+ }
+ }
+
+ public void cry() {
+ int i=0;
+ if(i<5) {
+ System.out.println("cry");
+ }
+ }
+}
diff --git a/tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/Helloworld.java b/tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/Helloworld.java
new file mode 100644
index 00000000000..37fae842697
--- /dev/null
+++ b/tests/integration/tests/maven-projects/java-complexity/src/main/java/foo/Helloworld.java
@@ -0,0 +1,42 @@
+package foo;
+
+// complexity: 6
+public class Helloworld {
+
+ private String field = null;
+
+ // this is considered as a method
+ // complexity: 2
+ static {
+ int i = 0;
+ if (i > 5) {
+ System.out.println("hello from static block");
+ }
+ }
+
+ // complexity: 1
+ public Helloworld(String s) {
+ this.field = s;
+ }
+
+ // accessor
+ // complexity: 0
+ public String getField() {
+ return field;
+ }
+
+ // accessor
+ // complexity: 0
+ public void setField(String s) {
+ this.field = s;
+ }
+
+ // complexity: 3
+ public void sayHello() {
+ for (int i = 0; i < 5; i++) {
+ if (field != null) {
+ System.out.println(field);
+ }
+ }
+ }
+}
diff --git a/tests/integration/tests/src/test/java/org/sonar/tests/integration/JavaComplexityIT.java b/tests/integration/tests/src/test/java/org/sonar/tests/integration/JavaComplexityIT.java
new file mode 100644
index 00000000000..e3e3ad1f157
--- /dev/null
+++ b/tests/integration/tests/src/test/java/org/sonar/tests/integration/JavaComplexityIT.java
@@ -0,0 +1,107 @@
+/*
+ * 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.tests.integration;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.wsclient.Sonar;
+import org.sonar.wsclient.services.Measure;
+import org.sonar.wsclient.services.ResourceQuery;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+
+public class JavaComplexityIT {
+ private static Sonar sonar;
+
+ @BeforeClass
+ public static void buildServer() {
+ sonar = ITUtils.createSonarWsClient();
+ }
+
+ @Test
+ public void testFileComplexity() {
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo.Helloworld", CoreMetrics.COMPLEXITY_KEY).getIntValue(), is(6));
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo.ContainsInnerClasses", CoreMetrics.COMPLEXITY_KEY).getIntValue(), is(5));
+ }
+
+ @Test
+ public void testPackageComplexity() {
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo", CoreMetrics.COMPLEXITY_KEY).getIntValue(), is(11));
+ }
+
+ @Test
+ public void testProjectComplexity() {
+ assertThat(getMeasure("org.sonar.tests:java-complexity", CoreMetrics.COMPLEXITY_KEY).getIntValue(), is(11));
+ }
+
+ @Test
+ public void testAverageMethodComplexity() {
+ // complexity 6 / 2 methods
+ // BUG http://jira.codehaus.org/browse/SONAR-2152
+ // => the complexity of the static block should not be included. Good value should be 4 / 2 = 2
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo.Helloworld", CoreMetrics.FUNCTION_COMPLEXITY_KEY).getValue(), is(3.0));
+
+ // complexity 5 / 4 methods. Real value is 1.25 but round up to 1.3
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo.ContainsInnerClasses", CoreMetrics.FUNCTION_COMPLEXITY_KEY).getValue(), is(1.3));
+
+ // 3.0 * 2 + 1.25 * 4 = 11 for 6 methods
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo", CoreMetrics.FUNCTION_COMPLEXITY_KEY).getValue(), is(1.8));
+ assertThat(getMeasure("org.sonar.tests:java-complexity", CoreMetrics.FUNCTION_COMPLEXITY_KEY).getValue(), is(1.8));
+ }
+
+ @Test
+ public void testAverageClassComplexity() {
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo.Helloworld", CoreMetrics.CLASS_COMPLEXITY_KEY).getValue(), is(6.0));
+
+ // 1 + 1 + 3 => complexity 5/3
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo.ContainsInnerClasses", CoreMetrics.CLASS_COMPLEXITY_KEY).getValue(), is(1.7));
+
+ // 1 + 1 + 3 + 6 => 11/4 = 2.75
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo", CoreMetrics.CLASS_COMPLEXITY_KEY).getValue(), is(2.8));
+ }
+
+ @Test
+ public void testDistributionOfClassComplexity() {
+ // 1 + 1 + 3 + 6 => 3 in range [0,5[ and 1 in range [5,10[
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo", CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION_KEY).getData(), is("0=3;5=1;10=0;20=0;30=0;60=0;90=0"));
+ assertThat(getMeasure("org.sonar.tests:java-complexity", CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION_KEY).getData(), is("0=3;5=1;10=0;20=0;30=0;60=0;90=0"));
+ }
+
+ @Test
+ public void testDistributionOfMethodComplexity() {
+ // ContainsInnerClasses: 1+ 1 + 2 + 1
+ // Helloworld: 1 + 3 (static block is not a method)
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo", CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY).getData(), is("1=4;2=2;4=0;6=0;8=0;10=0;12=0"));
+ assertThat(getMeasure("org.sonar.tests:java-complexity", CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY).getData(), is("1=4;2=2;4=0;6=0;8=0;10=0;12=0"));
+ }
+
+ @Test
+ public void shouldNotPersistDistributionOnFiles() {
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo.Helloworld", CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION_KEY), nullValue());
+ assertThat(getMeasure("org.sonar.tests:java-complexity:foo.Helloworld", CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY), nullValue());
+ }
+
+ private Measure getMeasure(String resourceKey, String metricKey) {
+ return sonar.find(ResourceQuery.createForMetrics(resourceKey, metricKey)).getMeasure(metricKey);
+ }
+}
diff --git a/tests/integration/tests/src/test/java/org/sonar/tests/integration/Struts139IT.java b/tests/integration/tests/src/test/java/org/sonar/tests/integration/Struts139IT.java
index bcffec6f59a..2724b24db7f 100644
--- a/tests/integration/tests/src/test/java/org/sonar/tests/integration/Struts139IT.java
+++ b/tests/integration/tests/src/test/java/org/sonar/tests/integration/Struts139IT.java
@@ -129,7 +129,23 @@ public class Struts139IT {
assertThat(getProjectMeasure("statements").getIntValue(), is(21896));
assertThat(getProjectMeasure("class_complexity").getValue(), is(21.5));
assertThat(getProjectMeasure("function_complexity").getValue(), is(2.6));
- assertThat(getProjectMeasure("class_complexity_distribution").getData(), is("0=172;5=90;10=86;20=55;30=69;60=34;90=17"));
+ }
+
+ @Test
+ public void classComplexityDistribution() throws Exception {
+ assertThat(sonar.find(ResourceQuery.createForMetrics("org.apache.struts:struts-core:org.apache.struts.config", "class_complexity_distribution")).getMeasure("class_complexity_distribution").getData(), is("0=10;5=3;10=2;20=1;30=4;60=4;90=1"));
+ assertThat(getCoreModuleMeasure("class_complexity_distribution").getData(), is("0=49;5=26;10=24;20=14;30=18;60=9;90=10"));
+ assertThat(getProjectMeasure("class_complexity_distribution").getData(), is("0=173;5=90;10=86;20=55;30=69;60=34;90=17"));
+ }
+
+ @Test
+ public void functionComplexityDistribution() throws Exception {
+ assertThat(sonar.find(ResourceQuery.createForMetrics("org.apache.struts:struts-core:org.apache.struts.config", "function_complexity_distribution")).getMeasure("function_complexity_distribution").getData(), is("1=186;2=88;4=11;6=12;8=7;10=2;12=8"));
+ }
+
+ @Test
+ public void shouldNotPersistComplexityDistributionsOnFiles() {
+ assertThat(sonar.find(ResourceQuery.createForMetrics("org.apache.struts:struts-core:org.apache.struts.config.ConfigRuleSet", "function_complexity_distribution", "class_complexity_distribution")).getMeasures().size(), is(0));
}
@Test