1 /*
   2  * Copyright (c) 2005, 2013, 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.File;
  30 import java.io.PrintWriter;
  31 import java.io.StringWriter;
  32 import java.net.MalformedURLException;
  33 import java.net.URL;
  34 import java.util.*;
  35 import java.util.regex.*;
  36 
  37 import javax.annotation.processing.*;
  38 import javax.lang.model.SourceVersion;
  39 import javax.lang.model.element.AnnotationMirror;
  40 import javax.lang.model.element.Element;
  41 import javax.lang.model.element.PackageElement;
  42 import javax.lang.model.element.TypeElement;
  43 import javax.lang.model.util.*;
  44 import javax.tools.DiagnosticListener;
  45 import javax.tools.JavaFileManager;
  46 import javax.tools.JavaFileObject;
  47 import javax.tools.StandardJavaFileManager;
  48 import static javax.tools.StandardLocation.*;
  49 
  50 import com.sun.source.util.JavacTask;
  51 import com.sun.source.util.TaskEvent;
  52 import com.sun.tools.javac.api.BasicJavacTask;
  53 import com.sun.tools.javac.api.JavacTrees;
  54 import com.sun.tools.javac.api.MultiTaskListener;
  55 import com.sun.tools.javac.code.*;
  56 import com.sun.tools.javac.code.Symbol.*;
  57 import com.sun.tools.javac.file.FSInfo;
  58 import com.sun.tools.javac.file.JavacFileManager;
  59 import com.sun.tools.javac.jvm.*;
  60 import com.sun.tools.javac.jvm.ClassReader.BadClassFile;
  61 import com.sun.tools.javac.main.JavaCompiler;
  62 import com.sun.tools.javac.model.JavacElements;
  63 import com.sun.tools.javac.model.JavacTypes;
  64 import com.sun.tools.javac.parser.*;
  65 import com.sun.tools.javac.tree.*;
  66 import com.sun.tools.javac.tree.JCTree.*;
  67 import com.sun.tools.javac.util.Abort;
  68 import com.sun.tools.javac.util.Assert;
  69 import com.sun.tools.javac.util.ClientCodeException;
  70 import com.sun.tools.javac.util.Context;
  71 import com.sun.tools.javac.util.Convert;
  72 import com.sun.tools.javac.util.JCDiagnostic;
  73 import com.sun.tools.javac.util.JavacMessages;
  74 import com.sun.tools.javac.util.List;
  75 import com.sun.tools.javac.util.Log;
  76 import com.sun.tools.javac.util.Name;
  77 import com.sun.tools.javac.util.Names;
  78 import com.sun.tools.javac.util.Options;
  79 import com.sun.tools.javac.util.ServiceLoader;
  80 import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING;
  81 import static com.sun.tools.javac.main.Option.*;
  82 import static com.sun.tools.javac.comp.CompileStates.CompileState;
  83 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
  84 
  85 /**
  86  * Objects of this class hold and manage the state needed to support
  87  * annotation processing.
  88  *
  89  * <p><b>This is NOT part of any supported API.
  90  * If you write code that depends on this, you do so at your own risk.
  91  * This code and its internal interfaces are subject to change or
  92  * deletion without notice.</b>
  93  */
  94 public class JavacProcessingEnvironment implements ProcessingEnvironment, Closeable {
  95     Options options;
  96 
  97     private final boolean printProcessorInfo;
  98     private final boolean printRounds;
  99     private final boolean verbose;
 100     private final boolean lint;
 101     private final boolean fatalErrors;
 102     private final boolean werror;
 103     private final boolean showResolveErrors;
 104 
 105     private final JavacFiler filer;
 106     private final JavacMessager messager;
 107     private final JavacElements elementUtils;
 108     private final JavacTypes typeUtils;
 109 
 110     /**
 111      * Holds relevant state history of which processors have been
 112      * used.
 113      */
 114     private DiscoveredProcessors discoveredProcs;
 115 
 116     /**
 117      * Map of processor-specific options.
 118      */
 119     private final Map<String, String> processorOptions;
 120 
 121     /**
 122      */
 123     private final Set<String> unmatchedProcessorOptions;
 124 
 125     /**
 126      * Annotations implicitly processed and claimed by javac.
 127      */
 128     private final Set<String> platformAnnotations;
 129 
 130     /**
 131      * Set of packages given on command line.
 132      */
 133     private Set<PackageSymbol> specifiedPackages = Collections.emptySet();
 134 
 135     /** The log to be used for error reporting.
 136      */
 137     Log log;
 138 
 139     /** Diagnostic factory.
 140      */
 141     JCDiagnostic.Factory diags;
 142 
 143     /**
 144      * Source level of the compile.
 145      */
 146     Source source;
 147 
 148     private ClassLoader processorClassLoader;
 149     private SecurityException processorClassLoaderException;
 150 
 151     /**
 152      * JavacMessages object used for localization
 153      */
 154     private JavacMessages messages;
 155 
 156     private MultiTaskListener taskListener;
 157 
 158     private Context context;
 159 
 160     /** Get the JavacProcessingEnvironment instance for this context. */
 161     public static JavacProcessingEnvironment instance(Context context) {
 162         JavacProcessingEnvironment instance = context.get(JavacProcessingEnvironment.class);
 163         if (instance == null)
 164             instance = new JavacProcessingEnvironment(context);
 165         return instance;
 166     }
 167 
 168     protected JavacProcessingEnvironment(Context context) {
 169         this.context = context;
 170         context.put(JavacProcessingEnvironment.class, this);
 171         log = Log.instance(context);
 172         source = Source.instance(context);
 173         diags = JCDiagnostic.Factory.instance(context);
 174         options = Options.instance(context);
 175         printProcessorInfo = options.isSet(XPRINTPROCESSORINFO);
 176         printRounds = options.isSet(XPRINTROUNDS);
 177         verbose = options.isSet(VERBOSE);
 178         lint = Lint.instance(context).isEnabled(PROCESSING);
 179         if (options.isSet(PROC, "only") || options.isSet(XPRINT)) {
 180             JavaCompiler compiler = JavaCompiler.instance(context);
 181             compiler.shouldStopPolicyIfNoError = CompileState.PROCESS;
 182         }
 183         fatalErrors = options.isSet("fatalEnterError");
 184         showResolveErrors = options.isSet("showResolveErrors");
 185         werror = options.isSet(WERROR);
 186         platformAnnotations = initPlatformAnnotations();
 187 
 188         // Initialize services before any processors are initialized
 189         // in case processors use them.
 190         filer = new JavacFiler(context);
 191         messager = new JavacMessager(context, this);
 192         elementUtils = JavacElements.instance(context);
 193         typeUtils = JavacTypes.instance(context);
 194         processorOptions = initProcessorOptions(context);
 195         unmatchedProcessorOptions = initUnmatchedProcessorOptions();
 196         messages = JavacMessages.instance(context);
 197         taskListener = MultiTaskListener.instance(context);
 198         initProcessorClassLoader();
 199     }
 200 
 201     public void setProcessors(Iterable<? extends Processor> processors) {
 202         Assert.checkNull(discoveredProcs);
 203         initProcessorIterator(context, processors);
 204     }
 205 
 206     private Set<String> initPlatformAnnotations() {
 207         Set<String> platformAnnotations = new HashSet<String>();
 208         platformAnnotations.add("java.lang.Deprecated");
 209         platformAnnotations.add("java.lang.Override");
 210         platformAnnotations.add("java.lang.SuppressWarnings");
 211         platformAnnotations.add("java.lang.annotation.Documented");
 212         platformAnnotations.add("java.lang.annotation.Inherited");
 213         platformAnnotations.add("java.lang.annotation.Retention");
 214         platformAnnotations.add("java.lang.annotation.Target");
 215         return Collections.unmodifiableSet(platformAnnotations);
 216     }
 217 
 218     private void initProcessorClassLoader() {
 219         JavaFileManager fileManager = context.get(JavaFileManager.class);
 220         try {
 221             // If processorpath is not explicitly set, use the classpath.
 222             processorClassLoader = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH)
 223                 ? fileManager.getClassLoader(ANNOTATION_PROCESSOR_PATH)
 224                 : fileManager.getClassLoader(CLASS_PATH);
 225 
 226             if (processorClassLoader != null && processorClassLoader instanceof Closeable) {
 227                 JavaCompiler compiler = JavaCompiler.instance(context);
 228                 compiler.closeables = compiler.closeables.prepend((Closeable) processorClassLoader);
 229             }
 230         } catch (SecurityException e) {
 231             processorClassLoaderException = e;
 232         }
 233     }
 234 
 235     private void initProcessorIterator(Context context, Iterable<? extends Processor> processors) {
 236         Log   log   = Log.instance(context);
 237         Iterator<? extends Processor> processorIterator;
 238 
 239         if (options.isSet(XPRINT)) {
 240             try {
 241                 Processor processor = PrintingProcessor.class.newInstance();
 242                 processorIterator = List.of(processor).iterator();
 243             } catch (Throwable t) {
 244                 AssertionError assertError =
 245                     new AssertionError("Problem instantiating PrintingProcessor.");
 246                 assertError.initCause(t);
 247                 throw assertError;
 248             }
 249         } else if (processors != null) {
 250             processorIterator = processors.iterator();
 251         } else {
 252             String processorNames = options.get(PROCESSOR);
 253             if (processorClassLoaderException == null) {
 254                 /*
 255                  * If the "-processor" option is used, search the appropriate
 256                  * path for the named class.  Otherwise, use a service
 257                  * provider mechanism to create the processor iterator.
 258                  */
 259                 if (processorNames != null) {
 260                     processorIterator = new NameProcessIterator(processorNames, processorClassLoader, log);
 261                 } else {
 262                     processorIterator = new ServiceIterator(processorClassLoader, log);
 263                 }
 264             } else {
 265                 /*
 266                  * A security exception will occur if we can't create a classloader.
 267                  * Ignore the exception if, with hindsight, we didn't need it anyway
 268                  * (i.e. no processor was specified either explicitly, or implicitly,
 269                  * in service configuration file.) Otherwise, we cannot continue.
 270                  */
 271                 processorIterator = handleServiceLoaderUnavailability("proc.cant.create.loader",
 272                         processorClassLoaderException);
 273             }
 274         }
 275         discoveredProcs = new DiscoveredProcessors(processorIterator);
 276     }
 277 
 278     /**
 279      * Returns an empty processor iterator if no processors are on the
 280      * relevant path, otherwise if processors are present, logs an
 281      * error.  Called when a service loader is unavailable for some
 282      * reason, either because a service loader class cannot be found
 283      * or because a security policy prevents class loaders from being
 284      * created.
 285      *
 286      * @param key The resource key to use to log an error message
 287      * @param e   If non-null, pass this exception to Abort
 288      */
 289     private Iterator<Processor> handleServiceLoaderUnavailability(String key, Exception e) {
 290         JavaFileManager fileManager = context.get(JavaFileManager.class);
 291 
 292         if (fileManager instanceof JavacFileManager) {
 293             StandardJavaFileManager standardFileManager = (JavacFileManager) fileManager;
 294             Iterable<? extends File> workingPath = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH)
 295                 ? standardFileManager.getLocation(ANNOTATION_PROCESSOR_PATH)
 296                 : standardFileManager.getLocation(CLASS_PATH);
 297 
 298             if (needClassLoader(options.get(PROCESSOR), workingPath) )
 299                 handleException(key, e);
 300 
 301         } else {
 302             handleException(key, e);
 303         }
 304 
 305         java.util.List<Processor> pl = Collections.emptyList();
 306         return pl.iterator();
 307     }
 308 
 309     /**
 310      * Handle a security exception thrown during initializing the
 311      * Processor iterator.
 312      */
 313     private void handleException(String key, Exception e) {
 314         if (e != null) {
 315             log.error(key, e.getLocalizedMessage());
 316             throw new Abort(e);
 317         } else {
 318             log.error(key);
 319             throw new Abort();
 320         }
 321     }
 322 
 323     /**
 324      * Use a service loader appropriate for the platform to provide an
 325      * iterator over annotations processors; fails if a loader is
 326      * needed but unavailable.
 327      */
 328     private class ServiceIterator implements Iterator<Processor> {
 329         private Iterator<Processor> iterator;
 330         private Log log;
 331         private ServiceLoader<Processor> loader;
 332 
 333         ServiceIterator(ClassLoader classLoader, Log log) {
 334             this.log = log;
 335             try {
 336                 try {
 337                     loader = ServiceLoader.load(Processor.class, classLoader);
 338                     this.iterator = loader.iterator();
 339                 } catch (Exception e) {
 340                     // Fail softly if a loader is not actually needed.
 341                     this.iterator = handleServiceLoaderUnavailability("proc.no.service", null);
 342                 }
 343             } catch (Throwable t) {
 344                 log.error("proc.service.problem");
 345                 throw new Abort(t);
 346             }
 347         }
 348 
 349         public boolean hasNext() {
 350             try {
 351                 return iterator.hasNext();
 352             } catch(ServiceConfigurationError sce) {
 353                 log.error("proc.bad.config.file", sce.getLocalizedMessage());
 354                 throw new Abort(sce);
 355             } catch (Throwable t) {
 356                 throw new Abort(t);
 357             }
 358         }
 359 
 360         public Processor next() {
 361             try {
 362                 return iterator.next();
 363             } catch (ServiceConfigurationError sce) {
 364                 log.error("proc.bad.config.file", sce.getLocalizedMessage());
 365                 throw new Abort(sce);
 366             } catch (Throwable t) {
 367                 throw new Abort(t);
 368             }
 369         }
 370 
 371         public void remove() {
 372             throw new UnsupportedOperationException();
 373         }
 374 
 375         public void close() {
 376             if (loader != null) {
 377                 try {
 378                     loader.reload();
 379                 } catch(Exception e) {
 380                     ; // Ignore problems during a call to reload.
 381                 }
 382             }
 383         }
 384     }
 385 
 386 
 387     private static class NameProcessIterator implements Iterator<Processor> {
 388         Processor nextProc = null;
 389         Iterator<String> names;
 390         ClassLoader processorCL;
 391         Log log;
 392 
 393         NameProcessIterator(String names, ClassLoader processorCL, Log log) {
 394             this.names = Arrays.asList(names.split(",")).iterator();
 395             this.processorCL = processorCL;
 396             this.log = log;
 397         }
 398 
 399         public boolean hasNext() {
 400             if (nextProc != null)
 401                 return true;
 402             else {
 403                 if (!names.hasNext())
 404                     return false;
 405                 else {
 406                     String processorName = names.next();
 407 
 408                     Processor processor;
 409                     try {
 410                         try {
 411                             processor =
 412                                 (Processor) (processorCL.loadClass(processorName).newInstance());
 413                         } catch (ClassNotFoundException cnfe) {
 414                             log.error("proc.processor.not.found", processorName);
 415                             return false;
 416                         } catch (ClassCastException cce) {
 417                             log.error("proc.processor.wrong.type", processorName);
 418                             return false;
 419                         } catch (Exception e ) {
 420                             log.error("proc.processor.cant.instantiate", processorName);
 421                             return false;
 422                         }
 423                     } catch(ClientCodeException e) {
 424                         throw e;
 425                     } catch(Throwable t) {
 426                         throw new AnnotationProcessingError(t);
 427                     }
 428                     nextProc = processor;
 429                     return true;
 430                 }
 431 
 432             }
 433         }
 434 
 435         public Processor next() {
 436             if (hasNext()) {
 437                 Processor p = nextProc;
 438                 nextProc = null;
 439                 return p;
 440             } else
 441                 throw new NoSuchElementException();
 442         }
 443 
 444         public void remove () {
 445             throw new UnsupportedOperationException();
 446         }
 447     }
 448 
 449     public boolean atLeastOneProcessor() {
 450         return discoveredProcs.iterator().hasNext();
 451     }
 452 
 453     private Map<String, String> initProcessorOptions(Context context) {
 454         Options options = Options.instance(context);
 455         Set<String> keySet = options.keySet();
 456         Map<String, String> tempOptions = new LinkedHashMap<String, String>();
 457 
 458         for(String key : keySet) {
 459             if (key.startsWith("-A") && key.length() > 2) {
 460                 int sepIndex = key.indexOf('=');
 461                 String candidateKey = null;
 462                 String candidateValue = null;
 463 
 464                 if (sepIndex == -1)
 465                     candidateKey = key.substring(2);
 466                 else if (sepIndex >= 3) {
 467                     candidateKey = key.substring(2, sepIndex);
 468                     candidateValue = (sepIndex < key.length()-1)?
 469                         key.substring(sepIndex+1) : null;
 470                 }
 471                 tempOptions.put(candidateKey, candidateValue);
 472             }
 473         }
 474 
 475         return Collections.unmodifiableMap(tempOptions);
 476     }
 477 
 478     private Set<String> initUnmatchedProcessorOptions() {
 479         Set<String> unmatchedProcessorOptions = new HashSet<String>();
 480         unmatchedProcessorOptions.addAll(processorOptions.keySet());
 481         return unmatchedProcessorOptions;
 482     }
 483 
 484     /**
 485      * State about how a processor has been used by the tool.  If a
 486      * processor has been used on a prior round, its process method is
 487      * called on all subsequent rounds, perhaps with an empty set of
 488      * annotations to process.  The {@code annotationSupported} method
 489      * caches the supported annotation information from the first (and
 490      * only) getSupportedAnnotationTypes call to the processor.
 491      */
 492     static class ProcessorState {
 493         public Processor processor;
 494         public boolean   contributed;
 495         private ArrayList<Pattern> supportedAnnotationPatterns;
 496         private ArrayList<String>  supportedOptionNames;
 497 
 498         ProcessorState(Processor p, Log log, Source source, ProcessingEnvironment env) {
 499             processor = p;
 500             contributed = false;
 501 
 502             try {
 503                 processor.init(env);
 504 
 505                 checkSourceVersionCompatibility(source, log);
 506 
 507                 supportedAnnotationPatterns = new ArrayList<Pattern>();
 508                 for (String importString : processor.getSupportedAnnotationTypes()) {
 509                     supportedAnnotationPatterns.add(importStringToPattern(importString,
 510                                                                           processor,
 511                                                                           log));
 512                 }
 513 
 514                 supportedOptionNames = new ArrayList<String>();
 515                 for (String optionName : processor.getSupportedOptions() ) {
 516                     if (checkOptionName(optionName, log))
 517                         supportedOptionNames.add(optionName);
 518                 }
 519 
 520             } catch (ClientCodeException e) {
 521                 throw e;
 522             } catch (Throwable t) {
 523                 throw new AnnotationProcessingError(t);
 524             }
 525         }
 526 
 527         /**
 528          * Checks whether or not a processor's source version is
 529          * compatible with the compilation source version.  The
 530          * processor's source version needs to be greater than or
 531          * equal to the source version of the compile.
 532          */
 533         private void checkSourceVersionCompatibility(Source source, Log log) {
 534             SourceVersion procSourceVersion = processor.getSupportedSourceVersion();
 535 
 536             if (procSourceVersion.compareTo(Source.toSourceVersion(source)) < 0 )  {
 537                 log.warning("proc.processor.incompatible.source.version",
 538                             procSourceVersion,
 539                             processor.getClass().getName(),
 540                             source.name);
 541             }
 542         }
 543 
 544         private boolean checkOptionName(String optionName, Log log) {
 545             boolean valid = isValidOptionName(optionName);
 546             if (!valid)
 547                 log.error("proc.processor.bad.option.name",
 548                             optionName,
 549                             processor.getClass().getName());
 550             return valid;
 551         }
 552 
 553         public boolean annotationSupported(String annotationName) {
 554             for(Pattern p: supportedAnnotationPatterns) {
 555                 if (p.matcher(annotationName).matches())
 556                     return true;
 557             }
 558             return false;
 559         }
 560 
 561         /**
 562          * Remove options that are matched by this processor.
 563          */
 564         public void removeSupportedOptions(Set<String> unmatchedProcessorOptions) {
 565             unmatchedProcessorOptions.removeAll(supportedOptionNames);
 566         }
 567     }
 568 
 569     // TODO: These two classes can probably be rewritten better...
 570     /**
 571      * This class holds information about the processors that have
 572      * been discoverd so far as well as the means to discover more, if
 573      * necessary.  A single iterator should be used per round of
 574      * annotation processing.  The iterator first visits already
 575      * discovered processors then fails over to the service provider
 576      * mechanism if additional queries are made.
 577      */
 578     class DiscoveredProcessors implements Iterable<ProcessorState> {
 579 
 580         class ProcessorStateIterator implements Iterator<ProcessorState> {
 581             DiscoveredProcessors psi;
 582             Iterator<ProcessorState> innerIter;
 583             boolean onProcInterator;
 584 
 585             ProcessorStateIterator(DiscoveredProcessors psi) {
 586                 this.psi = psi;
 587                 this.innerIter = psi.procStateList.iterator();
 588                 this.onProcInterator = false;
 589             }
 590 
 591             public ProcessorState next() {
 592                 if (!onProcInterator) {
 593                     if (innerIter.hasNext())
 594                         return innerIter.next();
 595                     else
 596                         onProcInterator = true;
 597                 }
 598 
 599                 if (psi.processorIterator.hasNext()) {
 600                     ProcessorState ps = new ProcessorState(psi.processorIterator.next(),
 601                                                            log, source, JavacProcessingEnvironment.this);
 602                     psi.procStateList.add(ps);
 603                     return ps;
 604                 } else
 605                     throw new NoSuchElementException();
 606             }
 607 
 608             public boolean hasNext() {
 609                 if (onProcInterator)
 610                     return  psi.processorIterator.hasNext();
 611                 else
 612                     return innerIter.hasNext() || psi.processorIterator.hasNext();
 613             }
 614 
 615             public void remove () {
 616                 throw new UnsupportedOperationException();
 617             }
 618 
 619             /**
 620              * Run all remaining processors on the procStateList that
 621              * have not already run this round with an empty set of
 622              * annotations.
 623              */
 624             public void runContributingProcs(RoundEnvironment re) {
 625                 if (!onProcInterator) {
 626                     Set<TypeElement> emptyTypeElements = Collections.emptySet();
 627                     while(innerIter.hasNext()) {
 628                         ProcessorState ps = innerIter.next();
 629                         if (ps.contributed)
 630                             callProcessor(ps.processor, emptyTypeElements, re);
 631                     }
 632                 }
 633             }
 634         }
 635 
 636         Iterator<? extends Processor> processorIterator;
 637         ArrayList<ProcessorState>  procStateList;
 638 
 639         public ProcessorStateIterator iterator() {
 640             return new ProcessorStateIterator(this);
 641         }
 642 
 643         DiscoveredProcessors(Iterator<? extends Processor> processorIterator) {
 644             this.processorIterator = processorIterator;
 645             this.procStateList = new ArrayList<ProcessorState>();
 646         }
 647 
 648         /**
 649          * Free jar files, etc. if using a service loader.
 650          */
 651         public void close() {
 652             if (processorIterator != null &&
 653                 processorIterator instanceof ServiceIterator) {
 654                 ((ServiceIterator) processorIterator).close();
 655             }
 656         }
 657     }
 658 
 659     private void discoverAndRunProcs(Context context,
 660                                      Set<TypeElement> annotationsPresent,
 661                                      List<ClassSymbol> topLevelClasses,
 662                                      List<PackageSymbol> packageInfoFiles) {
 663         Map<String, TypeElement> unmatchedAnnotations =
 664             new HashMap<String, TypeElement>(annotationsPresent.size());
 665 
 666         for(TypeElement a  : annotationsPresent) {
 667                 unmatchedAnnotations.put(a.getQualifiedName().toString(),
 668                                          a);
 669         }
 670 
 671         // Give "*" processors a chance to match
 672         if (unmatchedAnnotations.size() == 0)
 673             unmatchedAnnotations.put("", null);
 674 
 675         DiscoveredProcessors.ProcessorStateIterator psi = discoveredProcs.iterator();
 676         // TODO: Create proper argument values; need past round
 677         // information to fill in this constructor.  Note that the 1
 678         // st round of processing could be the last round if there
 679         // were parse errors on the initial source files; however, we
 680         // are not doing processing in that case.
 681 
 682         Set<Element> rootElements = new LinkedHashSet<Element>();
 683         rootElements.addAll(topLevelClasses);
 684         rootElements.addAll(packageInfoFiles);
 685         rootElements = Collections.unmodifiableSet(rootElements);
 686 
 687         RoundEnvironment renv = new JavacRoundEnvironment(false,
 688                                                           false,
 689                                                           rootElements,
 690                                                           JavacProcessingEnvironment.this);
 691 
 692         while(unmatchedAnnotations.size() > 0 && psi.hasNext() ) {
 693             ProcessorState ps = psi.next();
 694             Set<String>  matchedNames = new HashSet<String>();
 695             Set<TypeElement> typeElements = new LinkedHashSet<TypeElement>();
 696 
 697             for (Map.Entry<String, TypeElement> entry: unmatchedAnnotations.entrySet()) {
 698                 String unmatchedAnnotationName = entry.getKey();
 699                 if (ps.annotationSupported(unmatchedAnnotationName) ) {
 700                     matchedNames.add(unmatchedAnnotationName);
 701                     TypeElement te = entry.getValue();
 702                     if (te != null)
 703                         typeElements.add(te);
 704                 }
 705             }
 706 
 707             if (matchedNames.size() > 0 || ps.contributed) {
 708                 boolean processingResult = callProcessor(ps.processor, typeElements, renv);
 709                 ps.contributed = true;
 710                 ps.removeSupportedOptions(unmatchedProcessorOptions);
 711 
 712                 if (printProcessorInfo || verbose) {
 713                     log.printLines("x.print.processor.info",
 714                             ps.processor.getClass().getName(),
 715                             matchedNames.toString(),
 716                             processingResult);
 717                 }
 718 
 719                 if (processingResult) {
 720                     unmatchedAnnotations.keySet().removeAll(matchedNames);
 721                 }
 722 
 723             }
 724         }
 725         unmatchedAnnotations.remove("");
 726 
 727         if (lint && unmatchedAnnotations.size() > 0) {
 728             // Remove annotations processed by javac
 729             unmatchedAnnotations.keySet().removeAll(platformAnnotations);
 730             if (unmatchedAnnotations.size() > 0) {
 731                 log = Log.instance(context);
 732                 log.warning("proc.annotations.without.processors",
 733                             unmatchedAnnotations.keySet());
 734             }
 735         }
 736 
 737         // Run contributing processors that haven't run yet
 738         psi.runContributingProcs(renv);
 739 
 740         // Debugging
 741         if (options.isSet("displayFilerState"))
 742             filer.displayState();
 743     }
 744 
 745     /**
 746      * Computes the set of annotations on the symbol in question.
 747      * Leave class public for external testing purposes.
 748      */
 749     public static class ComputeAnnotationSet extends
 750         ElementScanner8<Set<TypeElement>, Set<TypeElement>> {
 751         final Elements elements;
 752 
 753         public ComputeAnnotationSet(Elements elements) {
 754             super();
 755             this.elements = elements;
 756         }
 757 
 758         @Override
 759         public Set<TypeElement> visitPackage(PackageElement e, Set<TypeElement> p) {
 760             // Don't scan enclosed elements of a package
 761             return p;
 762         }
 763 
 764         @Override
 765         public Set<TypeElement> scan(Element e, Set<TypeElement> p) {
 766             for (AnnotationMirror annotationMirror :
 767                      elements.getAllAnnotationMirrors(e) ) {
 768                 Element e2 = annotationMirror.getAnnotationType().asElement();
 769                 p.add((TypeElement) e2);
 770             }
 771             return super.scan(e, p);
 772         }
 773     }
 774 
 775     private boolean callProcessor(Processor proc,
 776                                          Set<? extends TypeElement> tes,
 777                                          RoundEnvironment renv) {
 778         try {
 779             return proc.process(tes, renv);
 780         } catch (BadClassFile ex) {
 781             log.error("proc.cant.access.1", ex.sym, ex.getDetailValue());
 782             return false;
 783         } catch (CompletionFailure ex) {
 784             StringWriter out = new StringWriter();
 785             ex.printStackTrace(new PrintWriter(out));
 786             log.error("proc.cant.access", ex.sym, ex.getDetailValue(), out.toString());
 787             return false;
 788         } catch (ClientCodeException e) {
 789             throw e;
 790         } catch (Throwable t) {
 791             throw new AnnotationProcessingError(t);
 792         }
 793     }
 794 
 795     /**
 796      * Helper object for a single round of annotation processing.
 797      */
 798     class Round {
 799         /** The round number. */
 800         final int number;
 801         /** The context for the round. */
 802         final Context context;
 803         /** The compiler for the round. */
 804         final JavaCompiler compiler;
 805         /** The log for the round. */
 806         final Log log;
 807         /** The diagnostic handler for the round. */
 808         final Log.DeferredDiagnosticHandler deferredDiagnosticHandler;
 809 
 810         /** The ASTs to be compiled. */
 811         List<JCCompilationUnit> roots;
 812         /** The classes to be compiler that have were generated. */
 813         Map<String, JavaFileObject> genClassFiles;
 814 
 815         /** The set of annotations to be processed this round. */
 816         Set<TypeElement> annotationsPresent;
 817         /** The set of top level classes to be processed this round. */
 818         List<ClassSymbol> topLevelClasses;
 819         /** The set of package-info files to be processed this round. */
 820         List<PackageSymbol> packageInfoFiles;
 821 
 822         /** Create a round (common code). */
 823         private Round(Context context, int number, int priorErrors, int priorWarnings,
 824                 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
 825             this.context = context;
 826             this.number = number;
 827 
 828             compiler = JavaCompiler.instance(context);
 829             log = Log.instance(context);
 830             log.nerrors = priorErrors;
 831             log.nwarnings = priorWarnings;
 832             if (number == 1) {
 833                 Assert.checkNonNull(deferredDiagnosticHandler);
 834                 this.deferredDiagnosticHandler = deferredDiagnosticHandler;
 835             } else {
 836                 this.deferredDiagnosticHandler = new Log.DeferredDiagnosticHandler(log);
 837             }
 838 
 839             // the following is for the benefit of JavacProcessingEnvironment.getContext()
 840             JavacProcessingEnvironment.this.context = context;
 841 
 842             // the following will be populated as needed
 843             topLevelClasses  = List.nil();
 844             packageInfoFiles = List.nil();
 845         }
 846 
 847         /** Create the first round. */
 848         Round(Context context, List<JCCompilationUnit> roots, List<ClassSymbol> classSymbols,
 849                 Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
 850             this(context, 1, 0, 0, deferredDiagnosticHandler);
 851             this.roots = roots;
 852             genClassFiles = new HashMap<String,JavaFileObject>();
 853 
 854             compiler.todo.clear(); // free the compiler's resources
 855 
 856             // The reverse() in the following line is to maintain behavioural
 857             // compatibility with the previous revision of the code. Strictly speaking,
 858             // it should not be necessary, but a javah golden file test fails without it.
 859             topLevelClasses =
 860                 getTopLevelClasses(roots).prependList(classSymbols.reverse());
 861 
 862             packageInfoFiles = getPackageInfoFiles(roots);
 863 
 864             findAnnotationsPresent();
 865         }
 866 
 867         /** Create a new round. */
 868         private Round(Round prev,
 869                 Set<JavaFileObject> newSourceFiles, Map<String,JavaFileObject> newClassFiles) {
 870             this(prev.nextContext(),
 871                     prev.number+1,
 872                     prev.compiler.log.nerrors,
 873                     prev.compiler.log.nwarnings,
 874                     null);
 875             this.genClassFiles = prev.genClassFiles;
 876 
 877             List<JCCompilationUnit> parsedFiles = compiler.parseFiles(newSourceFiles);
 878             roots = cleanTrees(prev.roots).appendList(parsedFiles);
 879 
 880             // Check for errors after parsing
 881             if (unrecoverableError())
 882                 return;
 883 
 884             enterClassFiles(genClassFiles);
 885             List<ClassSymbol> newClasses = enterClassFiles(newClassFiles);
 886             genClassFiles.putAll(newClassFiles);
 887             enterTrees(roots);
 888 
 889             if (unrecoverableError())
 890                 return;
 891 
 892             topLevelClasses = join(
 893                     getTopLevelClasses(parsedFiles),
 894                     getTopLevelClassesFromClasses(newClasses));
 895 
 896             packageInfoFiles = join(
 897                     getPackageInfoFiles(parsedFiles),
 898                     getPackageInfoFilesFromClasses(newClasses));
 899 
 900             findAnnotationsPresent();
 901         }
 902 
 903         /** Create the next round to be used. */
 904         Round next(Set<JavaFileObject> newSourceFiles, Map<String, JavaFileObject> newClassFiles) {
 905             try {
 906                 return new Round(this, newSourceFiles, newClassFiles);
 907             } finally {
 908                 compiler.close(false);
 909             }
 910         }
 911 
 912         /** Create the compiler to be used for the final compilation. */
 913         JavaCompiler finalCompiler() {
 914             try {
 915                 Context nextCtx = nextContext();
 916                 JavacProcessingEnvironment.this.context = nextCtx;
 917                 JavaCompiler c = JavaCompiler.instance(nextCtx);
 918                 c.log.initRound(compiler.log);
 919                 return c;
 920             } finally {
 921                 compiler.close(false);
 922             }
 923         }
 924 
 925         /** Return the number of errors found so far in this round.
 926          * This may include uncoverable errors, such as parse errors,
 927          * and transient errors, such as missing symbols. */
 928         int errorCount() {
 929             return compiler.errorCount();
 930         }
 931 
 932         /** Return the number of warnings found so far in this round. */
 933         int warningCount() {
 934             return compiler.warningCount();
 935         }
 936 
 937         /** Return whether or not an unrecoverable error has occurred. */
 938         boolean unrecoverableError() {
 939             if (messager.errorRaised())
 940                 return true;
 941 
 942             for (JCDiagnostic d: deferredDiagnosticHandler.getDiagnostics()) {
 943                 switch (d.getKind()) {
 944                     case WARNING:
 945                         if (werror)
 946                             return true;
 947                         break;
 948 
 949                     case ERROR:
 950                         if (fatalErrors || !d.isFlagSet(RECOVERABLE))
 951                             return true;
 952                         break;
 953                 }
 954             }
 955 
 956             return false;
 957         }
 958 
 959         /** Find the set of annotations present in the set of top level
 960          *  classes and package info files to be processed this round. */
 961         void findAnnotationsPresent() {
 962             ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(elementUtils);
 963             // Use annotation processing to compute the set of annotations present
 964             annotationsPresent = new LinkedHashSet<TypeElement>();
 965             for (ClassSymbol classSym : topLevelClasses)
 966                 annotationComputer.scan(classSym, annotationsPresent);
 967             for (PackageSymbol pkgSym : packageInfoFiles)
 968                 annotationComputer.scan(pkgSym, annotationsPresent);
 969         }
 970 
 971         /** Enter a set of generated class files. */
 972         private List<ClassSymbol> enterClassFiles(Map<String, JavaFileObject> classFiles) {
 973             ClassReader reader = ClassReader.instance(context);
 974             Names names = Names.instance(context);
 975             List<ClassSymbol> list = List.nil();
 976 
 977             for (Map.Entry<String,JavaFileObject> entry : classFiles.entrySet()) {
 978                 Name name = names.fromString(entry.getKey());
 979                 JavaFileObject file = entry.getValue();
 980                 if (file.getKind() != JavaFileObject.Kind.CLASS)
 981                     throw new AssertionError(file);
 982                 ClassSymbol cs;
 983                 if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) {
 984                     Name packageName = Convert.packagePart(name);
 985                     PackageSymbol p = reader.enterPackage(packageName);
 986                     if (p.package_info == null)
 987                         p.package_info = reader.enterClass(Convert.shortName(name), p);
 988                     cs = p.package_info;
 989                     if (cs.classfile == null)
 990                         cs.classfile = file;
 991                 } else
 992                     cs = reader.enterClass(name, file);
 993                 list = list.prepend(cs);
 994             }
 995             return list.reverse();
 996         }
 997 
 998         /** Enter a set of syntax trees. */
 999         private void enterTrees(List<JCCompilationUnit> roots) {
1000             compiler.enterTrees(roots);
1001         }
1002 
1003         /** Run a processing round. */
1004         void run(boolean lastRound, boolean errorStatus) {
1005             printRoundInfo(lastRound);
1006 
1007             if (!taskListener.isEmpty())
1008                 taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
1009 
1010             try {
1011                 if (lastRound) {
1012                     filer.setLastRound(true);
1013                     Set<Element> emptyRootElements = Collections.emptySet(); // immutable
1014                     RoundEnvironment renv = new JavacRoundEnvironment(true,
1015                             errorStatus,
1016                             emptyRootElements,
1017                             JavacProcessingEnvironment.this);
1018                     discoveredProcs.iterator().runContributingProcs(renv);
1019                 } else {
1020                     discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles);
1021                 }
1022             } finally {
1023                 if (!taskListener.isEmpty())
1024                     taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
1025             }
1026         }
1027 
1028         void showDiagnostics(boolean showAll) {
1029             Set<JCDiagnostic.Kind> kinds = EnumSet.allOf(JCDiagnostic.Kind.class);
1030             if (!showAll) {
1031                 // suppress errors, which are all presumed to be transient resolve errors
1032                 kinds.remove(JCDiagnostic.Kind.ERROR);
1033             }
1034             deferredDiagnosticHandler.reportDeferredDiagnostics(kinds);
1035             log.popDiagnosticHandler(deferredDiagnosticHandler);
1036         }
1037 
1038         /** Print info about this round. */
1039         private void printRoundInfo(boolean lastRound) {
1040             if (printRounds || verbose) {
1041                 List<ClassSymbol> tlc = lastRound ? List.<ClassSymbol>nil() : topLevelClasses;
1042                 Set<TypeElement> ap = lastRound ? Collections.<TypeElement>emptySet() : annotationsPresent;
1043                 log.printLines("x.print.rounds",
1044                         number,
1045                         "{" + tlc.toString(", ") + "}",
1046                         ap,
1047                         lastRound);
1048             }
1049         }
1050 
1051         /** Get the context for the next round of processing.
1052          * Important values are propagated from round to round;
1053          * other values are implicitly reset.
1054          */
1055         private Context nextContext() {
1056             Context next = new Context(context);
1057 
1058             Options options = Options.instance(context);
1059             Assert.checkNonNull(options);
1060             next.put(Options.optionsKey, options);
1061 
1062             Locale locale = context.get(Locale.class);
1063             if (locale != null)
1064                 next.put(Locale.class, locale);
1065 
1066             Assert.checkNonNull(messages);
1067             next.put(JavacMessages.messagesKey, messages);
1068 
1069             final boolean shareNames = true;
1070             if (shareNames) {
1071                 Names names = Names.instance(context);
1072                 Assert.checkNonNull(names);
1073                 next.put(Names.namesKey, names);
1074             }
1075 
1076             DiagnosticListener<?> dl = context.get(DiagnosticListener.class);
1077             if (dl != null)
1078                 next.put(DiagnosticListener.class, dl);
1079 
1080             MultiTaskListener mtl = context.get(MultiTaskListener.taskListenerKey);
1081             if (mtl != null)
1082                 next.put(MultiTaskListener.taskListenerKey, mtl);
1083 
1084             FSInfo fsInfo = context.get(FSInfo.class);
1085             if (fsInfo != null)
1086                 next.put(FSInfo.class, fsInfo);
1087 
1088             JavaFileManager jfm = context.get(JavaFileManager.class);
1089             Assert.checkNonNull(jfm);
1090             next.put(JavaFileManager.class, jfm);
1091             if (jfm instanceof JavacFileManager) {
1092                 ((JavacFileManager)jfm).setContext(next);
1093             }
1094 
1095             Names names = Names.instance(context);
1096             Assert.checkNonNull(names);
1097             next.put(Names.namesKey, names);
1098 
1099             Tokens tokens = Tokens.instance(context);
1100             Assert.checkNonNull(tokens);
1101             next.put(Tokens.tokensKey, tokens);
1102 
1103             Log nextLog = Log.instance(next);
1104             nextLog.initRound(log);
1105 
1106             JavaCompiler oldCompiler = JavaCompiler.instance(context);
1107             JavaCompiler nextCompiler = JavaCompiler.instance(next);
1108             nextCompiler.initRound(oldCompiler);
1109 
1110             filer.newRound(next);
1111             messager.newRound(next);
1112             elementUtils.setContext(next);
1113             typeUtils.setContext(next);
1114 
1115             JavacTask task = context.get(JavacTask.class);
1116             if (task != null) {
1117                 next.put(JavacTask.class, task);
1118                 if (task instanceof BasicJavacTask)
1119                     ((BasicJavacTask) task).updateContext(next);
1120             }
1121 
1122             JavacTrees trees = context.get(JavacTrees.class);
1123             if (trees != null) {
1124                 next.put(JavacTrees.class, trees);
1125                 trees.updateContext(next);
1126             }
1127 
1128             context.clear();
1129             return next;
1130         }
1131     }
1132 
1133 
1134     // TODO: internal catch clauses?; catch and rethrow an annotation
1135     // processing error
1136     public JavaCompiler doProcessing(Context context,
1137                                      List<JCCompilationUnit> roots,
1138                                      List<ClassSymbol> classSymbols,
1139                                      Iterable<? extends PackageSymbol> pckSymbols,
1140                                      Log.DeferredDiagnosticHandler deferredDiagnosticHandler) {
1141         log = Log.instance(context);
1142 
1143         Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>();
1144         for (PackageSymbol psym : pckSymbols)
1145             specifiedPackages.add(psym);
1146         this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages);
1147 
1148         Round round = new Round(context, roots, classSymbols, deferredDiagnosticHandler);
1149 
1150         boolean errorStatus;
1151         boolean moreToDo;
1152         do {
1153             // Run processors for round n
1154             round.run(false, false);
1155 
1156             // Processors for round n have run to completion.
1157             // Check for errors and whether there is more work to do.
1158             errorStatus = round.unrecoverableError();
1159             moreToDo = moreToDo();
1160 
1161             round.showDiagnostics(errorStatus || showResolveErrors);
1162 
1163             // Set up next round.
1164             // Copy mutable collections returned from filer.
1165             round = round.next(
1166                     new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects()),
1167                     new LinkedHashMap<String,JavaFileObject>(filer.getGeneratedClasses()));
1168 
1169              // Check for errors during setup.
1170             if (round.unrecoverableError())
1171                 errorStatus = true;
1172 
1173         } while (moreToDo && !errorStatus);
1174 
1175         // run last round
1176         round.run(true, errorStatus);
1177         round.showDiagnostics(true);
1178 
1179         filer.warnIfUnclosedFiles();
1180         warnIfUnmatchedOptions();
1181 
1182         /*
1183          * If an annotation processor raises an error in a round,
1184          * that round runs to completion and one last round occurs.
1185          * The last round may also occur because no more source or
1186          * class files have been generated.  Therefore, if an error
1187          * was raised on either of the last *two* rounds, the compile
1188          * should exit with a nonzero exit code.  The current value of
1189          * errorStatus holds whether or not an error was raised on the
1190          * second to last round; errorRaised() gives the error status
1191          * of the last round.
1192          */
1193         if (messager.errorRaised()
1194                 || werror && round.warningCount() > 0 && round.errorCount() > 0)
1195             errorStatus = true;
1196 
1197         Set<JavaFileObject> newSourceFiles =
1198                 new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects());
1199         roots = cleanTrees(round.roots);
1200 
1201         JavaCompiler compiler = round.finalCompiler();
1202 
1203         if (newSourceFiles.size() > 0)
1204             roots = roots.appendList(compiler.parseFiles(newSourceFiles));
1205 
1206         errorStatus = errorStatus || (compiler.errorCount() > 0);
1207 
1208         // Free resources
1209         this.close();
1210 
1211         if (!taskListener.isEmpty())
1212             taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
1213 
1214         if (errorStatus) {
1215             if (compiler.errorCount() == 0)
1216                 compiler.log.nerrors++;
1217             return compiler;
1218         }
1219 
1220         compiler.enterTreesIfNeeded(roots);
1221 
1222         return compiler;
1223     }
1224 
1225     private void warnIfUnmatchedOptions() {
1226         if (!unmatchedProcessorOptions.isEmpty()) {
1227             log.warning("proc.unmatched.processor.options", unmatchedProcessorOptions.toString());
1228         }
1229     }
1230 
1231     /**
1232      * Free resources related to annotation processing.
1233      */
1234     public void close() {
1235         filer.close();
1236         if (discoveredProcs != null) // Make calling close idempotent
1237             discoveredProcs.close();
1238         discoveredProcs = null;
1239     }
1240 
1241     private List<ClassSymbol> getTopLevelClasses(List<? extends JCCompilationUnit> units) {
1242         List<ClassSymbol> classes = List.nil();
1243         for (JCCompilationUnit unit : units) {
1244             for (JCTree node : unit.defs) {
1245                 if (node.hasTag(JCTree.Tag.CLASSDEF)) {
1246                     ClassSymbol sym = ((JCClassDecl) node).sym;
1247                     Assert.checkNonNull(sym);
1248                     classes = classes.prepend(sym);
1249                 }
1250             }
1251         }
1252         return classes.reverse();
1253     }
1254 
1255     private List<ClassSymbol> getTopLevelClassesFromClasses(List<? extends ClassSymbol> syms) {
1256         List<ClassSymbol> classes = List.nil();
1257         for (ClassSymbol sym : syms) {
1258             if (!isPkgInfo(sym)) {
1259                 classes = classes.prepend(sym);
1260             }
1261         }
1262         return classes.reverse();
1263     }
1264 
1265     private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) {
1266         List<PackageSymbol> packages = List.nil();
1267         for (JCCompilationUnit unit : units) {
1268             if (isPkgInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE)) {
1269                 packages = packages.prepend(unit.packge);
1270             }
1271         }
1272         return packages.reverse();
1273     }
1274 
1275     private List<PackageSymbol> getPackageInfoFilesFromClasses(List<? extends ClassSymbol> syms) {
1276         List<PackageSymbol> packages = List.nil();
1277         for (ClassSymbol sym : syms) {
1278             if (isPkgInfo(sym)) {
1279                 packages = packages.prepend((PackageSymbol) sym.owner);
1280             }
1281         }
1282         return packages.reverse();
1283     }
1284 
1285     // avoid unchecked warning from use of varargs
1286     private static <T> List<T> join(List<T> list1, List<T> list2) {
1287         return list1.appendList(list2);
1288     }
1289 
1290     private boolean isPkgInfo(JavaFileObject fo, JavaFileObject.Kind kind) {
1291         return fo.isNameCompatible("package-info", kind);
1292     }
1293 
1294     private boolean isPkgInfo(ClassSymbol sym) {
1295         return isPkgInfo(sym.classfile, JavaFileObject.Kind.CLASS) && (sym.packge().package_info == sym);
1296     }
1297 
1298     /*
1299      * Called retroactively to determine if a class loader was required,
1300      * after we have failed to create one.
1301      */
1302     private boolean needClassLoader(String procNames, Iterable<? extends File> workingpath) {
1303         if (procNames != null)
1304             return true;
1305 
1306         URL[] urls = new URL[1];
1307         for(File pathElement : workingpath) {
1308             try {
1309                 urls[0] = pathElement.toURI().toURL();
1310                 if (ServiceProxy.hasService(Processor.class, urls))
1311                     return true;
1312             } catch (MalformedURLException ex) {
1313                 throw new AssertionError(ex);
1314             }
1315             catch (ServiceProxy.ServiceConfigurationError e) {
1316                 log.error("proc.bad.config.file", e.getLocalizedMessage());
1317                 return true;
1318             }
1319         }
1320 
1321         return false;
1322     }
1323 
1324     private static <T extends JCTree> List<T> cleanTrees(List<T> nodes) {
1325         for (T node : nodes)
1326             treeCleaner.scan(node);
1327         return nodes;
1328     }
1329 
1330     private static final TreeScanner treeCleaner = new TreeScanner() {
1331             public void scan(JCTree node) {
1332                 super.scan(node);
1333                 if (node != null)
1334                     node.type = null;
1335             }
1336             public void visitTopLevel(JCCompilationUnit node) {
1337                 node.packge = null;
1338                 super.visitTopLevel(node);
1339             }
1340             public void visitClassDef(JCClassDecl node) {
1341                 node.sym = null;
1342                 super.visitClassDef(node);
1343             }
1344             public void visitMethodDef(JCMethodDecl node) {
1345                 node.sym = null;
1346                 super.visitMethodDef(node);
1347             }
1348             public void visitVarDef(JCVariableDecl node) {
1349                 node.sym = null;
1350                 super.visitVarDef(node);
1351             }
1352             public void visitNewClass(JCNewClass node) {
1353                 node.constructor = null;
1354                 super.visitNewClass(node);
1355             }
1356             public void visitAssignop(JCAssignOp node) {
1357                 node.operator = null;
1358                 super.visitAssignop(node);
1359             }
1360             public void visitUnary(JCUnary node) {
1361                 node.operator = null;
1362                 super.visitUnary(node);
1363             }
1364             public void visitBinary(JCBinary node) {
1365                 node.operator = null;
1366                 super.visitBinary(node);
1367             }
1368             public void visitSelect(JCFieldAccess node) {
1369                 node.sym = null;
1370                 super.visitSelect(node);
1371             }
1372             public void visitIdent(JCIdent node) {
1373                 node.sym = null;
1374                 super.visitIdent(node);
1375             }
1376             public void visitAnnotation(JCAnnotation node) {
1377                 node.attribute = null;
1378                 super.visitAnnotation(node);
1379             }
1380         };
1381 
1382 
1383     private boolean moreToDo() {
1384         return filer.newFiles();
1385     }
1386 
1387     /**
1388      * {@inheritdoc}
1389      *
1390      * Command line options suitable for presenting to annotation
1391      * processors.
1392      * {@literal "-Afoo=bar"} should be {@literal "-Afoo" => "bar"}.
1393      */
1394     public Map<String,String> getOptions() {
1395         return processorOptions;
1396     }
1397 
1398     public Messager getMessager() {
1399         return messager;
1400     }
1401 
1402     public Filer getFiler() {
1403         return filer;
1404     }
1405 
1406     public JavacElements getElementUtils() {
1407         return elementUtils;
1408     }
1409 
1410     public JavacTypes getTypeUtils() {
1411         return typeUtils;
1412     }
1413 
1414     public SourceVersion getSourceVersion() {
1415         return Source.toSourceVersion(source);
1416     }
1417 
1418     public Locale getLocale() {
1419         return messages.getCurrentLocale();
1420     }
1421 
1422     public Set<Symbol.PackageSymbol> getSpecifiedPackages() {
1423         return specifiedPackages;
1424     }
1425 
1426     private static final Pattern allMatches = Pattern.compile(".*");
1427     public static final Pattern noMatches  = Pattern.compile("(\\P{all})+");
1428 
1429     /**
1430      * Convert import-style string for supported annotations into a
1431      * regex matching that string.  If the string is a valid
1432      * import-style string, return a regex that won't match anything.
1433      */
1434     private static Pattern importStringToPattern(String s, Processor p, Log log) {
1435         if (isValidImportString(s)) {
1436             return validImportStringToPattern(s);
1437         } else {
1438             log.warning("proc.malformed.supported.string", s, p.getClass().getName());
1439             return noMatches; // won't match any valid identifier
1440         }
1441     }
1442 
1443     /**
1444      * Return true if the argument string is a valid import-style
1445      * string specifying claimed annotations; return false otherwise.
1446      */
1447     public static boolean isValidImportString(String s) {
1448         if (s.equals("*"))
1449             return true;
1450 
1451         boolean valid = true;
1452         String t = s;
1453         int index = t.indexOf('*');
1454 
1455         if (index != -1) {
1456             // '*' must be last character...
1457             if (index == t.length() -1) {
1458                 // ... any and preceding character must be '.'
1459                 if ( index-1 >= 0 ) {
1460                     valid = t.charAt(index-1) == '.';
1461                     // Strip off ".*$" for identifier checks
1462                     t = t.substring(0, t.length()-2);
1463                 }
1464             } else
1465                 return false;
1466         }
1467 
1468         // Verify string is off the form (javaId \.)+ or javaId
1469         if (valid) {
1470             String[] javaIds = t.split("\\.", t.length()+2);
1471             for(String javaId: javaIds)
1472                 valid &= SourceVersion.isIdentifier(javaId);
1473         }
1474         return valid;
1475     }
1476 
1477     public static Pattern validImportStringToPattern(String s) {
1478         if (s.equals("*")) {
1479             return allMatches;
1480         } else {
1481             String s_prime = s.replace(".", "\\.");
1482 
1483             if (s_prime.endsWith("*")) {
1484                 s_prime =  s_prime.substring(0, s_prime.length() - 1) + ".+";
1485             }
1486 
1487             return Pattern.compile(s_prime);
1488         }
1489     }
1490 
1491     /**
1492      * For internal use only.  This method may be removed without warning.
1493      */
1494     public Context getContext() {
1495         return context;
1496     }
1497 
1498     /**
1499      * For internal use only.  This method may be removed without warning.
1500      */
1501     public ClassLoader getProcessorClassLoader() {
1502         return processorClassLoader;
1503     }
1504 
1505     public String toString() {
1506         return "javac ProcessingEnvironment";
1507     }
1508 
1509     public static boolean isValidOptionName(String optionName) {
1510         for(String s : optionName.split("\\.", -1)) {
1511             if (!SourceVersion.isIdentifier(s))
1512                 return false;
1513         }
1514         return true;
1515     }
1516 }