]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6162 Fix NPE when searching for Check of custom rules
authorJulien HENRY <julien.henry@sonarsource.com>
Mon, 9 Feb 2015 16:17:00 +0000 (17:17 +0100)
committerJulien HENRY <julien.henry@sonarsource.com>
Mon, 9 Feb 2015 16:51:19 +0000 (17:51 +0100)
14 files changed:
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/Check.java [new file with mode: 0644]
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/TemplateRuleCheck.java [new file with mode: 0644]
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/ChecksSensor.java [new file with mode: 0644]
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooRulesDefinition.java
plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java
plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/XooRulesDefinitionTest.java
sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/ChecksMediumTest.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRule.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Checks.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultActiveRule.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewActiveRule.java
sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/CheckFactoryTest.java

index 102aa38dfb1bf0887e12ddd3979dcab2f80ccd1f..6623cbb3866db7e4fb5536c6e29502cb37999f97 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.xoo.lang.SymbolReferencesSensor;
 import org.sonar.xoo.lang.SyntaxHighlightingSensor;
 import org.sonar.xoo.lang.TestCaseSensor;
 import org.sonar.xoo.lang.XooTokenizerSensor;
+import org.sonar.xoo.rule.ChecksSensor;
 import org.sonar.xoo.rule.CreateIssueByInternalKeySensor;
 import org.sonar.xoo.rule.OneIssueOnDirPerFileSensor;
 import org.sonar.xoo.rule.OneIssuePerLineSensor;
@@ -72,11 +73,11 @@ public class XooPlugin extends SonarPlugin {
       TestCaseSensor.class,
       CoveragePerTestSensor.class,
       DependencySensor.class,
+      ChecksSensor.class,
 
       OneIssuePerLineSensor.class,
       OneIssueOnDirPerFileSensor.class,
       CreateIssueByInternalKeySensor.class
       );
   }
-
 }
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/Check.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/Check.java
new file mode 100644 (file)
index 0000000..40911b8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.xoo.checks;
+
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.rule.RuleKey;
+
+public interface Check {
+
+  public Class<Check>[] ALL = new Class[] {TemplateRuleCheck.class};
+
+  void execute(SensorContext context, InputFile file, RuleKey ruleKey);
+
+}
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/TemplateRuleCheck.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/TemplateRuleCheck.java
new file mode 100644 (file)
index 0000000..01fd6ad
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.xoo.checks;
+
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.check.Cardinality;
+import org.sonar.check.Rule;
+import org.sonar.check.RuleProperty;
+
+@Rule(key = TemplateRuleCheck.RULE_KEY, cardinality = Cardinality.MULTIPLE, name = "Template rule", description = "Sample template rule")
+public class TemplateRuleCheck implements Check {
+
+  public static final String RULE_KEY = "TemplateRule";
+
+  @RuleProperty(key = "line")
+  private int line;
+
+  @Override
+  public void execute(SensorContext sensorContext, InputFile file, RuleKey ruleKey) {
+    sensorContext.newIssue()
+      .onFile(file)
+      .ruleKey(ruleKey)
+      .atLine(line)
+      .save();
+  }
+
+}
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/ChecksSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/ChecksSensor.java
new file mode 100644 (file)
index 0000000..249967d
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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.xoo.rule;
+
+import org.sonar.api.batch.fs.FilePredicates;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputFile.Type;
+import org.sonar.api.batch.rule.CheckFactory;
+import org.sonar.api.batch.rule.Checks;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.xoo.Xoo;
+import org.sonar.xoo.checks.Check;
+
+public class ChecksSensor implements Sensor {
+
+  private final CheckFactory checkFactory;
+
+  public ChecksSensor(CheckFactory checkFactory) {
+    this.checkFactory = checkFactory;
+  }
+
+  @Override
+  public void describe(SensorDescriptor descriptor) {
+    descriptor
+      .name("ChecksSensor")
+      .workOnLanguages(Xoo.KEY)
+      .createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY)
+      .workOnFileTypes(InputFile.Type.MAIN);
+  }
+
+  @Override
+  public void execute(SensorContext context) {
+    Checks<Check> checks = checkFactory.create(XooRulesDefinition.XOO_REPOSITORY);
+    checks.addAnnotatedChecks(Check.ALL);
+    FilePredicates p = context.fileSystem().predicates();
+    for (InputFile file : context.fileSystem().inputFiles(p.and(p.hasLanguages(Xoo.KEY), p.hasType(Type.MAIN)))) {
+      for (Check check : checks.all()) {
+        check.execute(context, file, checks.ruleKey(check));
+      }
+    }
+  }
+
+}
index 0f37cefcb425eecd45c9dea396321f285fee6df0..7880f8a4b69776f2e2af70f01450a7ee278bc575 100644 (file)
@@ -23,7 +23,9 @@ import org.sonar.api.rule.RuleStatus;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.server.rule.RuleParamType;
 import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.server.rule.RulesDefinitionAnnotationLoader;
 import org.sonar.xoo.Xoo;
