From 389034c937d9358baf08e0877a2d0c119b67da59 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 16 Jul 2015 04:33:59 +0200 Subject: TypeLibrary now compatible with inner types. --- src/core/lombok/Builder.java | 30 +++++++++++++++- src/core/lombok/core/TypeLibrary.java | 40 ++++++++++++++++------ src/core/lombok/core/TypeResolver.java | 14 ++++---- .../eclipse/handlers/EclipseHandlerUtil.java | 2 +- 4 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java index 4556bef0..5bb978be 100644 --- a/src/core/lombok/Builder.java +++ b/src/core/lombok/Builder.java @@ -113,9 +113,37 @@ public @interface Builder { /** Name of the instance method in the builder class that creates an instance of your {@code @Builder}-annotated class. */ String buildMethodName() default "build"; - /** Name of the builder class. + /** + * Name of the builder class. + * * Default for {@code @Builder} on types and constructors: {@code (TypeName)Builder}. + *

* Default for {@code @Builder} on static methods: {@code (ReturnTypeName)Builder}. */ String builderClassName() default ""; + + /** + * If true, generate an instance method to obtain a builder that is initialized with the values of this instance. + * Legal only if {@code @Builder} is used on a constructor, on the type itself, or on a static method that returns itself. + */ + boolean toBuilder() default false; + + /** + * Put on a field (in case of {@code @Builder} on a type) or a parameter (for {@code @Builder} on a constructor or static method) to + * indicate how lombok should obtain a value for this given an instance; this is only relevant if {@code toBuilder} is true. + * + * Note that one of {@code field} or {@code method} should be set, or an error is generated. + *

+ * The default behaviour is to obtain a value by referencing the name of the parameter as a field on 'this'. + */ + public @interface ObtainVia { + /** Tells lombok to obtain a value with the expression {@code this.value}. */ + String field() default ""; + + /** Tells lombok to obtain a value with the expression {@code this.method()}. */ + String method() default ""; + + /** Tells lombok to obtain a value with the expression {@code SelfType.method(this)}; requires {@code method} to be set. */ + boolean isStatic() default false; + } } diff --git a/src/core/lombok/core/TypeLibrary.java b/src/core/lombok/core/TypeLibrary.java index dc557c47..d4f5f2b0 100644 --- a/src/core/lombok/core/TypeLibrary.java +++ b/src/core/lombok/core/TypeLibrary.java @@ -50,13 +50,20 @@ public class TypeLibrary { } private TypeLibrary(String fqnSingleton) { - unqualifiedToQualifiedMap = null; - qualified = fqnSingleton; - int idx = fqnSingleton.lastIndexOf('.'); - if (idx == -1) { - unqualified = fqnSingleton; + if (fqnSingleton.indexOf("$") != -1) { + unqualifiedToQualifiedMap = new HashMap(); + unqualified = null; + qualified = null; + addType(fqnSingleton); } else { - unqualified = fqnSingleton.substring(idx + 1); + unqualifiedToQualifiedMap = null; + qualified = fqnSingleton; + int idx = fqnSingleton.lastIndexOf('.'); + if (idx == -1) { + unqualified = fqnSingleton; + } else { + unqualified = fqnSingleton.substring(idx + 1); + } } locked = true; } @@ -71,18 +78,29 @@ public class TypeLibrary { * @param fullyQualifiedTypeName the FQN type name, such as 'java.lang.String'. */ public void addType(String fullyQualifiedTypeName) { + String dotBased = fullyQualifiedTypeName.replace("$", "."); + if (locked) throw new IllegalStateException("locked"); - fullyQualifiedTypeName = fullyQualifiedTypeName.replace("$", "."); int idx = fullyQualifiedTypeName.lastIndexOf('.'); if (idx == -1) throw new IllegalArgumentException( "Only fully qualified types are allowed (and stuff in the default package is not palatable to us either!)"); - String unqualified = fullyQualifiedTypeName.substring(idx + 1); + String unqualified = dotBased.substring(idx + 1); if (unqualifiedToQualifiedMap == null) throw new IllegalStateException("SingleType library"); - unqualifiedToQualifiedMap.put(unqualified, fullyQualifiedTypeName); - unqualifiedToQualifiedMap.put(fullyQualifiedTypeName, fullyQualifiedTypeName); + unqualifiedToQualifiedMap.put(unqualified.replace("$", "."), dotBased); + unqualifiedToQualifiedMap.put(unqualified, dotBased); + unqualifiedToQualifiedMap.put(fullyQualifiedTypeName, dotBased); + unqualifiedToQualifiedMap.put(dotBased, dotBased); for (Map.Entry e : LombokInternalAliasing.ALIASES.entrySet()) { - if (fullyQualifiedTypeName.equals(e.getValue())) unqualifiedToQualifiedMap.put(e.getKey(), fullyQualifiedTypeName); + if (fullyQualifiedTypeName.equals(e.getValue())) unqualifiedToQualifiedMap.put(e.getKey(), dotBased); + } + + int idx2 = fullyQualifiedTypeName.indexOf('$', idx + 1); + while (idx2 != -1) { + String unq = fullyQualifiedTypeName.substring(idx2 + 1); + unqualifiedToQualifiedMap.put(unq.replace("$", "."), dotBased); + unqualifiedToQualifiedMap.put(unq, dotBased); + idx2 = fullyQualifiedTypeName.indexOf('$', idx2 + 1); } } diff --git a/src/core/lombok/core/TypeResolver.java b/src/core/lombok/core/TypeResolver.java index 287a085f..a05394a7 100644 --- a/src/core/lombok/core/TypeResolver.java +++ b/src/core/lombok/core/TypeResolver.java @@ -53,10 +53,13 @@ public class TypeResolver { if (typeRef.equals(qualified)) return typeRef; // When asking if 'Getter' could possibly be referring to 'lombok.Getter' if 'import lombok.Getter;' is in the source file, the answer is yes. - String fromExplicitImport = imports.getFullyQualifiedNameForSimpleName(typeRef); + int firstDot = typeRef.indexOf('.'); + if (firstDot == -1) firstDot = typeRef.length(); + String firstTypeRef = typeRef.substring(0, firstDot); + String fromExplicitImport = imports.getFullyQualifiedNameForSimpleName(firstTypeRef); if (fromExplicitImport != null) { // ... and if 'import foobar.Getter;' is in the source file, the answer is no. - return fromExplicitImport.equals(qualified) ? qualified : null; + return (fromExplicitImport + typeRef.substring(firstDot)).equals(qualified) ? qualified : null; } // When asking if 'Getter' could possibly be referring to 'lombok.Getter' and 'import lombok.*; / package lombok;' isn't in the source file. the answer is no. @@ -68,7 +71,7 @@ public class TypeResolver { mainLoop: while (n != null) { - if (n.getKind() == Kind.TYPE && typeRef.equals(n.getName())) { + if (n.getKind() == Kind.TYPE && firstTypeRef.equals(n.getName())) { // Our own class or one of our outer classes is named 'typeRef' so that's what 'typeRef' is referring to, not one of our type library classes. return null; } @@ -81,7 +84,7 @@ public class TypeResolver { for (LombokNode child : newN.down()) { // We found a method local with the same name above our code. That's the one 'typeRef' is referring to, not // anything in the type library we're trying to find, so, no matches. - if (child.getKind() == Kind.TYPE && typeRef.equals(child.getName())) return null; + if (child.getKind() == Kind.TYPE && firstTypeRef.equals(child.getName())) return null; if (child == n) break; } } @@ -92,14 +95,13 @@ public class TypeResolver { if (n.getKind() == Kind.TYPE || n.getKind() == Kind.COMPILATION_UNIT) { for (LombokNode child : n.down()) { // Inner class that's visible to us has 'typeRef' as name, so that's the one being referred to, not one of our type library classes. - if (child.getKind() == Kind.TYPE && typeRef.equals(child.getName())) return null; + if (child.getKind() == Kind.TYPE && firstTypeRef.equals(child.getName())) return null; } } n = n.directUp(); } - return qualified; } } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 836a51c6..0ff5a7f6 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -450,7 +450,7 @@ public class EclipseHandlerUtil { */ public static boolean annotationTypeMatches(Class type, EclipseNode node) { if (node.getKind() != Kind.ANNOTATION) return false; - return typeMatches(type, node, ((Annotation)node.get()).type); + return typeMatches(type, node, ((Annotation) node.get()).type); } public static TypeReference cloneSelfType(EclipseNode context) { -- cgit