diff options
-rw-r--r-- | doc/changelog.markdown | 1 | ||||
-rw-r--r-- | src/eclipseAgent/lombok/eclipse/agent/PatchVal.java | 16 | ||||
-rw-r--r-- | src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java | 84 |
3 files changed, 70 insertions, 31 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown index a77dbb3d..e6392c53 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -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) diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index c2a362bd..fee104d3 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -210,16 +210,16 @@ public class PatchVal { 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; } @@ -269,7 +269,7 @@ public class PatchVal { } } - 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)); @@ -298,7 +298,7 @@ public class PatchVal { 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; } @@ -326,7 +326,7 @@ public class PatchVal { 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()) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java index d59b6a2e..99447bae 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java @@ -47,9 +47,9 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation; 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 { @@ -103,6 +103,10 @@ public class PatchValEclipse { } } + 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); } @@ -118,17 +122,18 @@ public class PatchValEclipse { } 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; } } @@ -139,10 +144,11 @@ public class PatchValEclipse { 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; } @@ -151,20 +157,18 @@ public class PatchValEclipse { 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); @@ -175,10 +179,19 @@ public class PatchValEclipse { } 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) { @@ -200,7 +213,7 @@ public class PatchValEclipse { 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); @@ -212,13 +225,23 @@ public class PatchValEclipse { 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); @@ -227,6 +250,21 @@ public class PatchValEclipse { 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); } |