diff options
author | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2019-09-12 23:17:05 +0200 |
---|---|---|
committer | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2019-09-12 23:17:05 +0200 |
commit | 538d2bd690b6288728cc8516bcb3c8093bf2acc6 (patch) | |
tree | 5e84527bd8b248307a39573ae5b0efde37f0e1b4 | |
parent | 5cceda7de97d1c761bb979433a5ae793668d1110 (diff) | |
download | lombok-538d2bd690b6288728cc8516bcb3c8093bf2acc6.tar.gz lombok-538d2bd690b6288728cc8516bcb3c8093bf2acc6.tar.bz2 lombok-538d2bd690b6288728cc8516bcb3c8093bf2acc6.zip |
Refactored how the type resolver deals with aliases; fixes star import issues.
-rw-r--r-- | src/core/lombok/core/LombokInternalAliasing.java | 35 | ||||
-rw-r--r-- | src/core/lombok/core/TypeLibrary.java | 60 | ||||
-rw-r--r-- | src/core/lombok/core/TypeResolver.java | 81 | ||||
-rw-r--r-- | src/core/lombok/eclipse/EclipseImportList.java | 10 | ||||
-rwxr-xr-x | src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java | 4 | ||||
-rw-r--r-- | src/core/lombok/javac/JavacImportList.java | 7 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/JavacSingularsRecipes.java | 4 | ||||
-rw-r--r-- | src/delombok/lombok/delombok/PrettyPrinter.java | 13 |
8 files changed, 118 insertions, 96 deletions
diff --git a/src/core/lombok/core/LombokInternalAliasing.java b/src/core/lombok/core/LombokInternalAliasing.java index 68ced84f..60dea0f2 100644 --- a/src/core/lombok/core/LombokInternalAliasing.java +++ b/src/core/lombok/core/LombokInternalAliasing.java @@ -28,8 +28,6 @@ import java.util.HashMap; import java.util.Map; public class LombokInternalAliasing { - /** Maps a package name to a space separated list of packages. If the key package is star-imported, assume all packages in the 'value' part of the MapEntry are too. */ - public static final Map<String, Collection<String>> IMPLIED_EXTRA_STAR_IMPORTS; public static final Map<String, String> ALIASES; public static final Map<String, Collection<String>> REVERSE_ALIASES; @@ -43,36 +41,31 @@ public class LombokInternalAliasing { } static { - Map<String, Collection<String>> m1 = new HashMap<String, Collection<String>>(); - m1.put("lombok.experimental", Collections.singleton("lombok")); - m1.put("lombok", Collections.singleton("lombok.experimental")); - IMPLIED_EXTRA_STAR_IMPORTS = Collections.unmodifiableMap(m1); + Map<String, String> m1 = new HashMap<String, String>(); + m1.put("lombok.experimental.Value", "lombok.Value"); + m1.put("lombok.experimental.Builder", "lombok.Builder"); + m1.put("lombok.experimental.var", "lombok.var"); + m1.put("lombok.Delegate", "lombok.experimental.Delegate"); + m1.put("lombok.experimental.Wither", "lombok.With"); + ALIASES = Collections.unmodifiableMap(m1); - Map<String, String> m2 = new HashMap<String, String>(); - m2.put("lombok.experimental.Value", "lombok.Value"); - m2.put("lombok.experimental.Builder", "lombok.Builder"); - m2.put("lombok.experimental.var", "lombok.var"); - m2.put("lombok.Delegate", "lombok.experimental.Delegate"); - m2.put("lombok.experimental.Wither", "lombok.With"); - ALIASES = Collections.unmodifiableMap(m2); - - Map<String, Collection<String>> m3 = new HashMap<String, Collection<String>>(); - for (Map.Entry<String, String> e : m2.entrySet()) { - Collection<String> c = m3.get(e.getValue()); + Map<String, Collection<String>> m2 = new HashMap<String, Collection<String>>(); + for (Map.Entry<String, String> e : m1.entrySet()) { + Collection<String> c = m2.get(e.getValue()); if (c == null) { - m3.put(e.getValue(), Collections.singleton(e.getKey())); + m2.put(e.getValue(), Collections.singleton(e.getKey())); } else if (c.size() == 1) { Collection<String> newC = new ArrayList<String>(2); newC.addAll(c); - m3.put(e.getValue(), c); + m2.put(e.getValue(), c); } else { c.add(e.getKey()); } } - for (Map.Entry<String, Collection<String>> e : m3.entrySet()) { + for (Map.Entry<String, Collection<String>> e : m2.entrySet()) { Collection<String> c = e.getValue(); if (c.size() > 1) e.setValue(Collections.unmodifiableList((ArrayList<String>) c)); } - REVERSE_ALIASES = Collections.unmodifiableMap(m3); + REVERSE_ALIASES = Collections.unmodifiableMap(m2); } } diff --git a/src/core/lombok/core/TypeLibrary.java b/src/core/lombok/core/TypeLibrary.java index 113ce67e..8b9fa4b0 100644 --- a/src/core/lombok/core/TypeLibrary.java +++ b/src/core/lombok/core/TypeLibrary.java @@ -21,8 +21,11 @@ */ package lombok.core; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -36,18 +39,18 @@ import java.util.Map; * <ul><li>foo.Spork</li><li>Spork</li><li>foo.*</li></ul> */ public class TypeLibrary { - private final Map<String, String> unqualifiedToQualifiedMap; + private final Map<String, Object> unqualifiedToQualifiedMap; // maps to usually a string, but could be a string array in aliasing cases. private final String unqualified, qualified; private boolean locked; public TypeLibrary() { - unqualifiedToQualifiedMap = new HashMap<String, String>(); + unqualifiedToQualifiedMap = new HashMap<String, Object>(); unqualified = null; qualified = null; } public TypeLibrary(TypeLibrary parent) { - unqualifiedToQualifiedMap = new HashMap<String, String>(); + unqualifiedToQualifiedMap = new HashMap<String, Object>(); unqualified = null; qualified = null; } @@ -58,7 +61,7 @@ public class TypeLibrary { private TypeLibrary(String fqnSingleton) { if (fqnSingleton.indexOf("$") != -1) { - unqualifiedToQualifiedMap = new HashMap<String, String>(); + unqualifiedToQualifiedMap = new HashMap<String, Object>(); unqualified = null; qualified = null; addType(fqnSingleton); @@ -93,6 +96,9 @@ public class TypeLibrary { * @param fullyQualifiedTypeName the FQN type name, such as 'java.lang.String'. */ public void addType(String fullyQualifiedTypeName) { + Collection<String> oldNames = LombokInternalAliasing.REVERSE_ALIASES.get(fullyQualifiedTypeName); + if (oldNames != null) for (String oldName : oldNames) addType(oldName); + String dotBased = fullyQualifiedTypeName.replace("$", "."); if (locked) throw new IllegalStateException("locked"); @@ -102,22 +108,16 @@ public class TypeLibrary { String unqualified = fullyQualifiedTypeName.substring(idx + 1); if (unqualifiedToQualifiedMap == null) throw new IllegalStateException("SingleType library"); - unqualifiedToQualifiedMap.put(unqualified.replace("$", "."), dotBased); - unqualifiedToQualifiedMap.put(unqualified, dotBased); - unqualifiedToQualifiedMap.put(fullyQualifiedTypeName, dotBased); - unqualifiedToQualifiedMap.put(dotBased, dotBased); - Collection<String> oldNames = LombokInternalAliasing.REVERSE_ALIASES.get(fullyQualifiedTypeName); - if (oldNames != null) for (String oldName : oldNames) { - unqualifiedToQualifiedMap.put(oldName, dotBased); - int li = oldName.lastIndexOf('.'); - if (li != -1) unqualifiedToQualifiedMap.put(oldName.substring(li + 1), dotBased); - } + put(unqualified.replace("$", "."), dotBased); + put(unqualified, dotBased); + put(fullyQualifiedTypeName, dotBased); + put(dotBased, 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); + put(unq.replace("$", "."), dotBased); + put(unq, dotBased); idx2 = fullyQualifiedTypeName.indexOf('$', idx2 + 1); } } @@ -126,13 +126,33 @@ public class TypeLibrary { * Translates an unqualified name such as 'String' to 'java.lang.String', _if_ you added 'java.lang.String' to the library via the {@code addType} method. * Also returns the input if it is equal to a fully qualified name added to this type library. * - * Returns null if it does not match any type in this type library. + * Returns an empty collection if it does not match any type in this type library. */ - public String toQualified(String typeReference) { + public List<String> toQualifieds(String typeReference) { if (unqualifiedToQualifiedMap == null) { - if (typeReference.equals(unqualified) || typeReference.equals(qualified)) return qualified; + if (typeReference.equals(unqualified) || typeReference.equals(qualified)) return Collections.singletonList(qualified); return null; } - return unqualifiedToQualifiedMap.get(typeReference); + + Object v = unqualifiedToQualifiedMap.get(typeReference); + if (v == null) return Collections.emptyList(); + if (v instanceof String) return Collections.singletonList((String) v); + return Arrays.asList((String[]) v); + } + + private void put(String k, String v) { + Object old = unqualifiedToQualifiedMap.put(k, v); + if (old == null) return; + String[] nv; + if (old instanceof String) { + if (old.equals(v)) return; + nv = new String[] {(String) old, v}; + } else { + String[] s = (String[]) old; + nv = new String[s.length + 1]; + System.arraycopy(s, 0, nv, 0, s.length); + nv[s.length] = v; + } + unqualifiedToQualifiedMap.put(k, nv); } } diff --git a/src/core/lombok/core/TypeResolver.java b/src/core/lombok/core/TypeResolver.java index 06c91138..3e126123 100644 --- a/src/core/lombok/core/TypeResolver.java +++ b/src/core/lombok/core/TypeResolver.java @@ -21,6 +21,8 @@ */ package lombok.core; +import java.util.List; + import lombok.core.AST.Kind; /** @@ -44,13 +46,12 @@ public class TypeResolver { } public String typeRefToFullyQualifiedName(LombokNode<?, ?, ?> context, TypeLibrary library, String typeRef) { - typeRef = LombokInternalAliasing.processAliases(typeRef); // When asking if 'Foo' could possibly be referring to 'bar.Baz', the answer is obviously no. - String qualified = library.toQualified(typeRef); - if (qualified == null) return null; + List<String> qualifieds = library.toQualifieds(typeRef); + if (qualifieds.isEmpty()) return null; // When asking if 'lombok.Getter' could possibly be referring to 'lombok.Getter', the answer is obviously yes. - if (typeRef.equals(qualified)) return typeRef; + if (qualifieds.contains(typeRef)) return LombokInternalAliasing.processAliases(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. int firstDot = typeRef.indexOf('.'); @@ -58,50 +59,58 @@ public class TypeResolver { String firstTypeRef = typeRef.substring(0, firstDot); String fromExplicitImport = imports.getFullyQualifiedNameForSimpleName(firstTypeRef); if (fromExplicitImport != null) { + String fqn = fromExplicitImport + typeRef.substring(firstDot); + if (qualifieds.contains(fqn)) return LombokInternalAliasing.processAliases(fqn); // ... and if 'import foobar.Getter;' is in the source file, the answer is no. - return (fromExplicitImport + typeRef.substring(firstDot)).equals(qualified) ? qualified : null; + return 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. - String pkgName = qualified.substring(0, qualified.length() - typeRef.length() - 1); - if (!imports.hasStarImport(pkgName)) return null; - - // Now the hard part: Given that there is a star import, 'Getter' most likely refers to 'lombok.Getter', but type shadowing may occur in which case it doesn't. - LombokNode<?, ?, ?> n = context; - - mainLoop: - while (n != null) { - 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; - } + for (String qualified : qualifieds) { + String pkgName = qualified.substring(0, qualified.length() - typeRef.length() - 1); + if (!imports.hasStarImport(pkgName)) continue; - if (n.getKind() == Kind.STATEMENT || n.getKind() == Kind.LOCAL) { - LombokNode<?, ?, ?> newN = n.directUp(); - if (newN == null) break mainLoop; + // Now the hard part: Given that there is a star import, 'Getter' most likely refers to 'lombok.Getter', but type shadowing may occur in which case it doesn't. + LombokNode<?, ?, ?> n = context; + + mainLoop: + while (n != null) { + 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; + } - if (newN.getKind() == Kind.STATEMENT || newN.getKind() == Kind.INITIALIZER || newN.getKind() == Kind.METHOD) { - 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 && firstTypeRef.equals(child.getName())) return null; - if (child == n) break; + if (n.getKind() == Kind.STATEMENT || n.getKind() == Kind.LOCAL) { + LombokNode<?, ?, ?> newN = n.directUp(); + if (newN == null) break mainLoop; + + if (newN.getKind() == Kind.STATEMENT || newN.getKind() == Kind.INITIALIZER || newN.getKind() == Kind.METHOD) { + 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 && firstTypeRef.equals(child.getName())) return null; + if (child == n) break; + } } + n = newN; + continue mainLoop; } - n = newN; - continue mainLoop; - } - - 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 && firstTypeRef.equals(child.getName())) return null; + + 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 && firstTypeRef.equals(child.getName())) return null; + } } + + n = n.directUp(); } - n = n.directUp(); + // If no shadowing thing has been found, the star import 'wins', so, return that. + return LombokInternalAliasing.processAliases(qualified); } - return qualified; + // No star import matches either. + return null; } } diff --git a/src/core/lombok/eclipse/EclipseImportList.java b/src/core/lombok/eclipse/EclipseImportList.java index 47167ec6..6d60f5aa 100644 --- a/src/core/lombok/eclipse/EclipseImportList.java +++ b/src/core/lombok/eclipse/EclipseImportList.java @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Map; import lombok.core.ImportList; import lombok.core.LombokInternalAliasing; @@ -65,19 +64,10 @@ public class EclipseImportList implements ImportList { if (isEqual(packageName, pkg)) return true; if ("java.lang".equals(packageName)) return true; - if (pkg != null && pkg.tokens != null && pkg.tokens.length == 0) { - for (Map.Entry<String, Collection<String>> e : LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.entrySet()) { - if (isEqual(e.getKey(), pkg) && e.getValue().contains(packageName)) return true; - } - } - if (imports != null) for (ImportReference imp : imports) { if ((imp.bits & ASTNode.OnDemand) == 0) continue; if (imp.isStatic()) continue; if (isEqual(packageName, imp)) return true; - for (Map.Entry<String, Collection<String>> e : LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.entrySet()) { - if (isEqual(e.getKey(), imp) && e.getValue().contains(packageName)) return true; - } } return false; diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index da0bf471..483431cc 100755 --- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java +++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java @@ -109,7 +109,9 @@ public class EclipseSingularsRecipes { } public String toQualified(String typeReference) { - return singularizableTypes.toQualified(typeReference); + List<String> q = singularizableTypes.toQualifieds(typeReference); + if (q.isEmpty()) return null; + return q.get(0); } public EclipseSingularizer getSingularizer(String fqn) { diff --git a/src/core/lombok/javac/JavacImportList.java b/src/core/lombok/javac/JavacImportList.java index 468d8c7b..8de61afc 100644 --- a/src/core/lombok/javac/JavacImportList.java +++ b/src/core/lombok/javac/JavacImportList.java @@ -60,11 +60,6 @@ public class JavacImportList implements ImportList { if (pkgStr != null && pkgStr.equals(packageName)) return true; if ("java.lang".equals(packageName)) return true; - if (pkgStr != null) { - Collection<String> extra = LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.get(pkgStr); - if (extra != null && extra.contains(packageName)) return true; - } - for (JCTree def : defs) { if (!(def instanceof JCImport)) continue; if (((JCImport) def).staticImport) continue; @@ -74,8 +69,6 @@ public class JavacImportList implements ImportList { if (!"*".equals(simpleName)) continue; String starImport = ((JCFieldAccess) qual).selected.toString(); if (packageName.equals(starImport)) return true; - Collection<String> extra = LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.get(starImport); - if (extra != null && extra.contains(packageName)) return true; } return false; diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index 341d44df..fa384df3 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -101,7 +101,9 @@ public class JavacSingularsRecipes { } public String toQualified(String typeReference) { - return singularizableTypes.toQualified(typeReference); + java.util.List<String> q = singularizableTypes.toQualifieds(typeReference); + if (q.isEmpty()) return null; + return q.get(0); } public JavacSingularizer getSingularizer(String fqn, JavacNode node) { diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index 1532319f..55210fbb 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -488,6 +488,19 @@ public class PrettyPrinter extends JCTree.Visitor { } @Override public void visitImport(JCImport tree) { + if (tree.qualid instanceof JCFieldAccess) { + JCFieldAccess fa = ((JCFieldAccess) tree.qualid); + if (fa.name.length() == 1 && fa.name.contentEquals("*")) { + if (fa.selected instanceof JCFieldAccess) { + JCFieldAccess lombokExperimental = (JCFieldAccess) fa.selected; + if (lombokExperimental.name.contentEquals("experimental") && lombokExperimental.selected instanceof JCIdent && ((JCIdent) lombokExperimental.selected).name.contentEquals("lombok")) { + // do not ever print lombok.experimental.*. + return; + } + } + } + } + aPrint("import "); if (tree.staticImport) print("static "); print(tree.qualid); |