diff --git a/check_api/src/main/java/com/google/errorprone/util/ErrorProneParser.java b/check_api/src/main/java/com/google/errorprone/util/ErrorProneParser.java new file mode 100644 index 00000000000..1e3d4f945e2 --- /dev/null +++ b/check_api/src/main/java/com/google/errorprone/util/ErrorProneParser.java @@ -0,0 +1,53 @@ +/* + * Copyright 2026 The Error Prone Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.errorprone.util; + +import com.sun.tools.javac.parser.JavacParser; +import com.sun.tools.javac.parser.ParserFactory; +import com.sun.tools.javac.util.Context; + +/** A compatibility wrapper around {@link ParserFactory}. */ +public final class ErrorProneParser { + + public static JavacParser newParser( + Context context, + CharSequence source, + boolean keepDocComments, + boolean keepEndPos, + boolean keepLineMap) { + ParserFactory parserFactory = ParserFactory.instance(context); + if (IS_END_POS_TABLE_PRESENT) { + return parserFactory.newParser(source, keepDocComments, keepEndPos, keepLineMap); + } + return parserFactory.newParser( + source, keepDocComments, keepLineMap, /* parseModuleInfo */ false); + } + + private static final boolean IS_END_POS_TABLE_PRESENT = getIsEndPosTablePresent(); + + private static boolean getIsEndPosTablePresent() { + try { + // JDK versions before https://bugs.openjdk.org/browse/JDK-8372948 + Class.forName("com.sun.tools.javac.tree.EndPosTable"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + + private ErrorProneParser() {} +} diff --git a/check_api/src/test/java/com/google/errorprone/util/ErrorProneParserTest.java b/check_api/src/test/java/com/google/errorprone/util/ErrorProneParserTest.java new file mode 100644 index 00000000000..31aa6bb8bd1 --- /dev/null +++ b/check_api/src/test/java/com/google/errorprone/util/ErrorProneParserTest.java @@ -0,0 +1,116 @@ +/* + * Copyright 2026 The Error Prone Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.errorprone.util; + +import static com.google.common.truth.Truth.assertThat; +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.errorprone.fixes.ErrorProneEndPosTable; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.parser.JavacParser; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.util.Context; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ErrorProneParserTest { + + private static final String SOURCE = "/** javadoc */ class Test {}"; + + @Test + public void keepDocComments() { + Context context = new Context(); + var unused = new JavacFileManager(context, true, UTF_8); + JavacParser parser = + ErrorProneParser.newParser( + context, + SOURCE, + /* keepDocComments= */ true, + /* keepEndPos= */ false, + /* keepLineMap= */ false); + JCCompilationUnit unit = parser.parseCompilationUnit(); + assertThat(unit.docComments).isNotNull(); + assertThat(unit.getLineMap()).isNull(); + } + + @Test + public void discardDocComments() { + Context context = new Context(); + var unused = new JavacFileManager(context, true, UTF_8); + JavacParser parser = + ErrorProneParser.newParser( + context, + SOURCE, + /* keepDocComments= */ false, + /* keepEndPos= */ false, + /* keepLineMap= */ false); + JCCompilationUnit unit = parser.parseCompilationUnit(); + assertThat(unit.docComments).isNull(); + assertThat(unit.getLineMap()).isNull(); + } + + @Test + public void keepEndPos() { + Context context = new Context(); + var unused = new JavacFileManager(context, true, UTF_8); + JavacParser parser = + ErrorProneParser.newParser( + context, + SOURCE, + /* keepDocComments= */ false, + /* keepEndPos= */ true, + /* keepLineMap= */ false); + JCCompilationUnit unit = parser.parseCompilationUnit(); + assertThat(unit.docComments).isNull(); + assertThat(ErrorProneEndPosTable.create(unit).getEndPosition(unit)).isEqualTo(28); + assertThat(unit.getLineMap()).isNull(); + } + + @Test + public void keepLineMap() { + Context context = new Context(); + var unused = new JavacFileManager(context, true, UTF_8); + JavacParser parser = + ErrorProneParser.newParser( + context, + SOURCE, + /* keepDocComments= */ false, + /* keepEndPos= */ false, + /* keepLineMap= */ true); + JCCompilationUnit unit = parser.parseCompilationUnit(); + assertThat(unit.docComments).isNull(); + assertThat(unit.getLineMap()).isNotNull(); + } + + @Test + public void discardLineMap() { + Context context = new Context(); + var unused = new JavacFileManager(context, true, UTF_8); + JavacParser parser = + ErrorProneParser.newParser( + context, + SOURCE, + /* keepDocComments= */ false, + /* keepEndPos= */ false, + /* keepLineMap= */ false); + JCCompilationUnit unit = parser.parseCompilationUnit(); + assertThat(unit.docComments).isNull(); + assertThat(unit.getLineMap()).isNull(); + } +} diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/inlineme/Inliner.java b/core/src/main/java/com/google/errorprone/bugpatterns/inlineme/Inliner.java index f9410a2a146..8d63826f45d 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/inlineme/Inliner.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/inlineme/Inliner.java @@ -49,6 +49,7 @@ import com.google.errorprone.fixes.SuggestedFix; import com.google.errorprone.fixes.SuggestedFixes; import com.google.errorprone.matchers.Description; +import com.google.errorprone.util.ErrorProneParser; import com.google.errorprone.util.MoreAnnotations; import com.google.errorprone.util.OperatorPrecedence; import com.sun.source.tree.AssignmentTree; @@ -67,7 +68,6 @@ import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.parser.JavacParser; -import com.sun.tools.javac.parser.ParserFactory; import com.sun.tools.javac.tree.JCTree; import java.util.ArrayList; import java.util.List; @@ -373,12 +373,12 @@ && stringContainsComments(state.getSourceForNode(tree), state.context)) { } private static JavacParser newParser(String replacement, VisitorState state) { - return ParserFactory.instance(state.context) - .newParser( - replacement, - /* keepDocComments= */ true, - /* keepEndPos= */ true, - /* keepLineMap= */ true); + return ErrorProneParser.newParser( + state.context, + replacement, + /* keepDocComments= */ true, + /* keepEndPos= */ true, + /* keepLineMap= */ true); } private static List getArguments(Tree tree) { diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/threadsafety/GuardedByUtils.java b/core/src/main/java/com/google/errorprone/bugpatterns/threadsafety/GuardedByUtils.java index deb83e7674e..f5f0be3b9a1 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/threadsafety/GuardedByUtils.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/threadsafety/GuardedByUtils.java @@ -24,12 +24,12 @@ import com.google.common.collect.ImmutableSet; import com.google.errorprone.VisitorState; import com.google.errorprone.bugpatterns.threadsafety.GuardedByExpression.Select; +import com.google.errorprone.util.ErrorProneParser; import com.google.errorprone.util.MoreAnnotations; import com.sun.source.tree.Tree; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.parser.JavacParser; -import com.sun.tools.javac.parser.ParserFactory; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Log; @@ -76,12 +76,12 @@ static ImmutableSet getGuardValues(Tree tree) { static JCTree.JCExpression parseString(String guardedByString, Context context) { JavacParser parser = - ParserFactory.instance(context) - .newParser( - guardedByString, - /* keepDocComments= */ false, - /* keepEndPos= */ true, - /* keepLineMap= */ false); + ErrorProneParser.newParser( + context, + guardedByString, + /* keepDocComments= */ false, + /* keepEndPos= */ true, + /* keepLineMap= */ false); Log log = Log.instance(context); Log.DeferredDiagnosticHandler deferredDiagnosticHandler = deferredDiagnosticHandler(log); JCTree.JCExpression exp; diff --git a/core/src/test/java/com/google/errorprone/refaster/AbstractUTreeTest.java b/core/src/test/java/com/google/errorprone/refaster/AbstractUTreeTest.java index 71f7021331b..d84905b3d5c 100644 --- a/core/src/test/java/com/google/errorprone/refaster/AbstractUTreeTest.java +++ b/core/src/test/java/com/google/errorprone/refaster/AbstractUTreeTest.java @@ -19,10 +19,10 @@ import static com.google.common.truth.Truth.assertWithMessage; import com.google.common.base.Joiner; +import com.google.errorprone.util.ErrorProneParser; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.parser.Parser; -import com.sun.tools.javac.parser.ParserFactory; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.util.Context; @@ -86,12 +86,12 @@ public void assertInlines(String expression, UStatement template) { protected JCExpression parseExpression(String contents) { Parser parser = - ParserFactory.instance(context) - .newParser( - contents, - /* keepDocComments= */ false, - /* keepEndPos= */ false, - /* keepLineMap= */ true); + ErrorProneParser.newParser( + context, + contents, + /* keepDocComments= */ false, + /* keepEndPos= */ false, + /* keepLineMap= */ true); return parser.parseExpression(); }