[WIP] Working fix for <Line, Offset> mapping to support any type of line separators in the same source file && other minor fixes

This commit is contained in:
gonzalo
2018-01-08 01:55:52 -03:00
parent 40bb0a0fe6
commit bb8b2cdd4e
4 changed files with 94 additions and 34 deletions

View File

@@ -7,14 +7,12 @@ package net.sourceforge.pmd.util.document;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
@@ -36,26 +34,42 @@ public class DocumentFile implements Document, Closeable {
private final BufferedReader reader;
private int currentPosition = 0;
private final Path temporaryPath = Files.createTempFile("pmd-", null);
private final Writer writer = new FileWriter(temporaryPath.toFile());
private final Path temporaryPath = Files.createTempFile("pmd-", ".tmp");
private final Writer writer = Files.newBufferedWriter(temporaryPath, StandardCharsets.UTF_8);
public DocumentFile(final File file) throws IOException {
reader = new BufferedReader(new FileReader(file));
reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8);
this.filePath = file.getAbsolutePath();
mapLinesToOffsets();
}
private void mapLinesToOffsets() throws IOException {
try (Scanner scanner = new Scanner(filePath)) {
try (Scanner scanner = new Scanner(Paths.get(filePath))) {
int currentGlobalOffset = 0;
while (scanner.hasNextLine()) {
lineToOffset.add(currentGlobalOffset);
currentGlobalOffset += scanner.nextLine().length();
currentGlobalOffset += getLineLengthWithLineSeparator(scanner);
}
}
}
/**
* Sums the line length without the line separation and the characters which matched the line separation pattern
* @param scanner the scanner from which to read the line's length
* @return the length of the line with the line separator.
*/
private int getLineLengthWithLineSeparator(final Scanner scanner) {
int lineLength = scanner.nextLine().length();
final String lineSeparationMatch = scanner.match().group(1);
if (lineSeparationMatch != null) {
lineLength += lineSeparationMatch.length();
}
return lineLength;
}
@Override
public void insert(int beginLine, int beginColumn, final String textToInsert) {
try {
@@ -135,7 +149,10 @@ public class DocumentFile implements Document, Closeable {
}
reader.close();
writer.close();
Files.copy(temporaryPath, Paths.get(filePath), StandardCopyOption.REPLACE_EXISTING);
if (!temporaryPath.toFile().renameTo(new File(filePath))) {
throw new IOException("Fixed file could not be renamed. Original path = " + filePath);
}
temporaryPath.toFile().delete();
}
@@ -146,4 +163,8 @@ public class DocumentFile implements Document, Closeable {
writer.write(line);
}
}
public List<Integer> getLineToOffset() {
return lineToOffset;
}
}

View File

