]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4865, SONAR-6052 Improved issue locations
authorJulien HENRY <julien.henry@sonarsource.com>
Mon, 8 Jun 2015 14:40:48 +0000 (16:40 +0200)
committerJulien HENRY <julien.henry@sonarsource.com>
Thu, 23 Jul 2015 11:56:46 +0000 (13:56 +0200)
66 files changed:
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/TemplateRuleCheck.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/DeprecatedResourceApiSensor.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/MultilineIssuesSensor.java [new file with mode: 0644]
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssueOnDirPerFileSensor.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/RandomAccessSensor.java
plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/OneIssuePerLineSensorTest.java
server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java
server/sonar-server/src/main/java/org/sonar/server/computation/source/DuplicationLineReader.java
server/sonar-server/src/main/java/org/sonar/server/computation/source/HighlightingLineReader.java
server/sonar-server/src/main/java/org/sonar/server/computation/source/RangeOffsetHelper.java
server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/source/DuplicationLineReaderTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/source/HighlightingLineReaderTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/source/RangeOffsetHelperTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/source/SymbolsLineReaderTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistDuplicationsStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java
sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java
sonar-batch-protocol/src/main/protobuf/batch_report.proto
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportReaderTest.java
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java
sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java
sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedIssueBuilderWrapper.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedIssueWrapper.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java
sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java
sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java
sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java
sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/coverage/CoverageMediumTest.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/cpd/CpdMediumTest.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/MultilineIssuesMediumTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ComponentIndexerTest.java
sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/sonar-project.properties [new file with mode: 0644]
sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/xources/hello/HelloJava.xoo [new file with mode: 0644]
sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/xources/hello/HelloJava.xoo.measures [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFile.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueLocation.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssue.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssueLocation.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java
sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java
sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java
sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocationTest.java [new file with mode: 0644]
sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java

index f76fde9b90a89ba19d8d3329bd74857bae673914..a0f9cfdb4e838d14e0599aba56f618d41ba7c2eb 100644 (file)
@@ -33,6 +33,7 @@ import org.sonar.xoo.lang.XooTokenizer;
 import org.sonar.xoo.rule.ChecksSensor;
 import org.sonar.xoo.rule.CreateIssueByInternalKeySensor;
 import org.sonar.xoo.rule.DeprecatedResourceApiSensor;
+import org.sonar.xoo.rule.MultilineIssuesSensor;
 import org.sonar.xoo.rule.OneIssueOnDirPerFileSensor;
 import org.sonar.xoo.rule.OneIssuePerLineSensor;
 import org.sonar.xoo.rule.RandomAccessSensor;
@@ -89,6 +90,7 @@ public class XooPlugin extends SonarPlugin {
       OneIssuePerLineSensor.class,
       OneIssueOnDirPerFileSensor.class,
       CreateIssueByInternalKeySensor.class,
+      MultilineIssuesSensor.class,
 
       // Coverage
       UtCoverageSensor.class,
index 9e58a41052606ff3d6d157294fc669bb2c8c94b9..c6fe84360c3e3ed8fd23dba8527748e95fbefa72 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.xoo.checks;
 
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.issue.NewIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.check.Cardinality;
 import org.sonar.check.Rule;
@@ -36,10 +37,12 @@ public class TemplateRuleCheck implements Check {
 
   @Override
   public void execute(SensorContext sensorContext, InputFile file, RuleKey ruleKey) {
-    sensorContext.newIssue()
-      .onFile(file)
+    NewIssue newIssue = sensorContext.newIssue();
+    newIssue
       .forRule(ruleKey)
-      .atLine(line)
+      .addLocation(newIssue.newLocation()
+        .onFile(file)
+        .at(file.selectLine(line)))
       .save();
   }
 
index 5a1cefcab8e96a2c049d8c2ecc6251134a833b1a..47e8a16794df05da70451c9c80ae8b5c24796ee5 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.api.batch.rule.ActiveRule;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
 import org.sonar.xoo.Xoo;
 
 public class CreateIssueByInternalKeySensor implements Sensor {
@@ -54,10 +55,12 @@ public class CreateIssueByInternalKeySensor implements Sensor {
     ActiveRule rule = context.activeRules().findByInternalKey(XooRulesDefinition.XOO_REPOSITORY,
       context.settings().getString(INTERNAL_KEY_PROPERTY));
     if (rule != null) {
-      context.newIssue()
+      NewIssue newIssue = context.newIssue();
+      newIssue
         .forRule(rule.ruleKey())
-        .onFile(file)
-        .message("This issue is generated on each file")
+        .addLocation(newIssue.newLocation()
+          .onFile(file)
+          .message("This issue is generated on each file"))
         .save();
     }
   }
index 7cb80fbf54129687e868e0335bfe65211722ef8c..99a6e39fe1ae7f11c00189a8e473b7be1ab55871 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.xoo.rule;
 
+import java.io.File;
 import org.sonar.api.batch.Sensor;
 import org.sonar.api.batch.rule.ActiveRules;
 import org.sonar.api.component.ResourcePerspectives;
@@ -31,8 +32,6 @@ import org.sonar.api.scan.filesystem.ModuleFileSystem;
 import org.sonar.api.scan.filesystem.PathResolver;
 import org.sonar.xoo.Xoo;
 
-import java.io.File;
-
 public class DeprecatedResourceApiSensor implements Sensor {
 
   public static final String RULE_KEY = "DeprecatedResourceApi";
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/MultilineIssuesSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/MultilineIssuesSensor.java
new file mode 100644 (file)
index 0000000..a4bcca6
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.xoo.rule;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.sonar.api.batch.fs.FilePredicates;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputFile.Type;
+import org.sonar.api.batch.fs.TextPointer;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.xoo.Xoo;
+
+public class MultilineIssuesSensor implements Sensor {
+
+  public static final String RULE_KEY = "MultilineIssue";
+  private static final String START_ISSUE_PATTERN = "\\{xoo-start-issue:([0-9]+):([0-9]+)\\}";
+  private static final String END_ISSUE_PATTERN = "\\{xoo-end-issue:([0-9]+):([0-9]+)\\}";
+
+  @Override
+  public void describe(SensorDescriptor descriptor) {
+    descriptor
+      .name("Multiline Issues")
+      .onlyOnLanguages(Xoo.KEY)
+      .createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY);
+  }
+
+  @Override
+  public void execute(SensorContext context) {
+    FileSystem fs = context.fileSystem();
+    FilePredicates p = fs.predicates();
+    for (InputFile file : fs.inputFiles(p.and(p.hasLanguages(Xoo.KEY), p.hasType(Type.MAIN)))) {
+      createIssues(file, context);
+    }
+  }
+
+  private void createIssues(InputFile file, SensorContext context) {
+    Pattern startPattern = Pattern.compile(START_ISSUE_PATTERN);
+    Pattern endPattern = Pattern.compile(END_ISSUE_PATTERN);
+    Map<Integer, Map<Integer, TextPointer>> startPositions = new HashMap<>();
+    Map<Integer, Map<Integer, TextPointer>> endPositions = new HashMap<>();
+
+    RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY);
+    int currentLine = 0;
+    try {
+      for (String lineStr : Files.readAllLines(file.path(), context.fileSystem().encoding())) {
+        currentLine++;
+
+        Matcher m = startPattern.matcher(lineStr);
+        while (m.find()) {
+          Integer issueId = Integer.parseInt(m.group(1));
+          Integer issueLocationId = Integer.parseInt(m.group(2));
+          TextPointer newPointer = file.newPointer(currentLine, m.start());
+          if (!startPositions.containsKey(issueId)) {
+            startPositions.put(issueId, new HashMap<Integer, TextPointer>());
+          }
+          startPositions.get(issueId).put(issueLocationId, newPointer);
+        }
+
+        m = endPattern.matcher(lineStr);
+        while (m.find()) {
+          Integer issueId = Integer.parseInt(m.group(1));
+          Integer issueLocationId = Integer.parseInt(m.group(2));
+          TextPointer newPointer = file.newPointer(currentLine, m.start());
+          if (!endPositions.containsKey(issueId)) {
+            endPositions.put(issueId, new HashMap<Integer, TextPointer>());
+          }
+          endPositions.get(issueId).put(issueLocationId, newPointer);
+        }
+      }
+    } catch (IOException e) {
+      throw new IllegalStateException("Unable to read file", e);
+    }
+    for (Map.Entry<Integer, Map<Integer, TextPointer>> entry : startPositions.entrySet()) {
+      NewIssue newIssue = context.newIssue().forRule(ruleKey);
+      for (Map.Entry<Integer, TextPointer> location : entry.getValue().entrySet()) {
+        newIssue.addLocation(newIssue.newLocation()
+          .onFile(file)
+          .at(file.newRange(location.getValue(), endPositions.get(entry.getKey()).get(location.getKey())))
+          .message("Multiline issue"));
+      }
+      newIssue.save();
+    }
+  }
+
+}
index 6dbda2f741a5c40f2a8dc10195c3e80b996ebeda..e53f0b17ccc4d398718bece4cf4e3268524910ba 100644 (file)
@@ -24,6 +24,7 @@ import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.xoo.Xoo;
 
@@ -50,10 +51,12 @@ public class OneIssueOnDirPerFileSensor implements Sensor {
     RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY);
     InputDir inputDir = context.fileSystem().inputDir(file.file().getParentFile());
     if (inputDir != null) {
-      context.newIssue()
+      NewIssue newIssue = context.newIssue();
+      newIssue
         .forRule(ruleKey)
-        .onDir(inputDir)
-        .message("This issue is generated for file " + file.relativePath())
+        .addLocation(newIssue.newLocation()
+          .onDir(inputDir)
+          .message("This issue is generated for file " + file.relativePath()))
         .save();
     }
   }
index fc0a564c69cd36010b4377ee4433b258099d9e2e..e8aed769087359a99b37200a206c6497c5d2efb8 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.xoo.Xoo;
 
@@ -57,14 +58,17 @@ public class OneIssuePerLineSensor implements Sensor {
     RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY);
     String severity = context.settings().getString(FORCE_SEVERITY_PROPERTY);
     for (int line = 1; line <= file.lines(); line++) {
-      context.newIssue()
+      NewIssue newIssue = context.newIssue();
+      newIssue
         .forRule(ruleKey)
-        .onFile(file)
-        .atLine(line)
+        .addLocation(newIssue.newLocation()
+          .onFile(file)
+          .at(file.selectLine(line))
+          .message("This issue is generated on each line"))
         .effortToFix(context.settings().getDouble(EFFORT_TO_FIX_PROPERTY))
         .overrideSeverity(severity != null ? Severity.valueOf(severity) : null)
-        .message("This issue is generated on each line")
         .save();
     }
   }
+
 }
index 0541d91755243c9379ef91379517038b4e41df41..69bf700b50b445870222f3be9758610c38062ad6 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.xoo.rule;
 
+import java.io.File;
+import java.io.IOException;
 import org.apache.commons.io.FileUtils;
 import org.sonar.api.batch.fs.FilePredicates;
 import org.sonar.api.batch.fs.FileSystem;
@@ -27,12 +29,10 @@ import org.sonar.api.batch.fs.InputFile.Type;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.xoo.Xoo;
 
-import java.io.File;
-import java.io.IOException;
-
 public class RandomAccessSensor implements Sensor {
 
   private static final String SONAR_XOO_RANDOM_ACCESS_ISSUE_PATHS = "sonar.xoo.randomAccessIssue.paths";
@@ -63,11 +63,13 @@ public class RandomAccessSensor implements Sensor {
 
   private void createIssues(InputFile file, SensorContext context) {
     RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY);
-    context.newIssue()
+    NewIssue newIssue = context.newIssue();
+    newIssue
       .forRule(ruleKey)
-      .onFile(file)
-      .atLine(1)
-      .message("This issue is generated on each file")
+      .addLocation(newIssue.newLocation()
+        .onFile(file)
+        .at(file.selectLine(1))
+        .message("This issue is generated on each file"))
       .save();
   }
 }
index a3cbbf5eb847408009849995b4b691f3e03a81f9..2b422ba50ee3f3a05d2d65c9d586d1cb0bc93f30 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.xoo.rule;
 
+import java.io.IOException;
+import java.io.StringReader;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -27,6 +29,7 @@ import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 import org.sonar.api.batch.fs.internal.DefaultFileSystem;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.FileMetadata;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
@@ -36,8 +39,6 @@ import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
 import org.sonar.api.config.Settings;
 import org.sonar.xoo.Xoo;
 
-import java.io.IOException;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -61,7 +62,8 @@ public class OneIssuePerLineSensorTest {
   @Test
   public void testRule() throws IOException {
     DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder().toPath());
-    DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.xoo").setLanguage(Xoo.KEY).setLines(10);
+    DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.xoo").setLanguage(Xoo.KEY)
+      .initMetadata(new FileMetadata().readMetadata(new StringReader("a\nb\nc\nd\ne\nf\ng\nh\ni\n")));
     fs.add(inputFile);
 
     SensorContext context = mock(SensorContext.class);
@@ -79,13 +81,14 @@ public class OneIssuePerLineSensorTest {
     ArgumentCaptor<DefaultIssue> argCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
     verify(sensorStorage, times(10)).store(argCaptor.capture());
     assertThat(argCaptor.getAllValues()).hasSize(10); // One issue per line
-    assertThat(argCaptor.getValue().overridenSeverity()).isNull();
+    assertThat(argCaptor.getValue().overriddenSeverity()).isNull();
   }
 
   @Test
   public void testForceSeverity() throws IOException {
     DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder().toPath());
-    DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.xoo").setLanguage(Xoo.KEY).setLines(10);
+    DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.xoo").setLanguage(Xoo.KEY)
+      .initMetadata(new FileMetadata().readMetadata(new StringReader("a\nb\nc\nd\ne\nf\ng\nh\ni\n")));
     fs.add(inputFile);
 
     SensorContext context = mock(SensorContext.class);
@@ -105,7 +108,7 @@ public class OneIssuePerLineSensorTest {
     ArgumentCaptor<DefaultIssue> argCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
     verify(sensorStorage, times(10)).store(argCaptor.capture());
     assertThat(argCaptor.getAllValues()).hasSize(10); // One issue per line
-    assertThat(argCaptor.getValue().overridenSeverity()).isEqualTo(Severity.MINOR);
+    assertThat(argCaptor.getValue().overriddenSeverity()).isEqualTo(Severity.MINOR);
   }
 
 }
index 914521f3d6f73ebd308d63741b93869c1d0de613..b8422b501bcb4d01cbbd3c634c24ba71a0f2f6f4 100644 (file)
@@ -171,7 +171,7 @@ public class PersistFileSourcesStepTest {
         .build());
 
       highlightings.add(BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(line).setEndLine(line)
           .setStartOffset(1).setEndOffset(3)
           .build())
@@ -179,21 +179,21 @@ public class PersistFileSourcesStepTest {
         .build());
 
       symbols.add(BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(line).setEndLine(line).setStartOffset(2).setEndOffset(4)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(line + 1).setEndLine(line + 1).setStartOffset(1).setEndOffset(3)
-          .build()
-        ).build());
+          .build())
+        .build());
 
       duplications.add(BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(line)
           .setEndLine(line)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(line + 1)
             .setEndLine(line + 1)
             .build())
