From: Julien HENRY Date: Mon, 8 Jun 2015 14:40:48 +0000 (+0200) Subject: SONAR-4865, SONAR-6052 Improved issue locations X-Git-Tag: 5.2-RC1~1010 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=056b4bdc63c2ef126d9f9d2e0526f60be930cb81;p=sonarqube.git SONAR-4865, SONAR-6052 Improved issue locations --- diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java index f76fde9b90a..a0f9cfdb4e8 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java @@ -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, diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/TemplateRuleCheck.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/TemplateRuleCheck.java index 9e58a410526..c6fe84360c3 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/TemplateRuleCheck.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/checks/TemplateRuleCheck.java @@ -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(); } diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java index 5a1cefcab8e..47e8a16794d 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java @@ -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(); } } diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/DeprecatedResourceApiSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/DeprecatedResourceApiSensor.java index 7cb80fbf541..99a6e39fe1a 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/DeprecatedResourceApiSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/DeprecatedResourceApiSensor.java @@ -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 index 00000000000..a4bcca64eab --- /dev/null +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/MultilineIssuesSensor.java @@ -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> startPositions = new HashMap<>(); + Map> 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()); + } + 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()); + } + endPositions.get(issueId).put(issueLocationId, newPointer); + } + } + } catch (IOException e) { + throw new IllegalStateException("Unable to read file", e); + } + for (Map.Entry> entry : startPositions.entrySet()) { + NewIssue newIssue = context.newIssue().forRule(ruleKey); + for (Map.Entry 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(); + } + } + +} diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssueOnDirPerFileSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssueOnDirPerFileSensor.java index 6dbda2f741a..e53f0b17ccc 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssueOnDirPerFileSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssueOnDirPerFileSensor.java @@ -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(); } } diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java index fc0a564c69c..e8aed769087 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java @@ -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(); } } + } diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/RandomAccessSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/RandomAccessSensor.java index 0541d917552..69bf700b50b 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/RandomAccessSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/RandomAccessSensor.java @@ -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(); } } diff --git a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/OneIssuePerLineSensorTest.java b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/OneIssuePerLineSensorTest.java index a3cbbf5eb84..2b422ba50ee 100644 --- a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/OneIssuePerLineSensorTest.java +++ b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/OneIssuePerLineSensorTest.java @@ -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 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 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); } } diff --git a/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java b/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java index 914521f3d6f..b8422b501bc 100644 --- a/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java +++ b/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java @@ -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()) diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/source/DuplicationLineReader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/source/DuplicationLineReader.java index 3920e15a96f..1d079a2e239 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/source/DuplicationLineReader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/source/DuplicationLineReader.java @@ -35,7 +35,7 @@ import static com.google.common.collect.Maps.newHashMap; public class DuplicationLineReader implements LineReader { private final List duplications; - private final Map duplicationIdsByRange; + private final Map duplicationIdsByRange; public DuplicationLineReader(Iterator 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 blocks = findDuplicationBlockMatchingLine(line); - for (BatchReport.Range block : blocks) { + List blocks = findDuplicationBlockMatchingLine(line); + for (BatchReport.TextRange block : blocks) { lineBuilder.addDuplication(duplicationIdsByRange.get(block)); } } - private List findDuplicationBlockMatchingLine(int line) { - List blocks = newArrayList(); + private List findDuplicationBlockMatchingLine(int line) { + List 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 createDuplicationIdsByRange(List duplications) { - Map map = newHashMap(); + private Map createDuplicationIdsByRange(List duplications) { + Map map = newHashMap(); int blockId = 1; for (BatchReport.Duplication duplication : this.duplications) { map.put(duplication.getOriginPosition(), blockId); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/source/HighlightingLineReader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/source/HighlightingLineReader.java index 11210885da4..f3e4763c296 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/source/HighlightingLineReader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/source/HighlightingLineReader.java @@ -63,7 +63,7 @@ public class HighlightingLineReader implements LineReader { incrementHighlightingListMatchingLine(line); for (Iterator 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()) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/source/RangeOffsetHelper.java b/server/sonar-server/src/main/java/org/sonar/server/computation/source/RangeOffsetHelper.java index fc4b80aa85a..35402dace4c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/source/RangeOffsetHelper.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/source/RangeOffsetHelper.java @@ -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)); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java index 5b44635d7b0..c84b8fc4eec 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java @@ -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; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java index 9696abfc4e0..c8766aa5116 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java @@ -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(" 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 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 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 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 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 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 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 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 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 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()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistDuplicationsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistDuplicationsStepTest.java index a117734529d..8af6d6c4d88 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistDuplicationsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistDuplicationsStepTest.java @@ -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()) diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java index 4cde198b47d..4816a2a9959 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java @@ -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) diff --git a/sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java b/sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java index c5e1b26604d..32168a1f7f8 100644 --- a/sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java +++ b/sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java @@ -6574,6 +6574,54 @@ public final class BatchReport { */ com.google.protobuf.ByteString getAttributesBytes(); + + /** + * repeated .IssueLocation locations = 8; + */ + java.util.List + getLocationsList(); + /** + * repeated .IssueLocation locations = 8; + */ + org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index); + /** + * repeated .IssueLocation locations = 8; + */ + int getLocationsCount(); + /** + * repeated .IssueLocation locations = 8; + */ + java.util.List + getLocationsOrBuilderList(); + /** + * repeated .IssueLocation locations = 8; + */ + org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder getLocationsOrBuilder( + int index); + + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + java.util.List + getExecutionFlowsList(); + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + org.sonar.batch.protocol.output.BatchReport.ExecutionFlow getExecutionFlows(int index); + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + int getExecutionFlowsCount(); + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + java.util.List + getExecutionFlowsOrBuilderList(); + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + 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(); + 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(); + 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 locations_; + /** + * repeated .IssueLocation locations = 8; + */ + public java.util.List getLocationsList() { + return locations_; + } + /** + * repeated .IssueLocation locations = 8; + */ + public java.util.List + getLocationsOrBuilderList() { + return locations_; + } + /** + * repeated .IssueLocation locations = 8; + */ + public int getLocationsCount() { + return locations_.size(); + } + /** + * repeated .IssueLocation locations = 8; + */ + public org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index) { + return locations_.get(index); + } + /** + * repeated .IssueLocation locations = 8; + */ + 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 executionFlows_; + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public java.util.List getExecutionFlowsList() { + return executionFlows_; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public java.util.List + getExecutionFlowsOrBuilderList() { + return executionFlows_; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public int getExecutionFlowsCount() { + return executionFlows_.size(); + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow getExecutionFlows(int index) { + return executionFlows_.get(index); + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + 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; } - /** - * optional int32 line = 3; - */ - public Builder clearLine() { - bitField0_ = (bitField0_ & ~0x00000004); - line_ = 0; - onChanged(); + /** + * optional int32 line = 3; + */ + public Builder clearLine() { + bitField0_ = (bitField0_ & ~0x00000004); + line_ = 0; + onChanged(); + return this; + } + + private java.lang.Object msg_ = ""; + /** + * optional string msg = 4; + */ + public boolean hasMsg() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional string msg = 4; + */ + 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; + } + } + /** + * optional string msg = 4; + */ + 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; + } + } + /** + * optional string msg = 4; + */ + public Builder setMsg( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + msg_ = value; + onChanged(); + return this; + } + /** + * optional string msg = 4; + */ + public Builder clearMsg() { + bitField0_ = (bitField0_ & ~0x00000008); + msg_ = getDefaultInstance().getMsg(); + onChanged(); + return this; + } + /** + * optional string msg = 4; + */ + 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; + /** + * optional .Severity severity = 5; + */ + public boolean hasSeverity() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional .Severity severity = 5; + */ + public org.sonar.batch.protocol.Constants.Severity getSeverity() { + return severity_; + } + /** + * optional .Severity severity = 5; + */ + public Builder setSeverity(org.sonar.batch.protocol.Constants.Severity value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + severity_ = value; + onChanged(); + return this; + } + /** + * optional .Severity severity = 5; + */ + public Builder clearSeverity() { + bitField0_ = (bitField0_ & ~0x00000010); + severity_ = org.sonar.batch.protocol.Constants.Severity.INFO; + onChanged(); + return this; + } + + private double effortToFix_ ; + /** + * optional double effort_to_fix = 6; + */ + public boolean hasEffortToFix() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional double effort_to_fix = 6; + */ + public double getEffortToFix() { + return effortToFix_; + } + /** + * optional double effort_to_fix = 6; + */ + public Builder setEffortToFix(double value) { + bitField0_ |= 0x00000020; + effortToFix_ = value; + onChanged(); + return this; + } + /** + * optional double effort_to_fix = 6; + */ + public Builder clearEffortToFix() { + bitField0_ = (bitField0_ & ~0x00000020); + effortToFix_ = 0D; + onChanged(); + return this; + } + + private java.lang.Object attributes_ = ""; + /** + * optional string attributes = 7; + */ + public boolean hasAttributes() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * optional string attributes = 7; + */ + 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; + } + } + /** + * optional string attributes = 7; + */ + 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; + } + } + /** + * optional string attributes = 7; + */ + public Builder setAttributes( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000040; + attributes_ = value; + onChanged(); + return this; + } + /** + * optional string attributes = 7; + */ + public Builder clearAttributes() { + bitField0_ = (bitField0_ & ~0x00000040); + attributes_ = getDefaultInstance().getAttributes(); + onChanged(); + return this; + } + /** + * optional string attributes = 7; + */ + 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 locations_ = + java.util.Collections.emptyList(); + private void ensureLocationsIsMutable() { + if (!((bitField0_ & 0x00000080) == 0x00000080)) { + locations_ = new java.util.ArrayList(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_; + + /** + * repeated .IssueLocation locations = 8; + */ + public java.util.List getLocationsList() { + if (locationsBuilder_ == null) { + return java.util.Collections.unmodifiableList(locations_); + } else { + return locationsBuilder_.getMessageList(); + } + } + /** + * repeated .IssueLocation locations = 8; + */ + public int getLocationsCount() { + if (locationsBuilder_ == null) { + return locations_.size(); + } else { + return locationsBuilder_.getCount(); + } + } + /** + * repeated .IssueLocation locations = 8; + */ + public org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index) { + if (locationsBuilder_ == null) { + return locations_.get(index); + } else { + return locationsBuilder_.getMessage(index); + } + } + /** + * repeated .IssueLocation locations = 8; + */ + 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; + } + /** + * repeated .IssueLocation locations = 8; + */ + 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; + } + /** + * repeated .IssueLocation locations = 8; + */ + 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; + } + /** + * repeated .IssueLocation locations = 8; + */ + 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; + } + /** + * repeated .IssueLocation locations = 8; + */ + 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; + } + /** + * repeated .IssueLocation locations = 8; + */ + 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; + } + /** + * repeated .IssueLocation locations = 8; + */ + public Builder addAllLocations( + java.lang.Iterable values) { + if (locationsBuilder_ == null) { + ensureLocationsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, locations_); + onChanged(); + } else { + locationsBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .IssueLocation locations = 8; + */ + public Builder clearLocations() { + if (locationsBuilder_ == null) { + locations_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000080); + onChanged(); + } else { + locationsBuilder_.clear(); + } + return this; + } + /** + * repeated .IssueLocation locations = 8; + */ + public Builder removeLocations(int index) { + if (locationsBuilder_ == null) { + ensureLocationsIsMutable(); + locations_.remove(index); + onChanged(); + } else { + locationsBuilder_.remove(index); + } + return this; + } + /** + * repeated .IssueLocation locations = 8; + */ + public org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder getLocationsBuilder( + int index) { + return getLocationsFieldBuilder().getBuilder(index); + } + /** + * repeated .IssueLocation locations = 8; + */ + public org.sonar.batch.protocol.output.BatchReport.IssueLocationOrBuilder getLocationsOrBuilder( + int index) { + if (locationsBuilder_ == null) { + return locations_.get(index); } else { + return locationsBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .IssueLocation locations = 8; + */ + public java.util.List + getLocationsOrBuilderList() { + if (locationsBuilder_ != null) { + return locationsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(locations_); + } + } + /** + * repeated .IssueLocation locations = 8; + */ + public org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder addLocationsBuilder() { + return getLocationsFieldBuilder().addBuilder( + org.sonar.batch.protocol.output.BatchReport.IssueLocation.getDefaultInstance()); + } + /** + * repeated .IssueLocation locations = 8; + */ + public org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder addLocationsBuilder( + int index) { + return getLocationsFieldBuilder().addBuilder( + index, org.sonar.batch.protocol.output.BatchReport.IssueLocation.getDefaultInstance()); + } + /** + * repeated .IssueLocation locations = 8; + */ + public java.util.List + 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 executionFlows_ = + java.util.Collections.emptyList(); + private void ensureExecutionFlowsIsMutable() { + if (!((bitField0_ & 0x00000100) == 0x00000100)) { + executionFlows_ = new java.util.ArrayList(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_; + + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public java.util.List getExecutionFlowsList() { + if (executionFlowsBuilder_ == null) { + return java.util.Collections.unmodifiableList(executionFlows_); + } else { + return executionFlowsBuilder_.getMessageList(); + } + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public int getExecutionFlowsCount() { + if (executionFlowsBuilder_ == null) { + return executionFlows_.size(); + } else { + return executionFlowsBuilder_.getCount(); + } + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow getExecutionFlows(int index) { + if (executionFlowsBuilder_ == null) { + return executionFlows_.get(index); + } else { + return executionFlowsBuilder_.getMessage(index); + } + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + 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; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + 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; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + 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; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + 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; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + 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; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + 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; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public Builder addAllExecutionFlows( + java.lang.Iterable values) { + if (executionFlowsBuilder_ == null) { + ensureExecutionFlowsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, executionFlows_); + onChanged(); + } else { + executionFlowsBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public Builder clearExecutionFlows() { + if (executionFlowsBuilder_ == null) { + executionFlows_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000100); + onChanged(); + } else { + executionFlowsBuilder_.clear(); + } + return this; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public Builder removeExecutionFlows(int index) { + if (executionFlowsBuilder_ == null) { + ensureExecutionFlowsIsMutable(); + executionFlows_.remove(index); + onChanged(); + } else { + executionFlowsBuilder_.remove(index); + } + return this; + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder getExecutionFlowsBuilder( + int index) { + return getExecutionFlowsFieldBuilder().getBuilder(index); + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public org.sonar.batch.protocol.output.BatchReport.ExecutionFlowOrBuilder getExecutionFlowsOrBuilder( + int index) { + if (executionFlowsBuilder_ == null) { + return executionFlows_.get(index); } else { + return executionFlowsBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public java.util.List + getExecutionFlowsOrBuilderList() { + if (executionFlowsBuilder_ != null) { + return executionFlowsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(executionFlows_); + } + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder addExecutionFlowsBuilder() { + return getExecutionFlowsFieldBuilder().addBuilder( + org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.getDefaultInstance()); + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.Builder addExecutionFlowsBuilder( + int index) { + return getExecutionFlowsFieldBuilder().addBuilder( + index, org.sonar.batch.protocol.output.BatchReport.ExecutionFlow.getDefaultInstance()); + } + /** + * repeated .ExecutionFlow execution_flows = 9; + */ + public java.util.List + 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 { + + /** + * optional int32 component_ref = 1; + */ + boolean hasComponentRef(); + /** + * optional int32 component_ref = 1; + */ + int getComponentRef(); + + /** + * optional .TextRange text_range = 2; + * + *
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * 
+ */ + boolean hasTextRange(); + /** + * optional .TextRange text_range = 2; + * + *
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * 
+ */ + org.sonar.batch.protocol.output.BatchReport.TextRange getTextRange(); + /** + * optional .TextRange text_range = 2; + * + *
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * 
+ */ + org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getTextRangeOrBuilder(); + + /** + * optional string msg = 3; + */ + boolean hasMsg(); + /** + * optional string msg = 3; + */ + java.lang.String getMsg(); + /** + * optional string msg = 3; + */ + 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 PARSER = + new com.google.protobuf.AbstractParser() { + 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 getParserForType() { + return PARSER; + } + + private int bitField0_; + public static final int COMPONENT_REF_FIELD_NUMBER = 1; + private int componentRef_; + /** + * optional int32 component_ref = 1; + */ + public boolean hasComponentRef() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional int32 component_ref = 1; + */ + public int getComponentRef() { + return componentRef_; + } + + public static final int TEXT_RANGE_FIELD_NUMBER = 2; + private org.sonar.batch.protocol.output.BatchReport.TextRange textRange_; + /** + * optional .TextRange text_range = 2; + * + *
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * 
+ */ + public boolean hasTextRange() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional .TextRange text_range = 2; + * + *
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * 
+ */ + public org.sonar.batch.protocol.output.BatchReport.TextRange getTextRange() { + return textRange_; + } + /** + * optional .TextRange text_range = 2; + * + *
+     * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+     * 
+ */ + public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getTextRangeOrBuilder() { + return textRange_; + } + + public static final int MSG_FIELD_NUMBER = 3; + private java.lang.Object msg_; + /** + * optional string msg = 3; + */ + public boolean hasMsg() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional string msg = 3; + */ + 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; + } + } + /** + * optional string msg = 3; + */ + 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 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_ ; + /** + * optional int32 component_ref = 1; + */ + public boolean hasComponentRef() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional int32 component_ref = 1; + */ + public int getComponentRef() { + return componentRef_; + } + /** + * optional int32 component_ref = 1; + */ + public Builder setComponentRef(int value) { + bitField0_ |= 0x00000001; + componentRef_ = value; + onChanged(); + return this; + } + /** + * optional int32 component_ref = 1; + */ + 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_; + /** + * optional .TextRange text_range = 2; + * + *
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * 
+ */ + public boolean hasTextRange() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional .TextRange text_range = 2; + * + *
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * 
+ */ + public org.sonar.batch.protocol.output.BatchReport.TextRange getTextRange() { + if (textRangeBuilder_ == null) { + return textRange_; + } else { + return textRangeBuilder_.getMessage(); + } + } + /** + * optional .TextRange text_range = 2; + * + *
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * 
+ */ + 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; + } + /** + * optional .TextRange text_range = 2; + * + *
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * 
+ */ + 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; + } + /** + * optional .TextRange text_range = 2; + * + *
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * 
+ */ + 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; + } + /** + * optional .TextRange text_range = 2; + * + *
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * 
+ */ + public Builder clearTextRange() { + if (textRangeBuilder_ == null) { + textRange_ = org.sonar.batch.protocol.output.BatchReport.TextRange.getDefaultInstance(); + onChanged(); + } else { + textRangeBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + /** + * optional .TextRange text_range = 2; + * + *
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * 
+ */ + public org.sonar.batch.protocol.output.BatchReport.TextRange.Builder getTextRangeBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return getTextRangeFieldBuilder().getBuilder(); + } + /** + * optional .TextRange text_range = 2; + * + *
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * 
+ */ + public org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getTextRangeOrBuilder() { + if (textRangeBuilder_ != null) { + return textRangeBuilder_.getMessageOrBuilder(); + } else { + return textRange_; + } + } + /** + * optional .TextRange text_range = 2; + * + *
+       * Only when component is a file. Can be empty for a file if this is an issue global to the file.
+       * 
+ */ + 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_ = ""; + /** + * optional string msg = 3; + */ + public boolean hasMsg() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional string msg = 3; + */ + 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; + } + } + /** + * optional string msg = 3; + */ + 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; + } + } + /** + * optional string msg = 3; + */ + public Builder setMsg( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + msg_ = value; + onChanged(); + return this; + } + /** + * optional string msg = 3; + */ + public Builder clearMsg() { + bitField0_ = (bitField0_ & ~0x00000004); + msg_ = getDefaultInstance().getMsg(); + onChanged(); + return this; + } + /** + * optional string msg = 3; + */ + 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 { + + /** + * repeated .IssueLocation locations = 1; + */ + java.util.List + getLocationsList(); + /** + * repeated .IssueLocation locations = 1; + */ + org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index); + /** + * repeated .IssueLocation locations = 1; + */ + int getLocationsCount(); + /** + * repeated .IssueLocation locations = 1; + */ + java.util.List + getLocationsOrBuilderList(); + /** + * repeated .IssueLocation locations = 1; + */ + 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(); + 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 PARSER = + new com.google.protobuf.AbstractParser() { + 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 getParserForType() { + return PARSER; + } + + public static final int LOCATIONS_FIELD_NUMBER = 1; + private java.util.List locations_; + /** + * repeated .IssueLocation locations = 1; + */ + public java.util.List getLocationsList() { + return locations_; + } + /** + * repeated .IssueLocation locations = 1; + */ + public java.util.List + getLocationsOrBuilderList() { + return locations_; + } + /** + * repeated .IssueLocation locations = 1; + */ + public int getLocationsCount() { + return locations_.size(); + } + /** + * repeated .IssueLocation locations = 1; + */ + public org.sonar.batch.protocol.output.BatchReport.IssueLocation getLocations(int index) { + return locations_.get(index); + } + /** + * repeated .IssueLocation locations = 1; + */ + 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 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_ = ""; - /** - * optional string msg = 4; - */ - public boolean hasMsg() { - return ((bitField0_ & 0x00000008) == 0x00000008); + private java.util.List locations_ = + java.util.Collections.emptyList(); + private void ensureLocationsIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + locations_ = new java.util.ArrayList(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_; + /** - * optional string msg = 4; + * repeated .IssueLocation locations = 1; */ - 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 getLocationsList() { + if (locationsBuilder_ == null) { + return java.util.Collections.unmodifiableList(locations_); } else { - return (java.lang.String) ref; + return locationsBuilder_.getMessageList(); } } /** - * optional string msg = 4; + * repeated .IssueLocation locations = 1; */ - 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(); } } /** - * optional string msg = 4; + * repeated .IssueLocation locations = 1; */ - 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); + } } /** - * optional string msg = 4; + * repeated .IssueLocation locations = 1; */ - 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; } /** - * optional string msg = 4; + * repeated .IssueLocation locations = 1; */ - 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; - /** - * optional .Severity severity = 5; - */ - public boolean hasSeverity() { - return ((bitField0_ & 0x00000010) == 0x00000010); - } /** - * optional .Severity severity = 5; + * repeated .IssueLocation locations = 1; */ - 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; } /** - * optional .Severity severity = 5; + * repeated .IssueLocation locations = 1; */ - 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; } /** - * optional .Severity severity = 5; + * repeated .IssueLocation locations = 1; */ - 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_ ; /** - * optional double effort_to_fix = 6; + * repeated .IssueLocation locations = 1; */ - 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; } /** - * optional double effort_to_fix = 6; + * repeated .IssueLocation locations = 1; */ - public double getEffortToFix() { - return effortToFix_; + public Builder addAllLocations( + java.lang.Iterable values) { + if (locationsBuilder_ == null) { + ensureLocationsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, locations_); + onChanged(); + } else { + locationsBuilder_.addAllMessages(values); + } + return this; } /** - * optional double effort_to_fix = 6; + * repeated .IssueLocation locations = 1; */ - 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; } /** - * optional double effort_to_fix = 6; + * repeated .IssueLocation locations = 1; */ - 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_ = ""; /** - * optional string attributes = 7; + * repeated .IssueLocation locations = 1; */ - public boolean hasAttributes() { - return ((bitField0_ & 0x00000040) == 0x00000040); + public org.sonar.batch.protocol.output.BatchReport.IssueLocation.Builder getLocationsBuilder( + int index) { + return getLocationsFieldBuilder().getBuilder(index); } /** - * optional string attributes = 7; + * repeated .IssueLocation locations = 1; */ - 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); } } /** - * optional string attributes = 7; + * repeated .IssueLocation locations = 1; */ - 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 + getLocationsOrBuilderList() { + if (locationsBuilder_ != null) { + return locationsBuilder_.getMessageOrBuilderList(); } else { - return (com.google.protobuf.ByteString) ref; + return java.util.Collections.unmodifiableList(locations_); } } /** - * optional string attributes = 7; + * repeated .IssueLocation locations = 1; */ - 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()); } /** - * optional string attributes = 7; + * repeated .IssueLocation locations = 1; */ - 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()); } /** - * optional string attributes = 7; + * repeated .IssueLocation locations = 1; */ - 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 + 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(); /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ boolean hasRange(); /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ - org.sonar.batch.protocol.output.BatchReport.Range getRange(); + org.sonar.batch.protocol.output.BatchReport.TextRange getRange(); /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ - org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getRangeOrBuilder(); + org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getRangeOrBuilder(); /** * optional string other_file_key = 3; @@ -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_; /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ public boolean hasRange() { return ((bitField0_ & 0x00000002) == 0x00000002); } /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ - public org.sonar.batch.protocol.output.BatchReport.Range getRange() { + public org.sonar.batch.protocol.output.BatchReport.TextRange getRange() { return range_; } /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ - 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_; /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ public boolean hasRange() { return ((bitField0_ & 0x00000002) == 0x00000002); } /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ - 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 { } } /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ - 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; } /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ 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; } /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ - 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; } /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ 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; } /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ - 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(); } /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ - 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 { } } /** - * optional .Range range = 2; + * optional .TextRange range = 2; */ 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 { /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
      * Origin position in current file
@@ -10199,21 +12398,21 @@ public final class BatchReport {
      */
     boolean hasOriginPosition();
     /**
-     * optional .Range origin_position = 1;
+     * optional .TextRange origin_position = 1;
      *
      * 
      * Origin position in current file
      * 
*/ - org.sonar.batch.protocol.output.BatchReport.Range getOriginPosition(); + org.sonar.batch.protocol.output.BatchReport.TextRange getOriginPosition(); /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
      * Origin position in current file
      * 
*/ - org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getOriginPositionOrBuilder(); + org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getOriginPositionOrBuilder(); /** * repeated .Duplicate duplicate = 2; @@ -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_; /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
      * Origin position in current file
@@ -10368,23 +12567,23 @@ public final class BatchReport {
       return ((bitField0_ & 0x00000001) == 0x00000001);
     }
     /**
-     * optional .Range origin_position = 1;
+     * optional .TextRange origin_position = 1;
      *
      * 
      * Origin position in current file
      * 
*/ - public org.sonar.batch.protocol.output.BatchReport.Range getOriginPosition() { + public org.sonar.batch.protocol.output.BatchReport.TextRange getOriginPosition() { return originPosition_; } /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
      * Origin position in current file
      * 
*/ - 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_; /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
        * Origin position in current file
@@ -10725,13 +12924,13 @@ public final class BatchReport {
         return ((bitField0_ & 0x00000001) == 0x00000001);
       }
       /**
-       * optional .Range origin_position = 1;
+       * optional .TextRange origin_position = 1;
        *
        * 
        * Origin position in current file
        * 
*/ - 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 { } } /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
        * Origin position in current file
        * 
*/ - 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; } /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
        * Origin position in current file
        * 
*/ 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; } /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
        * Origin position in current file
        * 
