Skip to content

Commit

Permalink
Merge pull request #3800 from amishra-u/ast-pos
Browse files Browse the repository at this point in the history
fix: Don't alter the AST node positions of original code.
  • Loading branch information
Rawi01 authored Jan 4, 2025
2 parents 9f5de53 + ba3c922 commit 3115fad
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 31 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Adam Juraszek <juriad@gmail.com>
Aleksandr Zhelezniak <lekan1992@gmail.com>
Amine Touzani <ttzn.dev@gmail.com>
Andre Brait <andrebrait@gmail.com>
Anshuman Mishra <a.mishra@uber.com>
Bulgakov Alexander <buls@yandex.ru>
Caleb Brinkman <floralvikings@gmail.com>
Christian Nüssgens <christian@nuessgens.com>
Expand Down
2 changes: 1 addition & 1 deletion src/core/lombok/javac/handlers/HandleConstructor.java
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ public static void addConstructorProperties(JCModifiers mods, JavacNode node, Li
if (addConstructorProperties && !isLocalType(typeNode) && LombokOptionsFactory.getDelombokOptions(typeNode.getContext()).getFormatPreferences().generateConstructorProperties()) {
addConstructorProperties(mods, typeNode, fieldsToParam);
}
if (onConstructor != null) mods.annotations = mods.annotations.appendList(copyAnnotations(onConstructor));
if (onConstructor != null) mods.annotations = mods.annotations.appendList(copyAnnotations(onConstructor, maker));
return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"),
null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(),
maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public void generateMethods(JavacNode typeNode, JavacNode source, java.util.List
injectMethod(typeNode, equalsMethod);

if (needsCanEqual && canEqualExists == MemberExistsResult.NOT_EXISTS) {
JCMethodDecl canEqualMethod = createCanEqual(typeNode, source, copyAnnotations(onParam));
JCMethodDecl canEqualMethod = createCanEqual(typeNode, source, copyAnnotations(onParam, typeNode.getTreeMaker()));
injectMethod(typeNode, canEqualMethod);
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/lombok/javac/handlers/HandleGetter.java
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ public JCMethodDecl createGetter(long access, JavacNode field, JavacTreeMaker tr

List<JCAnnotation> copyableAnnotations = findCopyableAnnotations(field);
List<JCAnnotation> delegates = findDelegatesAndRemoveFromField(field);
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod).appendList(copyableAnnotations);
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod, treeMaker).appendList(copyableAnnotations);
if (field.isFinal()) {
if (getCheckerFrameworkVersion(field).generatePure()) annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genTypeRef(field, CheckerFrameworkVersion.NAME__PURE), List.<JCExpression>nil()));
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/core/lombok/javac/handlers/HandleJacksonized.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> {

// Copy annotations from the class to the builder class.
List<JCAnnotation> copyableAnnotations = findJacksonAnnotationsOnClass(tdNode);
List<JCAnnotation> copiedAnnotations = copyAnnotations(copyableAnnotations);
List<JCAnnotation> copiedAnnotations = copyAnnotations(copyableAnnotations, maker);
for (JCAnnotation anno : copiedAnnotations) {
recursiveSetGeneratedBy(anno, annotationNode);
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/lombok/javac/handlers/HandleSetter.java
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ public static JCMethodDecl createSetterWithRecv(long access, boolean deprecate,
List<JCAnnotation> copyableAnnotations = findCopyableAnnotations(field);

Name methodName = field.toName(setterName);
List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(copyableAnnotations);
List<JCAnnotation> annsOnParam = copyAnnotations(onParam, treeMaker).appendList(copyableAnnotations);

long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, field.getContext());
JCExpression pType = cloneType(treeMaker, fieldDecl.vartype, source);
Expand Down Expand Up @@ -274,7 +274,7 @@ public static JCMethodDecl createSetterWithRecv(long access, boolean deprecate,
List<JCExpression> throwsClauses = List.nil();
JCExpression annotationMethodDefaultValue = null;

List<JCAnnotation> annsOnMethod = mergeAnnotations(copyAnnotations(onMethod), findCopyableToSetterAnnotations(field));
List<JCAnnotation> annsOnMethod = mergeAnnotations(copyAnnotations(onMethod, treeMaker), findCopyableToSetterAnnotations(field));
if (isFieldDeprecated(field) || deprecate) {
annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil()));
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/lombok/javac/handlers/HandleWith.java
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public JCMethodDecl createWith(long access, JavacNode field, JavacTreeMaker make

JCBlock methodBody = null;
long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, field.getContext());
List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(copyableAnnotations);
List<JCAnnotation> annsOnParam = copyAnnotations(onParam, maker).appendList(copyableAnnotations);

JCExpression pType = cloneType(maker, fieldDecl.vartype, source);
JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, annsOnParam), fieldDecl.name, pType, null);
Expand Down Expand Up @@ -278,7 +278,7 @@ public JCMethodDecl createWith(long access, JavacNode field, JavacTreeMaker make
List<JCExpression> throwsClauses = List.nil();
JCExpression annotationMethodDefaultValue = null;

List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod);
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod, maker);
CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(source);
if (checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil()));

