blob: 367e1c620dc797b2b8f225b9766af4794593db54 [file] [log] [blame]
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2009-2011 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*
* Contributor(s):
*
* Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
*/
package org.netbeans.modules.jackpot30.compiler;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.api.MultiTaskListener;
import com.sun.tools.javac.comp.Resolve;
import com.sun.tools.javac.jvm.Gen;
import com.sun.tools.javac.parser.ParserFactory;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Context.Key;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Options;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.source.ClasspathInfo;
import org.netbeans.api.java.source.CompilationInfoHack;
import org.netbeans.lib.nbjavac.services.NBParserFactory;
import org.netbeans.lib.nbjavac.services.NBResolve;
import org.netbeans.modules.jackpot30.compiler.AbstractHintsAnnotationProcessing.Reporter;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.openide.filesystems.FileUtil;
import org.openide.util.Lookup;
import org.openide.util.lookup.ServiceProvider;
/**
*
* @author lahvac
*/
@SupportedAnnotationTypes("*")
@ServiceProvider(service=Processor.class)
public final class HintsAnnotationProcessingImpl extends AbstractProcessor {
private final Collection<String> seenTypes = new LinkedList<String>();
private final Collection<AbstractHintsAnnotationProcessing> processors = new LinkedList<AbstractHintsAnnotationProcessing>();
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
for (AbstractHintsAnnotationProcessing p : Lookup.getDefault().lookupAll(AbstractHintsAnnotationProcessing.class)) {
if (p.initialize(processingEnv)) {
processors.add(p);
}
}
if (processors.isEmpty()) {
return;
}
if (!(processingEnv instanceof JavacProcessingEnvironment)) {
throw new UnsupportedOperationException("Not a JavacProcessingEnvironment");
}
Context c = ((JavacProcessingEnvironment) processingEnv).getContext();
MultiTaskListener.instance(c).add(new TaskListenerImpl());
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement type : ElementFilter.typesIn(roundEnv.getRootElements())) {
seenTypes.add(type.getQualifiedName().toString());
}
if (roundEnv.processingOver()) {
try {
//XXX: workarounding a bug in CRTable (see HintsAnnotationProcessingTest.testCRTable):
Context c = ((JavacProcessingEnvironment) processingEnv).getContext();
Options.instance(c).remove("-Xjcov");
Field f = Gen.class.getDeclaredField("genCrt");
f.setAccessible(true);
f.set(Gen.instance(c), false);
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
private void doProcessing(TypeElement type) {
if (!seenTypes.remove(type.getQualifiedName().toString())) return;
Context c = ((JavacProcessingEnvironment) processingEnv).getContext();
StandardJavaFileManager s = (StandardJavaFileManager) c.get(JavaFileManager.class);
ClassPath boot = computeClassPath(s, StandardLocation.PLATFORM_CLASS_PATH);
ClassPath compile = computeClassPath(s, StandardLocation.CLASS_PATH);
ClassPath source = computeClassPath(s, StandardLocation.SOURCE_PATH);
Trees trees = JavacTrees.instance(c);
final Log log = Log.instance(c);
final Key<ParserFactory> key = ParserFactoryKeyAccessor.getContextKey();
ParserFactory origParserFactory = c.get(key);
c.put(key, (ParserFactory) null);
NBParserFactory.preRegister(c);
final Key<Resolve> resolveKey = ResolveKeyAccessor.getContextKey();
Resolve origResolve = c.get(resolveKey);
c.put(resolveKey, (Resolve) null);
NBResolve.preRegister(c);
try {
TreePath elTree = trees.getPath(type);
JCCompilationUnit cut = (JCCompilationUnit) elTree.getCompilationUnit();
if (!cut.sourcefile.toUri().isAbsolute()) {
processingEnv.getMessager().printMessage(Kind.NOTE, "Not an absolute URI: " + cut.sourcefile.toUri().toASCIIString(), type);
return ; //XXX
}
CompilationInfoHack info = new CompilationInfoHack(c, ClasspathInfo.create(boot, compile, source), cut);
JavaFileObject origSourceFile = log.currentSourceFile();
try {
log.useSource(cut.sourcefile);
for (AbstractHintsAnnotationProcessing p : processors) {
p.doProcess(info, processingEnv, new Reporter() {
@Override public void warning(int offset, String message) {
log.warning(offset, "proc.messager", message);
}
});
}
} finally {
log.useSource(origSourceFile);
}
} finally {
if (seenTypes.isEmpty()) {
for (AbstractHintsAnnotationProcessing p : processors) {
p.finish();
}
}
c.put(key, (ParserFactory) null);
c.put(key, origParserFactory);
c.put(resolveKey, (Resolve) null);
c.put(resolveKey, origResolve);
}
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
@Override
public Set<String> getSupportedOptions() {
Set<String> options = new HashSet<String>();
for (AbstractHintsAnnotationProcessing p : Lookup.getDefault().lookupAll(AbstractHintsAnnotationProcessing.class)) {
options.addAll(p.getSupportedOptions());
}
return options;
}
private static ClassPath computeClassPath(StandardJavaFileManager m, StandardLocation kind) {
List<URL> urls = new LinkedList<URL>();
Iterable<? extends File> files = m.getLocation(kind);
if (files != null) {
for (File f : files) {
urls.add(FileUtil.urlForArchiveOrDir(FileUtil.normalizeFile(f.getAbsoluteFile())));
}
}
return ClassPathSupport.createClassPath(urls.toArray(new URL[0]));
}
private final class TaskListenerImpl implements TaskListener {
public TaskListenerImpl() { }
@Override
public void started(TaskEvent te) {
}
@Override
public void finished(TaskEvent te) {
if (te.getKind() == TaskEvent.Kind.ANALYZE) {
TypeElement toProcess = te.getTypeElement();
assert toProcess != null;
doProcessing(toProcess);
}
}
}
private static final class ParserFactoryKeyAccessor extends ParserFactory {
ParserFactoryKeyAccessor() {
super(null);
}
public static Key<ParserFactory> getContextKey() {
return parserFactoryKey;
}
}
private static final class ResolveKeyAccessor extends Resolve {
ResolveKeyAccessor() {
super(null);
}
public static Key<Resolve> getContextKey() {
return resolveKey;
}
}
static {
try {
ClassLoader l = HintsAnnotationProcessingImpl.class.getClassLoader();
if (l == null) {
l = ClassLoader.getSystemClassLoader();
}
l.setClassAssertionStatus("org.netbeans.api.java.source.CompilationInfo", false);
} catch (Throwable t) {
t.printStackTrace();
}
}
}