aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lombok/transformations/TypeLibrary.java38
-rw-r--r--src/lombok/transformations/TypeResolver.java95
2 files changed, 133 insertions, 0 deletions
diff --git a/src/lombok/transformations/TypeLibrary.java b/src/lombok/transformations/TypeLibrary.java
new file mode 100644
index 00000000..00ae64b0
--- /dev/null
+++ b/src/lombok/transformations/TypeLibrary.java
@@ -0,0 +1,38 @@
+package lombok.transformations;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class TypeLibrary {
+ private final Map<String, Set<String>> simpleToQualifiedMap = new HashMap<String, Set<String>>();
+
+ public void addType(String fullyQualifiedTypeName) {
+ 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!)");
+
+ final String simpleName = fullyQualifiedTypeName.substring(idx +1);
+ final String packageName = fullyQualifiedTypeName.substring(0, idx);
+
+ if ( simpleToQualifiedMap.put(fullyQualifiedTypeName, Collections.singleton(fullyQualifiedTypeName)) != null ) return;
+
+ addToMap(simpleName, fullyQualifiedTypeName);
+ addToMap(packageName + ".*", fullyQualifiedTypeName);
+ }
+
+ private TypeLibrary addToMap(String keyName, String fullyQualifiedTypeName) {
+ Set<String> existing = simpleToQualifiedMap.get(keyName);
+ Set<String> set = (existing == null) ? new HashSet<String>() : new HashSet<String>(existing);
+ set.add(fullyQualifiedTypeName);
+ simpleToQualifiedMap.put(keyName, Collections.unmodifiableSet(set));
+ return this;
+ }
+
+ public Collection<String> findCompatible(String typeReference) {
+ return simpleToQualifiedMap.get(typeReference);
+ }
+}
diff --git a/src/lombok/transformations/TypeResolver.java b/src/lombok/transformations/TypeResolver.java
new file mode 100644
index 00000000..2a012f57
--- /dev/null
+++ b/src/lombok/transformations/TypeResolver.java
@@ -0,0 +1,95 @@
+package lombok.transformations;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import lombok.eclipse.EclipseAST;
+
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
+
+public class TypeResolver {
+ private final TypeLibrary library;
+ private final EclipseAST ast;
+ private Collection<String> imports;
+
+
+ public TypeResolver(TypeLibrary library, Parser parser, EclipseAST ast) {
+ this.library = library;
+ this.ast = ast;
+ this.imports = makeImportList((CompilationUnitDeclaration) ast.top().getEclipseNode());
+ }
+
+ private static Collection<String> makeImportList(CompilationUnitDeclaration declaration) {
+ Set<String> imports = new HashSet<String>();
+ if ( declaration.currentPackage != null ) imports.add(toQualifiedName(declaration.currentPackage.getImportName()) + ".*");
+ if ( declaration.imports != null ) for ( ImportReference importStatement : declaration.imports ) {
+ imports.add(toQualifiedName(importStatement.getImportName()));
+ }
+ return imports;
+ }
+
+ public Collection<String> findTypeMatches(ASTNode context, TypeReference type) {
+ Collection<String> potentialMatches = library.findCompatible(toQualifiedName(type.getTypeName()));
+ if ( potentialMatches.isEmpty() ) return Collections.emptyList();
+
+ if ( type.getTypeName().length > 1 ) return potentialMatches;
+
+ String simpleName = new String(type.getTypeName()[0]);
+
+ //If there's an import statement that explicitly imports a 'Getter' that isn't any of our potentials, return no matches.
+ if ( nameConflictInImportList(simpleName, potentialMatches) ) return Collections.emptyList();
+
+ //Check if any of our potentials is even imported in the first place. If not: no matches.
+ potentialMatches = eliminateImpossibleMatches(potentialMatches);
+ if ( potentialMatches.isEmpty() ) return Collections.emptyList();
+
+ //Find a lexically accessible type of the same simple name in the same Compilation Unit. If it exists: no matches.
+
+
+ // The potential matches we found by comparing the import statements is our matching set. Return it.
+ return potentialMatches;
+ }
+
+ private Collection<String> eliminateImpossibleMatches(Collection<String> potentialMatches) {
+ Set<String> results = new HashSet<String>();
+
+ for ( String importedType : imports ) {
+ Collection<String> reduced = library.findCompatible(importedType);
+ reduced.retainAll(potentialMatches);
+ results.addAll(reduced);
+ }
+
+ return results;
+ }
+
+ private boolean nameConflictInImportList(String simpleName, Collection<String> potentialMatches) {
+ for ( String importedType : imports ) {
+ if ( !toSimpleName(importedType).equals(simpleName) ) continue;
+ if ( potentialMatches.contains(importedType) ) continue;
+ return true;
+ }
+
+ return false;
+ }
+
+ private static String toSimpleName(String typeName) {
+ int idx = typeName.lastIndexOf('.');
+ return idx == -1 ? typeName : typeName.substring(idx+1);
+ }
+
+ private static String toQualifiedName(char[][] typeName) {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for ( char[] c : typeName ) {
+ sb.append(first ? "" : ".").append(c);
+ first = false;
+ }
+ return sb.toString();
+ }
+}