Skip to content

Commit

Permalink
Apply recorded position mapping in a parser post-processing phase.
Browse files Browse the repository at this point in the history
  • Loading branch information
haumacher committed Jun 15, 2019
1 parent 8061934 commit ee156d8
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 130 deletions.
Expand Up @@ -21,34 +21,41 @@

package com.github.javaparser;

import static com.github.javaparser.ParseStart.*;
import static com.github.javaparser.ParserConfiguration.LanguageLevel.*;
import static com.github.javaparser.Providers.*;
import static com.github.javaparser.Range.*;
import static com.github.javaparser.StaticJavaParser.*;
import static com.github.javaparser.utils.CodeGenerationUtils.*;
import static com.github.javaparser.utils.TestUtils.*;
import static com.github.javaparser.utils.Utils.*;
import static org.junit.jupiter.api.Assertions.*;

import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.AnnotationMemberDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.*;
import com.github.javaparser.ast.expr.ArrayCreationExpr;
import com.github.javaparser.ast.expr.CastExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.LambdaExpr;
import com.github.javaparser.ast.expr.ObjectCreationExpr;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.ForStmt;
import com.github.javaparser.ast.stmt.ReturnStmt;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.stmt.SwitchEntry;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.IntersectionType;
import com.github.javaparser.ast.type.Type;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;

import static com.github.javaparser.ParseStart.COMPILATION_UNIT;
import static com.github.javaparser.ParserConfiguration.LanguageLevel.BLEEDING_EDGE;
import static com.github.javaparser.ParserConfiguration.LanguageLevel.CURRENT;
import static com.github.javaparser.Providers.provider;
import static com.github.javaparser.StaticJavaParser.*;
import static com.github.javaparser.Range.range;
import static com.github.javaparser.utils.CodeGenerationUtils.mavenModuleRoot;
import static com.github.javaparser.utils.TestUtils.assertInstanceOf;
import static com.github.javaparser.utils.Utils.EOL;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertThrows;

