aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorGodin <mandrikov@gmail.com>2010-10-21 11:27:13 +0000
committerGodin <mandrikov@gmail.com>2010-10-21 11:27:13 +0000
commit4309fc779ee20b873226cb3c0081f9d42145b967 (patch)
tree60c0fc181dd8727b39a9fbe32395bdc4de496039 /plugins
parentd0127fb555aebf6c10647d4495e0534c87e073f3 (diff)
downloadsonarqube-4309fc779ee20b873226cb3c0081f9d42145b967.tar.gz
sonarqube-4309fc779ee20b873226cb3c0081f9d42145b967.zip
SONAR-1832: Create an architecture rule engine
Diffstat (limited to 'plugins')
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/ArchitectureCheck.java85
-rw-r--r--plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/check/ArchitectureCheckTest.java20
2 files changed, 67 insertions, 38 deletions
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/ArchitectureCheck.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/ArchitectureCheck.java
index e51d241ce87..2ca7f47ee4f 100644
--- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/ArchitectureCheck.java
+++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/ArchitectureCheck.java
@@ -28,71 +28,100 @@ import org.sonar.check.Priority;
import org.sonar.java.bytecode.asm.AsmClass;
import org.sonar.java.bytecode.asm.AsmEdge;
import org.sonar.squid.api.CheckMessage;
-import org.sonar.squid.api.SourceCodeEdgeUsage;
import org.sonar.squid.api.SourceFile;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import java.util.List;
+import java.util.Set;
+
@Check(key = "Dependency", title = "Respect rule architecture", isoCategory = IsoCategory.Portability, priority = Priority.MINOR, description = "<p>Links between classes must respect defined architecture rules.</p>")
public class ArchitectureCheck extends BytecodeCheck {
- @CheckProperty(title = "Pattern forbidden for from classes", key = "fromClasses")
- private String fromClasses = new String();
+ @CheckProperty(title = "Pattern forbidden for from classes", key = "fromPatterns")
+ private String fromPatterns = new String();
- @CheckProperty(title = "Pattern forbidden for to classes", key = "toClasses")
- private String toClasses = new String();
+ @CheckProperty(title = "Pattern forbidden for to classes", key = "toPatterns")
+ private String toPatterns = new String();
- public String getFromClasses() {
- return fromClasses;
- }
+ private List<WildcardPattern> fromMatchers;
+ private List<WildcardPattern> toMatchers;
+ private AsmClass asmClass;
+ private Set<String> internalNames;
- public void setFromClasses(String fromClasses) {
- this.fromClasses = fromClasses;
+ public String getFromPatterns() {
+ return fromPatterns;
}
- public String getToClasses() {
- return toClasses;
+ public void setFromPatterns(String patterns) {
+ this.fromPatterns = patterns;
}
- public void setToClasses(String toClasses) {
- this.toClasses = toClasses;
+ public String getToPatterns() {
+ return toPatterns;
}
- private AsmClass asmClass;
+ public void setToPatterns(String patterns) {
+ this.toPatterns = patterns;
+ }
@Override
public void visitClass(AsmClass asmClass) {
this.asmClass = asmClass;
+ this.internalNames = Sets.newHashSet();
}
@Override
public void visitEdge(AsmEdge edge) {
if (edge != null) {
- SourceCodeEdgeUsage usage = edge.getUsage();
- if (usage.equals(SourceCodeEdgeUsage.USES) || usage.equals(SourceCodeEdgeUsage.CALLS_METHOD)
- || usage.equals(SourceCodeEdgeUsage.CALLS_FIELD) || usage.equals(SourceCodeEdgeUsage.CONTAINS)) {
- String internalNameTargetClass = edge.getTargetAsmClass().getInternalName();
+ String internalNameTargetClass = edge.getTargetAsmClass().getInternalName();
+ if ( !internalNames.contains(internalNameTargetClass)) {
String nameAsmClass = asmClass.getInternalName();
- if (matchesPattern(nameAsmClass, fromClasses) && matchesPattern(internalNameTargetClass, toClasses)) {
+ if (matches(nameAsmClass, getFromMatchers()) && matches(internalNameTargetClass, getToMatchers())) {
SourceFile sourceFile = getSourceFile(asmClass);
CheckMessage message = new CheckMessage(this, nameAsmClass + " shouldn't directly use " + internalNameTargetClass);
message.setLine(edge.getSourceLineNumber());
sourceFile.log(message);
+ internalNames.add(internalNameTargetClass);
}
}
}
}
- private boolean matchesPattern(String className, String pattern) {
- if (StringUtils.isEmpty(pattern)) {
- return true;
- }
- String[] patterns = pattern.split(",");
- for (String p : patterns) {
- p = StringUtils.replace(p, ".", "/");
- if (WildcardPattern.create(p).match(className)) {
+ private boolean matches(String className, List<WildcardPattern> matchers) {
+ for (WildcardPattern matcher : matchers) {
+ if (matcher.match(className)) {
return true;
}
}
return false;
}
+ private List<WildcardPattern> createMatchers(String pattern) {
+ List<WildcardPattern> matchers = Lists.newArrayList();
+ if (StringUtils.isNotEmpty(pattern)) {
+ String[] patterns = pattern.split(",");
+ for (String p : patterns) {
+ p = StringUtils.replace(p, ".", "/");
+ matchers.add(WildcardPattern.create(p));
+ }
+ }
+ return matchers;
+ }
+
+ private List<WildcardPattern> getFromMatchers() {
+ if (fromMatchers == null) {
+ fromMatchers = createMatchers(fromPatterns);
+ }
+ return fromMatchers;
+ }
+
+ private List<WildcardPattern> getToMatchers() {
+ if (toMatchers == null) {
+ toMatchers = createMatchers(toPatterns);
+ }
+ return toMatchers;
+ }
+
}
diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/check/ArchitectureCheckTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/check/ArchitectureCheckTest.java
index f56e2843a60..7ebe0a05c49 100644
--- a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/check/ArchitectureCheckTest.java
+++ b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/check/ArchitectureCheckTest.java
@@ -19,10 +19,6 @@
*/
package org.sonar.java.bytecode.check;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-import static org.sonar.java.ast.SquidTestUtils.getFile;
-
import org.junit.Test;
import org.sonar.java.ast.JavaAstScanner;
import org.sonar.java.bytecode.BytecodeScanner;
@@ -31,13 +27,17 @@ import org.sonar.squid.Squid;
import org.sonar.squid.api.CheckMessage;
import org.sonar.squid.api.SourceFile;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.sonar.java.ast.SquidTestUtils.getFile;
+
public class ArchitectureCheckTest {
private Squid squid;
@Test
public void testDependencyCheckOneErrorMessage() {
- check("", "java.**.Pattern");
+ check("*", "java.**.Pattern");
SourceFile file = (SourceFile) squid.search("ArchitectureCheckOneErrorMessage.java");
assertThat(file.getCheckMessages().size(), is(1));
@@ -48,10 +48,10 @@ public class ArchitectureCheckTest {
@Test
public void testDependencyCheckDateForbidden() {
- check("", "**.Date");
+ check("*", "**.Date");
SourceFile file = (SourceFile) squid.search("ArchitectureCheckDateForbidden.java");
- assertThat(file.getCheckMessages().size(), is(3));
+ assertThat(file.getCheckMessages().size(), is(2));
// for (CheckMessage message : file.getCheckMessages()) {
// System.out.println(message.getDefaultMessage());
// }
@@ -62,7 +62,7 @@ public class ArchitectureCheckTest {
check("*UI", "java.sql.*");
SourceFile file = (SourceFile) squid.search("ArchitectureCheckToSqlFromUI.java");
- assertThat(file.getCheckMessages().size(), is(7));
+ assertThat(file.getCheckMessages().size(), is(4));
// for (CheckMessage message : file.getCheckMessages()) {
// System.out.println(message.getDefaultMessage() + " at line " + message.getLine());
// }
@@ -78,8 +78,8 @@ public class ArchitectureCheckTest {
private void check(String fromClasses, String toClasses) {
ArchitectureCheck check = new ArchitectureCheck();
- check.setFromClasses(fromClasses);
- check.setToClasses(toClasses);
+ check.setFromPatterns(fromClasses);
+ check.setToPatterns(toClasses);
squid = new Squid(new JavaSquidConfiguration());
squid.register(JavaAstScanner.class).scanDirectory(getFile("/bytecode/architecture/src"));