From 1241f18a7b389336ce1eb98fe024f8db0bc5c627 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Mon, 17 Sep 2018 16:59:39 +0200 Subject: [PATCH] SONAR-11259 Improve source offset handling on Windows * Trying to create a range in the middle of a \r\n sequence will now automatically be adapted to exclude the eol * Fix a few other tests on Windows --- .../xoo/rule/AnalysisErrorSensorTest.java | 6 +- .../org/sonar/process/FileUtils2Test.java | 1 + .../batch/fs/internal/DefaultIndexedFile.java | 6 +- .../batch/fs/internal/DefaultInputFile.java | 34 +++++---- .../api/batch/fs/internal/FileMetadata.java | 6 +- .../sonar/api/batch/fs/internal/Metadata.java | 75 +++++++++++-------- .../fs/internal/TestInputFileBuilder.java | 29 ++++--- .../charhandler/LineOffsetCounter.java | 34 ++++++--- .../fs/internal/DefaultInputFileTest.java | 25 ++++--- .../batch/fs/internal/FileMetadataTest.java | 45 ++++++----- .../api/batch/fs/internal/MetadataTest.java | 8 +- .../cpd/internal/DefaultCpdTokensTest.java | 7 +- .../internal/DefaultHighlightingTest.java | 5 +- .../internal/DefaultSymbolTableTest.java | 5 +- .../scanner/report/ComponentsPublisher.java | 5 +- .../scan/filesystem/InputFileBuilder.java | 4 +- .../scanner/DefaultFileLinesContextTest.java | 4 +- .../report/ComponentsPublisherTest.java | 17 ++--- .../filesystem/MetadataGeneratorTest.java | 3 +- 19 files changed, 188 insertions(+), 131 deletions(-) diff --git a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/AnalysisErrorSensorTest.java b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/AnalysisErrorSensorTest.java index 396538ffee5..4eb1855c8c3 100644 --- a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/AnalysisErrorSensorTest.java +++ b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/rule/AnalysisErrorSensorTest.java @@ -65,10 +65,12 @@ public class AnalysisErrorSensorTest { Path baseDir = temp.newFolder().toPath().toAbsolutePath(); createErrorFile(baseDir); - int[] offsets = {10, 20, 30, 40}; + int[] startOffsets = {10, 20, 30, 40}; + int[] endOffsets = {19, 29, 39, 49}; DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/foo.xoo") .setLanguage("xoo") - .setOriginalLineOffsets(offsets) + .setOriginalLineStartOffsets(startOffsets) + .setOriginalLineEndOffsets(endOffsets) .setModuleBaseDir(baseDir) .setLines(4) .build(); diff --git a/server/sonar-process/src/test/java/org/sonar/process/FileUtils2Test.java b/server/sonar-process/src/test/java/org/sonar/process/FileUtils2Test.java index 2c7b9af0845..b36f46f200d 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/FileUtils2Test.java +++ b/server/sonar-process/src/test/java/org/sonar/process/FileUtils2Test.java @@ -283,6 +283,7 @@ public class FileUtils2Test { @Test public void sizeOf_ignores_size_of_non_regular_files() throws IOException { + assumeTrue(SystemUtils.IS_OS_UNIX); File outside = temporaryFolder.newFile(); FileUtils.write(outside, "outside!!!", UTF_8); File dir = temporaryFolder.newFolder(); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultIndexedFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultIndexedFile.java index 8dc6a48e0f3..18e7f4db12d 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultIndexedFile.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultIndexedFile.java @@ -49,7 +49,7 @@ public class DefaultIndexedFile extends DefaultInputComponent implements Indexed * Testing purposes only! */ public DefaultIndexedFile(String moduleKey, Path baseDir, String relativePath, @Nullable String language) { - this(baseDir.resolve(relativePath), moduleKey, PathUtils.sanitize(relativePath), PathUtils.sanitize(relativePath), Type.MAIN, language, TestInputFileBuilder.nextBatchId(), + this(baseDir.resolve(relativePath), moduleKey, relativePath, relativePath, Type.MAIN, language, TestInputFileBuilder.nextBatchId(), new SensorStrategy()); } @@ -57,8 +57,8 @@ public class DefaultIndexedFile extends DefaultInputComponent implements Indexed SensorStrategy sensorStrategy) { super(batchId); this.moduleKey = moduleKey; - this.projectRelativePath = projectRelativePath; - this.moduleRelativePath = moduleRelativePath; + this.projectRelativePath = PathUtils.sanitize(projectRelativePath); + this.moduleRelativePath = PathUtils.sanitize(moduleRelativePath); this.type = type; this.language = language; this.sensorStrategy = sensorStrategy; 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 6ee00d025a0..eecece92d06 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 @@ -203,7 +203,7 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile @Override public boolean isEmpty() { checkMetadata(); - return metadata.lastValidOffset() == 0; + return metadata.isEmpty(); } @Override @@ -214,7 +214,6 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile public int lastValidOffset() { checkMetadata(); - Preconditions.checkState(metadata.lastValidOffset() >= 0, "InputFile is not properly initialized."); return metadata.lastValidOffset(); } @@ -231,12 +230,20 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile return metadata.nonBlankLines(); } - public int[] originalLineOffsets() { + public int[] originalLineStartOffsets() { checkMetadata(); - Preconditions.checkState(metadata.originalLineOffsets() != null, "InputFile is not properly initialized."); - Preconditions.checkState(metadata.originalLineOffsets().length == metadata.lines(), - "InputFile is not properly initialized. 'originalLineOffsets' property length should be equal to 'lines'"); - return metadata.originalLineOffsets(); + Preconditions.checkState(metadata.originalLineStartOffsets() != null, "InputFile is not properly initialized."); + Preconditions.checkState(metadata.originalLineStartOffsets().length == metadata.lines(), + "InputFile is not properly initialized. 'originalLineStartOffsets' property length should be equal to 'lines'"); + return metadata.originalLineStartOffsets(); + } + + public int[] originalLineEndOffsets() { + checkMetadata(); + Preconditions.checkState(metadata.originalLineEndOffsets() != null, "InputFile is not properly initialized."); + Preconditions.checkState(metadata.originalLineEndOffsets().length == metadata.lines(), + "InputFile is not properly initialized. 'originalLineEndOffsets' property length should be equal to 'lines'"); + return metadata.originalLineEndOffsets(); } @Override @@ -290,8 +297,9 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile Preconditions.checkArgument(globalOffset >= 0, "%s is not a valid offset for a file", globalOffset); Preconditions.checkArgument(globalOffset <= lastValidOffset(), "%s is not a valid offset for file %s. Max offset is %s", globalOffset, this, lastValidOffset()); int line = findLine(globalOffset); - int startLineOffset = originalLineOffsets()[line - 1]; - return new DefaultTextPointer(line, globalOffset - startLineOffset); + int startLineOffset = originalLineStartOffsets()[line - 1]; + // In case the global offset is between \r and \n, move the pointer to a valid location + return new DefaultTextPointer(line, Math.min(globalOffset, originalLineEndOffsets()[line -1]) - startLineOffset); } public DefaultInputFile setStatus(Status status) { @@ -314,11 +322,7 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile } private int lineLength(int line) { - return lastValidGlobalOffsetForLine(line) - originalLineOffsets()[line - 1]; - } - - private int lastValidGlobalOffsetForLine(int line) { - return line < this.metadata.lines() ? (originalLineOffsets()[line] - 1) : lastValidOffset(); + return originalLineEndOffsets()[line - 1] - originalLineStartOffsets()[line - 1]; } private static TextRange newRangeValidPointers(TextPointer start, TextPointer end, boolean acceptEmptyRange) { @@ -328,7 +332,7 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile } private int findLine(int globalOffset) { - return Math.abs(Arrays.binarySearch(originalLineOffsets(), globalOffset) + 1); + return Math.abs(Arrays.binarySearch(originalLineStartOffsets(), globalOffset) + 1); } public DefaultInputFile setMetadata(Metadata metadata) { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java index 53ebc3fa2e0..ac3eb019ac9 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java @@ -64,7 +64,8 @@ public class FileMetadata { CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter}; readFile(stream, encoding, filePath, handlers); } - return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineOffsets(), + return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineStartOffsets(), + lineOffsetCounter.getOriginalLineEndOffsets(), lineOffsetCounter.getLastValidOffset()); } @@ -86,7 +87,8 @@ public class FileMetadata { } catch (IOException e) { throw new IllegalStateException("Should never occur", e); } - return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineOffsets(), + return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineStartOffsets(), + lineOffsetCounter.getOriginalLineEndOffsets(), lineOffsetCounter.getLastValidOffset()); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/Metadata.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/Metadata.java index 1b41b523a87..b917af0c81b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/Metadata.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/Metadata.java @@ -25,38 +25,47 @@ import javax.annotation.concurrent.Immutable; @Immutable public class Metadata { - private final int lines; - private final int nonBlankLines; - private final String hash; - private final int[] originalLineOffsets; - private final int lastValidOffset; - - public Metadata(int lines, int nonBlankLines, String hash, int[] originalLineOffsets, int lastValidOffset) { - this.lines = lines; - this.nonBlankLines = nonBlankLines; - this.hash = hash; - this.originalLineOffsets = Arrays.copyOf(originalLineOffsets, originalLineOffsets.length); - this.lastValidOffset = lastValidOffset; - } - - public int lines() { - return lines; - } - - public int nonBlankLines() { - return nonBlankLines; - } - - public String hash() { - return hash; - } - - public int[] originalLineOffsets() { - return originalLineOffsets; - } - - public int lastValidOffset() { - return lastValidOffset; - } + private final int lines; + private final int nonBlankLines; + private final String hash; + private final int[] originalLineStartOffsets; + private final int[] originalLineEndOffsets; + private final int lastValidOffset; + public Metadata(int lines, int nonBlankLines, String hash, int[] originalLineStartOffsets, int[] originalLineEndOffsets, int lastValidOffset) { + this.lines = lines; + this.nonBlankLines = nonBlankLines; + this.hash = hash; + this.originalLineStartOffsets = Arrays.copyOf(originalLineStartOffsets, originalLineStartOffsets.length); + this.originalLineEndOffsets = Arrays.copyOf(originalLineEndOffsets, originalLineEndOffsets.length); + this.lastValidOffset = lastValidOffset; + } + + public int lines() { + return lines; + } + + public int nonBlankLines() { + return nonBlankLines; + } + + public String hash() { + return hash; + } + + public int[] originalLineStartOffsets() { + return originalLineStartOffsets; + } + + public int[] originalLineEndOffsets() { + return originalLineEndOffsets; + } + + public int lastValidOffset() { + return lastValidOffset; + } + + public boolean isEmpty() { + return lastValidOffset == 0; + } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TestInputFileBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TestInputFileBuilder.java index 8d751371bd3..fa057451e24 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TestInputFileBuilder.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TestInputFileBuilder.java @@ -65,10 +65,11 @@ public class TestInputFileBuilder { private InputFile.Status status; private int lines = -1; private Charset charset; - private int lastValidOffset = -1; private String hash; private int nonBlankLines; - private int[] originalLineOffsets = new int[0]; + private int[] originalLineStartOffsets = new int[0]; + private int[] originalLineEndOffsets = new int[0]; + private int lastValidOffset = -1; private boolean publish = true; private String contents; @@ -155,11 +156,6 @@ public class TestInputFileBuilder { return this; } - public TestInputFileBuilder setLastValidOffset(int lastValidOffset) { - this.lastValidOffset = lastValidOffset; - return this; - } - public TestInputFileBuilder setHash(String hash) { this.hash = hash; return this; @@ -181,8 +177,18 @@ public class TestInputFileBuilder { return this; } - public TestInputFileBuilder setOriginalLineOffsets(int[] originalLineOffsets) { - this.originalLineOffsets = originalLineOffsets; + public TestInputFileBuilder setLastValidOffset(int lastValidOffset) { + this.lastValidOffset = lastValidOffset; + return this; + } + + public TestInputFileBuilder setOriginalLineStartOffsets(int[] originalLineStartOffsets) { + this.originalLineStartOffsets = originalLineStartOffsets; + return this; + } + + public TestInputFileBuilder setOriginalLineEndOffsets(int[] originalLineEndOffsets) { + this.originalLineEndOffsets = originalLineEndOffsets; return this; } @@ -196,7 +202,8 @@ public class TestInputFileBuilder { this.setLastValidOffset(metadata.lastValidOffset()); this.setNonBlankLines(metadata.nonBlankLines()); this.setHash(metadata.hash()); - this.setOriginalLineOffsets(metadata.originalLineOffsets()); + this.setOriginalLineStartOffsets(metadata.originalLineStartOffsets()); + this.setOriginalLineEndOffsets(metadata.originalLineEndOffsets()); return this; } @@ -212,7 +219,7 @@ public class TestInputFileBuilder { String projectRelativePath = projectBaseDir.relativize(absolutePath).toString(); DefaultIndexedFile indexedFile = new DefaultIndexedFile(absolutePath, moduleKey, projectRelativePath, relativePath, type, language, id, new SensorStrategy()); DefaultInputFile inputFile = new DefaultInputFile(indexedFile, - f -> f.setMetadata(new Metadata(lines, nonBlankLines, hash, originalLineOffsets, lastValidOffset)), + f -> f.setMetadata(new Metadata(lines, nonBlankLines, hash, originalLineStartOffsets, originalLineEndOffsets, lastValidOffset)), contents); inputFile.setStatus(status); inputFile.setCharset(charset); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineOffsetCounter.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineOffsetCounter.java index dd16a92e63b..e8f1c5b6dcb 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineOffsetCounter.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineOffsetCounter.java @@ -20,34 +20,48 @@ package org.sonar.api.batch.fs.internal.charhandler; public class LineOffsetCounter extends CharHandler { - private long currentOriginalOffset = 0; - private IntArrayList originalLineOffsets = new IntArrayList(); + private long currentOriginalLineStartOffset = 0; + private long currentOriginalLineEndOffset = 0; + private final IntArrayList originalLineStartOffsets = new IntArrayList(); + private final IntArrayList originalLineEndOffsets = new IntArrayList(); private long lastValidOffset = 0; public LineOffsetCounter() { - originalLineOffsets.add(0); + originalLineStartOffsets.add(0); } @Override public void handleAll(char c) { - currentOriginalOffset++; + currentOriginalLineStartOffset++; + } + + @Override + public void handleIgnoreEoL(char c) { + currentOriginalLineEndOffset++; } @Override public void newLine() { - if (currentOriginalOffset > Integer.MAX_VALUE) { - throw new IllegalStateException("File is too big: " + currentOriginalOffset); + if (currentOriginalLineStartOffset > Integer.MAX_VALUE) { + throw new IllegalStateException("File is too big: " + currentOriginalLineStartOffset); } - originalLineOffsets.add((int) currentOriginalOffset); + originalLineStartOffsets.add((int) currentOriginalLineStartOffset); + originalLineEndOffsets.add((int) currentOriginalLineEndOffset); + currentOriginalLineEndOffset = currentOriginalLineStartOffset; } @Override public void eof() { - lastValidOffset = currentOriginalOffset; + originalLineEndOffsets.add((int) currentOriginalLineEndOffset); + lastValidOffset = currentOriginalLineStartOffset; + } + + public int[] getOriginalLineStartOffsets() { + return originalLineStartOffsets.trimAndGet(); } - public int[] getOriginalLineOffsets() { - return originalLineOffsets.trimAndGet(); + public int[] getOriginalLineEndOffsets() { + return originalLineEndOffsets.trimAndGet(); } public int getLastValidOffset() { 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 77b5ed2ac70..0a9bb7a8373 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 @@ -69,7 +69,7 @@ public class DefaultInputFileTest { @Test public void test() throws Exception { - Metadata metadata = new Metadata(42, 42, "", new int[0], 0); + Metadata metadata = new Metadata(42, 42, "", new int[0], new int[0], 10); DefaultInputFile inputFile = new DefaultInputFile(indexedFile, (f) -> f.setMetadata(metadata)) .setStatus(InputFile.Status.ADDED) .setCharset(StandardCharsets.ISO_8859_1); @@ -103,7 +103,7 @@ public class DefaultInputFileTest { assertThat(Files.readAllLines(testFile, StandardCharsets.ISO_8859_1).get(0)).hasSize(content.length()); - Metadata metadata = new Metadata(42, 30, "", new int[0], 0); + Metadata metadata = new Metadata(42, 30, "", new int[0], new int[0], 10); DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> f.setMetadata(metadata)) .setStatus(InputFile.Status.ADDED) @@ -129,7 +129,7 @@ public class DefaultInputFileTest { assertThat(Files.readAllLines(testFile, StandardCharsets.UTF_8).get(0)).hasSize(content.length() + 1); - Metadata metadata = new Metadata(42, 30, "", new int[0], 0); + Metadata metadata = new Metadata(42, 30, "", new int[0], new int[0], 10); DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> f.setMetadata(metadata)) .setStatus(InputFile.Status.ADDED) @@ -167,7 +167,7 @@ public class DefaultInputFileTest { @Test public void checkValidPointer() { - Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, 15); + Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {9, 15}, 16); DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata)); assertThat(file.newPointer(1, 0).line()).isEqualTo(1); assertThat(file.newPointer(1, 0).lineOffset()).isEqualTo(0); @@ -204,13 +204,14 @@ public class DefaultInputFileTest { @Test public void checkValidPointerUsingGlobalOffset() { - Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, 15); + Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {8, 15}, 16); DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata)); assertThat(file.newPointer(0).line()).isEqualTo(1); assertThat(file.newPointer(0).lineOffset()).isEqualTo(0); assertThat(file.newPointer(9).line()).isEqualTo(1); - assertThat(file.newPointer(9).lineOffset()).isEqualTo(9); + // Ignore eol characters + assertThat(file.newPointer(9).lineOffset()).isEqualTo(8); assertThat(file.newPointer(10).line()).isEqualTo(2); assertThat(file.newPointer(10).lineOffset()).isEqualTo(0); @@ -218,6 +219,10 @@ public class DefaultInputFileTest { assertThat(file.newPointer(15).line()).isEqualTo(2); assertThat(file.newPointer(15).lineOffset()).isEqualTo(5); + assertThat(file.newPointer(16).line()).isEqualTo(2); + // Ignore eol characters + assertThat(file.newPointer(16).lineOffset()).isEqualTo(5); + try { file.newPointer(-1); fail(); @@ -226,10 +231,10 @@ public class DefaultInputFileTest { } try { - file.newPointer(16); + file.newPointer(17); fail(); } catch (Exception e) { - assertThat(e).hasMessage("16 is not a valid offset for file src/Foo.php. Max offset is 15"); + assertThat(e).hasMessage("17 is not a valid offset for file src/Foo.php. Max offset is 16"); } } @@ -285,7 +290,7 @@ public class DefaultInputFileTest { @Test public void checkValidRangeUsingGlobalOffset() { - Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, 15); + Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {9, 15}, 16); DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata)); TextRange newRange = file.newRange(10, 13); assertThat(newRange.start().line()).isEqualTo(2); @@ -296,7 +301,7 @@ public class DefaultInputFileTest { @Test public void testRangeOverlap() { - Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, 15); + Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {9, 15}, 16); DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata)); // Don't fail assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)))).isTrue(); diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/FileMetadataTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/FileMetadataTest.java index bc3237510bb..d2934e97af5 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/FileMetadataTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/FileMetadataTest.java @@ -59,8 +59,9 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(1); assertThat(metadata.nonBlankLines()).isEqualTo(0); assertThat(metadata.hash()).isNotEmpty(); - assertThat(metadata.originalLineOffsets()).containsOnly(0); - assertThat(metadata.lastValidOffset()).isEqualTo(0); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0); + assertThat(metadata.originalLineEndOffsets()).containsOnly(0); + assertThat(metadata.isEmpty()).isTrue(); } @Test @@ -72,8 +73,9 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(3); assertThat(metadata.nonBlankLines()).isEqualTo(3); assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 5, 10); - assertThat(metadata.lastValidOffset()).isEqualTo(13); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 5, 10); + assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 8, 13); + assertThat(metadata.isEmpty()).isFalse(); } @Test @@ -84,7 +86,7 @@ public class FileMetadataTest { Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName()); assertThat(metadata.lines()).isEqualTo(2); assertThat(metadata.hash()).isEqualTo(md5Hex("marker\ufffds\n")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 9); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 9); } @Test @@ -96,7 +98,7 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(4); assertThat(metadata.nonBlankLines()).isEqualTo(3); assertThat(metadata.hash()).isEqualTo(md5Hex("föo\nbàr\n\u1D11Ebaßz\n")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 5, 10, 18); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 5, 10, 18); } @Test @@ -107,7 +109,7 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(4); assertThat(metadata.nonBlankLines()).isEqualTo(3); assertThat(metadata.hash()).isEqualTo(md5Hex("föo\nbàr\n\u1D11Ebaßz\n".getBytes(StandardCharsets.UTF_8))); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 5, 10, 18); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 5, 10, 18); } @Test @@ -119,8 +121,9 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(3); assertThat(metadata.nonBlankLines()).isEqualTo(3); assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 4, 8); - assertThat(metadata.lastValidOffset()).isEqualTo(11); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8); + assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11); + assertThat(metadata.isEmpty()).isFalse(); } @Test @@ -132,8 +135,8 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(4); assertThat(metadata.nonBlankLines()).isEqualTo(3); assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz\n")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 4, 8, 12); - assertThat(metadata.lastValidOffset()).isEqualTo(12); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8, 12); + assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11, 12); } @Test @@ -145,8 +148,8 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(3); assertThat(metadata.nonBlankLines()).isEqualTo(3); assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 4, 8); - assertThat(metadata.lastValidOffset()).isEqualTo(11); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8); + assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11); } @Test @@ -158,8 +161,8 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(4); assertThat(metadata.nonBlankLines()).isEqualTo(3); assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz\n")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 4, 8, 12); - assertThat(metadata.lastValidOffset()).isEqualTo(12); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8, 12); + assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11, 12); } @Test @@ -171,7 +174,8 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(4); assertThat(metadata.nonBlankLines()).isEqualTo(3); assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz\n")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 4, 9, 13); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 9, 13); + assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 12, 13); } @Test @@ -183,7 +187,8 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(4); assertThat(metadata.nonBlankLines()).isEqualTo(2); assertThat(metadata.hash()).isEqualTo(md5Hex("foo\n\n\nbar")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 4, 5, 6); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 5, 6); + assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 4, 5, 9); } @Test @@ -195,7 +200,8 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(3); assertThat(metadata.nonBlankLines()).isEqualTo(3); assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 4, 9); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 9); + assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 12); } @Test @@ -207,7 +213,8 @@ public class FileMetadataTest { assertThat(metadata.lines()).isEqualTo(4); assertThat(metadata.nonBlankLines()).isEqualTo(3); assertThat(metadata.hash()).isEqualTo(md5Hex("\nfoo\nbar\nbaz")); - assertThat(metadata.originalLineOffsets()).containsOnly(0, 1, 5, 10); + assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 1, 5, 10); + assertThat(metadata.originalLineEndOffsets()).containsOnly(0, 4, 8, 13); } @Test diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/MetadataTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/MetadataTest.java index adeac3af82a..981eebec98a 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/MetadataTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/MetadataTest.java @@ -26,11 +26,13 @@ import org.junit.Test; public class MetadataTest { @Test public void testRoundtrip() { - Metadata metadata = new Metadata(10, 20, "hash", new int[] {1, 2}, 30); - assertThat(metadata.lastValidOffset()).isEqualTo(30); + Metadata metadata = new Metadata(10, 20, "hash", new int[] {1, 3}, new int[] {2, 4}, 5); + assertThat(metadata.isEmpty()).isFalse(); assertThat(metadata.lines()).isEqualTo(10); assertThat(metadata.nonBlankLines()).isEqualTo(20); - assertThat(metadata.originalLineOffsets()).isEqualTo(new int[] {1, 2}); + assertThat(metadata.originalLineStartOffsets()).isEqualTo(new int[] {1, 3}); + assertThat(metadata.originalLineEndOffsets()).isEqualTo(new int[] {2, 4}); + assertThat(metadata.lastValidOffset()).isEqualTo(5); assertThat(metadata.hash()).isEqualTo("hash"); } } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokensTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokensTest.java index f6cff7aca46..19b0faa04fc 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokensTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokensTest.java @@ -37,8 +37,9 @@ public class DefaultCpdTokensTest { private static final InputFile INPUT_FILE = new TestInputFileBuilder("foo", "src/Foo.java") .setLines(2) - .setOriginalLineOffsets(new int[] {0, 50}) - .setLastValidOffset(100) + .setOriginalLineStartOffsets(new int[] {0, 50}) + .setOriginalLineEndOffsets(new int[] {49, 100}) + .setLastValidOffset(101) .build(); @Test @@ -146,7 +147,7 @@ public class DefaultCpdTokensTest { tokens.addToken(INPUT_FILE.newRange(1, 2, 1, 5), "foo"); fail("Expected exception"); } catch (Exception e) { - assertThat(e).hasMessage("Tokens of file src" + File.separator + "Foo.java should be provided in order.\n" + + assertThat(e).hasMessage("Tokens of file src/Foo.java should be provided in order.\n" + "Previous token: Range[from [line=1, lineOffset=6] to [line=1, lineOffset=10]]\n" + "Last token: Range[from [line=1, lineOffset=2] to [line=1, lineOffset=5]]"); } 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 index e20c6e3050a..8b9b4755eee 100644 --- 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 @@ -41,8 +41,9 @@ public class DefaultHighlightingTest { private static final InputFile INPUT_FILE = new TestInputFileBuilder("foo", "src/Foo.java") .setLines(2) - .setOriginalLineOffsets(new int[] {0, 50}) - .setLastValidOffset(100) + .setOriginalLineStartOffsets(new int[] {0, 50}) + .setOriginalLineEndOffsets(new int[] {49, 100}) + .setLastValidOffset(101) .build(); private Collection highlightingRules; diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTableTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTableTest.java index 68e37d8a899..4d7ff101f32 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTableTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTableTest.java @@ -37,8 +37,9 @@ public class DefaultSymbolTableTest { private static final InputFile INPUT_FILE = new TestInputFileBuilder("foo", "src/Foo.java") .setLines(2) - .setOriginalLineOffsets(new int[] {0, 50}) - .setLastValidOffset(100) + .setOriginalLineStartOffsets(new int[] {0, 50}) + .setOriginalLineEndOffsets(new int[] {49, 100}) + .setLastValidOffset(101) .build(); private Map> referencesPerSymbol; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java index 2ad95729c13..5cf6649d310 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java @@ -36,6 +36,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.InputComponentTree; import org.sonar.api.batch.fs.internal.InputModuleHierarchy; +import org.sonar.api.utils.PathUtils; import org.sonar.core.util.CloseableIterator; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType; @@ -206,11 +207,11 @@ public class ComponentsPublisher implements ReportPublisherStep { Path projectBaseDir = moduleHierarchy.root().getBaseDir(); if (component instanceof InputDir) { InputDir inputDir = (InputDir) component; - return projectBaseDir.relativize(inputDir.path()).toString(); + return PathUtils.sanitize(projectBaseDir.relativize(inputDir.path()).toString()); } if (component instanceof InputModule) { DefaultInputModule module = (DefaultInputModule) component; - return projectBaseDir.relativize(module.getBaseDir()).toString(); + return PathUtils.sanitize(projectBaseDir.relativize(module.getBaseDir()).toString()); } throw new IllegalStateException("Unknown component: " + component.getClass()); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java index b6bf1899b6f..d17e9dc4e52 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java @@ -55,8 +55,8 @@ public class InputFileBuilder { DefaultInputFile create(InputFile.Type type, Path absolutePath, @Nullable String language) { DefaultIndexedFile indexedFile = new DefaultIndexedFile(absolutePath, moduleKey, - PathUtils.sanitize(projectBaseDir.relativize(absolutePath).toString()), - PathUtils.sanitize(moduleBaseDir.relativize(absolutePath).toString()), + projectBaseDir.relativize(absolutePath).toString(), + moduleBaseDir.relativize(absolutePath).toString(), type, language, idGenerator.getAsInt(), sensorStrategy); DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(f, moduleFileSystemInitializer.defaultEncoding())); if (language != null) { diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java index c4521bb6c31..1e2048cfb7c 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java @@ -94,13 +94,13 @@ public class DefaultFileLinesContextTest { @Test public void validateLineGreaterThanZero() { - thrown.expectMessage("Line number should be positive for file src" + File.separator + "foo.php."); + thrown.expectMessage("Line number should be positive for file src/foo.php."); fileLineMeasures.setIntValue(HITS_METRIC_KEY, 0, 2); } @Test public void validateLineLowerThanLineCount() { - thrown.expectMessage("Line 4 is out of range for file src" + File.separator + "foo.php. File has 3 lines"); + thrown.expectMessage("Line 4 is out of range for file src/foo.php. File has 3 lines"); fileLineMeasures.setIntValue(HITS_METRIC_KEY, 4, 2); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java index da85993c73a..e6bcc93c5b3 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java @@ -646,11 +646,11 @@ public class ComponentsPublisherTest { // file in dir in root assertThat(reader.readComponent(dir1_file.batchId()).getPath()).isEqualTo("dir1/Foo.java"); - assertThat(reader.readComponent(dir1_file.batchId()).getProjectRelativePath()).isEqualTo("dir1" + File.separator + "Foo.java"); + assertThat(reader.readComponent(dir1_file.batchId()).getProjectRelativePath()).isEqualTo("dir1/Foo.java"); // dir in dir in root assertThat(reader.readComponent(dir1_dir1.batchId()).getPath()).isEqualTo("dir1/dir1"); - assertThat(reader.readComponent(dir1_dir1.batchId()).getProjectRelativePath()).isEqualTo("dir1" + File.separator + "dir1"); + assertThat(reader.readComponent(dir1_dir1.batchId()).getProjectRelativePath()).isEqualTo("dir1/dir1"); // module in root assertThat(reader.readComponent(mod1.batchId()).getPath()).isEqualTo("mod1"); @@ -658,27 +658,26 @@ public class ComponentsPublisherTest { // dir in module in root assertThat(reader.readComponent(mod1_dir2.batchId()).getPath()).isEqualTo("dir2"); - assertThat(reader.readComponent(mod1_dir2.batchId()).getProjectRelativePath()).isEqualTo("mod1" + File.separator + "dir2"); + assertThat(reader.readComponent(mod1_dir2.batchId()).getProjectRelativePath()).isEqualTo("mod1/dir2"); // file in dir in module in root assertThat(reader.readComponent(mod1_dir2_file.batchId()).getPath()).isEqualTo("dir2/Foo.java"); - assertThat(reader.readComponent(mod1_dir2_file.batchId()).getProjectRelativePath()).isEqualTo("mod1" + File.separator + "dir2" + File.separator + "Foo.java"); + assertThat(reader.readComponent(mod1_dir2_file.batchId()).getProjectRelativePath()).isEqualTo("mod1/dir2/Foo.java"); // module in module assertThat(reader.readComponent(mod1_mod2.batchId()).getPath()).isEqualTo("mod2"); - assertThat(reader.readComponent(mod1_mod2.batchId()).getProjectRelativePath()).isEqualTo("mod1" + File.separator + "mod2"); + assertThat(reader.readComponent(mod1_mod2.batchId()).getProjectRelativePath()).isEqualTo("mod1/mod2"); // file in module in module assertThat(reader.readComponent(mod1_mod2_file.batchId()).getPath()).isEqualTo("Foo.java"); - assertThat(reader.readComponent(mod1_mod2_file.batchId()).getProjectRelativePath()).isEqualTo("mod1" + File.separator + "mod2" + File.separator + "Foo.java"); + assertThat(reader.readComponent(mod1_mod2_file.batchId()).getProjectRelativePath()).isEqualTo("mod1/mod2/Foo.java"); // dir in module in module assertThat(reader.readComponent(mod1_mod2_dir.batchId()).getPath()).isEqualTo("dir"); - assertThat(reader.readComponent(mod1_mod2_dir.batchId()).getProjectRelativePath()).isEqualTo("mod1" + File.separator + "mod2" + File.separator + "dir"); + assertThat(reader.readComponent(mod1_mod2_dir.batchId()).getProjectRelativePath()).isEqualTo("mod1/mod2/dir"); // file in dir in module in module assertThat(reader.readComponent(mod1_mod2_dir_file.batchId()).getPath()).isEqualTo("dir/Foo.java"); - assertThat(reader.readComponent(mod1_mod2_dir_file.batchId()).getProjectRelativePath()) - .isEqualTo("mod1" + File.separator + "mod2" + File.separator + "dir" + File.separator + "Foo.java"); + assertThat(reader.readComponent(mod1_mod2_dir_file.batchId()).getProjectRelativePath()).isEqualTo("mod1/mod2/dir/Foo.java"); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java index 3d9a950a3e2..4d0c4e24c6b 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java @@ -107,7 +107,8 @@ public class MetadataGeneratorTest { assertThat(inputFile.lines()).isEqualTo(3); assertThat(inputFile.nonBlankLines()).isEqualTo(3); assertThat(inputFile.hash()).isEqualTo(md5Hex("foo\nbar\nbaz")); - assertThat(inputFile.originalLineOffsets()).containsOnly(0, 4, 9); + assertThat(inputFile.originalLineStartOffsets()).containsOnly(0, 4, 9); + assertThat(inputFile.originalLineEndOffsets()).containsOnly(3, 7, 12); } @Test -- 2.39.5