diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2015-06-08 16:40:48 +0200 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2015-07-23 13:56:46 +0200 |
commit | 056b4bdc63c2ef126d9f9d2e0526f60be930cb81 (patch) | |
tree | 197ba8a832ab132a2e95c86bebdb1e61576c5e98 /plugins | |
parent | db4af09e8b2c1f44f25a689c3165f5f6d8c01126 (diff) | |
download | sonarqube-056b4bdc63c2ef126d9f9d2e0526f60be930cb81.tar.gz sonarqube-056b4bdc63c2ef126d9f9d2e0526f60be930cb81.zip |
SONAR-4865, SONAR-6052 Improved issue locations
Diffstat (limited to 'plugins')
9 files changed, 159 insertions, 28 deletions
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<Integer, Map<Integer, TextPointer>> startPositions = new HashMap<>(); + Map<Integer, Map<Integer, TextPointer>> endPositions = new HashMap<>(); + + RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY); + int currentLine = 0; + try { + for (String lineStr : Files.readAllLines(file.path(), context.fileSystem().encoding())) { + currentLine++; + + Matcher m = startPattern.matcher(lineStr); + while (m.find()) { + Integer issueId = Integer.parseInt(m.group(1)); + Integer issueLocationId = Integer.parseInt(m.group(2)); + TextPointer newPointer = file.newPointer(currentLine, m.start()); + if (!startPositions.containsKey(issueId)) { + startPositions.put(issueId, new HashMap<Integer, TextPointer>()); + } + startPositions.get(issueId).put(issueLocationId, newPointer); + } + + m = endPattern.matcher(lineStr); + while (m.find()) { + Integer issueId = Integer.parseInt(m.group(1)); + Integer issueLocationId = Integer.parseInt(m.group(2)); + TextPointer newPointer = file.newPointer(currentLine, m.start()); + if (!endPositions.containsKey(issueId)) { + endPositions.put(issueId, new HashMap<Integer, TextPointer>()); + } + endPositions.get(issueId).put(issueLocationId, newPointer); + } + } + } catch (IOException e) { + throw new IllegalStateException("Unable to read file", e); + } + for (Map.Entry<Integer, Map<Integer, TextPointer>> entry : startPositions.entrySet()) { + NewIssue newIssue = context.newIssue().forRule(ruleKey); + for (Map.Entry<Integer, TextPointer> location : entry.getValue().entrySet()) { + newIssue.addLocation(newIssue.newLocation() + .onFile(file) + .at(file.newRange(location.getValue(), endPositions.get(entry.getKey()).get(location.getKey()))) + .message("Multiline issue")); + } + newIssue.save(); + } + } + +} 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<DefaultIssue> argCaptor = ArgumentCaptor.forClass(DefaultIssue.class); verify(sensorStorage, times(10)).store(argCaptor.capture()); assertThat(argCaptor.getAllValues()).hasSize(10); // One issue per line - assertThat(argCaptor.getValue().overridenSeverity()).isNull(); + assertThat(argCaptor.getValue().overriddenSeverity()).isNull(); } @Test public void testForceSeverity() throws IOException { DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder().toPath()); - DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.xoo").setLanguage(Xoo.KEY).setLines(10); + DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.xoo").setLanguage(Xoo.KEY) + .initMetadata(new FileMetadata().readMetadata(new StringReader("a\nb\nc\nd\ne\nf\ng\nh\ni\n"))); fs.add(inputFile); SensorContext context = mock(SensorContext.class); @@ -105,7 +108,7 @@ public class OneIssuePerLineSensorTest { ArgumentCaptor<DefaultIssue> argCaptor = ArgumentCaptor.forClass(DefaultIssue.class); verify(sensorStorage, times(10)).store(argCaptor.capture()); assertThat(argCaptor.getAllValues()).hasSize(10); // One issue per line - assertThat(argCaptor.getValue().overridenSeverity()).isEqualTo(Severity.MINOR); + assertThat(argCaptor.getValue().overriddenSeverity()).isEqualTo(Severity.MINOR); } } |