*/ - 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; } /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
        * 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;
       }
       /**
-       * optional .Range origin_position = 1;
+       * optional .TextRange origin_position = 1;
        *
        * 
        * Origin position in current file
        * 
*/ - 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(); } /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
        * Origin position in current file
        * 
*/ - 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 { } } /** - * optional .Range origin_position = 1; + * optional .TextRange origin_position = 1; * *
        * Origin position in current file
        * 
*/ 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} * *
    * Lines start at 1 and line offsets start at 0
    * 
*/ - 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 PARSER = - new com.google.protobuf.AbstractParser() { - public Range parsePartialFrom( + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + 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 getParserForType() { + public com.google.protobuf.Parser 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} * *
      * 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 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 {
 
     /**
-     * optional .Range declaration = 1;
+     * optional .TextRange declaration = 1;
      */
     boolean hasDeclaration();
     /**
-     * optional .Range declaration = 1;
+     * optional .TextRange declaration = 1;
      */
-    org.sonar.batch.protocol.output.BatchReport.Range getDeclaration();
+    org.sonar.batch.protocol.output.BatchReport.TextRange getDeclaration();
     /**
-     * optional .Range declaration = 1;
+     * optional .TextRange declaration = 1;
      */
-    org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getDeclarationOrBuilder();
+    org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getDeclarationOrBuilder();
 
     /**
-     * repeated .Range reference = 2;
+     * repeated .TextRange reference = 2;
      */
-    java.util.List 
+    java.util.List 
         getReferenceList();
     /**
-     * repeated .Range reference = 2;
+     * repeated .TextRange reference = 2;
      */
-    org.sonar.batch.protocol.output.BatchReport.Range getReference(int index);
+    org.sonar.batch.protocol.output.BatchReport.TextRange getReference(int index);
     /**
-     * repeated .Range reference = 2;
+     * repeated .TextRange reference = 2;
      */
     int getReferenceCount();
     /**
-     * repeated .Range reference = 2;
+     * repeated .TextRange reference = 2;
      */
-    java.util.List 
+    java.util.List 
         getReferenceOrBuilderList();
     /**
-     * repeated .Range reference = 2;
+     * repeated .TextRange reference = 2;
      */
-    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();
+                reference_ = new java.util.ArrayList();
                 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_;
     /**
-     * optional .Range declaration = 1;
+     * optional .TextRange declaration = 1;
      */
     public boolean hasDeclaration() {
       return ((bitField0_ & 0x00000001) == 0x00000001);
     }
     /**
-     * optional .Range declaration = 1;
+     * optional .TextRange declaration = 1;
      */
-    public org.sonar.batch.protocol.output.BatchReport.Range getDeclaration() {
+    public org.sonar.batch.protocol.output.BatchReport.TextRange getDeclaration() {
       return declaration_;
     }
     /**
-     * optional .Range declaration = 1;
+     * optional .TextRange declaration = 1;
      */
-    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 reference_;
+    private java.util.List reference_;
     /**
-     * repeated .Range reference = 2;
+     * repeated .TextRange reference = 2;
      */
-    public java.util.List getReferenceList() {
+    public java.util.List getReferenceList() {
       return reference_;
     }
     /**
-     * repeated .Range reference = 2;
+     * repeated .TextRange reference = 2;
      */
-    public java.util.List 
+    public java.util.List 
         getReferenceOrBuilderList() {
       return reference_;
     }
     /**
-     * repeated .Range reference = 2;
+     * repeated .TextRange reference = 2;
      */
     public int getReferenceCount() {
       return reference_.size();
     }
     /**
-     * repeated .Range reference = 2;
+     * repeated .TextRange reference = 2;
      */
-    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);
     }
     /**
-     * repeated .Range reference = 2;
+     * repeated .TextRange reference = 2;
      */
-    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_;
       /**
-       * optional .Range declaration = 1;
+       * optional .TextRange declaration = 1;
        */
       public boolean hasDeclaration() {
         return ((bitField0_ & 0x00000001) == 0x00000001);
       }
       /**
-       * optional .Range declaration = 1;
+       * optional .TextRange declaration = 1;
        */
-      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 {
         }
       }
       /**
-       * optional .Range declaration = 1;
+       * optional .TextRange declaration = 1;
        */
-      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;
       }
       /**
-       * optional .Range declaration = 1;
+       * optional .TextRange declaration = 1;
        */
       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;
       }
       /**
-       * optional .Range declaration = 1;
+       * optional .TextRange declaration = 1;
        */