Expand Down
2 changes: 1 addition & 1 deletion src/core/lombok/javac/handlers/HandleWithBy.java
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ public JCMethodDecl createWithBy(long access, JavacNode field, JavacTreeMaker ma
List<JCExpression> throwsClauses = List.nil();
JCExpression annotationMethodDefaultValue = null;

List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod);
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod, maker);
CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(source);
if (checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil()));

Expand Down
20 changes: 14 additions & 6 deletions src/core/lombok/javac/handlers/JavacHandlerUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.Map;
import java.util.regex.Pattern;

import com.sun.source.tree.TreeVisitor;
import com.sun.tools.javac.code.Attribute;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Flags;
Expand Down Expand Up @@ -75,6 +76,7 @@
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
import com.sun.tools.javac.tree.TreeCopier;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.util.Context;
Expand Down Expand Up @@ -1746,7 +1748,8 @@ public static List<JCAnnotation> findCopyableAnnotations(JavacNode node) {
}
}
}
return copyAnnotations(result.toList());

return copyAnnotations(result.toList(), node.getTreeMaker());
}

/**
Expand Down Expand Up @@ -1784,7 +1787,7 @@ private static List<JCAnnotation> findAnnotationsInList(JavacNode node, java.uti
if (annoName == null) return List.nil();

if (!annoName.isEmpty()) {
for (String bn : annotationsToFind) if (typeMatches(bn, node, annoName)) return List.of(anno);
for (String bn : annotationsToFind) if (typeMatches(bn, node, annoName)) return copyAnnotations(List.of(anno), node.getTreeMaker());
}

ListBuffer<JCAnnotation> result = new ListBuffer<JCAnnotation>();
Expand All @@ -1799,7 +1802,7 @@ private static List<JCAnnotation> findAnnotationsInList(JavacNode node, java.uti
}
}
}
return copyAnnotations(result.toList());
return copyAnnotations(result.toList(), node.getTreeMaker());
}

/**
Expand Down Expand Up @@ -2108,15 +2111,20 @@ public static void sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(Javac
errorNode.addError(out.append(" are not allowed on builder classes.").toString());
}

static List<JCAnnotation> copyAnnotations(List<? extends JCExpression> in) {
static List<JCAnnotation> copyAnnotations(List<? extends JCExpression> in, JavacTreeMaker maker) {
ListBuffer<JCAnnotation> out = new ListBuffer<JCAnnotation>();
for (JCExpression expr : in) {
if (!(expr instanceof JCAnnotation)) continue;
out.append((JCAnnotation) expr.clone());
out.append(copyAnnotation((JCAnnotation) expr, maker));
}
return out.toList();
}

static JCAnnotation copyAnnotation(JCAnnotation annotation, JavacTreeMaker maker) {
TreeVisitor<JCTree, Void> visitor = new TreeCopier<Void>(maker.getUnderlyingTreeMaker());
return (JCAnnotation) visitor.visitAnnotation(annotation, null);
}

static List<JCAnnotation> mergeAnnotations(List<JCAnnotation> a, List<JCAnnotation> b) {
if (a == null || a.isEmpty()) return b;
if (b == null || b.isEmpty()) return a;
Expand Down Expand Up @@ -2266,7 +2274,7 @@ private static JCExpression cloneType0(JavacTreeMaker maker, JCTree in) {

if (JCAnnotatedTypeReflect.is(in)) {
JCExpression underlyingType = cloneType0(maker, JCAnnotatedTypeReflect.getUnderlyingType(in));
List<JCAnnotation> anns = copyAnnotations(JCAnnotatedTypeReflect.getAnnotations(in));
List<JCAnnotation> anns = copyAnnotations(JCAnnotatedTypeReflect.getAnnotations(in), maker);
return JCAnnotatedTypeReflect.create(anns, underlyingType);
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/lombok/javac/handlers/JavacSingularsRecipes.java
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ private void generateSingularMethod(CheckerFrameworkVersion cfv, boolean depreca
if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(source, setterPrefix, name.toString()));

statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source));
List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToBuilderSingularSetterAnnotations(data.annotation.up()));
List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToBuilderSingularSetterAnnotations(data.annotation.up()), maker);
finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, methodAnnotations, access, null);
}

Expand Down Expand Up @@ -362,7 +362,7 @@ private void generatePluralMethod(CheckerFrameworkVersion cfv, boolean deprecate
statements.prepend(JavacHandlerUtil.generateNullCheck(maker, null, data.getPluralName(), builderType, "%s cannot be null"));
}

List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToSetterAnnotations(data.annotation.up()));
List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToSetterAnnotations(data.annotation.up()), maker);

finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), methodAnnotations, access, ignoreNullCollections);
}
Expand Down
6 changes: 6 additions & 0 deletions src/delombok/lombok/delombok/Delombok.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public void setWriter(Writer writer) {
private LinkedHashMap<File, File> fileToBase = new LinkedHashMap<File, File>();
private List<File> filesToParse = new ArrayList<File>();
private Map<String, String> formatPrefs = new HashMap<String, String>();
private List<AbstractProcessor> preLombokProcessors = new ArrayList<AbstractProcessor>();
private List<AbstractProcessor> additionalAnnotationProcessors = new ArrayList<AbstractProcessor>();

/** If null, output to standard out. */
Expand Down Expand Up @@ -653,6 +654,10 @@ public void addFile(File base, String fileName) throws IOException {
fileToBase.put(f, base);
}

