2323import com .sun .source .tree .ParenthesizedTree ;
2424import com .sun .source .tree .Tree ;
2525import com .sun .source .util .TreePath ;
26+ import com .sun .tools .javac .parser .JavacParser ;
27+ import com .sun .tools .javac .parser .ParserFactory ;
2628import com .sun .tools .javac .tree .JCTree ;
29+ import com .sun .tools .javac .tree .JCTree .JCCompilationUnit ;
2730import com .sun .tools .javac .tree .Pretty ;
2831import com .sun .tools .javac .tree .TreeInfo ;
2932import java .io .IOException ;
3033import java .io .UncheckedIOException ;
34+ import java .lang .invoke .MethodHandle ;
35+ import java .lang .invoke .MethodHandles ;
36+ import java .lang .invoke .MethodType ;
37+ import java .lang .invoke .VarHandle ;
38+ import javax .annotation .Nullable ;
3139import javax .lang .model .element .Name ;
3240
3341/** Utilities for working with {@link Tree}s. */
@@ -44,8 +52,73 @@ static int getStartPosition(Tree expression) {
4452
4553 /** Returns the source end position of the node. */
4654 static int getEndPosition (Tree expression , TreePath path ) {
47- return ((JCTree ) expression )
48- .getEndPosition (((JCTree .JCCompilationUnit ) path .getCompilationUnit ()).endPositions );
55+ return getEndPosition (expression , (JCCompilationUnit ) path .getCompilationUnit ());
56+ }
57+
58+ /** Returns the source end position of the node. */
59+ static int getEndPosition (Tree tree , JCCompilationUnit unit ) {
60+ try {
61+ return (int ) GET_END_POSITION .invokeExact ((JCTree ) tree , unit );
62+ } catch (RuntimeException | Error e ) {
63+ throw e ;
64+ } catch (Throwable e ) {
65+ throw new IllegalStateException (e );
66+ }
67+ }
68+
69+ /**
70+ * Creates a parser that records end positions. JDK-8372948 (JDK 27) dropped the {@code keepEndPos} argument
71+ * from {@link ParserFactory#newParser}, so the remaining four-argument overload now reads
72+ * {@code (input, keepDocComments, keepLineMap, parseModuleInfo)}.
73+ */
74+ static JavacParser newParser (
75+ ParserFactory parserFactory , CharSequence input , boolean keepDocComments , boolean keepLineMap ) {
76+ if (END_POS_TABLE_CLASS != null ) {
77+ return parserFactory .newParser (input , keepDocComments , /* keepEndPos= */ true , keepLineMap );
78+ }
79+ // The last argument is parseModuleInfo on these JDKs.
80+ return parserFactory .newParser (input , keepDocComments , keepLineMap , false );
81+ }
82+
83+ /**
84+ * {@code com.sun.tools.javac.tree.EndPosTable}, or null on JDKs that store end positions directly in the tree
85+ * (JDK-8372948, JDK 27 and later).
86+ */
87+ @ Nullable
88+ private static final Class <?> END_POS_TABLE_CLASS = endPosTableClass ();
89+
90+ /** {@code (JCTree, JCCompilationUnit) -> int}, bound to whichever end position API this JDK has. */
91+ private static final MethodHandle GET_END_POSITION = getEndPositionHandle ();
92+
93+ @ Nullable
94+ private static Class <?> endPosTableClass () {
95+ try {
96+ return Class .forName ("com.sun.tools.javac.tree.EndPosTable" );
97+ } catch (ClassNotFoundException e ) {
98+ return null ;
99+ }
100+ }
101+
102+ private static MethodHandle getEndPositionHandle () {
103+ MethodHandles .Lookup lookup = MethodHandles .lookup ();
104+ try {
105+ if (END_POS_TABLE_CLASS == null ) {
106+ // (tree, unit) -> tree.getEndPosition()
107+ return MethodHandles .dropArguments (
108+ lookup .findVirtual (JCTree .class , "getEndPosition" , MethodType .methodType (int .class )),
109+ 1 ,
110+ JCCompilationUnit .class );
111+ }
112+ // (tree, unit) -> tree.getEndPosition(unit.endPositions)
113+ return MethodHandles .filterArguments (
114+ lookup .findVirtual (
115+ JCTree .class , "getEndPosition" , MethodType .methodType (int .class , END_POS_TABLE_CLASS )),
116+ 1 ,
117+ lookup .findVarHandle (JCCompilationUnit .class , "endPositions" , END_POS_TABLE_CLASS )
118+ .toMethodHandle (VarHandle .AccessMode .GET ));
119+ } catch (ReflectiveOperationException e ) {
120+ throw new IllegalStateException ("Unsupported javac end position API" , e );
121+ }
49122 }
50123
51124 /** Returns the source text for the node. */
0 commit comments