diff --git a/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java b/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java index 2c86ab6bb13..06bc2a78a27 100644 --- a/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java +++ b/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java @@ -1,7 +1,6 @@ package org.checkerframework.common.basetype; import com.github.javaparser.ParseProblemException; -import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.printer.PrettyPrinter; import com.sun.source.tree.AnnotatedTypeTree; @@ -131,6 +130,7 @@ import org.checkerframework.framework.util.ContractsFromMethod; import org.checkerframework.framework.util.FieldInvariants; import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException; +import org.checkerframework.framework.util.JavaParserUtil; import org.checkerframework.framework.util.StringToJavaExpression; import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; @@ -338,10 +338,8 @@ protected void testJointJavacJavaParserVisitor() { } Map treePairs = new HashMap<>(); - try { - java.io.InputStream reader = root.getSourceFile().openInputStream(); - com.github.javaparser.ast.CompilationUnit javaParserRoot = StaticJavaParser.parse(reader); - reader.close(); + try (InputStream reader = root.getSourceFile().openInputStream()) { + CompilationUnit javaParserRoot = JavaParserUtil.parseCompilationUnit(reader); JavaParserUtils.concatenateAddedStringLiterals(javaParserRoot); new JointVisitorWithDefaultAction() { @Override @@ -383,7 +381,7 @@ protected void testAnnotationInsertion() { CompilationUnit originalAst; try (InputStream originalInputStream = root.getSourceFile().openInputStream()) { - originalAst = StaticJavaParser.parse(originalInputStream); + originalAst = JavaParserUtil.parseCompilationUnit(originalInputStream); } catch (IOException e) { throw new BugInCF("Error while reading Java file: " + root.getSourceFile().toUri(), e); } @@ -406,7 +404,7 @@ protected void testAnnotationInsertion() { CompilationUnit modifiedAst = null; try { - modifiedAst = StaticJavaParser.parse(withAnnotations); + modifiedAst = JavaParserUtil.parseCompilationUnit(withAnnotations); } catch (ParseProblemException e) { throw new BugInCF("Failed to parse annotation insertion:\n" + withAnnotations, e); } diff --git a/framework/src/main/java/org/checkerframework/common/wholeprograminference/WholeProgramInferenceJavaParserStorage.java b/framework/src/main/java/org/checkerframework/common/wholeprograminference/WholeProgramInferenceJavaParserStorage.java index 63cfd53a736..982b32d9216 100644 --- a/framework/src/main/java/org/checkerframework/common/wholeprograminference/WholeProgramInferenceJavaParserStorage.java +++ b/framework/src/main/java/org/checkerframework/common/wholeprograminference/WholeProgramInferenceJavaParserStorage.java @@ -1,6 +1,5 @@ package org.checkerframework.common.wholeprograminference; -import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.CallableDeclaration; @@ -58,6 +57,7 @@ import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; import org.checkerframework.framework.type.GenericAnnotatedTypeFactory; +import org.checkerframework.framework.util.JavaParserUtil; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.BugInCF; import org.checkerframework.javacutil.ElementUtils; @@ -351,7 +351,7 @@ private void addSourceFile(String path) { CompilationUnit root; try { - root = StaticJavaParser.parse(new File(path)); + root = JavaParserUtil.parseCompilationUnit(new File(path)); } catch (FileNotFoundException e) { throw new BugInCF("Failed to read Java file " + path, e); } diff --git a/framework/src/main/java/org/checkerframework/framework/ajava/AnnotationFileStore.java b/framework/src/main/java/org/checkerframework/framework/ajava/AnnotationFileStore.java index 48d8b7b0fd8..1e2a6ccaaf8 100644 --- a/framework/src/main/java/org/checkerframework/framework/ajava/AnnotationFileStore.java +++ b/framework/src/main/java/org/checkerframework/framework/ajava/AnnotationFileStore.java @@ -1,6 +1,5 @@ package org.checkerframework.framework.ajava; -import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.TypeDeclaration; import java.io.File; @@ -10,6 +9,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.checkerframework.framework.util.JavaParserUtil; import org.checkerframework.javacutil.BugInCF; /** @@ -45,7 +45,7 @@ public void addFileOrDirectory(File location) { if (location.isFile() && location.getName().endsWith(".ajava")) { try { - CompilationUnit root = StaticJavaParser.parse(location); + CompilationUnit root = JavaParserUtil.parseCompilationUnit(location); for (TypeDeclaration type : root.getTypes()) { String name = JavaParserUtils.getFullyQualifiedName(type, root); diff --git a/framework/src/main/java/org/checkerframework/framework/ajava/InsertAjavaAnnotations.java b/framework/src/main/java/org/checkerframework/framework/ajava/InsertAjavaAnnotations.java index ba68086c50d..96eb24736c9 100644 --- a/framework/src/main/java/org/checkerframework/framework/ajava/InsertAjavaAnnotations.java +++ b/framework/src/main/java/org/checkerframework/framework/ajava/InsertAjavaAnnotations.java @@ -1,7 +1,6 @@ package org.checkerframework.framework.ajava; import com.github.javaparser.Position; -import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.ImportDeclaration; import com.github.javaparser.ast.Node; @@ -50,6 +49,7 @@ import org.checkerframework.checker.signature.qual.DotSeparatedIdentifiers; import org.checkerframework.checker.signature.qual.FullyQualifiedName; import org.checkerframework.framework.stub.AnnotationFileParser; +import org.checkerframework.framework.util.JavaParserUtil; import org.plumelib.util.FilesPlume; /** This program inserts annotations from an ajava file into a Java file. See {@link #main}. */ @@ -460,8 +460,8 @@ private Map getImportedAnnotations(CompilationUnit cu) { */ public String insertAnnotations( InputStream annotationFile, String javaFileContents, String lineSeparator) { - CompilationUnit annotationCu = StaticJavaParser.parse(annotationFile); - CompilationUnit javaCu = StaticJavaParser.parse(javaFileContents); + CompilationUnit annotationCu = JavaParserUtil.parseCompilationUnit(annotationFile); + CompilationUnit javaCu = JavaParserUtil.parseCompilationUnit(javaFileContents); BuildInsertionsVisitor insertionVisitor = new BuildInsertionsVisitor(javaFileContents, lineSeparator); annotationCu.accept(insertionVisitor, javaCu); @@ -568,7 +568,7 @@ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { CompilationUnit root = null; try { - root = StaticJavaParser.parse(path); + root = JavaParserUtil.parseCompilationUnit(path.toFile()); } catch (IOException e) { System.err.println("Failed to read file: " + path); System.exit(1); diff --git a/framework/src/main/java/org/checkerframework/framework/stub/AnnotationFileParser.java b/framework/src/main/java/org/checkerframework/framework/stub/AnnotationFileParser.java index df6f72d0bb6..b5f40862084 100644 --- a/framework/src/main/java/org/checkerframework/framework/stub/AnnotationFileParser.java +++ b/framework/src/main/java/org/checkerframework/framework/stub/AnnotationFileParser.java @@ -3,7 +3,6 @@ import com.github.javaparser.ParseProblemException; import com.github.javaparser.Position; import com.github.javaparser.Problem; -import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.AccessSpecifier; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.ImportDeclaration; @@ -98,6 +97,7 @@ import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType; +import org.checkerframework.framework.util.JavaParserUtil; import org.checkerframework.framework.util.element.ElementAnnotationUtil.ErrorTypeKindException; import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; @@ -607,7 +607,7 @@ private void parseStubUnit(InputStream inputStream) { if (debugAnnotationFileParser) { stubDebug(String.format("parsing stub file %s", filename)); } - stubUnit = StaticJavaParser.parseStubUnit(inputStream); + stubUnit = JavaParserUtil.parseStubUnit(inputStream); // getAllAnnotations() also modifies importedConstants and importedTypes. This should // be refactored to be nicer. diff --git a/framework/src/main/java/org/checkerframework/framework/stub/ToIndexFileConverter.java b/framework/src/main/java/org/checkerframework/framework/stub/ToIndexFileConverter.java index dfe7ff21d7f..3b6279984e1 100644 --- a/framework/src/main/java/org/checkerframework/framework/stub/ToIndexFileConverter.java +++ b/framework/src/main/java/org/checkerframework/framework/stub/ToIndexFileConverter.java @@ -2,7 +2,6 @@ import com.github.javaparser.ParseException; import com.github.javaparser.ParseProblemException; -import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.ImportDeclaration; import com.github.javaparser.ast.NodeList; @@ -54,6 +53,7 @@ import org.checkerframework.checker.signature.qual.ClassGetName; import org.checkerframework.checker.signature.qual.DotSeparatedIdentifiers; import org.checkerframework.checker.signature.qual.FullyQualifiedName; +import org.checkerframework.framework.util.JavaParserUtil; import org.checkerframework.javacutil.BugInCF; import org.plumelib.reflection.Signatures; import scenelib.annotations.Annotation; @@ -180,7 +180,7 @@ private static void convert(AScene scene, InputStream in, OutputStream out) throws IOException, DefException, ParseException { StubUnit iu; try { - iu = StaticJavaParser.parseStubUnit(in); + iu = JavaParserUtil.parseStubUnit(in); } catch (ParseProblemException e) { iu = null; throw new BugInCF( diff --git a/framework/src/main/java/org/checkerframework/framework/util/JavaParserUtil.java b/framework/src/main/java/org/checkerframework/framework/util/JavaParserUtil.java new file mode 100644 index 00000000000..6654389ed84 --- /dev/null +++ b/framework/src/main/java/org/checkerframework/framework/util/JavaParserUtil.java @@ -0,0 +1,104 @@ +package org.checkerframework.framework.util; + +import com.github.javaparser.JavaParser; +import com.github.javaparser.ParseProblemException; +import com.github.javaparser.ParseResult; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.StubUnit; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.InputStream; + +/** A replacement for StaticJavaParser that does not leak memory. */ +public class JavaParserUtil { + + /** + * Parses the Java code contained in the {@code InputStream} and returns a {@code CompilationUnit} + * that represents it. + * + *

This is like {@code StaticJavaParser.parse}, but it does not lead to memory leaks because it + * creates a new instance of JavaParser each time it is invoked. Re-using {@code StaticJavaParser} + * causes memory problems because it retains too much memory. + * + * @param inputStream the Java source code + * @return CompilationUnit representing the Java source code + * @throws ParseProblemException if the source code has parser errors + */ + public static CompilationUnit parseCompilationUnit(InputStream inputStream) { + JavaParser javaParser = new JavaParser(new ParserConfiguration()); + ParseResult parseResult = javaParser.parse(inputStream); + if (parseResult.isSuccessful() && parseResult.getResult().isPresent()) { + return parseResult.getResult().get(); + } else { + throw new ParseProblemException(parseResult.getProblems()); + } + } + + /** + * Parses the Java code contained in the {@code File} and returns a {@code CompilationUnit} that + * represents it. + * + *

This is like {@code StaticJavaParser.parse}, but it does not lead to memory leaks because it + * creates a new instance of JavaParser each time it is invoked. Re-using {@code StaticJavaParser} + * causes memory problems because it retains too much memory. + * + * @param file the Java source code + * @return CompilationUnit representing the Java source code + * @throws ParseProblemException if the source code has parser errors + * @throws FileNotFoundException if the file was not found + */ + public static CompilationUnit parseCompilationUnit(File file) throws FileNotFoundException { + JavaParser javaParser = new JavaParser(new ParserConfiguration()); + ParseResult parseResult = javaParser.parse(file); + if (parseResult.isSuccessful() && parseResult.getResult().isPresent()) { + return parseResult.getResult().get(); + } else { + throw new ParseProblemException(parseResult.getProblems()); + } + } + + /** + * Parses the Java code contained in the {@code String} and returns a {@code CompilationUnit} that + * represents it. + * + *

This is like {@code StaticJavaParser.parse}, but it does not lead to memory leaks because it + * creates a new instance of JavaParser each time it is invoked. Re-using {@code StaticJavaParser} + * causes memory problems because it retains too much memory. + * + * @param javaSource the Java source code + * @return CompilationUnit representing the Java source code + * @throws ParseProblemException if the source code has parser errors + */ + public static CompilationUnit parseCompilationUnit(String javaSource) { + JavaParser javaParser = new JavaParser(new ParserConfiguration()); + ParseResult parseResult = javaParser.parse(javaSource); + if (parseResult.isSuccessful() && parseResult.getResult().isPresent()) { + return parseResult.getResult().get(); + } else { + throw new ParseProblemException(parseResult.getProblems()); + } + } + + /** + * Parses the stub file contained in the {@code InputStream} and returns a {@code StubUnit} that + * represents it. + * + *

This is like {@code StaticJavaParser.parse}, but it does not lead to memory leaks because it + * creates a new instance of JavaParser each time it is invoked. Re-using {@code StaticJavaParser} + * causes memory problems because it retains too much memory. + * + * @param inputStream the stub file + * @return StubUnit representing the stub file + * @throws ParseProblemException if the source code has parser errors + */ + public static StubUnit parseStubUnit(InputStream inputStream) { + JavaParser javaParser = new JavaParser(new ParserConfiguration()); + ParseResult parseResult = javaParser.parseStubUnit(inputStream); + if (parseResult.isSuccessful() && parseResult.getResult().isPresent()) { + return parseResult.getResult().get(); + } else { + throw new ParseProblemException(parseResult.getProblems()); + } + } +}