1414
1515package com .google .googlejavaformat .java ;
1616
17- import static com .google .googlejavaformat .java .Trees .getEndPosition ;
18- import static com .google .googlejavaformat .java .Trees .getStartPosition ;
1917import static java .nio .charset .StandardCharsets .UTF_8 ;
2018
19+ import com .google .common .base .Throwables ;
2120import com .google .common .collect .ImmutableList ;
2221import com .sun .source .tree .ClassTree ;
2322import com .sun .source .tree .CompilationUnitTree ;
4140import com .sun .tools .javac .util .Options ;
4241import java .io .IOError ;
4342import java .io .IOException ;
43+ import java .lang .invoke .MethodHandle ;
44+ import java .lang .invoke .MethodHandles ;
45+ import java .lang .invoke .MethodType ;
46+ import java .lang .invoke .VarHandle ;
4447import java .net .URI ;
4548import java .util .List ;
4649import javax .lang .model .element .Name ;
4952import javax .tools .JavaFileObject ;
5053import javax .tools .SimpleJavaFileObject ;
5154import javax .tools .StandardLocation ;
55+ import org .jspecify .annotations .Nullable ;
5256
5357/** Utilities for working with {@link Tree}s. */
5458class Trees {
@@ -69,7 +73,12 @@ static int getEndPosition(Tree expression, TreePath path) {
6973
7074 /** Returns the source end position of the node. */
7175 public static int getEndPosition (Tree tree , CompilationUnitTree unit ) {
72- return ((JCTree ) tree ).getEndPosition (((JCCompilationUnit ) unit ).endPositions );
76+ try {
77+ return (int ) GET_END_POS_HANDLE .invokeExact ((JCTree ) tree , (JCCompilationUnit ) unit );
78+ } catch (Throwable e ) {
79+ Throwables .throwIfUnchecked (e );
80+ throw new AssertionError (e );
81+ }
7382 }
7483
7584 /** Returns the source text for the node. */
@@ -167,12 +176,20 @@ public String getCharContent(boolean ignoreEncodingErrors) {
167176 };
168177 Log .instance (context ).useSource (source );
169178 ParserFactory parserFactory = ParserFactory .instance (context );
170- JavacParser parser =
171- parserFactory .newParser (
172- javaInput ,
173- /* keepDocComments= */ true ,
174- /* keepEndPos= */ true ,
175- /* keepLineMap= */ true );
179+ JavacParser parser ;
180+ try {
181+ parser =
182+ (JavacParser )
183+ NEW_PARSER_HANDLE .invokeExact (
184+ parserFactory ,
185+ (CharSequence ) javaInput ,
186+ /* keepDocComments */ true ,
187+ /* keepEndPos */ true ,
188+ /* keepLineMap */ true );
189+ } catch (Throwable e ) {
190+ Throwables .throwIfUnchecked (e );
191+ throw new AssertionError (e );
192+ }
176193 JCCompilationUnit unit = parser .parseCompilationUnit ();
177194 unit .sourcefile = source ;
178195 return unit ;
@@ -186,4 +203,79 @@ private static boolean errorDiagnostic(Diagnostic<?> input) {
186203 // enclosing class
187204 return !input .getCode ().equals ("compiler.err.invalid.meth.decl.ret.type.req" );
188205 }
206+
207+ private static final @ Nullable Class <?> END_POS_TABLE_CLASS = getEndPosTableClass ();
208+
209+ private static @ Nullable Class <?> getEndPosTableClass () {
210+ try {
211+ return Class .forName ("com.sun.tools.javac.tree.EndPosTable" );
212+ } catch (ClassNotFoundException e ) {
213+ // JDK versions after https://bugs.openjdk.org/browse/JDK-8372948
214+ return null ;
215+ }
216+ }
217+
218+ private static final MethodHandle NEW_PARSER_HANDLE = getNewParserHandle ();
219+
220+ private static MethodHandle getNewParserHandle () {
221+ MethodHandles .Lookup lookup = MethodHandles .lookup ();
222+ if (END_POS_TABLE_CLASS == null ) {
223+ try {
224+ // (parserFactory, input, keepDocComments, keepEndPos, keepLineMap) ->
225+ // parserFactory.newParser(input, keepDocComments, keepLineMap)
226+ return MethodHandles .dropArguments (
227+ lookup .findVirtual (
228+ ParserFactory .class ,
229+ "newParser" ,
230+ MethodType .methodType (
231+ JavacParser .class , CharSequence .class , boolean .class , boolean .class )),
232+ 2 ,
233+ boolean .class );
234+ } catch (ReflectiveOperationException e ) {
235+ throw new LinkageError (e .getMessage (), e );
236+ }
237+ }
238+ try {
239+ // (parserFactory, input, keepDocComments, keepEndPos, keepLineMap) ->
240+ // parserFactory.newParser(input, keepDocComments, keepEndPos, keepLineMap)
241+ return lookup .findVirtual (
242+ ParserFactory .class ,
243+ "newParser" ,
244+ MethodType .methodType (
245+ JavacParser .class , CharSequence .class , boolean .class , boolean .class , boolean .class ));
246+ } catch (ReflectiveOperationException e ) {
247+ throw new LinkageError (e .getMessage (), e );
248+ }
249+ }
250+
251+ private static final MethodHandle GET_END_POS_HANDLE = getEndPosMethodHandle ();
252+
253+ private static MethodHandle getEndPosMethodHandle () {
254+ MethodHandles .Lookup lookup = MethodHandles .lookup ();
255+ if (END_POS_TABLE_CLASS == null ) {
256+ try {
257+ // (tree, unit) -> tree.getEndPosition()
258+ return MethodHandles .dropArguments (
259+ lookup .findVirtual (JCTree .class , "getEndPosition" , MethodType .methodType (int .class )),
260+ 1 ,
261+ JCCompilationUnit .class );
262+ } catch (ReflectiveOperationException e1 ) {
263+ throw new LinkageError (e1 .getMessage (), e1 );
264+ }
265+ }
266+ try {
267+ // (tree, unit) -> tree.getEndPosition(unit.endPositions)
268+ return MethodHandles .filterArguments (
269+ lookup .findVirtual (
270+ JCTree .class ,
271+ "getEndPosition" ,
272+ MethodType .methodType (int .class , END_POS_TABLE_CLASS )),
273+ 1 ,
274+ lookup
275+ .findVarHandle (JCCompilationUnit .class , "endPositions" , END_POS_TABLE_CLASS )
276+ .toMethodHandle (VarHandle .AccessMode .GET ));
277+ } catch (ReflectiveOperationException e ) {
278+ throw new LinkageError (e .getMessage (), e );
279+ }
280+ }
189281}
0 commit comments