From d986919813676f22b0d0f34f4e1cb8a65e7a0481 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Fri, 13 Nov 2015 16:24:18 +0100 Subject: [PATCH] SONAR-5894 Support symbol references with different length --- .../xoo/lang/SymbolReferencesSensor.java | 27 +++++++++++++--- .../xoo/lang/SymbolReferencesSensorTest.java | 4 +-- .../batch/source/DefaultSymbolTable.java | 7 ++++- .../batch/source/DefaultSymbolizable.java | 5 +++ .../mediumtest/symbol/SymbolMediumTest.java | 31 ++++++++++++++++++- .../batch/source/DefaultSymbolTableTest.java | 24 +++++++++++++- .../org/sonar/api/source/Symbolizable.java | 18 +++++++++++ 7 files changed, 107 insertions(+), 9 deletions(-) diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SymbolReferencesSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SymbolReferencesSensor.java index 66573470ddb..62927ccda7e 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SymbolReferencesSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SymbolReferencesSensor.java @@ -81,17 +81,36 @@ public class SymbolReferencesSensor implements Sensor { private static void processLine(File symbolFile, int lineNumber, Symbolizable.SymbolTableBuilder symbolTableBuilder, String line) { try { Iterator split = Splitter.on(",").split(line).iterator(); - int startOffset = Integer.parseInt(split.next()); - int endOffset = Integer.parseInt(split.next()); - Symbol s = symbolTableBuilder.newSymbol(startOffset, endOffset); + + Symbol s = addSymbol(symbolTableBuilder, split.next()); while (split.hasNext()) { - symbolTableBuilder.newReference(s, Integer.parseInt(split.next())); + addReference(symbolTableBuilder, s, split.next()); } } catch (Exception e) { throw new IllegalStateException("Error processing line " + lineNumber + " of file " + symbolFile.getAbsolutePath(), e); } } + private static void addReference(Symbolizable.SymbolTableBuilder symbolTableBuilder, Symbol s, String str) { + if (str.contains(":")) { + Iterator split = Splitter.on(":").split(str).iterator(); + int startOffset = Integer.parseInt(split.next()); + int toOffset = Integer.parseInt(split.next()); + symbolTableBuilder.newReference(s, startOffset, toOffset); + } else { + symbolTableBuilder.newReference(s, Integer.parseInt(str)); + } + } + + private static Symbol addSymbol(Symbolizable.SymbolTableBuilder symbolTableBuilder, String str) { + Iterator split = Splitter.on(":").split(str).iterator(); + + int startOffset = Integer.parseInt(split.next()); + int endOffset = Integer.parseInt(split.next()); + + return symbolTableBuilder.newSymbol(startOffset, endOffset); + } + @Override public void describe(SensorDescriptor descriptor) { descriptor diff --git a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/SymbolReferencesSensorTest.java b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/SymbolReferencesSensorTest.java index 332629c8469..d42ab2e5a79 100644 --- a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/SymbolReferencesSensorTest.java +++ b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/SymbolReferencesSensorTest.java @@ -74,7 +74,7 @@ public class SymbolReferencesSensorTest { @Test public void testExecution() throws IOException { File symbol = new File(baseDir, "src/foo.xoo.symbol"); - FileUtils.write(symbol, "1,4,7\n12,15,23\n\n#comment"); + FileUtils.write(symbol, "1:4,7\n12:15,23:33\n\n#comment"); DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setLanguage("xoo"); fileSystem.add(inputFile); Symbolizable symbolizable = mock(Symbolizable.class); @@ -92,7 +92,7 @@ public class SymbolReferencesSensorTest { verify(symbolTableBuilder).newSymbol(1, 4); verify(symbolTableBuilder).newReference(symbol1, 7); verify(symbolTableBuilder).newSymbol(12, 15); - verify(symbolTableBuilder).newReference(symbol2, 23); + verify(symbolTableBuilder).newReference(symbol2, 23, 33); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolTable.java b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolTable.java index 39d65df0cd1..99fa5a92f82 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolTable.java +++ b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolTable.java @@ -99,10 +99,15 @@ public class DefaultSymbolTable implements Symbolizable.SymbolTable { @Override public void newReference(Symbol symbol, int fromOffset) { + newReference(symbol, fromOffset, fromOffset + ((DefaultSymbol) symbol).getLength()); + } + + @Override + public void newReference(Symbol symbol, int fromOffset, int toOffset) { if (!referencesBySymbol.containsKey(symbol)) { throw new UnsupportedOperationException("Cannot add reference to a symbol in another file"); } - TextRange referenceRange = inputFile.newRange(fromOffset, fromOffset + ((DefaultSymbol) symbol).getLength()); + TextRange referenceRange = inputFile.newRange(fromOffset, toOffset); if (referenceRange.overlap(((DefaultSymbol) symbol).range())) { throw new UnsupportedOperationException("Cannot add reference (" + fromOffset + ") overlapping " + symbol + " in " + inputFile.key()); diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolizable.java b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolizable.java index 5089a9cca47..5b4781e14a1 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolizable.java +++ b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolizable.java @@ -45,6 +45,11 @@ public class DefaultSymbolizable implements Symbolizable { // Do nothing } + @Override + public void newReference(Symbol symbol, int fromOffset, int toOffset) { + // Do nothing + } + @Override public SymbolTable build() { return NO_OP_SYMBOL_TABLE; diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java index 15bb71b6c75..f918f14c341 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java @@ -66,7 +66,7 @@ public class SymbolMediumTest { File xooSymbolFile = new File(srcDir, "sample.xoo.symbol"); FileUtils.write(xooFile, "Sample xoo\ncontent\nanother xoo"); // Highlight xoo symbol - FileUtils.write(xooSymbolFile, "7,10,27"); + FileUtils.write(xooSymbolFile, "7:10,27"); TaskResult result = tester.newTask() .properties(ImmutableMap.builder() @@ -84,4 +84,33 @@ public class SymbolMediumTest { assertThat(result.symbolReferencesFor(file, 1, 7)).containsOnly(BatchReport.TextRange.newBuilder().setStartLine(3).setStartOffset(8).setEndLine(3).setEndOffset(11).build()); } + @Test + public void computeSymbolReferencesWithVariableLength() throws IOException { + + File baseDir = temp.getRoot(); + File srcDir = new File(baseDir, "src"); + srcDir.mkdir(); + + File xooFile = new File(srcDir, "sample.xoo"); + File xooSymbolFile = new File(srcDir, "sample.xoo.symbol"); + FileUtils.write(xooFile, "Sample xoo\ncontent\nanother xoo\nyet another"); + // Highlight xoo symbol + FileUtils.write(xooSymbolFile, "7:10,27:32"); + + TaskResult result = tester.newTask() + .properties(ImmutableMap.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(); + + InputFile file = result.inputFile("src/sample.xoo"); + assertThat(result.symbolReferencesFor(file, 1, 7)).containsOnly(BatchReport.TextRange.newBuilder().setStartLine(3).setStartOffset(8).setEndLine(4).setEndOffset(1).build()); + } + } diff --git a/sonar-batch/src/test/java/org/sonar/batch/source/DefaultSymbolTableTest.java b/sonar-batch/src/test/java/org/sonar/batch/source/DefaultSymbolTableTest.java index 465c26fbf67..22bcfef439d 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/source/DefaultSymbolTableTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/source/DefaultSymbolTableTest.java @@ -20,8 +20,12 @@ package org.sonar.batch.source; +import org.sonar.api.batch.fs.TextRange; import com.google.common.base.Strings; + import java.io.StringReader; +import java.util.Set; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -30,7 +34,6 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.FileMetadata; import org.sonar.api.source.Symbol; import org.sonar.api.source.Symbolizable; - import static org.assertj.core.api.Assertions.assertThat; public class DefaultSymbolTableTest { @@ -60,6 +63,25 @@ public class DefaultSymbolTableTest { assertThat(symbolTable.symbols()).containsExactly(firstSymbol, secondSymbol, thirdSymbol); } + @Test + public void variable_length_references() { + Symbolizable.SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTable.Builder(inputFile); + Symbol firstSymbol = symbolTableBuilder.newSymbol(10, 20); + symbolTableBuilder.newReference(firstSymbol, 32); + symbolTableBuilder.newReference(firstSymbol, 44, 47); + + DefaultSymbolTable symbolTable = (DefaultSymbolTable) symbolTableBuilder.build(); + + assertThat(symbolTable.symbols()).containsExactly(firstSymbol); + + Set references = symbolTable.getReferencesBySymbol().get(firstSymbol); + assertThat(references).containsExactly(range(32, 42), range(44, 47)); + } + + private TextRange range(int start, int end) { + return inputFile.newRange(start, end); + } + @Test public void should_reject_reference_conflicting_with_declaration() { throwable.expect(UnsupportedOperationException.class); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/source/Symbolizable.java b/sonar-plugin-api/src/main/java/org/sonar/api/source/Symbolizable.java index f205ec41c17..a16025bed58 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/source/Symbolizable.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/source/Symbolizable.java @@ -33,11 +33,29 @@ public interface Symbolizable extends Perspective { interface SymbolTableBuilder { + /** + * Creates a new Symbol. + * The offsets are global in the file. + */ Symbol newSymbol(int fromOffset, int toOffset); + /** + * Creates a new reference for a symbol. + * The length of the reference is assumed to be the same as the symbol's length. + */ void newReference(Symbol symbol, int fromOffset); + + /** + * Creates a new reference for a symbol. + * The offsets are global in the file. + */ + void newReference(Symbol symbol, int fromOffset, int toOffset); + /** + * Creates a {@link SymbolTable} containing all symbols and references previously created in this file. + */ SymbolTable build(); + } interface SymbolTable { -- 2.39.5