index 3920e15a96f3eca2bd89b96bdc8a89b99534b4e0..1d079a2e239d0ef415e2c363529b642eadb8cc8b 100644 (file)
@@ -35,7 +35,7 @@ import static com.google.common.collect.Maps.newHashMap;
 public class DuplicationLineReader implements LineReader {
 
   private final List<BatchReport.Duplication> duplications;
-  private final Map<BatchReport.Range, Integer> duplicationIdsByRange;
+  private final Map<BatchReport.TextRange, Integer> duplicationIdsByRange;
 
   public DuplicationLineReader(Iterator<BatchReport.Duplication> duplications) {
     this.duplications = newArrayList(duplications);
@@ -49,14 +49,14 @@ public class DuplicationLineReader implements LineReader {
   @Override
   public void read(FileSources.Line.Builder lineBuilder) {
     int line = lineBuilder.getLine();
-    List<BatchReport.Range> blocks = findDuplicationBlockMatchingLine(line);
-    for (BatchReport.Range block : blocks) {
+    List<BatchReport.TextRange> blocks = findDuplicationBlockMatchingLine(line);
+    for (BatchReport.TextRange block : blocks) {
       lineBuilder.addDuplication(duplicationIdsByRange.get(block));
     }
   }
 
-  private List<BatchReport.Range> findDuplicationBlockMatchingLine(int line) {
-    List<BatchReport.Range> blocks = newArrayList();
+  private List<BatchReport.TextRange> findDuplicationBlockMatchingLine(int line) {
+    List<BatchReport.TextRange> blocks = newArrayList();
     for (BatchReport.Duplication duplication : duplications) {
       if (matchLine(duplication.getOriginPosition(), line)) {
         blocks.add(duplication.getOriginPosition());
@@ -74,16 +74,16 @@ public class DuplicationLineReader implements LineReader {
     return !duplicate.hasOtherFileKey() && !duplicate.hasOtherFileRef();
   }
 
-  private static boolean matchLine(BatchReport.Range range, int line) {
+  private static boolean matchLine(BatchReport.TextRange range, int line) {
     return range.getStartLine() <= line && line <= range.getEndLine();
   }
 
-  private static int length(BatchReport.Range range) {
+  private static int length(BatchReport.TextRange range) {
     return (range.getEndLine() - range.getStartLine()) + 1;
   }
 
-  private Map<BatchReport.Range, Integer> createDuplicationIdsByRange(List<BatchReport.Duplication> duplications) {
-    Map<BatchReport.Range, Integer> map = newHashMap();
+  private Map<BatchReport.TextRange, Integer> createDuplicationIdsByRange(List<BatchReport.Duplication> duplications) {
+    Map<BatchReport.TextRange, Integer> map = newHashMap();
     int blockId = 1;
     for (BatchReport.Duplication duplication : this.duplications) {
       map.put(duplication.getOriginPosition(), blockId);
index 11210885da4f4b7b6f1a02ace683c0d125ff7722..f3e4763c296cd29d233615919c2f4ce7fd0e5aa2 100644 (file)
@@ -63,7 +63,7 @@ public class HighlightingLineReader implements LineReader {
     incrementHighlightingListMatchingLine(line);
     for (Iterator<BatchReport.SyntaxHighlighting> syntaxHighlightingIterator = highlightingList.iterator(); syntaxHighlightingIterator.hasNext();) {
       BatchReport.SyntaxHighlighting syntaxHighlighting = syntaxHighlightingIterator.next();
-      BatchReport.Range range = syntaxHighlighting.getRange();
+      BatchReport.TextRange range = syntaxHighlighting.getRange();
       if (range.getStartLine() <= line) {
         String offsets = RangeOffsetHelper.offsetToString(syntaxHighlighting.getRange(), line, lineBuilder.getSource().length());
         if (!offsets.isEmpty()) {
index fc4b80aa85a04e223915fed1b2b3af2f34751376..35402dace4cf6591a15dbfb21aee74127dacbc04 100644 (file)
@@ -31,7 +31,7 @@ public class RangeOffsetHelper {
     // Only static methods
   }
 
-  public static String offsetToString(BatchReport.Range range, int lineIndex, int lineLength) {
+  public static String offsetToString(BatchReport.TextRange range, int lineIndex, int lineLength) {
     StringBuilder element = new StringBuilder();
 
     validateOffsetOrder(range, lineIndex);
@@ -49,19 +49,19 @@ public class RangeOffsetHelper {
     return element.toString();
   }
 
-  private static void validateOffsetOrder(BatchReport.Range range, int line) {
+  private static void validateOffsetOrder(BatchReport.TextRange range, int line) {
     if (range.getStartLine() == range.getEndLine() && range.getStartOffset() > range.getEndOffset()) {
       throw new IllegalArgumentException(String.format("End offset %s cannot be defined before start offset %s on line %s", range.getEndOffset(), range.getStartOffset(), line));
     }
   }
 
-  private static void validateStartOffsetNotGreaterThanLineLength(BatchReport.Range range, int lineLength, int line) {
+  private static void validateStartOffsetNotGreaterThanLineLength(BatchReport.TextRange range, int lineLength, int line) {
     if (range.getStartLine() == line && range.getStartOffset() > lineLength) {
       throw new IllegalArgumentException(String.format("Start offset %s is defined outside the length (%s) of the line %s", range.getStartOffset(), lineLength, line));
     }
   }
 
-  private static void validateEndOffsetNotGreaterThanLineLength(BatchReport.Range range, int lineLength, int line) {
+  private static void validateEndOffsetNotGreaterThanLineLength(BatchReport.TextRange range, int lineLength, int line) {
     if (range.getEndLine() == line && range.getEndOffset() > lineLength) {
       throw new IllegalArgumentException(String.format("End offset %s is defined outside the length (%s) of the line %s", range.getEndOffset(), lineLength, line));
     }
index 5b44635d7b06e72462d72bd83baf6a225635b992..c84b8fc4eecaa6307b055489f9f11f9f49cd872c 100644 (file)
@@ -57,7 +57,7 @@ public class SymbolsLineReader implements LineReader {
       StringBuilder symbolString = new StringBuilder(lineBuilder.getSymbols());
 
       appendSymbol(symbolString, lineSymbol.getDeclaration(), line, symbolId, lineBuilder.getSource());
-      for (BatchReport.Range range : lineSymbol.getReferenceList()) {
+      for (BatchReport.TextRange range : lineSymbol.getReferenceList()) {
         appendSymbol(symbolString, range, line, symbolId, lineBuilder.getSource());
       }
 
@@ -67,7 +67,7 @@ public class SymbolsLineReader implements LineReader {
     }
   }
 
-  private static void appendSymbol(StringBuilder lineSymbol, BatchReport.Range range, int line, int symbolId, String sourceLine) {
+  private static void appendSymbol(StringBuilder lineSymbol, BatchReport.TextRange range, int line, int symbolId, String sourceLine) {
     if (matchLine(range, line)) {
       String offsets = RangeOffsetHelper.offsetToString(range, line, sourceLine.length());
       if (!offsets.isEmpty()) {
@@ -89,7 +89,7 @@ public class SymbolsLineReader implements LineReader {
         lineSymbols.add(symbol);
         symbolsIndex.add(symbol);
       } else {
-        for (BatchReport.Range range : symbol.getReferenceList()) {
+        for (BatchReport.TextRange range : symbol.getReferenceList()) {
           if (matchLine(range, line) && !symbolsIndex.contains(symbol)) {
             lineSymbols.add(symbol);
             symbolsIndex.add(symbol);
@@ -100,7 +100,7 @@ public class SymbolsLineReader implements LineReader {
     return lineSymbols;
   }
 
-  private static boolean matchLine(BatchReport.Range range, int line) {
+  private static boolean matchLine(BatchReport.TextRange range, int line) {
     return range.getStartLine() <= line && range.getEndLine() >= line;
   }
 
index 9696abfc4e0947cab42f913cbe8a704f0a45af3b..c8766aa5116039e6bf5e7facad2798c32cd270c2 100644 (file)
@@ -24,7 +24,6 @@ import java.util.Iterator;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.batch.protocol.output.BatchReport.Range;
 import org.sonar.core.util.CloseableIterator;
 import org.sonar.db.DbSession;
 import org.sonar.db.MyBatis;
@@ -138,7 +137,7 @@ public class PersistDuplicationsStep implements ComputationStep {
       appendDuplication(xml, componentKey, duplicate.getRange());
     }
 
-    private void appendDuplication(StringBuilder xml, String componentKey, Range range) {
+    private void appendDuplication(StringBuilder xml, String componentKey, BatchReport.TextRange range) {
       int length = range.getEndLine() - range.getStartLine() + 1;
       xml.append("<b s=\"").append(range.getStartLine())
         .append("\" l=\"").append(length)
index 2710ccaf0afe1aa70001d1bce90e26ee7ba9e20d..72b65f8179a47d8c5f8bec2e39fec757bf424f6e 100644 (file)
@@ -49,12 +49,12 @@ public class DuplicationLineReaderTest {
   public void read_duplication_with_duplicates_on_same_file() {
     DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
       BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(2)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(3)
             .setEndLine(4)
             .build())
@@ -76,13 +76,13 @@ public class DuplicationLineReaderTest {
   public void read_duplication_with_duplicates_on_other_file() {
     DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
       BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(2)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
           .setOtherFileRef(2)
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(3)
             .setEndLine(4)
             .build())
@@ -104,13 +104,13 @@ public class DuplicationLineReaderTest {
   public void read_duplication_with_duplicates_on_other_file_from_other_project() {
     DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
       BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(2)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
           .setOtherFileKey("other-component-key-from-another-project")
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(3)
             .setEndLine(4)
             .build())
@@ -132,24 +132,24 @@ public class DuplicationLineReaderTest {
   public void read_many_duplications() {
     DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
       BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(1)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(2)
             .setEndLine(2)
             .build())
           .build())
         .build(),
       BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(2)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(3)
             .setEndLine(4)
             .build())
@@ -171,24 +171,24 @@ public class DuplicationLineReaderTest {
   public void should_be_sorted_by_line_block() {
     DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
       BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(2)
           .setEndLine(2)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(4)
             .setEndLine(4)
             .build())
           .build())
         .build(),
       BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(1)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(3)
             .setEndLine(3)
             .build())
@@ -210,24 +210,24 @@ public class DuplicationLineReaderTest {
   public void should_be_sorted_by_line_length() {
     DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
       BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(2)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(3)
             .setEndLine(4)
             .build())
           .build())
         .build(),
       BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(1)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(4)
             .setEndLine(4)
             .build())
index 23b541b33fa174bf5eeb1699c747031ccb4f7518..82e82c6b71bc3583e9908aca4b7bff3392de5aac 100644 (file)
@@ -52,7 +52,7 @@ public class HighlightingLineReaderTest {
   public void read_one_line() {
     HighlightingLineReader highlightingLineReader = new HighlightingLineReader(newArrayList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1)
           .setStartOffset(2).setEndOffset(4)
           .build())
@@ -68,21 +68,21 @@ public class HighlightingLineReaderTest {
   public void read_many_lines() {
     HighlightingLineReader highlightingLineReader = new HighlightingLineReader(newArrayList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1)
           .setStartOffset(0).setEndOffset(4)
           .build())
         .setType(Constants.HighlightingType.ANNOTATION)
         .build(),
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(2).setEndLine(2)
           .setStartOffset(0).setEndOffset(1)
           .build())
         .setType(Constants.HighlightingType.COMMENT)
         .build(),
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(4).setEndLine(4)
           .setStartOffset(1).setEndOffset(2)
           .build())
@@ -103,14 +103,14 @@ public class HighlightingLineReaderTest {
   public void read_many_syntax_highlighting_on_same_line() {
     HighlightingLineReader highlightingLineReader = new HighlightingLineReader(newArrayList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1)
           .setStartOffset(2).setEndOffset(3)
           .build())
         .setType(Constants.HighlightingType.ANNOTATION)
         .build(),
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1)
           .setStartOffset(4).setEndOffset(5)
           .build())
@@ -126,7 +126,7 @@ public class HighlightingLineReaderTest {
   public void read_nested_syntax_highlighting_on_same_line() {
     HighlightingLineReader highlightingLineReader = new HighlightingLineReader(newArrayList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1)
           .setStartOffset(0).setEndOffset(4)
           .build())
@@ -134,7 +134,7 @@ public class HighlightingLineReaderTest {
         .build(),
       // This highlighting is nested in previous one
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1)
           .setStartOffset(2).setEndOffset(3)
           .build())
@@ -151,7 +151,7 @@ public class HighlightingLineReaderTest {
     HighlightingLineReader highlightingLineReader = new HighlightingLineReader(newArrayList(
       // This highlighting begin on line 1 and finish on line 3
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(3)
           .setStartOffset(3).setEndOffset(2)
           .build())
@@ -172,21 +172,21 @@ public class HighlightingLineReaderTest {
   public void read_many_syntax_highlighting_on_many_lines() {
     HighlightingLineReader highlightingLineReader = new HighlightingLineReader(newArrayList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(3)
           .setStartOffset(3).setEndOffset(2)
           .build())
         .setType(Constants.HighlightingType.ANNOTATION)
         .build(),
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(2).setEndLine(4)
           .setStartOffset(0).setEndOffset(3)
           .build())
         .setType(Constants.HighlightingType.HIGHLIGHTING_STRING)
         .build(),
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(2).setEndLine(2)
           .setStartOffset(1).setEndOffset(2)
           .build())
@@ -208,7 +208,7 @@ public class HighlightingLineReaderTest {
   public void read_highlighting_declared_on_a_whole_line() {
     HighlightingLineReader highlightingLineReader = new HighlightingLineReader(newArrayList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(2)
           .setStartOffset(0).setEndOffset(0)
           .build())
@@ -229,7 +229,7 @@ public class HighlightingLineReaderTest {
   public void fail_when_end_offset_is_before_start_offset() {
     HighlightingLineReader highlightingLineReader = new HighlightingLineReader(newArrayList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1)
           .setStartOffset(4).setEndOffset(2)
           .build())
@@ -248,7 +248,7 @@ public class HighlightingLineReaderTest {
   public void fail_when_end_offset_is_higher_than_line_length() {
     HighlightingLineReader highlightingLineReader = new HighlightingLineReader(newArrayList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1)
           .setStartOffset(2).setEndOffset(10)
           .build())
@@ -267,7 +267,7 @@ public class HighlightingLineReaderTest {
   public void fail_when_start_offset_is_higher_than_line_length() {
     HighlightingLineReader highlightingLineReader = new HighlightingLineReader(newArrayList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1)
           .setStartOffset(10).setEndOffset(11)
           .build())
index 8a1afbc496525d2da523f869f9a8a769d45a12de..a2d9a7ca80eb94ef9e43cc62e7962c643ac9b44e 100644 (file)
@@ -30,7 +30,7 @@ public class RangeOffsetHelperTest {
 
   @Test
   public void append_range() {
-    assertThat(RangeOffsetHelper.offsetToString(BatchReport.Range.newBuilder()
+    assertThat(RangeOffsetHelper.offsetToString(BatchReport.TextRange.newBuilder()
       .setStartLine(1).setEndLine(1)
       .setStartOffset(2).setEndOffset(3)
       .build(), 1, 5)).isEqualTo("2,3");
@@ -38,7 +38,7 @@ public class RangeOffsetHelperTest {
 
   @Test
   public void append_range_not_finishing_in_current_line() {
-    assertThat( RangeOffsetHelper.offsetToString(BatchReport.Range.newBuilder()
+    assertThat(RangeOffsetHelper.offsetToString(BatchReport.TextRange.newBuilder()
       .setStartLine(1).setEndLine(3)
       .setStartOffset(2).setEndOffset(3)
       .build(), 1, 5)).isEqualTo("2,5");
@@ -46,7 +46,7 @@ public class RangeOffsetHelperTest {
 
   @Test
   public void append_range_that_began_in_previous_line_and_finish_in_current_line() {
-    assertThat(RangeOffsetHelper.offsetToString(BatchReport.Range.newBuilder()
+    assertThat(RangeOffsetHelper.offsetToString(BatchReport.TextRange.newBuilder()
       .setStartLine(1).setEndLine(3)
       .setStartOffset(2).setEndOffset(3)
       .build(), 3, 5)).isEqualTo("0,3");
@@ -54,7 +54,7 @@ public class RangeOffsetHelperTest {
 
   @Test
   public void append_range_that_began_in_previous_line_and_not_finishing_in_current_line() {
-    assertThat(RangeOffsetHelper.offsetToString(BatchReport.Range.newBuilder()
+    assertThat(RangeOffsetHelper.offsetToString(BatchReport.TextRange.newBuilder()
       .setStartLine(1).setEndLine(3)
       .setStartOffset(2).setEndOffset(3)
       .build(), 2, 5)).isEqualTo("0,5");
@@ -62,7 +62,7 @@ public class RangeOffsetHelperTest {
 
   @Test
   public void do_nothing_if_offset_is_empty() {
-    assertThat(RangeOffsetHelper.offsetToString(BatchReport.Range.newBuilder()
+    assertThat(RangeOffsetHelper.offsetToString(BatchReport.TextRange.newBuilder()
       .setStartLine(1).setEndLine(1)
       .setStartOffset(0).setEndOffset(0)
       .build(), 1, 5)).isEmpty();
@@ -71,10 +71,10 @@ public class RangeOffsetHelperTest {
   @Test
   public void fail_when_end_offset_is_before_start_offset() {
     try {
-      RangeOffsetHelper.offsetToString(BatchReport.Range.newBuilder()
-          .setStartLine(1).setEndLine(1)
-          .setStartOffset(4).setEndOffset(2)
-          .build(),
+      RangeOffsetHelper.offsetToString(BatchReport.TextRange.newBuilder()
+        .setStartLine(1).setEndLine(1)
+        .setStartOffset(4).setEndOffset(2)
+        .build(),
         1, 5);
       failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
     } catch (IllegalArgumentException e) {
@@ -85,10 +85,10 @@ public class RangeOffsetHelperTest {
   @Test
   public void fail_when_end_offset_is_higher_than_line_length() {
     try {
-      RangeOffsetHelper.offsetToString(BatchReport.Range.newBuilder()
-          .setStartLine(1).setEndLine(1)
-          .setStartOffset(4).setEndOffset(10)
-          .build(),
+      RangeOffsetHelper.offsetToString(BatchReport.TextRange.newBuilder()
+        .setStartLine(1).setEndLine(1)
+        .setStartOffset(4).setEndOffset(10)
+        .build(),
         1, 5);
       failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
     } catch (IllegalArgumentException e) {
@@ -99,10 +99,10 @@ public class RangeOffsetHelperTest {
   @Test
   public void fail_when_start_offset_is_higher_than_line_length() {
     try {
-      RangeOffsetHelper.offsetToString(BatchReport.Range.newBuilder()
-          .setStartLine(1).setEndLine(1)
-          .setStartOffset(10).setEndOffset(11)
-          .build(),
+      RangeOffsetHelper.offsetToString(BatchReport.TextRange.newBuilder()
+        .setStartLine(1).setEndLine(1)
+        .setStartOffset(10).setEndOffset(11)
+        .build(),
         1, 5);
       failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
     } catch (IllegalArgumentException e) {
index 7fc254226ff898f8b341c169db0181704979dc9f..594abcf8b3131b008885c402d592cbde16b8f44c 100644 (file)
@@ -50,10 +50,10 @@ public class SymbolsLineReaderTest {
   public void read_symbols() {
     List<BatchReport.Symbol> symbols = newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(4)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(3).setStartOffset(1).setEndOffset(3)
           .build())
         .build());
@@ -72,10 +72,10 @@ public class SymbolsLineReaderTest {
   public void read_symbols_with_reference_on_same_line() {
     List<BatchReport.Symbol> symbols = newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(0).setEndOffset(1)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(3)
           .build())
         .build());
@@ -90,13 +90,13 @@ public class SymbolsLineReaderTest {
   public void read_symbols_with_two_references() {
     List<BatchReport.Symbol> symbols = newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(4)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(3).setStartOffset(1).setEndOffset(3)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(2).setEndLine(2).setStartOffset(0).setEndOffset(2)
           .build())
         .build());
@@ -115,13 +115,13 @@ public class SymbolsLineReaderTest {
   public void read_symbols_with_two_references_on_the_same_line() {
     List<BatchReport.Symbol> symbols = newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(3)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(2).setEndLine(2).setStartOffset(0).setEndOffset(1)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(2).setEndLine(2).setStartOffset(2).setEndOffset(3)
           .build())
         .build());
@@ -138,10 +138,10 @@ public class SymbolsLineReaderTest {
   public void read_symbols_when_reference_line_is_before_declaration_line() {
     List<BatchReport.Symbol> symbols = newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(2).setEndLine(2).setStartOffset(3).setEndOffset(4)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(1).setEndOffset(2)
           .build())
         .build());
@@ -158,18 +158,18 @@ public class SymbolsLineReaderTest {
   public void read_many_symbols_on_lines() {
     List<BatchReport.Symbol> symbols = newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(1).setEndOffset(2)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(3).setStartOffset(2).setEndOffset(3)
           .build())
         .build(),
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(3).setEndOffset(4)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(3).setStartOffset(0).setEndOffset(1)
           .build())
         .build());
@@ -188,19 +188,19 @@ public class SymbolsLineReaderTest {
   public void symbol_declaration_should_be_sorted_by_offset() {
     List<BatchReport.Symbol> symbols = newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           // This symbol begins after the second symbol, it should appear in second place
           .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(3)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(3).setStartOffset(2).setEndOffset(3)
           .build())
         .build(),
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(0).setEndOffset(1)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(3).setStartOffset(0).setEndOffset(1)
           .build())
         .build());
@@ -219,19 +219,19 @@ public class SymbolsLineReaderTest {
   public void symbol_declaration_should_be_sorted_by_line() {
     List<BatchReport.Symbol> symbols = newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           // This symbol begins after the second symbol, it should appear in second place
           .setStartLine(2).setEndLine(2).setStartOffset(0).setEndOffset(1)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(3).setStartOffset(2).setEndOffset(3)
           .build())
         .build(),
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(0).setEndOffset(1)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(3).setStartOffset(0).setEndOffset(1)
           .build())
         .build());
@@ -250,10 +250,10 @@ public class SymbolsLineReaderTest {
   public void read_symbols_defined_on_many_lines() {
     List<BatchReport.Symbol> symbols = newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(2).setStartOffset(1).setEndOffset(3)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(4).setStartOffset(1).setEndOffset(3)
           .build())
         .build());
@@ -274,10 +274,10 @@ public class SymbolsLineReaderTest {
   public void read_symbols_declared_on_a_whole_line() {
     List<BatchReport.Symbol> symbols = newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(2).setStartOffset(0).setEndOffset(0)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(3).setStartOffset(1).setEndOffset(3)
           .build())
         .build());
index a117734529d9aff0345e28c6680361e7b14ea4b7..8af6d6c4d88cfcce90fb447de2441dbd8ed6976c 100644 (file)
@@ -29,10 +29,10 @@ import org.junit.experimental.categories.Category;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.utils.System2;
 import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.batch.protocol.output.BatchReport.Range;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.measure.MeasureDao;
+import org.sonar.db.metric.MetricDao;
 import org.sonar.db.metric.MetricDto;
 import org.sonar.server.computation.batch.BatchReportReaderRule;
 import org.sonar.server.computation.batch.TreeRootHolderRule;
@@ -40,7 +40,6 @@ import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.DbIdsRepository;
 import org.sonar.server.computation.component.DumbComponent;
 import org.sonar.server.db.DbClient;
-import org.sonar.db.metric.MetricDao;
 import org.sonar.test.DbTests;
 
 import static com.google.common.collect.Lists.newArrayList;
@@ -104,13 +103,12 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
     initReportWithProjectAndFile();
 
     BatchReport.Duplication duplication = BatchReport.Duplication.newBuilder()
-      .setOriginPosition(Range.newBuilder()
+      .setOriginPosition(BatchReport.TextRange.newBuilder()
         .setStartLine(1)
         .setEndLine(5)
         .build())
       .addDuplicate(BatchReport.Duplicate.newBuilder()
-        .setOtherFileRef(2)
-        .setRange(Range.newBuilder()
+        .setOtherFileRef(2).setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(6)
           .setEndLine(10)
           .build())
@@ -145,13 +143,12 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
     saveDuplicationMetric();
 
     BatchReport.Duplication duplication = BatchReport.Duplication.newBuilder()
-      .setOriginPosition(Range.newBuilder()
+      .setOriginPosition(BatchReport.TextRange.newBuilder()
         .setStartLine(1)
         .setEndLine(5)
         .build())
       .addDuplicate(BatchReport.Duplicate.newBuilder()
-        .setOtherFileRef(3)
-        .setRange(Range.newBuilder()
+        .setOtherFileRef(3).setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(6)
           .setEndLine(10)
           .build())
@@ -185,13 +182,12 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
     saveDuplicationMetric();
 
     BatchReport.Duplication duplication = BatchReport.Duplication.newBuilder()
-      .setOriginPosition(Range.newBuilder()
+      .setOriginPosition(BatchReport.TextRange.newBuilder()
         .setStartLine(1)
         .setEndLine(5)
         .build())
       .addDuplicate(BatchReport.Duplicate.newBuilder()
-        .setOtherFileRef(3)
-        .setRange(Range.newBuilder()
+        .setOtherFileRef(3).setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(6)
           .setEndLine(10)
           .build())
@@ -228,13 +224,12 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
     saveDuplicationMetric();
 
     BatchReport.Duplication duplication = BatchReport.Duplication.newBuilder()
-      .setOriginPosition(Range.newBuilder()
+      .setOriginPosition(BatchReport.TextRange.newBuilder()
         .setStartLine(1)
         .setEndLine(5)
         .build())
       .addDuplicate(BatchReport.Duplicate.newBuilder()
-        .setOtherFileRef(10)
-        .setRange(Range.newBuilder()
+        .setOtherFileRef(10).setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(6)
           .setEndLine(10)
           .build())
@@ -267,13 +262,12 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
     dbIdsRepository.setSnapshotId(file2, 12);
 
     BatchReport.Duplication duplication = BatchReport.Duplication.newBuilder()
-      .setOriginPosition(Range.newBuilder()
+      .setOriginPosition(BatchReport.TextRange.newBuilder()
         .setStartLine(1)
         .setEndLine(5)
         .build())
       .addDuplicate(BatchReport.Duplicate.newBuilder()
-        .setOtherFileRef(3)
-        .setRange(Range.newBuilder()
+        .setOtherFileRef(3).setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(6)
           .setEndLine(10)
           .build())
@@ -296,13 +290,13 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
     initReportWithProjectAndFile();
 
     BatchReport.Duplication duplication = BatchReport.Duplication.newBuilder()
-      .setOriginPosition(Range.newBuilder()
+      .setOriginPosition(BatchReport.TextRange.newBuilder()
         .setStartLine(1)
         .setEndLine(5)
         .build())
       .addDuplicate(BatchReport.Duplicate.newBuilder()
         .setOtherFileKey("PROJECT2_KEY:file2")
-        .setRange(Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(6)
           .setEndLine(10)
           .build())
index 4cde198b47d0c4d00d4801a761a7746eafe26da5..4816a2a9959f0d4b3930cbb4cfba149b8194bba7 100644 (file)
@@ -219,7 +219,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
     initBasicReport(1);
 
     reportReader.putSyntaxHighlighting(FILE_REF, newArrayList(BatchReport.SyntaxHighlighting.newBuilder()
-      .setRange(BatchReport.Range.newBuilder()
+      .setRange(BatchReport.TextRange.newBuilder()
         .setStartLine(1).setEndLine(1)
         .setStartOffset(2).setEndOffset(4)
         .build())
@@ -243,10 +243,10 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
 
     reportReader.putSymbols(FILE_REF, newArrayList(
       BatchReport.Symbol.newBuilder()
-        .setDeclaration(BatchReport.Range.newBuilder()
+        .setDeclaration(BatchReport.TextRange.newBuilder()
           .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(4)
           .build())
-        .addReference(BatchReport.Range.newBuilder()
+        .addReference(BatchReport.TextRange.newBuilder()
           .setStartLine(3).setEndLine(3).setStartOffset(1).setEndOffset(3)
           .build())
         .build()));
@@ -270,12 +270,12 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
 
     reportReader.putDuplications(FILE_REF, newArrayList(
       BatchReport.Duplication.newBuilder()
-        .setOriginPosition(BatchReport.Range.newBuilder()
+        .setOriginPosition(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(2)
           .build())
         .addDuplicate(BatchReport.Duplicate.newBuilder()
-          .setRange(BatchReport.Range.newBuilder()
+          .setRange(BatchReport.TextRange.newBuilder()
             .setStartLine(3)
             .setEndLine(4)
             .build())
@@ -400,7 +400,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
     initBasicReport(1);
 
     reportReader.putSyntaxHighlighting(FILE_REF, newArrayList(BatchReport.SyntaxHighlighting.newBuilder()
-      .setRange(BatchReport.Range.newBuilder()
+      .setRange(BatchReport.TextRange.newBuilder()
         .setStartLine(1).setEndLine(1)
         // Wrong offset -> fail
         .setStartOffset(4).setEndOffset(2)
index c5e1b26604d461be336a3496ba480dd286eb4e55..32168a1f7f8bd9f50e470f56c016a479cace1457 100644 (file)
@@ -6574,6 +6574,54 @@ public final class BatchReport {
      */
     com.google.protobuf.ByteString
         getAttributesBytes();
+
+    /**
+     * <code>repeated .IssueLocation locations = 8;</code>
+     */
+    java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation> 
+        getLocationsList();
+    /**
+     * <code>repeated .IssueLocation locations = 8;</code>
+     */
+    org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index);
+    /**
+     * <code>repeated .IssueLocation locations = 8;</code>
+     */
+    int getLocationsCount();
+    /**
+     * <code>repeated .IssueLocation locations = 8;</code>
+     */
+    java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder> 
+        getLocationsOrBuilderList();
+    /**
+     * <code>repeated .IssueLocation locations = 8;</code>
+     */
+    org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder getLocationsOrBuilder(
+        int index);
+
+    /**
+     * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+     */
+    java.util.List<org.sonar.batch.protocol.output.BatchReport.ExecutionFlow> 
+        getExecutionFlowsList();
+    /**
+     * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+     */
+    org.sonar.batch.protocol.output.BatchReport.ExecutionFlow getExecutionFlows(int index);
+    /**
+     * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+     */
+    int getExecutionFlowsCount();
+    /**
+     * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+     */
+    java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder> 
+        getExecutionFlowsOrBuilderList();
+    /**
+     * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+     */
+    org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder getExecutionFlowsOrBuilder(
+        int index);
   }
   /**
    * Protobuf type {@code Issue}
@@ -6672,6 +6720,22 @@ public final class BatchReport {
               attributes_ = bs;
               break;
             }
+            case 66: {
+              if (!((mutable_bitField0_ & 0x00000080) == 0x00000080)) {
+                locations_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.IssueLocation>();
+                mutable_bitField0_ |= 0x00000080;
+              }
+              locations_.add(input.readMessage(org.sonar.batch.protocol.output.BatchReport.IssueLocation.PARSER, extensionRegistry));
+              break;
+            }
+            case 74: {
+              if (!((mutable_bitField0_ & 0x00000100) == 0x00000100)) {
+                executionFlows_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.ExecutionFlow>();
+                mutable_bitField0_ |= 0x00000100;
+              }
+              executionFlows_.add(input.readMessage(org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.PARSER, extensionRegistry));
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -6680,6 +6744,12 @@ public final class BatchReport {
         throw new com.google.protobuf.InvalidProtocolBufferException(
             e.getMessage()).setUnfinishedMessage(this);
       } finally {
+        if (((mutable_bitField0_ & 0x00000080) == 0x00000080)) {
+          locations_ = java.util.Collections.unmodifiableList(locations_);
+        }
+        if (((mutable_bitField0_ & 0x00000100) == 0x00000100)) {
+          executionFlows_ = java.util.Collections.unmodifiableList(executionFlows_);
+        }
         this.unknownFields = unknownFields.build();
         makeExtensionsImmutable();
       }
@@ -6925,6 +6995,76 @@ public final class BatchReport {
       }
     }
 
+    public static final int LOCATIONS_FIELD_NUMBER = 8;
+    private java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation> locations_;
+    /**
+     * <code>repeated .IssueLocation locations = 8;</code>
+     */
+    public java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation> getLocationsList() {
+      return locations_;
+    }
+    /**
+     * <code>repeated .IssueLocation locations = 8;</code>
+     */
+    public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder> 
+        getLocationsOrBuilderList() {
+      return locations_;
+    }
+    /**
+     * <code>repeated .IssueLocation locations = 8;</code>
+     */
+    public int getLocationsCount() {
+      return locations_.size();
+    }
+    /**
+     * <code>repeated .IssueLocation locations = 8;</code>
+     */
+    public org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index) {
+      return locations_.get(index);
+    }
+    /**
+     * <code>repeated .IssueLocation locations = 8;</code>
+     */
+    public org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder getLocationsOrBuilder(
+        int index) {
+      return locations_.get(index);
+    }
+
+    public static final int EXECUTION_FLOWS_FIELD_NUMBER = 9;
+    private java.util.List<org.sonar.batch.protocol.output.BatchReport.ExecutionFlow> executionFlows_;
+    /**
+     * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+     */
+    public java.util.List<org.sonar.batch.protocol.output.BatchReport.ExecutionFlow> getExecutionFlowsList() {
+      return executionFlows_;
+    }
+    /**
+     * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+     */
+    public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder> 
+        getExecutionFlowsOrBuilderList() {
+      return executionFlows_;
+    }
+    /**
+     * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+     */
+    public int getExecutionFlowsCount() {
+      return executionFlows_.size();
+    }
+    /**
+     * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+     */
+    public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow getExecutionFlows(int index) {
+      return executionFlows_.get(index);
+    }
+    /**
+     * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+     */
+    public org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder getExecutionFlowsOrBuilder(
+        int index) {
+      return executionFlows_.get(index);
+    }
+
     private void initFields() {
       ruleRepository_ = "";
       ruleKey_ = "";
@@ -6933,6 +7073,8 @@ public final class BatchReport {
       severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
       effortToFix_ = 0D;
       attributes_ = "";
+      locations_ = java.util.Collections.emptyList();
+      executionFlows_ = java.util.Collections.emptyList();
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -6968,6 +7110,12 @@ public final class BatchReport {
       if (((bitField0_ & 0x00000040) == 0x00000040)) {
         output.writeBytes(7, getAttributesBytes());
       }
+      for (int i = 0; i < locations_.size(); i++) {
+        output.writeMessage(8, locations_.get(i));
+      }
+      for (int i = 0; i < executionFlows_.size(); i++) {
+        output.writeMessage(9, executionFlows_.get(i));
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -7005,6 +7153,14 @@ public final class BatchReport {
         size += com.google.protobuf.CodedOutputStream
           .computeBytesSize(7, getAttributesBytes());
       }
+      for (int i = 0; i < locations_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(8, locations_.get(i));
+      }
+      for (int i = 0; i < executionFlows_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(9, executionFlows_.get(i));
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -7114,6 +7270,8 @@ public final class BatchReport {
       }
       private void maybeForceBuilderInitialization() {
         if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getLocationsFieldBuilder();
+          getExecutionFlowsFieldBuilder();
         }
       }
       private static Builder create() {
@@ -7136,6 +7294,18 @@ public final class BatchReport {
         bitField0_ = (bitField0_ & ~0x00000020);
         attributes_ = "";
         bitField0_ = (bitField0_ & ~0x00000040);
+        if (locationsBuilder_ == null) {
+          locations_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000080);
+        } else {
+          locationsBuilder_.clear();
+        }
+        if (executionFlowsBuilder_ == null) {
+          executionFlows_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000100);
+        } else {
+          executionFlowsBuilder_.clear();
+        }
         return this;
       }
 
@@ -7192,6 +7362,24 @@ public final class BatchReport {
           to_bitField0_ |= 0x00000040;
         }
         result.attributes_ = attributes_;
+        if (locationsBuilder_ == null) {
+          if (((bitField0_ & 0x00000080) == 0x00000080)) {
+            locations_ = java.util.Collections.unmodifiableList(locations_);
+            bitField0_ = (bitField0_ & ~0x00000080);
+          }
+          result.locations_ = locations_;
+        } else {
+          result.locations_ = locationsBuilder_.build();
+        }
+        if (executionFlowsBuilder_ == null) {
+          if (((bitField0_ & 0x00000100) == 0x00000100)) {
+            executionFlows_ = java.util.Collections.unmodifiableList(executionFlows_);
+            bitField0_ = (bitField0_ & ~0x00000100);
+          }
+          result.executionFlows_ = executionFlows_;
+        } else {
+          result.executionFlows_ = executionFlowsBuilder_.build();
+        }
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -7237,6 +7425,58 @@ public final class BatchReport {
           attributes_ = other.attributes_;
           onChanged();
         }
+        if (locationsBuilder_ == null) {
+          if (!other.locations_.isEmpty()) {
+            if (locations_.isEmpty()) {
+              locations_ = other.locations_;
+              bitField0_ = (bitField0_ & ~0x00000080);
+            } else {
+              ensureLocationsIsMutable();
+              locations_.addAll(other.locations_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.locations_.isEmpty()) {
+            if (locationsBuilder_.isEmpty()) {
+              locationsBuilder_.dispose();
+              locationsBuilder_ = null;
+              locations_ = other.locations_;
+              bitField0_ = (bitField0_ & ~0x00000080);
+              locationsBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getLocationsFieldBuilder() : null;
+            } else {
+              locationsBuilder_.addAllMessages(other.locations_);
+            }
+          }
+        }
+        if (executionFlowsBuilder_ == null) {
+          if (!other.executionFlows_.isEmpty()) {
+            if (executionFlows_.isEmpty()) {
+              executionFlows_ = other.executionFlows_;
+              bitField0_ = (bitField0_ & ~0x00000100);
+            } else {
+              ensureExecutionFlowsIsMutable();
+              executionFlows_.addAll(other.executionFlows_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.executionFlows_.isEmpty()) {
+            if (executionFlowsBuilder_.isEmpty()) {
+              executionFlowsBuilder_.dispose();
+              executionFlowsBuilder_ = null;
+              executionFlows_ = other.executionFlows_;
+              bitField0_ = (bitField0_ & ~0x00000100);
+              executionFlowsBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getExecutionFlowsFieldBuilder() : null;
+            } else {
+              executionFlowsBuilder_.addAllMessages(other.executionFlows_);
+            }
+          }
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -7438,244 +7678,2203 @@ public final class BatchReport {
         onChanged();
         return this;
       }
-      /**
-       * <code>optional int32 line = 3;</code>
-       */
-      public Builder clearLine() {
-        bitField0_ = (bitField0_ & ~0x00000004);
-        line_ = 0;
-        onChanged();
+      /**
+       * <code>optional int32 line = 3;</code>
+       */
+      public Builder clearLine() {
+        bitField0_ = (bitField0_ & ~0x00000004);
+        line_ = 0;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object msg_ = "";
+      /**
+       * <code>optional string msg = 4;</code>
+       */
+      public boolean hasMsg() {
+        return ((bitField0_ & 0x00000008) == 0x00000008);
+      }
+      /**
+       * <code>optional string msg = 4;</code>
+       */
+      public java.lang.String getMsg() {
+        java.lang.Object ref = msg_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            msg_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string msg = 4;</code>
+       */
+      public com.google.protobuf.ByteString
+          getMsgBytes() {
+        java.lang.Object ref = msg_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          msg_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string msg = 4;</code>
+       */
+      public Builder setMsg(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000008;
+        msg_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string msg = 4;</code>
+       */
+      public Builder clearMsg() {
+        bitField0_ = (bitField0_ & ~0x00000008);
+        msg_ = getDefaultInstance().getMsg();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string msg = 4;</code>
+       */
+      public Builder setMsgBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000008;
+        msg_ = value;
+        onChanged();
+        return this;
+      }
+
+      private org.sonar.batch.protocol.Constants.Severity severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
+      /**
+       * <code>optional .Severity severity = 5;</code>
+       */
+      public boolean hasSeverity() {
+        return ((bitField0_ & 0x00000010) == 0x00000010);
+      }
+      /**
+       * <code>optional .Severity severity = 5;</code>
+       */
+      public org.sonar.batch.protocol.Constants.Severity getSeverity() {
+        return severity_;
+      }
+      /**
+       * <code>optional .Severity severity = 5;</code>
+       */
+      public Builder setSeverity(org.sonar.batch.protocol.Constants.Severity value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        bitField0_ |= 0x00000010;
+        severity_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional .Severity severity = 5;</code>
+       */
+      public Builder clearSeverity() {
+        bitField0_ = (bitField0_ & ~0x00000010);
+        severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
+        onChanged();
+        return this;
+      }
+
+      private double effortToFix_ ;
+      /**
+       * <code>optional double effort_to_fix = 6;</code>
+       */
+      public boolean hasEffortToFix() {
+        return ((bitField0_ & 0x00000020) == 0x00000020);
+      }
+      /**
+       * <code>optional double effort_to_fix = 6;</code>
+       */
+      public double getEffortToFix() {
+        return effortToFix_;
+      }
+      /**
+       * <code>optional double effort_to_fix = 6;</code>
+       */
+      public Builder setEffortToFix(double value) {
+        bitField0_ |= 0x00000020;
+        effortToFix_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional double effort_to_fix = 6;</code>
+       */
+      public Builder clearEffortToFix() {
+        bitField0_ = (bitField0_ & ~0x00000020);
+        effortToFix_ = 0D;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object attributes_ = "";
+      /**
+       * <code>optional string attributes = 7;</code>
+       */
+      public boolean hasAttributes() {
+        return ((bitField0_ & 0x00000040) == 0x00000040);
+      }
+      /**
+       * <code>optional string attributes = 7;</code>
+       */
+      public java.lang.String getAttributes() {
+        java.lang.Object ref = attributes_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            attributes_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string attributes = 7;</code>
+       */
+      public com.google.protobuf.ByteString
+          getAttributesBytes() {
+        java.lang.Object ref = attributes_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          attributes_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string attributes = 7;</code>
+       */
+      public Builder setAttributes(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000040;
+        attributes_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string attributes = 7;</code>
+       */
+      public Builder clearAttributes() {
+        bitField0_ = (bitField0_ & ~0x00000040);
+        attributes_ = getDefaultInstance().getAttributes();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string attributes = 7;</code>
+       */
+      public Builder setAttributesBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000040;
+        attributes_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation> locations_ =
+        java.util.Collections.emptyList();
+      private void ensureLocationsIsMutable() {
+        if (!((bitField0_ & 0x00000080) == 0x00000080)) {
+          locations_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.IssueLocation>(locations_);
+          bitField0_ |= 0x00000080;
+         }
+      }
+
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonar.batch.protocol.output.BatchReport.IssueLocation, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder, org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder> locationsBuilder_;
+
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation> getLocationsList() {
+        if (locationsBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(locations_);
+        } else {
+          return locationsBuilder_.getMessageList();
+        }
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public int getLocationsCount() {
+        if (locationsBuilder_ == null) {
+          return locations_.size();
+        } else {
+          return locationsBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index) {
+        if (locationsBuilder_ == null) {
+          return locations_.get(index);
+        } else {
+          return locationsBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public Builder setLocations(
+          int index, org.sonar.batch.protocol.output.BatchReport.IssueLocation value) {
+        if (locationsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureLocationsIsMutable();
+          locations_.set(index, value);
+          onChanged();
+        } else {
+          locationsBuilder_.setMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public Builder setLocations(
+          int index, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder builderForValue) {
+        if (locationsBuilder_ == null) {
+          ensureLocationsIsMutable();
+          locations_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          locationsBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public Builder addLocations(org.sonar.batch.protocol.output.BatchReport.IssueLocation value) {
+        if (locationsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureLocationsIsMutable();
+          locations_.add(value);
+          onChanged();
+        } else {
+          locationsBuilder_.addMessage(value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public Builder addLocations(
+          int index, org.sonar.batch.protocol.output.BatchReport.IssueLocation value) {
+        if (locationsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureLocationsIsMutable();
+          locations_.add(index, value);
+          onChanged();
+        } else {
+          locationsBuilder_.addMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public Builder addLocations(
+          org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder builderForValue) {
+        if (locationsBuilder_ == null) {
+          ensureLocationsIsMutable();
+          locations_.add(builderForValue.build());
+          onChanged();
+        } else {
+          locationsBuilder_.addMessage(builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public Builder addLocations(
+          int index, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder builderForValue) {
+        if (locationsBuilder_ == null) {
+          ensureLocationsIsMutable();
+          locations_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          locationsBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public Builder addAllLocations(
+          java.lang.Iterable<? extends org.sonar.batch.protocol.output.BatchReport.IssueLocation> values) {
+        if (locationsBuilder_ == null) {
+          ensureLocationsIsMutable();
+          com.google.protobuf.AbstractMessageLite.Builder.addAll(
+              values, locations_);
+          onChanged();
+        } else {
+          locationsBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public Builder clearLocations() {
+        if (locationsBuilder_ == null) {
+          locations_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000080);
+          onChanged();
+        } else {
+          locationsBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public Builder removeLocations(int index) {
+        if (locationsBuilder_ == null) {
+          ensureLocationsIsMutable();
+          locations_.remove(index);
+          onChanged();
+        } else {
+          locationsBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder getLocationsBuilder(
+          int index) {
+        return getLocationsFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder getLocationsOrBuilder(
+          int index) {
+        if (locationsBuilder_ == null) {
+          return locations_.get(index);  } else {
+          return locationsBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder> 
+           getLocationsOrBuilderList() {
+        if (locationsBuilder_ != null) {
+          return locationsBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(locations_);
+        }
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder addLocationsBuilder() {
+        return getLocationsFieldBuilder().addBuilder(
+            org.sonar.batch.protocol.output.BatchReport.IssueLocation.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder addLocationsBuilder(
+          int index) {
+        return getLocationsFieldBuilder().addBuilder(
+            index, org.sonar.batch.protocol.output.BatchReport.IssueLocation.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .IssueLocation locations = 8;</code>
+       */
+      public java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder> 
+           getLocationsBuilderList() {
+        return getLocationsFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonar.batch.protocol.output.BatchReport.IssueLocation, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder, org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder> 
+          getLocationsFieldBuilder() {
+        if (locationsBuilder_ == null) {
+          locationsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.sonar.batch.protocol.output.BatchReport.IssueLocation, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder, org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder>(
+                  locations_,
+                  ((bitField0_ & 0x00000080) == 0x00000080),
+                  getParentForChildren(),
+                  isClean());
+          locations_ = null;
+        }
+        return locationsBuilder_;
+      }
+
+      private java.util.List<org.sonar.batch.protocol.output.BatchReport.ExecutionFlow> executionFlows_ =
+        java.util.Collections.emptyList();
+      private void ensureExecutionFlowsIsMutable() {
+        if (!((bitField0_ & 0x00000100) == 0x00000100)) {
+          executionFlows_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.ExecutionFlow>(executionFlows_);
+          bitField0_ |= 0x00000100;
+         }
+      }
+
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonar.batch.protocol.output.BatchReport.ExecutionFlow, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder, org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder> executionFlowsBuilder_;
+
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public java.util.List<org.sonar.batch.protocol.output.BatchReport.ExecutionFlow> getExecutionFlowsList() {
+        if (executionFlowsBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(executionFlows_);
+        } else {
+          return executionFlowsBuilder_.getMessageList();
+        }
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public int getExecutionFlowsCount() {
+        if (executionFlowsBuilder_ == null) {
+          return executionFlows_.size();
+        } else {
+          return executionFlowsBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow getExecutionFlows(int index) {
+        if (executionFlowsBuilder_ == null) {
+          return executionFlows_.get(index);
+        } else {
+          return executionFlowsBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public Builder setExecutionFlows(
+          int index, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow value) {
+        if (executionFlowsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureExecutionFlowsIsMutable();
+          executionFlows_.set(index, value);
+          onChanged();
+        } else {
+          executionFlowsBuilder_.setMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public Builder setExecutionFlows(
+          int index, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder builderForValue) {
+        if (executionFlowsBuilder_ == null) {
+          ensureExecutionFlowsIsMutable();
+          executionFlows_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          executionFlowsBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public Builder addExecutionFlows(org.sonar.batch.protocol.output.BatchReport.ExecutionFlow value) {
+        if (executionFlowsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureExecutionFlowsIsMutable();
+          executionFlows_.add(value);
+          onChanged();
+        } else {
+          executionFlowsBuilder_.addMessage(value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public Builder addExecutionFlows(
+          int index, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow value) {
+        if (executionFlowsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureExecutionFlowsIsMutable();
+          executionFlows_.add(index, value);
+          onChanged();
+        } else {
+          executionFlowsBuilder_.addMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public Builder addExecutionFlows(
+          org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder builderForValue) {
+        if (executionFlowsBuilder_ == null) {
+          ensureExecutionFlowsIsMutable();
+          executionFlows_.add(builderForValue.build());
+          onChanged();
+        } else {
+          executionFlowsBuilder_.addMessage(builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public Builder addExecutionFlows(
+          int index, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder builderForValue) {
+        if (executionFlowsBuilder_ == null) {
+          ensureExecutionFlowsIsMutable();
+          executionFlows_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          executionFlowsBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public Builder addAllExecutionFlows(
+          java.lang.Iterable<? extends org.sonar.batch.protocol.output.BatchReport.ExecutionFlow> values) {
+        if (executionFlowsBuilder_ == null) {
+          ensureExecutionFlowsIsMutable();
+          com.google.protobuf.AbstractMessageLite.Builder.addAll(
+              values, executionFlows_);
+          onChanged();
+        } else {
+          executionFlowsBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public Builder clearExecutionFlows() {
+        if (executionFlowsBuilder_ == null) {
+          executionFlows_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000100);
+          onChanged();
+        } else {
+          executionFlowsBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public Builder removeExecutionFlows(int index) {
+        if (executionFlowsBuilder_ == null) {
+          ensureExecutionFlowsIsMutable();
+          executionFlows_.remove(index);
+          onChanged();
+        } else {
+          executionFlowsBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder getExecutionFlowsBuilder(
+          int index) {
+        return getExecutionFlowsFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder getExecutionFlowsOrBuilder(
+          int index) {
+        if (executionFlowsBuilder_ == null) {
+          return executionFlows_.get(index);  } else {
+          return executionFlowsBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder> 
+           getExecutionFlowsOrBuilderList() {
+        if (executionFlowsBuilder_ != null) {
+          return executionFlowsBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(executionFlows_);
+        }
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder addExecutionFlowsBuilder() {
+        return getExecutionFlowsFieldBuilder().addBuilder(
+            org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder addExecutionFlowsBuilder(
+          int index) {
+        return getExecutionFlowsFieldBuilder().addBuilder(
+            index, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .ExecutionFlow execution_flows = 9;</code>
+       */
+      public java.util.List<org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder> 
+           getExecutionFlowsBuilderList() {
+        return getExecutionFlowsFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonar.batch.protocol.output.BatchReport.ExecutionFlow, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder, org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder> 
+          getExecutionFlowsFieldBuilder() {
+        if (executionFlowsBuilder_ == null) {
+          executionFlowsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.sonar.batch.protocol.output.BatchReport.ExecutionFlow, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder, org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder>(
+                  executionFlows_,
+                  ((bitField0_ & 0x00000100) == 0x00000100),
+                  getParentForChildren(),
+                  isClean());
+          executionFlows_ = null;
+        }
+        return executionFlowsBuilder_;
+      }
+
+      // @@protoc_insertion_point(builder_scope:Issue)
+    }
+
+    static {
+      defaultInstance = new Issue(true);
+      defaultInstance.initFields();
+    }
+
+    // @@protoc_insertion_point(class_scope:Issue)
+  }
+
+  public interface IssueLocationOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:IssueLocation)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional int32 component_ref = 1;</code>
+     */
+    boolean hasComponentRef();
+    /**
+     * <code>optional int32 component_ref = 1;</code>
+     */
+    int getComponentRef();
+
+    /**
+     * <code>optional .TextRange text_range = 2;</code>
+     *
+     * <pre>
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * </pre>
+     */
+    boolean hasTextRange();
+    /**
+     * <code>optional .TextRange text_range = 2;</code>
+     *
+     * <pre>
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * </pre>
+     */
+    org.sonar.batch.protocol.output.BatchReport.TextRange getTextRange();
+    /**
+     * <code>optional .TextRange text_range = 2;</code>
+     *
+     * <pre>
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * </pre>
+     */
+    org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getTextRangeOrBuilder();
+
+    /**
+     * <code>optional string msg = 3;</code>
+     */
+    boolean hasMsg();
+    /**
+     * <code>optional string msg = 3;</code>
+     */
+    java.lang.String getMsg();
+    /**
+     * <code>optional string msg = 3;</code>
+     */
+    com.google.protobuf.ByteString
+        getMsgBytes();
+  }
+  /**
+   * Protobuf type {@code IssueLocation}
+   */
+  public static final class IssueLocation extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:IssueLocation)
+      IssueLocationOrBuilder {
+    // Use IssueLocation.newBuilder() to construct.
+    private IssueLocation(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      super(builder);
+      this.unknownFields = builder.getUnknownFields();
+    }
+    private IssueLocation(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+    private static final IssueLocation defaultInstance;
+    public static IssueLocation getDefaultInstance() {
+      return defaultInstance;
+    }
+
+    public IssueLocation getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+
+    private final com.google.protobuf.UnknownFieldSet unknownFields;
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+        getUnknownFields() {
+      return this.unknownFields;
+    }
+    private IssueLocation(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      initFields();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 8: {
+              bitField0_ |= 0x00000001;
+              componentRef_ = input.readInt32();
+              break;
+            }
+            case 18: {
+              org.sonar.batch.protocol.output.BatchReport.TextRange.Builder subBuilder = null;
+              if (((bitField0_ & 0x00000002) == 0x00000002)) {
+                subBuilder = textRange_.toBuilder();
+              }
+              textRange_ = input.readMessage(org.sonar.batch.protocol.output.BatchReport.TextRange.PARSER, extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(textRange_);
+                textRange_ = subBuilder.buildPartial();
+              }
+              bitField0_ |= 0x00000002;
+              break;
+            }
+            case 26: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000004;
+              msg_ = bs;
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e.getMessage()).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.sonar.batch.protocol.output.BatchReport.internal_static_IssueLocation_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.sonar.batch.protocol.output.BatchReport.internal_static_IssueLocation_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.sonar.batch.protocol.output.BatchReport.IssueLocation.class, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder.class);
+    }
+
+    public static com.google.protobuf.Parser<IssueLocation> PARSER =
+        new com.google.protobuf.AbstractParser<IssueLocation>() {
+      public IssueLocation parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new IssueLocation(input, extensionRegistry);
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<IssueLocation> getParserForType() {
+      return PARSER;
+    }
+
+    private int bitField0_;
+    public static final int COMPONENT_REF_FIELD_NUMBER = 1;
+    private int componentRef_;
+    /**
+     * <code>optional int32 component_ref = 1;</code>
+     */
+    public boolean hasComponentRef() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional int32 component_ref = 1;</code>
+     */
+    public int getComponentRef() {
+      return componentRef_;
+    }
+
+    public static final int TEXT_RANGE_FIELD_NUMBER = 2;
+    private org.sonar.batch.protocol.output.BatchReport.TextRange textRange_;
+    /**
+     * <code>optional .TextRange text_range = 2;</code>
+     *
+     * <pre>
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * </pre>
+     */
+    public boolean hasTextRange() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>optional .TextRange text_range = 2;</code>
+     *
+     * <pre>
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * </pre>
+     */
+    public org.sonar.batch.protocol.output.BatchReport.TextRange getTextRange() {
+      return textRange_;
+    }
+    /**
+     * <code>optional .TextRange text_range = 2;</code>
+     *
+     * <pre>
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * </pre>
+     */
+    public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getTextRangeOrBuilder() {
+      return textRange_;
+    }
+
+    public static final int MSG_FIELD_NUMBER = 3;
+    private java.lang.Object msg_;
+    /**
+     * <code>optional string msg = 3;</code>
+     */
+    public boolean hasMsg() {
+      return ((bitField0_ & 0x00000004) == 0x00000004);
+    }
+    /**
+     * <code>optional string msg = 3;</code>
+     */
+    public java.lang.String getMsg() {
+      java.lang.Object ref = msg_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          msg_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string msg = 3;</code>
+     */
+    public com.google.protobuf.ByteString
+        getMsgBytes() {
+      java.lang.Object ref = msg_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        msg_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    private void initFields() {
+      componentRef_ = 0;
+      textRange_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
+      msg_ = "";
+    }
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeInt32(1, componentRef_);
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeMessage(2, textRange_);
+      }
+      if (((bitField0_ & 0x00000004) == 0x00000004)) {
+        output.writeBytes(3, getMsgBytes());
+      }
+      getUnknownFields().writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(1, componentRef_);
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(2, textRange_);
+      }
+      if (((bitField0_ & 0x00000004) == 0x00000004)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(3, getMsgBytes());
+      }
+      size += getUnknownFields().getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    @java.lang.Override
+    protected java.lang.Object writeReplace()
+        throws java.io.ObjectStreamException {
+      return super.writeReplace();
+    }
+
+    public static org.sonar.batch.protocol.output.BatchReport.IssueLocation parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.IssueLocation parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.IssueLocation parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.IssueLocation parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.IssueLocation parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.IssueLocation parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.IssueLocation parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.IssueLocation parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.IssueLocation parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.IssueLocation parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public static Builder newBuilder() { return Builder.create(); }
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder(org.sonar.batch.protocol.output.BatchReport.IssueLocation prototype) {
+      return newBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() { return newBuilder(this); }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code IssueLocation}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:IssueLocation)
+        org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_IssueLocation_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_IssueLocation_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonar.batch.protocol.output.BatchReport.IssueLocation.class, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder.class);
+      }
+
+      // Construct using org.sonar.batch.protocol.output.BatchReport.IssueLocation.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getTextRangeFieldBuilder();
+        }
+      }
+      private static Builder create() {
+        return new Builder();
+      }
+
+      public Builder clear() {
+        super.clear();
+        componentRef_ = 0;
+        bitField0_ = (bitField0_ & ~0x00000001);
+        if (textRangeBuilder_ == null) {
+          textRange_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
+        } else {
+          textRangeBuilder_.clear();
+        }
+        bitField0_ = (bitField0_ & ~0x00000002);
+        msg_ = "";
+        bitField0_ = (bitField0_ & ~0x00000004);
+        return this;
+      }
+
+      public Builder clone() {
+        return create().mergeFrom(buildPartial());
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_IssueLocation_descriptor;
+      }
+
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation getDefaultInstanceForType() {
+        return org.sonar.batch.protocol.output.BatchReport.IssueLocation.getDefaultInstance();
+      }
+
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation build() {
+        org.sonar.batch.protocol.output.BatchReport.IssueLocation result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation buildPartial() {
+        org.sonar.batch.protocol.output.BatchReport.IssueLocation result = new org.sonar.batch.protocol.output.BatchReport.IssueLocation(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.componentRef_ = componentRef_;
+        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        if (textRangeBuilder_ == null) {
+          result.textRange_ = textRange_;
+        } else {
+          result.textRange_ = textRangeBuilder_.build();
+        }
+        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+          to_bitField0_ |= 0x00000004;
+        }
+        result.msg_ = msg_;
+        result.bitField0_ = to_bitField0_;
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonar.batch.protocol.output.BatchReport.IssueLocation) {
+          return mergeFrom((org.sonar.batch.protocol.output.BatchReport.IssueLocation)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.sonar.batch.protocol.output.BatchReport.IssueLocation other) {
+        if (other == org.sonar.batch.protocol.output.BatchReport.IssueLocation.getDefaultInstance()) return this;
+        if (other.hasComponentRef()) {
+          setComponentRef(other.getComponentRef());
+        }
+        if (other.hasTextRange()) {
+          mergeTextRange(other.getTextRange());
+        }
+        if (other.hasMsg()) {
+          bitField0_ |= 0x00000004;
+          msg_ = other.msg_;
+          onChanged();
+        }
+        this.mergeUnknownFields(other.getUnknownFields());
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonar.batch.protocol.output.BatchReport.IssueLocation parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonar.batch.protocol.output.BatchReport.IssueLocation) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      private int componentRef_ ;
+      /**
+       * <code>optional int32 component_ref = 1;</code>
+       */
+      public boolean hasComponentRef() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>optional int32 component_ref = 1;</code>
+       */
+      public int getComponentRef() {
+        return componentRef_;
+      }
+      /**
+       * <code>optional int32 component_ref = 1;</code>
+       */
+      public Builder setComponentRef(int value) {
+        bitField0_ |= 0x00000001;
+        componentRef_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional int32 component_ref = 1;</code>
+       */
+      public Builder clearComponentRef() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        componentRef_ = 0;
+        onChanged();
+        return this;
+      }
+
+      private org.sonar.batch.protocol.output.BatchReport.TextRange textRange_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
+      private com.google.protobuf.SingleFieldBuilder<
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> textRangeBuilder_;
+      /**
+       * <code>optional .TextRange text_range = 2;</code>
+       *
+       * <pre>
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * </pre>
+       */
+      public boolean hasTextRange() {
+        return ((bitField0_ & 0x00000002) == 0x00000002);
+      }
+      /**
+       * <code>optional .TextRange text_range = 2;</code>
+       *
+       * <pre>
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * </pre>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.TextRange getTextRange() {
+        if (textRangeBuilder_ == null) {
+          return textRange_;
+        } else {
+          return textRangeBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .TextRange text_range = 2;</code>
+       *
+       * <pre>
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * </pre>
+       */
+      public Builder setTextRange(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
+        if (textRangeBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          textRange_ = value;
+          onChanged();
+        } else {
+          textRangeBuilder_.setMessage(value);
+        }
+        bitField0_ |= 0x00000002;
+        return this;
+      }
+      /**
+       * <code>optional .TextRange text_range = 2;</code>
+       *
+       * <pre>
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * </pre>
+       */
+      public Builder setTextRange(
+          org.sonar.batch.protocol.output.BatchReport.TextRange.Builder builderForValue) {
+        if (textRangeBuilder_ == null) {
+          textRange_ = builderForValue.build();
+          onChanged();
+        } else {
+          textRangeBuilder_.setMessage(builderForValue.build());
+        }
+        bitField0_ |= 0x00000002;
+        return this;
+      }
+      /**
+       * <code>optional .TextRange text_range = 2;</code>
+       *
+       * <pre>
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * </pre>
+       */
+      public Builder mergeTextRange(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
+        if (textRangeBuilder_ == null) {
+          if (((bitField0_ & 0x00000002) == 0x00000002) &&
+              textRange_ != org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance()) {
+            textRange_ =
+              org.sonar.batch.protocol.output.BatchReport.TextRange.newBuilder(textRange_).mergeFrom(value).buildPartial();
+          } else {
+            textRange_ = value;
+          }
+          onChanged();
+        } else {
+          textRangeBuilder_.mergeFrom(value);
+        }
+        bitField0_ |= 0x00000002;
+        return this;
+      }
+      /**
+       * <code>optional .TextRange text_range = 2;</code>
+       *
+       * <pre>
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * </pre>
+       */
+      public Builder clearTextRange() {
+        if (textRangeBuilder_ == null) {
+          textRange_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
+          onChanged();
+        } else {
+          textRangeBuilder_.clear();
+        }
+        bitField0_ = (bitField0_ & ~0x00000002);
+        return this;
+      }
+      /**
+       * <code>optional .TextRange text_range = 2;</code>
+       *
+       * <pre>
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * </pre>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.TextRange.Builder getTextRangeBuilder() {
+        bitField0_ |= 0x00000002;
+        onChanged();
+        return getTextRangeFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .TextRange text_range = 2;</code>
+       *
+       * <pre>
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * </pre>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getTextRangeOrBuilder() {
+        if (textRangeBuilder_ != null) {
+          return textRangeBuilder_.getMessageOrBuilder();
+        } else {
+          return textRange_;
+        }
+      }
+      /**
+       * <code>optional .TextRange text_range = 2;</code>
+       *
+       * <pre>
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * </pre>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> 
+          getTextRangeFieldBuilder() {
+        if (textRangeBuilder_ == null) {
+          textRangeBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder>(
+                  getTextRange(),
+                  getParentForChildren(),
+                  isClean());
+          textRange_ = null;
+        }
+        return textRangeBuilder_;
+      }
+
+      private java.lang.Object msg_ = "";
+      /**
+       * <code>optional string msg = 3;</code>
+       */
+      public boolean hasMsg() {
+        return ((bitField0_ & 0x00000004) == 0x00000004);
+      }
+      /**
+       * <code>optional string msg = 3;</code>
+       */
+      public java.lang.String getMsg() {
+        java.lang.Object ref = msg_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            msg_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string msg = 3;</code>
+       */
+      public com.google.protobuf.ByteString
+          getMsgBytes() {
+        java.lang.Object ref = msg_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          msg_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string msg = 3;</code>
+       */
+      public Builder setMsg(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000004;
+        msg_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string msg = 3;</code>
+       */
+      public Builder clearMsg() {
+        bitField0_ = (bitField0_ & ~0x00000004);
+        msg_ = getDefaultInstance().getMsg();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string msg = 3;</code>
+       */
+      public Builder setMsgBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000004;
+        msg_ = value;
+        onChanged();
+        return this;
+      }
+
+      // @@protoc_insertion_point(builder_scope:IssueLocation)
+    }
+
+    static {
+      defaultInstance = new IssueLocation(true);
+      defaultInstance.initFields();
+    }
+
+    // @@protoc_insertion_point(class_scope:IssueLocation)
+  }
+
+  public interface ExecutionFlowOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:ExecutionFlow)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>repeated .IssueLocation locations = 1;</code>
+     */
+    java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation> 
+        getLocationsList();
+    /**
+     * <code>repeated .IssueLocation locations = 1;</code>
+     */
+    org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index);
+    /**
+     * <code>repeated .IssueLocation locations = 1;</code>
+     */
+    int getLocationsCount();
+    /**
+     * <code>repeated .IssueLocation locations = 1;</code>
+     */
+    java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder> 
+        getLocationsOrBuilderList();
+    /**
+     * <code>repeated .IssueLocation locations = 1;</code>
+     */
+    org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder getLocationsOrBuilder(
+        int index);
+  }
+  /**
+   * Protobuf type {@code ExecutionFlow}
+   */
+  public static final class ExecutionFlow extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:ExecutionFlow)
+      ExecutionFlowOrBuilder {
+    // Use ExecutionFlow.newBuilder() to construct.
+    private ExecutionFlow(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      super(builder);
+      this.unknownFields = builder.getUnknownFields();
+    }
+    private ExecutionFlow(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+    private static final ExecutionFlow defaultInstance;
+    public static ExecutionFlow getDefaultInstance() {
+      return defaultInstance;
+    }
+
+    public ExecutionFlow getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+
+    private final com.google.protobuf.UnknownFieldSet unknownFields;
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+        getUnknownFields() {
+      return this.unknownFields;
+    }
+    private ExecutionFlow(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      initFields();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 10: {
+              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
+                locations_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.IssueLocation>();
+                mutable_bitField0_ |= 0x00000001;
+              }
+              locations_.add(input.readMessage(org.sonar.batch.protocol.output.BatchReport.IssueLocation.PARSER, extensionRegistry));
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e.getMessage()).setUnfinishedMessage(this);
+      } finally {
+        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
+          locations_ = java.util.Collections.unmodifiableList(locations_);
+        }
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.sonar.batch.protocol.output.BatchReport.internal_static_ExecutionFlow_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.sonar.batch.protocol.output.BatchReport.internal_static_ExecutionFlow_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.class, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder.class);
+    }
+
+    public static com.google.protobuf.Parser<ExecutionFlow> PARSER =
+        new com.google.protobuf.AbstractParser<ExecutionFlow>() {
+      public ExecutionFlow parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new ExecutionFlow(input, extensionRegistry);
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<ExecutionFlow> getParserForType() {
+      return PARSER;
+    }
+
+    public static final int LOCATIONS_FIELD_NUMBER = 1;
+    private java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation> locations_;
+    /**
+     * <code>repeated .IssueLocation locations = 1;</code>
+     */
+    public java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation> getLocationsList() {
+      return locations_;
+    }
+    /**
+     * <code>repeated .IssueLocation locations = 1;</code>
+     */
+    public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder> 
+        getLocationsOrBuilderList() {
+      return locations_;
+    }
+    /**
+     * <code>repeated .IssueLocation locations = 1;</code>
+     */
+    public int getLocationsCount() {
+      return locations_.size();
+    }
+    /**
+     * <code>repeated .IssueLocation locations = 1;</code>
+     */
+    public org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index) {
+      return locations_.get(index);
+    }
+    /**
+     * <code>repeated .IssueLocation locations = 1;</code>
+     */
+    public org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder getLocationsOrBuilder(
+        int index) {
+      return locations_.get(index);
+    }
+
+    private void initFields() {
+      locations_ = java.util.Collections.emptyList();
+    }
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      getSerializedSize();
+      for (int i = 0; i < locations_.size(); i++) {
+        output.writeMessage(1, locations_.get(i));
+      }
+      getUnknownFields().writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      for (int i = 0; i < locations_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(1, locations_.get(i));
+      }
+      size += getUnknownFields().getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    @java.lang.Override
+    protected java.lang.Object writeReplace()
+        throws java.io.ObjectStreamException {
+      return super.writeReplace();
+    }
+
+    public static org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public static Builder newBuilder() { return Builder.create(); }
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder(org.sonar.batch.protocol.output.BatchReport.ExecutionFlow prototype) {
+      return newBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() { return newBuilder(this); }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code ExecutionFlow}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:ExecutionFlow)
+        org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_ExecutionFlow_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_ExecutionFlow_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.class, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder.class);
+      }
+
+      // Construct using org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getLocationsFieldBuilder();
+        }
+      }
+      private static Builder create() {
+        return new Builder();
+      }
+
+      public Builder clear() {
+        super.clear();
+        if (locationsBuilder_ == null) {
+          locations_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000001);
+        } else {
+          locationsBuilder_.clear();
+        }
+        return this;
+      }
+
+      public Builder clone() {
+        return create().mergeFrom(buildPartial());
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_ExecutionFlow_descriptor;
+      }
+
+      public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow getDefaultInstanceForType() {
+        return org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.getDefaultInstance();
+      }
+
+      public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow build() {
+        org.sonar.batch.protocol.output.BatchReport.ExecutionFlow result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow buildPartial() {
+        org.sonar.batch.protocol.output.BatchReport.ExecutionFlow result = new org.sonar.batch.protocol.output.BatchReport.ExecutionFlow(this);
+        int from_bitField0_ = bitField0_;
+        if (locationsBuilder_ == null) {
+          if (((bitField0_ & 0x00000001) == 0x00000001)) {
+            locations_ = java.util.Collections.unmodifiableList(locations_);
+            bitField0_ = (bitField0_ & ~0x00000001);
+          }
+          result.locations_ = locations_;
+        } else {
+          result.locations_ = locationsBuilder_.build();
+        }
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonar.batch.protocol.output.BatchReport.ExecutionFlow) {
+          return mergeFrom((org.sonar.batch.protocol.output.BatchReport.ExecutionFlow)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.sonar.batch.protocol.output.BatchReport.ExecutionFlow other) {
+        if (other == org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.getDefaultInstance()) return this;
+        if (locationsBuilder_ == null) {
+          if (!other.locations_.isEmpty()) {
+            if (locations_.isEmpty()) {
+              locations_ = other.locations_;
+              bitField0_ = (bitField0_ & ~0x00000001);
+            } else {
+              ensureLocationsIsMutable();
+              locations_.addAll(other.locations_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.locations_.isEmpty()) {
+            if (locationsBuilder_.isEmpty()) {
+              locationsBuilder_.dispose();
+              locationsBuilder_ = null;
+              locations_ = other.locations_;
+              bitField0_ = (bitField0_ & ~0x00000001);
+              locationsBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getLocationsFieldBuilder() : null;
+            } else {
+              locationsBuilder_.addAllMessages(other.locations_);
+            }
+          }
+        }
+        this.mergeUnknownFields(other.getUnknownFields());
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonar.batch.protocol.output.BatchReport.ExecutionFlow parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonar.batch.protocol.output.BatchReport.ExecutionFlow) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
         return this;
       }
+      private int bitField0_;
 
-      private java.lang.Object msg_ = "";
-      /**
-       * <code>optional string msg = 4;</code>
-       */
-      public boolean hasMsg() {
-        return ((bitField0_ & 0x00000008) == 0x00000008);
+      private java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation> locations_ =
+        java.util.Collections.emptyList();
+      private void ensureLocationsIsMutable() {
+        if (!((bitField0_ & 0x00000001) == 0x00000001)) {
+          locations_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.IssueLocation>(locations_);
+          bitField0_ |= 0x00000001;
+         }
       }
+
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonar.batch.protocol.output.BatchReport.IssueLocation, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder, org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder> locationsBuilder_;
+
       /**
-       * <code>optional string msg = 4;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public java.lang.String getMsg() {
-        java.lang.Object ref = msg_;
-        if (!(ref instanceof java.lang.String)) {
-          com.google.protobuf.ByteString bs =
-              (com.google.protobuf.ByteString) ref;
-          java.lang.String s = bs.toStringUtf8();
-          if (bs.isValidUtf8()) {
-            msg_ = s;
-          }
-          return s;
+      public java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation> getLocationsList() {
+        if (locationsBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(locations_);
         } else {
-          return (java.lang.String) ref;
+          return locationsBuilder_.getMessageList();
         }
       }
       /**
-       * <code>optional string msg = 4;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public com.google.protobuf.ByteString
-          getMsgBytes() {
-        java.lang.Object ref = msg_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          msg_ = b;
-          return b;
+      public int getLocationsCount() {
+        if (locationsBuilder_ == null) {
+          return locations_.size();
         } else {
-          return (com.google.protobuf.ByteString) ref;
+          return locationsBuilder_.getCount();
         }
       }
       /**
-       * <code>optional string msg = 4;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public Builder setMsg(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000008;
-        msg_ = value;
-        onChanged();
-        return this;
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index) {
+        if (locationsBuilder_ == null) {
+          return locations_.get(index);
+        } else {
+          return locationsBuilder_.getMessage(index);
+        }
       }
       /**
-       * <code>optional string msg = 4;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public Builder clearMsg() {
-        bitField0_ = (bitField0_ & ~0x00000008);
-        msg_ = getDefaultInstance().getMsg();
-        onChanged();
+      public Builder setLocations(
+          int index, org.sonar.batch.protocol.output.BatchReport.IssueLocation value) {
+        if (locationsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureLocationsIsMutable();
+          locations_.set(index, value);
+          onChanged();
+        } else {
+          locationsBuilder_.setMessage(index, value);
+        }
         return this;
       }
       /**
-       * <code>optional string msg = 4;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public Builder setMsgBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000008;
-        msg_ = value;
-        onChanged();
+      public Builder setLocations(
+          int index, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder builderForValue) {
+        if (locationsBuilder_ == null) {
+          ensureLocationsIsMutable();
+          locations_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          locationsBuilder_.setMessage(index, builderForValue.build());
+        }
         return this;
       }
-
-      private org.sonar.batch.protocol.Constants.Severity severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
-      /**
-       * <code>optional .Severity severity = 5;</code>
-       */
-      public boolean hasSeverity() {
-        return ((bitField0_ & 0x00000010) == 0x00000010);
-      }
       /**
-       * <code>optional .Severity severity = 5;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public org.sonar.batch.protocol.Constants.Severity getSeverity() {
-        return severity_;
+      public Builder addLocations(org.sonar.batch.protocol.output.BatchReport.IssueLocation value) {
+        if (locationsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureLocationsIsMutable();
+          locations_.add(value);
+          onChanged();
+        } else {
+          locationsBuilder_.addMessage(value);
+        }
+        return this;
       }
       /**
-       * <code>optional .Severity severity = 5;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public Builder setSeverity(org.sonar.batch.protocol.Constants.Severity value) {
-        if (value == null) {
-          throw new NullPointerException();
+      public Builder addLocations(
+          int index, org.sonar.batch.protocol.output.BatchReport.IssueLocation value) {
+        if (locationsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureLocationsIsMutable();
+          locations_.add(index, value);
+          onChanged();
+        } else {
+          locationsBuilder_.addMessage(index, value);
         }
-        bitField0_ |= 0x00000010;
-        severity_ = value;
-        onChanged();
         return this;
       }
       /**
-       * <code>optional .Severity severity = 5;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public Builder clearSeverity() {
-        bitField0_ = (bitField0_ & ~0x00000010);
-        severity_ = org.sonar.batch.protocol.Constants.Severity.INFO;
-        onChanged();
+      public Builder addLocations(
+          org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder builderForValue) {
+        if (locationsBuilder_ == null) {
+          ensureLocationsIsMutable();
+          locations_.add(builderForValue.build());
+          onChanged();
+        } else {
+          locationsBuilder_.addMessage(builderForValue.build());
+        }
         return this;
       }
-
-      private double effortToFix_ ;
       /**
-       * <code>optional double effort_to_fix = 6;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public boolean hasEffortToFix() {
-        return ((bitField0_ & 0x00000020) == 0x00000020);
+      public Builder addLocations(
+          int index, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder builderForValue) {
+        if (locationsBuilder_ == null) {
+          ensureLocationsIsMutable();
+          locations_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          locationsBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
       }
       /**
-       * <code>optional double effort_to_fix = 6;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public double getEffortToFix() {
-        return effortToFix_;
+      public Builder addAllLocations(
+          java.lang.Iterable<? extends org.sonar.batch.protocol.output.BatchReport.IssueLocation> values) {
+        if (locationsBuilder_ == null) {
+          ensureLocationsIsMutable();
+          com.google.protobuf.AbstractMessageLite.Builder.addAll(
+              values, locations_);
+          onChanged();
+        } else {
+          locationsBuilder_.addAllMessages(values);
+        }
+        return this;
       }
       /**
-       * <code>optional double effort_to_fix = 6;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public Builder setEffortToFix(double value) {
-        bitField0_ |= 0x00000020;
-        effortToFix_ = value;
-        onChanged();
+      public Builder clearLocations() {
+        if (locationsBuilder_ == null) {
+          locations_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000001);
+          onChanged();
+        } else {
+          locationsBuilder_.clear();
+        }
         return this;
       }
       /**
-       * <code>optional double effort_to_fix = 6;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public Builder clearEffortToFix() {
-        bitField0_ = (bitField0_ & ~0x00000020);
-        effortToFix_ = 0D;
-        onChanged();
+      public Builder removeLocations(int index) {
+        if (locationsBuilder_ == null) {
+          ensureLocationsIsMutable();
+          locations_.remove(index);
+          onChanged();
+        } else {
+          locationsBuilder_.remove(index);
+        }
         return this;
       }
-
-      private java.lang.Object attributes_ = "";
       /**
-       * <code>optional string attributes = 7;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public boolean hasAttributes() {
-        return ((bitField0_ & 0x00000040) == 0x00000040);
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder getLocationsBuilder(
+          int index) {
+        return getLocationsFieldBuilder().getBuilder(index);
       }
       /**
-       * <code>optional string attributes = 7;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public java.lang.String getAttributes() {
-        java.lang.Object ref = attributes_;
-        if (!(ref instanceof java.lang.String)) {
-          com.google.protobuf.ByteString bs =
-              (com.google.protobuf.ByteString) ref;
-          java.lang.String s = bs.toStringUtf8();
-          if (bs.isValidUtf8()) {
-            attributes_ = s;
-          }
-          return s;
-        } else {
-          return (java.lang.String) ref;
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder getLocationsOrBuilder(
+          int index) {
+        if (locationsBuilder_ == null) {
+          return locations_.get(index);  } else {
+          return locationsBuilder_.getMessageOrBuilder(index);
         }
       }
       /**
-       * <code>optional string attributes = 7;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public com.google.protobuf.ByteString
-          getAttributesBytes() {
-        java.lang.Object ref = attributes_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          attributes_ = b;
-          return b;
+      public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder> 
+           getLocationsOrBuilderList() {
+        if (locationsBuilder_ != null) {
+          return locationsBuilder_.getMessageOrBuilderList();
         } else {
-          return (com.google.protobuf.ByteString) ref;
+          return java.util.Collections.unmodifiableList(locations_);
         }
       }
       /**
-       * <code>optional string attributes = 7;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public Builder setAttributes(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000040;
-        attributes_ = value;
-        onChanged();
-        return this;
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder addLocationsBuilder() {
+        return getLocationsFieldBuilder().addBuilder(
+            org.sonar.batch.protocol.output.BatchReport.IssueLocation.getDefaultInstance());
       }
       /**
-       * <code>optional string attributes = 7;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public Builder clearAttributes() {
-        bitField0_ = (bitField0_ & ~0x00000040);
-        attributes_ = getDefaultInstance().getAttributes();
-        onChanged();
-        return this;
+      public org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder addLocationsBuilder(
+          int index) {
+        return getLocationsFieldBuilder().addBuilder(
+            index, org.sonar.batch.protocol.output.BatchReport.IssueLocation.getDefaultInstance());
       }
       /**
-       * <code>optional string attributes = 7;</code>
+       * <code>repeated .IssueLocation locations = 1;</code>
        */
-      public Builder setAttributesBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000040;
-        attributes_ = value;
-        onChanged();
-        return this;
+      public java.util.List<org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder> 
+           getLocationsBuilderList() {
+        return getLocationsFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonar.batch.protocol.output.BatchReport.IssueLocation, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder, org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder> 
+          getLocationsFieldBuilder() {
+        if (locationsBuilder_ == null) {
+          locationsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.sonar.batch.protocol.output.BatchReport.IssueLocation, org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder, org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder>(
+                  locations_,
+                  ((bitField0_ & 0x00000001) == 0x00000001),
+                  getParentForChildren(),
+                  isClean());
+          locations_ = null;
+        }
+        return locationsBuilder_;
       }
 
-      // @@protoc_insertion_point(builder_scope:Issue)
+      // @@protoc_insertion_point(builder_scope:ExecutionFlow)
     }
 
     static {
-      defaultInstance = new Issue(true);
+      defaultInstance = new ExecutionFlow(true);
       defaultInstance.initFields();
     }
 
-    // @@protoc_insertion_point(class_scope:Issue)
+    // @@protoc_insertion_point(class_scope:ExecutionFlow)
   }
 
   public interface ChangesetsOrBuilder extends
@@ -9385,17 +11584,17 @@ public final class BatchReport {
     int getOtherFileRef();
 
     /**
-     * <code>optional .Range range = 2;</code>
+     * <code>optional .TextRange range = 2;</code>
      */
     boolean hasRange();
     /**
-     * <code>optional .Range range = 2;</code>
+     * <code>optional .TextRange range = 2;</code>
      */
-    org.sonar.batch.protocol.output.BatchReport.Range getRange();
+    org.sonar.batch.protocol.output.BatchReport.TextRange getRange();
     /**
-     * <code>optional .Range range = 2;</code>
+     * <code>optional .TextRange range = 2;</code>
      */
-    org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getRangeOrBuilder();
+    org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getRangeOrBuilder();
 
     /**
      * <code>optional string other_file_key = 3;</code>
@@ -9481,11 +11680,11 @@ public final class BatchReport {
               break;
             }
             case 18: {
-              org.sonar.batch.protocol.output.BatchReport.Range.Builder subBuilder = null;
+              org.sonar.batch.protocol.output.BatchReport.TextRange.Builder subBuilder = null;
               if (((bitField0_ & 0x00000002) == 0x00000002)) {
                 subBuilder = range_.toBuilder();
               }
-              range_ = input.readMessage(org.sonar.batch.protocol.output.BatchReport.Range.PARSER, extensionRegistry);
+              range_ = input.readMessage(org.sonar.batch.protocol.output.BatchReport.TextRange.PARSER, extensionRegistry);
               if (subBuilder != null) {
                 subBuilder.mergeFrom(range_);
                 range_ = subBuilder.buildPartial();
@@ -9563,23 +11762,23 @@ public final class BatchReport {
     }
 
     public static final int RANGE_FIELD_NUMBER = 2;
-    private org.sonar.batch.protocol.output.BatchReport.Range range_;
+    private org.sonar.batch.protocol.output.BatchReport.TextRange range_;
     /**
-     * <code>optional .Range range = 2;</code>
+     * <code>optional .TextRange range = 2;</code>
      */
     public boolean hasRange() {
       return ((bitField0_ & 0x00000002) == 0x00000002);
     }
     /**
-     * <code>optional .Range range = 2;</code>
+     * <code>optional .TextRange range = 2;</code>
      */
-    public org.sonar.batch.protocol.output.BatchReport.Range getRange() {
+    public org.sonar.batch.protocol.output.BatchReport.TextRange getRange() {
       return range_;
     }
     /**
-     * <code>optional .Range range = 2;</code>
+     * <code>optional .TextRange range = 2;</code>
      */
-    public org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getRangeOrBuilder() {
+    public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getRangeOrBuilder() {
       return range_;
     }
 
@@ -9639,7 +11838,7 @@ public final class BatchReport {
 
     private void initFields() {
       otherFileRef_ = 0;
-      range_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+      range_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
       otherFileKey_ = "";
     }
     private byte memoizedIsInitialized = -1;
@@ -9806,7 +12005,7 @@ public final class BatchReport {
         otherFileRef_ = 0;
         bitField0_ = (bitField0_ & ~0x00000001);
         if (rangeBuilder_ == null) {
-          range_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+          range_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
         } else {
           rangeBuilder_.clear();
         }
@@ -9959,19 +12158,19 @@ public final class BatchReport {
         return this;
       }
 
-      private org.sonar.batch.protocol.output.BatchReport.Range range_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+      private org.sonar.batch.protocol.output.BatchReport.TextRange range_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
       private com.google.protobuf.SingleFieldBuilder<
-          org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> rangeBuilder_;
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> rangeBuilder_;
       /**
-       * <code>optional .Range range = 2;</code>
+       * <code>optional .TextRange range = 2;</code>
        */
       public boolean hasRange() {
         return ((bitField0_ & 0x00000002) == 0x00000002);
       }
       /**
-       * <code>optional .Range range = 2;</code>
+       * <code>optional .TextRange range = 2;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range getRange() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRange getRange() {
         if (rangeBuilder_ == null) {
           return range_;
         } else {
@@ -9979,9 +12178,9 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional .Range range = 2;</code>
+       * <code>optional .TextRange range = 2;</code>
        */
-      public Builder setRange(org.sonar.batch.protocol.output.BatchReport.Range value) {
+      public Builder setRange(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (rangeBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -9995,10 +12194,10 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range range = 2;</code>
+       * <code>optional .TextRange range = 2;</code>
        */
       public Builder setRange(
-          org.sonar.batch.protocol.output.BatchReport.Range.Builder builderForValue) {
+          org.sonar.batch.protocol.output.BatchReport.TextRange.Builder builderForValue) {
         if (rangeBuilder_ == null) {
           range_ = builderForValue.build();
           onChanged();
@@ -10009,14 +12208,14 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range range = 2;</code>
+       * <code>optional .TextRange range = 2;</code>
        */
-      public Builder mergeRange(org.sonar.batch.protocol.output.BatchReport.Range value) {
+      public Builder mergeRange(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (rangeBuilder_ == null) {
           if (((bitField0_ & 0x00000002) == 0x00000002) &&
-              range_ != org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance()) {
+              range_ != org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance()) {
             range_ =
-              org.sonar.batch.protocol.output.BatchReport.Range.newBuilder(range_).mergeFrom(value).buildPartial();
+              org.sonar.batch.protocol.output.BatchReport.TextRange.newBuilder(range_).mergeFrom(value).buildPartial();
           } else {
             range_ = value;
           }
@@ -10028,11 +12227,11 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range range = 2;</code>
+       * <code>optional .TextRange range = 2;</code>
        */
       public Builder clearRange() {
         if (rangeBuilder_ == null) {
-          range_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+          range_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
           onChanged();
         } else {
           rangeBuilder_.clear();
@@ -10041,17 +12240,17 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range range = 2;</code>
+       * <code>optional .TextRange range = 2;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range.Builder getRangeBuilder() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRange.Builder getRangeBuilder() {
         bitField0_ |= 0x00000002;
         onChanged();
         return getRangeFieldBuilder().getBuilder();
       }
       /**
-       * <code>optional .Range range = 2;</code>
+       * <code>optional .TextRange range = 2;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getRangeOrBuilder() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getRangeOrBuilder() {
         if (rangeBuilder_ != null) {
           return rangeBuilder_.getMessageOrBuilder();
         } else {
@@ -10059,14 +12258,14 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional .Range range = 2;</code>
+       * <code>optional .TextRange range = 2;</code>
        */
       private com.google.protobuf.SingleFieldBuilder<
-          org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> 
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> 
           getRangeFieldBuilder() {
         if (rangeBuilder_ == null) {
           rangeBuilder_ = new com.google.protobuf.SingleFieldBuilder<
-              org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder>(
+              org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder>(
                   getRange(),
                   getParentForChildren(),
                   isClean());
@@ -10191,7 +12390,7 @@ public final class BatchReport {
       com.google.protobuf.MessageOrBuilder {
 
     /**
-     * <code>optional .Range origin_position = 1;</code>
+     * <code>optional .TextRange origin_position = 1;</code>
      *
      * <pre>
      * Origin position in current file
@@ -10199,21 +12398,21 @@ public final class BatchReport {
      */
     boolean hasOriginPosition();
     /**
-     * <code>optional .Range origin_position = 1;</code>
+     * <code>optional .TextRange origin_position = 1;</code>
      *
      * <pre>
      * Origin position in current file
      * </pre>
      */
-    org.sonar.batch.protocol.output.BatchReport.Range getOriginPosition();
+    org.sonar.batch.protocol.output.BatchReport.TextRange getOriginPosition();
     /**
-     * <code>optional .Range origin_position = 1;</code>
+     * <code>optional .TextRange origin_position = 1;</code>
      *
      * <pre>
      * Origin position in current file
      * </pre>
      */
-    org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getOriginPositionOrBuilder();
+    org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getOriginPositionOrBuilder();
 
     /**
      * <code>repeated .Duplicate duplicate = 2;</code>
@@ -10292,11 +12491,11 @@ public final class BatchReport {
               break;
             }
             case 10: {
-              org.sonar.batch.protocol.output.BatchReport.Range.Builder subBuilder = null;
+              org.sonar.batch.protocol.output.BatchReport.TextRange.Builder subBuilder = null;
               if (((bitField0_ & 0x00000001) == 0x00000001)) {
                 subBuilder = originPosition_.toBuilder();
               }
-              originPosition_ = input.readMessage(org.sonar.batch.protocol.output.BatchReport.Range.PARSER, extensionRegistry);
+              originPosition_ = input.readMessage(org.sonar.batch.protocol.output.BatchReport.TextRange.PARSER, extensionRegistry);
               if (subBuilder != null) {
                 subBuilder.mergeFrom(originPosition_);
                 originPosition_ = subBuilder.buildPartial();
@@ -10356,9 +12555,9 @@ public final class BatchReport {
 
     private int bitField0_;
     public static final int ORIGIN_POSITION_FIELD_NUMBER = 1;
-    private org.sonar.batch.protocol.output.BatchReport.Range originPosition_;
+    private org.sonar.batch.protocol.output.BatchReport.TextRange originPosition_;
     /**
-     * <code>optional .Range origin_position = 1;</code>
+     * <code>optional .TextRange origin_position = 1;</code>
      *
      * <pre>
      * Origin position in current file
@@ -10368,23 +12567,23 @@ public final class BatchReport {
       return ((bitField0_ & 0x00000001) == 0x00000001);
     }
     /**
-     * <code>optional .Range origin_position = 1;</code>
+     * <code>optional .TextRange origin_position = 1;</code>
      *
      * <pre>
      * Origin position in current file
      * </pre>
      */
-    public org.sonar.batch.protocol.output.BatchReport.Range getOriginPosition() {
+    public org.sonar.batch.protocol.output.BatchReport.TextRange getOriginPosition() {
       return originPosition_;
     }
     /**
-     * <code>optional .Range origin_position = 1;</code>
+     * <code>optional .TextRange origin_position = 1;</code>
      *
      * <pre>
      * Origin position in current file
      * </pre>
      */
-    public org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getOriginPositionOrBuilder() {
+    public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getOriginPositionOrBuilder() {
       return originPosition_;
     }
 
@@ -10424,7 +12623,7 @@ public final class BatchReport {
     }
 
     private void initFields() {
-      originPosition_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+      originPosition_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
       duplicate_ = java.util.Collections.emptyList();
     }
     private byte memoizedIsInitialized = -1;
@@ -10583,7 +12782,7 @@ public final class BatchReport {
       public Builder clear() {
         super.clear();
         if (originPositionBuilder_ == null) {
-          originPosition_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+          originPosition_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
         } else {
           originPositionBuilder_.clear();
         }
@@ -10711,11 +12910,11 @@ public final class BatchReport {
       }
       private int bitField0_;
 
-      private org.sonar.batch.protocol.output.BatchReport.Range originPosition_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+      private org.sonar.batch.protocol.output.BatchReport.TextRange originPosition_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
       private com.google.protobuf.SingleFieldBuilder<
-          org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> originPositionBuilder_;
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> originPositionBuilder_;
       /**
-       * <code>optional .Range origin_position = 1;</code>
+       * <code>optional .TextRange origin_position = 1;</code>
        *
        * <pre>
        * Origin position in current file
@@ -10725,13 +12924,13 @@ public final class BatchReport {
         return ((bitField0_ & 0x00000001) == 0x00000001);
       }
       /**
-       * <code>optional .Range origin_position = 1;</code>
+       * <code>optional .TextRange origin_position = 1;</code>
        *
        * <pre>
        * Origin position in current file
        * </pre>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range getOriginPosition() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRange getOriginPosition() {
         if (originPositionBuilder_ == null) {
           return originPosition_;
         } else {
@@ -10739,13 +12938,13 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional .Range origin_position = 1;</code>
+       * <code>optional .TextRange origin_position = 1;</code>
        *
        * <pre>
        * Origin position in current file
        * </pre>
        */
-      public Builder setOriginPosition(org.sonar.batch.protocol.output.BatchReport.Range value) {
+      public Builder setOriginPosition(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (originPositionBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -10759,14 +12958,14 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range origin_position = 1;</code>
+       * <code>optional .TextRange origin_position = 1;</code>
        *
        * <pre>
        * Origin position in current file
        * </pre>
        */
       public Builder setOriginPosition(
-          org.sonar.batch.protocol.output.BatchReport.Range.Builder builderForValue) {
+          org.sonar.batch.protocol.output.BatchReport.TextRange.Builder builderForValue) {
         if (originPositionBuilder_ == null) {
           originPosition_ = builderForValue.build();
           onChanged();
@@ -10777,18 +12976,18 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range origin_position = 1;</code>
+       * <code>optional .TextRange origin_position = 1;</code>
        *
        * <pre>
        * Origin position in current file
        * </pre>
        */
-      public Builder mergeOriginPosition(org.sonar.batch.protocol.output.BatchReport.Range value) {
+      public Builder mergeOriginPosition(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (originPositionBuilder_ == null) {
           if (((bitField0_ & 0x00000001) == 0x00000001) &&
-              originPosition_ != org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance()) {
+              originPosition_ != org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance()) {
             originPosition_ =
-              org.sonar.batch.protocol.output.BatchReport.Range.newBuilder(originPosition_).mergeFrom(value).buildPartial();
+              org.sonar.batch.protocol.output.BatchReport.TextRange.newBuilder(originPosition_).mergeFrom(value).buildPartial();
           } else {
             originPosition_ = value;
           }
@@ -10800,7 +12999,7 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range origin_position = 1;</code>
+       * <code>optional .TextRange origin_position = 1;</code>
        *
        * <pre>
        * Origin position in current file
@@ -10808,7 +13007,7 @@ public final class BatchReport {
        */
       public Builder clearOriginPosition() {
         if (originPositionBuilder_ == null) {
-          originPosition_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+          originPosition_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
           onChanged();
         } else {
           originPositionBuilder_.clear();
@@ -10817,25 +13016,25 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range origin_position = 1;</code>
+       * <code>optional .TextRange origin_position = 1;</code>
        *
        * <pre>
        * Origin position in current file
        * </pre>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range.Builder getOriginPositionBuilder() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRange.Builder getOriginPositionBuilder() {
         bitField0_ |= 0x00000001;
         onChanged();
         return getOriginPositionFieldBuilder().getBuilder();
       }
       /**
-       * <code>optional .Range origin_position = 1;</code>
+       * <code>optional .TextRange origin_position = 1;</code>
        *
        * <pre>
        * Origin position in current file
        * </pre>
        */
-      public org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getOriginPositionOrBuilder() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getOriginPositionOrBuilder() {
         if (originPositionBuilder_ != null) {
           return originPositionBuilder_.getMessageOrBuilder();
         } else {
@@ -10843,18 +13042,18 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional .Range origin_position = 1;</code>
+       * <code>optional .TextRange origin_position = 1;</code>
        *
        * <pre>
        * Origin position in current file
        * </pre>
        */
       private com.google.protobuf.SingleFieldBuilder<
-          org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> 
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> 
           getOriginPositionFieldBuilder() {
         if (originPositionBuilder_ == null) {
           originPositionBuilder_ = new com.google.protobuf.SingleFieldBuilder<
-              org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder>(
+              org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder>(
                   getOriginPosition(),
                   getParentForChildren(),
                   isClean());
@@ -11114,8 +13313,8 @@ public final class BatchReport {
     // @@protoc_insertion_point(class_scope:Duplication)
   }
 
-  public interface RangeOrBuilder extends
-      // @@protoc_insertion_point(interface_extends:Range)
+  public interface TextRangeOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:TextRange)
       com.google.protobuf.MessageOrBuilder {
 
     /**
@@ -11187,29 +13386,29 @@ public final class BatchReport {
     int getEndOffset();
   }
   /**
-   * Protobuf type {@code Range}
+   * Protobuf type {@code TextRange}
    *
    * <pre>
    * Lines start at 1 and line offsets start at 0
    * </pre>
    */
-  public static final class Range extends
+  public static final class TextRange extends
       com.google.protobuf.GeneratedMessage implements
-      // @@protoc_insertion_point(message_implements:Range)
-      RangeOrBuilder {
-    // Use Range.newBuilder() to construct.
-    private Range(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      // @@protoc_insertion_point(message_implements:TextRange)
+      TextRangeOrBuilder {
+    // Use TextRange.newBuilder() to construct.
+    private TextRange(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
       super(builder);
       this.unknownFields = builder.getUnknownFields();
     }
-    private Range(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+    private TextRange(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
 
-    private static final Range defaultInstance;
-    public static Range getDefaultInstance() {
+    private static final TextRange defaultInstance;
+    public static TextRange getDefaultInstance() {
       return defaultInstance;
     }
 
-    public Range getDefaultInstanceForType() {
+    public TextRange getDefaultInstanceForType() {
       return defaultInstance;
     }
 
@@ -11219,7 +13418,7 @@ public final class BatchReport {
         getUnknownFields() {
       return this.unknownFields;
     }
-    private Range(
+    private TextRange(
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws com.google.protobuf.InvalidProtocolBufferException {
@@ -11276,28 +13475,28 @@ public final class BatchReport {
     }
     public static final com.google.protobuf.Descriptors.Descriptor
         getDescriptor() {
-      return org.sonar.batch.protocol.output.BatchReport.internal_static_Range_descriptor;
+      return org.sonar.batch.protocol.output.BatchReport.internal_static_TextRange_descriptor;
     }
 
     protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
         internalGetFieldAccessorTable() {
-      return org.sonar.batch.protocol.output.BatchReport.internal_static_Range_fieldAccessorTable
+      return org.sonar.batch.protocol.output.BatchReport.internal_static_TextRange_fieldAccessorTable
           .ensureFieldAccessorsInitialized(
-              org.sonar.batch.protocol.output.BatchReport.Range.class, org.sonar.batch.protocol.output.BatchReport.Range.Builder.class);
+              org.sonar.batch.protocol.output.BatchReport.TextRange.class, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder.class);
     }
 
-    public static com.google.protobuf.Parser<Range> PARSER =
-        new com.google.protobuf.AbstractParser<Range>() {
-      public Range parsePartialFrom(
+    public static com.google.protobuf.Parser<TextRange> PARSER =
+        new com.google.protobuf.AbstractParser<TextRange>() {
+      public TextRange parsePartialFrom(
           com.google.protobuf.CodedInputStream input,
           com.google.protobuf.ExtensionRegistryLite extensionRegistry)
           throws com.google.protobuf.InvalidProtocolBufferException {
-        return new Range(input, extensionRegistry);
+        return new TextRange(input, extensionRegistry);
       }
     };
 
     @java.lang.Override
-    public com.google.protobuf.Parser<Range> getParserForType() {
+    public com.google.protobuf.Parser<TextRange> getParserForType() {
       return PARSER;
     }
 
@@ -11462,53 +13661,53 @@ public final class BatchReport {
       return super.writeReplace();
     }
 
-    public static org.sonar.batch.protocol.output.BatchReport.Range parseFrom(
+    public static org.sonar.batch.protocol.output.BatchReport.TextRange parseFrom(
         com.google.protobuf.ByteString data)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data);
     }
-    public static org.sonar.batch.protocol.output.BatchReport.Range parseFrom(
+    public static org.sonar.batch.protocol.output.BatchReport.TextRange parseFrom(
         com.google.protobuf.ByteString data,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data, extensionRegistry);
     }
-    public static org.sonar.batch.protocol.output.BatchReport.Range parseFrom(byte[] data)
+    public static org.sonar.batch.protocol.output.BatchReport.TextRange parseFrom(byte[] data)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data);
     }
-    public static org.sonar.batch.protocol.output.BatchReport.Range parseFrom(
+    public static org.sonar.batch.protocol.output.BatchReport.TextRange parseFrom(
         byte[] data,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data, extensionRegistry);
     }
-    public static org.sonar.batch.protocol.output.BatchReport.Range parseFrom(java.io.InputStream input)
+    public static org.sonar.batch.protocol.output.BatchReport.TextRange parseFrom(java.io.InputStream input)
         throws java.io.IOException {
       return PARSER.parseFrom(input);
     }
-    public static org.sonar.batch.protocol.output.BatchReport.Range parseFrom(
+    public static org.sonar.batch.protocol.output.BatchReport.TextRange parseFrom(
         java.io.InputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws java.io.IOException {
       return PARSER.parseFrom(input, extensionRegistry);
     }
-    public static org.sonar.batch.protocol.output.BatchReport.Range parseDelimitedFrom(java.io.InputStream input)
+    public static org.sonar.batch.protocol.output.BatchReport.TextRange parseDelimitedFrom(java.io.InputStream input)
         throws java.io.IOException {
       return PARSER.parseDelimitedFrom(input);
     }
-    public static org.sonar.batch.protocol.output.BatchReport.Range parseDelimitedFrom(
+    public static org.sonar.batch.protocol.output.BatchReport.TextRange parseDelimitedFrom(
         java.io.InputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws java.io.IOException {
       return PARSER.parseDelimitedFrom(input, extensionRegistry);
     }
-    public static org.sonar.batch.protocol.output.BatchReport.Range parseFrom(
+    public static org.sonar.batch.protocol.output.BatchReport.TextRange parseFrom(
         com.google.protobuf.CodedInputStream input)
         throws java.io.IOException {
       return PARSER.parseFrom(input);
     }
-    public static org.sonar.batch.protocol.output.BatchReport.Range parseFrom(
+    public static org.sonar.batch.protocol.output.BatchReport.TextRange parseFrom(
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws java.io.IOException {
@@ -11517,7 +13716,7 @@ public final class BatchReport {
 
     public static Builder newBuilder() { return Builder.create(); }
     public Builder newBuilderForType() { return newBuilder(); }
-    public static Builder newBuilder(org.sonar.batch.protocol.output.BatchReport.Range prototype) {
+    public static Builder newBuilder(org.sonar.batch.protocol.output.BatchReport.TextRange prototype) {
       return newBuilder().mergeFrom(prototype);
     }
     public Builder toBuilder() { return newBuilder(this); }
@@ -11529,7 +13728,7 @@ public final class BatchReport {
       return builder;
     }
     /**
-     * Protobuf type {@code Range}
+     * Protobuf type {@code TextRange}
      *
      * <pre>
      * Lines start at 1 and line offsets start at 0
@@ -11537,21 +13736,21 @@ public final class BatchReport {
      */
     public static final class Builder extends
         com.google.protobuf.GeneratedMessage.Builder<Builder> implements
-        // @@protoc_insertion_point(builder_implements:Range)
-        org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder {
+        // @@protoc_insertion_point(builder_implements:TextRange)
+        org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder {
       public static final com.google.protobuf.Descriptors.Descriptor
           getDescriptor() {
-        return org.sonar.batch.protocol.output.BatchReport.internal_static_Range_descriptor;
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_TextRange_descriptor;
       }
 
       protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
           internalGetFieldAccessorTable() {
-        return org.sonar.batch.protocol.output.BatchReport.internal_static_Range_fieldAccessorTable
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_TextRange_fieldAccessorTable
             .ensureFieldAccessorsInitialized(
-                org.sonar.batch.protocol.output.BatchReport.Range.class, org.sonar.batch.protocol.output.BatchReport.Range.Builder.class);
+                org.sonar.batch.protocol.output.BatchReport.TextRange.class, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder.class);
       }
 
-      // Construct using org.sonar.batch.protocol.output.BatchReport.Range.newBuilder()
+      // Construct using org.sonar.batch.protocol.output.BatchReport.TextRange.newBuilder()
       private Builder() {
         maybeForceBuilderInitialization();
       }
@@ -11588,23 +13787,23 @@ public final class BatchReport {
 
       public com.google.protobuf.Descriptors.Descriptor
           getDescriptorForType() {
-        return org.sonar.batch.protocol.output.BatchReport.internal_static_Range_descriptor;
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_TextRange_descriptor;
       }
 
-      public org.sonar.batch.protocol.output.BatchReport.Range getDefaultInstanceForType() {
-        return org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+      public org.sonar.batch.protocol.output.BatchReport.TextRange getDefaultInstanceForType() {
+        return org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
       }
 
-      public org.sonar.batch.protocol.output.BatchReport.Range build() {
-        org.sonar.batch.protocol.output.BatchReport.Range result = buildPartial();
+      public org.sonar.batch.protocol.output.BatchReport.TextRange build() {
+        org.sonar.batch.protocol.output.BatchReport.TextRange result = buildPartial();
         if (!result.isInitialized()) {
           throw newUninitializedMessageException(result);
         }
         return result;
       }
 
-      public org.sonar.batch.protocol.output.BatchReport.Range buildPartial() {
-        org.sonar.batch.protocol.output.BatchReport.Range result = new org.sonar.batch.protocol.output.BatchReport.Range(this);
+      public org.sonar.batch.protocol.output.BatchReport.TextRange buildPartial() {
+        org.sonar.batch.protocol.output.BatchReport.TextRange result = new org.sonar.batch.protocol.output.BatchReport.TextRange(this);
         int from_bitField0_ = bitField0_;
         int to_bitField0_ = 0;
         if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
@@ -11629,16 +13828,16 @@ public final class BatchReport {
       }
 
       public Builder mergeFrom(com.google.protobuf.Message other) {
-        if (other instanceof org.sonar.batch.protocol.output.BatchReport.Range) {
-          return mergeFrom((org.sonar.batch.protocol.output.BatchReport.Range)other);
+        if (other instanceof org.sonar.batch.protocol.output.BatchReport.TextRange) {
+          return mergeFrom((org.sonar.batch.protocol.output.BatchReport.TextRange)other);
         } else {
           super.mergeFrom(other);
           return this;
         }
       }
 
-      public Builder mergeFrom(org.sonar.batch.protocol.output.BatchReport.Range other) {
-        if (other == org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance()) return this;
+      public Builder mergeFrom(org.sonar.batch.protocol.output.BatchReport.TextRange other) {
+        if (other == org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance()) return this;
         if (other.hasStartLine()) {
           setStartLine(other.getStartLine());
         }
@@ -11663,11 +13862,11 @@ public final class BatchReport {
           com.google.protobuf.CodedInputStream input,
           com.google.protobuf.ExtensionRegistryLite extensionRegistry)
           throws java.io.IOException {
-        org.sonar.batch.protocol.output.BatchReport.Range parsedMessage = null;
+        org.sonar.batch.protocol.output.BatchReport.TextRange parsedMessage = null;
         try {
           parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
         } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-          parsedMessage = (org.sonar.batch.protocol.output.BatchReport.Range) e.getUnfinishedMessage();
+          parsedMessage = (org.sonar.batch.protocol.output.BatchReport.TextRange) e.getUnfinishedMessage();
           throw e;
         } finally {
           if (parsedMessage != null) {
@@ -11870,15 +14069,15 @@ public final class BatchReport {
         return this;
       }
 
-      // @@protoc_insertion_point(builder_scope:Range)
+      // @@protoc_insertion_point(builder_scope:TextRange)
     }
 
     static {
-      defaultInstance = new Range(true);
+      defaultInstance = new TextRange(true);
       defaultInstance.initFields();
     }
 
-    // @@protoc_insertion_point(class_scope:Range)
+    // @@protoc_insertion_point(class_scope:TextRange)
   }
 
   public interface SymbolOrBuilder extends
@@ -11886,40 +14085,40 @@ public final class BatchReport {
       com.google.protobuf.MessageOrBuilder {
 
     /**
-     * <code>optional .Range declaration = 1;</code>
+     * <code>optional .TextRange declaration = 1;</code>
      */
     boolean hasDeclaration();
     /**
-     * <code>optional .Range declaration = 1;</code>
+     * <code>optional .TextRange declaration = 1;</code>
      */
-    org.sonar.batch.protocol.output.BatchReport.Range getDeclaration();
+    org.sonar.batch.protocol.output.BatchReport.TextRange getDeclaration();
     /**
-     * <code>optional .Range declaration = 1;</code>
+     * <code>optional .TextRange declaration = 1;</code>
      */
-    org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getDeclarationOrBuilder();
+    org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getDeclarationOrBuilder();
 
     /**
-     * <code>repeated .Range reference = 2;</code>
+     * <code>repeated .TextRange reference = 2;</code>
      */
-    java.util.List<org.sonar.batch.protocol.output.BatchReport.Range> 
+    java.util.List<org.sonar.batch.protocol.output.BatchReport.TextRange> 
         getReferenceList();
     /**
-     * <code>repeated .Range reference = 2;</code>
+     * <code>repeated .TextRange reference = 2;</code>
      */
-    org.sonar.batch.protocol.output.BatchReport.Range getReference(int index);
+    org.sonar.batch.protocol.output.BatchReport.TextRange getReference(int index);
     /**
-     * <code>repeated .Range reference = 2;</code>
+     * <code>repeated .TextRange reference = 2;</code>
      */
     int getReferenceCount();
     /**
-     * <code>repeated .Range reference = 2;</code>
+     * <code>repeated .TextRange reference = 2;</code>
      */
-    java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> 
+    java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> 
         getReferenceOrBuilderList();
     /**
-     * <code>repeated .Range reference = 2;</code>
+     * <code>repeated .TextRange reference = 2;</code>
      */
-    org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getReferenceOrBuilder(
+    org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getReferenceOrBuilder(
         int index);
   }
   /**
@@ -11975,11 +14174,11 @@ public final class BatchReport {
               break;
             }
             case 10: {
-              org.sonar.batch.protocol.output.BatchReport.Range.Builder subBuilder = null;
+              org.sonar.batch.protocol.output.BatchReport.TextRange.Builder subBuilder = null;
               if (((bitField0_ & 0x00000001) == 0x00000001)) {
                 subBuilder = declaration_.toBuilder();
               }
-              declaration_ = input.readMessage(org.sonar.batch.protocol.output.BatchReport.Range.PARSER, extensionRegistry);
+              declaration_ = input.readMessage(org.sonar.batch.protocol.output.BatchReport.TextRange.PARSER, extensionRegistry);
               if (subBuilder != null) {
                 subBuilder.mergeFrom(declaration_);
                 declaration_ = subBuilder.buildPartial();
@@ -11989,10 +14188,10 @@ public final class BatchReport {
             }
             case 18: {
               if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
-                reference_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.Range>();
+                reference_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.TextRange>();
                 mutable_bitField0_ |= 0x00000002;
               }
-              reference_.add(input.readMessage(org.sonar.batch.protocol.output.BatchReport.Range.PARSER, extensionRegistry));
+              reference_.add(input.readMessage(org.sonar.batch.protocol.output.BatchReport.TextRange.PARSER, extensionRegistry));
               break;
             }
           }
@@ -12039,63 +14238,63 @@ public final class BatchReport {
 
     private int bitField0_;
     public static final int DECLARATION_FIELD_NUMBER = 1;
-    private org.sonar.batch.protocol.output.BatchReport.Range declaration_;
+    private org.sonar.batch.protocol.output.BatchReport.TextRange declaration_;
     /**
-     * <code>optional .Range declaration = 1;</code>
+     * <code>optional .TextRange declaration = 1;</code>
      */
     public boolean hasDeclaration() {
       return ((bitField0_ & 0x00000001) == 0x00000001);
     }
     /**
-     * <code>optional .Range declaration = 1;</code>
+     * <code>optional .TextRange declaration = 1;</code>
      */
-    public org.sonar.batch.protocol.output.BatchReport.Range getDeclaration() {
+    public org.sonar.batch.protocol.output.BatchReport.TextRange getDeclaration() {
       return declaration_;
     }
     /**
-     * <code>optional .Range declaration = 1;</code>
+     * <code>optional .TextRange declaration = 1;</code>
      */
-    public org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getDeclarationOrBuilder() {
+    public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getDeclarationOrBuilder() {
       return declaration_;
     }
 
     public static final int REFERENCE_FIELD_NUMBER = 2;
-    private java.util.List<org.sonar.batch.protocol.output.BatchReport.Range> reference_;
+    private java.util.List<org.sonar.batch.protocol.output.BatchReport.TextRange> reference_;
     /**
-     * <code>repeated .Range reference = 2;</code>
+     * <code>repeated .TextRange reference = 2;</code>
      */
-    public java.util.List<org.sonar.batch.protocol.output.BatchReport.Range> getReferenceList() {
+    public java.util.List<org.sonar.batch.protocol.output.BatchReport.TextRange> getReferenceList() {
       return reference_;
     }
     /**
-     * <code>repeated .Range reference = 2;</code>
+     * <code>repeated .TextRange reference = 2;</code>
      */
-    public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> 
+    public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> 
         getReferenceOrBuilderList() {
       return reference_;
     }
     /**
-     * <code>repeated .Range reference = 2;</code>
+     * <code>repeated .TextRange reference = 2;</code>
      */
     public int getReferenceCount() {
       return reference_.size();
     }
     /**
-     * <code>repeated .Range reference = 2;</code>
+     * <code>repeated .TextRange reference = 2;</code>
      */
-    public org.sonar.batch.protocol.output.BatchReport.Range getReference(int index) {
+    public org.sonar.batch.protocol.output.BatchReport.TextRange getReference(int index) {
       return reference_.get(index);
     }
     /**
-     * <code>repeated .Range reference = 2;</code>
+     * <code>repeated .TextRange reference = 2;</code>
      */
-    public org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getReferenceOrBuilder(
+    public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getReferenceOrBuilder(
         int index) {
       return reference_.get(index);
     }
 
     private void initFields() {
-      declaration_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+      declaration_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
       reference_ = java.util.Collections.emptyList();
     }
     private byte memoizedIsInitialized = -1;
@@ -12254,7 +14453,7 @@ public final class BatchReport {
       public Builder clear() {
         super.clear();
         if (declarationBuilder_ == null) {
-          declaration_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+          declaration_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
         } else {
           declarationBuilder_.clear();
         }
@@ -12382,19 +14581,19 @@ public final class BatchReport {
       }
       private int bitField0_;
 
-      private org.sonar.batch.protocol.output.BatchReport.Range declaration_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+      private org.sonar.batch.protocol.output.BatchReport.TextRange declaration_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
       private com.google.protobuf.SingleFieldBuilder<
-          org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> declarationBuilder_;
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> declarationBuilder_;
       /**
-       * <code>optional .Range declaration = 1;</code>
+       * <code>optional .TextRange declaration = 1;</code>
        */
       public boolean hasDeclaration() {
         return ((bitField0_ & 0x00000001) == 0x00000001);
       }
       /**
-       * <code>optional .Range declaration = 1;</code>
+       * <code>optional .TextRange declaration = 1;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range getDeclaration() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRange getDeclaration() {
         if (declarationBuilder_ == null) {
           return declaration_;
         } else {
@@ -12402,9 +14601,9 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional .Range declaration = 1;</code>
+       * <code>optional .TextRange declaration = 1;</code>
        */
-      public Builder setDeclaration(org.sonar.batch.protocol.output.BatchReport.Range value) {
+      public Builder setDeclaration(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (declarationBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -12418,10 +14617,10 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range declaration = 1;</code>
+       * <code>optional .TextRange declaration = 1;</code>
        */
       public Builder setDeclaration(
-          org.sonar.batch.protocol.output.BatchReport.Range.Builder builderForValue) {
+          org.sonar.batch.protocol.output.BatchReport.TextRange.Builder builderForValue) {
         if (declarationBuilder_ == null) {
           declaration_ = builderForValue.build();
           onChanged();
@@ -12432,14 +14631,14 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range declaration = 1;</code>
+       * <code>optional .TextRange declaration = 1;</code>
        */
-      public Builder mergeDeclaration(org.sonar.batch.protocol.output.BatchReport.Range value) {
+      public Builder mergeDeclaration(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (declarationBuilder_ == null) {
           if (((bitField0_ & 0x00000001) == 0x00000001) &&
-              declaration_ != org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance()) {
+              declaration_ != org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance()) {
             declaration_ =
-              org.sonar.batch.protocol.output.BatchReport.Range.newBuilder(declaration_).mergeFrom(value).buildPartial();
+              org.sonar.batch.protocol.output.BatchReport.TextRange.newBuilder(declaration_).mergeFrom(value).buildPartial();
           } else {
             declaration_ = value;
           }
@@ -12451,11 +14650,11 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range declaration = 1;</code>
+       * <code>optional .TextRange declaration = 1;</code>
        */
       public Builder clearDeclaration() {
         if (declarationBuilder_ == null) {
-          declaration_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+          declaration_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
           onChanged();
         } else {
           declarationBuilder_.clear();
@@ -12464,17 +14663,17 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range declaration = 1;</code>
+       * <code>optional .TextRange declaration = 1;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range.Builder getDeclarationBuilder() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRange.Builder getDeclarationBuilder() {
         bitField0_ |= 0x00000001;
         onChanged();
         return getDeclarationFieldBuilder().getBuilder();
       }
       /**
-       * <code>optional .Range declaration = 1;</code>
+       * <code>optional .TextRange declaration = 1;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getDeclarationOrBuilder() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getDeclarationOrBuilder() {
         if (declarationBuilder_ != null) {
           return declarationBuilder_.getMessageOrBuilder();
         } else {
@@ -12482,14 +14681,14 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional .Range declaration = 1;</code>
+       * <code>optional .TextRange declaration = 1;</code>
        */
       private com.google.protobuf.SingleFieldBuilder<
-          org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> 
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> 
           getDeclarationFieldBuilder() {
         if (declarationBuilder_ == null) {
           declarationBuilder_ = new com.google.protobuf.SingleFieldBuilder<
-              org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder>(
+              org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder>(
                   getDeclaration(),
                   getParentForChildren(),
                   isClean());
@@ -12498,22 +14697,22 @@ public final class BatchReport {
         return declarationBuilder_;
       }
 
-      private java.util.List<org.sonar.batch.protocol.output.BatchReport.Range> reference_ =
+      private java.util.List<org.sonar.batch.protocol.output.BatchReport.TextRange> reference_ =
         java.util.Collections.emptyList();
       private void ensureReferenceIsMutable() {
         if (!((bitField0_ & 0x00000002) == 0x00000002)) {
-          reference_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.Range>(reference_);
+          reference_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.TextRange>(reference_);
           bitField0_ |= 0x00000002;
          }
       }
 
       private com.google.protobuf.RepeatedFieldBuilder<
-          org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> referenceBuilder_;
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> referenceBuilder_;
 
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
-      public java.util.List<org.sonar.batch.protocol.output.BatchReport.Range> getReferenceList() {
+      public java.util.List<org.sonar.batch.protocol.output.BatchReport.TextRange> getReferenceList() {
         if (referenceBuilder_ == null) {
           return java.util.Collections.unmodifiableList(reference_);
         } else {
@@ -12521,7 +14720,7 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
       public int getReferenceCount() {
         if (referenceBuilder_ == null) {
@@ -12531,9 +14730,9 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range getReference(int index) {
+      public org.sonar.batch.protocol.output.BatchReport.TextRange getReference(int index) {
         if (referenceBuilder_ == null) {
           return reference_.get(index);
         } else {
@@ -12541,10 +14740,10 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
       public Builder setReference(
-          int index, org.sonar.batch.protocol.output.BatchReport.Range value) {
+          int index, org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (referenceBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -12558,10 +14757,10 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
       public Builder setReference(
-          int index, org.sonar.batch.protocol.output.BatchReport.Range.Builder builderForValue) {
+          int index, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder builderForValue) {
         if (referenceBuilder_ == null) {
           ensureReferenceIsMutable();
           reference_.set(index, builderForValue.build());
@@ -12572,9 +14771,9 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
-      public Builder addReference(org.sonar.batch.protocol.output.BatchReport.Range value) {
+      public Builder addReference(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (referenceBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -12588,10 +14787,10 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
       public Builder addReference(
-          int index, org.sonar.batch.protocol.output.BatchReport.Range value) {
+          int index, org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (referenceBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -12605,10 +14804,10 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
       public Builder addReference(
-          org.sonar.batch.protocol.output.BatchReport.Range.Builder builderForValue) {
+          org.sonar.batch.protocol.output.BatchReport.TextRange.Builder builderForValue) {
         if (referenceBuilder_ == null) {
           ensureReferenceIsMutable();
           reference_.add(builderForValue.build());
@@ -12619,10 +14818,10 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
       public Builder addReference(
-          int index, org.sonar.batch.protocol.output.BatchReport.Range.Builder builderForValue) {
+          int index, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder builderForValue) {
         if (referenceBuilder_ == null) {
           ensureReferenceIsMutable();
           reference_.add(index, builderForValue.build());
@@ -12633,10 +14832,10 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
       public Builder addAllReference(
-          java.lang.Iterable<? extends org.sonar.batch.protocol.output.BatchReport.Range> values) {
+          java.lang.Iterable<? extends org.sonar.batch.protocol.output.BatchReport.TextRange> values) {
         if (referenceBuilder_ == null) {
           ensureReferenceIsMutable();
           com.google.protobuf.AbstractMessageLite.Builder.addAll(
@@ -12648,7 +14847,7 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
       public Builder clearReference() {
         if (referenceBuilder_ == null) {
@@ -12661,7 +14860,7 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
       public Builder removeReference(int index) {
         if (referenceBuilder_ == null) {
@@ -12674,16 +14873,16 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range.Builder getReferenceBuilder(
+      public org.sonar.batch.protocol.output.BatchReport.TextRange.Builder getReferenceBuilder(
           int index) {
         return getReferenceFieldBuilder().getBuilder(index);
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getReferenceOrBuilder(
+      public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getReferenceOrBuilder(
           int index) {
         if (referenceBuilder_ == null) {
           return reference_.get(index);  } else {
@@ -12691,9 +14890,9 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
-      public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> 
+      public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> 
            getReferenceOrBuilderList() {
         if (referenceBuilder_ != null) {
           return referenceBuilder_.getMessageOrBuilderList();
@@ -12702,33 +14901,33 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range.Builder addReferenceBuilder() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRange.Builder addReferenceBuilder() {
         return getReferenceFieldBuilder().addBuilder(
-            org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance());
+            org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance());
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range.Builder addReferenceBuilder(
+      public org.sonar.batch.protocol.output.BatchReport.TextRange.Builder addReferenceBuilder(
           int index) {
         return getReferenceFieldBuilder().addBuilder(
-            index, org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance());
+            index, org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance());
       }
       /**
-       * <code>repeated .Range reference = 2;</code>
+       * <code>repeated .TextRange reference = 2;</code>
        */
-      public java.util.List<org.sonar.batch.protocol.output.BatchReport.Range.Builder> 
+      public java.util.List<org.sonar.batch.protocol.output.BatchReport.TextRange.Builder> 
            getReferenceBuilderList() {
         return getReferenceFieldBuilder().getBuilderList();
       }
       private com.google.protobuf.RepeatedFieldBuilder<
-          org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> 
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> 
           getReferenceFieldBuilder() {
         if (referenceBuilder_ == null) {
           referenceBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
-              org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder>(
+              org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder>(
                   reference_,
                   ((bitField0_ & 0x00000002) == 0x00000002),
                   getParentForChildren(),
@@ -13821,17 +16020,17 @@ public final class BatchReport {
       com.google.protobuf.MessageOrBuilder {
 
     /**
-     * <code>optional .Range range = 1;</code>
+     * <code>optional .TextRange range = 1;</code>
      */
     boolean hasRange();
     /**
-     * <code>optional .Range range = 1;</code>
+     * <code>optional .TextRange range = 1;</code>
      */
-    org.sonar.batch.protocol.output.BatchReport.Range getRange();
+    org.sonar.batch.protocol.output.BatchReport.TextRange getRange();
     /**
-     * <code>optional .Range range = 1;</code>
+     * <code>optional .TextRange range = 1;</code>
      */
-    org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getRangeOrBuilder();
+    org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getRangeOrBuilder();
 
     /**
      * <code>optional .HighlightingType type = 2;</code>
@@ -13900,11 +16099,11 @@ public final class BatchReport {
               break;
             }
             case 10: {
-              org.sonar.batch.protocol.output.BatchReport.Range.Builder subBuilder = null;
+              org.sonar.batch.protocol.output.BatchReport.TextRange.Builder subBuilder = null;
               if (((bitField0_ & 0x00000001) == 0x00000001)) {
                 subBuilder = range_.toBuilder();
               }
-              range_ = input.readMessage(org.sonar.batch.protocol.output.BatchReport.Range.PARSER, extensionRegistry);
+              range_ = input.readMessage(org.sonar.batch.protocol.output.BatchReport.TextRange.PARSER, extensionRegistry);
               if (subBuilder != null) {
                 subBuilder.mergeFrom(range_);
                 range_ = subBuilder.buildPartial();
@@ -13964,23 +16163,23 @@ public final class BatchReport {
 
     private int bitField0_;
     public static final int RANGE_FIELD_NUMBER = 1;
-    private org.sonar.batch.protocol.output.BatchReport.Range range_;
+    private org.sonar.batch.protocol.output.BatchReport.TextRange range_;
     /**
-     * <code>optional .Range range = 1;</code>
+     * <code>optional .TextRange range = 1;</code>
      */
     public boolean hasRange() {
       return ((bitField0_ & 0x00000001) == 0x00000001);
     }
     /**
-     * <code>optional .Range range = 1;</code>
+     * <code>optional .TextRange range = 1;</code>
      */
-    public org.sonar.batch.protocol.output.BatchReport.Range getRange() {
+    public org.sonar.batch.protocol.output.BatchReport.TextRange getRange() {
       return range_;
     }
     /**
-     * <code>optional .Range range = 1;</code>
+     * <code>optional .TextRange range = 1;</code>
      */
-    public org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getRangeOrBuilder() {
+    public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getRangeOrBuilder() {
       return range_;
     }
 
@@ -14000,7 +16199,7 @@ public final class BatchReport {
     }
 
     private void initFields() {
-      range_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+      range_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
       type_ = org.sonar.batch.protocol.Constants.HighlightingType.ANNOTATION;
     }
     private byte memoizedIsInitialized = -1;
@@ -14163,7 +16362,7 @@ public final class BatchReport {
       public Builder clear() {
         super.clear();
         if (rangeBuilder_ == null) {
-          range_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+          range_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
         } else {
           rangeBuilder_.clear();
         }
@@ -14259,19 +16458,19 @@ public final class BatchReport {
       }
       private int bitField0_;
 
-      private org.sonar.batch.protocol.output.BatchReport.Range range_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+      private org.sonar.batch.protocol.output.BatchReport.TextRange range_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
       private com.google.protobuf.SingleFieldBuilder<
-          org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> rangeBuilder_;
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> rangeBuilder_;
       /**
-       * <code>optional .Range range = 1;</code>
+       * <code>optional .TextRange range = 1;</code>
        */
       public boolean hasRange() {
         return ((bitField0_ & 0x00000001) == 0x00000001);
       }
       /**
-       * <code>optional .Range range = 1;</code>
+       * <code>optional .TextRange range = 1;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range getRange() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRange getRange() {
         if (rangeBuilder_ == null) {
           return range_;
         } else {
@@ -14279,9 +16478,9 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional .Range range = 1;</code>
+       * <code>optional .TextRange range = 1;</code>
        */
-      public Builder setRange(org.sonar.batch.protocol.output.BatchReport.Range value) {
+      public Builder setRange(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (rangeBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -14295,10 +16494,10 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range range = 1;</code>
+       * <code>optional .TextRange range = 1;</code>
        */
       public Builder setRange(
-          org.sonar.batch.protocol.output.BatchReport.Range.Builder builderForValue) {
+          org.sonar.batch.protocol.output.BatchReport.TextRange.Builder builderForValue) {
         if (rangeBuilder_ == null) {
           range_ = builderForValue.build();
           onChanged();
@@ -14309,14 +16508,14 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range range = 1;</code>
+       * <code>optional .TextRange range = 1;</code>
        */
-      public Builder mergeRange(org.sonar.batch.protocol.output.BatchReport.Range value) {
+      public Builder mergeRange(org.sonar.batch.protocol.output.BatchReport.TextRange value) {
         if (rangeBuilder_ == null) {
           if (((bitField0_ & 0x00000001) == 0x00000001) &&
-              range_ != org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance()) {
+              range_ != org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance()) {
             range_ =
-              org.sonar.batch.protocol.output.BatchReport.Range.newBuilder(range_).mergeFrom(value).buildPartial();
+              org.sonar.batch.protocol.output.BatchReport.TextRange.newBuilder(range_).mergeFrom(value).buildPartial();
           } else {
             range_ = value;
           }
@@ -14328,11 +16527,11 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range range = 1;</code>
+       * <code>optional .TextRange range = 1;</code>
        */
       public Builder clearRange() {
         if (rangeBuilder_ == null) {
-          range_ = org.sonar.batch.protocol.output.BatchReport.Range.getDefaultInstance();
+          range_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance();
           onChanged();
         } else {
           rangeBuilder_.clear();
@@ -14341,17 +16540,17 @@ public final class BatchReport {
         return this;
       }
       /**
-       * <code>optional .Range range = 1;</code>
+       * <code>optional .TextRange range = 1;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.Range.Builder getRangeBuilder() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRange.Builder getRangeBuilder() {
         bitField0_ |= 0x00000001;
         onChanged();
         return getRangeFieldBuilder().getBuilder();
       }
       /**
-       * <code>optional .Range range = 1;</code>
+       * <code>optional .TextRange range = 1;</code>
        */
-      public org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getRangeOrBuilder() {
+      public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getRangeOrBuilder() {
         if (rangeBuilder_ != null) {
           return rangeBuilder_.getMessageOrBuilder();
         } else {
@@ -14359,14 +16558,14 @@ public final class BatchReport {
         }
       }
       /**
-       * <code>optional .Range range = 1;</code>
+       * <code>optional .TextRange range = 1;</code>
        */
       private com.google.protobuf.SingleFieldBuilder<
-          org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder> 
+          org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder> 
           getRangeFieldBuilder() {
         if (rangeBuilder_ == null) {
           rangeBuilder_ = new com.google.protobuf.SingleFieldBuilder<
-              org.sonar.batch.protocol.output.BatchReport.Range, org.sonar.batch.protocol.output.BatchReport.Range.Builder, org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder>(
+              org.sonar.batch.protocol.output.BatchReport.TextRange, org.sonar.batch.protocol.output.BatchReport.TextRange.Builder, org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder>(
                   getRange(),
                   getParentForChildren(),
                   isClean());
@@ -16809,6 +19008,16 @@ public final class BatchReport {
   private static
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
       internal_static_Issue_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_IssueLocation_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_IssueLocation_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_ExecutionFlow_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_ExecutionFlow_fieldAccessorTable;
   private static final com.google.protobuf.Descriptors.Descriptor
     internal_static_Changesets_descriptor;
   private static
@@ -16830,10 +19039,10 @@ public final class BatchReport {
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
       internal_static_Duplication_fieldAccessorTable;
   private static final com.google.protobuf.Descriptors.Descriptor
-    internal_static_Range_descriptor;
+    internal_static_TextRange_descriptor;
   private static
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
-      internal_static_Range_fieldAccessorTable;
+      internal_static_TextRange_fieldAccessorTable;
   private static final com.google.protobuf.Descriptors.Descriptor
     internal_static_Symbol_descriptor;
   private static
@@ -16892,37 +19101,43 @@ public final class BatchReport {
       "_type\030\001 \001(\0162\021.MeasureValueType\022\025\n\rboolea" +
       "n_value\030\002 \001(\010\022\021\n\tint_value\030\003 \001(\005\022\022\n\nlong" +
       "_value\030\004 \001(\003\022\024\n\014double_value\030\005 \001(\001\022\024\n\014st" +
-      "ring_value\030\006 \001(\t\022\022\n\nmetric_key\030\007 \001(\t\"\225\001\n",
+      "ring_value\030\006 \001(\t\022\022\n\nmetric_key\030\007 \001(\t\"\341\001\n",
       "\005Issue\022\027\n\017rule_repository\030\001 \001(\t\022\020\n\010rule_" +
       "key\030\002 \001(\t\022\014\n\004line\030\003 \001(\005\022\013\n\003msg\030\004 \001(\t\022\033\n\010" +
       "severity\030\005 \001(\0162\t.Severity\022\025\n\reffort_to_f" +
-      "ix\030\006 \001(\001\022\022\n\nattributes\030\007 \001(\t\"\254\001\n\nChanges" +
-      "ets\022\025\n\rcomponent_ref\030\001 \001(\005\022(\n\tchangeset\030" +
-      "\002 \003(\0132\025.Changesets.Changeset\022 \n\024changese" +
-      "tIndexByLine\030\003 \003(\005B\002\020\001\032;\n\tChangeset\022\020\n\010r" +
-      "evision\030\001 \001(\t\022\016\n\006author\030\002 \001(\t\022\014\n\004date\030\003 " +
-      "\001(\003\"R\n\tDuplicate\022\026\n\016other_file_ref\030\001 \001(\005" +
-      "\022\025\n\005range\030\002 \001(\0132\006.Range\022\026\n\016other_file_ke",
-      "y\030\003 \001(\t\"M\n\013Duplication\022\037\n\017origin_positio" +
-      "n\030\001 \001(\0132\006.Range\022\035\n\tduplicate\030\002 \003(\0132\n.Dup" +
-      "licate\"W\n\005Range\022\022\n\nstart_line\030\001 \001(\005\022\020\n\010e" +
-      "nd_line\030\002 \001(\005\022\024\n\014start_offset\030\003 \001(\005\022\022\n\ne" +
-      "nd_offset\030\004 \001(\005\"@\n\006Symbol\022\033\n\013declaration" +
-      "\030\001 \001(\0132\006.Range\022\031\n\treference\030\002 \003(\0132\006.Rang" +
-      "e\"\260\001\n\010Coverage\022\014\n\004line\030\001 \001(\005\022\022\n\nconditio" +
-      "ns\030\002 \001(\005\022\017\n\007ut_hits\030\003 \001(\010\022\017\n\007it_hits\030\004 \001" +
-      "(\010\022\035\n\025ut_covered_conditions\030\005 \001(\005\022\035\n\025it_" +
-      "covered_conditions\030\006 \001(\005\022\"\n\032overall_cove",
-      "red_conditions\030\007 \001(\005\"L\n\022SyntaxHighlighti" +
-      "ng\022\025\n\005range\030\001 \001(\0132\006.Range\022\037\n\004type\030\002 \001(\0162" +
-      "\021.HighlightingType\"j\n\004Test\022\014\n\004name\030\001 \001(\t" +
-      "\022\033\n\006status\030\002 \001(\0162\013.TestStatus\022\026\n\016duratio" +
-      "n_in_ms\030\003 \001(\003\022\022\n\nstacktrace\030\004 \001(\t\022\013\n\003msg" +
-      "\030\005 \001(\t\"\221\001\n\016CoverageDetail\022\021\n\ttest_name\030\001" +
-      " \001(\t\0221\n\014covered_file\030\002 \003(\0132\033.CoverageDet" +
-      "ail.CoveredFile\0329\n\013CoveredFile\022\020\n\010file_r" +
-      "ef\030\001 \001(\005\022\030\n\014covered_line\030\002 \003(\005B\002\020\001B#\n\037or" +
-      "g.sonar.batch.protocol.outputH\001"
+      "ix\030\006 \001(\001\022\022\n\nattributes\030\007 \001(\t\022!\n\tlocation" +
+      "s\030\010 \003(\0132\016.IssueLocation\022\'\n\017execution_flo" +
+      "ws\030\t \003(\0132\016.ExecutionFlow\"S\n\rIssueLocatio" +
+      "n\022\025\n\rcomponent_ref\030\001 \001(\005\022\036\n\ntext_range\030\002" +
+      " \001(\0132\n.TextRange\022\013\n\003msg\030\003 \001(\t\"2\n\rExecuti" +
+      "onFlow\022!\n\tlocations\030\001 \003(\0132\016.IssueLocatio" +
+      "n\"\254\001\n\nChangesets\022\025\n\rcomponent_ref\030\001 \001(\005\022",
+      "(\n\tchangeset\030\002 \003(\0132\025.Changesets.Changese" +
+      "t\022 \n\024changesetIndexByLine\030\003 \003(\005B\002\020\001\032;\n\tC" +
+      "hangeset\022\020\n\010revision\030\001 \001(\t\022\016\n\006author\030\002 \001" +
+      "(\t\022\014\n\004date\030\003 \001(\003\"V\n\tDuplicate\022\026\n\016other_f" +
+      "ile_ref\030\001 \001(\005\022\031\n\005range\030\002 \001(\0132\n.TextRange" +
+      "\022\026\n\016other_file_key\030\003 \001(\t\"Q\n\013Duplication\022" +
+      "#\n\017origin_position\030\001 \001(\0132\n.TextRange\022\035\n\t" +
+      "duplicate\030\002 \003(\0132\n.Duplicate\"[\n\tTextRange" +
+      "\022\022\n\nstart_line\030\001 \001(\005\022\020\n\010end_line\030\002 \001(\005\022\024" +
+      "\n\014start_offset\030\003 \001(\005\022\022\n\nend_offset\030\004 \001(\005",
+      "\"H\n\006Symbol\022\037\n\013declaration\030\001 \001(\0132\n.TextRa" +
+      "nge\022\035\n\treference\030\002 \003(\0132\n.TextRange\"\260\001\n\010C" +
+      "overage\022\014\n\004line\030\001 \001(\005\022\022\n\nconditions\030\002 \001(" +
+      "\005\022\017\n\007ut_hits\030\003 \001(\010\022\017\n\007it_hits\030\004 \001(\010\022\035\n\025u" +
+      "t_covered_conditions\030\005 \001(\005\022\035\n\025it_covered" +
+      "_conditions\030\006 \001(\005\022\"\n\032overall_covered_con" +
+      "ditions\030\007 \001(\005\"P\n\022SyntaxHighlighting\022\031\n\005r" +
+      "ange\030\001 \001(\0132\n.TextRange\022\037\n\004type\030\002 \001(\0162\021.H" +
+      "ighlightingType\"j\n\004Test\022\014\n\004name\030\001 \001(\t\022\033\n" +
+      "\006status\030\002 \001(\0162\013.TestStatus\022\026\n\016duration_i",
+      "n_ms\030\003 \001(\003\022\022\n\nstacktrace\030\004 \001(\t\022\013\n\003msg\030\005 " +
+      "\001(\t\"\221\001\n\016CoverageDetail\022\021\n\ttest_name\030\001 \001(" +
+      "\t\0221\n\014covered_file\030\002 \003(\0132\033.CoverageDetail" +
+      ".CoveredFile\0329\n\013CoveredFile\022\020\n\010file_ref\030" +
+      "\001 \001(\005\022\030\n\014covered_line\030\002 \003(\005B\002\020\001B#\n\037org.s" +
+      "onar.batch.protocol.outputH\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
         new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
@@ -16978,9 +19193,21 @@ public final class BatchReport {
     internal_static_Issue_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Issue_descriptor,
-        new java.lang.String[] { "RuleRepository", "RuleKey", "Line", "Msg", "Severity", "EffortToFix", "Attributes", });
-    internal_static_Changesets_descriptor =
+        new java.lang.String[] { "RuleRepository", "RuleKey", "Line", "Msg", "Severity", "EffortToFix", "Attributes", "Locations", "ExecutionFlows", });
+    internal_static_IssueLocation_descriptor =
       getDescriptor().getMessageTypes().get(6);
+    internal_static_IssueLocation_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_IssueLocation_descriptor,
+        new java.lang.String[] { "ComponentRef", "TextRange", "Msg", });
+    internal_static_ExecutionFlow_descriptor =
+      getDescriptor().getMessageTypes().get(7);
+    internal_static_ExecutionFlow_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_ExecutionFlow_descriptor,
+        new java.lang.String[] { "Locations", });
+    internal_static_Changesets_descriptor =
+      getDescriptor().getMessageTypes().get(8);
     internal_static_Changesets_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Changesets_descriptor,
@@ -16992,49 +19219,49 @@ public final class BatchReport {
         internal_static_Changesets_Changeset_descriptor,
         new java.lang.String[] { "Revision", "Author", "Date", });
     internal_static_Duplicate_descriptor =
-      getDescriptor().getMessageTypes().get(7);
+      getDescriptor().getMessageTypes().get(9);
     internal_static_Duplicate_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Duplicate_descriptor,
         new java.lang.String[] { "OtherFileRef", "Range", "OtherFileKey", });
     internal_static_Duplication_descriptor =
-      getDescriptor().getMessageTypes().get(8);
+      getDescriptor().getMessageTypes().get(10);
     internal_static_Duplication_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Duplication_descriptor,
         new java.lang.String[] { "OriginPosition", "Duplicate", });
-    internal_static_Range_descriptor =
-      getDescriptor().getMessageTypes().get(9);
-    internal_static_Range_fieldAccessorTable = new
+    internal_static_TextRange_descriptor =
+      getDescriptor().getMessageTypes().get(11);
+    internal_static_TextRange_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
-        internal_static_Range_descriptor,
+        internal_static_TextRange_descriptor,
         new java.lang.String[] { "StartLine", "EndLine", "StartOffset", "EndOffset", });
     internal_static_Symbol_descriptor =
-      getDescriptor().getMessageTypes().get(10);
+      getDescriptor().getMessageTypes().get(12);
     internal_static_Symbol_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Symbol_descriptor,
         new java.lang.String[] { "Declaration", "Reference", });
     internal_static_Coverage_descriptor =
-      getDescriptor().getMessageTypes().get(11);
+      getDescriptor().getMessageTypes().get(13);
     internal_static_Coverage_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Coverage_descriptor,
         new java.lang.String[] { "Line", "Conditions", "UtHits", "ItHits", "UtCoveredConditions", "ItCoveredConditions", "OverallCoveredConditions", });
     internal_static_SyntaxHighlighting_descriptor =
-      getDescriptor().getMessageTypes().get(12);
+      getDescriptor().getMessageTypes().get(14);
     internal_static_SyntaxHighlighting_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_SyntaxHighlighting_descriptor,
         new java.lang.String[] { "Range", "Type", });
     internal_static_Test_descriptor =
-      getDescriptor().getMessageTypes().get(13);
+      getDescriptor().getMessageTypes().get(15);
     internal_static_Test_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_Test_descriptor,
         new java.lang.String[] { "Name", "Status", "DurationInMs", "Stacktrace", "Msg", });
     internal_static_CoverageDetail_descriptor =
-      getDescriptor().getMessageTypes().get(14);
+      getDescriptor().getMessageTypes().get(16);
     internal_static_CoverageDetail_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_CoverageDetail_descriptor,
index 1d034a80b959d45bb843ae665ee101667ccc8853..e973a338021eeee49050caa9c4262ddf0ce8a0ee 100644 (file)
@@ -104,6 +104,19 @@ message Issue {
   optional Severity severity = 5;
   optional double effort_to_fix = 6;
   optional string attributes = 7;
+  repeated IssueLocation locations = 8;
+  repeated ExecutionFlow execution_flows = 9;
+}
+
+message IssueLocation {
+  optional int32 component_ref = 1;
+  // Only when component is a file. Can be empty for a file if this is an issue global to the file.
+  optional TextRange text_range = 2;
+  optional string msg = 3;
+}
+
+message ExecutionFlow {
+  repeated IssueLocation locations = 1;
 }
 
 message Changesets {
@@ -122,7 +135,7 @@ message Changesets {
 message Duplicate {
   // Will be null when duplicate is in the same file
   optional int32 other_file_ref = 1;
-  optional Range range = 2;
+  optional TextRange range = 2;
 
   // temporary field during development of computation stack for cross project duplications
   optional string other_file_key = 3;
@@ -130,12 +143,12 @@ message Duplicate {
 
 message Duplication {
   // Origin position in current file
-  optional Range origin_position = 1;
+  optional TextRange origin_position = 1;
   repeated Duplicate duplicate = 2;
 }
 
 // Lines start at 1 and line offsets start at 0
-message Range {
+message TextRange {
   // Should never be null
   optional int32 start_line = 1;
   // End line (inclusive). Null means it is same as start line
@@ -147,8 +160,8 @@ message Range {
 }
 
 message Symbol {
-  optional Range declaration = 1;
-  repeated Range reference = 2;
+  optional TextRange declaration = 1;
+  repeated TextRange reference = 2;
 }
 
 // Only FILE component has coverage information, and only executable lines should contains this information.
@@ -173,7 +186,7 @@ message Coverage {
 // Must be sorted by line and start offset
 // TODO rename it SyntaxHighlightingRule ?
 message SyntaxHighlighting {
-  optional Range range = 1;
+  optional TextRange range = 1;
   optional HighlightingType type = 2;
 }
 
index 283933d18bfb63f90284252c4b1b9de2480a2f03..19b29fb5f033e201eb9e48e2dc0144497227bd63 100644 (file)
@@ -144,14 +144,14 @@ public class BatchReportReaderTest {
       .setRef(1).build());
 
     BatchReport.Duplication duplication = BatchReport.Duplication.newBuilder()
-      .setOriginPosition(BatchReport.Range.newBuilder()
+      .setOriginPosition(BatchReport.TextRange.newBuilder()
         .setStartLine(1)
         .setEndLine(5)
         .build())
       .addDuplicate(BatchReport.Duplicate.newBuilder()
         .setOtherFileKey("COMPONENT_A")
         .setOtherFileRef(2)
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(6)
           .setEndLine(10)
           .build())
@@ -179,7 +179,7 @@ public class BatchReportReaderTest {
 
     writer.writeComponentSyntaxHighlighting(1, Arrays.asList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(10)
           .build())
@@ -210,13 +210,13 @@ public class BatchReportReaderTest {
       .setRef(1).build());
 
     writer.writeComponentSymbols(1, Arrays.asList(BatchReport.Symbol.newBuilder()
-      .setDeclaration(BatchReport.Range.newBuilder()
+      .setDeclaration(BatchReport.TextRange.newBuilder()
         .setStartLine(1)
         .setStartOffset(3)
         .setEndLine(1)
         .setEndOffset(5)
         .build())
-      .addReference(BatchReport.Range.newBuilder()
+      .addReference(BatchReport.TextRange.newBuilder()
         .setStartLine(10)
         .setStartOffset(15)
         .setEndLine(11)
index ae1a6cd143e824443f3beb70a2a54a30c99dd636..93a394a59cdd52e66ff4f891ee6218575f19cd9b 100644 (file)
@@ -28,7 +28,6 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.batch.protocol.Constants;
-import org.sonar.batch.protocol.output.BatchReport.Range;
 import org.sonar.core.util.CloseableIterator;
 import org.sonar.core.util.Protobuf;
 
@@ -166,14 +165,14 @@ public class BatchReportWriterTest {
     assertThat(underTest.hasComponentData(FileStructure.Domain.DUPLICATIONS, 1)).isFalse();
 
     BatchReport.Duplication duplication = BatchReport.Duplication.newBuilder()
-      .setOriginPosition(Range.newBuilder()
+      .setOriginPosition(BatchReport.TextRange.newBuilder()
         .setStartLine(1)
         .setEndLine(5)
         .build())
       .addDuplicate(BatchReport.Duplicate.newBuilder()
         .setOtherFileKey("COMPONENT_A")
         .setOtherFileRef(2)
-        .setRange(Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(6)
           .setEndLine(10)
           .build())
@@ -198,13 +197,13 @@ public class BatchReportWriterTest {
 
     // write data
     BatchReport.Symbol symbol = BatchReport.Symbol.newBuilder()
-      .setDeclaration(BatchReport.Range.newBuilder()
+      .setDeclaration(BatchReport.TextRange.newBuilder()
         .setStartLine(1)
         .setStartOffset(3)
         .setEndLine(1)
         .setEndOffset(5)
         .build())
-      .addReference(BatchReport.Range.newBuilder()
+      .addReference(BatchReport.TextRange.newBuilder()
         .setStartLine(10)
         .setStartOffset(15)
         .setEndLine(11)
@@ -230,7 +229,7 @@ public class BatchReportWriterTest {
 
     underTest.writeComponentSyntaxHighlighting(1, Arrays.asList(
       BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(1)
           .setEndLine(1)
           .build())
index 63dac585a2cc17b2b4c678c45e8f537c5d07cd47..fb39cf956e57167ce5d4a33702305c274bec4ace 100644 (file)
@@ -21,6 +21,15 @@ package org.sonar.batch.index;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.ObjectUtils;
 import org.apache.commons.lang.StringUtils;
@@ -28,10 +37,12 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.batch.SonarIndex;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.measure.Metric;
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.measure.MetricFinder;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
+import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
 import org.sonar.api.design.Dependency;
-import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Measure;
 import org.sonar.api.measures.MeasuresFilter;
 import org.sonar.api.measures.MeasuresFilters;
@@ -41,69 +52,30 @@ import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.resources.Resource;
 import org.sonar.api.resources.ResourceUtils;
-import org.sonar.api.resources.Scopes;
+import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.Violation;
 import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.api.utils.SonarException;
 import org.sonar.batch.DefaultProjectTree;
-import org.sonar.batch.issue.ModuleIssues;
 import org.sonar.batch.scan.measure.MeasureCache;
+import org.sonar.batch.sensor.DefaultSensorStorage;
 import org.sonar.core.component.ComponentKeys;
 
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 public class DefaultIndex extends SonarIndex {
 
   private static final Logger LOG = LoggerFactory.getLogger(DefaultIndex.class);
 
-  private static final List<Metric> INTERNAL_METRICS = Arrays.<Metric>asList(
-    // Computed by CpdSensor
-    CoreMetrics.DUPLICATED_FILES,
-    CoreMetrics.DUPLICATED_LINES,
-    CoreMetrics.DUPLICATED_BLOCKS,
-    // Computed by LinesSensor
-    CoreMetrics.LINES
-    );
-
-  private static final List<String> DEPRECATED_METRICS_KEYS = Arrays.<String>asList(
-    CoreMetrics.DEPENDENCY_MATRIX_KEY,
-    CoreMetrics.DIRECTORY_CYCLES_KEY,
-    CoreMetrics.DIRECTORY_EDGES_WEIGHT_KEY,
-    CoreMetrics.DIRECTORY_FEEDBACK_EDGES_KEY,
-    CoreMetrics.DIRECTORY_TANGLE_INDEX_KEY,
-    CoreMetrics.DIRECTORY_TANGLES_KEY,
-    CoreMetrics.FILE_CYCLES_KEY,
-    CoreMetrics.FILE_EDGES_WEIGHT_KEY,
-    CoreMetrics.FILE_FEEDBACK_EDGES_KEY,
-    CoreMetrics.FILE_TANGLE_INDEX_KEY,
-    CoreMetrics.FILE_TANGLES_KEY,
-    CoreMetrics.DUPLICATIONS_DATA_KEY
-    );
-
-  private final BatchComponentCache resourceCache;
-  private final MetricFinder metricFinder;
+  private final BatchComponentCache componentCache;
   private final MeasureCache measureCache;
+  private DefaultSensorStorage sensorStorage;
   // caches
   private Project currentProject;
   private Map<Resource, Bucket> buckets = Maps.newLinkedHashMap();
   private DefaultProjectTree projectTree;
-  private ModuleIssues moduleIssues;
 
-  public DefaultIndex(BatchComponentCache resourceCache, DefaultProjectTree projectTree, MetricFinder metricFinder, MeasureCache measureCache) {
-    this.resourceCache = resourceCache;
+  public DefaultIndex(BatchComponentCache componentCache, DefaultProjectTree projectTree, MetricFinder metricFinder, MeasureCache measureCache) {
+    this.componentCache = componentCache;
     this.projectTree = projectTree;
-    this.metricFinder = metricFinder;
     this.measureCache = measureCache;
   }
 
@@ -117,7 +89,7 @@ public class DefaultIndex extends SonarIndex {
   void doStart(Project rootProject) {
     Bucket bucket = new Bucket(rootProject);
     addBucket(rootProject, bucket);
-    resourceCache.add(rootProject, null);
+    componentCache.add(rootProject, null);
     currentProject = rootProject;
 
     for (Project module : rootProject.getModules()) {
@@ -146,11 +118,11 @@ public class DefaultIndex extends SonarIndex {
     return currentProject;
   }
 
-  public void setCurrentProject(Project project, ModuleIssues moduleIssues) {
+  public void setCurrentProject(Project project, DefaultSensorStorage sensorStorage) {
     this.currentProject = project;
 
     // the following components depend on the current module, so they need to be reloaded.
-    this.moduleIssues = moduleIssues;
+    this.sensorStorage = sensorStorage;
   }
 
   /**
@@ -203,22 +175,7 @@ public class DefaultIndex extends SonarIndex {
   public Measure addMeasure(Resource resource, Measure measure) {
     Bucket bucket = getBucket(resource);
     if (bucket != null) {
-      if (DEPRECATED_METRICS_KEYS.contains(measure.getMetricKey())) {
-        // Ignore deprecated metrics
-        return null;
-      }
-      org.sonar.api.batch.measure.Metric metric = metricFinder.findByKey(measure.getMetricKey());
-      if (metric == null) {
-        throw new SonarException("Unknown metric: " + measure.getMetricKey());
-      }
-      if (!measure.isFromCore() && INTERNAL_METRICS.contains(metric)) {
-        LOG.debug("Metric " + metric.key() + " is an internal metric computed by SonarQube. Provided value is ignored.");
-        return measure;
-      }
-      if (measureCache.contains(resource, measure)) {
-        throw new SonarException("Can not add the same measure twice on " + resource + ": " + measure);
-      }
-      measureCache.put(resource, measure);
+      return sensorStorage.saveMeasure(resource, measure);
     }
     return measure;
   }
@@ -243,11 +200,10 @@ public class DefaultIndex extends SonarIndex {
 
   @Override
   public void addViolation(Violation violation, boolean force) {
-    Resource resource = violation.getResource();
-    if (resource == null) {
-      violation.setResource(currentProject);
-    } else if (!Scopes.isHigherThanOrEquals(resource, Scopes.FILE)) {
-      throw new IllegalArgumentException("Violations are only supported on files, directories and project");
+    BatchComponent component = componentCache.get(violation.getResource());
+    if (component == null) {
+      LOG.warn("Resource is not indexed. Ignoring violation {}", violation);
+      return;
     }
 
     Rule rule = violation.getRule();
@@ -256,19 +212,29 @@ public class DefaultIndex extends SonarIndex {
       return;
     }
 
-    Bucket bucket = getBucket(resource);
-    if (bucket == null) {
-      LOG.warn("Resource is not indexed. Ignoring violation {}", violation);
-      return;
-    }
-
     // keep a limitation (bug?) of deprecated violations api : severity is always
     // set by sonar. The severity set by plugins is overridden.
     // This is not the case with issue api.
-    violation.setSeverity(null);
 
-    violation.setResource(bucket.getResource());
-    moduleIssues.initAndAddViolation(violation);
+    DefaultIssue newIssue = new DefaultIssue(sensorStorage);
+    NewIssueLocation newLocation = newIssue.newLocation();
+    if (component.isProjectOrModule()) {
+      newLocation.onProject();
+    } else if (component.isDir()) {
+      newLocation.onDir((InputDir) component.inputPath());
+    } else if (component.isFile()) {
+      InputFile inputFile = (InputFile) component.inputPath();
+      newLocation.onFile(inputFile);
+      if (violation.hasLineId()) {
+        newLocation.at(inputFile.selectLine(violation.getLineId()));
+      }
+    }
+    newLocation.message(violation.getMessage());
+
+    newIssue.addLocation(newLocation)
+      .forRule(RuleKey.of(violation.getRule().getRepositoryKey(), violation.getRule().getKey()))
+      .effortToFix(violation.getCost())
+      .save();
   }
 
   @Override
@@ -378,7 +344,7 @@ public class DefaultIndex extends SonarIndex {
     addBucket(resource, bucket);
 
     Resource parentResource = parentBucket != null ? parentBucket.getResource() : null;
-    resourceCache.add(resource, parentResource);
+    componentCache.add(resource, parentResource);
 
     return bucket;
   }
index 9dd268a8d2231639f27288da35926163e4ba1479..76970b5c80f4d51ceb1a15221ba4f242c3def559 100644 (file)
@@ -21,44 +21,43 @@ package org.sonar.batch.issue;
 
 import com.google.common.collect.Lists;
 import java.util.List;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
 import org.sonar.api.issue.Issuable;
 import org.sonar.api.issue.Issue;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.api.resources.Project;
 import org.sonar.batch.index.BatchComponent;
-import org.sonar.core.issue.DefaultIssueBuilder;
 
 /**
  * @since 3.6
  */
 public class DefaultIssuable implements Issuable {
 
-  private final ModuleIssues moduleIssues;
   private final IssueCache cache;
   private final BatchComponent component;
-  private final Project project;
+  private final SensorContext sensorContext;
 
-  DefaultIssuable(BatchComponent component, Project project, ModuleIssues moduleIssues, IssueCache cache) {
+  DefaultIssuable(BatchComponent component, IssueCache cache, SensorContext sensorContext) {
     this.component = component;
-    this.project = project;
-    this.moduleIssues = moduleIssues;
     this.cache = cache;
+    this.sensorContext = sensorContext;
   }
 
   @Override
   public IssueBuilder newIssueBuilder() {
-    return new DefaultIssueBuilder().componentKey(component.key()).projectKey(project.getKey());
+    DefaultIssue newIssue = (DefaultIssue) sensorContext.newIssue();
+    return new DeprecatedIssueBuilderWrapper(component, newIssue);
   }
 
   @Override
   public boolean addIssue(Issue issue) {
-    return moduleIssues.initAndAddIssue((DefaultIssue) issue);
+    ((DeprecatedIssueWrapper) issue).wrapped().save();
+    return true;
   }
 
   @Override
   public List<Issue> resolvedIssues() {
     List<Issue> result = Lists.newArrayList();
-    for (DefaultIssue issue : cache.byComponent(component.key())) {
+    for (org.sonar.core.issue.DefaultIssue issue : cache.byComponent(component.key())) {
       if (issue.resolution() != null) {
         result.add(issue);
       }
@@ -69,7 +68,7 @@ public class DefaultIssuable implements Issuable {
   @Override
   public List<Issue> issues() {
     List<Issue> result = Lists.newArrayList();
-    for (DefaultIssue issue : cache.byComponent(component.key())) {
+    for (org.sonar.core.issue.DefaultIssue issue : cache.byComponent(component.key())) {
       if (issue.resolution() == null) {
         result.add(issue);
       }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedIssueBuilderWrapper.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedIssueBuilderWrapper.java
new file mode 100644 (file)
index 0000000..99186f9
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.issue;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
+import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
+import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation;
+import org.sonar.api.issue.Issuable;
+import org.sonar.api.issue.Issuable.IssueBuilder;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.batch.index.BatchComponent;
+
+public class DeprecatedIssueBuilderWrapper implements Issuable.IssueBuilder {
+
+  private final DefaultIssue newIssue;
+  private final BatchComponent primaryComponent;
+  private TextRange primaryRange = null;
+  private String primaryMessage = null;
+  private List<NewIssueLocation> locations = new ArrayList<>();
+
+  public DeprecatedIssueBuilderWrapper(BatchComponent primaryComponent, DefaultIssue newIssue) {
+    this.primaryComponent = primaryComponent;
+    this.newIssue = newIssue;
+  }
+
+  @Override
+  public IssueBuilder ruleKey(RuleKey ruleKey) {
+    newIssue.forRule(ruleKey);
+    return this;
+  }
+
+  @Override
+  public IssueBuilder line(Integer line) {
+    if (primaryComponent.isFile()) {
+      this.primaryRange = ((InputFile) primaryComponent.inputPath()).selectLine(line);
+      return this;
+    } else {
+      throw new IllegalArgumentException("Unable to set line for issues on project or directory");
+    }
+  }
+
+  @Override
+  public IssueBuilder message(String message) {
+    this.primaryMessage = message;
+    return this;
+  }
+
+  @Override
+  public NewIssueLocation newLocation() {
+    return new DefaultIssueLocation();
+  }
+
+  @Override
+  public IssueBuilder addLocation(NewIssueLocation location) {
+    locations.add(location);
+    return this;
+  }
+
+  @Override
+  public IssueBuilder addExecutionFlow(NewIssueLocation... flow) {
+    newIssue.addExecutionFlow(flow);
+    return this;
+  }
+
+  @Override
+  public IssueBuilder severity(String severity) {
+    newIssue.overrideSeverity(Severity.valueOf(severity));
+    return this;
+  }
+
+  @Override
+  public IssueBuilder reporter(String reporter) {
+    throw new UnsupportedOperationException("Not supported during sensor phase");
+  }
+
+  @Override
+  public IssueBuilder effortToFix(Double d) {
+    newIssue.effortToFix(d);
+    return this;
+  }
+
+  @Override
+  public IssueBuilder attribute(String key, String value) {
+    throw new UnsupportedOperationException("Unused");
+  }
+
+  @Override
+  public Issue build() {
+    if (primaryMessage != null || primaryRange != null || locations.isEmpty()) {
+      NewIssueLocation newLocation = newIssue.newLocation().message(primaryMessage);
+      if (primaryComponent.isProjectOrModule()) {
+        newLocation.onProject();
+      } else if (primaryComponent.isFile()) {
+        newLocation.onFile((InputFile) primaryComponent.inputPath());
+        if (primaryRange != null) {
+          newLocation.at(primaryRange);
+        }
+      } else if (primaryComponent.isDir()) {
+        newLocation.onDir((InputDir) primaryComponent.inputPath());
+      }
+      newIssue.addLocation(newLocation);
+    }
+    for (NewIssueLocation issueLocation : locations) {
+      newIssue.addLocation(issueLocation);
+    }
+
+    return new DeprecatedIssueWrapper(newIssue);
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedIssueWrapper.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedIssueWrapper.java
new file mode 100644 (file)
index 0000000..e2773e0
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.issue;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.IssueComment;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
+
+public class DeprecatedIssueWrapper implements Issue {
+
+  private final DefaultIssue newIssue;
+
+  public DeprecatedIssueWrapper(DefaultIssue newIssue) {
+    this.newIssue = newIssue;
+  }
+
+  public DefaultIssue wrapped() {
+    return newIssue;
+  }
+
+  @Override
+  public String key() {
+    return newIssue.key();
+  }
+
+  @Override
+  public String componentKey() {
+    return null;
+  }
+
+  @Override
+  public RuleKey ruleKey() {
+    return newIssue.ruleKey();
+  }
+
+  @Override
+  public String language() {
+    return null;
+  }
+
+  @Override
+  public String severity() {
+    Severity overridenSeverity = newIssue.overriddenSeverity();
+    return overridenSeverity != null ? overridenSeverity.name() : null;
+  }
+
+  @Override
+  public String message() {
+    return newIssue.locations().get(0).message();
+  }
+
+  @Override
+  public Integer line() {
+    TextRange textRange = newIssue.locations().get(0).textRange();
+    return textRange != null ? textRange.start().line() : null;
+  }
+
+  @Override
+  public Double effortToFix() {
+    return newIssue.effortToFix();
+  }
+
+  @Override
+  public String status() {
+    return null;
+  }
+
+  @Override
+  public String resolution() {
+    return null;
+  }
+
+  @Override
+  public String reporter() {
+    return null;
+  }
+
+  @Override
+  public String assignee() {
+    return null;
+  }
+
+  @Override
+  public Date creationDate() {
+    return null;
+  }
+
+  @Override
+  public Date updateDate() {
+    return null;
+  }
+
+  @Override
+  public Date closeDate() {
+    return null;
+  }
+
+  @Override
+  public String attribute(String key) {
+    return null;
+  }
+
+  @Override
+  public Map<String, String> attributes() {
+    return null;
+  }
+
+  @Override
+  public String authorLogin() {
+    return null;
+  }
+
+  @Override
+  public String actionPlanKey() {
+    return null;
+  }
+
+  @Override
+  public List<IssueComment> comments() {
+    return null;
+  }
+
+  @Override
+  public boolean isNew() {
+    return false;
+  }
+
+  @Override
+  public Duration debt() {
+    return null;
+  }
+
+  @Override
+  public String projectKey() {
+    return null;
+  }
+
+  @Override
+  public String projectUuid() {
+    return null;
+  }
+
+  @Override
+  public String componentUuid() {
+    return null;
+  }
+
+  @Override
+  public Collection<String> tags() {
+    return null;
+  }
+
+}
index 1fda7c27513a9f1af4b7554f0a7bb29c3e18b68c..6425abaca60f5d53bb5a9e66dc3cfb80025e66e6 100644 (file)
  */
 package org.sonar.batch.issue;
 
+import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.issue.Issuable;
-import org.sonar.batch.DefaultProjectTree;
 import org.sonar.batch.deprecated.perspectives.PerspectiveBuilder;
 import org.sonar.batch.index.BatchComponent;
+import org.sonar.batch.sensor.DefaultSensorContext;
 
 /**
  * Create the perspective {@link Issuable} on components.
@@ -30,19 +31,17 @@ import org.sonar.batch.index.BatchComponent;
  */
 public class IssuableFactory extends PerspectiveBuilder<Issuable> {
 
-  private final ModuleIssues moduleIssues;
   private final IssueCache cache;
-  private final DefaultProjectTree projectTree;
+  private final SensorContext sensorContext;
 
-  public IssuableFactory(ModuleIssues moduleIssues, IssueCache cache, DefaultProjectTree projectTree) {
+  public IssuableFactory(IssueCache cache, DefaultSensorContext sensorContext) {
     super(Issuable.class);
-    this.moduleIssues = moduleIssues;
     this.cache = cache;
-    this.projectTree = projectTree;
+    this.sensorContext = sensorContext;
   }
 
   @Override
   public Issuable loadPerspective(Class<Issuable> perspectiveClass, BatchComponent component) {
-    return new DefaultIssuable(component, projectTree.getRootProject(), moduleIssues, cache);
+    return new DefaultIssuable(component, cache, sensorContext);
   }
 }
index 73c7604860c19f7b66a26c15b5242d818aafb1eb..5fad21f090567cc911eff118c2a53002f9282f6f 100644 (file)
@@ -28,10 +28,8 @@ import org.sonar.api.batch.rule.Rules;
 import org.sonar.api.batch.rule.internal.DefaultActiveRule;
 import org.sonar.api.resources.Project;
 import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Violation;
 import org.sonar.api.utils.MessageException;
 import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.DefaultIssueBuilder;
 
 /**
  * Initialize the issues raised during scan.
@@ -56,24 +54,6 @@ public class ModuleIssues {
     this(activeRules, null, cache, project, filters);
   }
 
-  public boolean initAndAddViolation(Violation violation) {
-    DefaultIssue issue = newIssue(violation);
-    return initAndAddIssue(issue);
-  }
-
-  private DefaultIssue newIssue(Violation violation) {
-    return new DefaultIssueBuilder()
-      .componentKey(violation.getResource().getEffectiveKey())
-      // Project can be null but Violation not used by scan2
-      .projectKey(project.getRoot().getEffectiveKey())
-      .ruleKey(RuleKey.of(violation.getRule().getRepositoryKey(), violation.getRule().getKey()))
-      .effortToFix(violation.getCost())
-      .line(violation.getLineId())
-      .message(violation.getMessage())
-      .severity(violation.getSeverity() != null ? violation.getSeverity().name() : null)
-      .build();
-  }
-
   public boolean initAndAddIssue(DefaultIssue issue) {
     RuleKey ruleKey = issue.ruleKey();
     Rule rule = null;
index d1ca1ff324cd5fa1fec35ec8df87929bd1873d13..c553aeb349a1ee1a0e3c06af0b4df0d8a5ac16c7 100644 (file)
@@ -266,7 +266,8 @@ public class BatchMediumTester {
     }
 
     public FakeProjectRepositoriesLoader addQProfile(String language, String name) {
-      ref.addQProfile(new org.sonar.batch.protocol.input.QProfile(name, name, language, new Date()));
+      // Use a fixed date to allow assertions
+      ref.addQProfile(new org.sonar.batch.protocol.input.QProfile(name, name, language, new Date(1234567891212L)));
       return this;
     }
 
index 589f2bbe5f2c11cfbe2a8304fd4c7c4d6f741867..10341e8dcbe3baa420afd931d394d289c991f5a7 100644 (file)
  */
 package org.sonar.batch.mediumtest;
 
-import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Iterators;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Multimap;
 import java.io.InputStream;
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -38,30 +36,23 @@ import org.slf4j.LoggerFactory;
 import org.sonar.api.batch.AnalysisMode;
 import org.sonar.api.batch.fs.InputDir;
 import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputPath;
 import org.sonar.api.batch.fs.TextPointer;
 import org.sonar.api.batch.fs.TextRange;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.sensor.duplication.Duplication;
 import org.sonar.api.batch.sensor.highlighting.TypeOfText;
-import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.issue.Issue;
-import org.sonar.api.measures.Measure;
 import org.sonar.batch.duplication.DuplicationCache;
-import org.sonar.batch.index.BatchComponentCache;
-import org.sonar.batch.index.Cache.Entry;
 import org.sonar.batch.issue.IssueCache;
 import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.batch.protocol.output.BatchReport.Component;
 import org.sonar.batch.protocol.output.BatchReport.Metadata;
-import org.sonar.batch.protocol.output.BatchReport.Range;
 import org.sonar.batch.protocol.output.BatchReport.Symbol;
 import org.sonar.batch.protocol.output.BatchReportReader;
 import org.sonar.batch.report.BatchReportUtils;
 import org.sonar.batch.report.ReportPublisher;
 import org.sonar.batch.scan.ProjectScanContainer;
 import org.sonar.batch.scan.filesystem.InputPathCache;
-import org.sonar.batch.scan.measure.MeasureCache;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.util.CloseableIterator;
 
@@ -70,7 +61,6 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {
   private static final Logger LOG = LoggerFactory.getLogger(TaskResult.class);
 
   private List<Issue> issues = new ArrayList<>();
-  private Multimap<String, org.sonar.api.batch.sensor.measure.Measure> measures = LinkedHashMultimap.create();
   private Map<String, List<Duplication>> duplications = new HashMap<>();
   private Map<String, InputFile> inputFiles = new HashMap<>();
   private Map<String, Component> reportComponents = new HashMap<>();
@@ -94,8 +84,6 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {
 
     storeFs(container);
 
-    storeMeasures(container);
-
     storeDuplication(container);
   }
 
@@ -116,28 +104,6 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {
     return reader;
   }
 
-  private void storeMeasures(ProjectScanContainer container) {
-    BatchComponentCache resourceCache = container.getComponentByType(BatchComponentCache.class);
-    for (Entry<Measure> measureEntry : container.getComponentByType(MeasureCache.class).entries()) {
-      String componentKey = measureEntry.key()[0].toString();
-      InputPath path = resourceCache.get(componentKey).inputPath();
-      Measure oldMeasure = measureEntry.value();
-      DefaultMeasure<Serializable> newMeasure = new DefaultMeasure<>().forMetric(oldMeasure.getMetric());
-      if (path != null) {
-        if (path instanceof InputFile) {
-          newMeasure.onFile((InputFile) path);
-        } else {
-          // Ignore measure on directories since this will disappear in target architecture
-          continue;
-        }
-      } else {
-        newMeasure.onProject();
-      }
-      newMeasure.withValue(oldMeasure.value());
-      measures.put(componentKey, newMeasure);
-    }
-  }
-
   private void storeDuplication(ProjectScanContainer container) {
     DuplicationCache duplicationCache = container.getComponentByType(DuplicationCache.class);
     for (String effectiveKey : duplicationCache.componentKeys()) {
@@ -159,14 +125,6 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {
     return issues;
   }
 
-  public Collection<org.sonar.api.batch.sensor.measure.Measure> allMeasures() {
-    return measures.values();
-  }
-
-  public Collection<org.sonar.api.batch.sensor.measure.Measure> measures(String componentKey) {
-    return measures.get(componentKey);
-  }
-
   public Collection<InputFile> inputFiles() {
     return inputFiles.values();
   }
@@ -189,6 +147,18 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {
     return duplications.get(((DefaultInputFile) inputFile).key());
   }
 
+  public Map<String, List<BatchReport.Measure>> allMeasures() {
+    Map<String, List<BatchReport.Measure>> result = new HashMap<>();
+    for (Map.Entry<String, Component> component : reportComponents.entrySet()) {
+      List<BatchReport.Measure> measures = new ArrayList<>();
+      try (CloseableIterator<BatchReport.Measure> it = reader.readComponentMeasures(component.getValue().getRef())) {
+        Iterators.addAll(measures, it);
+      }
+      result.put(component.getKey(), measures);
+    }
+    return result;
+  }
+
   /**
    * Get highlighting types at a given position in an inputfile
    * @param lineOffset 0-based offset in file
@@ -214,7 +184,7 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {
     return result;
   }
 
-  private static TextRange toRange(InputFile file, Range reportRange) {
+  private static TextRange toRange(InputFile file, BatchReport.TextRange reportRange) {
     return file.newRange(file.newPointer(reportRange.getStartLine(), reportRange.getStartOffset()), file.newPointer(reportRange.getEndLine(), reportRange.getEndOffset()));
   }
 
@@ -224,7 +194,7 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {
    * @param symbolStartLineOffset 0-based end offset for the symbol in file
    */
   @CheckForNull
-  public List<Range> symbolReferencesFor(InputFile file, int symbolStartLine, int symbolStartLineOffset) {
+  public List<BatchReport.TextRange> symbolReferencesFor(InputFile file, int symbolStartLine, int symbolStartLineOffset) {
     int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef();
     try (CloseableIterator<Symbol> symbols = getReportReader().readComponentSymbols(ref)) {
       while (symbols.hasNext()) {
index b40521f355fd0810ce47790ffca6928b75b322e7..6cf132a9f6ee7e955a346f1c31be5a91e773a639 100644 (file)
@@ -26,10 +26,10 @@ import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
 import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.BatchComponent;
 import org.sonar.batch.index.BatchComponentCache;
-import org.sonar.batch.protocol.output.*;
+import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.batch.protocol.output.BatchReport.Duplicate;
 import org.sonar.batch.protocol.output.BatchReport.Duplication;
-import org.sonar.batch.protocol.output.BatchReport.Range;
+import org.sonar.batch.protocol.output.BatchReportWriter;
 
 public class DuplicationsPublisher implements ReportPublisherStep {
 
@@ -69,7 +69,7 @@ public class DuplicationsPublisher implements ReportPublisherStep {
     dupBuilder.clear();
     Block originBlock = input.originBlock();
     blockBuilder.clear();
-    dupBuilder.setOriginPosition(Range.newBuilder()
+    dupBuilder.setOriginPosition(BatchReport.TextRange.newBuilder()
       .setStartLine(originBlock.startLine())
       .setEndLine(originBlock.startLine() + originBlock.length() - 1)
       .build());
@@ -85,7 +85,7 @@ public class DuplicationsPublisher implements ReportPublisherStep {
         }
       }
       dupBuilder.addDuplicate(blockBuilder
-        .setRange(Range.newBuilder()
+        .setRange(BatchReport.TextRange.newBuilder()
           .setStartLine(duplicate.startLine())
           .setEndLine(duplicate.startLine() + duplicate.length() - 1)
           .build())
index fd03094668e6f2886e77be7fb6664aa8cb7bcb49..f6bc443c94e18765a612bcf532c9716f84cd9de8 100644 (file)
@@ -120,7 +120,7 @@ public class ModuleScanContainer extends ComponentContainer {
       ProjectInitializer.class,
       moduleDefinition.getContainerExtensions(),
 
-      // file system
+    // file system
       ModuleInputFileCache.class,
       FileExclusions.class,
       ExclusionFilters.class,
@@ -139,10 +139,10 @@ public class ModuleScanContainer extends ComponentContainer {
       ProjectClasspath.class,
       QProfileVerifier.class,
 
-      SensorOptimizer.class,
+    SensorOptimizer.class,
       PostJobOptimizer.class,
 
-      DefaultSensorContext.class,
+    DefaultSensorContext.class,
       DefaultPostJobContext.class,
       DefaultSensorStorage.class,
       DeprecatedSensorContext.class,
@@ -151,21 +151,21 @@ public class ModuleScanContainer extends ComponentContainer {
       CoverageExclusions.class,
       ResourceFilters.class,
 
-      // rules
+    // rules
       ModuleQProfiles.class,
       new RulesProfileProvider(),
       QProfileSensor.class,
       CheckFactory.class,
 
-      // report
+    // report
       IssuesReports.class,
 
-      // issues
+    // issues
       IssuableFactory.class,
       ModuleIssues.class,
       org.sonar.api.issue.NoSonarFilter.class,
 
-      // issue exclusions
+    // issue exclusions
       IssueInclusionPatternInitializer.class,
       IssueExclusionPatternInitializer.class,
       IssueExclusionsRegexpScanner.class,
@@ -174,7 +174,7 @@ public class ModuleScanContainer extends ComponentContainer {
       IgnoreIssuesFilter.class,
       NoSonarFilter.class,
 
-      // Perspectives
+    // Perspectives
       BatchPerspectives.class,
       HighlightableBuilder.class,
       SymbolizableBuilder.class);
@@ -193,7 +193,7 @@ public class ModuleScanContainer extends ComponentContainer {
   @Override
   protected void doAfterStart() {
     DefaultIndex index = getComponentByType(DefaultIndex.class);
-    index.setCurrentProject(module, getComponentByType(ModuleIssues.class));
+    index.setCurrentProject(module, getComponentByType(DefaultSensorStorage.class));
 
     getComponentByType(PhaseExecutor.class).execute(module);
 
index d3caddc45a100c5f4b02a5a6f50d2e7b36f9e09b..5e79960365c8d7197734bed8b34781515a3aebb2 100644 (file)
@@ -21,11 +21,13 @@ package org.sonar.batch.scan.filesystem;
 
 import org.sonar.api.batch.BatchSide;
 import org.sonar.api.batch.SonarIndex;
+import org.sonar.api.batch.fs.InputDir;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.resources.File;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Resource;
+import org.sonar.batch.index.BatchComponent;
 import org.sonar.batch.index.BatchComponentCache;
 
 /**
@@ -39,13 +41,13 @@ public class ComponentIndexer {
   private final Languages languages;
   private final SonarIndex sonarIndex;
   private final Project module;
-  private final BatchComponentCache resourceCache;
+  private final BatchComponentCache componentCache;
 
-  public ComponentIndexer(Project module, Languages languages, SonarIndex sonarIndex, BatchComponentCache resourceCache) {
+  public ComponentIndexer(Project module, Languages languages, SonarIndex sonarIndex, BatchComponentCache componentCache) {
     this.module = module;
     this.languages = languages;
     this.sonarIndex = sonarIndex;
-    this.resourceCache = resourceCache;
+    this.componentCache = componentCache;
   }
 
   public void execute(DefaultModuleFileSystem fs) {
@@ -56,7 +58,11 @@ public class ComponentIndexer {
       boolean unitTest = InputFile.Type.TEST == inputFile.type();
       Resource sonarFile = File.create(inputFile.relativePath(), languages.get(languageKey), unitTest);
       sonarIndex.index(sonarFile);
-      resourceCache.get(sonarFile).setInputPath(inputFile);
+      BatchComponent file = componentCache.get(sonarFile);
+      file.setInputPath(inputFile);
+      Resource sonarDir = file.parent().resource();
+      InputDir inputDir = fs.inputDir(inputFile.file().getParentFile());
+      componentCache.get(sonarDir).setInputPath(inputDir);
     }
   }
 }
index f1adc47cf10cd7c5395fee8345053133a0622cff..19bf0f2bc52e6f8a7851d909b11eeb5db2a41e3c 100644 (file)
@@ -21,9 +21,13 @@ package org.sonar.batch.sensor;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Iterables;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.sonar.api.batch.fs.FileSystem;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputPath;
@@ -43,53 +47,79 @@ import org.sonar.api.batch.sensor.issue.Issue;
 import org.sonar.api.batch.sensor.measure.Measure;
 import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.config.Settings;
-import org.sonar.core.issue.DefaultIssue;
+import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Formula;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.measures.PersistenceMode;
 import org.sonar.api.measures.SumChildDistributionFormula;
 import org.sonar.api.resources.File;
 import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
 import org.sonar.api.resources.Scopes;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.source.Symbol;
 import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.api.utils.SonarException;
 import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.BatchComponent;
 import org.sonar.batch.index.BatchComponentCache;
-import org.sonar.batch.index.DefaultIndex;
 import org.sonar.batch.issue.ModuleIssues;
 import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.batch.protocol.output.BatchReport.Range;
 import org.sonar.batch.protocol.output.BatchReportWriter;
 import org.sonar.batch.report.BatchReportUtils;
 import org.sonar.batch.report.ReportPublisher;
+import org.sonar.batch.scan.measure.MeasureCache;
 import org.sonar.batch.sensor.coverage.CoverageExclusions;
 import org.sonar.batch.source.DefaultSymbol;
 import org.sonar.core.component.ComponentKeys;
+import org.sonar.core.issue.DefaultIssue;
 
 public class DefaultSensorStorage implements SensorStorage {
 
+  private static final Logger LOG = LoggerFactory.getLogger(DefaultSensorStorage.class);
+
+  private static final List<Metric> INTERNAL_METRICS = Arrays.<Metric>asList(
+    // Computed by CpdSensor
+    CoreMetrics.DUPLICATED_FILES,
+    CoreMetrics.DUPLICATED_LINES,
+    CoreMetrics.DUPLICATED_BLOCKS,
+    // Computed by LinesSensor
+    CoreMetrics.LINES);
+
+  private static final List<String> DEPRECATED_METRICS_KEYS = Arrays.<String>asList(
+    CoreMetrics.DEPENDENCY_MATRIX_KEY,
+    CoreMetrics.DIRECTORY_CYCLES_KEY,
+    CoreMetrics.DIRECTORY_EDGES_WEIGHT_KEY,
+    CoreMetrics.DIRECTORY_FEEDBACK_EDGES_KEY,
+    CoreMetrics.DIRECTORY_TANGLE_INDEX_KEY,
+    CoreMetrics.DIRECTORY_TANGLES_KEY,
+    CoreMetrics.FILE_CYCLES_KEY,
+    CoreMetrics.FILE_EDGES_WEIGHT_KEY,
+    CoreMetrics.FILE_FEEDBACK_EDGES_KEY,
+    CoreMetrics.FILE_TANGLE_INDEX_KEY,
+    CoreMetrics.FILE_TANGLES_KEY,
+    CoreMetrics.DUPLICATIONS_DATA_KEY);
+
   private final MetricFinder metricFinder;
   private final Project project;
   private final ModuleIssues moduleIssues;
-  private final DefaultIndex sonarIndex;
   private final CoverageExclusions coverageExclusions;
   private final DuplicationCache duplicationCache;
   private final BatchComponentCache resourceCache;
   private final ReportPublisher reportPublisher;
+  private final MeasureCache measureCache;
 
   public DefaultSensorStorage(MetricFinder metricFinder, Project project, ModuleIssues moduleIssues,
-    Settings settings, FileSystem fs, ActiveRules activeRules, DuplicationCache duplicationCache, DefaultIndex sonarIndex,
-    CoverageExclusions coverageExclusions, BatchComponentCache resourceCache, ReportPublisher reportPublisher) {
+    Settings settings, FileSystem fs, ActiveRules activeRules, DuplicationCache duplicationCache,
+    CoverageExclusions coverageExclusions, BatchComponentCache resourceCache, ReportPublisher reportPublisher, MeasureCache measureCache) {
     this.metricFinder = metricFinder;
     this.project = project;
     this.moduleIssues = moduleIssues;
-    this.sonarIndex = sonarIndex;
     this.coverageExclusions = coverageExclusions;
     this.duplicationCache = duplicationCache;
     this.resourceCache = resourceCache;
     this.reportPublisher = reportPublisher;
+    this.measureCache = measureCache;
   }
 
   private Metric findMetricOrFail(String metricKey) {
@@ -116,11 +146,31 @@ public class DefaultSensorStorage implements SensorStorage {
       }
       File sonarFile = getFile(inputFile);
       if (coverageExclusions.accept(sonarFile, measureToSave)) {
-        sonarIndex.addMeasure(sonarFile, measureToSave);
+        saveMeasure(sonarFile, measureToSave);
       }
     } else {
-      sonarIndex.addMeasure(project, measureToSave);
+      saveMeasure(project, measureToSave);
+    }
+  }
+
+  public org.sonar.api.measures.Measure saveMeasure(Resource resource, org.sonar.api.measures.Measure measure) {
+    if (DEPRECATED_METRICS_KEYS.contains(measure.getMetricKey())) {
+      // Ignore deprecated metrics
+      return null;
+    }
+    org.sonar.api.batch.measure.Metric metric = metricFinder.findByKey(measure.getMetricKey());
+    if (metric == null) {
+      throw new SonarException("Unknown metric: " + measure.getMetricKey());
+    }
+    if (!measure.isFromCore() && INTERNAL_METRICS.contains(metric)) {
+      LOG.debug("Metric " + metric.key() + " is an internal metric computed by SonarQube. Provided value is ignored.");
+      return measure;
+    }
+    if (measureCache.contains(resource, measure)) {
+      throw new SonarException("Can not add the same measure twice on " + resource + ": " + measure);
     }
+    measureCache.put(resource, measure);
+    return measure;
   }
 
   private void setValueAccordingToMetricType(Measure<?> measure, org.sonar.api.measures.Metric<?> m, org.sonar.api.measures.Measure measureToSave) {
@@ -154,7 +204,7 @@ public class DefaultSensorStorage implements SensorStorage {
   @Override
   public void store(Issue issue) {
     String componentKey;
-    InputPath inputPath = issue.inputPath();
+    InputPath inputPath = issue.locations().get(0).inputPath();
     if (inputPath != null) {
       componentKey = ComponentKeys.createEffectiveKey(project.getKey(), inputPath);
     } else {
@@ -164,15 +214,16 @@ public class DefaultSensorStorage implements SensorStorage {
   }
 
   public static DefaultIssue toDefaultIssue(String projectKey, String componentKey, Issue issue) {
-    Severity overridenSeverity = issue.overridenSeverity();
+    Severity overriddenSeverity = issue.overriddenSeverity();
+    TextRange textRange = issue.locations().get(0).textRange();
     return new org.sonar.core.issue.DefaultIssueBuilder()
       .componentKey(componentKey)
       .projectKey(projectKey)
       .ruleKey(RuleKey.of(issue.ruleKey().repository(), issue.ruleKey().rule()))
       .effortToFix(issue.effortToFix())
-      .line(issue.line())
-      .message(issue.message())
-      .severity(overridenSeverity != null ? overridenSeverity.name() : null)
+      .line(textRange != null ? textRange.start().line() : null)
+      .message(issue.locations().get(0).message())
+      .severity(overriddenSeverity != null ? overriddenSeverity.name() : null)
       .build();
   }
 
@@ -202,7 +253,7 @@ public class DefaultSensorStorage implements SensorStorage {
     writer.writeComponentSymbols(resourceCache.get(inputFile).batchId(),
       Iterables.transform(referencesBySymbol.entrySet(), new Function<Map.Entry<Symbol, Set<TextRange>>, BatchReport.Symbol>() {
         private BatchReport.Symbol.Builder builder = BatchReport.Symbol.newBuilder();
-        private Range.Builder rangeBuilder = Range.newBuilder();
+        private BatchReport.TextRange.Builder rangeBuilder = BatchReport.TextRange.newBuilder();
 
         @Override
         public BatchReport.Symbol apply(Map.Entry<Symbol, Set<TextRange>> input) {
@@ -235,21 +286,21 @@ public class DefaultSensorStorage implements SensorStorage {
     }
     CoverageType type = defaultCoverage.type();
     if (defaultCoverage.linesToCover() > 0) {
-      sonarIndex.addMeasure(file, new org.sonar.api.measures.Measure(type.linesToCover(), (double) defaultCoverage.linesToCover()));
-      sonarIndex.addMeasure(file, new org.sonar.api.measures.Measure(type.uncoveredLines(), (double) (defaultCoverage.linesToCover() - defaultCoverage.coveredLines())));
-      sonarIndex.addMeasure(file, new org.sonar.api.measures.Measure(type.lineHitsData()).setData(KeyValueFormat.format(defaultCoverage.hitsByLine())));
+      saveMeasure(file, new org.sonar.api.measures.Measure(type.linesToCover(), (double) defaultCoverage.linesToCover()));
+      saveMeasure(file, new org.sonar.api.measures.Measure(type.uncoveredLines(), (double) (defaultCoverage.linesToCover() - defaultCoverage.coveredLines())));
+      saveMeasure(file, new org.sonar.api.measures.Measure(type.lineHitsData()).setData(KeyValueFormat.format(defaultCoverage.hitsByLine())));
     }
     if (defaultCoverage.conditions() > 0) {
-      sonarIndex.addMeasure(file, new org.sonar.api.measures.Measure(type.conditionsToCover(), (double) defaultCoverage.conditions()));
-      sonarIndex.addMeasure(file, new org.sonar.api.measures.Measure(type.uncoveredConditions(), (double) (defaultCoverage.conditions() - defaultCoverage.coveredConditions())));
-      sonarIndex.addMeasure(file, new org.sonar.api.measures.Measure(type.coveredConditionsByLine()).setData(KeyValueFormat.format(defaultCoverage.coveredConditionsByLine())));
-      sonarIndex.addMeasure(file, new org.sonar.api.measures.Measure(type.conditionsByLine()).setData(KeyValueFormat.format(defaultCoverage.conditionsByLine())));
+      saveMeasure(file, new org.sonar.api.measures.Measure(type.conditionsToCover(), (double) defaultCoverage.conditions()));
+      saveMeasure(file, new org.sonar.api.measures.Measure(type.uncoveredConditions(), (double) (defaultCoverage.conditions() - defaultCoverage.coveredConditions())));
+      saveMeasure(file, new org.sonar.api.measures.Measure(type.coveredConditionsByLine()).setData(KeyValueFormat.format(defaultCoverage.coveredConditionsByLine())));
+      saveMeasure(file, new org.sonar.api.measures.Measure(type.conditionsByLine()).setData(KeyValueFormat.format(defaultCoverage.conditionsByLine())));
     }
   }
 
   private static class BuildSyntaxHighlighting implements Function<SyntaxHighlightingRule, BatchReport.SyntaxHighlighting> {
     private BatchReport.SyntaxHighlighting.Builder builder = BatchReport.SyntaxHighlighting.newBuilder();
-    private Range.Builder rangeBuilder = Range.newBuilder();
+    private BatchReport.TextRange.Builder rangeBuilder = BatchReport.TextRange.newBuilder();
 
     @Override
     public BatchReport.SyntaxHighlighting apply(@Nonnull SyntaxHighlightingRule input) {
index 29cdc0e6f24b42889c589e9edb0002c9f3a3debd..d98cd10efeb6ea247fc2a0a958cfaead4158c2f2 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.batch.index;
 
+import java.io.IOException;
 import org.apache.commons.io.FileUtils;
 import org.junit.Before;
 import org.junit.Test;
@@ -37,10 +38,8 @@ import org.sonar.api.resources.Resource;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.batch.DefaultProjectTree;
-import org.sonar.batch.issue.ModuleIssues;
 import org.sonar.batch.scan.measure.MeasureCache;
-
-import java.io.IOException;
+import org.sonar.batch.sensor.DefaultSensorStorage;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -85,7 +84,7 @@ public class DefaultIndexTest {
     rule = Rule.create("repoKey", "ruleKey", "Rule");
     rule.setId(1);
     rulesProfile.activateRule(rule, null);
-    index.setCurrentProject(project, mock(ModuleIssues.class));
+    index.setCurrentProject(project, mock(DefaultSensorStorage.class));
     index.doStart(project);
   }
 
index 7f50a767efe8670e244642c6c4e38256a5b2bb9a..5df842973701423c48310ed0d6791567593f745f 100644 (file)
@@ -22,10 +22,10 @@ package org.sonar.batch.issue;
 import java.util.Arrays;
 import java.util.List;
 import org.junit.Test;
+import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.issue.Issue;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.api.resources.Project;
 import org.sonar.batch.index.BatchComponent;
+import org.sonar.core.issue.DefaultIssue;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -33,9 +33,7 @@ import static org.mockito.Mockito.when;
 
 public class DefaultIssuableTest {
 
-  ModuleIssues moduleIssues = mock(ModuleIssues.class);
   IssueCache cache = mock(IssueCache.class);
-  Project project = mock(Project.class);
   BatchComponent component = mock(BatchComponent.class);
 
   @Test
@@ -45,7 +43,7 @@ public class DefaultIssuableTest {
     DefaultIssue unresolved = new DefaultIssue();
     when(cache.byComponent("struts:org.apache.Action")).thenReturn(Arrays.asList(resolved, unresolved));
 
-    DefaultIssuable perspective = new DefaultIssuable(component, project, moduleIssues, cache);
+    DefaultIssuable perspective = new DefaultIssuable(component, cache, mock(SensorContext.class));
 
     List<Issue> issues = perspective.issues();
     assertThat(issues).containsOnly(unresolved);
@@ -58,7 +56,7 @@ public class DefaultIssuableTest {
     DefaultIssue unresolved = new DefaultIssue();
     when(cache.byComponent("struts:org.apache.Action")).thenReturn(Arrays.asList(resolved, unresolved));
 
-    DefaultIssuable perspective = new DefaultIssuable(component, project, moduleIssues, cache);
+    DefaultIssuable perspective = new DefaultIssuable(component, cache, mock(SensorContext.class));
 
     List<Issue> issues = perspective.resolvedIssues();
     assertThat(issues).containsOnly(resolved);
index c124a40fc496769db549862784b607a3350c2a01..ddabedba240914a6fb07d77def49b675c1693c51 100644 (file)
@@ -26,6 +26,7 @@ import org.sonar.api.resources.File;
 import org.sonar.api.resources.Project;
 import org.sonar.batch.DefaultProjectTree;
 import org.sonar.batch.index.BatchComponent;
+import org.sonar.batch.sensor.DefaultSensorContext;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -38,7 +39,7 @@ public class IssuableFactoryTest {
 
   @Test
   public void file_should_be_issuable() {
-    IssuableFactory factory = new IssuableFactory(moduleIssues, cache, projectTree);
+    IssuableFactory factory = new IssuableFactory(cache, mock(DefaultSensorContext.class));
     BatchComponent component = new BatchComponent(1, File.create("foo/bar.c").setEffectiveKey("foo/bar.c"), null);
     Issuable issuable = factory.loadPerspective(Issuable.class, component);
 
@@ -48,7 +49,7 @@ public class IssuableFactoryTest {
 
   @Test
   public void project_should_be_issuable() {
-    IssuableFactory factory = new IssuableFactory(moduleIssues, cache, projectTree);
+    IssuableFactory factory = new IssuableFactory(cache, mock(DefaultSensorContext.class));
     BatchComponent component = new BatchComponent(1, new Project("Foo").setEffectiveKey("foo"), null);
     Issuable issuable = factory.loadPerspective(Issuable.class, component);
 
index 356b9f9e43633ecd297c093c3c7b5b9e1da79f76..3199c7c8f03f4e7812f1f6758b59a0d8dd23035e 100644 (file)
@@ -30,19 +30,14 @@ import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
 import org.sonar.api.batch.rule.internal.RulesBuilder;
-import org.sonar.api.resources.File;
 import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
-import org.sonar.api.rules.RulePriority;
-import org.sonar.api.rules.Violation;
 import org.sonar.api.utils.MessageException;
 import org.sonar.core.issue.DefaultIssue;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
@@ -197,36 +192,6 @@ public class ModuleIssuesTest {
     assertThat(argument.getValue().message()).isEqualTo("Avoid Cycle");
   }
 
-  @Test
-  public void add_deprecated_violation() {
-    ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME);
-    activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate();
-    initModuleIssues();
-
-    org.sonar.api.rules.Rule rule = org.sonar.api.rules.Rule.create("squid", "AvoidCycle", "Avoid Cycle");
-    Resource resource = File.create("org/struts/Action.java").setEffectiveKey("struts:src/org/struts/Action.java");
-    Violation violation = new Violation(rule, resource);
-    violation.setLineId(42);
-    violation.setSeverity(RulePriority.CRITICAL);
-    violation.setMessage("the message");
-
-    when(filters.accept(any(DefaultIssue.class))).thenReturn(true);
-
-    boolean added = moduleIssues.initAndAddViolation(violation);
-    assertThat(added).isTrue();
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(cache).put(argument.capture());
-    DefaultIssue issue = argument.getValue();
-    assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
-    assertThat(issue.line()).isEqualTo(42);
-    assertThat(issue.message()).isEqualTo("the message");
-    assertThat(issue.key()).isNotEmpty();
-    assertThat(issue.ruleKey().toString()).isEqualTo("squid:AvoidCycle");
-    assertThat(issue.componentKey()).isEqualTo("struts:src/org/struts/Action.java");
-    assertThat(issue.projectKey()).isEqualTo("org.apache:struts-core");
-  }
-
   @Test
   public void filter_issue() {
     ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME);
index e740ea47c009a95ef259774537fc8213197c8af1..79de3e1afa2af18465007e5a0fa479fce48928a8 100644 (file)
@@ -22,20 +22,21 @@ package org.sonar.batch.mediumtest.coverage;
 import com.google.common.collect.ImmutableMap;
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
+import java.util.Map;
 import org.apache.commons.io.FileUtils;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.batch.mediumtest.BatchMediumTester;
 import org.sonar.batch.mediumtest.TaskResult;
 import org.sonar.xoo.XooPlugin;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
 
 public class CoverageMediumTest {
 
@@ -89,25 +90,12 @@ public class CoverageMediumTest {
     assertThat(result.coverageFor(file, 2).getItCoveredConditions()).isEqualTo(0);
     assertThat(result.coverageFor(file, 2).getOverallCoveredConditions()).isEqualTo(0);
 
-    assertThat(result.allMeasures()).contains(new DefaultMeasure<Integer>()
-      .forMetric(CoreMetrics.LINES_TO_COVER)
-      .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo"))
-      .withValue(2));
-
-    assertThat(result.allMeasures()).contains(new DefaultMeasure<Integer>()
-      .forMetric(CoreMetrics.UNCOVERED_LINES)
-      .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo"))
-      .withValue(0));
-
-    assertThat(result.allMeasures()).contains(new DefaultMeasure<Integer>()
-      .forMetric(CoreMetrics.CONDITIONS_TO_COVER)
-      .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo"))
-      .withValue(2));
-
-    assertThat(result.allMeasures()).contains(new DefaultMeasure<String>()
-      .forMetric(CoreMetrics.COVERED_CONDITIONS_BY_LINE)
-      .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo"))
-      .withValue("2=1"));
+    Map<String, List<org.sonar.batch.protocol.output.BatchReport.Measure>> allMeasures = result.allMeasures();
+    assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue", "stringValue")
+      .contains(tuple(CoreMetrics.LINES_TO_COVER_KEY, 2, ""),
+        tuple(CoreMetrics.UNCOVERED_LINES_KEY, 0, ""),
+        tuple(CoreMetrics.CONDITIONS_TO_COVER_KEY, 2, ""),
+        tuple(CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY, 0, "2=1"));
   }
 
   @Test
@@ -138,8 +126,11 @@ public class CoverageMediumTest {
     InputFile file = result.inputFile("src/sample.xoo");
     assertThat(result.coverageFor(file, 2)).isNull();
 
-    assertThat(result.allMeasures()).extracting("metric.key").doesNotContain(CoreMetrics.LINES_TO_COVER, CoreMetrics.UNCOVERED_LINES, CoreMetrics.CONDITIONS_TO_COVER,
-      CoreMetrics.COVERED_CONDITIONS_BY_LINE);
+    Map<String, List<org.sonar.batch.protocol.output.BatchReport.Measure>> allMeasures = result.allMeasures();
+    assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey")
+      .doesNotContain(CoreMetrics.LINES_TO_COVER_KEY, CoreMetrics.UNCOVERED_LINES_KEY, CoreMetrics.CONDITIONS_TO_COVER_KEY,
+        CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY);
+
   }
 
 }
index 221b6a88af6f4df25de480a9c82fdfb2a0ad0f86..bc4aeb777cb82a3930240fbc3330f38b7bedc33d 100644 (file)
 package org.sonar.batch.mediumtest.cpd;
 
 import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
 import org.apache.commons.io.FileUtils;
+import org.assertj.core.groups.Tuple;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -30,15 +35,12 @@ import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.sensor.duplication.Duplication;
-import org.sonar.api.batch.sensor.measure.Measure;
+import org.sonar.api.measures.CoreMetrics;
 import org.sonar.batch.mediumtest.BatchMediumTester;
 import org.sonar.batch.mediumtest.TaskResult;
+import org.sonar.batch.protocol.output.BatchReport.Measure;
 import org.sonar.xoo.XooPlugin;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
 
@@ -102,8 +104,11 @@ public class CpdMediumTest {
 
     assertThat(result.inputFiles()).hasSize(2);
 
-    assertThat(result.measures("com.foo.project:src/sample1.xoo")).extracting("metric.key", "value").contains(tuple("duplicated_blocks", 1), tuple("duplicated_files", 1),
-      tuple("duplicated_lines", 17));
+    Map<String, List<org.sonar.batch.protocol.output.BatchReport.Measure>> allMeasures = result.allMeasures();
+    assertThat(allMeasures.get("com.foo.project:src/sample1.xoo")).extracting("metricKey", "intValue")
+      .contains(tuple("duplicated_blocks", 1),
+        tuple("duplicated_files", 1),
+        tuple("duplicated_lines", 17));
 
     InputFile inputFile1 = result.inputFile("src/sample1.xoo");
     InputFile inputFile2 = result.inputFile("src/sample2.xoo");
@@ -154,13 +159,17 @@ public class CpdMediumTest {
         .build())
       .start();
 
-    Measure duplicatedBlocks = null;
-    for (Measure m : result.allMeasures()) {
-      if (m.metric().key().equals("duplicated_blocks")) {
-        duplicatedBlocks = m;
-      }
-    }
-    assertThat(duplicatedBlocks.value()).isEqualTo(blockCount);
+    Map<String, List<Measure>> allMeasures = result.allMeasures();
+
+    assertThat(allMeasures.get("com.foo.project")).extracting("metricKey", "intValue", "doubleValue", "stringValue").containsOnly(
+      Tuple.tuple(CoreMetrics.QUALITY_PROFILES_KEY, 0, 0.0,
+        "[{\"key\":\"Sonar Way\",\"language\":\"xoo\",\"name\":\"Sonar Way\",\"rulesUpdatedAt\":\"2009-02-13T23:31:31+0000\"}]"));
+
+    assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue").containsOnly(
+      Tuple.tuple(CoreMetrics.LINES_KEY, blockCount * 2 + 1),
+      Tuple.tuple(CoreMetrics.DUPLICATED_FILES_KEY, 1),
+      Tuple.tuple(CoreMetrics.DUPLICATED_BLOCKS_KEY, blockCount),
+      Tuple.tuple(CoreMetrics.DUPLICATED_LINES_KEY, blockCount));
 
     List<Duplication> duplicationGroups = result.duplicationsFor(result.inputFile("src/sample.xoo"));
     assertThat(duplicationGroups).hasSize(1);
@@ -188,8 +197,11 @@ public class CpdMediumTest {
         .build())
       .start();
 
-    assertThat(result.measures("com.foo.project:src/sample.xoo")).extracting("metric.key", "value").contains(tuple("duplicated_blocks", 2), tuple("duplicated_files", 1),
-      tuple("duplicated_lines", 4));
+    Map<String, List<org.sonar.batch.protocol.output.BatchReport.Measure>> allMeasures = result.allMeasures();
+    assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue")
+      .contains(tuple("duplicated_blocks", 2),
+        tuple("duplicated_files", 1),
+        tuple("duplicated_lines", 4));
 
     InputFile inputFile = result.inputFile("src/sample.xoo");
     // One clone group
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/MultilineIssuesMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/MultilineIssuesMediumTest.java
new file mode 100644 (file)
index 0000000..749260c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.mediumtest.issues;
+
+import java.io.File;
+import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.batch.mediumtest.BatchMediumTester;
+import org.sonar.batch.mediumtest.TaskResult;
+import org.sonar.batch.protocol.input.ActiveRule;
+import org.sonar.xoo.XooPlugin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MultilineIssuesMediumTest {
+
+  @org.junit.Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  public BatchMediumTester tester = BatchMediumTester.builder()
+    .registerPlugin("xoo", new XooPlugin())
+    .addDefaultQProfile("xoo", "Sonar Way")
+    .activateRule(new ActiveRule("xoo", "MultilineIssue", null, "Multinile Issue", "MAJOR", null, "xoo"))
+    .build();
+
+  @Before
+  public void prepare() {
+    tester.start();
+  }
+
+  @After
+  public void stop() {
+    tester.stop();
+  }
+
+  @Test
+  public void testIssueRange() throws Exception {
+    File projectDir = new File(MultilineIssuesMediumTest.class.getResource("/mediumtest/xoo/sample-multiline").toURI());
+    File tmpDir = temp.newFolder();
+    FileUtils.copyDirectory(projectDir, tmpDir);
+
+    TaskResult result = tester
+      .newScanTask(new File(tmpDir, "sonar-project.properties"))
+      .start();
+
+    assertThat(result.issues()).hasSize(1);
+
+  }
+
+}
index ae97beaec18eeab0ec774e4f3e3b09cf77235679..f25b28fedc94f66a4517e80c0b2853ab22560645 100644 (file)
@@ -22,16 +22,18 @@ package org.sonar.batch.mediumtest.measures;
 import com.google.common.collect.ImmutableMap;
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
+import java.util.Map;
 import org.apache.commons.io.FileUtils;
+import org.assertj.core.groups.Tuple;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.batch.mediumtest.BatchMediumTester;
 import org.sonar.batch.mediumtest.TaskResult;
+import org.sonar.batch.protocol.output.BatchReport.Measure;
 import org.sonar.xoo.XooPlugin;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -57,19 +59,6 @@ public class MeasuresMediumTest {
     tester.stop();
   }
 
-  @Test
-  public void computeMeasuresOnSampleProject() throws Exception {
-    File projectDir = new File(MeasuresMediumTest.class.getResource("/mediumtest/xoo/sample").toURI());
-    File tmpDir = temp.newFolder();
-    FileUtils.copyDirectory(projectDir, tmpDir);
-    
-    TaskResult result = tester
-      .newScanTask(new File(tmpDir, "sonar-project.properties"))
-      .start();
-
-    assertThat(result.allMeasures()).hasSize(13);
-  }
-
   @Test
   public void computeMeasuresOnTempProject() throws IOException {
 
@@ -91,16 +80,18 @@ public class MeasuresMediumTest {
         .put("sonar.projectVersion", "1.0-SNAPSHOT")
         .put("sonar.projectDescription", "Description of Foo Project")
         .put("sonar.sources", "src")
+        .put("sonar.cpd.xoo.skip", "true")
         .build())
       .start();
 
-    assertThat(result.allMeasures()).hasSize(2);
+    Map<String, List<Measure>> allMeasures = result.allMeasures();
 
-    assertThat(result.allMeasures()).contains(new DefaultMeasure<Integer>()
-      .forMetric(CoreMetrics.LINES)
-      .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo"))
-      .withValue(2));
+    assertThat(allMeasures.get("com.foo.project")).extracting("metricKey", "intValue", "doubleValue", "stringValue").containsOnly(
+      Tuple.tuple(CoreMetrics.QUALITY_PROFILES_KEY, 0, 0.0,
+        "[{\"key\":\"Sonar Way\",\"language\":\"xoo\",\"name\":\"Sonar Way\",\"rulesUpdatedAt\":\"2009-02-13T23:31:31+0000\"}]"));
 
+    assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue").containsOnly(
+      Tuple.tuple(CoreMetrics.LINES_KEY, 2));
   }
 
   @Test
@@ -129,8 +120,12 @@ public class MeasuresMediumTest {
         .build())
       .start();
 
-    assertThat(result.measures("com.foo.project:src/sample.xoo")).extracting("metric.key", "value").contains(tuple("lines", 3));
-    assertThat(result.measures("com.foo.project:src/sample.other")).extracting("metric.key", "value").contains(tuple("lines", 3), tuple("ncloc", 2));
+    Map<String, List<Measure>> allMeasures = result.allMeasures();
+
+    assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue")
+      .contains(tuple("lines", 3));
+    assertThat(allMeasures.get("com.foo.project:src/sample.other")).extracting("metricKey", "intValue")
+      .contains(tuple("lines", 3), tuple("ncloc", 2));
   }
 
 }
index a9aae88e06c449895561417ba472cb2c1849fa67..5f094972269d8ce0b29cd1c587df109a1703da6b 100644 (file)
@@ -20,6 +20,8 @@
 package org.sonar.batch.mediumtest.symbol;
 
 import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
 import org.apache.commons.io.FileUtils;
 import org.junit.After;
 import org.junit.Before;
@@ -28,12 +30,9 @@ import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.batch.mediumtest.BatchMediumTester;
 import org.sonar.batch.mediumtest.TaskResult;
-import org.sonar.batch.protocol.output.BatchReport.Range;
+import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.xoo.XooPlugin;
 
-import java.io.File;
-import java.io.IOException;
-
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class SymbolMediumTest {
@@ -82,7 +81,7 @@ public class SymbolMediumTest {
       .start();
 
     InputFile file = result.inputFile("src/sample.xoo");
-    assertThat(result.symbolReferencesFor(file, 1, 7)).containsOnly(Range.newBuilder().setStartLine(3).setStartOffset(8).setEndLine(3).setEndOffset(11).build());
+    assertThat(result.symbolReferencesFor(file, 1, 7)).containsOnly(BatchReport.TextRange.newBuilder().setStartLine(3).setStartOffset(8).setEndLine(3).setEndOffset(11).build());
   }
 
 }
index df55eddc1f799217bb7e6f1354e701eb27dd642b..016dc1c3c463d354799e89f10f1f938aab4450de 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.batch.scan.filesystem;
 
+import java.io.File;
+import java.io.IOException;
 import org.apache.commons.io.FileUtils;
 import org.junit.Before;
 import org.junit.Rule;
@@ -30,6 +32,7 @@ import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultFileSystem;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.resources.AbstractLanguage;
+import org.sonar.api.resources.Directory;
 import org.sonar.api.resources.Java;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.resources.Project;
@@ -38,9 +41,6 @@ import org.sonar.api.resources.Resource;
 import org.sonar.batch.index.BatchComponent;
 import org.sonar.batch.index.BatchComponentCache;
 
-import java.io.File;
-import java.io.IOException;
-
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.argThat;
 import static org.mockito.Mockito.mock;
@@ -101,7 +101,8 @@ public class ComponentIndexerTest {
 
   private ComponentIndexer createIndexer(Languages languages) {
     BatchComponentCache resourceCache = mock(BatchComponentCache.class);
-    when(resourceCache.get(any(Resource.class))).thenReturn(new BatchComponent(1, org.sonar.api.resources.File.create("foo.php"), null));
+    when(resourceCache.get(any(Resource.class)))
+      .thenReturn(new BatchComponent(2, org.sonar.api.resources.File.create("foo.php"), new BatchComponent(1, Directory.create("src"), null)));
     return new ComponentIndexer(project, languages, sonarIndex, resourceCache);
   }
 
index 69b176538a1bc8510b096521f0e40f11873746bb..aa2e32f96e68051610875fab56d29261b84a36e2 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.batch.sensor;
 
+import java.io.StringReader;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -30,11 +31,13 @@ import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultFileSystem;
 import org.sonar.api.batch.fs.internal.DefaultInputDir;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.FileMetadata;
 import org.sonar.api.batch.measure.MetricFinder;
 import org.sonar.api.batch.rule.ActiveRules;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
 import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
+import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation;
 import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.config.Settings;
 import org.sonar.api.measures.CoreMetrics;
@@ -45,9 +48,9 @@ import org.sonar.api.resources.Resource;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.BatchComponentCache;
-import org.sonar.batch.index.DefaultIndex;
 import org.sonar.batch.issue.ModuleIssues;
 import org.sonar.batch.report.ReportPublisher;
+import org.sonar.batch.scan.measure.MeasureCache;
 import org.sonar.batch.sensor.coverage.CoverageExclusions;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -71,7 +74,7 @@ public class DefaultSensorStorageTest {
   private Settings settings;
   private ModuleIssues moduleIssues;
   private Project project;
-  private DefaultIndex sonarIndex;
+  private MeasureCache measureCache;
 
   private BatchComponentCache resourceCache;
 
@@ -85,12 +88,12 @@ public class DefaultSensorStorageTest {
     settings = new Settings();
     moduleIssues = mock(ModuleIssues.class);
     project = new Project("myProject");
-    sonarIndex = mock(DefaultIndex.class);
+    measureCache = mock(MeasureCache.class);
     CoverageExclusions coverageExclusions = mock(CoverageExclusions.class);
     when(coverageExclusions.accept(any(Resource.class), any(Measure.class))).thenReturn(true);
     resourceCache = new BatchComponentCache();
     sensorStorage = new DefaultSensorStorage(metricFinder, project,
-      moduleIssues, settings, fs, activeRules, mock(DuplicationCache.class), sonarIndex, coverageExclusions, resourceCache, mock(ReportPublisher.class));
+      moduleIssues, settings, fs, activeRules, mock(DuplicationCache.class), coverageExclusions, resourceCache, mock(ReportPublisher.class), measureCache);
   }
 
   @Test
@@ -113,7 +116,7 @@ public class DefaultSensorStorageTest {
     ArgumentCaptor<org.sonar.api.measures.Measure> argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class);
     Resource sonarFile = File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
     resourceCache.add(sonarFile, null).setInputPath(file);
-    when(sonarIndex.addMeasure(eq(sonarFile), argumentCaptor.capture())).thenReturn(null);
+    when(measureCache.put(eq(sonarFile), argumentCaptor.capture())).thenReturn(null);
     sensorStorage.store(new DefaultMeasure()
       .onFile(file)
       .forMetric(CoreMetrics.NCLOC)
@@ -128,7 +131,7 @@ public class DefaultSensorStorageTest {
   public void shouldSaveProjectMeasureToSensorContext() {
 
     ArgumentCaptor<org.sonar.api.measures.Measure> argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class);
-    when(sonarIndex.addMeasure(eq(project), argumentCaptor.capture())).thenReturn(null);
+    when(measureCache.put(eq(project), argumentCaptor.capture())).thenReturn(null);
 
     sensorStorage.store(new DefaultMeasure()
       .onProject()
@@ -142,15 +145,13 @@ public class DefaultSensorStorageTest {
 
   @Test
   public void shouldAddIssueOnFile() {
-    InputFile file = new DefaultInputFile("foo", "src/Foo.php").setLines(4);
+    InputFile file = new DefaultInputFile("foo", "src/Foo.php").initMetadata(new FileMetadata().readMetadata(new StringReader("Foo\nBar\nBiz\n")));
 
     ArgumentCaptor<org.sonar.core.issue.DefaultIssue> argumentCaptor = ArgumentCaptor.forClass(org.sonar.core.issue.DefaultIssue.class);
 
     sensorStorage.store(new DefaultIssue()
-      .onFile(file)
+      .addLocation(new DefaultIssueLocation().onFile(file).at(file.selectLine(3)).message("Foo"))
       .forRule(RuleKey.of("foo", "bar"))
-      .message("Foo")
-      .atLine(3)
       .effortToFix(10.0));
 
     verify(moduleIssues).initAndAddIssue(argumentCaptor.capture());
@@ -170,9 +171,8 @@ public class DefaultSensorStorageTest {
     ArgumentCaptor<org.sonar.core.issue.DefaultIssue> argumentCaptor = ArgumentCaptor.forClass(org.sonar.core.issue.DefaultIssue.class);
 
     sensorStorage.store(new DefaultIssue()
-      .onDir(dir)
+      .addLocation(new DefaultIssueLocation().onDir(dir).message("Foo"))
       .forRule(RuleKey.of("foo", "bar"))
-      .message("Foo")
       .effortToFix(10.0));
 
     verify(moduleIssues).initAndAddIssue(argumentCaptor.capture());
@@ -190,9 +190,8 @@ public class DefaultSensorStorageTest {
     ArgumentCaptor<org.sonar.core.issue.DefaultIssue> argumentCaptor = ArgumentCaptor.forClass(org.sonar.core.issue.DefaultIssue.class);
 
     sensorStorage.store(new DefaultIssue()
-      .onProject()
+      .addLocation(new DefaultIssueLocation().onProject().message("Foo"))
       .forRule(RuleKey.of("foo", "bar"))
-      .message("Foo")
       .overrideSeverity(Severity.BLOCKER)
       .effortToFix(10.0));
 
diff --git a/sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/sonar-project.properties b/sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/sonar-project.properties
new file mode 100644 (file)
index 0000000..0c8e5dc
--- /dev/null
@@ -0,0 +1,4 @@
+sonar.projectKey=sample-multiline
+sonar.projectName=Sample Multiline
+sonar.projectVersion=0.1-SNAPSHOT
+sonar.sources=xources
diff --git a/sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/xources/hello/HelloJava.xoo b/sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/xources/hello/HelloJava.xoo
new file mode 100644 (file)
index 0000000..0b815e0
--- /dev/null
@@ -0,0 +1,8 @@
+package hello;
+
+public class HelloJava {
+
+  public static void main(String[] args) {
+    {xoo-start-issue:1:1}System.out.println("Hello"){xoo-end-issue:1:1};
+  }
+}
\ No newline at end of file
diff --git a/sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/xources/hello/HelloJava.xoo.measures b/sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/xources/hello/HelloJava.xoo.measures
new file mode 100644 (file)
index 0000000..9eaf8ba
--- /dev/null
@@ -0,0 +1,2 @@
+ncloc:3
+complexity:1
index 5990eb41146778363e284999fd45f3ad0b4dc7c3..caa6f3d86630423b70d659c41e3905326da30aeb 100644 (file)
@@ -23,7 +23,9 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import java.util.Map;
 import javax.annotation.Nullable;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
 import org.sonar.api.issue.Issuable;
+import org.sonar.api.issue.Issuable.IssueBuilder;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.internal.Uuids;
@@ -73,6 +75,25 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder {
     return this;
   }
 
+  @Override
+  public NewIssueLocation newLocation() {
+    throw unsupported();
+  }
+
+  @Override
+  public IssueBuilder addExecutionFlow(NewIssueLocation... flow) {
+    throw unsupported();
+  }
+
+  @Override
+  public IssueBuilder addLocation(NewIssueLocation location) {
+    throw unsupported();
+  }
+
+  private static UnsupportedOperationException unsupported() {
+    return new UnsupportedOperationException("Not supported for manual issues");
+  }
+
   @Override
   public DefaultIssueBuilder severity(@Nullable String severity) {
     this.severity = severity;
index d98180bf41709edde0827c0af5120193d6640c0b..fb1f25bdcdf3940ef4c347f5f9a5ea3003f5c44f 100644 (file)
  */
 package org.sonar.api.batch.fs;
 
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-
-import javax.annotation.CheckForNull;
-
 import java.io.File;
 import java.nio.file.Path;
+import javax.annotation.CheckForNull;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
 
 /**
  * This layer over {@link java.io.File} adds information for code analyzers.
@@ -126,10 +124,22 @@ public interface InputFile extends InputPath {
 
   /**
    * Return a {@link TextRange} in the given file.
-   * @param start
-   * @param end
+   * @param start start pointer
+   * @param end end pointer
    * @throw {@link IllegalArgumentException} if start or stop pointers are not valid for the given file.
    */
   TextRange newRange(TextPointer start, TextPointer end);
 
+  /**
+   * Return a {@link TextRange} in the given file.
+   * @throw {@link IllegalArgumentException} if start or stop positions are not valid for the given file.
+   */
+  TextRange newRange(int startLine, int startLineOffset, int endLine, int endLineOffset);
+
+  /**
+   * Return a {@link TextRange} in the given file that select the full line.
+   * @param line Start at 1.
+   * @throw {@link IllegalArgumentException} if line is not valid for the given file.
+   */
+  TextRange selectLine(int line);
 }
index df42847def64f9a2e814be69ecafbf479fa01f93..3c0cb4a243b409afbcc791cff67b1dae3c623036 100644 (file)
@@ -232,8 +232,25 @@ public class DefaultInputFile implements InputFile, org.sonar.api.resources.Inpu
     return newRangeValidPointers(start, end);
   }
 
+  @Override
+  public TextRange newRange(int startLine, int startLineOffset, int endLine, int endLineOffset) {
+    return newRangeValidPointers(newPointer(startLine, startLineOffset), newPointer(endLine, endLineOffset));
+  }
+
+  @Override
+  public TextRange selectLine(int line) {
+    TextPointer startPointer = newPointer(line, 0);
+    TextPointer endPointer = newPointer(line, lineLength(line));
+    return newRangeValidPointers(startPointer, endPointer);
+  }
+
+  public void validate(TextRange range) {
+    checkValid(range.start(), "start pointer");
+    checkValid(range.end(), "end pointer");
+  }
+
   private static TextRange newRangeValidPointers(TextPointer start, TextPointer end) {
-    Preconditions.checkArgument(start.compareTo(end) < 0, "Start pointer %s should be before end pointer %s", start, end);
+    Preconditions.checkArgument(start.compareTo(end) <= 0, "Start pointer %s should be before end pointer %s", start, end);
     return new DefaultTextRange(start, end);
   }
 
index b264e35ce85c999786f14f217df8f41b146d6141..9d574bb86bd222450f399fbee9757c0f23766a1f 100644 (file)
@@ -154,24 +154,7 @@ public class SensorContextTester implements SensorContext {
   }
 
   public Collection<Issue> allIssues() {
-    List<Issue> result = new ArrayList<>();
-    result.addAll(sensorStorage.projectIssues);
-    for (String key : sensorStorage.issuesByComponent.keySet()) {
-      result.addAll(sensorStorage.issuesByComponent.get(key));
-    }
-    return result;
-  }
-
-  /**
-   * @param componentKey null for project issues
-   */
-  public Collection<Issue> issues(@Nullable String componentKey) {
-    if (componentKey != null) {
-      List<Issue> list = sensorStorage.issuesByComponent.get(componentKey);
-      return list != null ? list : Collections.<Issue>emptyList();
-    } else {
-      return sensorStorage.projectIssues;
-    }
+    return sensorStorage.allIssues;
   }
 
   @CheckForNull
@@ -272,8 +255,7 @@ public class SensorContextTester implements SensorContext {
     private Map<String, Measure> projectMeasuresByMetric = new HashMap<>();
     private Map<String, Map<String, Measure>> measuresByComponentAndMetric = new HashMap<>();
 
-    private Collection<Issue> projectIssues = new ArrayList<>();
-    private Map<String, List<Issue>> issuesByComponent = new HashMap<>();
+    private Collection<Issue> allIssues = new ArrayList<>();
 
     private Map<String, DefaultHighlighting> highlightingByComponent = new HashMap<>();
     private Map<String, Map<CoverageType, DefaultCoverage>> coverageByComponent = new HashMap<>();
@@ -295,15 +277,7 @@ public class SensorContextTester implements SensorContext {
 
     @Override
     public void store(Issue issue) {
-      String key = getKey(issue.inputPath());
-      if (key == null) {
-        projectIssues.add(issue);
-      } else {
-        if (!issuesByComponent.containsKey(key)) {
-          issuesByComponent.put(key, new ArrayList<Issue>());
-        }
-        issuesByComponent.get(key).add(issue);
-      }
+      allIssues.add(issue);
     }
 
     @Override
index 8a446731c3cb06b0b7814030a148e4d3d059fb32..1c519115e297798bbbd16d499d1a78ae30cbd054 100644 (file)
 package org.sonar.api.batch.sensor.issue;
 
 import com.google.common.annotations.Beta;
-import org.sonar.api.batch.fs.InputPath;
+import java.util.List;
+import javax.annotation.CheckForNull;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.api.rule.RuleKey;
 
-import javax.annotation.CheckForNull;
-
 /**
  * Represents an issue detected by a {@link Sensor}.
  *
@@ -35,40 +34,40 @@ import javax.annotation.CheckForNull;
 @Beta
 public interface Issue {
 
+  interface ExecutionFlow {
+    /**
+     * @return Ordered list of locations for the execution flow
+     */
+    List<IssueLocation> locations();
+  }
+
   /**
    * The {@link RuleKey} of this issue.
    */
   RuleKey ruleKey();
 
   /**
-   * The {@link InputPath} this issue belongs to. Returns null if issue is global to the project.
-   */
-  @CheckForNull
-  InputPath inputPath();
-
-  /**
-   * Line of the issue. Null for global issues and issues on directories. Can also be null
-   * for files (issue global to the file).
+   * Effort to fix the issue. Used by technical debt model.
    */
   @CheckForNull
-  Integer line();
+  Double effortToFix();
 
   /**
-   * Effort to fix the issue. Used by technical debt model.
+   * Overridden severity.
    */
   @CheckForNull
-  Double effortToFix();
+  Severity overriddenSeverity();
 
   /**
-   * Message of the issue.
+   * List of locations for this issue. Returns at least one location.
+   * @since 5.2
    */
-  @CheckForNull
-  String message();
+  List<IssueLocation> locations();
 
   /**
-   * Overriden severity.
+   * List of execution flows for this issue. Can be empty.
+   * @since 5.2
    */
-  @CheckForNull
-  Severity overridenSeverity();
+  List<ExecutionFlow> executionFlows();
 
 }
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueLocation.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueLocation.java
new file mode 100644 (file)
index 0000000..fa587f8
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.api.batch.sensor.issue;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.CheckForNull;
+import org.sonar.api.batch.fs.InputPath;
+import org.sonar.api.batch.fs.TextRange;
+
+/**
+ * Represents an issue location.
+ *
+ * @since 5.2
+ */
+@Beta
+public interface IssueLocation {
+
+  /**
+   * The {@link InputPath} this location belongs to. Returns null if location is global to the project.
+   */
+  @CheckForNull
+  InputPath inputPath();
+
+  /**
+   * Range of the issue. Null for global issues and issues on directories. Can also be null
+   * for files (issue global to the file).
+   */
+  @CheckForNull
+  TextRange textRange();
+
+  /**
+   * Message of the issue.
+   */
+  @CheckForNull
+  String message();
+
+}
index 8a088f533c74ecd355a55f5c1f59994e44a956fd..7c44f331163f1b8a7faed4bbd3d016f9c965539c 100644 (file)
 package org.sonar.api.batch.sensor.issue;
 
 import com.google.common.annotations.Beta;
-import org.sonar.api.batch.fs.InputDir;
-import org.sonar.api.batch.fs.InputFile;
+import javax.annotation.Nullable;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.api.rule.RuleKey;
 
-import javax.annotation.Nullable;
-
 /**
  * Represents an issue detected by a {@link Sensor}.
  *
@@ -42,41 +39,33 @@ public interface NewIssue {
   NewIssue forRule(RuleKey ruleKey);
 
   /**
-   * The {@link InputFile} the issue belongs to. For global issues call {@link #onProject()}.
-   */
-  NewIssue onFile(InputFile file);
-
-  /**
-   * The {@link InputDir} the issue belongs to. For global issues call {@link #onProject()}.
-   */
-  NewIssue onDir(InputDir inputDir);
-
-  /**
-   * Tell that the issue is global to the project.
+   * Effort to fix the issue.
    */
-  NewIssue onProject();
+  NewIssue effortToFix(@Nullable Double effortToFix);
 
   /**
-   * Line of the issue. Only available for {@link #onFile(InputFile)} issues. 
-   * If no line is specified it means that issue is global to the file.
+   * Override severity of the issue.
+   * Setting a null value or not calling this method means to use severity configured in quality profile.
    */
-  NewIssue atLine(int line);
+  NewIssue overrideSeverity(@Nullable Severity severity);
 
   /**
-   * Effort to fix the issue.
+   * @since 5.2
+   * Register a new location for this issue. First registered location is considered as primary location.
    */
-  NewIssue effortToFix(@Nullable Double effortToFix);
+  NewIssue addLocation(NewIssueLocation location);
 
   /**
-   * Message of the issue.
+   * @since 5.2
+   * Register an execution flow for this issue.
    */
-  NewIssue message(String message);
+  NewIssue addExecutionFlow(NewIssueLocation... flow);
 
   /**
-   * Override severity of the issue.
-   * Setting a null value or not calling this method means to use severity configured in quality profile.
+   * @since 5.2
+   * Create a new location for this issue. First registered location is considered as primary location.
    */
-  NewIssue overrideSeverity(@Nullable Severity severity);
+  NewIssueLocation newLocation();
 
   /**
    * Save the issue. If rule key is unknown or rule not enabled in the current quality profile then a warning is logged but no exception
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssueLocation.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssueLocation.java
new file mode 100644 (file)
index 0000000..3ead59e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.api.batch.sensor.issue;
+
+import com.google.common.annotations.Beta;
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+
+/**
+ * Represents one issue location. See {@link NewIssue#newLocation()}.
+ *
+ * @since 5.2
+ */
+@Beta
+public interface NewIssueLocation {
+
+  /**
+   * Maximum number of characters in the message.
+   */
+  int MESSAGE_MAX_SIZE = 4000;
+
+  /**
+   * The {@link InputFile} the issue location belongs to. For global issues call {@link #onProject()}.
+   */
+  NewIssueLocation onFile(InputFile file);
+
+  /**
+   * The {@link InputDir} the issue location belongs to. For global issues call {@link #onProject()}.
+   */
+  NewIssueLocation onDir(InputDir inputDir);
+
+  /**
+   * Tell that the issue location is global to the project.
+   */
+  NewIssueLocation onProject();
+
+  /**
+   * Position in the file. Only valid when {@link #onFile(InputFile)} has been called. 
+   * See {@link InputFile#newRange(org.sonar.api.batch.fs.TextPointer, org.sonar.api.batch.fs.TextPointer)}
+   */
+  NewIssueLocation at(TextRange location);
+
+  /**
+   * Optional, but recommended, plain-text message for this location.
+   * <p/>
+   * Formats like Markdown or HTML are not supported. Size must not be greater than {@link #MESSAGE_MAX_SIZE} characters.
+   */
+  NewIssueLocation message(String message);
+
+}
index 7eee7b189dd65d3eab4d4dc9e5e401aba6e965d5..686677ffb29692bad268e5a4a02a92575994091d 100644 (file)
  */
 package org.sonar.api.batch.sensor.issue.internal;
 
+import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
-import org.sonar.api.batch.fs.InputDir;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputPath;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nullable;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.batch.sensor.internal.DefaultStorable;
 import org.sonar.api.batch.sensor.internal.SensorStorage;
 import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.issue.IssueLocation;
 import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.internal.Uuids;
 
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
 public class DefaultIssue extends DefaultStorable implements Issue, NewIssue {
 
-  private static final String INPUT_DIR_SHOULD_BE_NON_NULL = "InputDir should be non null";
-  private static final String INPUT_FILE_SHOULD_BE_NON_NULL = "InputFile should be non null";
-  private static final String ON_FILE_OR_ON_DIR_ALREADY_CALLED = "onFile or onDir already called";
-  private static final String ON_PROJECT_ALREADY_CALLED = "onProject already called";
   private String key;
-  private boolean onProject = false;
-  private InputPath path;
   private RuleKey ruleKey;
-  private String message;
-  private Integer line;
   private Double effortToFix;
-  private Severity overridenSeverity;
+  private Severity overriddenSeverity;
+  private List<IssueLocation> locations = new ArrayList<>();
+  private List<List<IssueLocation>> executionFlows = new ArrayList<>();
 
   public DefaultIssue() {
     super(null);
@@ -67,57 +63,36 @@ public class DefaultIssue extends DefaultStorable implements Issue, NewIssue {
   }
 
   @Override
-  public DefaultIssue onFile(InputFile file) {
-    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
-    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
-    Preconditions.checkNotNull(file, INPUT_FILE_SHOULD_BE_NON_NULL);
-    this.path = file;
-    return this;
-  }
-
-  @Override
-  public DefaultIssue onDir(InputDir dir) {
-    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
-    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
-    Preconditions.checkNotNull(dir, INPUT_DIR_SHOULD_BE_NON_NULL);
-    this.path = dir;
+  public DefaultIssue effortToFix(@Nullable Double effortToFix) {
+    this.effortToFix = effortToFix;
     return this;
   }
 
   @Override
-  public DefaultIssue onProject() {
-    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
-    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
-    this.onProject = true;
+  public DefaultIssue overrideSeverity(@Nullable Severity severity) {
+    this.overriddenSeverity = severity;
     return this;
   }
 
   @Override
-  public DefaultIssue atLine(int line) {
-    Preconditions.checkState(this.path != null && this.path instanceof InputFile, "atLine should be called after onFile.");
-    Preconditions.checkArgument(line > 0, "line starts at 1, invalid value " + line + ".");
-    int lines = ((InputFile) path).lines();
-    Preconditions.checkArgument(line <= lines, "File " + path + " has " + lines + " lines. Unable to create issue at line " + line + ".");
-    this.line = line;
-    return this;
+  public NewIssueLocation newLocation() {
+    return new DefaultIssueLocation();
   }
 
   @Override
-  public DefaultIssue effortToFix(@Nullable Double effortToFix) {
-    this.effortToFix = effortToFix;
+  public DefaultIssue addLocation(NewIssueLocation location) {
+    locations.add((DefaultIssueLocation) location);
     return this;
   }
 
   @Override
-  public DefaultIssue message(String message) {
-    this.message = message;
-    return this;
-  }
-
-  @Override
-  public DefaultIssue overrideSeverity(@Nullable Severity severity) {
-    this.overridenSeverity = severity;
-    return this;
+  public DefaultIssue addExecutionFlow(NewIssueLocation... flow) {
+    List<IssueLocation> flowAsList = new ArrayList<>();
+    for (NewIssueLocation issueLocation : flow) {
+      flowAsList.add((DefaultIssueLocation) issueLocation);
+    }
+    executionFlows.add(flowAsList);
+    return null;
   }
 
   @Override
@@ -125,40 +100,45 @@ public class DefaultIssue extends DefaultStorable implements Issue, NewIssue {
     return this.ruleKey;
   }
 
-  @CheckForNull
   @Override
-  public InputPath inputPath() {
-    return this.path;
+  public Severity overriddenSeverity() {
+    return this.overriddenSeverity;
   }
 
   @Override
-  public Integer line() {
-    return this.line;
+  public Double effortToFix() {
+    return this.effortToFix;
   }
 
-  @Override
-  public String message() {
-    return this.message;
+  public String key() {
+    return this.key;
   }
 
   @Override
-  public Severity overridenSeverity() {
-    return this.overridenSeverity;
+  public List<IssueLocation> locations() {
+    return ImmutableList.copyOf(this.locations);
   }
 
   @Override
-  public Double effortToFix() {
-    return this.effortToFix;
-  }
-
-  public String key() {
-    return this.key;
+  public List<ExecutionFlow> executionFlows() {
+    return Lists.transform(this.executionFlows, new Function<List<IssueLocation>, ExecutionFlow>() {
+      @Override
+      public ExecutionFlow apply(final List<IssueLocation> input) {
+        return new ExecutionFlow() {
+          @Override
+          public List<IssueLocation> locations() {
+            return ImmutableList.copyOf(input);
+          }
+        };
+      }
+    });
   }
 
   @Override
   public void doSave() {
     Preconditions.checkNotNull(this.ruleKey, "ruleKey is mandatory on issue");
     Preconditions.checkState(!Strings.isNullOrEmpty(key), "Fail to generate issue key");
+    Preconditions.checkState(!locations.isEmpty(), "At least one location is mandatory on every issue");
     storage.store(this);
   }
 
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java
new file mode 100644 (file)
index 0000000..3840cd5
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.api.batch.sensor.issue.internal;
+
+import com.google.common.base.Preconditions;
+import javax.annotation.CheckForNull;
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputPath;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.issue.IssueLocation;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
+
+public class DefaultIssueLocation implements NewIssueLocation, IssueLocation {
+
+  private static final String INPUT_DIR_SHOULD_BE_NON_NULL = "InputDir should be non null";
+  private static final String INPUT_FILE_SHOULD_BE_NON_NULL = "InputFile should be non null";
+  private static final String ON_FILE_OR_ON_DIR_ALREADY_CALLED = "onFile or onDir already called";
+  private static final String ON_PROJECT_ALREADY_CALLED = "onProject already called";
+
+  private boolean onProject = false;
+  private InputPath path;
+  private TextRange textRange;
+  private String message;
+
+  @Override
+  public NewIssueLocation onFile(InputFile file) {
+    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
+    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
+    Preconditions.checkNotNull(file, INPUT_FILE_SHOULD_BE_NON_NULL);
+    this.path = file;
+    return this;
+  }
+
+  @Override
+  public NewIssueLocation onDir(InputDir dir) {
+    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
+    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
+    Preconditions.checkNotNull(dir, INPUT_DIR_SHOULD_BE_NON_NULL);
+    this.path = dir;
+    return this;
+  }
+
+  @Override
+  public NewIssueLocation onProject() {
+    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
+    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
+    this.onProject = true;
+    return this;
+  }
+
+  @Override
+  public NewIssueLocation at(TextRange location) {
+    Preconditions.checkState(this.path != null && this.path instanceof InputFile, "at() should be called after onFile.");
+    DefaultInputFile file = (DefaultInputFile) this.path;
+    file.validate(location);
+    this.textRange = location;
+    return this;
+  }
+
+  @Override
+  public NewIssueLocation message(String message) {
+    Preconditions.checkNotNull(message, "Message can't be null");
+    Preconditions.checkArgument(message.length() <= MESSAGE_MAX_SIZE,
+      "Message of an issue can't be greater than " + MESSAGE_MAX_SIZE + ": [" + message + "] size is " + message.length());
+    this.message = message;
+    return this;
+  }
+
+  @Override
+  @CheckForNull
+  public InputPath inputPath() {
+    return this.path;
+  }
+
+  @Override
+  public TextRange textRange() {
+    return textRange;
+  }
+
+  @Override
+  public String message() {
+    return this.message;
+  }
+
+}
index ef2fe0f6f4e78c9d5d89b92c07f7b584eb41c4e4..428d49d56f0aa531330346ff894e97047b3dc1fe 100644 (file)
 
 package org.sonar.api.issue;
 
+import java.util.List;
+import javax.annotation.Nullable;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
 import org.sonar.api.component.Perspective;
 import org.sonar.api.rule.RuleKey;
 
-import javax.annotation.Nullable;
-
-import java.util.List;
-
 /**
  * This perspective allows to add and get issues related to the selected component. It can be used from
  * {@link org.sonar.api.batch.Sensor}s and {@link org.sonar.api.batch.Decorator}s. Web extensions
@@ -68,16 +67,38 @@ public interface Issuable extends Perspective {
 
     /**
      * Optional line index, starting from 1. It must not be zero or negative.
+     * @deprecated since 5.2 use {@link #addLocation(NewIssueLocation)}
      */
+    @Deprecated
     IssueBuilder line(@Nullable Integer line);
 
     /**
      * Optional, but recommended, plain-text message.
      * <p/>
      * Formats like Markdown or HTML are not supported. Size must not be greater than {@link Issue#MESSAGE_MAX_SIZE} characters.
+     * @deprecated since 5.2 use {@link #addLocation(NewIssueLocation)}
      */
+    @Deprecated
     IssueBuilder message(@Nullable String message);
 
+    /**
+     * @since 5.2
+     * Create a new location for this issue. First registered location is considered as primary location.
+     */
+    NewIssueLocation newLocation();
+
+    /**
+     * @since 5.2
+     * Register a new secondary location for this issue.
+     */
+    IssueBuilder addLocation(NewIssueLocation location);
+
+    /**
+     * @since 5.2
+     * Register an execution flow for this issue.
+     */
+    IssueBuilder addExecutionFlow(NewIssueLocation... flow);
+
     /**
      * Overrides the severity declared in Quality profile. Do not execute in standard use-cases.
      * @see org.sonar.api.rule.Severity
index 596662d861a33b3ee22628eaa2d333222ceff75b..99f70ac964b2ce32c1c105f46c54fa6e435a9622 100644 (file)
  */
 package org.sonar.api.batch.fs.internal;
 
+import java.io.File;
+import java.nio.file.Path;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.fs.InputFile;
 
-import java.io.File;
-import java.nio.file.Path;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
 
@@ -163,12 +162,13 @@ public class DefaultInputFileTest {
     file.newRange(file.newPointer(1, 0), file.newPointer(1, 9));
     file.newRange(file.newPointer(1, 0), file.newPointer(2, 0));
     assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(2, 5))).isEqualTo(file.newRange(0, 15));
+    file.newRange(file.newPointer(1, 0), file.newPointer(1, 0));
 
     try {
-      file.newRange(file.newPointer(1, 0), file.newPointer(1, 0));
+      file.newRange(file.newPointer(1, 1), file.newPointer(1, 0));
       fail();
     } catch (Exception e) {
-      assertThat(e).hasMessage("Start pointer [line=1, lineOffset=0] should be before end pointer [line=1, lineOffset=0]");
+      assertThat(e).hasMessage("Start pointer [line=1, lineOffset=1] should be before end pointer [line=1, lineOffset=0]");
     }
     try {
       file.newRange(file.newPointer(1, 0), file.newPointer(1, 10));
index eef7173599079b058b7a13d027ddb9d2357180f1..8837c6eb6da373694ee27893fe01da3d0de63175 100644 (file)
  */
 package org.sonar.api.batch.sensor.internal;
 
+import java.io.File;
+import java.io.StringReader;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.fs.internal.DefaultFileSystem;
-import org.sonar.api.batch.fs.internal.DefaultInputDir;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.FileMetadata;
 import org.sonar.api.batch.rule.ActiveRules;
 import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
 import org.sonar.api.batch.sensor.coverage.CoverageType;
 import org.sonar.api.batch.sensor.highlighting.TypeOfText;
+import org.sonar.api.batch.sensor.issue.NewIssue;
 import org.sonar.api.config.Settings;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.rule.RuleKey;
 
-import java.io.File;
-import java.io.StringReader;
-
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class SensorContextTesterTest {
@@ -87,32 +86,18 @@ public class SensorContextTesterTest {
 
   @Test
   public void testIssues() {
-    assertThat(tester.issues("foo:src/Foo.java")).isEmpty();
     assertThat(tester.allIssues()).isEmpty();
-    tester.newIssue()
-      .onFile(new DefaultInputFile("foo", "src/Foo.java").setLines(10))
+    NewIssue newIssue = tester.newIssue();
+    newIssue
+      .addLocation(newIssue.newLocation().onFile(new DefaultInputFile("foo", "src/Foo.java")))
       .forRule(RuleKey.of("repo", "rule"))
-      .atLine(1)
       .save();
-    tester.newIssue()
-      .onFile(new DefaultInputFile("foo", "src/Foo.java").setLines(10))
+    newIssue = tester.newIssue();
+    newIssue
+      .addLocation(newIssue.newLocation().onFile(new DefaultInputFile("foo", "src/Foo.java")))
       .forRule(RuleKey.of("repo", "rule"))
-      .atLine(3)
       .save();
-    assertThat(tester.issues("foo:src/Foo.java")).hasSize(2);
     assertThat(tester.allIssues()).hasSize(2);
-    tester.newIssue()
-      .onDir(new DefaultInputDir("foo", "src"))
-      .forRule(RuleKey.of("repo", "rule"))
-      .save();
-    assertThat(tester.issues("foo:src")).hasSize(1);
-    assertThat(tester.allIssues()).hasSize(3);
-    tester.newIssue()
-      .onProject()
-      .forRule(RuleKey.of("repo", "rule"))
-      .save();
-    assertThat(tester.issues(null)).hasSize(1);
-    assertThat(tester.allIssues()).hasSize(4);
   }
 
   @Test
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocationTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocationTest.java
new file mode 100644 (file)
index 0000000..6ed1a7a
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.api.batch.sensor.issue.internal;
+
+import java.io.StringReader;
+import org.apache.commons.lang.StringUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.FileMetadata;
+
+public class DefaultIssueLocationTest {
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  private DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.php").initMetadata(new FileMetadata().readMetadata(new StringReader("Foo\nBar\n")));
+
+  @Test
+  public void not_allowed_to_call_onFile_and_onProject() {
+    thrown.expect(IllegalStateException.class);
+    thrown.expectMessage("onProject already called");
+    new DefaultIssueLocation()
+      .onProject()
+      .onFile(inputFile)
+      .message("Wrong way!");
+  }
+
+  @Test
+  public void prevent_too_long_messages() {
+    new DefaultIssueLocation()
+      .onFile(inputFile)
+      .message(StringUtils.repeat("a", 4000));
+
+    thrown.expect(IllegalArgumentException.class);
+    thrown.expectMessage("Message of an issue can't be greater than 4000: [aaa");
+    thrown.expectMessage("aaa] size is 4001");
+
+    new DefaultIssueLocation()
+      .onFile(inputFile)
+      .message(StringUtils.repeat("a", 4001));
+
+  }
+
+}
index 41ebf8e7a5b3a25afeba897db1b599af6a5aa959..e9b27548b359626d2e710bc2f1b643e87fe60959 100644 (file)
  */
 package org.sonar.api.batch.sensor.issue.internal;
 
-import org.junit.Rule;
+import java.io.StringReader;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.sonar.api.batch.fs.internal.DefaultInputDir;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.FileMetadata;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.batch.sensor.internal.SensorStorage;
 import org.sonar.api.rule.RuleKey;
@@ -34,24 +34,24 @@ import static org.mockito.Mockito.verify;
 
 public class DefaultIssueTest {
 
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
+  private DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.php").initMetadata(new FileMetadata().readMetadata(new StringReader("Foo\nBar\n")));
 
   @Test
   public void build_file_issue() {
     SensorStorage storage = mock(SensorStorage.class);
     DefaultIssue issue = new DefaultIssue(storage)
-      .onFile(new DefaultInputFile("foo", "src/Foo.php").setLines(3))
+      .addLocation(new DefaultIssueLocation()
+        .onFile(inputFile)
+        .at(inputFile.selectLine(1))
+        .message("Wrong way!"))
       .forRule(RuleKey.of("repo", "rule"))
-      .atLine(1)
-      .effortToFix(10.0)
-      .message("Wrong way!");
+      .effortToFix(10.0);
 
-    assertThat(issue.inputPath()).isEqualTo(new DefaultInputFile("foo", "src/Foo.php"));
+    assertThat(issue.locations().get(0).inputPath()).isEqualTo(inputFile);
     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
-    assertThat(issue.line()).isEqualTo(1);
+    assertThat(issue.locations().get(0).textRange().start().line()).isEqualTo(1);
     assertThat(issue.effortToFix()).isEqualTo(10.0);
-    assertThat(issue.message()).isEqualTo("Wrong way!");
+    assertThat(issue.locations().get(0).message()).isEqualTo("Wrong way!");
 
     issue.save();
 
@@ -62,15 +62,17 @@ public class DefaultIssueTest {
   public void build_directory_issue() {
     SensorStorage storage = mock(SensorStorage.class);
     DefaultIssue issue = new DefaultIssue(storage)
-      .onDir(new DefaultInputDir("foo", "src"))
+      .addLocation(new DefaultIssueLocation()
+        .onDir(new DefaultInputDir("foo", "src"))
+        .message("Wrong way!"))
       .forRule(RuleKey.of("repo", "rule"))
-      .overrideSeverity(Severity.BLOCKER)
-      .message("Wrong way!");
+      .overrideSeverity(Severity.BLOCKER);
 
-    assertThat(issue.inputPath()).isEqualTo(new DefaultInputDir("foo", "src"));
+    assertThat(issue.locations().get(0).inputPath()).isEqualTo(new DefaultInputDir("foo", "src"));
     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
-    assertThat(issue.message()).isEqualTo("Wrong way!");
-    assertThat(issue.overridenSeverity()).isEqualTo(Severity.BLOCKER);
+    assertThat(issue.locations().get(0).textRange()).isNull();
+    assertThat(issue.locations().get(0).message()).isEqualTo("Wrong way!");
+    assertThat(issue.overriddenSeverity()).isEqualTo(Severity.BLOCKER);
 
     issue.save();
 
@@ -81,53 +83,21 @@ public class DefaultIssueTest {
   public void build_project_issue() {
     SensorStorage storage = mock(SensorStorage.class);
     DefaultIssue issue = new DefaultIssue(storage)
-      .onProject()
+      .addLocation(new DefaultIssueLocation()
+        .onProject()
+        .message("Wrong way!"))
       .forRule(RuleKey.of("repo", "rule"))
-      .effortToFix(10.0)
-      .message("Wrong way!");
+      .effortToFix(10.0);
 
-    assertThat(issue.inputPath()).isNull();
+    assertThat(issue.locations().get(0).inputPath()).isNull();
     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
-    assertThat(issue.line()).isNull();
+    assertThat(issue.locations().get(0).textRange()).isNull();
     assertThat(issue.effortToFix()).isEqualTo(10.0);
-    assertThat(issue.message()).isEqualTo("Wrong way!");
+    assertThat(issue.locations().get(0).message()).isEqualTo("Wrong way!");
 
     issue.save();
 
     verify(storage).store(issue);
   }
 
-  @Test
-  public void not_allowed_to_call_onFile_and_onProject() {
-    thrown.expect(IllegalStateException.class);
-    thrown.expectMessage("onProject already called");
-    new DefaultIssue()
-      .onProject()
-      .onFile(new DefaultInputFile("foo", "src/Foo.php"))
-      .forRule(RuleKey.of("repo", "rule"))
-      .atLine(1)
-      .effortToFix(10.0)
-      .message("Wrong way!");
-  }
-
-  @Test
-  public void line_is_positive() {
-    thrown.expect(IllegalArgumentException.class);
-    thrown.expectMessage("line starts at 1, invalid value 0.");
-    new DefaultIssue()
-      .onFile(new DefaultInputFile("foo", "src/Foo.php").setLines(3))
-      .forRule(RuleKey.of("repo", "rule"))
-      .atLine(0);
-  }
-
-  @Test
-  public void not_allowed_to_create_issues_on_unexisting_line() {
-    thrown.expect(IllegalArgumentException.class);
-    thrown.expectMessage("File [moduleKey=foo, relative=src/Foo.php, basedir=null] has 3 lines. Unable to create issue at line 5.");
-    new DefaultIssue()
-      .onFile(new DefaultInputFile("foo", "src/Foo.php").setLines(3))
-      .forRule(RuleKey.of("repo", "rule"))
-      .atLine(5);
-  }
-
 }