Source Code Cross Referenced for JavacProcessingEnvironment.java in  » 6.0-JDK-Modules-sun » javac-compiler » com » sun » tools » javac » processing » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules sun » javac compiler » com.sun.tools.javac.processing 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package com.sun.tools.javac.processing;
0027:
0028:        import com.sun.source.util.TaskEvent;
0029:        import com.sun.source.util.TaskListener;
0030:        import com.sun.tools.javac.api.JavacTaskImpl;
0031:        import com.sun.tools.javac.util.List;
0032:        import com.sun.tools.javac.util.*;
0033:        import com.sun.tools.javac.code.*;
0034:        import com.sun.tools.javac.code.Symbol.*;
0035:        import com.sun.tools.javac.comp.*;
0036:        import com.sun.tools.javac.jvm.*;
0037:        import com.sun.tools.javac.tree.*;
0038:        import com.sun.tools.javac.parser.*;
0039:        import com.sun.tools.javac.code.Symbol.*;
0040:        import com.sun.tools.javac.model.JavacElements;
0041:        import com.sun.tools.javac.model.JavacTypes;
0042:        import com.sun.tools.javac.tree.JCTree.*;
0043:        import com.sun.tools.javac.main.JavaCompiler;
0044:        import java.io.StringWriter;
0045:
0046:        import javax.annotation.processing.*;
0047:        import javax.lang.model.SourceVersion;
0048:        import javax.lang.model.element.AnnotationMirror;
0049:        import javax.lang.model.element.Element;
0050:        import javax.lang.model.element.TypeElement;
0051:        import javax.lang.model.element.PackageElement;
0052:        import javax.lang.model.util.*;
0053:
0054:        import javax.tools.JavaFileManager;
0055:        import javax.tools.StandardJavaFileManager;
0056:        import javax.tools.JavaFileObject;
0057:        import javax.tools.DiagnosticListener;
0058:        import static javax.tools.StandardLocation.*;
0059:
0060:        import java.lang.reflect.*;
0061:        import java.util.*;
0062:        import java.util.regex.*;
0063:
0064:        import java.net.URLClassLoader;
0065:        import java.net.URL;
0066:        import java.io.Closeable;
0067:        import java.io.File;
0068:        import java.io.PrintWriter;
0069:        import java.io.IOException;
0070:        import java.net.MalformedURLException;
0071:
0072:        /**
0073:         * Objects of this class hold and manage the state needed to support
0074:         * annotation processing.
0075:         *
0076:         * <p><b>This is NOT part of any API supported by Sun Microsystems.
0077:         * If you write code that depends on this, you do so at your own risk.
0078:         * This code and its internal interfaces are subject to change or
0079:         * deletion without notice.</b>
0080:         */
0081:        @Version("@(#)JavacProcessingEnvironment.java	1.36 07/07/13")
0082:        public class JavacProcessingEnvironment implements 
0083:                ProcessingEnvironment, Closeable {
0084:            Options options;
0085:
0086:            private final boolean printProcessorInfo;
0087:            private final boolean printRounds;
0088:            private final boolean verbose;
0089:            private final boolean lint;
0090:            private final boolean procOnly;
0091:            private final boolean fatalErrors;
0092:
0093:            private final JavacFiler filer;
0094:            private final JavacMessager messager;
0095:            private final JavacElements elementUtils;
0096:            private final JavacTypes typeUtils;
0097:
0098:            /**
0099:             * Holds relevant state history of which processors have been
0100:             * used.
0101:             */
0102:            private DiscoveredProcessors discoveredProcs;
0103:
0104:            /**
0105:             * Map of processor-specific options.
0106:             */
0107:            private final Map<String, String> processorOptions;
0108:
0109:            /**
0110:             */
0111:            private final Set<String> unmatchedProcessorOptions;
0112:
0113:            /**
0114:             * Annotations implicitly processed and claimed by javac.
0115:             */
0116:            private final Set<String> platformAnnotations;
0117:
0118:            /**
0119:             * Set of packages given on command line.
0120:             */
0121:            private Set<PackageSymbol> specifiedPackages = Collections
0122:                    .emptySet();
0123:
0124:            /** The log to be used for error reporting.
0125:             */
0126:            Log log;
0127:
0128:            /**
0129:             * Source level of the compile.
0130:             */
0131:            Source source;
0132:
0133:            private Context context;
0134:
0135:            public JavacProcessingEnvironment(Context context,
0136:                    Iterable<? extends Processor> processors) {
0137:                options = Options.instance(context);
0138:                this .context = context;
0139:                log = Log.instance(context);
0140:                source = Source.instance(context);
0141:                printProcessorInfo = options.get("-XprintProcessorInfo") != null;
0142:                printRounds = options.get("-XprintRounds") != null;
0143:                verbose = options.get("-verbose") != null;
0144:                lint = options.lint("processing");
0145:                procOnly = options.get("-proc:only") != null
0146:                        || options.get("-Xprint") != null;
0147:                fatalErrors = options.get("fatalEnterError") != null;
0148:                platformAnnotations = initPlatformAnnotations();
0149:
0150:                // Initialize services before any processors are initialzied
0151:                // in case processors use them.
0152:                filer = new JavacFiler(context);
0153:                messager = new JavacMessager(context, this );
0154:                elementUtils = new JavacElements(context);
0155:                typeUtils = new JavacTypes(context);
0156:                processorOptions = initProcessorOptions(context);
0157:                unmatchedProcessorOptions = initUnmatchedProcessorOptions();
0158:                initProcessorIterator(context, processors);
0159:            }
0160:
0161:            private Set<String> initPlatformAnnotations() {
0162:                Set<String> platformAnnotations = new HashSet<String>();
0163:                platformAnnotations.add("java.lang.Deprecated");
0164:                platformAnnotations.add("java.lang.Override");
0165:                platformAnnotations.add("java.lang.SuppressWarnings");
0166:                platformAnnotations.add("java.lang.annotation.Documented");
0167:                platformAnnotations.add("java.lang.annotation.Inherited");
0168:                platformAnnotations.add("java.lang.annotation.Retention");
0169:                platformAnnotations.add("java.lang.annotation.Target");
0170:                return Collections.unmodifiableSet(platformAnnotations);
0171:            }
0172:
0173:            private void initProcessorIterator(Context context,
0174:                    Iterable<? extends Processor> processors) {
0175:                Paths paths = Paths.instance(context);
0176:                Log log = Log.instance(context);
0177:                Iterator<? extends Processor> processorIterator;
0178:
0179:                if (options.get("-Xprint") != null) {
0180:                    try {
0181:                        Processor processor = PrintingProcessor.class
0182:                                .newInstance();
0183:                        processorIterator = List.of(processor).iterator();
0184:                    } catch (Throwable t) {
0185:                        AssertionError assertError = new AssertionError(
0186:                                "Problem instantiating PrintingProcessor.");
0187:                        assertError.initCause(t);
0188:                        throw assertError;
0189:                    }
0190:                } else if (processors != null) {
0191:                    processorIterator = processors.iterator();
0192:                } else {
0193:                    String processorNames = options.get("-processor");
0194:                    JavaFileManager fileManager = context
0195:                            .get(JavaFileManager.class);
0196:                    try {
0197:                        // If processorpath is not explicitly set, use the classpath.
0198:                        ClassLoader processorCL = fileManager
0199:                                .hasLocation(ANNOTATION_PROCESSOR_PATH) ? fileManager
0200:                                .getClassLoader(ANNOTATION_PROCESSOR_PATH)
0201:                                : fileManager.getClassLoader(CLASS_PATH);
0202:
0203:                        /*
0204:                         * If the "-processor" option is used, search the appropriate
0205:                         * path for the named class.  Otherwise, use a service
0206:                         * provider mechanism to create the processor iterator.
0207:                         */
0208:                        if (processorNames != null) {
0209:                            processorIterator = new NameProcessIterator(
0210:                                    processorNames, processorCL, log);
0211:                        } else {
0212:                            processorIterator = new ServiceIterator(
0213:                                    processorCL, log);
0214:                        }
0215:                    } catch (SecurityException e) {
0216:                        /*
0217:                         * A security exception will occur if we can't create a classloader.
0218:                         * Ignore the exception if, with hindsight, we didn't need it anyway
0219:                         * (i.e. no processor was specified either explicitly, or implicitly,
0220:                         * in service configuration file.) Otherwise, we cannot continue.
0221:                         */
0222:                        processorIterator = handleServiceLoaderUnavailability(
0223:                                "proc.cant.create.loader", e);
0224:                    }
0225:                }
0226:                discoveredProcs = new DiscoveredProcessors(processorIterator);
0227:            }
0228:
0229:            /**
0230:             * Returns an empty processor iterator if no processors are on the
0231:             * relevant path, otherwise if processors are present, logs an
0232:             * error.  Called when a service loader is unavailable for some
0233:             * reason, either because a service loader class cannot be found
0234:             * or because a security policy prevents class loaders from being
0235:             * created.
0236:             *
0237:             * @param key The resource key to use to log an error message
0238:             * @param e   If non-null, pass this exception to Abort
0239:             */
0240:            private Iterator<Processor> handleServiceLoaderUnavailability(
0241:                    String key, Exception e) {
0242:                JavaFileManager fileManager = context
0243:                        .get(JavaFileManager.class);
0244:
0245:                if (fileManager instanceof  JavacFileManager) {
0246:                    StandardJavaFileManager standardFileManager = (JavacFileManager) fileManager;
0247:                    Iterable<? extends File> workingPath = fileManager
0248:                            .hasLocation(ANNOTATION_PROCESSOR_PATH) ? standardFileManager
0249:                            .getLocation(ANNOTATION_PROCESSOR_PATH)
0250:                            : standardFileManager.getLocation(CLASS_PATH);
0251:
0252:                    if (needClassLoader(options.get("-processor"), workingPath))
0253:                        handleException(key, e);
0254:
0255:                } else {
0256:                    handleException(key, e);
0257:                }
0258:
0259:                java.util.List<Processor> pl = Collections.emptyList();
0260:                return pl.iterator();
0261:            }
0262:
0263:            /**
0264:             * Handle a security exception thrown during initializing the
0265:             * Processor iterator.
0266:             */
0267:            private void handleException(String key, Exception e) {
0268:                if (e != null) {
0269:                    log.error(key, e.getLocalizedMessage());
0270:                    throw new Abort(e);
0271:                } else {
0272:                    log.error(key);
0273:                    throw new Abort();
0274:                }
0275:            }
0276:
0277:            /**
0278:             * Use a service loader appropriate for the platform to provide an
0279:             * iterator over annotations processors.  If
0280:             * java.util.ServiceLoader is present use it, otherwise, use
0281:             * sun.misc.Service, otherwise fail if a loader is needed.
0282:             */
0283:            private class ServiceIterator implements  Iterator<Processor> {
0284:                // The to-be-wrapped iterator.
0285:                private Iterator<?> iterator;
0286:                private Log log;
0287:
0288:                ServiceIterator(ClassLoader classLoader, Log log) {
0289:                    Class<?> loaderClass;
0290:                    String loadMethodName;
0291:                    boolean jusl;
0292:
0293:                    this .log = log;
0294:                    try {
0295:                        try {
0296:                            loaderClass = Class
0297:                                    .forName("java.util.ServiceLoader");
0298:                            loadMethodName = "load";
0299:                            jusl = true;
0300:                        } catch (ClassNotFoundException cnfe) {
0301:                            try {
0302:                                loaderClass = Class.forName("sun.misc.Service");
0303:                                loadMethodName = "providers";
0304:                                jusl = false;
0305:                            } catch (ClassNotFoundException cnfe2) {
0306:                                // Fail softly if a loader is not actually needed.
0307:                                this .iterator = handleServiceLoaderUnavailability(
0308:                                        "proc.no.service", null);
0309:                                return;
0310:                            }
0311:                        }
0312:
0313:                        // java.util.ServiceLoader.load or sun.misc.Service.providers
0314:                        Method loadMethod = loaderClass.getMethod(
0315:                                loadMethodName, Class.class, ClassLoader.class);
0316:
0317:                        Object result = loadMethod.invoke(null,
0318:                                Processor.class, classLoader);
0319:
0320:                        // For java.util.ServiceLoader, we have to call another
0321:                        // method to get the iterator.
0322:                        if (jusl) {
0323:                            Method m = loaderClass.getMethod("iterator");
0324:                            result = m.invoke(result); // serviceLoader.iterator();
0325:                        }
0326:
0327:                        // The result should now be an iterator.
0328:                        this .iterator = (Iterator<?>) result;
0329:                    } catch (Throwable t) {
0330:                        log.error("proc.service.problem");
0331:                        throw new Abort(t);
0332:                    }
0333:                }
0334:
0335:                public boolean hasNext() {
0336:                    try {
0337:                        return iterator.hasNext();
0338:                    } catch (Throwable t) {
0339:                        if ("ServiceConfigurationError".equals(t.getClass()
0340:                                .getSimpleName())) {
0341:                            log.error("proc.bad.config.file", t
0342:                                    .getLocalizedMessage());
0343:                        }
0344:                        throw new Abort(t);
0345:                    }
0346:                }
0347:
0348:                public Processor next() {
0349:                    try {
0350:                        return (Processor) (iterator.next());
0351:                    } catch (Throwable t) {
0352:                        if ("ServiceConfigurationError".equals(t.getClass()
0353:                                .getSimpleName())) {
0354:                            log.error("proc.bad.config.file", t
0355:                                    .getLocalizedMessage());
0356:                        } else {
0357:                            log.error("proc.processor.constructor.error", t
0358:                                    .getLocalizedMessage());
0359:                        }
0360:                        throw new Abort(t);
0361:                    }
0362:                }
0363:
0364:                public void remove() {
0365:                    throw new UnsupportedOperationException();
0366:                }
0367:            }
0368:
0369:            private static class NameProcessIterator implements 
0370:                    Iterator<Processor> {
0371:                Processor nextProc = null;
0372:                Iterator<String> names;
0373:                ClassLoader processorCL;
0374:                Log log;
0375:
0376:                NameProcessIterator(String names, ClassLoader processorCL,
0377:                        Log log) {
0378:                    this .names = Arrays.asList(names.split(",")).iterator();
0379:                    this .processorCL = processorCL;
0380:                    this .log = log;
0381:                }
0382:
0383:                public boolean hasNext() {
0384:                    if (nextProc != null)
0385:                        return true;
0386:                    else {
0387:                        if (!names.hasNext())
0388:                            return false;
0389:                        else {
0390:                            String processorName = names.next();
0391:
0392:                            Processor processor;
0393:                            try {
0394:                                try {
0395:                                    processor = (Processor) (processorCL
0396:                                            .loadClass(processorName)
0397:                                            .newInstance());
0398:                                } catch (ClassNotFoundException cnfe) {
0399:                                    log.error("proc.processor.not.found",
0400:                                            processorName);
0401:                                    return false;
0402:                                } catch (ClassCastException cce) {
0403:                                    log.error("proc.processor.wrong.type",
0404:                                            processorName);
0405:                                    return false;
0406:                                } catch (Exception e) {
0407:                                    log.error(
0408:                                            "proc.processor.cant.instantiate",
0409:                                            processorName);
0410:                                    return false;
0411:                                }
0412:                            } catch (Throwable t) {
0413:                                throw new AnnotationProcessingError(t);
0414:                            }
0415:                            nextProc = processor;
0416:                            return true;
0417:                        }
0418:
0419:                    }
0420:                }
0421:
0422:                public Processor next() {
0423:                    if (hasNext()) {
0424:                        Processor p = nextProc;
0425:                        nextProc = null;
0426:                        return p;
0427:                    } else
0428:                        throw new NoSuchElementException();
0429:                }
0430:
0431:                public void remove() {
0432:                    throw new UnsupportedOperationException();
0433:                }
0434:            }
0435:
0436:            public boolean atLeastOneProcessor() {
0437:                return discoveredProcs.iterator().hasNext();
0438:            }
0439:
0440:            private Map<String, String> initProcessorOptions(Context context) {
0441:                Options options = Options.instance(context);
0442:                Set<String> keySet = options.keySet();
0443:                Map<String, String> tempOptions = new LinkedHashMap<String, String>();
0444:
0445:                for (String key : keySet) {
0446:                    if (key.startsWith("-A") && key.length() > 2) {
0447:                        int sepIndex = key.indexOf('=');
0448:                        String candidateKey = null;
0449:                        String candidateValue = null;
0450:
0451:                        if (sepIndex == -1)
0452:                            candidateKey = key.substring(2);
0453:                        else if (sepIndex >= 3) {
0454:                            candidateKey = key.substring(2, sepIndex);
0455:                            candidateValue = (sepIndex < key.length() - 1) ? key
0456:                                    .substring(sepIndex + 1)
0457:                                    : null;
0458:                        }
0459:                        tempOptions.put(candidateKey, candidateValue);
0460:                    }
0461:                }
0462:
0463:                return Collections.unmodifiableMap(tempOptions);
0464:            }
0465:
0466:            private Set<String> initUnmatchedProcessorOptions() {
0467:                Set<String> unmatchedProcessorOptions = new HashSet<String>();
0468:                unmatchedProcessorOptions.addAll(processorOptions.keySet());
0469:                return unmatchedProcessorOptions;
0470:            }
0471:
0472:            /**
0473:             * State about how a processor has been used by the tool.  If a
0474:             * processor has been used on a prior round, its process method is
0475:             * called on all subsequent rounds, perhaps with an empty set of
0476:             * annotations to process.  The {@code annotatedSupported} method
0477:             * caches the supported annotation information from the first (and
0478:             * only) getSupportedAnnotationTypes call to the processor.
0479:             */
0480:            static class ProcessorState {
0481:                public Processor processor;
0482:                public boolean contributed;
0483:                private ArrayList<Pattern> supportedAnnotationPatterns;
0484:                private ArrayList<String> supportedOptionNames;
0485:
0486:                ProcessorState(Processor p, Log log, Source source,
0487:                        ProcessingEnvironment env) {
0488:                    processor = p;
0489:                    contributed = false;
0490:
0491:                    try {
0492:                        processor.init(env);
0493:
0494:                        checkSourceVersionCompatibility(source, log);
0495:
0496:                        supportedAnnotationPatterns = new ArrayList<Pattern>();
0497:                        for (String importString : processor
0498:                                .getSupportedAnnotationTypes()) {
0499:                            supportedAnnotationPatterns
0500:                                    .add(importStringToPattern(importString,
0501:                                            processor, log));
0502:                        }
0503:
0504:                        supportedOptionNames = new ArrayList<String>();
0505:                        for (String optionName : processor
0506:                                .getSupportedOptions()) {
0507:                            if (checkOptionName(optionName, log))
0508:                                supportedOptionNames.add(optionName);
0509:                        }
0510:
0511:                    } catch (Throwable t) {
0512:                        throw new AnnotationProcessingError(t);
0513:                    }
0514:                }
0515:
0516:                /**
0517:                 * Checks whether or not a processor's source version is
0518:                 * compatible with the compilation source version.  The
0519:                 * processor's source version needs to be greater than or
0520:                 * equal to the source version of the compile.
0521:                 */
0522:                private void checkSourceVersionCompatibility(Source source,
0523:                        Log log) {
0524:                    SourceVersion procSourceVersion = processor
0525:                            .getSupportedSourceVersion();
0526:
0527:                    if (procSourceVersion.compareTo(Source
0528:                            .toSourceVersion(source)) < 0) {
0529:                        log.warning(
0530:                                "proc.processor.incompatible.source.version",
0531:                                procSourceVersion, processor.getClass()
0532:                                        .getName(), source.name);
0533:                    }
0534:                }
0535:
0536:                private boolean checkOptionName(String optionName, Log log) {
0537:                    boolean valid = isValidOptionName(optionName);
0538:                    if (!valid)
0539:                        log.error("proc.processor.bad.option.name", optionName,
0540:                                processor.getClass().getName());
0541:                    return valid;
0542:                }
0543:
0544:                public boolean annotationSupported(String annotationName) {
0545:                    for (Pattern p : supportedAnnotationPatterns) {
0546:                        if (p.matcher(annotationName).matches())
0547:                            return true;
0548:                    }
0549:                    return false;
0550:                }
0551:
0552:                /**
0553:                 * Remove options that are matched by this processor.
0554:                 */
0555:                public void removeSupportedOptions(
0556:                        Set<String> unmatchedProcessorOptions) {
0557:                    unmatchedProcessorOptions.removeAll(supportedOptionNames);
0558:                }
0559:            }
0560:
0561:            // TODO: These two classes can probably be rewritten better...
0562:            /**
0563:             * This class holds information about the processors that have
0564:             * been discoverd so far as well as the means to discover more, if
0565:             * necessary.  A single iterator should be used per round of
0566:             * annotation processing.  The iterator first visits already
0567:             * discovered processors then fails over to the service provided
0568:             * mechanism if additional queries are made.
0569:             */
0570:            class DiscoveredProcessors implements  Iterable<ProcessorState> {
0571:
0572:                class ProcessorStateIterator implements 
0573:                        Iterator<ProcessorState> {
0574:                    DiscoveredProcessors psi;
0575:                    Iterator<ProcessorState> innerIter;
0576:                    boolean onProcInterator;
0577:
0578:                    ProcessorStateIterator(DiscoveredProcessors psi) {
0579:                        this .psi = psi;
0580:                        this .innerIter = psi.procStateList.iterator();
0581:                        this .onProcInterator = false;
0582:                    }
0583:
0584:                    public ProcessorState next() {
0585:                        if (!onProcInterator) {
0586:                            if (innerIter.hasNext())
0587:                                return innerIter.next();
0588:                            else
0589:                                onProcInterator = true;
0590:                        }
0591:
0592:                        if (psi.processorIterator.hasNext()) {
0593:                            ProcessorState ps = new ProcessorState(
0594:                                    psi.processorIterator.next(), log, source,
0595:                                    JavacProcessingEnvironment.this );
0596:                            psi.procStateList.add(ps);
0597:                            return ps;
0598:                        } else
0599:                            throw new NoSuchElementException();
0600:                    }
0601:
0602:                    public boolean hasNext() {
0603:                        if (onProcInterator)
0604:                            return psi.processorIterator.hasNext();
0605:                        else
0606:                            return innerIter.hasNext()
0607:                                    || psi.processorIterator.hasNext();
0608:                    }
0609:
0610:                    public void remove() {
0611:                        throw new UnsupportedOperationException();
0612:                    }
0613:
0614:                    /**
0615:                     * Run all remaining processors on the procStateList that
0616:                     * have not already run this round with an empty set of
0617:                     * annotations.
0618:                     */
0619:                    public void runContributingProcs(RoundEnvironment re) {
0620:                        if (!onProcInterator) {
0621:                            Set<TypeElement> emptyTypeElements = Collections
0622:                                    .emptySet();
0623:                            while (innerIter.hasNext()) {
0624:                                ProcessorState ps = innerIter.next();
0625:                                if (ps.contributed)
0626:                                    callProcessor(ps.processor,
0627:                                            emptyTypeElements, re);
0628:                            }
0629:                        }
0630:                    }
0631:                }
0632:
0633:                Iterator<? extends Processor> processorIterator;
0634:                ArrayList<ProcessorState> procStateList;
0635:
0636:                public ProcessorStateIterator iterator() {
0637:                    return new ProcessorStateIterator(this );
0638:                }
0639:
0640:                DiscoveredProcessors(
0641:                        Iterator<? extends Processor> processorIterator) {
0642:                    this .processorIterator = processorIterator;
0643:                    this .procStateList = new ArrayList<ProcessorState>();
0644:                }
0645:            }
0646:
0647:            private void discoverAndRunProcs(Context context,
0648:                    Set<TypeElement> annotationsPresent,
0649:                    List<ClassSymbol> topLevelClasses,
0650:                    List<PackageSymbol> packageInfoFiles) {
0651:                // Writer for -XprintRounds and -XprintProcessorInfo data
0652:                PrintWriter xout = context.get(Log.outKey);
0653:
0654:                Map<String, TypeElement> unmatchedAnnotations = new HashMap<String, TypeElement>(
0655:                        annotationsPresent.size());
0656:
0657:                for (TypeElement a : annotationsPresent) {
0658:                    unmatchedAnnotations
0659:                            .put(a.getQualifiedName().toString(), a);
0660:                }
0661:
0662:                // Give "*" processors a chance to match
0663:                if (unmatchedAnnotations.size() == 0)
0664:                    unmatchedAnnotations.put("", null);
0665:
0666:                DiscoveredProcessors.ProcessorStateIterator psi = discoveredProcs
0667:                        .iterator();
0668:                // TODO: Create proper argument values; need past round
0669:                // information to fill in this constructor.  Note that the 1
0670:                // st round of processing could be the last round if there
0671:                // were parse errors on the initial source files; however, we
0672:                // are not doing processing in that case.
0673:
0674:                Set<Element> rootElements = new LinkedHashSet<Element>();
0675:                rootElements.addAll(topLevelClasses);
0676:                rootElements.addAll(packageInfoFiles);
0677:                rootElements = Collections.unmodifiableSet(rootElements);
0678:
0679:                RoundEnvironment renv = new JavacRoundEnvironment(false, false,
0680:                        rootElements, JavacProcessingEnvironment.this );
0681:
0682:                while (unmatchedAnnotations.size() > 0 && psi.hasNext()) {
0683:                    ProcessorState ps = psi.next();
0684:                    Set<String> matchedNames = new HashSet<String>();
0685:                    Set<TypeElement> typeElements = new LinkedHashSet<TypeElement>();
0686:                    for (String unmatchedAnnotationName : unmatchedAnnotations
0687:                            .keySet()) {
0688:                        if (ps.annotationSupported(unmatchedAnnotationName)) {
0689:                            matchedNames.add(unmatchedAnnotationName);
0690:                            TypeElement te = unmatchedAnnotations
0691:                                    .get(unmatchedAnnotationName);
0692:                            if (te != null)
0693:                                typeElements.add(te);
0694:                        }
0695:                    }
0696:
0697:                    if (matchedNames.size() > 0 || ps.contributed) {
0698:                        boolean processingResult = callProcessor(ps.processor,
0699:                                typeElements, renv);
0700:                        ps.contributed = true;
0701:                        ps.removeSupportedOptions(unmatchedProcessorOptions);
0702:
0703:                        if (printProcessorInfo || verbose) {
0704:                            xout.println(Log.getLocalizedString(
0705:                                    "x.print.processor.info", ps.processor
0706:                                            .getClass().getName(), matchedNames
0707:                                            .toString(), processingResult));
0708:                        }
0709:
0710:                        if (processingResult) {
0711:                            unmatchedAnnotations.keySet().removeAll(
0712:                                    matchedNames);
0713:                        }
0714:
0715:                    }
0716:                }
0717:                unmatchedAnnotations.remove("");
0718:
0719:                if (lint && unmatchedAnnotations.size() > 0) {
0720:                    // Remove annotations processed by javac
0721:                    unmatchedAnnotations.keySet()
0722:                            .removeAll(platformAnnotations);
0723:                    if (unmatchedAnnotations.size() > 0) {
0724:                        log = Log.instance(context);
0725:                        log.warning("proc.annotations.without.processors",
0726:                                unmatchedAnnotations.keySet());
0727:                    }
0728:                }
0729:
0730:                // Run contributing processors that haven't run yet
0731:                psi.runContributingProcs(renv);
0732:
0733:                // Debugging
0734:                if (options.get("displayFilerState") != null)
0735:                    filer.displayState();
0736:            }
0737:
0738:            /**
0739:             * Computes the set of annotations on the symbol in question.
0740:             * Leave class public for external testing purposes.
0741:             */
0742:            public static class ComputeAnnotationSet extends
0743:                    ElementScanner6<Set<TypeElement>, Set<TypeElement>> {
0744:                final Elements elements;
0745:
0746:                public ComputeAnnotationSet(Elements elements) {
0747:                    super ();
0748:                    this .elements = elements;
0749:                }
0750:
0751:                @Override
0752:                public Set<TypeElement> visitPackage(PackageElement e,
0753:                        Set<TypeElement> p) {
0754:                    // Don't scan enclosed elements of a package
0755:                    return p;
0756:                }
0757:
0758:                @Override
0759:                public Set<TypeElement> scan(Element e, Set<TypeElement> p) {
0760:                    for (AnnotationMirror annotationMirror : elements
0761:                            .getAllAnnotationMirrors(e)) {
0762:                        Element e2 = annotationMirror.getAnnotationType()
0763:                                .asElement();
0764:                        p.add((TypeElement) e2);
0765:                    }
0766:                    return super .scan(e, p);
0767:                }
0768:            }
0769:
0770:            private boolean callProcessor(Processor proc,
0771:                    Set<? extends TypeElement> tes, RoundEnvironment renv) {
0772:                try {
0773:                    return proc.process(tes, renv);
0774:                } catch (CompletionFailure ex) {
0775:                    StringWriter out = new StringWriter();
0776:                    ex.printStackTrace(new PrintWriter(out));
0777:                    log.error("proc.cant.access", ex.sym, ex.errmsg, out
0778:                            .toString());
0779:                    return false;
0780:                } catch (Throwable t) {
0781:                    throw new AnnotationProcessingError(t);
0782:                }
0783:            }
0784:
0785:            // TODO: internal catch clauses?; catch and rethrow an annotation
0786:            // processing error
0787:            public JavaCompiler doProcessing(Context context,
0788:                    List<JCCompilationUnit> roots,
0789:                    List<ClassSymbol> classSymbols,
0790:                    Iterable<? extends PackageSymbol> pckSymbols)
0791:                    throws IOException {
0792:
0793:                log = Log.instance(context);
0794:                // Writer for -XprintRounds and -XprintProcessorInfo data
0795:                PrintWriter xout = context.get(Log.outKey);
0796:                TaskListener taskListener = context.get(TaskListener.class);
0797:
0798:                AnnotationCollector collector = new AnnotationCollector();
0799:
0800:                JavaCompiler compiler = JavaCompiler.instance(context);
0801:                compiler.todo.clear(); // free the compiler's resources
0802:
0803:                int round = 0;
0804:
0805:                // List<JCAnnotation> annotationsPresentInSource = collector.findAnnotations(roots);
0806:                List<ClassSymbol> topLevelClasses = getTopLevelClasses(roots);
0807:
0808:                for (ClassSymbol classSym : classSymbols)
0809:                    topLevelClasses = topLevelClasses.prepend(classSym);
0810:                List<PackageSymbol> packageInfoFiles = getPackageInfoFiles(roots);
0811:
0812:                Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>();
0813:                for (PackageSymbol psym : pckSymbols)
0814:                    specifiedPackages.add(psym);
0815:                this .specifiedPackages = Collections
0816:                        .unmodifiableSet(specifiedPackages);
0817:
0818:                // Use annotation processing to compute the set of annotations present
0819:                Set<TypeElement> annotationsPresent = new LinkedHashSet<TypeElement>();
0820:                ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(
0821:                        elementUtils);
0822:                for (ClassSymbol classSym : topLevelClasses)
0823:                    annotationComputer.scan(classSym, annotationsPresent);
0824:                for (PackageSymbol pkgSym : packageInfoFiles)
0825:                    annotationComputer.scan(pkgSym, annotationsPresent);
0826:
0827:                Context currentContext = context;
0828:
0829:                int roundNumber = 0;
0830:                boolean errorStatus = false;
0831:
0832:                runAround: while (true) {
0833:                    if (fatalErrors && compiler.errorCount() != 0) {
0834:                        errorStatus = true;
0835:                        break runAround;
0836:                    }
0837:
0838:                    this .context = currentContext;
0839:                    roundNumber++;
0840:                    printRoundInfo(xout, roundNumber, topLevelClasses,
0841:                            annotationsPresent, false);
0842:
0843:                    if (taskListener != null)
0844:                        taskListener.started(new TaskEvent(
0845:                                TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
0846:
0847:                    try {
0848:                        discoverAndRunProcs(currentContext, annotationsPresent,
0849:                                topLevelClasses, packageInfoFiles);
0850:                    } finally {
0851:                        if (taskListener != null)
0852:                            taskListener
0853:                                    .finished(new TaskEvent(
0854:                                            TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
0855:                    }
0856:
0857:                    /*
0858:                     * Processors for round n have run to completion.  Prepare
0859:                     * for round (n+1) by checked for errors raised by
0860:                     * annotation processors and then checking for syntax
0861:                     * errors on any generated source files.
0862:                     */
0863:                    if (messager.errorRaised()) {
0864:                        errorStatus = true;
0865:                        break runAround;
0866:                    } else {
0867:                        if (moreToDo()) {
0868:                            // annotationsPresentInSource = List.nil();
0869:                            annotationsPresent = new LinkedHashSet<TypeElement>();
0870:                            topLevelClasses = List.nil();
0871:                            packageInfoFiles = List.nil();
0872:
0873:                            compiler.close();
0874:                            currentContext = contextForNextRound(
0875:                                    currentContext, true);
0876:
0877:                            JavaFileManager fileManager = currentContext
0878:                                    .get(JavaFileManager.class);
0879:
0880:                            List<JavaFileObject> fileObjects = List.nil();
0881:                            for (JavaFileObject jfo : filer
0882:                                    .getGeneratedSourceFileObjects()) {
0883:                                fileObjects = fileObjects.prepend(jfo);
0884:                            }
0885:
0886:                            compiler = JavaCompiler.instance(currentContext);
0887:                            List<JCCompilationUnit> parsedFiles = compiler
0888:                                    .parseFiles(fileObjects);
0889:                            roots = cleanTrees(roots).reverse();
0890:
0891:                            for (JCCompilationUnit unit : parsedFiles)
0892:                                roots = roots.prepend(unit);
0893:                            roots = roots.reverse();
0894:
0895:                            // Check for errors after parsing
0896:                            if (compiler.parseErrors()) {
0897:                                errorStatus = true;
0898:                                break runAround;
0899:                            } else {
0900:                                ListBuffer<ClassSymbol> classes = enterNewClassFiles(currentContext);
0901:                                compiler.enterTrees(roots);
0902:
0903:                                // annotationsPresentInSource =
0904:                                // collector.findAnnotations(parsedFiles);
0905:                                classes
0906:                                        .appendList(getTopLevelClasses(parsedFiles));
0907:                                topLevelClasses = classes.toList();
0908:                                packageInfoFiles = getPackageInfoFiles(parsedFiles);
0909:
0910:                                annotationsPresent = new LinkedHashSet<TypeElement>();
0911:                                for (ClassSymbol classSym : topLevelClasses)
0912:                                    annotationComputer.scan(classSym,
0913:                                            annotationsPresent);
0914:                                for (PackageSymbol pkgSym : packageInfoFiles)
0915:                                    annotationComputer.scan(pkgSym,
0916:                                            annotationsPresent);
0917:
0918:                                updateProcessingState(currentContext, false);
0919:                            }
0920:                        } else
0921:                            break runAround; // No new files
0922:                    }
0923:                }
0924:                runLastRound(xout, roundNumber, errorStatus, taskListener);
0925:
0926:                compiler.close();
0927:                currentContext = contextForNextRound(currentContext, true);
0928:                compiler = JavaCompiler.instance(currentContext);
0929:                filer.newRound(currentContext, true);
0930:                filer.warnIfUnclosedFiles();
0931:                warnIfUnmatchedOptions();
0932:
0933:                /*
0934:                 * If an annotation processor raises an error in a round,
0935:                 * that round runs to completion and one last round occurs.
0936:                 * The last round may also occur because no more source or
0937:                 * class files have been generated.  Therefore, if an error
0938:                 * was raised on either of the last *two* rounds, the compile
0939:                 * should exit with a nonzero exit code.  The current value of
0940:                 * errorStatus holds whether or not an error was raised on the
0941:                 * second to last round; errorRaised() gives the error status
0942:                 * of the last round.
0943:                 */
0944:                errorStatus = errorStatus || messager.errorRaised();
0945:
0946:                // Free resources
0947:                this .close();
0948:
0949:                if (taskListener != null)
0950:                    taskListener.finished(new TaskEvent(
0951:                            TaskEvent.Kind.ANNOTATION_PROCESSING));
0952:
0953:                if (errorStatus) {
0954:                    compiler.log.nerrors += messager.errorCount();
0955:                    if (compiler.errorCount() == 0)
0956:                        compiler.log.nerrors++;
0957:                } else if (procOnly) {
0958:                    compiler.todo.clear();
0959:                } else { // Final compilation
0960:                    compiler.close();
0961:                    currentContext = contextForNextRound(currentContext, true);
0962:                    compiler = JavaCompiler.instance(currentContext);
0963:
0964:                    if (true) {
0965:                        compiler.enterTrees(cleanTrees(roots));
0966:                    } else {
0967:                        List<JavaFileObject> fileObjects = List.nil();
0968:                        for (JCCompilationUnit unit : roots)
0969:                            fileObjects = fileObjects.prepend(unit
0970:                                    .getSourceFile());
0971:                        roots = null;
0972:                        compiler.enterTrees(compiler.parseFiles(fileObjects
0973:                                .reverse()));
0974:                    }
0975:                }
0976:
0977:                return compiler;
0978:            }
0979:
0980:            // Call the last round of annotation processing
0981:            private void runLastRound(PrintWriter xout, int roundNumber,
0982:                    boolean errorStatus, TaskListener taskListener)
0983:                    throws IOException {
0984:                roundNumber++;
0985:                List<ClassSymbol> noTopLevelClasses = List.nil();
0986:                Set<TypeElement> noAnnotations = Collections.emptySet();
0987:                printRoundInfo(xout, roundNumber, noTopLevelClasses,
0988:                        noAnnotations, true);
0989:
0990:                Set<Element> emptyRootElements = Collections.emptySet(); // immutable
0991:                RoundEnvironment renv = new JavacRoundEnvironment(true,
0992:                        errorStatus, emptyRootElements,
0993:                        JavacProcessingEnvironment.this );
0994:                if (taskListener != null)
0995:                    taskListener.started(new TaskEvent(
0996:                            TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
0997:
0998:                try {
0999:                    discoveredProcs.iterator().runContributingProcs(renv);
1000:                } finally {
1001:                    if (taskListener != null)
1002:                        taskListener.finished(new TaskEvent(
1003:                                TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
1004:                }
1005:            }
1006:
1007:            private void updateProcessingState(Context currentContext,
1008:                    boolean lastRound) {
1009:                filer.newRound(currentContext, lastRound);
1010:                messager.newRound(currentContext);
1011:
1012:                elementUtils.setContext(currentContext);
1013:                typeUtils.setContext(currentContext);
1014:            }
1015:
1016:            private void warnIfUnmatchedOptions() {
1017:                if (!unmatchedProcessorOptions.isEmpty()) {
1018:                    log.warning("proc.unmatched.processor.options",
1019:                            unmatchedProcessorOptions.toString());
1020:                }
1021:            }
1022:
1023:            private void printRoundInfo(PrintWriter xout, int roundNumber,
1024:                    List<ClassSymbol> topLevelClasses,
1025:                    Set<TypeElement> annotationsPresent, boolean lastRound) {
1026:                if (printRounds || verbose) {
1027:                    xout.println(Log.getLocalizedString("x.print.rounds",
1028:                            roundNumber, "{" + topLevelClasses.toString(", ")
1029:                                    + "}", annotationsPresent, lastRound));
1030:                }
1031:            }
1032:
1033:            private ListBuffer<ClassSymbol> enterNewClassFiles(
1034:                    Context currentContext) {
1035:                ClassReader reader = ClassReader.instance(currentContext);
1036:                Name.Table names = Name.Table.instance(currentContext);
1037:                ListBuffer<ClassSymbol> list = new ListBuffer<ClassSymbol>();
1038:
1039:                for (Map.Entry<String, JavaFileObject> entry : filer
1040:                        .getGeneratedClasses().entrySet()) {
1041:                    Name name = names.fromString(entry.getKey());
1042:                    JavaFileObject file = entry.getValue();
1043:                    if (file.getKind() != JavaFileObject.Kind.CLASS)
1044:                        throw new AssertionError(file);
1045:                    ClassSymbol cs = reader.enterClass(name, file);
1046:                    list.append(cs);
1047:                }
1048:                return list;
1049:            }
1050:
1051:            /**
1052:             * Free resources related to annotation processing.
1053:             */
1054:            public void close() {
1055:                filer.close();
1056:                discoveredProcs = null;
1057:            }
1058:
1059:            private List<ClassSymbol> getTopLevelClasses(
1060:                    List<? extends JCCompilationUnit> units) {
1061:                List<ClassSymbol> classes = List.nil();
1062:                for (JCCompilationUnit unit : units) {
1063:                    for (JCTree node : unit.defs) {
1064:                        if (node.getTag() == JCTree.CLASSDEF) {
1065:                            classes = classes.prepend(((JCClassDecl) node).sym);
1066:                        }
1067:                    }
1068:                }
1069:                return classes.reverse();
1070:            }
1071:
1072:            private List<PackageSymbol> getPackageInfoFiles(
1073:                    List<? extends JCCompilationUnit> units) {
1074:                List<PackageSymbol> packages = List.nil();
1075:                for (JCCompilationUnit unit : units) {
1076:                    boolean isPkgInfo = unit.sourcefile.isNameCompatible(
1077:                            "package-info", JavaFileObject.Kind.SOURCE);
1078:                    if (isPkgInfo) {
1079:                        packages = packages.prepend(unit.packge);
1080:                    }
1081:                }
1082:                return packages.reverse();
1083:            }
1084:
1085:            private Context contextForNextRound(Context context,
1086:                    boolean shareNames) throws IOException {
1087:                Context next = new Context();
1088:
1089:                Options options = Options.instance(context);
1090:                assert options != null;
1091:                next.put(Options.optionsKey, options);
1092:
1093:                PrintWriter out = context.get(Log.outKey);
1094:                assert out != null;
1095:                next.put(Log.outKey, out);
1096:
1097:                if (shareNames) {
1098:                    Name.Table names = Name.Table.instance(context);
1099:                    assert names != null;
1100:                    next.put(Name.Table.namesKey, names);
1101:                }
1102:
1103:                DiagnosticListener dl = context.get(DiagnosticListener.class);
1104:                if (dl != null)
1105:                    next.put(DiagnosticListener.class, dl);
1106:
1107:                TaskListener tl = context.get(TaskListener.class);
1108:                if (tl != null)
1109:                    next.put(TaskListener.class, tl);
1110:
1111:                JavaFileManager jfm = context.get(JavaFileManager.class);
1112:                assert jfm != null;
1113:                next.put(JavaFileManager.class, jfm);
1114:                if (jfm instanceof  JavacFileManager) {
1115:                    ((JavacFileManager) jfm).setContext(next);
1116:                }
1117:
1118:                Name.Table names = Name.Table.instance(context);
1119:                assert names != null;
1120:                next.put(Name.Table.namesKey, names);
1121:
1122:                Keywords keywords = Keywords.instance(context);
1123:                assert (keywords != null);
1124:                next.put(Keywords.keywordsKey, keywords);
1125:
1126:                JavaCompiler oldCompiler = JavaCompiler.instance(context);
1127:                JavaCompiler nextCompiler = JavaCompiler.instance(next);
1128:                nextCompiler.initRound(oldCompiler);
1129:
1130:                JavacTaskImpl task = context.get(JavacTaskImpl.class);
1131:                if (task != null) {
1132:                    next.put(JavacTaskImpl.class, task);
1133:                    task.updateContext(next);
1134:                }
1135:
1136:                context.clear();
1137:                return next;
1138:            }
1139:
1140:            /*
1141:             * Called retroactively to determine if a class loader was required,
1142:             * after we have failed to create one.
1143:             */
1144:            private boolean needClassLoader(String procNames,
1145:                    Iterable<? extends File> workingpath) {
1146:                if (procNames != null)
1147:                    return true;
1148:
1149:                String procPath;
1150:                URL[] urls = new URL[1];
1151:                for (File pathElement : workingpath) {
1152:                    try {
1153:                        urls[0] = pathElement.toURI().toURL();
1154:                        if (ServiceProxy.hasService(Processor.class, urls))
1155:                            return true;
1156:                    } catch (MalformedURLException ex) {
1157:                        throw new AssertionError(ex);
1158:                    } catch (ServiceProxy.ServiceConfigurationError e) {
1159:                        log.error("proc.bad.config.file", e
1160:                                .getLocalizedMessage());
1161:                        return true;
1162:                    }
1163:                }
1164:
1165:                return false;
1166:            }
1167:
1168:            private class AnnotationCollector extends TreeScanner {
1169:                List<JCTree> path = List.nil();
1170:                static final boolean verbose = false;
1171:                List<JCAnnotation> annotations = List.nil();
1172:
1173:                public List<JCAnnotation> findAnnotations(
1174:                        List<? extends JCTree> nodes) {
1175:                    annotations = List.nil();
1176:                    scan(nodes);
1177:                    List<JCAnnotation> found = annotations;
1178:                    annotations = List.nil();
1179:                    return found.reverse();
1180:                }
1181:
1182:                public void scan(JCTree node) {
1183:                    if (node == null)
1184:                        return;
1185:                    Symbol sym = TreeInfo.symbolFor(node);
1186:                    if (sym != null)
1187:                        path = path.prepend(node);
1188:                    super .scan(node);
1189:                    if (sym != null)
1190:                        path = path.tail;
1191:                }
1192:
1193:                public void visitAnnotation(JCAnnotation node) {
1194:                    annotations = annotations.prepend(node);
1195:                    if (verbose) {
1196:                        StringBuilder sb = new StringBuilder();
1197:                        for (JCTree tree : path.reverse()) {
1198:                            System.err.print(sb);
1199:                            System.err.println(TreeInfo.symbolFor(tree));
1200:                            sb.append("  ");
1201:                        }
1202:                        System.err.print(sb);
1203:                        System.err.println(node);
1204:                    }
1205:                }
1206:            }
1207:
1208:            private static <T extends JCTree> List<T> cleanTrees(List<T> nodes) {
1209:                for (T node : nodes)
1210:                    treeCleaner.scan(node);
1211:                return nodes;
1212:            }
1213:
1214:            private static TreeScanner treeCleaner = new TreeScanner() {
1215:                public void scan(JCTree node) {
1216:                    super .scan(node);
1217:                    if (node != null)
1218:                        node.type = null;
1219:                }
1220:
1221:                public void visitTopLevel(JCCompilationUnit node) {
1222:                    node.packge = null;
1223:                    super .visitTopLevel(node);
1224:                }
1225:
1226:                public void visitClassDef(JCClassDecl node) {
1227:                    node.sym = null;
1228:                    super .visitClassDef(node);
1229:                }
1230:
1231:                public void visitMethodDef(JCMethodDecl node) {
1232:                    node.sym = null;
1233:                    super .visitMethodDef(node);
1234:                }
1235:
1236:                public void visitVarDef(JCVariableDecl node) {
1237:                    node.sym = null;
1238:                    super .visitVarDef(node);
1239:                }
1240:
1241:                public void visitNewClass(JCNewClass node) {
1242:                    node.constructor = null;
1243:                    super .visitNewClass(node);
1244:                }
1245:
1246:                public void visitAssignop(JCAssignOp node) {
1247:                    node.operator = null;
1248:                    super .visitAssignop(node);
1249:                }
1250:
1251:                public void visitUnary(JCUnary node) {
1252:                    node.operator = null;
1253:                    super .visitUnary(node);
1254:                }
1255:
1256:                public void visitBinary(JCBinary node) {
1257:                    node.operator = null;
1258:                    super .visitBinary(node);
1259:                }
1260:
1261:                public void visitSelect(JCFieldAccess node) {
1262:                    node.sym = null;
1263:                    super .visitSelect(node);
1264:                }
1265:
1266:                public void visitIdent(JCIdent node) {
1267:                    node.sym = null;
1268:                    super .visitIdent(node);
1269:                }
1270:            };
1271:
1272:            private boolean moreToDo() {
1273:                return filer.newFiles();
1274:            }
1275:
1276:            /**
1277:             * {@inheritdoc}
1278:             *
1279:             * Command line options suitable for presenting to annotation
1280:             * processors.  "-Afoo=bar" should be "-Afoo" => "bar".
1281:             */
1282:            public Map<String, String> getOptions() {
1283:                return processorOptions;
1284:            }
1285:
1286:            public Messager getMessager() {
1287:                return messager;
1288:            }
1289:
1290:            public Filer getFiler() {
1291:                return filer;
1292:            }
1293:
1294:            public JavacElements getElementUtils() {
1295:                return elementUtils;
1296:            }
1297:
1298:            public JavacTypes getTypeUtils() {
1299:                return typeUtils;
1300:            }
1301:
1302:            public SourceVersion getSourceVersion() {
1303:                return Source.toSourceVersion(source);
1304:            }
1305:
1306:            public Locale getLocale() {
1307:                return Locale.getDefault();
1308:            }
1309:
1310:            public Set<Symbol.PackageSymbol> getSpecifiedPackages() {
1311:                return specifiedPackages;
1312:            }
1313:
1314:            // Borrowed from DocletInvoker and apt
1315:            // TODO: remove from apt's Main
1316:            /**
1317:             * Utility method for converting a search path string to an array
1318:             * of directory and JAR file URLs.
1319:             *
1320:             * @param path the search path string
1321:             * @return the resulting array of directory and JAR file URLs
1322:             */
1323:            public static URL[] pathToURLs(String path) {
1324:                StringTokenizer st = new StringTokenizer(path,
1325:                        File.pathSeparator);
1326:                URL[] urls = new URL[st.countTokens()];
1327:                int count = 0;
1328:                while (st.hasMoreTokens()) {
1329:                    URL url = fileToURL(new File(st.nextToken()));
1330:                    if (url != null) {
1331:                        urls[count++] = url;
1332:                    }
1333:                }
1334:                if (urls.length != count) {
1335:                    URL[] tmp = new URL[count];
1336:                    System.arraycopy(urls, 0, tmp, 0, count);
1337:                    urls = tmp;
1338:                }
1339:                return urls;
1340:            }
1341:
1342:            /**
1343:             * Returns the directory or JAR file URL corresponding to the specified
1344:             * local file name.
1345:             *
1346:             * @param file the File object
1347:             * @return the resulting directory or JAR file URL, or null if unknown
1348:             */
1349:            private static URL fileToURL(File file) {
1350:                String name;
1351:                try {
1352:                    name = file.getCanonicalPath();
1353:                } catch (IOException e) {
1354:                    name = file.getAbsolutePath();
1355:                }
1356:                name = name.replace(File.separatorChar, '/');
1357:                if (!name.startsWith("/")) {
1358:                    name = "/" + name;
1359:                }
1360:                // If the file does not exist, then assume that it's a directory
1361:                if (!file.isFile()) {
1362:                    name = name + "/";
1363:                }
1364:                try {
1365:                    return new URL("file", "", name);
1366:                } catch (MalformedURLException e) {
1367:                    throw new IllegalArgumentException("file");
1368:                }
1369:            }
1370:
1371:            private static final Pattern allMatches = Pattern.compile(".*");
1372:
1373:            private static final Pattern noMatches = Pattern
1374:                    .compile("(\\P{all})+");
1375:
1376:            /**
1377:             * Convert import-style string to regex matching that string.  If
1378:             * the string is a valid import-style string, return a regex that
1379:             * won't match anything.
1380:             */
1381:            // TODO: remove version in Apt.java
1382:            public static Pattern importStringToPattern(String s, Processor p,
1383:                    Log log) {
1384:                if (s.equals("*")) {
1385:                    return allMatches;
1386:                } else {
1387:                    String t = s;
1388:                    boolean star = false;
1389:
1390:                    /*
1391:                     * Validate string from factory is legal.  If the string
1392:                     * has more than one asterisks or the asterisks does not
1393:                     * appear as the last character (preceded by a period),
1394:                     * the string is not legal.
1395:                     */
1396:
1397:                    boolean valid = true;
1398:                    int index = t.indexOf('*');
1399:                    if (index != -1) {
1400:                        // '*' must be last character...
1401:                        if (index == t.length() - 1) {
1402:                            // ... and preceeding character must be '.'
1403:                            if (index - 1 >= 0) {
1404:                                valid = t.charAt(index - 1) == '.';
1405:                                // Strip off ".*$" for identifier checks
1406:                                t = t.substring(0, t.length() - 2);
1407:                            }
1408:                        } else
1409:                            valid = false;
1410:                    }
1411:
1412:                    // Verify string is off the form (javaId \.)+ or javaId
1413:                    if (valid) {
1414:                        String[] javaIds = t.split("\\.", t.length() + 2);
1415:                        for (String javaId : javaIds)
1416:                            valid &= SourceVersion.isIdentifier(javaId);
1417:                    }
1418:
1419:                    if (!valid) {
1420:                        log.warning("proc.malformed.supported.string", s, p
1421:                                .getClass().getName());
1422:                        return noMatches; // won't match any valid identifier
1423:                    }
1424:
1425:                    String s_prime = s.replaceAll("\\.", "\\\\.");
1426:
1427:                    if (s_prime.endsWith("*")) {
1428:                        s_prime = s_prime.substring(0, s_prime.length() - 1)
1429:                                + ".+";
1430:                    }
1431:
1432:                    return Pattern.compile(s_prime);
1433:                }
1434:            }
1435:
1436:            /**
1437:             * For internal use by Sun Microsystems only.  This method will be
1438:             * removed without warning.
1439:             */
1440:            public Context getContext() {
1441:                return context;
1442:            }
1443:
1444:            public String toString() {
1445:                return "javac ProcessingEnvironment version @(#)JavacProcessingEnvironment.java	1.36 07/07/13";
1446:            }
1447:
1448:            public static boolean isValidOptionName(String optionName) {
1449:                for (String s : optionName.split("\\.", -1)) {
1450:                    if (!SourceVersion.isIdentifier(s))
1451:                        return false;
1452:                }
1453:                return true;
1454:            }
1455:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.