+import org.sonar.xoo.checks.Check;
 
 /**
  * Define all the coding rules that are supported on the repository named "xoo".
@@ -36,6 +38,9 @@ public class XooRulesDefinition implements RulesDefinition {
   public void define(Context context) {
     NewRepository repository = context.createRepository(XOO_REPOSITORY, Xoo.KEY).setName("Xoo");
 
+    // Load checks
+    new RulesDefinitionAnnotationLoader().load(repository, Check.ALL);
+
     // define a single rule programmatically. Note that rules
     // can be loaded from JSON or XML files too.
     NewRule x1Rule = repository.createRule("x1")
index d5913f277a8ed3c26cb27d752ba6250065120c26..63f20b2e62849eab3bbee7192e8738d8b2e616e3 100644 (file)
@@ -27,6 +27,6 @@ public class XooPluginTest {
 
   @Test
   public void provide_extensions() {
-    assertThat(new XooPlugin().getExtensions()).hasSize(18);
+    assertThat(new XooPlugin().getExtensions()).hasSize(19);
   }
 }
index 184e8d470743809a7967c66362ae58d9a7f1dcfa..86432b6cffb7a1628de60497f3f68862e15d1abf 100644 (file)
@@ -37,7 +37,7 @@ public class XooRulesDefinitionTest {
     assertThat(repo).isNotNull();
     assertThat(repo.name()).isEqualTo("Xoo");
     assertThat(repo.language()).isEqualTo("xoo");
-    assertThat(repo.rules()).hasSize(1);
+    assertThat(repo.rules()).hasSize(2);
 
     RulesDefinition.Rule x1 = repo.rule("x1");
     assertThat(x1.key()).isEqualTo("x1");
index a539b74407355d0fcebf623ec5f1315100d7f0eb..d90841ee8075e5b8378b8e50b48d5afc3bf2af6c 100644 (file)
@@ -52,6 +52,7 @@ public class ActiveRulesProvider extends ProviderAdapter {
       newActiveRule.setSeverity(activeRule.severity());
       newActiveRule.setLanguage(activeRule.language());
       newActiveRule.setInternalKey(activeRule.internalKey());
+      newActiveRule.setTemplateRuleKey(activeRule.templateRuleKey());
 
       // load parameters
       for (Entry<String, String> param : activeRule.params().entrySet()) {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/ChecksMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/ChecksMediumTest.java
new file mode 100644 (file)
index 0000000..54c2aab
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.mediumtest.issues;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.batch.mediumtest.BatchMediumTester;
+import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult;
+import org.sonar.batch.protocol.input.ActiveRule;
+import org.sonar.xoo.XooPlugin;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class ChecksMediumTest {
+
+  @org.junit.Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  public BatchMediumTester tester = BatchMediumTester.builder()
+    .registerPlugin("xoo", new XooPlugin())
+    .addDefaultQProfile("xoo", "Sonar Way")
+    .activateRule(new ActiveRule("xoo", "TemplateRule_1234", "TemplateRule", "A template rule", "MAJOR", null, "xoo").addParam("line", "1"))
+    .activateRule(new ActiveRule("xoo", "TemplateRule_1235", "TemplateRule", "Another template rule", "MAJOR", null, "xoo").addParam("line", "2"))
+    .bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "sensor"))
+    .build();
+
+  @Before
+  public void prepare() {
+    tester.start();
+  }
+
+  @After
+  public void stop() {
+    tester.stop();
+  }
+
+  @Test
+  public void testCheckWithTemplate() throws IOException {
+
+    File baseDir = temp.newFolder();
+    File srcDir = new File(baseDir, "src");
+    srcDir.mkdir();
+
+    File xooFile = new File(srcDir, "sample.xoo");
+    FileUtils.write(xooFile, "foo");
+
+    TaskResult result = tester.newTask()
+      .properties(ImmutableMap.<String, String>builder()
+        .put("sonar.task", "scan")
+        .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+        .put("sonar.projectKey", "com.foo.project")
+        .put("sonar.projectName", "Foo Project")
+        .put("sonar.projectVersion", "1.0-SNAPSHOT")
+        .put("sonar.projectDescription", "Description of Foo Project")
+        .put("sonar.sources", "src")
+        .build())
+      .start();
+
+    assertThat(result.issues()).hasSize(2);
+
+    boolean foundIssueAtLine1 = false;
+    boolean foundIssueAtLine2 = false;
+    for (Issue issue : result.issues()) {
+      if (issue.line() == 1) {
+        foundIssueAtLine1 = true;
+        assertThat(issue.inputPath()).isEqualTo(new DefaultInputFile("com.foo.project", "src/sample.xoo"));
+        assertThat(issue.message()).isEqualTo("A template rule");
+      }
+      if (issue.line() == 2) {
+        foundIssueAtLine2 = true;
+        assertThat(issue.inputPath()).isEqualTo(new DefaultInputFile("com.foo.project", "src/sample.xoo"));
+        assertThat(issue.message()).isEqualTo("Another template rule");
+      }
+    }
+    assertThat(foundIssueAtLine1).isTrue();
+    assertThat(foundIssueAtLine2).isTrue();
+  }
+
+}
index 35447556df9113288b23d316b352d65188bb6225..06091f3729722bebca521da73608f043c372fb0b 100644 (file)
@@ -63,4 +63,11 @@ public interface ActiveRule {
    */
   @CheckForNull
   String internalKey();