-      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;
       }
       /**
-       * optional .Range declaration = 1;
+       * optional .TextRange declaration = 1;
        */
       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;
       }
       /**
-       * optional .Range declaration = 1;
+       * optional .TextRange declaration = 1;
        */
-      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();
       }
       /**
-       * optional .Range declaration = 1;
+       * optional .TextRange declaration = 1;
        */
-      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 {
         }
       }
       /**
-       * optional .Range declaration = 1;
+       * optional .TextRange declaration = 1;
        */
       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 reference_ =
+      private java.util.List reference_ =
         java.util.Collections.emptyList();
       private void ensureReferenceIsMutable() {
         if (!((bitField0_ & 0x00000002) == 0x00000002)) {
-          reference_ = new java.util.ArrayList(reference_);
+          reference_ = new java.util.ArrayList(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_;
 
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
-      public java.util.List getReferenceList() {
+      public java.util.List getReferenceList() {
         if (referenceBuilder_ == null) {
           return java.util.Collections.unmodifiableList(reference_);
         } else {
@@ -12521,7 +14720,7 @@ public final class BatchReport {
         }
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
       public int getReferenceCount() {
         if (referenceBuilder_ == null) {
@@ -12531,9 +14730,9 @@ public final class BatchReport {
         }
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
-      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 {
         }
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
       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;
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
       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;
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
-      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;
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
       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;
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
       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;
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
       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;
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
       public Builder addAllReference(
-          java.lang.Iterable values) {
+          java.lang.Iterable values) {
         if (referenceBuilder_ == null) {
           ensureReferenceIsMutable();
           com.google.protobuf.AbstractMessageLite.Builder.addAll(
@@ -12648,7 +14847,7 @@ public final class BatchReport {
         return this;
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
       public Builder clearReference() {
         if (referenceBuilder_ == null) {
@@ -12661,7 +14860,7 @@ public final class BatchReport {
         return this;
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
       public Builder removeReference(int index) {
         if (referenceBuilder_ == null) {
@@ -12674,16 +14873,16 @@ public final class BatchReport {
         return this;
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
-      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);
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
-      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 {
         }
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
-      public java.util.List 
+      public java.util.List 
            getReferenceOrBuilderList() {
         if (referenceBuilder_ != null) {
           return referenceBuilder_.getMessageOrBuilderList();
@@ -12702,33 +14901,33 @@ public final class BatchReport {
         }
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
-      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());
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
-      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());
       }
       /**
-       * repeated .Range reference = 2;
+       * repeated .TextRange reference = 2;
        */
-      public java.util.List 
+      public java.util.List 
            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 {
 
     /**
-     * optional .Range range = 1;
+     * optional .TextRange range = 1;
      */
     boolean hasRange();
     /**
-     * optional .Range range = 1;
+     * optional .TextRange range = 1;
      */
-    org.sonar.batch.protocol.output.BatchReport.Range getRange();
+    org.sonar.batch.protocol.output.BatchReport.TextRange getRange();
     /**
-     * optional .Range range = 1;
+     * optional .TextRange range = 1;
      */
-    org.sonar.batch.protocol.output.BatchReport.RangeOrBuilder getRangeOrBuilder();
+    org.sonar.batch.protocol.output.BatchReport.TextRangeOrBuilder getRangeOrBuilder();
 
     /**
      * optional .HighlightingType type = 2;
@@ -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_;
     /**
-     * optional .Range range = 1;
+     * optional .TextRange range = 1;
      */
     public boolean hasRange() {
       return ((bitField0_ & 0x00000001) == 0x00000001);
     }
     /**
-     * optional .Range range = 1;
+     * optional .TextRange range = 1;
      */
-    public org.sonar.batch.protocol.output.BatchReport.Range getRange() {
+    public org.sonar.batch.protocol.output.BatchReport.TextRange getRange() {
       return range_;
     }
     /**
-     * optional .Range range = 1;
+     * optional .TextRange range = 1;
      */
-    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_;
       /**
-       * optional .Range range = 1;
+       * optional .TextRange range = 1;
        */
       public boolean hasRange() {
         return ((bitField0_ & 0x00000001) == 0x00000001);
       }
       /**
-       * optional .Range range = 1;
+       * optional .TextRange range = 1;
        */
-      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 {
         }
       }
       /**
-       * optional .Range range = 1;
+       * optional .TextRange range = 1;
        */
-      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;
       }
       /**
-       * optional .Range range = 1;
+       * optional .TextRange range = 1;
        */
       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;
       }
       /**
-       * optional .Range range = 1;
+       * optional .TextRange range = 1;
        */
-      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;
       }
       /**
-       * optional .Range range = 1;
+       * optional .TextRange range = 1;
        */
       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;
       }
       /**
-       * optional .Range range = 1;
+       * optional .TextRange range = 1;
        */
-      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();
       }
       /**
-       * optional .Range range = 1;
+       * optional .TextRange range = 1;
        */
-      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 {
         }
       }
       /**
-       * optional .Range range = 1;
+       * optional .TextRange range = 1;
        */
       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,
diff --git a/sonar-batch-protocol/src/main/protobuf/batch_report.proto b/sonar-batch-protocol/src/main/protobuf/batch_report.proto
index 1d034a80b95..e973a338021 100644
--- a/sonar-batch-protocol/src/main/protobuf/batch_report.proto
+++ b/sonar-batch-protocol/src/main/protobuf/batch_report.proto
@@ -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;
 }
 
diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportReaderTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportReaderTest.java
index 283933d18bf..19b29fb5f03 100644
--- a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportReaderTest.java
+++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportReaderTest.java
@@ -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)
diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java
index ae1a6cd143e..93a394a59cd 100644
--- a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java
+++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java
@@ -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())
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
index 63dac585a2c..fb39cf956e5 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
@@ -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 INTERNAL_METRICS = Arrays.asList(
-    // Computed by CpdSensor
-    CoreMetrics.DUPLICATED_FILES,
-    CoreMetrics.DUPLICATED_LINES,
-    CoreMetrics.DUPLICATED_BLOCKS,
-    // Computed by LinesSensor
-    CoreMetrics.LINES
-    );
-
-  private static final List DEPRECATED_METRICS_KEYS = Arrays.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 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;
   }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java
index 9dd268a8d22..76970b5c80f 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java
@@ -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 resolvedIssues() {
     List 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 issues() {
     List 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
index 00000000000..99186f95006
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedIssueBuilderWrapper.java
@@ -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 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
index 00000000000..e2773e08658
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedIssueWrapper.java
@@ -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 attributes() {
+    return null;
+  }
+
+  @Override
+  public String authorLogin() {
+    return null;
+  }
+
+  @Override
+  public String actionPlanKey() {
+    return null;
+  }
+
+  @Override
+  public List 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 tags() {
+    return null;
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java b/sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java
index 1fda7c27513..6425abaca60 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java
@@ -19,10 +19,11 @@
  */
 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 {
 
-  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 perspectiveClass, BatchComponent component) {
-    return new DefaultIssuable(component, projectTree.getRootProject(), moduleIssues, cache);
+    return new DefaultIssuable(component, cache, sensorContext);
   }
 }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java b/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
index 73c7604860c..5fad21f0905 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
@@ -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;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
index d1ca1ff324c..c553aeb349a 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
@@ -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;
     }
 
diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java
index 589f2bbe5f2..10341e8dcbe 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java
@@ -19,11 +19,9 @@
  */
 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 issues = new ArrayList<>();
-  private Multimap measures = LinkedHashMultimap.create();
   private Map> duplications = new HashMap<>();
   private Map inputFiles = new HashMap<>();
   private Map 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 measureEntry : container.getComponentByType(MeasureCache.class).entries()) {
-      String componentKey = measureEntry.key()[0].toString();
-      InputPath path = resourceCache.get(componentKey).inputPath();
-      Measure oldMeasure = measureEntry.value();
-      DefaultMeasure 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 allMeasures() {
-    return measures.values();
-  }
-
-  public Collection measures(String componentKey) {
-    return measures.get(componentKey);
-  }
-
   public Collection 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> allMeasures() {
+    Map> result = new HashMap<>();
+    for (Map.Entry component : reportComponents.entrySet()) {
+      List measures = new ArrayList<>();
+      try (CloseableIterator 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 symbolReferencesFor(InputFile file, int symbolStartLine, int symbolStartLineOffset) {
+  public List symbolReferencesFor(InputFile file, int symbolStartLine, int symbolStartLineOffset) {
     int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef();
     try (CloseableIterator symbols = getReportReader().readComponentSymbols(ref)) {
       while (symbols.hasNext()) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java
index b40521f355f..6cf132a9f6e 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java
@@ -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())
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
index fd03094668e..f6bc443c94e 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
@@ -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);
 
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java
index d3caddc45a1..5e79960365c 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java
@@ -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);
     }
   }
 }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
index f1adc47cf10..19bf0f2bc52 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
@@ -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 INTERNAL_METRICS = Arrays.asList(
+    // Computed by CpdSensor
+    CoreMetrics.DUPLICATED_FILES,
+    CoreMetrics.DUPLICATED_LINES,
+    CoreMetrics.DUPLICATED_BLOCKS,
+    // Computed by LinesSensor
+    CoreMetrics.LINES);
+
+  private static final List DEPRECATED_METRICS_KEYS = Arrays.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>, 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> 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 {
     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) {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
index 29cdc0e6f24..d98cd10efeb 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
@@ -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);
   }
 
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java
index 7f50a767efe..5df84297370 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java
@@ -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 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 issues = perspective.resolvedIssues();
     assertThat(issues).containsOnly(resolved);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java
index c124a40fc49..ddabedba240 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java
@@ -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);
 
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
index 356b9f9e436..3199c7c8f03 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
@@ -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 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);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/coverage/CoverageMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/coverage/CoverageMediumTest.java
index e740ea47c00..79de3e1afa2 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/coverage/CoverageMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/coverage/CoverageMediumTest.java
@@ -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()
-      .forMetric(CoreMetrics.LINES_TO_COVER)
-      .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo"))
-      .withValue(2));
-
-    assertThat(result.allMeasures()).contains(new DefaultMeasure()
-      .forMetric(CoreMetrics.UNCOVERED_LINES)
-      .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo"))
-      .withValue(0));
-
-    assertThat(result.allMeasures()).contains(new DefaultMeasure()
-      .forMetric(CoreMetrics.CONDITIONS_TO_COVER)
-      .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo"))
-      .withValue(2));
-
-    assertThat(result.allMeasures()).contains(new DefaultMeasure()
-      .forMetric(CoreMetrics.COVERED_CONDITIONS_BY_LINE)
-      .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo"))
-      .withValue("2=1"));
+    Map> 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> 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);
+
   }
 
 }
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/cpd/CpdMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/cpd/CpdMediumTest.java
index 221b6a88af6..bc4aeb777cb 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/cpd/CpdMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/cpd/CpdMediumTest.java
@@ -20,7 +20,12 @@
 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> 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> 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 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> 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
index 00000000000..749260c4233
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/MultilineIssuesMediumTest.java
@@ -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);
+
+  }
+
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java
index ae97beaec18..f25b28fedc9 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java
@@ -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> allMeasures = result.allMeasures();
 
