cmdline/compiler/src/org/netbeans/modules/jackpot30/compiler/HintsAnnotationProcessingImpl.java
author Jan Lahoda <jlahoda@netbeans.org>
Sun, 03 Feb 2013 00:13:11 +0100
branchjdk8
changeset 926 d1e1adedc8cc
parent 812 8d0ac461ca68
child 941 4235164505af
permissions -rw-r--r--
Adjusting to NB-JDK8 changes
     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2009-2011 Sun Microsystems, Inc. All rights reserved.
     5  *
     6  * The contents of this file are subject to the terms of either the GNU
     7  * General Public License Version 2 only ("GPL") or the Common
     8  * Development and Distribution License("CDDL") (collectively, the
     9  * "License"). You may not use this file except in compliance with the
    10  * License. You can obtain a copy of the License at
    11  * http://www.netbeans.org/cddl-gplv2.html
    12  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    13  * specific language governing permissions and limitations under the
    14  * License.  When distributing the software, include this License Header
    15  * Notice in each file and include the License file at
    16  * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    17  * particular file as subject to the "Classpath" exception as provided
    18  * by Sun in the GPL Version 2 section of the License file that
    19  * accompanied this code. If applicable, add the following below the
    20  * License Header, with the fields enclosed by brackets [] replaced by
    21  * your own identifying information:
    22  * "Portions Copyrighted [year] [name of copyright owner]"
    23  *
    24  * If you wish your version of this file to be governed by only the CDDL
    25  * or only the GPL Version 2, indicate your decision by adding
    26  * "[Contributor] elects to include this software in this distribution
    27  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    28  * single choice of license, a recipient has the option to distribute
    29  * your version of this file under either the CDDL, the GPL Version 2 or
    30  * to extend the choice of license to its licensees as provided above.
    31  * However, if you add GPL Version 2 code and therefore, elected the GPL
    32  * Version 2 license, then the option applies only if the new code is
    33  * made subject to such option by the copyright holder.
    34  *
    35  * Contributor(s):
    36  *
    37  * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
    38  */
    39 package org.netbeans.modules.jackpot30.compiler;
    40 
    41 import com.sun.source.util.JavacTask;
    42 import com.sun.source.util.TaskEvent;
    43 import com.sun.source.util.TaskListener;
    44 import com.sun.source.util.TreePath;
    45 import com.sun.source.util.Trees;
    46 import com.sun.tools.javac.api.JavacTrees;
    47 import com.sun.tools.javac.api.MultiTaskListener;
    48 import com.sun.tools.javac.jvm.Gen;
    49 import com.sun.tools.javac.parser.ParserFactory;
    50 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
    51 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
    52 import com.sun.tools.javac.util.Context;
    53 import com.sun.tools.javac.util.Context.Key;
    54 import com.sun.tools.javac.util.Log;
    55 import com.sun.tools.javac.util.Options;
    56 import java.io.File;
    57 import java.lang.reflect.Field;
    58 import java.net.URL;
    59 import java.util.Collection;
    60 import java.util.HashSet;
    61 import java.util.LinkedList;
    62 import java.util.List;
    63 import java.util.Set;
    64 import javax.annotation.processing.AbstractProcessor;
    65 import javax.annotation.processing.ProcessingEnvironment;
    66 import javax.annotation.processing.Processor;
    67 import javax.annotation.processing.RoundEnvironment;
    68 import javax.annotation.processing.SupportedAnnotationTypes;
    69 import javax.lang.model.SourceVersion;
    70 import javax.lang.model.element.TypeElement;
    71 import javax.lang.model.util.ElementFilter;
    72 import javax.tools.Diagnostic.Kind;
    73 import javax.tools.JavaFileManager;
    74 import javax.tools.JavaFileObject;
    75 import javax.tools.StandardJavaFileManager;
    76 import javax.tools.StandardLocation;
    77 import org.netbeans.api.java.classpath.ClassPath;
    78 import org.netbeans.api.java.source.ClasspathInfo;
    79 import org.netbeans.api.java.source.CompilationInfoHack;
    80 import org.netbeans.lib.nbjavac.services.NBParserFactory;
    81 import org.netbeans.modules.jackpot30.compiler.AbstractHintsAnnotationProcessing.Reporter;
    82 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
    83 import org.openide.filesystems.FileUtil;
    84 import org.openide.util.Lookup;
    85 import org.openide.util.lookup.ServiceProvider;
    86 
    87 /**
    88  *
    89  * @author lahvac
    90  */
    91 @SupportedAnnotationTypes("*")
    92 @ServiceProvider(service=Processor.class)
    93 public final class HintsAnnotationProcessingImpl extends AbstractProcessor {
    94 
    95     private final Collection<String> seenTypes = new LinkedList<String>();
    96     private final Collection<AbstractHintsAnnotationProcessing> processors = new LinkedList<AbstractHintsAnnotationProcessing>();
    97 
    98     @Override
    99     public synchronized void init(ProcessingEnvironment processingEnv) {
   100         super.init(processingEnv);
   101 
   102         for (AbstractHintsAnnotationProcessing p : Lookup.getDefault().lookupAll(AbstractHintsAnnotationProcessing.class)) {
   103             if (p.initialize(processingEnv)) {
   104                 processors.add(p);
   105             }
   106         }
   107 
   108         if (processors.isEmpty()) {
   109             return;
   110         }
   111 
   112         if (!(processingEnv instanceof JavacProcessingEnvironment)) {
   113             throw new UnsupportedOperationException("Not a JavacProcessingEnvironment");
   114         }
   115 
   116         Context c = ((JavacProcessingEnvironment) processingEnv).getContext();
   117         
   118         MultiTaskListener.instance(c).add(new TaskListenerImpl());
   119     }
   120 
   121     @Override
   122     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
   123         for (TypeElement type : ElementFilter.typesIn(roundEnv.getRootElements())) {
   124             seenTypes.add(type.getQualifiedName().toString());
   125         }
   126 
   127         if (roundEnv.processingOver()) {
   128             try {
   129                 //XXX: workarounding a bug in CRTable (see HintsAnnotationProcessingTest.testCRTable):
   130                 Context c = ((JavacProcessingEnvironment) processingEnv).getContext();
   131                 Options.instance(c).remove("-Xjcov");
   132                 Field f = Gen.class.getDeclaredField("genCrt");
   133                 f.setAccessible(true);
   134                 f.set(Gen.instance(c), false);
   135             } catch (Exception e) {
   136                 e.printStackTrace();
   137             }
   138         }
   139         return false;
   140     }
   141 
   142     private void doProcessing(TypeElement type) {
   143         if (!seenTypes.remove(type.getQualifiedName().toString())) return;
   144         
   145         Context c = ((JavacProcessingEnvironment) processingEnv).getContext();
   146         StandardJavaFileManager s = (StandardJavaFileManager) c.get(JavaFileManager.class);
   147         ClassPath boot = computeClassPath(s, StandardLocation.PLATFORM_CLASS_PATH);
   148         ClassPath compile = computeClassPath(s, StandardLocation.CLASS_PATH);
   149         ClassPath source = computeClassPath(s, StandardLocation.SOURCE_PATH);
   150         Trees trees = JavacTrees.instance(c);
   151         final Log log = Log.instance(c);
   152         final Key<ParserFactory> key = ParserFactoryKeyAccessor.getContextKey();
   153         ParserFactory origParserFactory = c.get(key);
   154         c.put(key, (ParserFactory) null);
   155         NBParserFactory.preRegister(c);
   156 
   157         try {
   158             TreePath elTree = trees.getPath(type);
   159             JCCompilationUnit cut = (JCCompilationUnit) elTree.getCompilationUnit();
   160 
   161             if (!cut.sourcefile.toUri().isAbsolute()) {
   162                 processingEnv.getMessager().printMessage(Kind.NOTE, "Not an absolute URI: " + cut.sourcefile.toUri().toASCIIString(), type);
   163                 return ; //XXX
   164             }
   165 
   166             CompilationInfoHack info = new CompilationInfoHack(c, ClasspathInfo.create(boot, compile, source), cut);
   167             JavaFileObject origSourceFile = log.currentSourceFile();
   168 
   169             try {
   170                 log.useSource(cut.sourcefile);
   171 
   172                 for (AbstractHintsAnnotationProcessing p : processors) {
   173                     p.doProcess(info, processingEnv, new Reporter() {
   174                         @Override public void warning(int offset, String message) {
   175                             log.warning(offset, "proc.messager", message);
   176                         }
   177                     });
   178                 }
   179             } finally {
   180                 log.useSource(origSourceFile);
   181             }
   182         } finally {
   183             if (seenTypes.isEmpty()) {
   184                 for (AbstractHintsAnnotationProcessing p : processors) {
   185                     p.finish();
   186                 }
   187             }
   188 
   189             c.put(key, (ParserFactory) null);
   190             c.put(key, origParserFactory);
   191         }
   192     }
   193 
   194     @Override
   195     public SourceVersion getSupportedSourceVersion() {
   196         return SourceVersion.latest();
   197     }
   198 
   199     @Override
   200     public Set<String> getSupportedOptions() {
   201         Set<String> options = new HashSet<String>();
   202 
   203         for (AbstractHintsAnnotationProcessing p : Lookup.getDefault().lookupAll(AbstractHintsAnnotationProcessing.class)) {
   204             options.addAll(p.getSupportedOptions());
   205         }
   206 
   207         return options;
   208     }
   209 
   210     private static ClassPath computeClassPath(StandardJavaFileManager m, StandardLocation kind) {
   211         List<URL> urls = new LinkedList<URL>();
   212         Iterable<? extends File> files = m.getLocation(kind);
   213 
   214         if (files != null) {
   215             for (File f : files) {
   216                 urls.add(FileUtil.urlForArchiveOrDir(FileUtil.normalizeFile(f)));
   217             }
   218         }
   219 
   220         return ClassPathSupport.createClassPath(urls.toArray(new URL[0]));
   221     }
   222 
   223     private final class TaskListenerImpl implements TaskListener {
   224 
   225         public TaskListenerImpl() { }
   226 
   227         @Override
   228         public void started(TaskEvent te) {
   229         }
   230 
   231         @Override
   232         public void finished(TaskEvent te) {
   233             if (te.getKind() == TaskEvent.Kind.ANALYZE) {
   234                 TypeElement toProcess = te.getTypeElement();
   235 
   236                 assert toProcess != null;
   237                 doProcessing(toProcess);
   238             }
   239         }
   240 
   241     }
   242 
   243     private static final class ParserFactoryKeyAccessor extends ParserFactory {
   244         ParserFactoryKeyAccessor() {
   245             super(null);
   246         }
   247         public static Key<ParserFactory> getContextKey() {
   248             return parserFactoryKey;
   249         }
   250     }
   251 
   252 
   253     static {
   254         try {
   255             ClassLoader l = HintsAnnotationProcessingImpl.class.getClassLoader();
   256 
   257             if (l == null) {
   258                 l = ClassLoader.getSystemClassLoader();
   259             }
   260 
   261             l.setClassAssertionStatus("org.netbeans.api.java.source.CompilationInfo", false);
   262         } catch (Throwable t) {
   263             t.printStackTrace();
   264         }
   265     }
   266 
   267 }