From 54beb6267d98d4e7429480bfbfaa70c8d1f73eff Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Fri, 20 Feb 2015 10:53:39 +0100 Subject: [PATCH] SONAR-5931 Cleanup highlighting API --- .../xoo/lang/SyntaxHighlightingSensor.java | 8 +- .../lang/SyntaxHighlightingSensorTest.java | 11 +- .../DefaultHighlightingBuilder.java | 54 --------- .../highlighting/SyntaxHighlightingData.java | 1 + .../SyntaxHighlightingDataBuilder.java | 1 + .../SyntaxHighlightingDataValueCoder.java | 1 + .../SyntaxHighlightingRuleValueCoder.java | 4 +- .../sonar/batch/index/SourceDataFactory.java | 2 +- .../sonar/batch/mediumtest/TaskResult.java | 2 +- .../batch/sensor/DefaultSensorContext.java | 8 +- .../batch/sensor/DefaultSensorStorage.java | 15 ++- .../batch/source/DefaultHighlightable.java | 3 - .../DefaultHighlightingBuilderTest.java | 50 --------- .../SyntaxHighlightingDataBuilderTest.java | 1 + .../SyntaxHighlightingDataTest.java | 1 + .../sonar/api/batch/sensor/SensorContext.java | 6 +- ...htingBuilder.java => NewHighlighting.java} | 18 +-- .../internal/DefaultHighlighting.java | 106 ++++++++++++++++++ .../internal}/SyntaxHighlightingRule.java | 2 +- .../highlighting/internal/package-info.java | 21 ++++ .../batch/sensor/internal/SensorStorage.java | 3 + .../internal/DefaultHighlightingTest.java | 73 ++++++++++++ 22 files changed, 254 insertions(+), 137 deletions(-) delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/highlighting/DefaultHighlightingBuilder.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/highlighting/DefaultHighlightingBuilderTest.java rename sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/{HighlightingBuilder.java => NewHighlighting.java} (83%) create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java rename {sonar-batch/src/main/java/org/sonar/batch/highlighting => sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal}/SyntaxHighlightingRule.java (96%) create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/package-info.java create mode 100644 sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlightingTest.java diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SyntaxHighlightingSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SyntaxHighlightingSensor.java index 549a655573e..8daffb64026 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SyntaxHighlightingSensor.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/SyntaxHighlightingSensor.java @@ -26,7 +26,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.highlighting.HighlightingBuilder; +import org.sonar.api.batch.sensor.highlighting.NewHighlighting; import org.sonar.api.batch.sensor.highlighting.TypeOfText; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; @@ -54,7 +54,7 @@ public class SyntaxHighlightingSensor implements Sensor { try { List lines = FileUtils.readLines(highlightingFile, context.fileSystem().encoding().name()); int lineNumber = 0; - HighlightingBuilder highlightingBuilder = context.highlightingBuilder(inputFile); + NewHighlighting highlightingBuilder = context.newHighlighting().onFile(inputFile); for (String line : lines) { lineNumber++; if (StringUtils.isBlank(line) || line.startsWith("#")) { @@ -62,14 +62,14 @@ public class SyntaxHighlightingSensor implements Sensor { } processLine(highlightingFile, lineNumber, highlightingBuilder, line); } - highlightingBuilder.done(); + highlightingBuilder.save(); } catch (IOException e) { throw new IllegalStateException(e); } } } - private void processLine(File highlightingFile, int lineNumber, HighlightingBuilder highlightingBuilder, String line) { + private void processLine(File highlightingFile, int lineNumber, NewHighlighting highlightingBuilder, String line) { try { Iterator split = Splitter.on(":").split(line).iterator(); int startOffset = Integer.parseInt(split.next()); diff --git a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/SyntaxHighlightingSensorTest.java b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/SyntaxHighlightingSensorTest.java index 559f6b37b08..4bd8aa2da61 100644 --- a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/SyntaxHighlightingSensorTest.java +++ b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/SyntaxHighlightingSensorTest.java @@ -24,16 +24,18 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +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.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; +import org.sonar.api.batch.sensor.highlighting.NewHighlighting; import org.sonar.api.batch.sensor.highlighting.TypeOfText; import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; import java.io.File; import java.io.IOException; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -74,13 +76,14 @@ public class SyntaxHighlightingSensorTest { FileUtils.write(symbol, "1:4:k\n12:15:cppd\n\n#comment"); DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setLanguage("xoo"); fileSystem.add(inputFile); - HighlightingBuilder builder = mock(HighlightingBuilder.class); - when(context.highlightingBuilder(inputFile)).thenReturn(builder); + NewHighlighting builder = mock(NewHighlighting.class); + when(context.newHighlighting()).thenReturn(builder); + when(builder.onFile(any(InputFile.class))).thenReturn(builder); sensor.execute(context); verify(builder).highlight(1, 4, TypeOfText.KEYWORD); verify(builder).highlight(12, 15, TypeOfText.CPP_DOC); - verify(builder).done(); + verify(builder).save(); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/highlighting/DefaultHighlightingBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/DefaultHighlightingBuilder.java deleted file mode 100644 index 6682e32536c..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/highlighting/DefaultHighlightingBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.highlighting; - -import org.sonar.api.batch.sensor.highlighting.TypeOfText; - -import com.google.common.base.Preconditions; -import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; -import org.sonar.batch.index.ComponentDataCache; -import org.sonar.core.source.SnapshotDataTypes; - -public class DefaultHighlightingBuilder implements HighlightingBuilder { - - private final SyntaxHighlightingDataBuilder builder; - private String componentKey; - private ComponentDataCache cache; - private boolean done = false; - - public DefaultHighlightingBuilder(String componentKey, ComponentDataCache cache) { - this.componentKey = componentKey; - this.cache = cache; - this.builder = new SyntaxHighlightingDataBuilder(); - } - - @Override - public HighlightingBuilder highlight(int startOffset, int endOffset, TypeOfText typeOfText) { - Preconditions.checkState(!done, "done() already called"); - builder.registerHighlightingRule(startOffset, endOffset, typeOfText); - return this; - } - - @Override - public void done() { - Preconditions.checkState(!done, "done() already called"); - cache.setData(componentKey, SnapshotDataTypes.SYNTAX_HIGHLIGHTING, builder.build()); - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingData.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingData.java index b1075a9ed19..7b9b334e15a 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingData.java +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingData.java @@ -19,6 +19,7 @@ */ package org.sonar.batch.highlighting; +import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; import org.sonar.batch.index.Data; import java.util.ArrayList; diff --git a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilder.java index da5166a9753..be0fa73a3e9 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilder.java @@ -23,6 +23,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Ordering; import com.google.common.collect.Sets; import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; import javax.annotation.Nullable; diff --git a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataValueCoder.java index 621c1e5c2f5..a748b499d57 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataValueCoder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataValueCoder.java @@ -22,6 +22,7 @@ package org.sonar.batch.highlighting; import com.persistit.Value; import com.persistit.encoding.CoderContext; import com.persistit.encoding.ValueCoder; +import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; import java.util.ArrayList; import java.util.List; diff --git a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRuleValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRuleValueCoder.java index 3d69f717c6b..8700c81f345 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRuleValueCoder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRuleValueCoder.java @@ -19,11 +19,11 @@ */ package org.sonar.batch.highlighting; -import org.sonar.api.batch.sensor.highlighting.TypeOfText; - import com.persistit.Value; import com.persistit.encoding.CoderContext; import com.persistit.encoding.ValueCoder; +import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; class SyntaxHighlightingRuleValueCoder implements ValueCoder { diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/SourceDataFactory.java b/sonar-batch/src/main/java/org/sonar/batch/index/SourceDataFactory.java index 6d1cfc1e7f1..edea3a94051 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/SourceDataFactory.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/SourceDataFactory.java @@ -26,6 +26,7 @@ import org.sonar.api.BatchComponent; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.sensor.duplication.Duplication; import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication; +import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; import org.sonar.api.batch.sensor.symbol.Symbol; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; @@ -33,7 +34,6 @@ import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.KeyValueFormat; import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.highlighting.SyntaxHighlightingData; -import org.sonar.batch.highlighting.SyntaxHighlightingRule; import org.sonar.batch.scan.filesystem.InputFileMetadata; import org.sonar.batch.scan.measure.MeasureCache; import org.sonar.batch.source.CodeColorizers; 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 edde3baad06..8c07b72e5a6 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 @@ -29,6 +29,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency; import org.sonar.api.batch.sensor.duplication.Duplication; import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.symbol.Symbol; import org.sonar.api.issue.Issue; @@ -37,7 +38,6 @@ import org.sonar.api.measures.Measure; import org.sonar.batch.dependency.DependencyCache; import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.highlighting.SyntaxHighlightingData; -import org.sonar.batch.highlighting.SyntaxHighlightingRule; import org.sonar.batch.index.Cache.Entry; import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.issue.IssueCache; diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java index e010b83fca2..73a05a177b5 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java +++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java @@ -29,7 +29,8 @@ import org.sonar.api.batch.sensor.dependency.NewDependency; import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency; import org.sonar.api.batch.sensor.duplication.NewDuplication; import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication; -import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; +import org.sonar.api.batch.sensor.highlighting.NewHighlighting; +import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.batch.sensor.issue.NewIssue; import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; @@ -37,7 +38,6 @@ import org.sonar.api.batch.sensor.measure.NewMeasure; import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; import org.sonar.api.config.Settings; -import org.sonar.batch.highlighting.DefaultHighlightingBuilder; import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.symbol.DefaultSymbolTableBuilder; @@ -93,8 +93,8 @@ public class DefaultSensorContext implements SensorContext { } @Override - public HighlightingBuilder highlightingBuilder(InputFile inputFile) { - return new DefaultHighlightingBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); + public NewHighlighting newHighlighting() { + return new DefaultHighlighting(sensorStorage); } @Override 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 170fd671daf..f91d3cdb25a 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 @@ -19,17 +19,18 @@ */ package org.sonar.batch.sensor; -import org.sonar.api.batch.sensor.internal.SensorStorage; - import com.google.common.base.Preconditions; import org.sonar.api.batch.fs.FileSystem; 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.internal.DefaultInputFile; import org.sonar.api.batch.measure.MetricFinder; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.sensor.duplication.Duplication; import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication; +import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; +import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.Issue.Severity; import org.sonar.api.batch.sensor.measure.Measure; @@ -51,12 +52,14 @@ import org.sonar.api.resources.Resource; import org.sonar.api.resources.Scopes; import org.sonar.api.rule.RuleKey; import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.highlighting.SyntaxHighlightingData; import org.sonar.batch.index.BatchResource; import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.index.DefaultIndex; import org.sonar.batch.index.ResourceCache; import org.sonar.batch.sensor.coverage.CoverageExclusions; import org.sonar.core.component.ComponentKeys; +import org.sonar.core.source.SnapshotDataTypes; public class DefaultSensorStorage implements SensorStorage { @@ -68,6 +71,7 @@ public class DefaultSensorStorage implements SensorStorage { private final CoverageExclusions coverageExclusions; private final DuplicationCache duplicationCache; private final ResourceCache resourceCache; + private final ComponentDataCache componentDataCache; public DefaultSensorStorage(MetricFinder metricFinder, Project project, ResourcePerspectives perspectives, @@ -77,6 +81,7 @@ public class DefaultSensorStorage implements SensorStorage { this.metricFinder = metricFinder; this.project = project; this.perspectives = perspectives; + this.componentDataCache = componentDataCache; this.sonarIndex = sonarIndex; this.coverageExclusions = coverageExclusions; this.duplicationCache = duplicationCache; @@ -238,4 +243,10 @@ public class DefaultSensorStorage implements SensorStorage { public void store(Duplication duplication) { duplicationCache.put(duplication.originBlock().resourceKey(), (DefaultDuplication) duplication); } + + @Override + public void store(DefaultHighlighting highlighting) { + String componentKey = ((DefaultInputFile) highlighting.inputFile()).key(); + componentDataCache.setData(componentKey, SnapshotDataTypes.SYNTAX_HIGHLIGHTING, new SyntaxHighlightingData(highlighting.getSyntaxHighlightingRuleSet())); + } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultHighlightable.java b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultHighlightable.java index 0fbedcaeb22..bef343b872a 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultHighlightable.java +++ b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultHighlightable.java @@ -20,7 +20,6 @@ package org.sonar.batch.source; import org.sonar.api.batch.sensor.highlighting.TypeOfText; - import org.sonar.api.component.Component; import org.sonar.api.source.Highlightable; import org.sonar.batch.highlighting.SyntaxHighlightingDataBuilder; @@ -29,9 +28,7 @@ import org.sonar.core.source.SnapshotDataTypes; /** * @since 3.6 - * @deprecated since 4.5 no more used in batch 2.0 */ -@Deprecated public class DefaultHighlightable implements Highlightable { private final Component component; diff --git a/sonar-batch/src/test/java/org/sonar/batch/highlighting/DefaultHighlightingBuilderTest.java b/sonar-batch/src/test/java/org/sonar/batch/highlighting/DefaultHighlightingBuilderTest.java deleted file mode 100644 index d5875d5c973..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/highlighting/DefaultHighlightingBuilderTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.highlighting; - -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.sonar.api.batch.sensor.highlighting.TypeOfText; -import org.sonar.batch.index.ComponentDataCache; -import org.sonar.core.source.SnapshotDataTypes; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class DefaultHighlightingBuilderTest { - - @Test - public void should_apply_registered_highlighting() throws Exception { - - ComponentDataCache cache = mock(ComponentDataCache.class); - - DefaultHighlightingBuilder highlightable = new DefaultHighlightingBuilder("myComponent", cache); - highlightable - .highlight(0, 10, TypeOfText.KEYWORD) - .highlight(20, 30, TypeOfText.CPP_DOC) - .done(); - - ArgumentCaptor argCaptor = ArgumentCaptor.forClass(SyntaxHighlightingData.class); - verify(cache).setData(eq("myComponent"), eq(SnapshotDataTypes.SYNTAX_HIGHLIGHTING), argCaptor.capture()); - assertThat(argCaptor.getValue().writeString()).isEqualTo("0,10,k;20,30,cppd"); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilderTest.java b/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilderTest.java index 40a8d5164f1..b4c4828b204 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilderTest.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; import java.util.Collection; diff --git a/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataTest.java b/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataTest.java index cf8e825e5cb..dcebfe2893e 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataTest.java @@ -21,6 +21,7 @@ package org.sonar.batch.highlighting; import com.google.common.collect.Lists; import org.junit.Test; +import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; import java.util.List; diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java index bd15a900398..b07a14560a2 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java @@ -26,7 +26,7 @@ import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.sensor.dependency.NewDependency; import org.sonar.api.batch.sensor.duplication.NewDuplication; -import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; +import org.sonar.api.batch.sensor.highlighting.NewHighlighting; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.NewIssue; import org.sonar.api.batch.sensor.measure.Measure; @@ -79,9 +79,9 @@ public interface SensorContext { // ------------ HIGHLIGHTING ------------ /** - * Builder to define highlighting of a file. + * Builder to define highlighting of a file. Don't forget to call {@link NewHighlighting#save()} once all elements are provided. */ - HighlightingBuilder highlightingBuilder(InputFile inputFile); + NewHighlighting newHighlighting(); // ------------ SYMBOL REFERENCES ------------ diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/HighlightingBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/NewHighlighting.java similarity index 83% rename from sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/HighlightingBuilder.java rename to sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/NewHighlighting.java index aef7d5393a7..2066ce8ffeb 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/HighlightingBuilder.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/NewHighlighting.java @@ -19,16 +19,18 @@ */ package org.sonar.api.batch.sensor.highlighting; -import com.google.common.annotations.Beta; +import org.sonar.api.batch.fs.InputFile; /** - * Experimental, do not use. - *

* This builder is used to define syntax highlighting (aka code coloration) on files. - * @since 4.5 + * @since 5.1 */ -@Beta -public interface HighlightingBuilder { +public interface NewHighlighting { + + /** + * The file the highlighting belongs to. + */ + NewHighlighting onFile(InputFile inputFile); /** * Call this method to indicate the type of text in a range. @@ -36,11 +38,11 @@ public interface HighlightingBuilder { * @param endOffset End position in file for this type of text. * @param typeOfText see {@link TypeOfText} values. */ - HighlightingBuilder highlight(int startOffset, int endOffset, TypeOfText typeOfText); + NewHighlighting highlight(int startOffset, int endOffset, TypeOfText typeOfText); /** * Call this method only once when your are done with defining highlighting of the file. * @throws IllegalStateException if you have defined overlapping highlighting */ - void done(); + void save(); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java new file mode 100644 index 00000000000..9849c058335 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java @@ -0,0 +1,106 @@ +/* + * 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.highlighting.internal; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Ordering; +import com.google.common.collect.Sets; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.highlighting.NewHighlighting; +import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.api.batch.sensor.internal.DefaultStorable; +import org.sonar.api.batch.sensor.internal.SensorStorage; + +import javax.annotation.Nullable; + +import java.util.Iterator; +import java.util.Set; + +public class DefaultHighlighting extends DefaultStorable implements NewHighlighting { + + private InputFile inputFile; + private Set syntaxHighlightingRuleSet; + + public DefaultHighlighting() { + this(null); + } + + public DefaultHighlighting(@Nullable SensorStorage storage) { + super(storage); + syntaxHighlightingRuleSet = Sets.newTreeSet(new Ordering() { + @Override + public int compare(@Nullable SyntaxHighlightingRule left, + @Nullable SyntaxHighlightingRule right) { + int result = left.getStartPosition() - right.getStartPosition(); + if (result == 0) { + result = right.getEndPosition() - left.getEndPosition(); + } + return result; + } + }); + } + + public Set getSyntaxHighlightingRuleSet() { + return syntaxHighlightingRuleSet; + } + + private void checkOverlappingBoudaries() { + if (syntaxHighlightingRuleSet.size() > 1) { + Iterator it = syntaxHighlightingRuleSet.iterator(); + SyntaxHighlightingRule previous = it.next(); + while (it.hasNext()) { + SyntaxHighlightingRule current = it.next(); + if (previous.getEndPosition() > current.getStartPosition() && !(previous.getEndPosition() >= current.getEndPosition())) { + String errorMsg = String.format("Cannot register highlighting rule for characters from %s to %s as it " + + "overlaps at least one existing rule", current.getStartPosition(), current.getEndPosition()); + throw new IllegalStateException(errorMsg); + } + previous = current; + } + } + } + + @Override + public DefaultHighlighting onFile(InputFile inputFile) { + Preconditions.checkNotNull(inputFile, "file can't be null"); + this.inputFile = inputFile; + return this; + } + + public InputFile inputFile() { + return inputFile; + } + + @Override + public DefaultHighlighting highlight(int startOffset, int endOffset, TypeOfText typeOfText) { + Preconditions.checkState(inputFile != null, "Call onFile() first"); + SyntaxHighlightingRule syntaxHighlightingRule = SyntaxHighlightingRule.create(startOffset, endOffset, + typeOfText); + this.syntaxHighlightingRuleSet.add(syntaxHighlightingRule); + return this; + } + + @Override + protected void doSave() { + Preconditions.checkState(inputFile != null, "Call onFile() first"); + checkOverlappingBoudaries(); + storage.store(this); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/SyntaxHighlightingRule.java similarity index 96% rename from sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRule.java rename to sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/SyntaxHighlightingRule.java index 81016289477..9989449ff00 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRule.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/SyntaxHighlightingRule.java @@ -17,7 +17,7 @@ * 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.highlighting; +package org.sonar.api.batch.sensor.highlighting.internal; import org.sonar.api.batch.sensor.highlighting.TypeOfText; diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/package-info.java new file mode 100644 index 00000000000..964bc08744f --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ +@javax.annotation.ParametersAreNonnullByDefault +package org.sonar.api.batch.sensor.highlighting.internal; diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorStorage.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorStorage.java index 69b79f7addf..850d3e6cdc7 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorStorage.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorStorage.java @@ -21,6 +21,7 @@ package org.sonar.api.batch.sensor.internal; import org.sonar.api.batch.sensor.dependency.Dependency; import org.sonar.api.batch.sensor.duplication.Duplication; +import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.measure.Measure; @@ -38,4 +39,6 @@ public interface SensorStorage { void store(Dependency dependency); + void store(DefaultHighlighting highlighting); + } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlightingTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlightingTest.java new file mode 100644 index 00000000000..2770df6cb31 --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlightingTest.java @@ -0,0 +1,73 @@ +package org.sonar.api.batch.sensor.highlighting.internal; + +import org.junit.Before; +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.sensor.internal.SensorStorage; + +import java.util.Collection; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.sonar.api.batch.sensor.highlighting.TypeOfText.COMMENT; +import static org.sonar.api.batch.sensor.highlighting.TypeOfText.CPP_DOC; +import static org.sonar.api.batch.sensor.highlighting.TypeOfText.KEYWORD; + +public class DefaultHighlightingTest { + + private Collection highlightingRules; + + @Rule + public ExpectedException throwable = ExpectedException.none(); + + @Before + public void setUpSampleRules() { + + DefaultHighlighting highlightingDataBuilder = new DefaultHighlighting() + .onFile(new DefaultInputFile("foo", "src/Foo.java")) + .highlight(0, 10, COMMENT) + .highlight(10, 12, KEYWORD) + .highlight(24, 38, KEYWORD) + .highlight(42, 50, KEYWORD) + .highlight(24, 65, CPP_DOC) + .highlight(12, 20, COMMENT); + + highlightingRules = highlightingDataBuilder.getSyntaxHighlightingRuleSet(); + } + + @Test + public void should_register_highlighting_rule() throws Exception { + assertThat(highlightingRules).hasSize(6); + } + + @Test + public void should_order_by_start_then_end_offset() throws Exception { + assertThat(highlightingRules).extracting("startPosition").containsOnly(0, 10, 12, 24, 24, 42); + assertThat(highlightingRules).extracting("endPosition").containsOnly(10, 12, 20, 38, 65, 50); + assertThat(highlightingRules).extracting("textType").containsOnly(COMMENT, KEYWORD, COMMENT, KEYWORD, CPP_DOC, KEYWORD); + } + + @Test + public void should_suport_overlapping() throws Exception { + new DefaultHighlighting(mock(SensorStorage.class)) + .onFile(new DefaultInputFile("foo", "src/Foo.java")) + .highlight(0, 15, KEYWORD) + .highlight(8, 12, CPP_DOC) + .save(); + } + + @Test + public void should_prevent_boudaries_overlapping() throws Exception { + throwable.expect(IllegalStateException.class); + throwable.expectMessage("Cannot register highlighting rule for characters from 8 to 15 as it overlaps at least one existing rule"); + + new DefaultHighlighting(mock(SensorStorage.class)) + .onFile(new DefaultInputFile("foo", "src/Foo.java")) + .highlight(0, 10, KEYWORD) + .highlight(8, 15, KEYWORD) + .save(); + } + +} -- 2.39.5