-    assertThat(result.allMeasures()).contains(new DefaultMeasure()
-      .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> 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));
   }
 
 }
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java
index a9aae88e06c..5f094972269 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java
@@ -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());
   }
 
 }
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ComponentIndexerTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ComponentIndexerTest.java
index df55eddc1f7..016dc1c3c46 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ComponentIndexerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ComponentIndexerTest.java
@@ -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);
   }
 
diff --git a/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
index 69b176538a1..aa2e32f96e6 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
@@ -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 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 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 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 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 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
index 00000000000..0c8e5dc5354
--- /dev/null
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/sonar-project.properties
@@ -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
index 00000000000..0b815e09295
--- /dev/null
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/xources/hello/HelloJava.xoo
@@ -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
index 00000000000..9eaf8ba2549
--- /dev/null
+++ b/sonar-batch/src/test/resources/mediumtest/xoo/sample-multiline/xources/hello/HelloJava.xoo.measures
@@ -0,0 +1,2 @@
+ncloc:3
+complexity:1
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java
index 5990eb41146..caa6f3d8663 100644
--- a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java
+++ b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java
@@ -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;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFile.java
index d98180bf417..fb1f25bdcdf 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFile.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFile.java
@@ -19,12 +19,10 @@
  */
 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);
 }
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
index df42847def6..3c0cb4a243b 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
@@ -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);
   }
 
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
index b264e35ce85..9d574bb86bd 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
@@ -154,24 +154,7 @@ public class SensorContextTester implements SensorContext {
   }
 
   public Collection allIssues() {
-    List 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 issues(@Nullable String componentKey) {
-    if (componentKey != null) {
-      List list = sensorStorage.issuesByComponent.get(componentKey);
-      return list != null ? list : Collections.emptyList();
-    } else {
-      return sensorStorage.projectIssues;
-    }
+    return sensorStorage.allIssues;
   }
 
   @CheckForNull
@@ -272,8 +255,7 @@ public class SensorContextTester implements SensorContext {
     private Map projectMeasuresByMetric = new HashMap<>();
     private Map> measuresByComponentAndMetric = new HashMap<>();
 
-    private Collection projectIssues = new ArrayList<>();
-    private Map> issuesByComponent = new HashMap<>();
+    private Collection allIssues = new ArrayList<>();
 
     private Map highlightingByComponent = new HashMap<>();
     private Map> 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());
-        }
-        issuesByComponent.get(key).add(issue);
-      }
+      allIssues.add(issue);
     }
 
     @Override
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java
index 8a446731c3c..1c519115e29 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java
@@ -20,13 +20,12 @@
 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 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 locations();
 
   /**
-   * Overriden severity.
+   * List of execution flows for this issue. Can be empty.
+   * @since 5.2
    */
