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