aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2014-06-19 14:48:07 +0200
committerJulien HENRY <julien.henry@sonarsource.com>2014-06-19 14:48:47 +0200
commite6a79a3f8da7bd3351aade2e9fb8a4f57c9fabe6 (patch)
tree6b590a32cc284372ef50bee6c1354b394ba3c60f
parent059c65d520fc80ac85616e98d789b4b67cac9019 (diff)
downloadsonarqube-e6a79a3f8da7bd3351aade2e9fb8a4f57c9fabe6.tar.gz
sonarqube-e6a79a3f8da7bd3351aade2e9fb8a4f57c9fabe6.zip
SONAR-5389 Analyzer optimizer
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerOptimizer.java45
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan2/AnalyzerOptimizerTest.java117
-rw-r--r--sonar-deprecated/src/main/java/org/sonar/api/rules/RuleRepository.java10
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/AnalyzerDescriptor.java11
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/internal/DefaultAnalyzerDescriptor.java22
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilder.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewActiveRule.java9
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/analyzer/internal/DefaultAnalyzerDescriptorTest.java4
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilderTest.java20
10 files changed, 207 insertions, 40 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java
index 1f5408c2002..701233abbef 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java
@@ -19,8 +19,6 @@
*/
package org.sonar.batch.scan;
-import org.sonar.api.batch.measure.Metric;
-
import org.sonar.api.batch.DependedUpon;
import org.sonar.api.batch.DependsUpon;
import org.sonar.api.batch.Sensor;
@@ -29,6 +27,7 @@ import org.sonar.api.batch.analyzer.Analyzer;
import org.sonar.api.batch.analyzer.AnalyzerContext;
import org.sonar.api.batch.analyzer.internal.DefaultAnalyzerDescriptor;
import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.measure.Metric;
import org.sonar.api.resources.Project;
import org.sonar.batch.scan2.AnalyzerOptimizer;
@@ -53,12 +52,12 @@ public class SensorWrapper implements Sensor {
}
@DependedUpon
- public List<Metric<?>> provides() {
+ public List<Metric> provides() {
return Arrays.asList(descriptor.provides());
}
@DependsUpon
- public List<Metric<?>> depends() {
+ public List<Metric> depends() {
return Arrays.asList(descriptor.dependsOn());
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerOptimizer.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerOptimizer.java
index 3ad0a29aa76..0e875360743 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerOptimizer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerOptimizer.java
@@ -23,27 +23,54 @@ import org.sonar.api.BatchComponent;
import org.sonar.api.batch.analyzer.internal.DefaultAnalyzerDescriptor;
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.rule.ActiveRules;
public class AnalyzerOptimizer implements BatchComponent {
- private FileSystem fs;
+ private final FileSystem fs;
+ private final ActiveRules activeRules;
- public AnalyzerOptimizer(FileSystem fs) {
+ public AnalyzerOptimizer(FileSystem fs, ActiveRules activeRules) {
this.fs = fs;
+ this.activeRules = activeRules;
}
/**
* Decide if the given Analyzer should be executed.
*/
public boolean shouldExecute(DefaultAnalyzerDescriptor descriptor) {
- FilePredicate predicate = fs.predicates().hasLanguages(descriptor.languages());
- if (descriptor.types().size() == 1) {
- // Size = 0 or Size = 2 means both main and test type
- predicate = fs.predicates().and(
- predicate,
- fs.predicates().hasType(descriptor.types().iterator().next()));
+ // FS Conditions
+ boolean fsCondition = fsCondition(descriptor);
+ boolean activeRulesCondition = activeRulesCondition(descriptor);
+ return fsCondition && activeRulesCondition;
+ }
+
+ private boolean activeRulesCondition(DefaultAnalyzerDescriptor descriptor) {
+ if (!descriptor.ruleRepositories().isEmpty()) {
+ for (String repoKey : descriptor.ruleRepositories()) {
+ if (!activeRules.findByRepository(repoKey).isEmpty()) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ private boolean fsCondition(DefaultAnalyzerDescriptor descriptor) {
+ if (!descriptor.languages().isEmpty() || !descriptor.types().isEmpty()) {
+ FilePredicate langPredicate = descriptor.languages().isEmpty() ? fs.predicates().all() : fs.predicates().hasLanguages(descriptor.languages());
+
+ FilePredicate typePredicate = descriptor.types().isEmpty() ? fs.predicates().all() : fs.predicates().none();
+ for (InputFile.Type type : descriptor.types()) {
+ typePredicate = fs.predicates().or(
+ typePredicate,
+ fs.predicates().hasType(type));
+ }
+ return fs.hasFiles(fs.predicates().and(langPredicate, typePredicate));
}
- return fs.hasFiles(predicate);
+ return true;
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan2/AnalyzerOptimizerTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan2/AnalyzerOptimizerTest.java
new file mode 100644
index 00000000000..1384950b99d
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/scan2/AnalyzerOptimizerTest.java
@@ -0,0 +1,117 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan2;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.analyzer.internal.DefaultAnalyzerDescriptor;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
+import org.sonar.api.rule.RuleKey;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class AnalyzerOptimizerTest {
+
+ DefaultFileSystem fs = new DefaultFileSystem();
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+ private AnalyzerOptimizer optimizer;
+
+ @Before
+ public void prepare() {
+ optimizer = new AnalyzerOptimizer(fs, new ActiveRulesBuilder().build());
+ }
+
+ @Test
+ public void should_run_analyzer_with_no_metadata() throws Exception {
+ DefaultAnalyzerDescriptor descriptor = new DefaultAnalyzerDescriptor();
+
+ assertThat(optimizer.shouldExecute(descriptor)).isTrue();
+ }
+
+ @Test
+ public void should_optimize_on_language() throws Exception {
+ DefaultAnalyzerDescriptor descriptor = new DefaultAnalyzerDescriptor()
+ .workOnLanguages("java", "php");
+ assertThat(optimizer.shouldExecute(descriptor)).isFalse();
+
+ fs.add(new DefaultInputFile("src/Foo.java").setLanguage("java"));
+ assertThat(optimizer.shouldExecute(descriptor)).isTrue();
+ }
+
+ @Test
+ public void should_optimize_on_type() throws Exception {
+ DefaultAnalyzerDescriptor descriptor = new DefaultAnalyzerDescriptor()
+ .workOnFileTypes(InputFile.Type.MAIN);
+ assertThat(optimizer.shouldExecute(descriptor)).isFalse();
+
+ fs.add(new DefaultInputFile("tests/FooTest.java").setType(InputFile.Type.TEST));
+ assertThat(optimizer.shouldExecute(descriptor)).isFalse();
+
+ fs.add(new DefaultInputFile("src/Foo.java").setType(InputFile.Type.MAIN));
+ assertThat(optimizer.shouldExecute(descriptor)).isTrue();
+ }
+
+ @Test
+ public void should_optimize_on_both_type_and_language() throws Exception {
+ DefaultAnalyzerDescriptor descriptor = new DefaultAnalyzerDescriptor()
+ .workOnLanguages("java", "php")
+ .workOnFileTypes(InputFile.Type.MAIN);
+ assertThat(optimizer.shouldExecute(descriptor)).isFalse();
+
+ fs.add(new DefaultInputFile("tests/FooTest.java").setLanguage("java").setType(InputFile.Type.TEST));
+ fs.add(new DefaultInputFile("src/Foo.cbl").setLanguage("cobol").setType(InputFile.Type.MAIN));
+ assertThat(optimizer.shouldExecute(descriptor)).isFalse();
+
+ fs.add(new DefaultInputFile("src/Foo.java").setLanguage("java").setType(InputFile.Type.MAIN));
+ assertThat(optimizer.shouldExecute(descriptor)).isTrue();
+ }
+
+ @Test
+ public void should_optimize_on_repository() throws Exception {
+ DefaultAnalyzerDescriptor descriptor = new DefaultAnalyzerDescriptor()
+ .createIssuesForRuleRepositories("squid");
+ assertThat(optimizer.shouldExecute(descriptor)).isFalse();
+
+ ActiveRules activeRules = new ActiveRulesBuilder()
+ .activate(RuleKey.of("repo1", "foo"))
+ .end()
+ .build();
+ optimizer = new AnalyzerOptimizer(fs, activeRules);
+
+ assertThat(optimizer.shouldExecute(descriptor)).isFalse();
+
+ activeRules = new ActiveRulesBuilder()
+ .activate(RuleKey.of("repo1", "foo"))
+ .end()
+ .activate(RuleKey.of("squid", "rule"))
+ .end()
+ .build();
+ optimizer = new AnalyzerOptimizer(fs, activeRules);
+ assertThat(optimizer.shouldExecute(descriptor)).isTrue();
+ }
+}
diff --git a/sonar-deprecated/src/main/java/org/sonar/api/rules/RuleRepository.java b/sonar-deprecated/src/main/java/org/sonar/api/rules/RuleRepository.java
index 1072dc9dc4d..a6d849c8970 100644
--- a/sonar-deprecated/src/main/java/org/sonar/api/rules/RuleRepository.java
+++ b/sonar-deprecated/src/main/java/org/sonar/api/rules/RuleRepository.java
@@ -28,7 +28,7 @@ import java.util.List;
/**
* @since 2.3
- * @deprecated in 4.2. Replaced by org.sonar.api.rule.RuleDefinitions
+ * @deprecated in 4.2. Replaced by org.sonar.api.server.rule.RuleDefinition
*/
@Deprecated
public abstract class RuleRepository implements ServerExtension {
@@ -71,9 +71,9 @@ public abstract class RuleRepository implements ServerExtension {
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
- .append("key", key)
- .append("language", language)
- .append("name", name)
- .toString();
+ .append("key", key)
+ .append("language", language)
+ .append("name", name)
+ .toString();
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/AnalyzerDescriptor.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/AnalyzerDescriptor.java
index 1a06563949d..3e38e5da708 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/AnalyzerDescriptor.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/AnalyzerDescriptor.java
@@ -51,13 +51,20 @@ public interface AnalyzerDescriptor {
* no file for given languages are present in the project.
* If no language is provided then it will be executed for all languages.
*/
- AnalyzerDescriptor runOnLanguages(String... languageKeys);
+ AnalyzerDescriptor workOnLanguages(String... languageKeys);
/**
* List {@link InputFile.Type} this {@link Analyzer} work on. May be used by the platform to skip execution of the {@link Analyzer} when
* no file for given type are present in the project.
* If not type is provided then it will be executed for all types.
*/
- AnalyzerDescriptor runOnTypes(InputFile.Type... types);
+ AnalyzerDescriptor workOnFileTypes(InputFile.Type... types);
+
+ /**
+ * List {@link InputFile.Type} this {@link Analyzer} work on. May be used by the platform to skip execution of the {@link Analyzer} when
+ * no file for given type are present in the project.
+ * If not type is provided then it will be executed for all types.
+ */
+ AnalyzerDescriptor createIssuesForRuleRepositories(String... repositoryKeys);
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/internal/DefaultAnalyzerDescriptor.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/internal/DefaultAnalyzerDescriptor.java
index dea8593013f..3f793c98a64 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/internal/DefaultAnalyzerDescriptor.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/internal/DefaultAnalyzerDescriptor.java
@@ -19,10 +19,9 @@
*/
package org.sonar.api.batch.analyzer.internal;
-import org.sonar.api.batch.measure.Metric;
-
import org.sonar.api.batch.analyzer.AnalyzerDescriptor;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.measure.Metric;
import java.util.Arrays;
import java.util.Collection;
@@ -34,16 +33,17 @@ public class DefaultAnalyzerDescriptor implements AnalyzerDescriptor {
private Metric<?>[] provides = new Metric<?>[0];
private String[] languages = new String[0];
private InputFile.Type[] types = new InputFile.Type[0];
+ private String[] ruleRepositories = new String[0];
public String name() {
return name;
}
- public Metric<?>[] dependsOn() {
+ public Metric[] dependsOn() {
return dependsOn;
}
- public Metric<?>[] provides() {
+ public Metric[] provides() {
return provides;
}
@@ -55,6 +55,10 @@ public class DefaultAnalyzerDescriptor implements AnalyzerDescriptor {
return Arrays.asList(types);
}
+ public Collection<String> ruleRepositories() {
+ return Arrays.asList(ruleRepositories);
+ }
+
@Override
public DefaultAnalyzerDescriptor name(String name) {
this.name = name;
@@ -74,15 +78,21 @@ public class DefaultAnalyzerDescriptor implements AnalyzerDescriptor {
}
@Override
- public DefaultAnalyzerDescriptor runOnLanguages(String... languageKeys) {
+ public DefaultAnalyzerDescriptor workOnLanguages(String... languageKeys) {
this.languages = languageKeys;
return this;
}
@Override
- public DefaultAnalyzerDescriptor runOnTypes(InputFile.Type... types) {
+ public DefaultAnalyzerDescriptor workOnFileTypes(InputFile.Type... types) {
this.types = types;
return this;
}
+ @Override
+ public DefaultAnalyzerDescriptor createIssuesForRuleRepositories(String... repositoryKeys) {
+ this.ruleRepositories = repositoryKeys;
+ return this;
+ }
+
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilder.java
index a871a3faf88..208335e2ff3 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilder.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilder.java
@@ -39,7 +39,7 @@ public class ActiveRulesBuilder {
if (map.containsKey(ruleKey)) {
throw new IllegalStateException(String.format("Rule '%s' is already activated", ruleKey));
}
- NewActiveRule newActiveRule = new NewActiveRule(ruleKey);
+ NewActiveRule newActiveRule = new NewActiveRule(this, ruleKey);
map.put(ruleKey, newActiveRule);
return newActiveRule;
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewActiveRule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewActiveRule.java
index 73bc8e8afd5..d2dbcf3f420 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewActiveRule.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewActiveRule.java
@@ -24,6 +24,7 @@ import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import javax.annotation.Nullable;
+
import java.util.HashMap;
import java.util.Map;
@@ -35,8 +36,10 @@ public class NewActiveRule {
String severity = Severity.defaultSeverity();
Map<String, String> params = new HashMap<String, String>();
String internalKey, language;
+ private final ActiveRulesBuilder builder;
- NewActiveRule(RuleKey ruleKey) {
+ NewActiveRule(ActiveRulesBuilder builder, RuleKey ruleKey) {
+ this.builder = builder;
this.ruleKey = ruleKey;
}
@@ -68,4 +71,8 @@ public class NewActiveRule {
public Map<String, String> params() {
return params;
}
+
+ public ActiveRulesBuilder end() {
+ return builder;
+ }
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/analyzer/internal/DefaultAnalyzerDescriptorTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/analyzer/internal/DefaultAnalyzerDescriptorTest.java
index 0c63dd2167c..b55bae7bf75 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/analyzer/internal/DefaultAnalyzerDescriptorTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/analyzer/internal/DefaultAnalyzerDescriptorTest.java
@@ -34,8 +34,8 @@ public class DefaultAnalyzerDescriptorTest {
.name("Foo")
.dependsOn(CoreMetrics.NCLOC)
.provides(CoreMetrics.BLOCKER_VIOLATIONS)
- .runOnLanguages("java", "php")
- .runOnTypes(InputFile.Type.MAIN);
+ .workOnLanguages("java", "php")
+ .workOnFileTypes(InputFile.Type.MAIN);
assertThat(descriptor.name()).isEqualTo("Foo");
assertThat(descriptor.dependsOn()).containsOnly(CoreMetrics.NCLOC);
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilderTest.java
index 41ff35f22c4..d83456058fd 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilderTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilderTest.java
@@ -38,16 +38,16 @@ public class ActiveRulesBuilderTest {
@Test
public void build_rules() throws Exception {
- ActiveRulesBuilder builder = new ActiveRulesBuilder();
- NewActiveRule newSquid1 = builder.activate(RuleKey.of("squid", "S0001"));
- newSquid1.setSeverity(Severity.CRITICAL);
- newSquid1.setInternalKey("__S0001__");
- newSquid1.setParam("min", "20");
- // most simple rule
- builder.activate(RuleKey.of("squid", "S0002"));
- builder.activate(RuleKey.of("findbugs", "NPE")).setInternalKey(null).setSeverity(null).setParam("foo", null);
-
- ActiveRules activeRules = builder.build();
+ ActiveRules activeRules = new ActiveRulesBuilder()
+ .activate(RuleKey.of("squid", "S0001"))
+ .setSeverity(Severity.CRITICAL)
+ .setInternalKey("__S0001__")
+ .setParam("min", "20")
+ .end()
+ // most simple rule
+ .activate(RuleKey.of("squid", "S0002")).end()
+ .activate(RuleKey.of("findbugs", "NPE")).setInternalKey(null).setSeverity(null).setParam("foo", null).end()
+ .build();
assertThat(activeRules.findAll()).hasSize(3);
assertThat(activeRules.findByRepository("squid")).hasSize(2);