class JavaParserTest {

Expand All @@ -71,6 +78,32 @@ void rangeOfAnnotationMemberDeclarationIsCorrect() {
assertEquals(new Range(new Position(1, 17), new Position(1, 29)), memberDeclaration.getRange().get());
}

@Test
void testSourcePositionsWithUnicodeEscapes() {
String code = "@interface AD \\u007B String foo(); \\u007D";
CompilationUnit cu = parseWithUnicodeEscapes(code).getResult().get();
AnnotationMemberDeclaration memberDeclaration = cu.getAnnotationDeclarationByName("AD").get().getMember(0).asAnnotationMemberDeclaration();
assertTrue(memberDeclaration.getRange().isPresent());
assertEquals(new Range(new Position(1, 22), new Position(1, 34)), memberDeclaration.getRange().get());
}

@Test
void testSourcePositionsWithBrokenUnicodeEscapes() {
// Source positions
// 111111111122222222 2 22333 3333
// 123456789012345678901234567 8 90123 4567
String code = "@interface AD { String X = \"\\uABC\"; }";
ParseResult<CompilationUnit> cu = parseWithUnicodeEscapes(code);
assertFalse(cu.getResult().isPresent());
assertEquals("Lexical error at line 1, column 34. Encountered: \"\\\"\" (34), after : \"\\\"\\\\uABC\"", cu.getProblem(0).getMessage());
}

private static ParseResult<CompilationUnit> parseWithUnicodeEscapes(String code) {
ParserConfiguration config = new ParserConfiguration();
config.setPreprocessUnicodeEscapes(true);
return new JavaParser(config).parse(code);
}

@Test
void rangeOfAnnotationMemberDeclarationWithArrayTypeIsCorrect() {
String code = "@interface AD { String[] foo(); }";
Expand Down
Expand Up @@ -29,7 +29,6 @@

import org.junit.jupiter.api.Test;

import com.github.javaparser.UnicodeEscapeProcessingProvider.Pos;
import com.github.javaparser.UnicodeEscapeProcessingProvider.PositionMapping;

/**
Expand All @@ -54,7 +53,7 @@ public void testNoMapping() throws IOException {
PositionMapping mapping = provider.getPositionMapping();
assertEquals(4, provider.getInputCounter().getLine());
assertEquals(4, provider.getOutputCounter().getLine());
assertSame(PositionMapping.PositionUpdate.NONE, mapping.lookup(new Pos(10000, 1)));
assertSame(PositionMapping.PositionUpdate.NONE, mapping.lookup(new Position(10000, 1)));
}

@Test
Expand Down Expand Up @@ -111,9 +110,9 @@ private void checkConvert(List<List<String>> input,
for (String inPart : inLine) {
assertFalse(outFinished);

Pos inPos = new Pos(inPosLine, inPosColumn);
Pos outPos = new Pos(outPosLine, outPosColumn);
Pos transfomedOutPos = mapping.transform(outPos);
Position inPos = new Position(inPosLine, inPosColumn);
Position outPos = new Position(outPosLine, outPosColumn);
Position transfomedOutPos = mapping.transform(outPos);

assertEquals(inPos, transfomedOutPos,
"Position mismatch at '" + outPart + "' " + outPos + " -> '" + inPart + "' " + inPos + ".");
Expand Down
Expand Up @@ -21,23 +21,40 @@

package com.github.javaparser;

import static com.github.javaparser.ParserConfiguration.LanguageLevel.*;
import static com.github.javaparser.utils.Utils.*;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import com.github.javaparser.ParseResult.PostProcessor;
import com.github.javaparser.Providers.PreProcessor;
import com.github.javaparser.UnicodeEscapeProcessingProvider.PositionMapping;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.validator.*;
import com.github.javaparser.ast.validator.Java10Validator;
import com.github.javaparser.ast.validator.Java11Validator;
import com.github.javaparser.ast.validator.Java12Validator;
import com.github.javaparser.ast.validator.Java1_0Validator;
import com.github.javaparser.ast.validator.Java1_1Validator;
import com.github.javaparser.ast.validator.Java1_2Validator;
import com.github.javaparser.ast.validator.Java1_3Validator;
import com.github.javaparser.ast.validator.Java1_4Validator;
import com.github.javaparser.ast.validator.Java5Validator;
import com.github.javaparser.ast.validator.Java6Validator;
import com.github.javaparser.ast.validator.Java7Validator;
import com.github.javaparser.ast.validator.Java8Validator;
import com.github.javaparser.ast.validator.Java9Validator;
import com.github.javaparser.ast.validator.ProblemReporter;
import com.github.javaparser.ast.validator.Validator;
import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;
import com.github.javaparser.resolution.SymbolResolver;
import com.github.javaparser.version.Java10PostProcessor;
import com.github.javaparser.version.Java11PostProcessor;
import com.github.javaparser.version.Java12PostProcessor;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static com.github.javaparser.ParserConfiguration.LanguageLevel.*;
import static com.github.javaparser.utils.Utils.assertNotNull;

/**
* The configuration that is used by the parser.
* Note that this can be changed even when reusing the same JavaParser instance.
Expand Down Expand Up @@ -138,12 +155,45 @@ public enum LanguageLevel {
private final List<ParseResult.PostProcessor> postProcessors = new ArrayList<>();

public ParserConfiguration() {
preProcessors.add(innerProvider -> {
if (preprocessUnicodeEscapes) {
return new UnicodeEscapeProcessingProvider(innerProvider);
}
return innerProvider;
});
class UnicodeEscapeProcessor implements PreProcessor, PostProcessor {
private UnicodeEscapeProcessingProvider _unicodeDecoder;

@Override
public Provider process(Provider innerProvider) {
if (isPreprocessUnicodeEscapes()) {
_unicodeDecoder = new UnicodeEscapeProcessingProvider(innerProvider);
return _unicodeDecoder;
}
return innerProvider;
}

@Override
public void process(ParseResult<? extends Node> result,
ParserConfiguration configuration) {
if (configuration.isPreprocessUnicodeEscapes()) {
Optional<? extends Node> nodeHandle = result.getResult();
if (nodeHandle.isPresent()) {
PositionMapping positionMapping = _unicodeDecoder.getPositionMapping();
adjustPositions(positionMapping, result.getResult().get());
}
}
}

private void adjustPositions(PositionMapping positionMapping, Node node) {
Optional<Range> rangeHandle = node.getRange();
if (rangeHandle.isPresent()) {
Range range = rangeHandle.get();
node.setRange(positionMapping.transform(range));
}

for (Node child : node.getChildNodes()) {
adjustPositions(positionMapping, child);
}
}
}
UnicodeEscapeProcessor unicodeProcessor = new UnicodeEscapeProcessor();
preProcessors.add(unicodeProcessor);
postProcessors.add(unicodeProcessor);
postProcessors.add((result, configuration) -> {
if (configuration.isLexicalPreservationEnabled()) {
result.ifSuccessful(LexicalPreservingPrinter::setup);
Expand Down

0 comments on commit ee156d8

Please sign in to comment.