Skip to content

Commit

Permalink
SONAR-6162 Fix NPE when searching for Check of custom rules
Browse files Browse the repository at this point in the history
  • Loading branch information
henryju committed Feb 9, 2015
1 parent b49f4a0 commit a2fa3e4
Show file tree
Hide file tree
Showing 14 changed files with 284 additions and 11 deletions.
Expand Up @@ -27,6 +27,7 @@
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;
Expand Down Expand Up @@ -72,11 +73,11 @@ public List getExtensions() {
TestCaseSensor.class,
CoveragePerTestSensor.class,
DependencySensor.class,
ChecksSensor.class,

OneIssuePerLineSensor.class,
OneIssueOnDirPerFileSensor.class,
CreateIssueByInternalKeySensor.class
);
}

}
@@ -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);

}
@@ -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();
}

}
@@ -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));
}
}
}

}
Expand Up @@ -23,7 +23,9 @@
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".
Expand All @@ -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")
Expand Down
Expand Up @@ -27,6 +27,6 @@ public class XooPluginTest {

@Test
public void provide_extensions() {
assertThat(new XooPlugin().getExtensions()).hasSize(18);
assertThat(new XooPlugin().getExtensions()).hasSize(19);
}
}
Expand Up @@ -37,7 +37,7 @@ public void define_xoo_rules() {
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");
Expand Down
Expand Up @@ -52,6 +52,7 @@ private ActiveRules load(ProjectReferentials ref) {
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()) {
Expand Down
@@ -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();
}

}
Expand Up @@ -63,4 +63,11 @@ public interface ActiveRule {
*/
@CheckForNull
String internalKey();

/**
* Optional rule key of the template rule.
* @since 4.5.3
*/
@CheckForNull
String templateRuleKey();
}
Expand Up @@ -28,6 +28,7 @@
import org.sonar.check.RuleProperty;

import javax.annotation.CheckForNull;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -122,10 +123,12 @@ public Checks<C> addAnnotatedChecks(Collection checkClassesOrObjects) {
}

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;
}
Expand Down
Expand Up @@ -31,13 +31,14 @@
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;
Expand Down Expand Up @@ -77,4 +78,9 @@ public Map<String, String> params() {
public String internalKey() {
return internalKey;
}

@Override
public String templateRuleKey() {
return templateRuleKey;
}
}
Expand Up @@ -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) {
Expand All @@ -59,6 +59,11 @@ public NewActiveRule setInternalKey(@Nullable String internalKey) {
return this;
}

public NewActiveRule setTemplateRuleKey(@Nullable String templateRuleKey) {
this.templateRuleKey = templateRuleKey;
return this;
}

public NewActiveRule setLanguage(@Nullable String language) {
this.language = language;
return this;
Expand Down

0 comments on commit a2fa3e4

Please sign in to comment.