package lombok.eclipse;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.lang.reflect.Field;
import lombok.ConfigurationKeys;
import lombok.core.LombokConfiguration;
import lombok.core.debug.DebugSnapshotStore;
import lombok.core.debug.HistogramTracker;
import lombok.patcher.Symbols;
import lombok.permit.Permit;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.parser.Parser;
public class TransformEclipseAST {
private final EclipseAST ast;
private static final Field astCacheField;
private static final HandlerLibrary handlers;
public static boolean disableLombok = false;
private static final HistogramTracker lombokTracker;
static {
String v = System.getProperty("lombok.histogram");
if (v == null) lombokTracker = null;
else if (v.toLowerCase().equals("sysout")) lombokTracker = new HistogramTracker("lombok.histogram", System.out);
else lombokTracker = new HistogramTracker("lombok.histogram");
}
static {
Field f = null;
HandlerLibrary h = null;
if (System.getProperty("lombok.disable") != null) {
disableLombok = true;
astCacheField = null;
handlers = null;
} else {
try {
h = HandlerLibrary.load();
} catch (Throwable t) {
try {
error(null, "Problem initializing lombok", t);
} catch (Throwable t2) {
System.err.println("Problem initializing lombok");
t.printStackTrace();
}
disableLombok = true;
}
try {
f = Permit.getField(CompilationUnitDeclaration.class, "$lombokAST");
} catch (Throwable t) {
}
astCacheField = f;
handlers = h;
}
}
public static void transform_swapped(CompilationUnitDeclaration ast, Parser parser) {
transform(parser, ast);
}
public static EclipseAST getAST(CompilationUnitDeclaration ast, boolean forceRebuild) {
EclipseAST existing = null;
if (astCacheField != null) {
try {
existing = (EclipseAST) astCacheField.get(ast);
} catch (Exception e) {
}
}
if (existing == null) {
existing = new EclipseAST(ast);
if (astCacheField != null) try {
astCacheField.set(ast, existing);
} catch (Exception ignore) {
}
} else {
existing.rebuild(forceRebuild);
}
return existing;
}
public static void transform(Parser parser, CompilationUnitDeclaration ast) {
if (disableLombok) return;
if (Symbols.hasSymbol("lombok.disable")) return;
if (Boolean.TRUE.equals(LombokConfiguration.read(ConfigurationKeys.LOMBOK_DISABLE, EclipseAST.getAbsoluteFileLocation(ast)))) return;
try {
DebugSnapshotStore.INSTANCE.snapshot(ast, "transform entry");
long histoToken = lombokTracker == null ? 0L : lombokTracker.start();
EclipseAST existing = getAST(ast, false);
new TransformEclipseAST(existing).go();
if (lombokTracker != null) lombokTracker.end(histoToken);
DebugSnapshotStore.INSTANCE.snapshot(ast, "transform exit");
} catch (Throwable t) {
DebugSnapshotStore.INSTANCE.snapshot(ast, "transform error: %s", t.getClass().getSimpleName());
try {
String message = "Lombok can't parse this source: " + t.toString();
EclipseAST.addProblemToCompilationResult(ast.getFileName(), ast.compilationResult, false, message, 0, 0);
t.printStackTrace();
} catch (Throwable t2) {
try {
error(ast, "Can't create an error in the problems dialog while adding: " + t.toString(), t2);
} catch (Throwable t3) {
disableLombok = true;
}
}
}
}
public TransformEclipseAST(EclipseAST ast) {
this.ast = ast;
}
public void go() {
long nextPriority = Long.MIN_VALUE;
for (Long d : handlers.getPriorities()) {
if (nextPriority > d) continue;
AnnotationVisitor visitor = new AnnotationVisitor(d);
ast.traverse(visitor);
nextPriority = visitor.getNextPriority();
nextPriority = Math.min(nextPriority, handlers.callASTVisitors(ast, d, ast.isCompleteParse()));
}
}
private static class AnnotationVisitor extends EclipseASTAdapter {
private final long priority;
private long nextPriority = Long.MAX_VALUE;
public AnnotationVisitor(long priority) {
this.priority = priority;
}
public long getNextPriority() {
return nextPriority;
}
@Override public void visitAnnotationOnField(FieldDeclaration field, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
@Override public void visitAnnotationOnMethodArgument(Argument arg, AbstractMethodDeclaration method, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
@Override public void visitAnnotationOnLocal(LocalDeclaration local, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
@Override public void visitAnnotationOnMethod(AbstractMethodDeclaration method, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
@Override public void visitAnnotationOnType(TypeDeclaration type, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
@Override public void visitAnnotationOnTypeUse(TypeReference typeUse, EclipseNode annotationNode, Annotation annotation) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get();
nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority));
}
}
}