+
+  /**
+   * Optional rule key of the template rule.
+   * @since 4.5.3
+   */
+  @CheckForNull
+  String templateRuleKey();
 }
index ab8ff4fbdec3f0f999d4f1d60a1f794da9962a16..5cdc2aba2b3455e20465d21815a6bb411cf0ac35 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.api.utils.SonarException;
 import org.sonar.check.RuleProperty;
 
 import javax.annotation.CheckForNull;
+
 import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.Collection;
@@ -122,10 +123,12 @@ public class Checks<C> {
     }
 
     for (ActiveRule activeRule : activeRules.findByRepository(repository)) {
-      String engineKey = StringUtils.defaultIfBlank(activeRule.internalKey(), activeRule.ruleKey().rule());
+      String engineKey = StringUtils.defaultIfBlank(activeRule.templateRuleKey(), activeRule.ruleKey().rule());
       Object checkClassesOrObject = checksByEngineKey.get(engineKey);
-      Object obj = instantiate(activeRule, checkClassesOrObject);
-      add(activeRule.ruleKey(), (C) obj);
+      if (checkClassesOrObject != null) {
+        Object obj = instantiate(activeRule, checkClassesOrObject);
+        add(activeRule.ruleKey(), (C) obj);
+      }
     }
     return this;
   }
index 08d34525d69f56db5a5a4c374c2fe611d2ade2cd..bfe7b620828546f90c6afacb4614299f3e64c584 100644 (file)
@@ -31,13 +31,14 @@ import java.util.Map;
 public class DefaultActiveRule implements ActiveRule {
   private final RuleKey ruleKey;
   private final String name;
-  private final String severity, internalKey, language;
+  private final String severity, internalKey, language, templateRuleKey;
   private final Map<String, String> params;
 
   DefaultActiveRule(NewActiveRule newActiveRule) {
     this.severity = newActiveRule.severity;
     this.name = newActiveRule.name;
     this.internalKey = newActiveRule.internalKey;
+    this.templateRuleKey = newActiveRule.templateRuleKey;
     this.ruleKey = newActiveRule.ruleKey;
     this.params = ImmutableMap.copyOf(newActiveRule.params);
     this.language = newActiveRule.language;
@@ -77,4 +78,9 @@ public class DefaultActiveRule implements ActiveRule {
   public String internalKey() {
     return internalKey;
   }
+
+  @Override
+  public String templateRuleKey() {
+    return templateRuleKey;
+  }
 }
index 3f20d89bf3f3a666a88d6180c7f58f83932d3530..07e85dc9a76e51155fcb26af2e9496aacd2d5c23 100644 (file)
@@ -36,7 +36,7 @@ public class NewActiveRule {
   String name;
   String severity = Severity.defaultSeverity();
   Map<String, String> params = new HashMap<String, String>();
-  String internalKey, language;
+  String internalKey, language, templateRuleKey;
   private final ActiveRulesBuilder builder;
 
   NewActiveRule(ActiveRulesBuilder builder, RuleKey ruleKey) {
@@ -59,6 +59,11 @@ public class NewActiveRule {
     return this;
   }
 
+  public NewActiveRule setTemplateRuleKey(@Nullable String templateRuleKey) {
+    this.templateRuleKey = templateRuleKey;
+    return this;
+  }
+
   public NewActiveRule setLanguage(@Nullable String language) {
     this.language = language;
     return this;
index 42f8d7f66541062ace3368a9254eb5d326ec2319..d802900f71bb5d560446d2276cd3c93a2d05d7e5 100644 (file)
@@ -114,9 +114,9 @@ public class CheckFactoryTest {
   }
 
   @Test
-  public void use_engine_key() {
-    RuleKey ruleKey = RuleKey.of("squid", "One");
-    builder.create(ruleKey).setInternalKey("S0001").activate();
+  public void use_template_rule_key() {
+    RuleKey ruleKey = RuleKey.of("squid", "S0001_123");
+    builder.create(ruleKey).setTemplateRuleKey("S0001").activate();
 
     CheckFactory checkFactory = new CheckFactory(builder.build());
     Checks checks = checkFactory.create("squid").addAnnotatedChecks(CheckWithKey.class);