1515 */
1616package com .google .testing .compile ;
1717
18- import static com .google .common .base .MoreObjects .firstNonNull ;
19- import static java .lang .Boolean .TRUE ;
2018import static java .nio .charset .StandardCharsets .UTF_8 ;
21- import static java .util .function .Predicate .isEqual ;
2219import static javax .tools .Diagnostic .Kind .ERROR ;
2320
2421import com .google .common .base .Joiner ;
2522import com .google .common .collect .ImmutableList ;
2623import com .google .common .collect .ImmutableListMultimap ;
27- import com .google .common .collect .ImmutableSet ;
28- import com .google .common .collect .Iterables ;
2924import com .google .common .collect .Multimaps ;
3025import com .sun .source .tree .CompilationUnitTree ;
31- import com .sun .source .tree .ErroneousTree ;
32- import com .sun .source .tree .Tree ;
3326import com .sun .source .util .JavacTask ;
34- import com .sun .source .util .TreeScanner ;
3527import com .sun .source .util .Trees ;
36- import com .sun .tools .javac .api .JavacTool ;
28+ import com .sun .tools .javac .api .JavacTrees ;
29+ import com .sun .tools .javac .file .JavacFileManager ;
30+ import com .sun .tools .javac .parser .JavacParser ;
31+ import com .sun .tools .javac .parser .ParserFactory ;
32+ import com .sun .tools .javac .tree .JCTree .JCCompilationUnit ;
3733import com .sun .tools .javac .util .Context ;
34+ import com .sun .tools .javac .util .Log ;
3835import java .io .IOException ;
36+ import java .util .ArrayList ;
3937import java .util .List ;
40- import java .util .Locale ;
4138import javax .tools .Diagnostic ;
4239import javax .tools .DiagnosticCollector ;
43- import javax .tools .JavaCompiler ;
40+ import javax .tools .DiagnosticListener ;
4441import javax .tools .JavaFileObject ;
45- import javax .tools .ToolProvider ;
4642
4743/** Methods to parse Java source files. */
48- public final class Parser {
44+ final class Parser {
4945
5046 /**
5147 * Parses {@code sources} into {@linkplain CompilationUnitTree compilation units}. This method
@@ -55,89 +51,42 @@ public final class Parser {
5551 * @throws IllegalStateException if any parsing errors occur.
5652 */
5753 static ParseResult parse (Iterable <? extends JavaFileObject > sources , String sourcesDescription ) {
58- JavaCompiler compiler = ToolProvider .getSystemJavaCompiler ();
5954 DiagnosticCollector <JavaFileObject > diagnosticCollector = new DiagnosticCollector <>();
60- InMemoryJavaFileManager fileManager =
61- new InMemoryJavaFileManager (
62- compiler .getStandardFileManager (diagnosticCollector , Locale .getDefault (), UTF_8 ));
6355 Context context = new Context ();
64- JavacTask task =
65- ((JavacTool ) compiler )
66- .getTask (
67- null , // explicitly use the default because old javac logs some output on stderr
68- fileManager ,
69- diagnosticCollector ,
70- ImmutableSet .<String >of (),
71- ImmutableSet .<String >of (),
72- sources ,
73- context );
56+ context .put (DiagnosticListener .class , diagnosticCollector );
57+ Log log = Log .instance (context );
58+ // The constructor registers the instance in the Context
59+ JavacFileManager unused = new JavacFileManager (context , true , UTF_8 );
60+ ParserFactory parserFactory = ParserFactory .instance (context );
7461 try {
75- Iterable <? extends CompilationUnitTree > parsedCompilationUnits = task .parse ();
62+ List <CompilationUnitTree > parsedCompilationUnits = new ArrayList <>();
63+ for (JavaFileObject source : sources ) {
64+ log .useSource (source );
65+ JavacParser parser =
66+ parserFactory .newParser (
67+ source .getCharContent (false ),
68+ /* keepDocComments= */ true ,
69+ /* keepEndPos= */ true ,
70+ /* keepLineMap= */ true );
71+ JCCompilationUnit unit = parser .parseCompilationUnit ();
72+ unit .sourcefile = source ;
73+ parsedCompilationUnits .add (unit );
74+ }
7675 List <Diagnostic <? extends JavaFileObject >> diagnostics = diagnosticCollector .getDiagnostics ();
77- if (foundParseErrors (parsedCompilationUnits , diagnostics )) {
76+ if (foundParseErrors (diagnostics )) {
7877 String msgPrefix = String .format ("Error while parsing %s:\n " , sourcesDescription );
7978 throw new IllegalStateException (msgPrefix + Joiner .on ('\n' ).join (diagnostics ));
8079 }
8180 return new ParseResult (
82- sortDiagnosticsByKind (diagnostics ), parsedCompilationUnits , Trees .instance (task ));
81+ sortDiagnosticsByKind (diagnostics ), parsedCompilationUnits , JavacTrees .instance (context ));
8382 } catch (IOException e ) {
8483 throw new RuntimeException (e );
85- } finally {
86- DummyJavaCompilerSubclass .closeCompiler (context );
8784 }
8885 }
8986
90- /**
91- * Returns {@code true} if errors were found while parsing source files.
92- *
93- * <p>Normally, the parser reports error diagnostics, but in some cases there are no diagnostics;
94- * instead the parse tree contains {@linkplain ErroneousTree "erroneous"} nodes.
95- */
96- private static boolean foundParseErrors (
97- Iterable <? extends CompilationUnitTree > parsedCompilationUnits ,
98- List <Diagnostic <? extends JavaFileObject >> diagnostics ) {
99- return diagnostics .stream ().map (Diagnostic ::getKind ).anyMatch (isEqual (ERROR ))
100- || Iterables .any (parsedCompilationUnits , Parser ::hasErrorNode );
101- }
102-
103- /**
104- * Returns {@code true} if the tree contains at least one {@linkplain ErroneousTree "erroneous"}
105- * node.
106- */
107- private static boolean hasErrorNode (Tree tree ) {
108- return isTrue (HAS_ERRONEOUS_NODE .scan (tree , false ));
109- }
110-
111- private static final TreeScanner <Boolean , Boolean > HAS_ERRONEOUS_NODE =
112- new TreeScanner <Boolean , Boolean >() {
113- @ Override
114- public Boolean visitErroneous (ErroneousTree node , Boolean p ) {
115- return true ;
116- }
117-
118- @ Override
119- public Boolean scan (Iterable <? extends Tree > nodes , Boolean p ) {
120- for (Tree node : firstNonNull (nodes , ImmutableList .<Tree >of ())) {
121- if (isTrue (scan (node , p ))) {
122- return true ;
123- }
124- }
125- return p ;
126- }
127-
128- @ Override
129- public Boolean scan (Tree tree , Boolean p ) {
130- return isTrue (p ) ? p : super .scan (tree , p );
131- }
132-
133- @ Override
134- public Boolean reduce (Boolean r1 , Boolean r2 ) {
135- return isTrue (r1 ) || isTrue (r2 );
136- }
137- };
138-
139- private static boolean isTrue (Boolean p ) {
140- return TRUE .equals (p );
87+ /** Returns {@code true} if errors were found while parsing source files. */
88+ private static boolean foundParseErrors (List <Diagnostic <? extends JavaFileObject >> diagnostics ) {
89+ return diagnostics .stream ().anyMatch (d -> d .getKind ().equals (ERROR ));
14190 }
14291
14392 private static ImmutableListMultimap <Diagnostic .Kind , Diagnostic <? extends JavaFileObject >>
@@ -184,20 +133,5 @@ Trees trees() {
184133 }
185134 }
186135
187- // JavaCompiler.compilerKey has protected access until Java 9, so this is a workaround.
188- private static final class DummyJavaCompilerSubclass extends com .sun .tools .javac .main .JavaCompiler {
189- private static void closeCompiler (Context context ) {
190- com .sun .tools .javac .main .JavaCompiler compiler = context .get (compilerKey );
191- if (compiler != null ) {
192- compiler .close ();
193- }
194- }
195-
196- private DummyJavaCompilerSubclass () {
197- // not instantiable
198- super (null );
199- }
200- }
201-
202136 private Parser () {}
203137}
0 commit comments