diff options
7 files changed, 315 insertions, 24 deletions
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidExecutor.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidExecutor.java index bbc1bb31777..a2736b7c755 100644 --- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidExecutor.java +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/SquidExecutor.java @@ -19,11 +19,6 @@ */ package org.sonar.plugins.squid; -import java.io.File; -import java.nio.charset.Charset; -import java.util.Collection; -import java.util.List; - import org.apache.commons.lang.StringUtils; import org.sonar.api.batch.SensorContext; import org.sonar.api.checks.CheckFactory; @@ -31,6 +26,8 @@ import org.sonar.api.checks.NoSonarFilter; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.utils.TimeProfiler; +import org.sonar.java.api.JavaClass; +import org.sonar.java.api.JavaMethod; import org.sonar.java.ast.JavaAstScanner; import org.sonar.java.bytecode.BytecodeScanner; import org.sonar.java.squid.JavaSquidConfiguration; @@ -39,13 +36,15 @@ import org.sonar.plugins.squid.bridges.Bridge; import org.sonar.plugins.squid.bridges.BridgeFactory; import org.sonar.plugins.squid.bridges.ResourceIndex; import org.sonar.squid.Squid; -import org.sonar.squid.api.CodeVisitor; -import org.sonar.squid.api.SourceCode; -import org.sonar.squid.api.SourceFile; -import org.sonar.squid.api.SourcePackage; +import org.sonar.squid.api.*; import org.sonar.squid.indexer.QueryByType; import org.sonar.squid.measures.Metric; +import java.io.File; +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.List; + public final class SquidExecutor { private Squid squid; @@ -100,6 +99,8 @@ public final class SquidExecutor { saveProject(resourceIndex, bridges); savePackages(resourceIndex, bridges); saveFiles(resourceIndex, bridges); + saveClasses(resourceIndex, bridges); + saveMethods(resourceIndex, bridges); profiler.stop(); } } @@ -131,6 +132,27 @@ public final class SquidExecutor { } } + private void saveClasses(ResourceIndex resourceIndex, List<Bridge> bridges) { + Collection<SourceCode> squidClasses = squid.search(new QueryByType(SourceClass.class)); + for (SourceCode squidClass : squidClasses) { + Resource sonarClass = resourceIndex.get(squidClass); + for (Bridge bridge : bridges) { + bridge.onClass((SourceClass) squidClass, (JavaClass)sonarClass); + } + } + } + + private void saveMethods(ResourceIndex resourceIndex, List<Bridge> bridges) { + Collection<SourceCode> squidMethods = squid.search(new QueryByType(SourceMethod.class)); + for (SourceCode squidMethod : squidMethods) { + JavaMethod sonarMethod = (JavaMethod)resourceIndex.get(squidMethod); + for (Bridge bridge : bridges) { + bridge.onMethod((SourceMethod) squidMethod, sonarMethod); + } + } + } + + void scanSources(Collection<File> sourceFiles) { if (sourceFiles != null && !sourceFiles.isEmpty()) { TimeProfiler profiler = new TimeProfiler(getClass()).start("Java AST scan"); diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BasicBridge.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BasicBridge.java index 13e5779afaf..9331d9c09b7 100644 --- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BasicBridge.java +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BasicBridge.java @@ -21,10 +21,9 @@ package org.sonar.plugins.squid.bridges; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; -import org.sonar.squid.api.SourceCode; -import org.sonar.squid.api.SourceFile; -import org.sonar.squid.api.SourcePackage; -import org.sonar.squid.api.SourceProject; +import org.sonar.java.api.JavaClass; +import org.sonar.java.api.JavaMethod; +import org.sonar.squid.api.*; public abstract class BasicBridge extends Bridge { @@ -47,6 +46,16 @@ public abstract class BasicBridge extends Bridge { onResource(squidFile, sonarFile); } + @Override + public final void onClass(SourceClass squidClass, JavaClass sonarClass) { + onResource(squidClass, sonarClass); + } + + @Override + public final void onMethod(SourceMethod squidMethod, JavaMethod sonarMethod) { + onResource(squidMethod, sonarMethod); + } + protected void onResource(SourceCode squidResource, Resource sonarResource) { } diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/Bridge.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/Bridge.java index 51ab4d0e1f7..01752ffe749 100644 --- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/Bridge.java +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/Bridge.java @@ -24,11 +24,9 @@ import org.sonar.api.checks.CheckFactory; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.java.api.JavaClass; +import org.sonar.java.api.JavaMethod; import org.sonar.squid.Squid; -import org.sonar.squid.api.SourceClass; -import org.sonar.squid.api.SourceFile; -import org.sonar.squid.api.SourcePackage; -import org.sonar.squid.api.SourceProject; +import org.sonar.squid.api.*; /** * Pattern visitor : project -> packages -> files -> classes @@ -80,4 +78,8 @@ public abstract class Bridge { public void onClass(SourceClass squidClass, JavaClass sonarClass) { } + + public void onMethod(SourceMethod squidMethod, JavaMethod sonarMethod) { + + } } diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BridgeFactory.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BridgeFactory.java index f3c822ca2a2..05b8726e1b1 100644 --- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BridgeFactory.java +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/BridgeFactory.java @@ -35,7 +35,7 @@ public final class BridgeFactory { } private static List<Bridge> create(NoSonarFilter noSonarFilter) { - return Arrays.asList(new OneToOneBridge(), new PackagesBridge(), new PublicUndocumentedApiBridge(), new CommentLinesDensityBridge(), + return Arrays.asList(new CopyBasicMeasuresBridge(), new PackagesBridge(), new PublicUndocumentedApiBridge(), new ClassComplexityDistributionBridge(), new FunctionComplexityDistributionBridge(), new NoSonarFilterLoader(noSonarFilter), new ChidamberKemererBridge(), new RobertCMartinBridge(), new ChidamberKemererDistributionBridge(), new DesignBridge(), new Lcom4BlocksBridge(), new ChecksBridge()); diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ResourceIndex.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ResourceIndex.java index c5d5fa3c55a..1e869d208f2 100644 --- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ResourceIndex.java +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/plugins/squid/bridges/ResourceIndex.java @@ -19,6 +19,7 @@ */ package org.sonar.plugins.squid.bridges; +import org.apache.commons.lang.StringUtils; import org.sonar.api.batch.SensorContext; import org.sonar.api.batch.SquidUtils; import org.sonar.api.resources.JavaFile; @@ -26,6 +27,7 @@ import org.sonar.api.resources.JavaPackage; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.java.api.JavaClass; +import org.sonar.java.api.JavaMethod; import org.sonar.squid.Squid; import org.sonar.squid.api.*; import org.sonar.squid.indexer.QueryByType; @@ -40,7 +42,7 @@ public final class ResourceIndex extends HashMap<SourceCode, Resource> { loadSquidPackages(squid, context); loadSquidFiles(squid, context); loadSquidClasses(squid, context); -// loadSquidMethods(squid, context); + loadSquidMethods(squid, context); return this; } @@ -71,22 +73,34 @@ public final class ResourceIndex extends HashMap<SourceCode, Resource> { for (SourceCode squidClass : classes) { JavaFile sonarFile = (JavaFile)get(squidClass.getParent(SourceFile.class)); JavaClass sonarClass = new JavaClass.Builder() - .setName(squidClass.getKey()) + .setName(convertClassKey(squidClass.getKey())) .setFromLine(squidClass.getStartAtLine()) .setToLine(squidClass.getEndAtLine()) .create(); context.index(sonarClass, sonarFile); - put(squidClass, context.getResource(sonarClass)); // resource is reloaded to get the id + put(squidClass, sonarClass); } } private void loadSquidMethods(Squid squid, SensorContext context) { Collection<SourceCode> methods = squid.search(new QueryByType(SourceMethod.class)); for (SourceCode squidMethod : methods) { - JavaClass sonarClass = (JavaClass)get(squidMethod.getParent(SourceClass.class)); - //context.index(new JavaMethod(squidMethod.getKey()), sonarClass); - //put(squidMethod, context.getResource(sonarClass)); // resource is reloaded to get the id + SourceClass squidClass = squidMethod.getParent(SourceClass.class); + JavaClass sonarClass = (JavaClass)get(squidClass); + JavaMethod sonarMethod = new JavaMethod.Builder() + .setClass(sonarClass) + .setSignature(squidMethod.getName()) + .setFromLine(squidMethod.getStartAtLine()) + .setToLine(squidMethod.getEndAtLine()) + .create(); + + context.index(sonarMethod, sonarClass); + put(squidMethod, sonarMethod); } } + static String convertClassKey(String squidClassKey) { + return StringUtils.replace(squidClassKey, "/", "."); + } + } diff --git a/sonar-java-api/src/main/java/org/sonar/java/api/JavaMethod.java b/sonar-java-api/src/main/java/org/sonar/java/api/JavaMethod.java new file mode 100644 index 00000000000..6cf02551be6 --- /dev/null +++ b/sonar-java-api/src/main/java/org/sonar/java/api/JavaMethod.java @@ -0,0 +1,195 @@ +/* + * 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.java.api; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.resources.Java; +import org.sonar.api.resources.Language; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.Resource; + +/** + * @since 2.6 + */ +public final class JavaMethod extends Resource { + + public static final int UNKNOWN_LINE = -1; + private static final String CLASS_SEPARATOR = "#"; + + private String signature; + private String className; + private int fromLine; + private int toLine; + + private JavaMethod(String className, String signature) { + setKey(toKey(className, signature)); + this.className = className; + this.signature = signature; + } + + private JavaMethod(String className, String signature, int fromLine, int toLine) { + this(className, signature); + this.fromLine = fromLine; + this.toLine = toLine; + } + + public int getFromLine() { + return fromLine; + } + + public int getToLine() { + return toLine; + } + + public String getSignature() { + return signature; + } + + public String getClassName() { + return className; + } + + @Override + public String getName() { + return signature; + } + + @Override + public String getLongName() { + return getKey(); + } + + @Override + public String getDescription() { + return null; + } + + @Override + public Language getLanguage() { + return Java.INSTANCE; + } + + @Override + public String getScope() { + return null; + } + + @Override + public String getQualifier() { + return Qualifiers.METHOD; + } + + @Override + public Resource getParent() { + return null; + } + + @Override + public boolean matchFilePattern(String antPattern) { + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JavaMethod that = (JavaMethod) o; + return getKey().equals(that.getKey()); + } + + @Override + public int hashCode() { + return getKey().hashCode(); + } + + @Override + public String toString() { + return getKey(); + } + + public static JavaMethod createRef(String key) { + String[] parts = splitClassAndMethodFromKey(key); + return new JavaMethod(parts[0], parts[1]); + } + + private static String[] splitClassAndMethodFromKey(String key) { + String[] parts = StringUtils.split(key, CLASS_SEPARATOR); + if (parts.length!=2) { + throw new IllegalArgumentException("Java method does not respect the format: org.foo.Bar#methodName(LString;)V. Got: " + key); + } + return parts; + } + + public static JavaMethod createRef(JavaClass javaClass, String signature) { + return new JavaMethod(javaClass.getName(), signature); + } + + static String toKey(JavaClass javaClass, String signature) { + return toKey(javaClass.getName(), signature); + } + + static String toKey(String className, String signature) { + return new StringBuilder().append(className).append(CLASS_SEPARATOR).append(signature).toString(); + } + + public static class Builder { + private String className; + private String signature; + private int fromLine = UNKNOWN_LINE; + private int toLine = UNKNOWN_LINE; + + public Builder setKey(String key) { + String[] parts = splitClassAndMethodFromKey(key); + this.className = parts[0]; + this.signature = parts[1]; + return this; + } + + public Builder setClass(String className) { + this.className = className; + return this; + } + + public Builder setClass(JavaClass javaClass) { + this.className = javaClass.getName(); + return this; + } + + public Builder setSignature(String signature) { + this.signature = signature; + return this; + } + + public Builder setFromLine(int fromLine) { + this.fromLine = Math.max(UNKNOWN_LINE, fromLine); + return this; + } + + public Builder setToLine(int toLine) { + this.toLine = Math.max(UNKNOWN_LINE, toLine); + return this; + } + + public JavaMethod create() { + return new JavaMethod(className, signature, fromLine, toLine); + } + } +} diff --git a/sonar-java-api/src/test/java/org/sonar/java/api/JavaMethodTest.java b/sonar-java-api/src/test/java/org/sonar/java/api/JavaMethodTest.java new file mode 100644 index 00000000000..bc6976aca25 --- /dev/null +++ b/sonar-java-api/src/test/java/org/sonar/java/api/JavaMethodTest.java @@ -0,0 +1,49 @@ +/* + * 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.java.api; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +public class JavaMethodTest { + @Test + public void shouldCreateReference() { + String key = "org.foo.Bar#hello(LString;)V"; + JavaMethod method = JavaMethod.createRef(key); + assertThat(method.getKey(), is(key)); + assertThat(method.getClassName(), is("org.foo.Bar")); + assertThat(method.getLongName(), is(key)); + assertThat(method.getName(), is("hello(LString;)V")); + assertThat(method.getSignature(), is("hello(LString;)V")); + } + + @Test + public void shouldCreateReferenceFromClassAndSignature() { + String className = "org.foo.Bar"; + String signature = "hello(LString;)V"; + JavaMethod method = JavaMethod.createRef(JavaClass.createRef(className), signature); + assertThat(method.getKey(), is(className + "#" + signature)); + assertThat(method.getClassName(), is(className)); + assertThat(method.getName(), is(signature)); + assertThat(method.getSignature(), is(signature)); + } +} |