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