public void addPreLombokProcessors(AbstractProcessor processor) {
preLombokProcessors.add(processor);
}

public void addAdditionalAnnotationProcessor(AbstractProcessor processor) {
additionalAnnotationProcessors.add(processor);
}
Expand Down Expand Up @@ -735,6 +740,7 @@ public boolean delombok() throws IOException {
Map<JCCompilationUnit, File> baseMap = new IdentityHashMap<JCCompilationUnit, File>();

Set<AbstractProcessor> processors = new LinkedHashSet<AbstractProcessor>();
processors.addAll(preLombokProcessors);
processors.add(new lombok.javac.apt.LombokProcessor());
processors.addAll(additionalAnnotationProcessors);

Expand Down
73 changes: 59 additions & 14 deletions test/core/src/lombok/RunTestsViaDelombok.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -83,7 +84,11 @@ public TransformationResult transformCode(final File file, TestParameters parame

delombok.setDiagnosticsListener(new CapturingDiagnosticListener(file, result.getMessages()));

if (parameters.isCheckPositions()) delombok.addAdditionalAnnotationProcessor(new ValidatePositionProcessor(parameters.getMinVersion()));
if (parameters.isCheckPositions()) {
NodePositionMapper nodePositionMapper = new NodePositionMapper();
delombok.addPreLombokProcessors(nodePositionMapper);
delombok.addAdditionalAnnotationProcessor(new ValidatePositionProcessor(parameters.getMinVersion(), nodePositionMapper));
}
delombok.addAdditionalAnnotationProcessor(new ValidateTypesProcessor());
delombok.addAdditionalAnnotationProcessor(new ValidateNoDuplicateTreeNodeProcessor());

Expand All @@ -105,15 +110,35 @@ public TransformationResult transformCode(final File file, TestParameters parame
}
}

public static class NodePositionMapper extends TreeProcessor {
Map<JCTree, Integer> nodePositions = new HashMap<JCTree, Integer>();

@Override void processCompilationUnit(final JCCompilationUnit unit) {
unit.accept(new TreeScanner() {
@Override public void scan(JCTree tree) {
if (tree == null) return;
if (tree.pos >= 0) {
nodePositions.put(tree, tree.pos);
}
super.scan(tree);

}
});
}

}

public static class ValidatePositionProcessor extends TreeProcessor {
private final int version;
private final NodePositionMapper nodePositionMapper;

public ValidatePositionProcessor(int version) {
public ValidatePositionProcessor(int version, NodePositionMapper nodePositionMapper) {
this.version = version;
this.nodePositionMapper = nodePositionMapper;
}

private String craftFailMsg(String problematicNode, Deque<JCTree> astContext) {
StringBuilder msg = new StringBuilder(problematicNode).append(" position of node not set: ");
StringBuilder msg = new StringBuilder(problematicNode);
for (JCTree t : astContext) {
msg.append("\n ").append(t.getClass().getSimpleName());
String asStr = t.toString();
Expand All @@ -125,12 +150,30 @@ private String craftFailMsg(String problematicNode, Deque<JCTree> astContext) {
return msg.append("\n-------").toString();
}

private boolean isLombokGenerated(JCTree tree) {
List<JCAnnotation> annotations = com.sun.tools.javac.util.List.nil();
if (tree instanceof JCMethodDecl) {
annotations = ((JCMethodDecl) tree).mods.annotations;
}
if (tree instanceof JCVariableDecl) {
annotations = ((JCVariableDecl) tree).mods.annotations;
}
for (JCAnnotation annotation: annotations) {
if ("lombok.Generated".equals(annotation.getAnnotationType().toString())) {
return true;
}
}
return false;
}

@Override void processCompilationUnit(final JCCompilationUnit unit) {
final Deque<JCTree> astContext = new ArrayDeque<JCTree>();
final Deque<JCTree> lombokGeneratedNodes = new ArrayDeque<JCTree>();
unit.accept(new TreeScanner() {
@Override public void scan(JCTree tree) {
if (tree == null) return;
if (tree instanceof JCMethodDecl && (((JCMethodDecl) tree).mods.flags & Flags.GENERATEDCONSTR) != 0) return;
if (isLombokGenerated(tree)) lombokGeneratedNodes.add(tree);
astContext.push(tree);
try {
if (tree instanceof JCModifiers) return;
Expand All @@ -153,16 +196,26 @@ private String craftFailMsg(String problematicNode, Deque<JCTree> astContext) {

if (tree instanceof JCVariableDecl && (((JCVariableDecl) tree).mods.flags & Javac.GENERATED_MEMBER) != 0) return;

if (check && tree.pos == -1) fail(craftFailMsg("Start", astContext));
if (check && tree.pos == -1) fail(craftFailMsg("Start position of node not set: ", astContext));

// Ignore ast position validation on lombok generated nodes.
if (lombokGeneratedNodes.isEmpty()) {
Integer expectedPos = nodePositionMapper.nodePositions.get(tree);
if (expectedPos != null && !expectedPos.equals(tree.pos)) {
fail(craftFailMsg(String.format("Expected node position %d, actual node position %d: ", expectedPos, tree.pos), astContext));
}
}
if (check && Javac.getEndPosition(tree, unit) == -1) {
fail(craftFailMsg("End", astContext));
fail(craftFailMsg("End position of node not set: ", astContext));
}
} finally {
try {
super.scan(tree);
} finally {
astContext.pop();
JCTree _tree = astContext.pop();
if (!lombokGeneratedNodes.isEmpty() && lombokGeneratedNodes.peek().equals(_tree)) {
lombokGeneratedNodes.pop();
}
}
}
}
Expand Down Expand Up @@ -289,14 +342,6 @@ public void scan(JCTree tree) {
super.scan(tree);
parents.pop();
}

/**
* We always generate shallow copies for annotations
*/
@Override
public void visitAnnotation(JCAnnotation tree) {
return;
}
});
}

Expand Down

0 comments on commit 3115fad

Please sign in to comment.