@@ -12,15 +12,15 @@ import java.util.Objects;
public class DocumentOperationsApplierForNonOverlappingRegions {
private static final Comparator<DocumentOperation> COMPARATOR = new DocumentOperationNonOverlappingRegionsComparator();
private final Document document;
private final List<DocumentOperation> operations;
private final Comparator<DocumentOperation> comparator;
private boolean applied;
public DocumentOperationsApplierForNonOverlappingRegions(final Document document) {
this.document = Objects.requireNonNull(document);
comparator = new DocumentOperationNonOverlappingRegionsComparator();
operations = new ArrayList<>();
applied = false;
}
@@ -39,7 +39,7 @@ public class DocumentOperationsApplierForNonOverlappingRegions {
}
private int getIndexForDocumentOperation(final DocumentOperation documentOperation) {
int potentialIndex = Collections.binarySearch(operations, documentOperation, comparator);
int potentialIndex = Collections.binarySearch(operations, documentOperation, COMPARATOR);
if (potentialIndex < 0) {
return ~potentialIndex;
@@ -53,7 +53,7 @@ public class DocumentOperationsApplierForNonOverlappingRegions {
}
private boolean areSiblingsEqual(final int index) {
return comparator.compare(operations.get(index), operations.get(index + 1)) == 0;
return COMPARATOR.compare(operations.get(index), operations.get(index + 1)) == 0;
}
public void apply() {
@@ -65,7 +65,7 @@ public class DocumentOperationsApplierForNonOverlappingRegions {
}
}
private class DocumentOperationNonOverlappingRegionsComparator implements Comparator<DocumentOperation> {
private static class DocumentOperationNonOverlappingRegionsComparator implements Comparator<DocumentOperation> {
@Override
public int compare(final DocumentOperation o1, final DocumentOperation o2) {
@@ -73,7 +73,7 @@ public class DocumentOperationsApplierForNonOverlappingRegions {
final RegionByLine r2 = Objects.requireNonNull(o2).getRegionByLine();
final int comparison;
if (areInsertOperations(r1, r2)) {
if (areInsertOperationsAtTheSameOffset(r1, r2)) {
comparison = 0;
} else if (doesFirstRegionEndBeforeSecondRegionBegins(r1, r2)) {
comparison = -1;
@@ -85,7 +85,7 @@ public class DocumentOperationsApplierForNonOverlappingRegions {
return comparison;
}
private boolean areInsertOperations(final RegionByLine r1, final RegionByLine r2) {
private boolean areInsertOperationsAtTheSameOffset(final RegionByLine r1, final RegionByLine r2) {
return r1.getBeginLine() == r2.getBeginLine() && r1.getBeginColumn() == r2.getBeginColumn()
&& r1.getBeginLine() == r1.getEndLine() && r1.getBeginColumn() == r1.getEndColumn();
}

View File

@@ -6,22 +6,21 @@ package net.sourceforge.pmd.util.document;
import static org.junit.Assert.assertEquals;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class DocumentFileTest {
private static final String FILE_PATH = "psvm.java";
@@ -35,11 +34,6 @@ public class DocumentFileTest {
temporaryFile = temporaryFolder.newFile(FILE_PATH);
}
@After
public void deleteTemporaryFiles() {
temporaryFile.delete();
}
@Test
public void insertAtStartOfTheFileShouldSucceed() throws IOException {
writeContentToTemporaryFile("static void main(String[] args) {}");
@@ -218,8 +212,59 @@ public class DocumentFileTest {
}
}
@Test
public void lineToOffsetMappingWithLineFeedShouldSucceed() throws IOException {
final String code = "public static int main(String[] args) {" + '\n'
+ "int var;" + '\n'
+ "}";
writeContentToTemporaryFile(code);
final List<Integer> expectedLineToOffset = new ArrayList<>();
expectedLineToOffset.add(0);
expectedLineToOffset.add(40);
expectedLineToOffset.add(49);
try (DocumentFile documentFile = new DocumentFile(temporaryFile)) {
assertEquals(expectedLineToOffset, documentFile.getLineToOffset());
}
}
@Test
public void lineToOffsetMappingWithCarriageReturnFeedLineFeedShouldSucceed() throws IOException {
final String code = "public static int main(String[] args) {" + "\r\n"
+ "int var;" + "\r\n"
+ "}";
writeContentToTemporaryFile(code);
final List<Integer> expectedLineToOffset = new ArrayList<>();
expectedLineToOffset.add(0);
expectedLineToOffset.add(41);
expectedLineToOffset.add(51);
try (DocumentFile documentFile = new DocumentFile(temporaryFile)) {
assertEquals(expectedLineToOffset, documentFile.getLineToOffset());
}
}
@Test
public void lineToOffsetMappingWithMixedLineSeparatorsShouldSucceed() throws IOException {
final String code = "public static int main(String[] args) {" + "\r\n"
+ "int var;" + "\n"
+ "}";
writeContentToTemporaryFile(code);
final List<Integer> expectedLineToOffset = new ArrayList<>();
expectedLineToOffset.add(0);
expectedLineToOffset.add(41);
expectedLineToOffset.add(50);
try (DocumentFile documentFile = new DocumentFile(temporaryFile)) {
assertEquals(expectedLineToOffset, documentFile.getLineToOffset());
}
}
private void writeContentToTemporaryFile(final String content) throws IOException {
try (FileWriter writer = new FileWriter(temporaryFile)) {
try (BufferedWriter writer = Files.newBufferedWriter(temporaryFile.toPath(), StandardCharsets.UTF_8)) {
writer.write(content);
}
}

View File

@@ -15,7 +15,6 @@ import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -36,11 +35,6 @@ public class DocumentOperationsApplierForNonOverlappingRegionsWithDocumentFileTe
temporaryFile = temporaryFolder.newFile(FILE_PATH);
}
@After
public void deleteTemporaryFiles() {
temporaryFile.delete();
}
@Test
public void insertAtStartOfTheDocumentShouldSucceed() throws IOException {
writeContentToTemporaryFile("static void main(String[] args) {}");