]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5867 Sort symbol references to avoid variations between consecutive runs
authorJulien HENRY <julien.henry@sonarsource.com>
Wed, 17 Dec 2014 15:29:22 +0000 (16:29 +0100)
committerJulien HENRY <julien.henry@sonarsource.com>
Wed, 17 Dec 2014 15:29:22 +0000 (16:29 +0100)
sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java
sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolTable.java
sonar-batch/src/main/java/org/sonar/batch/symbol/DefaultSymbolTableBuilder.java
sonar-batch/src/main/java/org/sonar/batch/symbol/SymbolData.java
sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java
sonar-batch/src/test/java/org/sonar/batch/symbol/DefaultSymbolTableBuilderTest.java

index 186e37edaa64e1f0c7fef1d45048e1c4716a1054..342c3503fb6b8d2156f9a83a00820348621907f3 100644 (file)
@@ -58,7 +58,9 @@ import javax.annotation.Nullable;
 
 import java.io.IOException;
 import java.io.StringWriter;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -330,7 +332,15 @@ public class SourcePersister implements ScanPersister {
     StringBuilder[] symbolRefsPerLine = new StringBuilder[file.lines()];
     long[] originalLineOffsets = file.originalLineOffsets();
     int symbolId = 1;
-    for (Symbol symbol : symbolRefs.referencesBySymbol().keySet()) {
+    List<Symbol> symbols = new ArrayList<Symbol>(symbolRefs.referencesBySymbol().keySet());
+    // Sort symbols to avoid false variation that would lead to an unnecessary update
+    Collections.sort(symbols, new Comparator<Symbol>() {
+      @Override
+      public int compare(Symbol o1, Symbol o2) {
+        return o1.getDeclarationStartOffset() - o2.getDeclarationStartOffset();
+      }
+    });
+    for (Symbol symbol : symbols) {
       int declarationStartOffset = symbol.getDeclarationStartOffset();
       int declarationEndOffset = symbol.getDeclarationEndOffset();
       int length = declarationEndOffset - declarationStartOffset;
index 8499776bfb7230237798be8ace1eec50a90c6813..2886cfbc28c87f413f6d6cad4a360ba8555663d4 100644 (file)
@@ -80,6 +80,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 
 /**
  * Main utility class for writing batch medium tests.
@@ -406,7 +407,7 @@ public class BatchMediumTester {
      * @param symbolEndOffset 0-based end offset for the symbol in file
      */
     @CheckForNull
-    public List<Integer> symbolReferencesFor(InputFile file, int symbolStartOffset, int symbolEndOffset) {
+    public Set<Integer> symbolReferencesFor(InputFile file, int symbolStartOffset, int symbolEndOffset) {
       SymbolData data = symbolTablePerFile.get(file);
       if (data == null) {
         return null;
index 8aafb847386a3bab94ce9b80627b930992ca7923..b4ce0c158787e82d95d9056344e44aaccd8b510e 100644 (file)
@@ -28,16 +28,18 @@ import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 
 public class DefaultSymbolTable implements Symbolizable.SymbolTable {
 
-  private Map<Symbol, List<Integer>> referencesBySymbol;
+  private Map<Symbol, Set<Integer>> referencesBySymbol;
 
-  private DefaultSymbolTable(Map<Symbol, List<Integer>> referencesBySymbol) {
+  private DefaultSymbolTable(Map<Symbol, Set<Integer>> referencesBySymbol) {
     this.referencesBySymbol = referencesBySymbol;
   }
 
-  public Map<Symbol, List<Integer>> getReferencesBySymbol() {
+  public Map<Symbol, Set<Integer>> getReferencesBySymbol() {
     return referencesBySymbol;
   }
 
@@ -57,7 +59,7 @@ public class DefaultSymbolTable implements Symbolizable.SymbolTable {
 
   public static class Builder implements Symbolizable.SymbolTableBuilder {
 
-    private final Map<Symbol, List<Integer>> referencesBySymbol = new LinkedHashMap<Symbol, List<Integer>>();
+    private final Map<Symbol, Set<Integer>> referencesBySymbol = new LinkedHashMap<Symbol, Set<Integer>>();
     private final String componentKey;
 
     public Builder(String componentKey) {
@@ -67,7 +69,7 @@ public class DefaultSymbolTable implements Symbolizable.SymbolTable {
     @Override
     public Symbol newSymbol(int fromOffset, int toOffset) {
       Symbol symbol = new DefaultSymbol(fromOffset, toOffset);
-      referencesBySymbol.put(symbol, new ArrayList<Integer>());
+      referencesBySymbol.put(symbol, new TreeSet<Integer>());
       return symbol;
     }
 
index a6e8c8c0aafe375e9a6f0b4fadd6d1de7883746a..72d4c050eb4b79ad87f8c342238a49f3316fc482 100644 (file)
@@ -27,17 +27,17 @@ import org.sonar.batch.index.ComponentDataCache;
 import org.sonar.core.source.SnapshotDataTypes;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 
 public class DefaultSymbolTableBuilder implements SymbolTableBuilder {
 
   private final String componentKey;
   private final ComponentDataCache cache;
-  private final Map<org.sonar.api.source.Symbol, List<Integer>> referencesBySymbol = new LinkedHashMap<org.sonar.api.source.Symbol, List<Integer>>();
+  private final Map<org.sonar.api.source.Symbol, Set<Integer>> referencesBySymbol = new LinkedHashMap<org.sonar.api.source.Symbol, Set<Integer>>();
 
   public DefaultSymbolTableBuilder(String componentKey, ComponentDataCache cache) {
     this.componentKey = componentKey;
@@ -47,7 +47,7 @@ public class DefaultSymbolTableBuilder implements SymbolTableBuilder {
   @Override
   public Symbol newSymbol(int fromOffset, int toOffset) {
     org.sonar.api.source.Symbol symbol = new DefaultSymbol(fromOffset, toOffset);
-    referencesBySymbol.put(symbol, new ArrayList<Integer>());
+    referencesBySymbol.put(symbol, new TreeSet<Integer>());
     return symbol;
   }
 
index 0f55e194e8bccba43d0fdae37d16fc611462f5f6..baf897c6d1bc0cd64ec844e7a12de598a613196e 100644 (file)
@@ -24,21 +24,21 @@ import org.sonar.api.batch.sensor.symbol.Symbol;
 import org.sonar.batch.index.Data;
 
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 public class SymbolData implements Data {
 
   public static final String FIELD_SEPARATOR = ",";
   public static final String SYMBOL_SEPARATOR = ";";
 
-  private final Map<org.sonar.api.source.Symbol, List<Integer>> referencesBySymbol;
+  private final Map<org.sonar.api.source.Symbol, Set<Integer>> referencesBySymbol;
 
-  public SymbolData(Map<org.sonar.api.source.Symbol, List<Integer>> referencesBySymbol) {
+  public SymbolData(Map<org.sonar.api.source.Symbol, Set<Integer>> referencesBySymbol) {
     this.referencesBySymbol = referencesBySymbol;
   }
 
-  public Map<org.sonar.api.source.Symbol, List<Integer>> referencesBySymbol() {
+  public Map<org.sonar.api.source.Symbol, Set<Integer>> referencesBySymbol() {
     return referencesBySymbol;
   }
 
index af2c5474d94db4aab1fac01132a45e63ff8eea88..4b405cca96ca684238c77148daf244c9bfddde4d 100644 (file)
@@ -362,6 +362,25 @@ public class SourcePersisterTest extends AbstractDaoTestCase {
     assertThat(symbolsPerLine).containsOnly("1,2,1;0,2,2", "0,1,1;0,2,2", "4,5,1;0,2,2");
   }
 
+  @Test
+  public void verifyDeclarationOrderOfSymbolHasNoImpact() {
+    DefaultInputFile file = new DefaultInputFile(PROJECT_KEY, "src/foo.java")
+      .setLines(3)
+      .setOriginalLineOffsets(new long[] {0, 4, 7});
+
+    DefaultSymbolTableBuilder symbolBuilder = new DefaultSymbolTableBuilder(PROJECT_KEY + ":" + "src/foo.java", null);
+    org.sonar.api.batch.sensor.symbol.Symbol s2 = symbolBuilder.newSymbol(4, 6);
+    symbolBuilder.newReference(s2, 7);
+    symbolBuilder.newReference(s2, 0);
+    org.sonar.api.batch.sensor.symbol.Symbol s1 = symbolBuilder.newSymbol(1, 2);
+    symbolBuilder.newReference(s1, 11);
+    symbolBuilder.newReference(s1, 4);
+
+    String[] symbolsPerLine = sourcePersister.computeSymbolReferencesPerLine(file, symbolBuilder.build());
+
+    assertThat(symbolsPerLine).containsOnly("1,2,1;0,2,2", "0,1,1;0,2,2", "4,5,1;0,2,2");
+  }
+
   private void mockResourceCache(String relativePathEmpty, String projectKey, String uuid) {
     File sonarFile = File.create(relativePathEmpty);
     sonarFile.setUuid(uuid);
index aa8c67edc5688f546ee63f11317e89eb7a3cca15..c68156c0a2d53f3842b8d3140de43961c0ec34ff 100644 (file)
@@ -30,8 +30,8 @@ import org.sonar.batch.index.ComponentDataCache;
 import org.sonar.core.source.SnapshotDataTypes;
 
 import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.fest.assertions.Assertions.assertThat;
 import static org.mockito.Matchers.eq;
@@ -58,7 +58,7 @@ public class DefaultSymbolTableBuilderTest {
     ArgumentCaptor<SymbolData> argCaptor = ArgumentCaptor.forClass(SymbolData.class);
     verify(componentDataCache).setData(eq("foo"), eq(SnapshotDataTypes.SYMBOL_HIGHLIGHTING), argCaptor.capture());
 
-    Map<org.sonar.api.source.Symbol, List<Integer>> referencesBySymbol = argCaptor.getValue().referencesBySymbol();
+    Map<org.sonar.api.source.Symbol, Set<Integer>> referencesBySymbol = argCaptor.getValue().referencesBySymbol();
 
     assertThat(new ArrayList<Symbol>(referencesBySymbol.keySet())).containsExactly(firstSymbol, secondSymbol, thirdSymbol);
     assertThat(new ArrayList<Integer>(referencesBySymbol.get(firstSymbol))).containsExactly(32);