-  @CheckForNull
-  Severity overridenSeverity();
+  List 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
index 00000000000..fa587f89cb8
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueLocation.java
@@ -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();
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssue.java
index 8a088f533c7..7c44f331163 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssue.java
@@ -20,14 +20,11 @@
 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
index 00000000000..3ead59ed7f5
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/NewIssueLocation.java
@@ -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.
+   * 

+ * Formats like Markdown or HTML are not supported. Size must not be greater than {@link #MESSAGE_MAX_SIZE} characters. + */ + NewIssueLocation message(String message); + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java index 7eee7b189dd..686677ffb29 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java @@ -19,36 +19,32 @@ */ 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 locations = new ArrayList<>(); + private List> 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 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 locations() { + return ImmutableList.copyOf(this.locations); } @Override - public Double effortToFix() { - return this.effortToFix; - } - - public String key() { - return this.key; + public List executionFlows() { + return Lists.transform(this.executionFlows, new Function, ExecutionFlow>() { + @Override + public ExecutionFlow apply(final List input) { + return new ExecutionFlow() { + @Override + public List 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 index 00000000000..3840cd595f8 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java @@ -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; + } + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java index ef2fe0f6f4e..428d49d56f0 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java @@ -20,13 +20,12 @@ 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. *

* 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 diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java index 596662d861a..99f70ac964b 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java @@ -19,14 +19,13 @@ */ 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)); diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java index eef71735990..8837c6eb6da 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java @@ -19,25 +19,24 @@ */ 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 index 00000000000..6ed1a7aa686 --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocationTest.java @@ -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)); + + } + +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java index 41ebf8e7a5b..e9b27548b35 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java @@ -19,11 +19,11 @@ */ 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); - } - }