1 /*
2 * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.javac.processing;
27
28 import java.io.Closeable;
29 import java.io.IOException;
30 import java.io.PrintWriter;
31 import java.io.StringWriter;
32 import java.lang.reflect.Method;
33 import java.util.*;
34 import java.util.Map.Entry;
35 import java.util.function.Predicate;
36 import java.util.regex.*;
37
38 import javax.annotation.processing.*;
39 import javax.lang.model.SourceVersion;
40 import javax.lang.model.element.*;
41 import javax.lang.model.util.*;
42 import javax.tools.Diagnostic;
43 import javax.tools.JavaFileManager;
44 import javax.tools.JavaFileObject;
45 import javax.tools.JavaFileObject.Kind;
46
47 import static javax.tools.StandardLocation.*;
48
49 import com.sun.source.util.TaskEvent;
50 import com.sun.tools.javac.api.MultiTaskListener;
51 import com.sun.tools.javac.code.*;
52 import com.sun.tools.javac.code.DeferredCompletionFailureHandler.Handler;
53 import com.sun.tools.javac.code.Scope.WriteableScope;
54 import com.sun.tools.javac.code.Source.Feature;
55 import com.sun.tools.javac.code.Symbol.*;
56 import com.sun.tools.javac.code.Type.ClassType;
57 import com.sun.tools.javac.code.Types;
58 import com.sun.tools.javac.comp.AttrContext;
59 import com.sun.tools.javac.comp.Check;
60 import com.sun.tools.javac.comp.Enter;
61 import com.sun.tools.javac.comp.Env;
62 import com.sun.tools.javac.comp.Modules;
63 import com.sun.tools.javac.main.JavaCompiler;
64 import com.sun.tools.javac.main.Option;
65 import com.sun.tools.javac.model.JavacElements;
66 import com.sun.tools.javac.model.JavacTypes;
67 import com.sun.tools.javac.platform.PlatformDescription;
68 import com.sun.tools.javac.platform.PlatformDescription.PluginInfo;
69 import com.sun.tools.javac.resources.CompilerProperties.Errors;
70 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
71 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
72 import com.sun.tools.javac.tree.*;
73 import com.sun.tools.javac.tree.JCTree.*;
74 import com.sun.tools.javac.util.Abort;
75 import com.sun.tools.javac.util.Assert;
76 import com.sun.tools.javac.util.ClientCodeException;
77 import com.sun.tools.javac.util.Context;
78 import com.sun.tools.javac.util.Convert;
79 import com.sun.tools.javac.util.DefinedBy;
80 import com.sun.tools.javac.util.DefinedBy.Api;
81 import com.sun.tools.javac.util.Iterators;
82 import com.sun.tools.javac.util.JCDiagnostic;
83 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
84 import com.sun.tools.javac.util.JavacMessages;
85 import com.sun.tools.javac.util.List;
86 import com.sun.tools.javac.util.Log;
87 import com.sun.tools.javac.util.MatchingUtils;
88 import com.sun.tools.javac.util.ModuleHelper;
89 import com.sun.tools.javac.util.Name;
90 import com.sun.tools.javac.util.Names;
91 import com.sun.tools.javac.util.Options;
92
93 import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING;
94 import static com.sun.tools.javac.code.Kinds.Kind.*;
95 import com.sun.tools.javac.comp.Annotate;
96 import static com.sun.tools.javac.comp.CompileStates.CompileState;
97 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
98
99 /**
100 * Objects of this class hold and manage the state needed to support
101 * annotation processing.
102 *
103 * <p><b>This is NOT part of any supported API.
104 * If you write code that depends on this, you do so at your own risk.
105 * This code and its internal interfaces are subject to change or
106 * deletion without notice.</b>
107 */
108 public class JavacProcessingEnvironment implements ProcessingEnvironment, Closeable {
109 private final Options options;
110
111 private final boolean printProcessorInfo;
112 private final boolean printRounds;
113 private final boolean verbose;
114 private final boolean fatalErrors;
115 private final boolean werror;
116 private final boolean showResolveErrors;
117
118 private final JavacFiler filer;
119 private final JavacMessager messager;
120 private final JavacElements elementUtils;
121 private final JavacTypes typeUtils;
122 private final JavaCompiler compiler;
123 private final Modules modules;
124 private final Types types;
125 private final Annotate annotate;
126 private final Lint lint;
127
128 /**
129 * Holds relevant state history of which processors have been
130 * used.
131 */
132 private DiscoveredProcessors discoveredProcs;
133
134 /**
135 * Map of processor-specific options.
136 */
137 private final Map<String, String> processorOptions;
138
139 /**
140 */
141 private final Set<String> unmatchedProcessorOptions;
142
143 /**
144 * Annotations implicitly processed and claimed by javac.
145 */
146 private final Set<String> platformAnnotations;
147
148 /**
149 * Set of packages given on command line.
150 */
151 private Set<PackageSymbol> specifiedPackages = Collections.emptySet();
152
153 /** The log to be used for error reporting.
154 */
155 final Log log;
156
157 /** Diagnostic factory.
158 */
159 JCDiagnostic.Factory diags;
160
161 /**
162 * Source level of the compile.
163 */
164 Source source;
165
166 private ClassLoader processorClassLoader;
167 private ServiceLoader<Processor> serviceLoader;
168
169 private final JavaFileManager fileManager;
170
171 /**
172 * JavacMessages object used for localization
173 */
174 private JavacMessages messages;
175
176 private MultiTaskListener taskListener;
177 private final Symtab symtab;
178 private final DeferredCompletionFailureHandler dcfh;
179 private final Names names;
180 private final Enter enter;
181 private final Completer initialCompleter;
182 private final Check chk;
183
184 private final Context context;
185
186 /**
187 * Support for preview language features.
188 */
189 private final Preview preview;
190
191 /** Get the JavacProcessingEnvironment instance for this context. */
192 public static JavacProcessingEnvironment instance(Context context) {
193 JavacProcessingEnvironment instance = context.get(JavacProcessingEnvironment.class);
194 if (instance == null)
195 instance = new JavacProcessingEnvironment(context);
196 return instance;
197 }
198
199 protected JavacProcessingEnvironment(Context context) {
200 this.context = context;
201 context.put(JavacProcessingEnvironment.class, this);
202 log = Log.instance(context);
203 source = Source.instance(context);
204 diags = JCDiagnostic.Factory.instance(context);
205 options = Options.instance(context);
206 printProcessorInfo = options.isSet(Option.XPRINTPROCESSORINFO);
207 printRounds = options.isSet(Option.XPRINTROUNDS);
208 verbose = options.isSet(Option.VERBOSE);
209 lint = Lint.instance(context);
210 compiler = JavaCompiler.instance(context);
211 if (options.isSet(Option.PROC, "only") || options.isSet(Option.XPRINT)) {
212 compiler.shouldStopPolicyIfNoError = CompileState.PROCESS;
213 }
214 fatalErrors = options.isSet("fatalEnterError");
215 showResolveErrors = options.isSet("showResolveErrors");
216 werror = options.isSet(Option.WERROR);
217 fileManager = context.get(JavaFileManager.class);
218 platformAnnotations = initPlatformAnnotations();
219
220 // Initialize services before any processors are initialized
221 // in case processors use them.
222 filer = new JavacFiler(context);
223 messager = new JavacMessager(context, this);
224 elementUtils = JavacElements.instance(context);
225 typeUtils = JavacTypes.instance(context);
226 modules = Modules.instance(context);
227 types = Types.instance(context);
228 annotate = Annotate.instance(context);
229 processorOptions = initProcessorOptions();
230 unmatchedProcessorOptions = initUnmatchedProcessorOptions();
231 messages = JavacMessages.instance(context);
232 taskListener = MultiTaskListener.instance(context);
233 symtab = Symtab.instance(context);
234 dcfh = DeferredCompletionFailureHandler.instance(context);
235 names = Names.instance(context);
236 enter = Enter.instance(context);
237 initialCompleter = ClassFinder.instance(context).getCompleter();
238 chk = Check.instance(context);
239 preview = Preview.instance(context);
240 initProcessorLoader();
241 }
242
243 public void setProcessors(Iterable<? extends Processor> processors) {
244 Assert.checkNull(discoveredProcs);
245 initProcessorIterator(processors);
246 }
247
248 private Set<String> initPlatformAnnotations() {
249 final String module_prefix =
250 Feature.MODULES.allowedInSource(source) ? "java.base/" : "";
251 return Set.of(module_prefix + "java.lang.Deprecated",
252 module_prefix + "java.lang.FunctionalInterface",
253 module_prefix + "java.lang.Override",
254 module_prefix + "java.lang.SafeVarargs",
255 module_prefix + "java.lang.SuppressWarnings",
256
257 module_prefix + "java.lang.annotation.Documented",
258 module_prefix + "java.lang.annotation.Inherited",
259 module_prefix + "java.lang.annotation.Native",
260 module_prefix + "java.lang.annotation.Repeatable",
261 module_prefix + "java.lang.annotation.Retention",
262 module_prefix + "java.lang.annotation.Target",
263
264 module_prefix + "java.io.Serial");
265 }
266
267 private void initProcessorLoader() {
268 if (fileManager.hasLocation(ANNOTATION_PROCESSOR_MODULE_PATH)) {
269 try {
270 serviceLoader = fileManager.getServiceLoader(ANNOTATION_PROCESSOR_MODULE_PATH, Processor.class);
271 } catch (IOException e) {
272 throw new Abort(e);
273 }
274 } else {
275 // If processorpath is not explicitly set, use the classpath.
276 processorClassLoader = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH)
277 ? fileManager.getClassLoader(ANNOTATION_PROCESSOR_PATH)
278 : fileManager.getClassLoader(CLASS_PATH);
279
280 if (options.isSet("accessInternalAPI"))
281 ModuleHelper.addExports(getClass().getModule(), processorClassLoader.getUnnamedModule());
282
283 if (processorClassLoader != null && processorClassLoader instanceof Closeable closeable) {
284 compiler.closeables = compiler.closeables.prepend(closeable);
285 }
286 }
287 }
288
289 private void initProcessorIterator(Iterable<? extends Processor> processors) {
290 Iterator<? extends Processor> processorIterator;
291
292 if (options.isSet(Option.XPRINT)) {
293 try {
294 processorIterator = List.of(new PrintingProcessor()).iterator();
295 } catch (Throwable t) {
296 throw new AssertionError("Problem instantiating PrintingProcessor.", t);
297 }
298 } else if (processors != null) {
299 processorIterator = processors.iterator();
300 } else {
301 /*
302 * If the "-processor" option is used, search the appropriate
303 * path for the named class. Otherwise, use a service
304 * provider mechanism to create the processor iterator.
305 *
306 * Note: if an explicit processor path is not set,
307 * only the class path and _not_ the module path are
308 * searched for processors.
309 */
310 String processorNames = options.get(Option.PROCESSOR);
311 if (fileManager.hasLocation(ANNOTATION_PROCESSOR_MODULE_PATH)) {
312 processorIterator = (processorNames == null) ?
313 new ServiceIterator(serviceLoader, log) :
314 new NameServiceIterator(serviceLoader, log, processorNames);
315 } else if (processorNames != null) {
316 processorIterator = new NameProcessIterator(processorNames, processorClassLoader, log);
317 } else {
318 processorIterator = new ServiceIterator(processorClassLoader, log);
319 }
320 }
321 PlatformDescription platformProvider = context.get(PlatformDescription.class);
322 java.util.List<Processor> platformProcessors = Collections.emptyList();
323 if (platformProvider != null) {
324 platformProcessors = platformProvider.getAnnotationProcessors()
325 .stream()
326 .map(PluginInfo::getPlugin)
327 .toList();
328 }
329 List<Iterator<? extends Processor>> iterators = List.of(processorIterator,
330 platformProcessors.iterator());
331 Iterator<? extends Processor> compoundIterator =
332 Iterators.createCompoundIterator(iterators, i -> i);
333 discoveredProcs = new DiscoveredProcessors(compoundIterator);
334 }
335
336 public <S> ServiceLoader<S> getServiceLoader(Class<S> service) {
337 if (fileManager.hasLocation(ANNOTATION_PROCESSOR_MODULE_PATH)) {
338 try {
339 return fileManager.getServiceLoader(ANNOTATION_PROCESSOR_MODULE_PATH, service);
340 } catch (IOException e) {
341 throw new Abort(e);
342 }
343 } else {
344 return ServiceLoader.load(service, getProcessorClassLoader());
345 }
346 }
347
348 /**
349 * Use a service loader appropriate for the platform to provide an
350 * iterator over annotations processors; fails if a loader is
351 * needed but unavailable.
352 */
353 private class ServiceIterator implements Iterator<Processor> {
354 Iterator<Processor> iterator;
355 Log log;
356 ServiceLoader<Processor> loader;
357
358 ServiceIterator(ClassLoader classLoader, Log log) {
359 this.log = log;
360 try {
361 loader = ServiceLoader.load(Processor.class, classLoader);
362 this.iterator = loader.iterator();
363 } catch (Throwable t) {
364 log.error(Errors.ProcServiceProblem);
365 throw new Abort(t);
366 }
367 }
368
369 ServiceIterator(ServiceLoader<Processor> loader, Log log) {
370 this.log = log;
371 this.loader = loader;
372 this.iterator = loader.iterator();
373 }
374
375 @Override
376 public boolean hasNext() {
377 try {
378 return internalHasNext();
379 } catch(ServiceConfigurationError sce) {
380 log.error(Errors.ProcBadConfigFile(sce.getLocalizedMessage()));
381 throw new Abort(sce);
382 } catch (UnsupportedClassVersionError ucve) {
383 log.error(Errors.ProcCantLoadClass(ucve.getLocalizedMessage()));
384 throw new Abort(ucve);
385 } catch (ClassFormatError cfe) {
386 log.error(Errors.ProcCantLoadClass(cfe.getLocalizedMessage()));
387 throw new Abort(cfe);
388 } catch (Throwable t) {
389 log.error(Errors.ProcBadConfigFile(t.getLocalizedMessage()));
390 throw new Abort(t);
391 }
392 }
393
394 boolean internalHasNext() {
395 return iterator.hasNext();
396 }
397
398 @Override
399 public Processor next() {
400 try {
401 return internalNext();
402 } catch (ServiceConfigurationError sce) {
403 log.error(Errors.ProcBadConfigFile(sce.getLocalizedMessage()));
404 throw new Abort(sce);
405 } catch (Throwable t) {
406 log.error(Errors.ProcBadConfigFile(t.getLocalizedMessage()));
407 throw new Abort(t);
408 }
409 }
410
411 Processor internalNext() {
412 return iterator.next();
413 }
414
415 @Override
416 public void remove() {
417 throw new UnsupportedOperationException();
418 }
419
420 public void close() {
421 if (loader != null) {
422 try {
423 loader.reload();
424 } catch(Exception e) {
425 // Ignore problems during a call to reload.
426 }
427 }
428 }
429 }
430
431 private class NameServiceIterator extends ServiceIterator {
432 private Map<String, Processor> namedProcessorsMap = new HashMap<>();
433 private Iterator<String> processorNames = null;
434 private Processor nextProc = null;
435
436 public NameServiceIterator(ServiceLoader<Processor> loader, Log log, String theNames) {
437 super(loader, log);
438 this.processorNames = Arrays.asList(theNames.split(",")).iterator();
439 }
440
441 @Override
442 boolean internalHasNext() {
443 if (nextProc != null) {
444 return true;
445 }
446 if (!processorNames.hasNext()) {
447 namedProcessorsMap = null;
448 return false;
449 }
450 String processorName = processorNames.next();
451 Processor theProcessor = namedProcessorsMap.get(processorName);
452 if (theProcessor != null) {
453 namedProcessorsMap.remove(processorName);
454 nextProc = theProcessor;
455 return true;
456 } else {
457 while (iterator.hasNext()) {
458 theProcessor = iterator.next();
459 String name = theProcessor.getClass().getName();
460 if (name.equals(processorName)) {
461 nextProc = theProcessor;
462 return true;
463 } else {
464 namedProcessorsMap.put(name, theProcessor);
465 }
466 }
467 log.error(Errors.ProcProcessorNotFound(processorName));
468 return false;
469 }
470 }
471
472 @Override
473 Processor internalNext() {
474 if (hasNext()) {
475 Processor p = nextProc;
476 nextProc = null;
477 return p;
478 } else {
479 throw new NoSuchElementException();
480 }
481 }
482 }
483
484 private static class NameProcessIterator implements Iterator<Processor> {
485 Processor nextProc = null;
486 Iterator<String> names;
487 ClassLoader processorCL;
488 Log log;
489
490 NameProcessIterator(String names, ClassLoader processorCL, Log log) {
491 this.names = Arrays.asList(names.split(",")).iterator();
492 this.processorCL = processorCL;
493 this.log = log;
494 }
495
496 public boolean hasNext() {
497 if (nextProc != null)
498 return true;
499 else {
500 if (!names.hasNext()) {
501 return false;
502 } else {
503 Processor processor = getNextProcessor(names.next());
504 if (processor == null) {
505 return false;
506 } else {
507 nextProc = processor;
508 return true;
509 }
510 }
511 }
512 }
513
514 private Processor getNextProcessor(String processorName) {
515 try {
516 try {
517 Class<?> processorClass = processorCL.loadClass(processorName);
518 ensureReadable(processorClass);
519 return (Processor) processorClass.getConstructor().newInstance();
520 } catch (ClassNotFoundException cnfe) {
521 log.error(Errors.ProcProcessorNotFound(processorName));
522 return null;
523 } catch (ClassCastException cce) {
524 log.error(Errors.ProcProcessorWrongType(processorName));
525 return null;
526 } catch (Exception e ) {
527 log.error(Errors.ProcProcessorCantInstantiate(processorName));
528 return null;
529 }
530 } catch (ClientCodeException e) {
531 throw e;
532 } catch (Throwable t) {
533 throw new AnnotationProcessingError(t);
534 }
535 }
536
537 public Processor next() {
538 if (hasNext()) {
539 Processor p = nextProc;
540 nextProc = null;
541 return p;
542 } else
543 throw new NoSuchElementException();
544 }
545
546 public void remove () {
547 throw new UnsupportedOperationException();
548 }
549
550 /**
551 * Ensures that the module of the given class is readable to this
552 * module.
553 */
554 private void ensureReadable(Class<?> targetClass) {
555 try {
556 Method getModuleMethod = Class.class.getMethod("getModule");
557 Object thisModule = getModuleMethod.invoke(this.getClass());
558 Object targetModule = getModuleMethod.invoke(targetClass);
559
560 Class<?> moduleClass = getModuleMethod.getReturnType();
561 Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass);
562 addReadsMethod.invoke(thisModule, targetModule);
563 } catch (NoSuchMethodException e) {
564 // ignore
565 } catch (Exception e) {
566 throw new InternalError(e);
567 }
568 }
569 }
570
571 public boolean atLeastOneProcessor() {
572 return discoveredProcs.iterator().hasNext();
573 }
574
575 private Map<String, String> initProcessorOptions() {
576 Set<String> keySet = options.keySet();
577 Map<String, String> tempOptions = new LinkedHashMap<>();
578
579 for(String key : keySet) {
580 if (key.startsWith("-A") && key.length() > 2) {
581 int sepIndex = key.indexOf('=');
582 String candidateKey = null;
583 String candidateValue = null;
584
585 if (sepIndex == -1)
586 candidateKey = key.substring(2);
587 else if (sepIndex >= 3) {
588 candidateKey = key.substring(2, sepIndex);
589 candidateValue = (sepIndex < key.length()-1)?
590 key.substring(sepIndex+1) : null;
591 }
592 tempOptions.put(candidateKey, candidateValue);
593 }
594 }
595
596 PlatformDescription platformProvider = context.get(PlatformDescription.class);
597
598 if (platformProvider != null) {
599 for (PluginInfo<Processor> ap : platformProvider.getAnnotationProcessors()) {
600 tempOptions.putAll(ap.getOptions());
601 }
602 }
603
604 return Collections.unmodifiableMap(tempOptions);
605 }
606
607 private Set<String> initUnmatchedProcessorOptions() {
608 Set<String> unmatchedProcessorOptions = new HashSet<>();
609 unmatchedProcessorOptions.addAll(processorOptions.keySet());
610 return unmatchedProcessorOptions;
611 }
612
613 /**
614 * State about how a processor has been used by the tool. If a
615 * processor has been used on a prior round, its process method is
616 * called on all subsequent rounds, perhaps with an empty set of
617 * annotations to process. The {@code annotationSupported} method
618 * caches the supported annotation information from the first (and
619 * only) getSupportedAnnotationTypes call to the processor.
620 */
621 static class ProcessorState {
622 public Processor processor;
623 public boolean contributed;
624 private Set<String> supportedAnnotationStrings; // Used for warning generation
625 private Set<Pattern> supportedAnnotationPatterns;
626 private Set<String> supportedOptionNames;
627
628 ProcessorState(Processor p, Log log, Source source, DeferredCompletionFailureHandler dcfh,
629 boolean allowModules, ProcessingEnvironment env, Lint lint) {
630 processor = p;
631 contributed = false;
632
633 Handler prevDeferredHandler = dcfh.setHandler(dcfh.userCodeHandler);
634 try {
635 processor.init(env);
636
637 checkSourceVersionCompatibility(source, log);
638
639
640 // Check for direct duplicates in the strings of
641 // supported annotation types. Do not check for
642 // duplicates that would result after stripping of
643 // module prefixes.
644 supportedAnnotationStrings = new LinkedHashSet<>();
645 supportedAnnotationPatterns = new LinkedHashSet<>();
646 for (String annotationPattern : processor.getSupportedAnnotationTypes()) {
647 boolean patternAdded = supportedAnnotationStrings.add(annotationPattern);
648
649 supportedAnnotationPatterns.
650 add(importStringToPattern(allowModules, annotationPattern,
651 processor, log, lint));
652 if (!patternAdded) {
653 lint.logIfEnabled(LintWarnings.ProcDuplicateSupportedAnnotation(annotationPattern,
654 p.getClass().getName()));
655 }
656 }
657
658 // If a processor supports "*", that matches
659 // everything and other entries are redundant. With
660 // more work, it could be checked that the supported
661 // annotation types were otherwise non-overlapping
662 // with each other in other cases, for example "foo.*"
663 // and "foo.bar.*".
664 if (supportedAnnotationPatterns.contains(MatchingUtils.validImportStringToPattern("*")) &&
665 supportedAnnotationPatterns.size() > 1) {
666 lint.logIfEnabled(LintWarnings.ProcRedundantTypesWithWildcard(p.getClass().getName()));
667 }
668
669 supportedOptionNames = new LinkedHashSet<>();
670 for (String optionName : processor.getSupportedOptions() ) {
671 if (checkOptionName(optionName, log)) {
672 boolean optionAdded = supportedOptionNames.add(optionName);
673 if (!optionAdded) {
674 lint.logIfEnabled(LintWarnings.ProcDuplicateOptionName(optionName,
675 p.getClass().getName()));
676 }
677 }
678 }
679
680 } catch (ClientCodeException e) {
681 throw e;
682 } catch (Throwable t) {
683 throw new AnnotationProcessingError(t);
684 } finally {
685 dcfh.setHandler(prevDeferredHandler);
686 }
687 }
688
689 /**
690 * Checks whether or not a processor's source version is
691 * compatible with the compilation source version. The
692 * processor's source version needs to be greater than or
693 * equal to the source version of the compile.
694 */
695 private void checkSourceVersionCompatibility(Source source, Log log) {
696 SourceVersion procSourceVersion = processor.getSupportedSourceVersion();
697 if (procSourceVersion.compareTo(Source.toSourceVersion(source)) < 0 ) {
698 log.warning(Warnings.ProcProcessorIncompatibleSourceVersion(procSourceVersion,
699 processor.getClass().getName(),
700 source.name));
701 }
702 }
703
704 private boolean checkOptionName(String optionName, Log log) {
705 boolean valid = isValidOptionName(optionName);
706 if (!valid)
707 log.error(Errors.ProcProcessorBadOptionName(optionName,
708 processor.getClass().getName()));
709 return valid;
710 }
711
712 public boolean annotationSupported(String annotationName) {
713 for(Pattern p: supportedAnnotationPatterns) {
714 if (p.matcher(annotationName).matches())
715 return true;
716 }
717 return false;
718 }
719
720 /**
721 * Remove options that are matched by this processor.
722 */
723 public void removeSupportedOptions(Set<String> unmatchedProcessorOptions) {
724 unmatchedProcessorOptions.removeAll(supportedOptionNames);
725 }
726 }
727
728 // TODO: These two classes can probably be rewritten better...
729 /**
730 * This class holds information about the processors that have
731 * been discovered so far as well as the means to discover more, if
732 * necessary. A single iterator should be used per round of
733 * annotation processing. The iterator first visits already
734 * discovered processors then fails over to the service provider
735 * mechanism if additional queries are made.
736 */
737 class DiscoveredProcessors implements Iterable<ProcessorState> {
738
739 class ProcessorStateIterator implements Iterator<ProcessorState> {
740 DiscoveredProcessors psi;
741 Iterator<ProcessorState> innerIter;
742 boolean onProcIterator;
743
744 ProcessorStateIterator(DiscoveredProcessors psi) {
745 this.psi = psi;
746 this.innerIter = psi.procStateList.iterator();
747 this.onProcIterator = false;
748 }
749
750 public ProcessorState next() {
751 if (!onProcIterator) {
752 if (innerIter.hasNext())
753 return innerIter.next();
754 else
755 onProcIterator = true;
756 }
757
758 if (psi.processorIterator.hasNext()) {
759 ProcessorState ps = new ProcessorState(psi.processorIterator.next(),
760 log, source, dcfh,
761 Feature.MODULES.allowedInSource(source),
762 JavacProcessingEnvironment.this,
763 lint);
764 psi.procStateList.add(ps);
765 return ps;
766 } else
767 throw new NoSuchElementException();
768 }
769
770 public boolean hasNext() {
771 if (onProcIterator)
772 return psi.processorIterator.hasNext();
773 else
774 return innerIter.hasNext() || psi.processorIterator.hasNext();
775 }
776
777 public void remove () {
778 throw new UnsupportedOperationException();
779 }
780
781 /**
782 * Run all remaining processors on the procStateList that
783 * have not already run this round with an empty set of
784 * annotations.
785 */
786 public void runContributingProcs(RoundEnvironment re) {
787 if (!onProcIterator) {
788 Set<TypeElement> emptyTypeElements = Collections.emptySet();
789 while(innerIter.hasNext()) {
790 ProcessorState ps = innerIter.next();
791 if (ps.contributed)
792 callProcessor(ps.processor, emptyTypeElements, re);
793 }
794 }
795 }
796 }
797
798 Iterator<? extends Processor> processorIterator;
799 ArrayList<ProcessorState> procStateList;
800
801 public ProcessorStateIterator iterator() {
802 return new ProcessorStateIterator(this);
803 }
804
805 DiscoveredProcessors(Iterator<? extends Processor> processorIterator) {
806 this.processorIterator = processorIterator;
807 this.procStateList = new ArrayList<>();
808 }
809
810 /**
811 * Free jar files, etc. if using a service loader.
812 */
813 public void close() {
814 if (processorIterator != null &&
815 processorIterator instanceof ServiceIterator serviceIterator) {
816 serviceIterator.close();
817 }
818 }
819 }
820
821 private void discoverAndRunProcs(Set<TypeElement> annotationsPresent,
822 List<ClassSymbol> topLevelClasses,
823 List<PackageSymbol> packageInfoFiles,
824 List<ModuleSymbol> moduleInfoFiles) {
825 Map<String, TypeElement> unmatchedAnnotations = new HashMap<>(annotationsPresent.size());
826
827 for(TypeElement a : annotationsPresent) {
828 ModuleElement mod = elementUtils.getModuleOf(a);
829 String moduleSpec = Feature.MODULES.allowedInSource(source) && mod != null ? mod.getQualifiedName() + "/" : "";
830 unmatchedAnnotations.put(moduleSpec + a.getQualifiedName().toString(),
831 a);
832 }
833
834 // Give "*" processors a chance to match
835 if (unmatchedAnnotations.size() == 0)
836 unmatchedAnnotations.put("", null);
837
838 DiscoveredProcessors.ProcessorStateIterator psi = discoveredProcs.iterator();
839 // TODO: Create proper argument values; need past round
840 // information to fill in this constructor. Note that the 1
841 // st round of processing could be the last round if there
842 // were parse errors on the initial source files; however, we
843 // are not doing processing in that case.
844
845 Set<Element> rootElements = new LinkedHashSet<>();
846 rootElements.addAll(topLevelClasses);
847 rootElements.addAll(packageInfoFiles);
848 rootElements.addAll(moduleInfoFiles);
849 rootElements = Collections.unmodifiableSet(rootElements);
850
851 RoundEnvironment renv = new JavacRoundEnvironment(false,
852 false,
853 rootElements,
854 JavacProcessingEnvironment.this);
855
856 while(unmatchedAnnotations.size() > 0 && psi.hasNext() ) {
857 ProcessorState ps = psi.next();
858 Set<String> matchedNames = new HashSet<>();
859 Set<TypeElement> typeElements = new LinkedHashSet<>();
860
861 for (Map.Entry<String, TypeElement> entry: unmatchedAnnotations.entrySet()) {
862 String unmatchedAnnotationName = entry.getKey();
863 if (ps.annotationSupported(unmatchedAnnotationName) ) {
864 matchedNames.add(unmatchedAnnotationName);
865 TypeElement te = entry.getValue();
866 if (te != null)
867 typeElements.add(te);
868 }
869 }
870
871 if (matchedNames.size() > 0 || ps.contributed) {
872 boolean processingResult = callProcessor(ps.processor, typeElements, renv);
873 ps.contributed = true;
874 ps.removeSupportedOptions(unmatchedProcessorOptions);
875
876 if (printProcessorInfo || verbose) {
877 log.printLines("x.print.processor.info",
878 ps.processor.getClass().getName(),
879 matchedNames.toString(),
880 processingResult);
881 }
882
883 if (processingResult) {
884 unmatchedAnnotations.keySet().removeAll(matchedNames);
885 }
886
887 }
888 }
889 unmatchedAnnotations.remove("");
890
891 if (lint.isEnabled(PROCESSING) && unmatchedAnnotations.size() > 0) {
892 // Remove annotations processed by javac
893 unmatchedAnnotations.keySet().removeAll(platformAnnotations);
894 if (unmatchedAnnotations.size() > 0) {
895 log.warning(LintWarnings.ProcAnnotationsWithoutProcessors(unmatchedAnnotations.keySet()));
896 }
897 }
898
899 // Run contributing processors that haven't run yet
900 psi.runContributingProcs(renv);
901 }
902
903 /**
904 * Computes the set of annotations on the symbol in question.
905 * Leave class public for external testing purposes.
906 */
907 public static class ComputeAnnotationSet extends
908 ElementScanner14<Set<TypeElement>, Set<TypeElement>> {
909 final Elements elements;
910
911 public ComputeAnnotationSet(Elements elements) {
912 super();
913 this.elements = elements;
914 }
915
916 @Override @DefinedBy(Api.LANGUAGE_MODEL)
917 public Set<TypeElement> visitPackage(PackageElement e, Set<TypeElement> p) {
918 // Don't scan enclosed elements of a package
919 return p;
920 }
921
922 @Override @DefinedBy(Api.LANGUAGE_MODEL)
923 public Set<TypeElement> visitType(TypeElement e, Set<TypeElement> p) {
924 // Type parameters are not considered to be enclosed by a type
925 scan(e.getTypeParameters(), p);
926 return super.visitType(e, p);
927 }
928
929 @Override @DefinedBy(Api.LANGUAGE_MODEL)
930 public Set<TypeElement> visitExecutable(ExecutableElement e, Set<TypeElement> p) {
931 // Type parameters are not considered to be enclosed by an executable
932 scan(e.getTypeParameters(), p);
933 return super.visitExecutable(e, p);
934 }
935
936 void addAnnotations(Element e, Set<TypeElement> p) {
937 for (AnnotationMirror annotationMirror :
938 elements.getAllAnnotationMirrors(e) ) {
939 Element e2 = annotationMirror.getAnnotationType().asElement();
940 p.add((TypeElement) e2);
941 }
942 }
943
944 @Override @DefinedBy(Api.LANGUAGE_MODEL)
945 public Set<TypeElement> scan(Element e, Set<TypeElement> p) {
946 addAnnotations(e, p);
947 return super.scan(e, p);
948 }
949 }
950
951 private boolean callProcessor(Processor proc,
952 Set<? extends TypeElement> tes,
953 RoundEnvironment renv) {
954 Handler prevDeferredHandler = dcfh.setHandler(dcfh.userCodeHandler);
955 try {
956 return proc.process(tes, renv);
957 } catch (ClassFinder.BadClassFile ex) {
958 log.error(Errors.ProcCantAccess1(ex.sym, ex.getDetailValue()));
959 return false;
960 } catch (CompletionFailure ex) {
961 StringWriter out = new StringWriter();
962 ex.printStackTrace(new PrintWriter(out));
963 log.error(Errors.ProcCantAccess(ex.sym, ex.getDetailValue(), out.toString()));
964 return false;
965 } catch (ClientCodeException e) {
966 throw e;
967 } catch (Throwable t) {
968 throw new AnnotationProcessingError(t);
969 } finally {
970 dcfh.setHandler(prevDeferredHandler);
971 }
972 }
973
974 /**
975 * Helper object for a single round of annotation processing.
976 */
977 class Round {
978 /** The round number. */
979 final int number;
980 /** The diagnostic handler for the round. */
981 final Log.DeferredDiagnosticHandler deferredDiagnosticHandler;
982
983 /** The ASTs to be compiled. */
984 List<JCCompilationUnit> roots;
985 /** The trees that need to be cleaned - includes roots and implicitly parsed trees. */
986 Set<JCCompilationUnit> treesToClean;
987 /** The classes to be compiler that have were generated. */
988 Map<ModuleSymbol, Map<String, JavaFileObject>> genClassFiles;
989
990 /** The set of annotations to be processed this round. */
991 Set<TypeElement> annotationsPresent;
992 /** The set of top level classes to be processed this round. */
993 List<ClassSymbol> topLevelClasses;
994 /** The set of package-info files to be processed this round. */
995 List<PackageSymbol> packageInfoFiles;
996 /** The set of module-info files to be processed this round. */
997 List<ModuleSymbol> moduleInfoFiles;
998
999 /** Create a round (common code). */
1000 private Round(int number, Set<JCCompilationUnit> treesToClean,
1001 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
1002 this.number = number;
1003
1004 if (number == 1) {
1005 Assert.checkNonNull(deferredDiagnosticHandler);
1006 this.deferredDiagnosticHandler = deferredDiagnosticHandler;
1007 } else {
1008 this.deferredDiagnosticHandler = log.new DeferredDiagnosticHandler();
1009 compiler.setDeferredDiagnosticHandler(this.deferredDiagnosticHandler);
1010 }
1011
1012 // the following will be populated as needed
1013 topLevelClasses = List.nil();
1014 packageInfoFiles = List.nil();
1015 moduleInfoFiles = List.nil();
1016 this.treesToClean = treesToClean;
1017 }
1018
1019 /** Create the first round. */
1020 Round(List<JCCompilationUnit> roots,
1021 List<ClassSymbol> classSymbols,
1022 Set<JCCompilationUnit> treesToClean,
1023 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
1024 this(1, treesToClean, deferredDiagnosticHandler);
1025 this.roots = roots;
1026 genClassFiles = new HashMap<>();
1027
1028 // The reverse() in the following line is to maintain behavioural
1029 // compatibility with the previous revision of the code. Strictly speaking,
1030 // it should not be necessary, but a javah golden file test fails without it.
1031 topLevelClasses =
1032 getTopLevelClasses(roots).prependList(classSymbols.reverse());
1033
1034 packageInfoFiles = getPackageInfoFiles(roots);
1035
1036 moduleInfoFiles = getModuleInfoFiles(roots);
1037
1038 findAnnotationsPresent();
1039 }
1040
1041 /** Create a new round. */
1042 private Round(Round prev,
1043 Set<JavaFileObject> newSourceFiles, Map<ModuleSymbol, Map<String,JavaFileObject>> newClassFiles) {
1044 this(prev.number+1, prev.treesToClean, null);
1045 prev.newRound();
1046 this.genClassFiles = prev.genClassFiles;
1047
1048 //parse the generated files even despite errors reported so far, to eliminate
1049 //recoverable errors related to the type declared in the generated files:
1050 List<JCCompilationUnit> parsedFiles = compiler.parseFiles(newSourceFiles, true);
1051 roots = prev.roots.appendList(parsedFiles);
1052
1053 // Check for errors after parsing
1054 if (unrecoverableError()) {
1055 compiler.initModules(List.nil());
1056 return;
1057 }
1058
1059 roots = compiler.initModules(roots);
1060
1061 enterClassFiles(genClassFiles);
1062 List<ClassSymbol> newClasses = enterClassFiles(newClassFiles);
1063 for (Entry<ModuleSymbol, Map<String, JavaFileObject>> moduleAndClassFiles : newClassFiles.entrySet()) {
1064 genClassFiles.computeIfAbsent(moduleAndClassFiles.getKey(), m -> new LinkedHashMap<>()).putAll(moduleAndClassFiles.getValue());
1065 }
1066 enterTrees(roots);
1067
1068 if (unrecoverableError())
1069 return;
1070
1071 topLevelClasses = join(
1072 getTopLevelClasses(parsedFiles),
1073 getTopLevelClassesFromClasses(newClasses));
1074
1075 packageInfoFiles = join(
1076 getPackageInfoFiles(parsedFiles),
1077 getPackageInfoFilesFromClasses(newClasses));
1078
1079 moduleInfoFiles = List.nil(); //module-info cannot be generated
1080
1081 findAnnotationsPresent();
1082 }
1083
1084 /** Create the next round to be used. */
1085 Round next(Set<JavaFileObject> newSourceFiles, Map<ModuleSymbol, Map<String, JavaFileObject>> newClassFiles) {
1086 return new Round(this, newSourceFiles, newClassFiles);
1087 }
1088
1089 /** Prepare the compiler for the final compilation. */
1090 void finalCompiler() {
1091 newRound();
1092 }
1093
1094 /** Return the number of errors found so far in this round.
1095 * This may include unrecoverable errors, such as parse errors,
1096 * and transient errors, such as missing symbols. */
1097 int errorCount() {
1098 return compiler.errorCount();
1099 }
1100
1101 /** Return the number of warnings found so far in this round. */
1102 int warningCount() {
1103 return compiler.warningCount();
1104 }
1105
1106 /** Return whether or not an unrecoverable error has occurred. */
1107 boolean unrecoverableError() {
1108 if (messager.errorRaised())
1109 return true;
1110
1111 return deferredDiagnosticHandler.getDiagnostics().stream()
1112 .anyMatch(d -> (d.getKind() == Diagnostic.Kind.WARNING && werror) ||
1113 (d.getKind() == Diagnostic.Kind.ERROR && (fatalErrors || !d.isFlagSet(RECOVERABLE))));
1114 }
1115
1116 /** Find the set of annotations present in the set of top level
1117 * classes and package info files to be processed this round. */
1118 void findAnnotationsPresent() {
1119 ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(elementUtils);
1120 // Use annotation processing to compute the set of annotations present
1121 annotationsPresent = new LinkedHashSet<>();
1122 for (ClassSymbol classSym : topLevelClasses)
1123 annotationComputer.scan(classSym, annotationsPresent);
1124 for (PackageSymbol pkgSym : packageInfoFiles)
1125 annotationComputer.scan(pkgSym, annotationsPresent);
1126 for (ModuleSymbol mdlSym : moduleInfoFiles)
1127 annotationComputer.scan(mdlSym, annotationsPresent);
1128 }
1129
1130 /** Enter a set of generated class files. */
1131 private List<ClassSymbol> enterClassFiles(Map<ModuleSymbol, Map<String, JavaFileObject>> modulesAndClassFiles) {
1132 List<ClassSymbol> list = List.nil();
1133
1134 for (Entry<ModuleSymbol, Map<String, JavaFileObject>> moduleAndClassFiles : modulesAndClassFiles.entrySet()) {
1135 for (Map.Entry<String,JavaFileObject> entry : moduleAndClassFiles.getValue().entrySet()) {
1136 Name name = names.fromString(entry.getKey());
1137 JavaFileObject file = entry.getValue();
1138 if (file.getKind() != JavaFileObject.Kind.CLASS)
1139 throw new AssertionError(file);
1140 ClassSymbol cs;
1141 if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) {
1142 Name packageName = Convert.packagePart(name);
1143 PackageSymbol p = symtab.enterPackage(moduleAndClassFiles.getKey(), packageName);
1144 if (p.package_info == null)
1145 p.package_info = symtab.enterClass(moduleAndClassFiles.getKey(), Convert.shortName(name), p);
1146 cs = p.package_info;
1147 cs.reset();
1148 if (cs.classfile == null)
1149 cs.classfile = file;
1150 cs.completer = initialCompleter;
1151 } else {
1152 cs = symtab.enterClass(moduleAndClassFiles.getKey(), name);
1153 cs.reset();
1154 cs.classfile = file;
1155 cs.completer = initialCompleter;
1156 if (cs.owner.kind == PCK) {
1157 cs.owner.members().enter(cs); //XXX - OverwriteBetweenCompilations; syms.getClass is not sufficient anymore
1158 }
1159 }
1160 list = list.prepend(cs);
1161 }
1162 }
1163 return list.reverse();
1164 }
1165
1166 /** Enter a set of syntax trees. */
1167 private void enterTrees(List<JCCompilationUnit> roots) {
1168 compiler.enterTrees(roots);
1169 }
1170
1171 /** Run a processing round. */
1172 void run(boolean lastRound, boolean errorStatus) {
1173 printRoundInfo(lastRound);
1174
1175 if (!taskListener.isEmpty())
1176 taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
1177
1178 try {
1179 if (lastRound) {
1180 filer.setLastRound(true);
1181 Set<Element> emptyRootElements = Collections.emptySet(); // immutable
1182 RoundEnvironment renv = new JavacRoundEnvironment(true,
1183 errorStatus,
1184 emptyRootElements,
1185 JavacProcessingEnvironment.this);
1186 discoveredProcs.iterator().runContributingProcs(renv);
1187 } else {
1188 discoverAndRunProcs(annotationsPresent, topLevelClasses, packageInfoFiles, moduleInfoFiles);
1189 }
1190 } catch (Throwable t) {
1191 // we're specifically expecting Abort here, but if any Throwable
1192 // comes by, we should flush all deferred diagnostics, rather than
1193 // drop them on the ground.
1194 compiler.reportDeferredDiagnosticAndClearHandler();
1195 throw t;
1196 } finally {
1197 if (!taskListener.isEmpty())
1198 taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
1199 }
1200 }
1201
1202 void showDiagnostics(boolean showAll) {
1203 deferredDiagnosticHandler.reportDeferredDiagnostics(showAll ? ACCEPT_ALL
1204 : ACCEPT_NON_RECOVERABLE);
1205 log.popDiagnosticHandler(deferredDiagnosticHandler);
1206 compiler.setDeferredDiagnosticHandler(null);
1207 }
1208 //where:
1209 private final Predicate<JCDiagnostic> ACCEPT_NON_RECOVERABLE =
1210 d -> d.getKind() != JCDiagnostic.Kind.ERROR ||
1211 !d.isFlagSet(DiagnosticFlag.RECOVERABLE) ||
1212 d.isFlagSet(DiagnosticFlag.API);
1213 private final Predicate<JCDiagnostic> ACCEPT_ALL = d -> true;
1214
1215 /** Print info about this round. */
1216 private void printRoundInfo(boolean lastRound) {
1217 if (printRounds || verbose) {
1218 List<ClassSymbol> tlc = lastRound ? List.nil() : topLevelClasses;
1219 Set<TypeElement> ap = lastRound ? Collections.emptySet() : annotationsPresent;
1220 log.printLines("x.print.rounds",
1221 number,
1222 "{" + tlc.toString(", ") + "}",
1223 ap,
1224 lastRound);
1225 }
1226 }
1227
1228 /** Prepare for new round of annotation processing. Cleans trees, resets symbols, and
1229 * asks selected services to prepare to a new round of annotation processing.
1230 */
1231 private void newRound() {
1232 //ensure treesToClean contains all trees, including implicitly parsed ones
1233 for (Env<AttrContext> env : enter.getEnvs()) {
1234 treesToClean.add(env.toplevel);
1235 }
1236 for (JCCompilationUnit node : treesToClean) {
1237 treeCleaner.scan(node);
1238 }
1239 chk.newRound();
1240 enter.newRound();
1241 filer.newRound();
1242 messager.newRound();
1243 compiler.newRound();
1244 modules.newRound();
1245 types.newRound();
1246 annotate.newRound();
1247 elementUtils.newRound();
1248
1249 boolean foundError = false;
1250
1251 for (ClassSymbol cs : symtab.getAllClasses()) {
1252 if (cs.kind == ERR) {
1253 foundError = true;
1254 break;
1255 }
1256 }
1257
1258 if (foundError) {
1259 for (ClassSymbol cs : symtab.getAllClasses()) {
1260 if (cs.classfile != null || cs.kind == ERR) {
1261 Kinds.Kind symKind = cs.kind;
1262 cs.reset();
1263 if (symKind == ERR) {
1264 cs.type = new ClassType(cs.type.getEnclosingType(), null, cs);
1265 }
1266 if (cs.isCompleted()) {
1267 cs.completer = initialCompleter;
1268 }
1269 }
1270 }
1271 }
1272 }
1273 }
1274
1275
1276 // TODO: internal catch clauses?; catch and rethrow an annotation
1277 // processing error
1278 public boolean doProcessing(List<JCCompilationUnit> roots,
1279 List<ClassSymbol> classSymbols,
1280 Iterable<? extends PackageSymbol> pckSymbols,
1281 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
1282 final Set<JCCompilationUnit> treesToClean =
1283 Collections.newSetFromMap(new IdentityHashMap<JCCompilationUnit, Boolean>());
1284
1285 //fill already attributed implicit trees:
1286 for (Env<AttrContext> env : enter.getEnvs()) {
1287 treesToClean.add(env.toplevel);
1288 }
1289
1290 Set<PackageSymbol> specifiedPackages = new LinkedHashSet<>();
1291 for (PackageSymbol psym : pckSymbols)
1292 specifiedPackages.add(psym);
1293 this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages);
1294
1295 Round round = new Round(roots, classSymbols, treesToClean, deferredDiagnosticHandler);
1296
1297 boolean errorStatus;
1298 boolean moreToDo;
1299 do {
1300 // Run processors for round n
1301 round.run(false, false);
1302
1303 // Processors for round n have run to completion.
1304 // Check for errors and whether there is more work to do.
1305 errorStatus = round.unrecoverableError();
1306 moreToDo = moreToDo();
1307
1308 round.showDiagnostics(showResolveErrors);
1309
1310 // Set up next round.
1311 // Copy mutable collections returned from filer.
1312 round = round.next(
1313 new LinkedHashSet<>(filer.getGeneratedSourceFileObjects()),
1314 new LinkedHashMap<>(filer.getGeneratedClasses()));
1315
1316 // Check for errors during setup.
1317 if (round.unrecoverableError())
1318 errorStatus = true;
1319
1320 } while (moreToDo && !errorStatus);
1321
1322 // run last round
1323 round.run(true, errorStatus);
1324 round.showDiagnostics(true);
1325
1326 filer.warnIfUnclosedFiles();
1327 warnIfUnmatchedOptions();
1328
1329 /*
1330 * If an annotation processor raises an error in a round,
1331 * that round runs to completion and one last round occurs.
1332 * The last round may also occur because no more source or
1333 * class files have been generated. Therefore, if an error
1334 * was raised on either of the last *two* rounds, the compile
1335 * should exit with a nonzero exit code. The current value of
1336 * errorStatus holds whether or not an error was raised on the
1337 * second to last round; errorRaised() gives the error status
1338 * of the last round.
1339 */
1340 if (messager.errorRaised()
1341 || werror && round.warningCount() > 0 && round.errorCount() > 0)
1342 errorStatus = true;
1343
1344 Set<JavaFileObject> newSourceFiles =
1345 new LinkedHashSet<>(filer.getGeneratedSourceFileObjects());
1346 roots = round.roots;
1347
1348 errorStatus = errorStatus || (compiler.errorCount() > 0);
1349
1350
1351 if (newSourceFiles.size() > 0)
1352 roots = roots.appendList(compiler.parseFiles(newSourceFiles));
1353
1354 errorStatus = errorStatus || (compiler.errorCount() > 0);
1355
1356 if (errorStatus && compiler.errorCount() == 0) {
1357 compiler.log.nerrors++;
1358 }
1359
1360 if (compiler.continueAfterProcessAnnotations()) {
1361 round.finalCompiler();
1362 compiler.enterTrees(compiler.initModules(roots));
1363 } else {
1364 compiler.todo.clear();
1365 }
1366
1367 // Free resources
1368 this.close();
1369
1370 if (!taskListener.isEmpty())
1371 taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
1372
1373 return true;
1374 }
1375
1376 private void warnIfUnmatchedOptions() {
1377 if (!unmatchedProcessorOptions.isEmpty()) {
1378 log.warning(Warnings.ProcUnmatchedProcessorOptions(unmatchedProcessorOptions.toString()));
1379 }
1380 }
1381
1382 /**
1383 * Free resources related to annotation processing.
1384 */
1385 public void close() {
1386 filer.close();
1387 if (discoveredProcs != null) // Make calling close idempotent
1388 discoveredProcs.close();
1389 discoveredProcs = null;
1390 }
1391
1392 private List<ClassSymbol> getTopLevelClasses(List<? extends JCCompilationUnit> units) {
1393 List<ClassSymbol> classes = List.nil();
1394 for (JCCompilationUnit unit : units) {
1395 for (JCTree node : unit.defs) {
1396 if (node.hasTag(JCTree.Tag.CLASSDEF)) {
1397 ClassSymbol sym = ((JCClassDecl) node).sym;
1398 Assert.checkNonNull(sym);
1399 classes = classes.prepend(sym);
1400 }
1401 }
1402 }
1403 return classes.reverse();
1404 }
1405
1406 private List<ClassSymbol> getTopLevelClassesFromClasses(List<? extends ClassSymbol> syms) {
1407 List<ClassSymbol> classes = List.nil();
1408 for (ClassSymbol sym : syms) {
1409 if (!isPkgInfo(sym)) {
1410 classes = classes.prepend(sym);
1411 }
1412 }
1413 return classes.reverse();
1414 }
1415
1416 private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) {
1417 List<PackageSymbol> packages = List.nil();
1418 for (JCCompilationUnit unit : units) {
1419 if (isPkgInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE)) {
1420 packages = packages.prepend(unit.packge);
1421 }
1422 }
1423 return packages.reverse();
1424 }
1425
1426 private List<PackageSymbol> getPackageInfoFilesFromClasses(List<? extends ClassSymbol> syms) {
1427 List<PackageSymbol> packages = List.nil();
1428 for (ClassSymbol sym : syms) {
1429 if (isPkgInfo(sym)) {
1430 packages = packages.prepend((PackageSymbol) sym.owner);
1431 }
1432 }
1433 return packages.reverse();
1434 }
1435
1436 private List<ModuleSymbol> getModuleInfoFiles(List<? extends JCCompilationUnit> units) {
1437 List<ModuleSymbol> modules = List.nil();
1438 for (JCCompilationUnit unit : units) {
1439 if (isModuleInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE) && unit.defs.nonEmpty()) {
1440 for (JCTree tree : unit.defs) {
1441 if (tree.hasTag(Tag.IMPORT)) {
1442 continue;
1443 }
1444 else if (tree.hasTag(Tag.MODULEDEF)) {
1445 modules = modules.prepend(unit.modle);
1446 break;
1447 }
1448 else {
1449 break;
1450 }
1451 }
1452 }
1453 }
1454 return modules.reverse();
1455 }
1456
1457 // avoid unchecked warning from use of varargs
1458 private static <T> List<T> join(List<T> list1, List<T> list2) {
1459 return list1.appendList(list2);
1460 }
1461
1462 private boolean isPkgInfo(JavaFileObject fo, JavaFileObject.Kind kind) {
1463 return fo.isNameCompatible("package-info", kind);
1464 }
1465
1466 private boolean isPkgInfo(ClassSymbol sym) {
1467 return isPkgInfo(sym.classfile, JavaFileObject.Kind.CLASS) && (sym.packge().package_info == sym);
1468 }
1469
1470 private boolean isModuleInfo(JavaFileObject fo, JavaFileObject.Kind kind) {
1471 return fo.isNameCompatible("module-info", kind);
1472 }
1473
1474 class ImplicitCompleter implements Completer {
1475
1476 private final JCCompilationUnit topLevel;
1477
1478 public ImplicitCompleter(JCCompilationUnit topLevel) {
1479 this.topLevel = topLevel;
1480 }
1481
1482 @Override public void complete(Symbol sym) throws CompletionFailure {
1483 compiler.readSourceFile(topLevel, (ClassSymbol) sym);
1484 }
1485 }
1486
1487 private final TreeScanner treeCleaner = new TreeScanner() {
1488 public void scan(JCTree node) {
1489 super.scan(node);
1490 if (node != null)
1491 node.type = null;
1492 }
1493 JCCompilationUnit topLevel;
1494 public void visitTopLevel(JCCompilationUnit node) {
1495 if (node.packge != null) {
1496 if (isPkgInfo(node.sourcefile, Kind.SOURCE)) {
1497 node.packge.package_info.reset();
1498 }
1499 node.packge.reset();
1500 }
1501 if (isModuleInfo(node.sourcefile, Kind.SOURCE)) {
1502 node.modle.reset();
1503 node.modle.completer = sym -> modules.enter(List.of(node), node.modle.module_info);
1504 node.modle.module_info.reset();
1505 node.modle.module_info.members_field = WriteableScope.create(node.modle.module_info);
1506 }
1507 node.packge = null;
1508 topLevel = node;
1509 try {
1510 super.visitTopLevel(node);
1511 } finally {
1512 topLevel = null;
1513 }
1514 }
1515 public void visitClassDef(JCClassDecl node) {
1516 super.visitClassDef(node);
1517 // remove generated constructor that may have been added during attribution:
1518 List<JCTree> beforeConstructor = List.nil();
1519 List<JCTree> defs = node.defs;
1520 while (defs.nonEmpty() && !defs.head.hasTag(Tag.METHODDEF)) {
1521 beforeConstructor = beforeConstructor.prepend(defs.head);
1522 defs = defs.tail;
1523 }
1524 if (defs.nonEmpty() &&
1525 (((JCMethodDecl) defs.head).mods.flags & Flags.GENERATEDCONSTR) != 0) {
1526 defs = defs.tail;
1527 while (beforeConstructor.nonEmpty()) {
1528 defs = defs.prepend(beforeConstructor.head);
1529 beforeConstructor = beforeConstructor.tail;
1530 }
1531 node.defs = defs;
1532 }
1533 if (node.sym != null) {
1534 node.sym.completer = new ImplicitCompleter(topLevel);
1535 List<? extends RecordComponent> recordComponents = node.sym.getRecordComponents();
1536 for (RecordComponent rc : recordComponents) {
1537 List<JCAnnotation> originalAnnos = rc.getOriginalAnnos();
1538 originalAnnos.forEach(a -> visitAnnotation(a));
1539 }
1540 // we should empty the list of permitted subclasses for next round
1541 node.sym.clearPermittedSubclasses();
1542 }
1543 node.sym = null;
1544 }
1545 public void visitMethodDef(JCMethodDecl node) {
1546 // remove super constructor call that may have been added during attribution:
1547 if (TreeInfo.isConstructor(node) && node.sym != null && node.sym.owner.isEnum() &&
1548 node.body != null && node.body.stats.nonEmpty() && TreeInfo.isSuperCall(node.body.stats.head) &&
1549 node.body.stats.head.pos == node.body.pos) {
1550 node.body.stats = node.body.stats.tail;
1551 }
1552 node.sym = null;
1553 super.visitMethodDef(node);
1554 }
1555 public void visitVarDef(JCVariableDecl node) {
1556 node.sym = null;
1557 super.visitVarDef(node);
1558 }
1559 public void visitNewClass(JCNewClass node) {
1560 node.constructor = null;
1561 super.visitNewClass(node);
1562 }
1563 public void visitAssignop(JCAssignOp node) {
1564 node.operator = null;
1565 super.visitAssignop(node);
1566 }
1567 public void visitUnary(JCUnary node) {
1568 node.operator = null;
1569 super.visitUnary(node);
1570 }
1571 public void visitBinary(JCBinary node) {
1572 node.operator = null;
1573 super.visitBinary(node);
1574 }
1575 public void visitSelect(JCFieldAccess node) {
1576 node.sym = null;
1577 super.visitSelect(node);
1578 }
1579 public void visitIdent(JCIdent node) {
1580 node.sym = null;
1581 super.visitIdent(node);
1582 }
1583 public void visitAnnotation(JCAnnotation node) {
1584 node.attribute = null;
1585 super.visitAnnotation(node);
1586 }
1587 };
1588
1589
1590 private boolean moreToDo() {
1591 return filer.newFiles();
1592 }
1593
1594 /**
1595 * {@inheritDoc}
1596 *
1597 * Command line options suitable for presenting to annotation
1598 * processors.
1599 * {@literal "-Afoo=bar"} should be {@literal "-Afoo" => "bar"}.
1600 */
1601 @DefinedBy(Api.ANNOTATION_PROCESSING)
1602 public Map<String,String> getOptions() {
1603 return processorOptions;
1604 }
1605
1606 @DefinedBy(Api.ANNOTATION_PROCESSING)
1607 public Messager getMessager() {
1608 return messager;
1609 }
1610
1611 @DefinedBy(Api.ANNOTATION_PROCESSING)
1612 public JavacFiler getFiler() {
1613 return filer;
1614 }
1615
1616 @DefinedBy(Api.ANNOTATION_PROCESSING)
1617 public JavacElements getElementUtils() {
1618 return elementUtils;
1619 }
1620
1621 @DefinedBy(Api.ANNOTATION_PROCESSING)
1622 public JavacTypes getTypeUtils() {
1623 return typeUtils;
1624 }
1625
1626 @DefinedBy(Api.ANNOTATION_PROCESSING)
1627 public SourceVersion getSourceVersion() {
1628 return Source.toSourceVersion(source);
1629 }
1630
1631 @DefinedBy(Api.ANNOTATION_PROCESSING)
1632 public Locale getLocale() {
1633 return messages.getCurrentLocale();
1634 }
1635
1636 @DefinedBy(Api.ANNOTATION_PROCESSING)
1637 public boolean isPreviewEnabled() {
1638 return preview.isEnabled();
1639 }
1640
1641 public Set<Symbol.PackageSymbol> getSpecifiedPackages() {
1642 return specifiedPackages;
1643 }
1644
1645 public static final Pattern noMatches = Pattern.compile("(\\P{all})+");
1646
1647 /**
1648 * Convert import-style string for supported annotations into a
1649 * regex matching that string. If the string is not a valid
1650 * import-style string, return a regex that won't match anything.
1651 */
1652 private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log, Lint lint) {
1653 String module;
1654 String pkg;
1655 int slash = s.indexOf('/');
1656 if (slash == (-1)) {
1657 if (s.equals("*")) {
1658 return MatchingUtils.validImportStringToPattern(s);
1659 }
1660 module = allowModules ? ".*/" : "";
1661 pkg = s;
1662 } else {
1663 String moduleName = s.substring(0, slash);
1664 if (!SourceVersion.isName(moduleName)) {
1665 return warnAndNoMatches(s, p, log, lint);
1666 }
1667 module = Pattern.quote(moduleName + "/");
1668 // And warn if module is specified if modules aren't supported, conditional on -Xlint:proc?
1669 pkg = s.substring(slash + 1);
1670 }
1671 if (MatchingUtils.isValidImportString(pkg)) {
1672 return Pattern.compile(module + MatchingUtils.validImportStringToPatternString(pkg));
1673 } else {
1674 return warnAndNoMatches(s, p, log, lint);
1675 }
1676 }
1677
1678 private static Pattern warnAndNoMatches(String s, Processor p, Log log, Lint lint) {
1679 lint.logIfEnabled(LintWarnings.ProcMalformedSupportedString(s, p.getClass().getName()));
1680 return noMatches; // won't match any valid identifier
1681 }
1682
1683 /**
1684 * For internal use only. This method may be removed without warning.
1685 */
1686 public Context getContext() {
1687 return context;
1688 }
1689
1690 /**
1691 * For internal use only. This method may be removed without warning.
1692 */
1693 public ClassLoader getProcessorClassLoader() {
1694 return processorClassLoader;
1695 }
1696
1697 public String toString() {
1698 return "javac ProcessingEnvironment";
1699 }
1700
1701 public static boolean isValidOptionName(String optionName) {
1702 for(String s : optionName.split("\\.", -1)) {
1703 if (!SourceVersion.isIdentifier(s))
1704 return false;
1705 }
1706 return true;
1707 }
1708 }