blob: ce01590f00092c26558b2385dccfcc322ef78d6e [file] [log] [blame]
/*
* Copyright 2014 The Kythe Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.devtools.kythe.extractors.java;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import java.io.IOException;
import java.util.Arrays;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Generated;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardLocation;
/**
* This class is used to visit all the annotation used in Java files and record the usage of these
* annotation as JavaFileObject. This processing will eliminate some of the platform errors caused
* by javac not being able to find the class for some of the annotations in the analysis phase. The
* recorded files will later be put in the datastore for analysis phase.
*/
@SupportedAnnotationTypes(value = {"*"})
public class ProcessAnnotation extends AbstractProcessor {
private static final Logger logger = Logger.getLogger(ProcessAnnotation.class.getName());
// ANDROID_BUILD: This line has been copied from ../../platform/shared/Metadata.java to avoid
// compiling that file and all its dependencies when building javac_extractor for Android.
private static final String ANNOTATION_COMMENT_PREFIX = "annotations:";
UsageAsInputReportingFileManager fileManager;
public ProcessAnnotation(UsageAsInputReportingFileManager fileManager) {
this.fileManager = fileManager;
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement e : annotations) {
TypeSymbol s = (TypeSymbol) e;
try {
UsageAsInputReportingJavaFileObject jfo =
(UsageAsInputReportingJavaFileObject)
fileManager.getJavaFileForInput(
StandardLocation.CLASS_OUTPUT, s.flatName().toString(), Kind.CLASS);
if (jfo == null) {
jfo =
(UsageAsInputReportingJavaFileObject)
fileManager.getJavaFileForInput(
StandardLocation.CLASS_PATH, s.flatName().toString(), Kind.CLASS);
}
if (jfo == null) {
jfo =
(UsageAsInputReportingJavaFileObject)
fileManager.getJavaFileForInput(
StandardLocation.SOURCE_PATH, s.flatName().toString(), Kind.CLASS);
}
if (jfo != null) {
jfo.markUsed();
}
} catch (IOException ex) {
// We only log any IO exception here and do not cancel the whole processing because of an
// exception in this stage.
logger.log(Level.SEVERE, "Error in annotation processing", ex);
}
}
for (Element ae : roundEnv.getElementsAnnotatedWith(Generated.class)) {
Generated generated = ae.getAnnotation(Generated.class);
if (generated == null
|| generated.comments() == null
|| !generated.comments().startsWith(ANNOTATION_COMMENT_PREFIX)) {
continue;
}
String annotationFile = generated.comments().substring(ANNOTATION_COMMENT_PREFIX.length());
if (ae instanceof ClassSymbol) {
ClassSymbol cs = (ClassSymbol) ae;
try {
String annotationPath = cs.sourcefile.toUri().resolve(annotationFile).getPath();
for (JavaFileObject file :
fileManager.getJavaFileForSources(Arrays.asList(annotationPath))) {
((UsageAsInputReportingJavaFileObject) file).markUsed();
}
} catch (IllegalArgumentException ex) {
logger.log(Level.WARNING, "Bad annotationFile: " + annotationFile, ex);
}
}
}
// We must return false so normal processors run after us.
return false;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}