Skip to content

Commit

Permalink
[Fixes issue #1783] lombok.var / lombok.experimental.var import would…
Browse files Browse the repository at this point in the history
… be removed by eclipse’s organize imports.
  • Loading branch information
rzwitserloot committed Jul 25, 2018
1 parent 5ec61bb commit 7c3724c
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 31 deletions.
1 change: 1 addition & 0 deletions doc/changelog.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Lombok Changelog
### v1.18.1 "Edgy Guinea Pig"
* BUGFIX: mapstruct + lombok in eclipse should hopefully work again. [Issue #1359](https://github.com/rzwitserloot/lombok/issues/1359) and [mapstruct issue #1159](https://github.com/mapstruct/mapstruct/issues/1159)
* BUGFIX: Equals and hashCode again exclude transient fields by default. [Issue #1724](https://github.com/rzwitserloot/lombok/issues/1724)
* BUGFIX: Eclipse 'organize imports' feature (either explicitly, or if automatically triggered on saving via 'save actions') would remove the import for `lombok.var`. [Issue #1783](https://github.com/rzwitserloot/lombok/issues/1783)
* FEATURE: You can now make builders for type hierarchies, using the new (experimental) `@SuperBuilder` annotation. Thanks for the contribution, Jan Rieke. [`@SuperBuilder` documentation](https://projectlombok.org/features/experimental/SuperBuilder)
* FEATURE: `@NoArgsConstructor`, including forcing one with `lombok.config: lombok.noArgsConstructor.extraPrivate=true` now take any defaults set with `@Builder.Default` into account. [Issue #1347](https://github.com/rzwitserloot/lombok/issues/1347)

Expand Down
16 changes: 8 additions & 8 deletions src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
Original file line number Diff line number Diff line change
Expand Up @@ -210,16 +210,16 @@ public static boolean handleValForLocalDeclaration(LocalDeclaration local, Block
if (local == null || !LocalDeclaration.class.equals(local.getClass())) return false;
boolean decomponent = false;

boolean val = isVal(local, scope);
boolean var = isVar(local, scope);
if (!(val || var)) return false;
boolean val = isVal(local, scope);
boolean var = isVar(local, scope);
if (!(val || var)) return false;

StackTraceElement[] st = new Throwable().getStackTrace();
for (int i = 0; i < st.length - 2 && i < 10; i++) {
if (st[i].getClassName().equals("lombok.launch.PatchFixesHider$Val")) {
boolean valInForStatement = val &&
st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") &&
st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement");
st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") &&
st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement");
if (valInForStatement) return false;
break;
}
Expand Down Expand Up @@ -269,7 +269,7 @@ public static boolean handleValForLocalDeclaration(LocalDeclaration local, Block
}
}

if(val) local.modifiers |= ClassFileConstants.AccFinal;
if (val) local.modifiers |= ClassFileConstants.AccFinal;
local.annotations = addValAnnotation(local.annotations, local.type, scope);
local.type = replacement != null ? replacement : new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(local.type, 3));

Expand Down Expand Up @@ -298,7 +298,7 @@ public static boolean handleValForForEach(ForeachStatement forEach, BlockScope s
if (val) forEach.elementVariable.modifiers |= ClassFileConstants.AccFinal;
forEach.elementVariable.annotations = addValAnnotation(forEach.elementVariable.annotations, forEach.elementVariable.type, scope);
forEach.elementVariable.type = replacement != null ? replacement :
new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(forEach.elementVariable.type, 3));
new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(forEach.elementVariable.type, 3));

return false;
}
Expand Down Expand Up @@ -326,7 +326,7 @@ private static TypeBinding getForEachComponentType(Expression collection, BlockS
resolved = ((ArrayBinding) resolved).elementsType();
return resolved;
} else if (resolved instanceof ReferenceBinding) {
ReferenceBinding iterableType = ((ReferenceBinding)resolved).findSuperTypeOriginatingFrom(TypeIds.T_JavaLangIterable, false);
ReferenceBinding iterableType = ((ReferenceBinding) resolved).findSuperTypeOriginatingFrom(TypeIds.T_JavaLangIterable, false);

TypeBinding[] arguments = null;
if (iterableType != null) switch (iterableType.kind()) {
Expand Down
84 changes: 61 additions & 23 deletions src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@
import org.eclipse.jdt.internal.compiler.ast.ForeachStatement;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.parser.Parser;

public class PatchValEclipse {
Expand Down Expand Up @@ -103,6 +103,10 @@ public static void copyInitializationOfLocalDeclaration(Parser parser) {
}
}

private static boolean couldBeVal(ImportReference[] imports, TypeReference type) {
return PatchVal.couldBe(imports, "lombok.val", type);
}

private static boolean couldBeVar(ImportReference[] imports, TypeReference type) {
return PatchVal.couldBe(imports, "lombok.experimental.var", type) || PatchVal.couldBe(imports, "lombok.var", type);
}
Expand All @@ -118,17 +122,18 @@ public static void addFinalAndValAnnotationToVariableDeclarationStatement(Object
}

public static void addFinalAndValAnnotationToModifierList(Object converter, List<IExtendedModifier> modifiers, AST ast, LocalDeclaration in) {
// First check that 'in' has the final flag on, and a @val / @lombok.val annotation.
if ((in.modifiers & ClassFileConstants.AccFinal) == 0) return;
// First check that 'in' has the final flag on, and a @val / @lombok.val / @var / @lombok.var annotation.
if (in.annotations == null) return;
boolean found = false;
Annotation valAnnotation = null;

Annotation valAnnotation = null, varAnnotation = null;
for (Annotation ann : in.annotations) {
if (couldBeVal(null, ann.type)) {
found = true;
valAnnotation = ann;
break;
}
if (couldBeVar(null, ann.type)) {
found = true;
varAnnotation = ann;
}
}

Expand All @@ -139,10 +144,11 @@ public static void addFinalAndValAnnotationToModifierList(Object converter, List
if (modifiers == null) return; // This is null only if the project is 1.4 or less. Lombok doesn't work in that.
boolean finalIsPresent = false;
boolean valIsPresent = false;
boolean varIsPresent = false;

for (Object present : modifiers) {
if (present instanceof Modifier) {
ModifierKeyword keyword = ((Modifier)present).getKeyword();
ModifierKeyword keyword = ((Modifier) present).getKeyword();
if (keyword == null) continue;
if (keyword.toFlagValue() == Modifier.FINAL) finalIsPresent = true;
}
Expand All @@ -151,20 +157,18 @@ public static void addFinalAndValAnnotationToModifierList(Object converter, List
Name typeName = ((org.eclipse.jdt.core.dom.Annotation) present).getTypeName();
if (typeName != null) {
String fullyQualifiedName = typeName.getFullyQualifiedName();
if ("val".equals(fullyQualifiedName) || "lombok.val".equals(fullyQualifiedName)) {
valIsPresent = true;
}
if ("val".equals(fullyQualifiedName) || "lombok.val".equals(fullyQualifiedName)) valIsPresent = true;
if ("var".equals(fullyQualifiedName) || "lombok.var".equals(fullyQualifiedName) || "lombok.experimental.var".equals(fullyQualifiedName)) varIsPresent = true;
}
}
}

if (!finalIsPresent) {
modifiers.add(
createModifier(ast, ModifierKeyword.FINAL_KEYWORD, valAnnotation.sourceStart, valAnnotation.sourceEnd));
if (!finalIsPresent && valAnnotation != null) {
modifiers.add(createModifier(ast, ModifierKeyword.FINAL_KEYWORD, valAnnotation.sourceStart, valAnnotation.sourceEnd));
}

if (!valIsPresent) {
MarkerAnnotation newAnnotation = createValAnnotation(ast, valAnnotation, valAnnotation.sourceStart, valAnnotation.sourceEnd);
if (!valIsPresent && valAnnotation != null) {
MarkerAnnotation newAnnotation = createValVarAnnotation(ast, valAnnotation, valAnnotation.sourceStart, valAnnotation.sourceEnd);
try {
Reflection.astConverterRecordNodes.invoke(converter, newAnnotation, valAnnotation);
Reflection.astConverterRecordNodes.invoke(converter, newAnnotation.getTypeName(), valAnnotation.type);
Expand All @@ -175,10 +179,19 @@ public static void addFinalAndValAnnotationToModifierList(Object converter, List
}
modifiers.add(newAnnotation);
}
}

private static boolean couldBeVal(ImportReference[] imports, TypeReference type) {
return PatchVal.couldBe(imports, "lombok.val", type);

if (!varIsPresent && varAnnotation != null) {
MarkerAnnotation newAnnotation = createValVarAnnotation(ast, varAnnotation, varAnnotation.sourceStart, varAnnotation.sourceEnd);
try {
Reflection.astConverterRecordNodes.invoke(converter, newAnnotation, varAnnotation);
Reflection.astConverterRecordNodes.invoke(converter, newAnnotation.getTypeName(), varAnnotation.type);
} catch (IllegalAccessException e) {
throw Lombok.sneakyThrow(e);
} catch (InvocationTargetException e) {
throw Lombok.sneakyThrow(e.getCause());
}
modifiers.add(newAnnotation);
}
}

public static Modifier createModifier(AST ast, ModifierKeyword keyword, int start, int end) {
Expand All @@ -200,7 +213,7 @@ public static Modifier createModifier(AST ast, ModifierKeyword keyword, int star
return modifier;
}

public static MarkerAnnotation createValAnnotation(AST ast, Annotation original, int start, int end) {
public static MarkerAnnotation createValVarAnnotation(AST ast, Annotation original, int start, int end) {
MarkerAnnotation out = null;
try {
out = Reflection.markerAnnotationConstructor.newInstance(ast);
Expand All @@ -212,13 +225,23 @@ public static MarkerAnnotation createValAnnotation(AST ast, Annotation original,
throw Lombok.sneakyThrow(e);
}

char[][] tokens;
if (original.type instanceof SingleTypeReference) {
tokens = new char[1][];
tokens[0] = ((SingleTypeReference) original.type).token;
} else if (original.type instanceof QualifiedTypeReference) {
tokens = ((QualifiedTypeReference) original.type).tokens;
} else {
return null;
}

if (out != null) {
SimpleName valName = ast.newSimpleName("val");
SimpleName valName = ast.newSimpleName(new String(tokens[tokens.length - 1]));
valName.setSourceRange(start, end - start + 1);
if (original.type instanceof SingleTypeReference) {
if (tokens.length == 1) {
out.setTypeName(valName);
setIndex(valName, 1);
} else {
} else if (tokens.length == 2) {
SimpleName lombokName = ast.newSimpleName("lombok");
lombokName.setSourceRange(start, end - start + 1);
setIndex(lombokName, 1);
Expand All @@ -227,6 +250,21 @@ public static MarkerAnnotation createValAnnotation(AST ast, Annotation original,
setIndex(fullName, 1);
fullName.setSourceRange(start, end - start + 1);
out.setTypeName(fullName);
} else {
SimpleName lombokName = ast.newSimpleName("lombok");
lombokName.setSourceRange(start, end - start + 1);
SimpleName experimentalName = ast.newSimpleName("experimental");
lombokName.setSourceRange(start, end - start + 1);
setIndex(lombokName, 1);
setIndex(experimentalName, 2);
setIndex(valName, 3);
QualifiedName lombokExperimentalName = ast.newQualifiedName(lombokName, experimentalName);
lombokExperimentalName.setSourceRange(start, end - start + 1);
setIndex(lombokExperimentalName, 1);
QualifiedName fullName = ast.newQualifiedName(lombokExperimentalName, valName);
setIndex(fullName, 1);
fullName.setSourceRange(start, end - start + 1);
out.setTypeName(fullName);
}
out.setSourceRange(start, end - start + 1);
}
Expand Down

0 comments on commit 7c3724c

Please sign in to comment.