Browse Source

add AnnotationRuleRepository to load rules from sonar-check-api annotations

tags/2.6
simonbrandhof 13 years ago
parent
commit
1dfd7034c4

+ 1
- 1
plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleAuditListener.java View File

@@ -53,7 +53,7 @@ public class CheckstyleAuditListener implements AuditListener, BatchExtension {
Rule rule = ruleFinder.findByKey(CheckstyleConstants.REPOSITORY_KEY, ruleKey);
if (rule != null) {
initResource(event);
Violation violation = new Violation(rule, currentResource)
Violation violation = Violation.create(rule, currentResource)
.setLineId(getLineId(event))
.setMessage(getMessage(event));
context.saveViolation(violation);

+ 1
- 1
plugins/sonar-findbugs-plugin/src/main/java/org/sonar/plugins/findbugs/FindbugsSensor.java View File

@@ -60,7 +60,7 @@ public class FindbugsSensor implements Sensor, DependsUponMavenPlugin, Generates
Rule rule = ruleFinder.findByKey(FindbugsConstants.REPOSITORY_KEY, fbViolation.getType());
JavaFile resource = new JavaFile(fbViolation.getSonarJavaFileKey());
if (context.getResource(resource) != null) {
Violation violation = new Violation(rule, resource).setLineId(fbViolation.getStart()).setMessage(fbViolation.getLongMessage());
Violation violation = Violation.create(rule, resource).setLineId(fbViolation.getStart()).setMessage(fbViolation.getLongMessage());
context.saveViolation(violation);
}
}

+ 1
- 1
plugins/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdViolationsXmlParserTest.java View File

@@ -72,7 +72,7 @@ public class PmdViolationsXmlParserTest {
verify(context, times(30)).saveViolation(argThat(new IsViolationOnJavaClass()));
verify(context, times(4)).saveViolation(argThat(new IsViolationOnJavaClass(new JavaFile("ch.hortis.sonar.mvn.ClassWithComments"))));

Violation wanted = new Violation(null, new JavaFile("ch.hortis.sonar.mvn.ClassWithComments"))
Violation wanted = Violation.create((Rule)null, new JavaFile("ch.hortis.sonar.mvn.ClassWithComments"))
.setMessage("Avoid unused local variables such as 'toto'.")
.setLineId(22);
verify(context, times(1)).saveViolation(argThat(new IsViolation(wanted)));

+ 0
- 1
plugins/sonar-squid-java-plugin/pom.xml View File

@@ -134,7 +134,6 @@
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

+ 1
- 1
sonar-batch/src/main/java/org/sonar/batch/ViolationsDao.java View File

@@ -52,7 +52,7 @@ public class ViolationsDao {
List<RuleFailureModel> models = session.getResults(RuleFailureModel.class, "snapshotId", snapshotId);
List<Violation> violations = new ArrayList<Violation>();
for (RuleFailureModel model : models) {
Violation violation = new Violation(model.getRule(), resource);
Violation violation = Violation.create(model.getRule(), resource);
violation.setLineId(model.getLine());
violation.setMessage(model.getMessage());
violation.setPriority(model.getPriority());

+ 1
- 1
sonar-deprecated/src/main/java/org/sonar/api/batch/AbstractViolationsStaxParser.java View File

@@ -164,7 +164,7 @@ public abstract class AbstractViolationsStaxParser {
Rule rule = getRule(violationCursor);
Integer line = getLineIndex(violationCursor);
if (rule != null && resource != null) {
Violation violation = new Violation(rule, resource)
Violation violation = Violation.create(rule, resource)
.setLineId(line)
.setMessage(messageFor(violationCursor));
context.saveViolation(violation);

+ 1
- 1
sonar-deprecated/src/main/java/org/sonar/api/checks/checkers/MessageDispatcher.java View File

@@ -96,7 +96,7 @@ public class MessageDispatcher {
public void log(Resource resource, Message message) {
Object checker = message.getChecker();
Check check = getCheck(checker);
Violation violation = new Violation(new Rule(check.getRepositoryKey(), check.getTemplateKey()), resource);
Violation violation = Violation.create(new Rule(check.getRepositoryKey(), check.getTemplateKey()), resource);
violation.setLineId(message.getLine());
violation.setMessage(message.getText(Locale.ENGLISH));
violation.setPriority(RulePriority.fromCheckPriority(check.getPriority()));

+ 31
- 0
sonar-plugin-api/src/main/java/org/sonar/api/ExtensionProvider.java View File

@@ -0,0 +1,31 @@
/*
* 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;

import java.util.Collection;

/**
* @since 2.3
*/
public interface ExtensionProvider {

Collection provide();

}

+ 2
- 2
sonar-plugin-api/src/main/java/org/sonar/api/profiles/AnnotationProfileDefinition.java View File

@@ -20,10 +20,10 @@
package org.sonar.api.profiles;

import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleAnnotationUtils;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.check.AnnotationIntrospector;
import org.sonar.check.BelongsToProfile;

import java.util.Collection;
@@ -61,7 +61,7 @@ public abstract class AnnotationProfileDefinition extends ProfileDefinition {

private void registerRule(Class aClass, BelongsToProfile belongsToProfile, RulesProfile profile, ValidationMessages validation) {
if (belongsToProfile != null) {
String ruleKey = AnnotationIntrospector.getCheckKey(aClass);
String ruleKey = RuleAnnotationUtils.getRuleKey(aClass);
Rule rule = ruleFinder.findByKey(repositoryKey, ruleKey);
if (rule == null) {
validation.addErrorText("Rule not found: [repository=" + repositoryKey + ", key=" + ruleKey + "]");

+ 13
- 60
sonar-plugin-api/src/main/java/org/sonar/api/rules/RuleAnnotationUtils.java View File

@@ -19,77 +19,30 @@
*/
package org.sonar.api.rules;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.check.AnnotationIntrospector;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.utils.AnnotationUtils;
import org.sonar.check.Check;

/**
* @since 2.3
*/
public final class RuleAnnotationUtils {

private static final Logger LOG = LoggerFactory.getLogger(RuleAnnotationUtils.class);

private RuleAnnotationUtils() {
// only static methods
}

public static List<Rule> readAnnotatedClasses(Collection<Class> annotatedClasses) {
List<Rule> rules = new ArrayList<Rule>();
if (annotatedClasses != null) {
for (Class annotatedClass : annotatedClasses) {
Rule rule = readAnnotatedClass(annotatedClass);
if (rule != null) {
rules.add(rule);
}
}
}
return rules;
}

public static Rule readAnnotatedClass(Class annotatedClass) {
org.sonar.check.Check checkAnnotation = AnnotationIntrospector.getCheckAnnotation(annotatedClass);
if (checkAnnotation == null) {
LOG.warn("The class " + annotatedClass.getCanonicalName() + " is not a rule. It should be annotated with " + org.sonar.check.Check.class);
return null;
}

Rule rule = toRule(annotatedClass, checkAnnotation);
Field[] fields = annotatedClass.getDeclaredFields();
if (fields != null) {
for (Field field : fields) {
createParam(rule, field);
}
}
return rule;
}

private static Rule toRule(Class annotatedClass, org.sonar.check.Check annotation) {
String key = AnnotationIntrospector.getCheckKey(annotatedClass);

Rule rule = Rule.create();
rule.setKey(key);
rule.setName(annotation.title());
rule.setDescription(annotation.description());
rule.setRulesCategory(new RulesCategory(annotation.isoCategory().name()));
rule.setPriority(RulePriority.fromCheckPriority(annotation.priority()));
return rule;
}

private static void createParam(Rule rule, Field field) {
org.sonar.check.CheckProperty propertyAnnotation = field.getAnnotation(org.sonar.check.CheckProperty.class);
if (propertyAnnotation != null) {
String fieldKey = propertyAnnotation.key();
if (fieldKey==null || "".equals(fieldKey)) {
fieldKey = field.getName();
public static String getRuleKey(Class annotatedClass) {
String key = null;
org.sonar.check.Rule ruleAnnotation = AnnotationUtils.getClassAnnotation(annotatedClass, org.sonar.check.Rule.class);
if (ruleAnnotation != null) {
key = ruleAnnotation.key();
} else {
Check checkAnnotation = AnnotationUtils.getClassAnnotation(annotatedClass, Check.class);
if (checkAnnotation != null) {
key = checkAnnotation.key();
}
RuleParam param = rule.createParameter(fieldKey);
param.setDescription(propertyAnnotation.description());
}
return StringUtils.defaultIfEmpty(key, annotatedClass.getCanonicalName());
}
}

+ 14
- 0
sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java View File

@@ -38,7 +38,9 @@ public class Violation {

/**
* Creates of a violation from a rule. Will need to define the resource later on
* @deprecated since 2.3. Use the factory method create()
*/
@Deprecated
public Violation(Rule rule) {
this.rule = rule;
}
@@ -48,7 +50,9 @@ public class Violation {
*
* @param rule the rule that has been violated
* @param resource the resource the violation should be attached to
* @deprecated since 2.3. Use the factory method create()
*/
@Deprecated
public Violation(Rule rule, Resource resource) {
this.resource = resource;
this.rule = rule;
@@ -118,7 +122,9 @@ public class Violation {
* Sets the violation priority
*
* @return the current object
* @deprecated since 2.3. The priority is set by the quality profile.
*/
@Deprecated
public Violation setPriority(RulePriority priority) {
this.priority = priority;
return this;
@@ -170,4 +176,12 @@ public class Violation {
public String toString() {
return ReflectionToStringBuilder.toString(this);
}

public static Violation create(ActiveRule activeRule, Resource resource) {
return new Violation(activeRule.getRule()).setResource(resource);
}

public static Violation create(Rule rule, Resource resource) {
return new Violation(rule).setResource(resource);
}
}

+ 28
- 17
sonar-plugin-api/src/test/java/org/sonar/api/resources/JavaFileTest.java View File

@@ -22,7 +22,10 @@ package org.sonar.api.resources;
import org.apache.commons.io.FileUtils;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.io.IOException;
@@ -30,6 +33,10 @@ import java.util.Arrays;
import java.util.List;

public class JavaFileTest {

@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
@Test
public void testNewClass() {
JavaFile javaClass = new JavaFile("org.foo.bar.Hello", false);
@@ -127,8 +134,9 @@ public class JavaFileTest {
assertEquals("onelevel.MyFile", clazz.getKey());
assertEquals("onelevel", clazz.getParent().getKey());

List<File> sources = Arrays.asList(newDir("sources"));
JavaFile javaFile = JavaFile.fromAbsolutePath(absPath("sources/onelevel/MyFile.java"), sources, false);
File sourceDir = newDir("sources");
List<File> sources = Arrays.asList(sourceDir);
JavaFile javaFile = JavaFile.fromAbsolutePath(absPath(sourceDir, "onelevel/MyFile.java"), sources, false);
assertEquals("onelevel.MyFile", javaFile.getKey());
assertEquals("MyFile", javaFile.getName());
assertEquals("onelevel", javaFile.getParent().getKey());
@@ -139,8 +147,10 @@ public class JavaFileTest {

@Test
public void shouldResolveClassFromAbsolutePath() throws IOException {
List<File> sources = Arrays.asList(newDir("source1"), newDir("source2"));
JavaFile javaFile = JavaFile.fromAbsolutePath(absPath("source2/foo/bar/MyFile.java"), sources, false);
File sources1 = newDir("source1");
File sources2 = newDir("source2");
List<File> sources = Arrays.asList(sources1, sources2);
JavaFile javaFile = JavaFile.fromAbsolutePath(absPath(sources2, "foo/bar/MyFile.java"), sources, false);
assertThat("foo.bar.MyFile", is(javaFile.getKey()));
assertThat(javaFile.getLongName(), is("foo.bar.MyFile"));
assertThat(javaFile.getName(), is("MyFile"));
@@ -149,9 +159,11 @@ public class JavaFileTest {

@Test
public void shouldResolveFromAbsolutePathEvenIfDefaultPackage() throws IOException {
List<File> sources = Arrays.asList(newDir("source1"), newDir("source2"));
File source1 = newDir("source1");
File source2 = newDir("source2");
List<File> sources = Arrays.asList(source1, source2);

JavaFile javaClass = JavaFile.fromAbsolutePath(absPath("source1/MyClass.java"), sources, false);
JavaFile javaClass = JavaFile.fromAbsolutePath(absPath(source1, "MyClass.java"), sources, false);
assertEquals(JavaPackage.DEFAULT_PACKAGE_NAME + ".MyClass", javaClass.getKey());
assertEquals("MyClass", javaClass.getName());

@@ -160,14 +172,16 @@ public class JavaFileTest {

@Test
public void shouldResolveOnlyJavaFromAbsolutePath() throws IOException {
List<File> sources = Arrays.asList(newDir("source1"));
assertNull(JavaFile.fromAbsolutePath(absPath("source1/foo/bar/my_file.sql"), sources, false));
File source1 = newDir("source1");
List<File> sources = Arrays.asList(source1);
assertNull(JavaFile.fromAbsolutePath(absPath(source1, "foo/bar/my_file.sql"), sources, false));
}

@Test
public void shouldNotFailWhenResolvingUnknownClassFromAbsolutePath() throws IOException {
List<File> sources = Arrays.asList(newDir("source1"));
assertNull(JavaFile.fromAbsolutePath(absPath("/home/other/src/main/java/foo/bar/MyClass.java"), sources, false));
File source1 = newDir("source1");
List<File> sources = Arrays.asList(source1);
assertNull(JavaFile.fromAbsolutePath("/home/other/src/main/java/foo/bar/MyClass.java", sources, false));
}

@Test
@@ -211,14 +225,11 @@ public class JavaFileTest {
}


private File newDir(String relativePath) throws IOException {
File target = new File("target", relativePath);
FileUtils.forceMkdir(target);
FileUtils.cleanDirectory(target);
return target;
private File newDir(String dirName) throws IOException {
return tempFolder.newFolder(dirName);
}

private String absPath(String relativePath) throws IOException {
return new File("target", relativePath).getCanonicalPath();
private String absPath(File dir, String filePath) throws IOException {
return new File(dir, filePath).getPath();
}
}

+ 1
- 2
sonar-plugin-api/src/test/java/org/sonar/api/rules/AnnotatedCheck.java View File

@@ -19,9 +19,8 @@
*/
package org.sonar.api.rules;

import org.sonar.check.Check;
import org.sonar.check.IsoCategory;

@Check(title ="Annotated Check", description = "Description", isoCategory = IsoCategory.Reliability)
@org.sonar.check.Rule(name ="Annotated Check", description = "Description", isoCategory = IsoCategory.Reliability)
public class AnnotatedCheck {
}

+ 4
- 5
sonar-plugin-api/src/test/java/org/sonar/api/rules/AnnotatedCheckWithParameters.java View File

@@ -19,17 +19,16 @@
*/
package org.sonar.api.rules;

import org.sonar.check.Check;
import org.sonar.check.CheckProperty;
import org.sonar.check.IsoCategory;
import org.sonar.check.RuleProperty;

@Check(key = "overriden_key",title ="Check with parameters", description = "Has parameters", isoCategory = IsoCategory.Efficiency)
@org.sonar.check.Rule(key = "overridden_key", name = "Check with parameters", description = "Has parameters", isoCategory = IsoCategory.Efficiency)
public class AnnotatedCheckWithParameters {

@CheckProperty(description ="Maximum value")
@RuleProperty(description = "Maximum value")
private String max;

@CheckProperty(key = "overidden_min", description ="Minimum value")
@RuleProperty(key = "overridden_min", description = "Minimum value")
protected String min;

private int nonConfigurableProperty;

+ 27
- 0
sonar-plugin-api/src/test/java/org/sonar/api/rules/DeprecatedAnnotatedCheck.java View File

@@ -0,0 +1,27 @@
/*
* 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.rules;

import org.sonar.check.Check;
import org.sonar.check.IsoCategory;

@Check(title ="Annotated Check", description = "Description", isoCategory = IsoCategory.Reliability)
public class DeprecatedAnnotatedCheck {
}

+ 10
- 28
sonar-plugin-api/src/test/java/org/sonar/api/rules/RuleAnnotationUtilsTest.java View File

@@ -19,46 +19,28 @@
*/
package org.sonar.api.rules;

import org.hamcrest.core.Is;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;

public class RuleAnnotationUtilsTest {

@Test
public void readAnnotatedClassWithoutParameters() {
Rule rule = RuleAnnotationUtils.readAnnotatedClass(AnnotatedCheck.class);
assertNotNull(rule);
assertThat(rule.getKey(), is(AnnotatedCheck.class.getName()));
assertThat(rule.getName(), is("Annotated Check"));
assertThat(rule.getConfigKey(), nullValue());
assertThat(rule.getParams().size(), is(0));
assertThat(rule.getDescription(), is("Description"));
assertThat(rule.getCardinality(), Is.is(Rule.Cardinality.SINGLE));
assertThat(rule.getRulesCategory().getName(), Is.is(Iso9126RulesCategories.RELIABILITY.getName()));
public void defaultKeyShouldBeTheClassName() {
String key = RuleAnnotationUtils.getRuleKey(AnnotatedCheck.class);
assertThat(key, is(AnnotatedCheck.class.getName()));
}

@Test
public void ruleKeyCanBeOverridden() {
Rule rule = RuleAnnotationUtils.readAnnotatedClass(AnnotatedCheckWithParameters.class);
assertNotNull(rule);
assertThat(rule.getKey(), is("overriden_key"));
public void shouldGetKeyFromDeprecatedCheckAnnotation() {
String key = RuleAnnotationUtils.getRuleKey(DeprecatedAnnotatedCheck.class);
assertThat(key, is(DeprecatedAnnotatedCheck.class.getName()));
}
@Test
public void readAnnotatedClassWithParameters() {
Rule rule = RuleAnnotationUtils.readAnnotatedClass(AnnotatedCheckWithParameters.class);
assertNotNull(rule);
assertThat(rule.getParams().size(), is(2));
assertThat(rule.getParam("max"), not(nullValue()));
assertThat(rule.getParam("max").getDescription(), is("Maximum value"));

assertThat(rule.getParam("min"), nullValue());
assertThat(rule.getParam("overidden_min"), not(nullValue()));
assertThat(rule.getParam("overidden_min").getDescription(), is("Minimum value"));
@Test
public void shouldGetKey() {
String key = RuleAnnotationUtils.getRuleKey(AnnotatedCheckWithParameters.class);
assertThat(key, is("overridden_key"));
}
}

Loading…
Cancel
Save