mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-11 12:19:00 +00:00
Refactored how the type resolver deals with aliases; fixes star import issues.
This commit is contained in:
8 files changed
+118
-96
No files matched your search
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 (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;
|
||||
}
|
||||
|
||||
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 (child == n) break;
|
||||
}
|
||||
}
|
||||
n = newN;
|
||||
continue mainLoop;
|
||||
|
||||
n = n.directUp();
|
||||
}
|
||||
|
||||
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();
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user