blob: 86c44c6581f81306695a869200bc3bbf9fd584da [file] [log] [blame]
/*
* Copyright (C) 2007-2010 JĂșlio Vilmar Gesser.
* Copyright (C) 2011, 2013-2016 The JavaParser Team.
*
* This file is part of JavaParser.
*
* JavaParser can be used either under the terms of
* a) 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.
* b) the terms of the Apache License
*
* You should have received a copy of both licenses in LICENCE.LGPL and
* LICENCE.APACHE. Please refer to those files for details.
*
* JavaParser 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.
*/
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.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;
class JavaParserTest {
@BeforeEach
void setToLatestJava() {
StaticJavaParser.getConfiguration().setLanguageLevel(BLEEDING_EDGE);
}
@AfterEach
void resetJavaLevel() {
StaticJavaParser.getConfiguration().setLanguageLevel(CURRENT);
}
@Test
void rangeOfAnnotationMemberDeclarationIsCorrect() {
String code = "@interface AD { String foo(); }";
CompilationUnit cu = parse(code);
AnnotationMemberDeclaration memberDeclaration = cu.getAnnotationDeclarationByName("AD").get().getMember(0).asAnnotationMemberDeclaration();
assertTrue(memberDeclaration.getRange().isPresent());
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(); }";
CompilationUnit cu = parse(code);
AnnotationMemberDeclaration memberDeclaration = cu.getAnnotationDeclarationByName("AD").get().getMember(0).asAnnotationMemberDeclaration();
assertTrue(memberDeclaration.getRange().isPresent());
assertEquals(new Range(new Position(1, 17), new Position(1, 31)), memberDeclaration.getRange().get());
}
@Test
void rangeOfArrayCreationLevelWithExpressionIsCorrect() {
String code = "new int[123][456]";
ArrayCreationExpr expression = parseExpression(code);
Optional<Range> range;
range = expression.getLevels().get(0).getRange();
assertTrue(range.isPresent());
assertEquals(new Range(new Position(1, 8), new Position(1, 12)), range.get());
range = expression.getLevels().get(1).getRange();
assertTrue(range.isPresent());
assertEquals(new Range(new Position(1, 13), new Position(1, 17)), range.get());
}
@Test
void rangeOfArrayCreationLevelWithoutExpressionIsCorrect() {
String code = "new int[][]";
ArrayCreationExpr expression = parseExpression(code);
Optional<Range> range;
range = expression.getLevels().get(0).getRange();
assertTrue(range.isPresent());
assertEquals(new Range(new Position(1, 8), new Position(1, 9)), range.get());
range = expression.getLevels().get(1).getRange();
assertTrue(range.isPresent());
assertEquals(new Range(new Position(1, 10), new Position(1, 11)), range.get());
}
@Test
void parseErrorContainsLocation() {
ParseResult<CompilationUnit> result = new JavaParser().parse(COMPILATION_UNIT, provider("class X { // blah"));
Problem problem = result.getProblem(0);
assertEquals(range(1, 9, 1, 17), problem.getLocation().get().toRange().get());
assertEquals("Parse error. Found <EOF>, expected one of \";\" \"<\" \"@\" \"abstract\" \"boolean\" \"byte\" \"char\" \"class\" \"default\" \"double\" \"enum\" \"exports\" \"final\" \"float\" \"int\" \"interface\" \"long\" \"module\" \"native\" \"open\" \"opens\" \"private\" \"protected\" \"provides\" \"public\" \"requires\" \"short\" \"static\" \"strictfp\" \"synchronized\" \"to\" \"transient\" \"transitive\" \"uses\" \"void\" \"volatile\" \"with\" \"{\" \"}\" <IDENTIFIER>", problem.getMessage());
assertInstanceOf(ParseException.class, problem.getCause().get());
}
@Test
void parseIntersectionType() {
String code = "(Runnable & Serializable) (() -> {})";
Expression expression = parseExpression(code);
Type type = expression.asCastExpr().getType();
assertTrue(type instanceof IntersectionType);
IntersectionType intersectionType = type.asIntersectionType();
assertEquals(2, intersectionType.getElements().size());
assertTrue(intersectionType.getElements().get(0) instanceof ClassOrInterfaceType);
assertEquals("Runnable", intersectionType.getElements().get(0).asClassOrInterfaceType().getNameAsString());
assertTrue(intersectionType.getElements().get(1) instanceof ClassOrInterfaceType);
assertEquals("Serializable", intersectionType.getElements().get(1).asClassOrInterfaceType().getNameAsString());
}
@Test
void rangeOfIntersectionType() {
String code = "class A {" + EOL
+ " Object f() {" + EOL
+ " return (Comparator<Map.Entry<K, V>> & Serializable)(c1, c2) -> c1.getKey().compareTo(c2.getKey()); " + EOL
+ "}}";
CompilationUnit cu = parse(code);
MethodDeclaration methodDeclaration = cu.getClassByName("A").get().getMember(0).asMethodDeclaration();
ReturnStmt returnStmt = methodDeclaration.getBody().get().getStatement(0).asReturnStmt();
CastExpr castExpr = returnStmt.getExpression().get().asCastExpr();
Type type = castExpr.getType();
assertEquals(range(3, 13, 3, 54), type.getRange().get());
}
@Test
void rangeOfCast() {
String code = "class A {" + EOL
+ " Object f() {" + EOL
+ " return (Comparator<Map.Entry<K, V>> & Serializable)(c1, c2) -> c1.getKey().compareTo(c2.getKey()); " + EOL
+ "}}";
CompilationUnit cu = parse(code);
MethodDeclaration methodDeclaration = cu.getClassByName("A").get().getMember(0).asMethodDeclaration();
ReturnStmt returnStmt = methodDeclaration.getBody().get().getStatement(0).asReturnStmt();
CastExpr castExpr = returnStmt.getExpression().get().asCastExpr();
assertEquals(range(3, 12, 3, 101), castExpr.getRange().get());
}
@Test
void rangeOfCastNonIntersection() {
String code = "class A {" + EOL
+ " Object f() {" + EOL
+ " return (Comparator<Map.Entry<K, V>> )(c1, c2) -> c1.getKey().compareTo(c2.getKey()); " + EOL
+ "}}";
CompilationUnit cu = parse(code);
MethodDeclaration methodDeclaration = cu.getClassByName("A").get().getMember(0).asMethodDeclaration();
ReturnStmt returnStmt = methodDeclaration.getBody().get().getStatement(0).asReturnStmt();
CastExpr castExpr = returnStmt.getExpression().get().asCastExpr();
assertEquals(range(3, 12, 3, 101), castExpr.getRange().get());
}
@Test
void rangeOfLambda() {
String code = "class A {" + EOL
+ " Object f() {" + EOL
+ " return (Comparator<Map.Entry<K, V>> & Serializable)(c1, c2) -> c1.getKey().compareTo(c2.getKey()); " + EOL
+ "}}";
CompilationUnit cu = parse(code);
MethodDeclaration methodDeclaration = cu.getClassByName("A").get().getMember(0).asMethodDeclaration();
ReturnStmt returnStmt = methodDeclaration.getBody().get().getStatement(0).asReturnStmt();
CastExpr castExpr = returnStmt.getExpression().get().asCastExpr();
LambdaExpr lambdaExpr = castExpr.getExpression().asLambdaExpr();
assertEquals(range(3, 56, 3, 101), lambdaExpr.getRange().get());
assertEquals(GeneratedJavaParserConstants.LPAREN, lambdaExpr.getTokenRange().get().getBegin().getKind());
assertEquals(GeneratedJavaParserConstants.RPAREN, lambdaExpr.getTokenRange().get().getEnd().getKind());
}
@Test
void rangeOfLambdaBody() {
String code = "class A {" + EOL
+ " Object f() {" + EOL
+ " return (Comparator<Map.Entry<K, V>> & Serializable)(c1, c2) -> c1.getKey().compareTo(c2.getKey()); " + EOL
+ "}}";
CompilationUnit cu = parse(code);
MethodDeclaration methodDeclaration = cu.getClassByName("A").get().getMember(0).asMethodDeclaration();
ReturnStmt returnStmt = methodDeclaration.getBody().get().getStatement(0).asReturnStmt();
CastExpr castExpr = returnStmt.getExpression().get().asCastExpr();
LambdaExpr lambdaExpr = castExpr.getExpression().asLambdaExpr();
Statement lambdaBody = lambdaExpr.getBody();
assertEquals(range(3, 68, 3, 101), lambdaBody.getRange().get());
}
@Test
void testNotStoringTokens() {
JavaParser javaParser = new JavaParser(new ParserConfiguration().setStoreTokens(false));
ParseResult<CompilationUnit> result = javaParser.parse(ParseStart.COMPILATION_UNIT, provider("class X{}"));
assertFalse(result.getResult().get().getTokenRange().isPresent());
}
@Test
void trailingCodeIsAnError() {
assertThrows(ParseProblemException.class, () -> parseBlock("{} efijqoifjqefj"));
}
@Test
void trailingWhitespaceIsIgnored() {
BlockStmt blockStmt = parseBlock("{} // hello");
assertEquals("{}", blockStmt.getTokenRange().get().toString());
}
@Test
void everyTokenHasACategory() throws IOException {
final int tokenCount = GeneratedJavaParserConstants.tokenImage.length;
Path tokenTypesPath = mavenModuleRoot(JavaParserTest.class).resolve("../javaparser-core/src/main/java/com/github/javaparser/TokenTypes.java");
CompilationUnit tokenTypesCu = parse(tokenTypesPath);
// -1 to take off the default: case.
int switchEntries = tokenTypesCu.findAll(SwitchEntry.class).size() - 1;
// The amount of "case XXX:" in TokenTypes.java should be equal to the amount of tokens JavaCC knows about:
assertEquals(tokenCount, switchEntries);
}
@Test
void parsingInitializedAndUnitializedVarsInForStmt() {
ForStmt forStmt = parseStatement("for(int a,b=0;;){}").asForStmt();
assertEquals(1, forStmt.getInitialization().size());
assertTrue(forStmt.getInitialization().get(0).isVariableDeclarationExpr());
assertEquals(2, forStmt.getInitialization().get(0).asVariableDeclarationExpr().getVariables().size());
assertEquals("a", forStmt.getInitialization().get(0).asVariableDeclarationExpr().getVariables().get(0).getNameAsString());
assertEquals("b", forStmt.getInitialization().get(0).asVariableDeclarationExpr().getVariables().get(1).getNameAsString());
assertFalse(forStmt.getInitialization().get(0).asVariableDeclarationExpr().getVariables().get(0).getInitializer().isPresent());
assertTrue(forStmt.getInitialization().get(0).asVariableDeclarationExpr().getVariables().get(1).getInitializer().isPresent());
}
@Test
void parsingInitializedAndUnitializedVarsInForStmtComplexCase() {
// See issue 1281
ForStmt forStmt = parseStatement("for(int i, j = array2.length - 1;;){}").asForStmt();
assertEquals(1, forStmt.getInitialization().size());
assertTrue(forStmt.getInitialization().get(0).isVariableDeclarationExpr());
assertEquals(2, forStmt.getInitialization().get(0).asVariableDeclarationExpr().getVariables().size());
assertEquals("i", forStmt.getInitialization().get(0).asVariableDeclarationExpr().getVariables().get(0).getNameAsString());
assertEquals("j", forStmt.getInitialization().get(0).asVariableDeclarationExpr().getVariables().get(1).getNameAsString());
assertFalse(forStmt.getInitialization().get(0).asVariableDeclarationExpr().getVariables().get(0).getInitializer().isPresent());
assertTrue(forStmt.getInitialization().get(0).asVariableDeclarationExpr().getVariables().get(1).getInitializer().isPresent());
}
@Test
void creatingNewObjectCreationExprShouldDefaultToParsing() {
String className = String.class.getCanonicalName();
ClassOrInterfaceType type = parseClassOrInterfaceType(className);
ObjectCreationExpr expected = parseExpression("new " + className + "()");
ObjectCreationExpr actual = new ObjectCreationExpr(null, type, NodeList.nodeList());
assertEquals(expected, actual);
}
@Test
void parseModuleDeclaration() {
StaticJavaParser.parseModuleDeclaration("module X {}");
}
@Test
void parseModuleDirective() {
StaticJavaParser.parseModuleDirective("opens C;");
}
@Test
void parseTypeParameter() {
StaticJavaParser.parseTypeParameter("T extends Serializable & AttachableListener");
}
@Test
void parseTypeDeclaration() {
StaticJavaParser.parseTypeDeclaration("enum Z {A, B}");
}
}