From 5dca3b7eea4ba6db0098bc46c24de9cba0548c34 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Fri, 12 Jun 2009 03:42:01 +0200 Subject: Incomplete work on pseudo-resolving something like "@Getter" to: Yes, this is almost certainly intended to be lombok.Getter, so get to work! --- src/lombok/transformations/TypeLibrary.java | 38 +++++++++++ src/lombok/transformations/TypeResolver.java | 95 ++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 src/lombok/transformations/TypeLibrary.java create mode 100644 src/lombok/transformations/TypeResolver.java 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> simpleToQualifiedMap = new HashMap>(); + + 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 existing = simpleToQualifiedMap.get(keyName); + Set set = (existing == null) ? new HashSet() : new HashSet(existing); + set.add(fullyQualifiedTypeName); + simpleToQualifiedMap.put(keyName, Collections.unmodifiableSet(set)); + return this; + } + + public Collection 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 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 makeImportList(CompilationUnitDeclaration declaration) { + Set imports = new HashSet(); + 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 findTypeMatches(ASTNode context, TypeReference type) { + Collection 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 eliminateImpossibleMatches(Collection potentialMatches) { + Set results = new HashSet(); + + for ( String importedType : imports ) { + Collection reduced = library.findCompatible(importedType); + reduced.retainAll(potentialMatches); + results.addAll(reduced); + } + + return results; + } + + private boolean nameConflictInImportList(String simpleName, Collection 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(); + } +} -- cgit