diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java @ 16908:d3f282a9e287

Truffle-DSL: optimize import generation.
author Christian Humer <christian.humer@gmail.com>
date Sat, 23 Aug 2014 19:31:13 +0200
parents 85c6e6fc3961
children 93e061157811
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java	Sat Aug 23 19:31:09 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java	Sat Aug 23 19:31:13 2014 +0200
@@ -35,14 +35,8 @@
 
 public final class OrganizedImports {
 
-    private final Set<TypeMirror> staticImportUsage = new HashSet<>();
-
-    private final Map<String, TypeMirror> simpleNamesUsed = new HashMap<>();
-
-    private final Set<String> declaredStaticMethods = new HashSet<>();
-    private final Set<String> declaredStaticFields = new HashSet<>();
-    private final Set<String> ambiguousStaticMethods = new HashSet<>();
-    private final Set<String> ambiguousStaticFields = new HashSet<>();
+    private final Map<String, String> classImportUsage = new HashMap<>();
+    private final Map<String, String> staticImportUsage = new HashMap<>();
     private final Map<String, Set<String>> autoImportCache = new HashMap<>();
 
     private final CodeTypeElement topLevelClass;
@@ -61,22 +55,6 @@
         ImportTypeReferenceVisitor reference = new ImportTypeReferenceVisitor();
         topLevelClass.accept(reference, null);
 
-        processStaticImports(topLevelClass);
-        List<TypeElement> types = ElementUtils.getSuperTypes(topLevelClass);
-        for (TypeElement typeElement : types) {
-            processStaticImports(typeElement);
-        }
-
-        for (TypeMirror type : staticImportUsage) {
-            TypeElement element = fromTypeMirror(type);
-            if (element != null) {
-                // already processed by supertype
-                if (types.contains(element)) {
-                    continue;
-                }
-                processStaticImports(element);
-            }
-        }
     }
 
     public String createTypeReference(Element enclosedElement, TypeMirror type) {
@@ -105,15 +83,16 @@
     }
 
     public String createStaticFieldReference(Element enclosedElement, TypeMirror type, String fieldName) {
-        return createStaticReference(enclosedElement, type, fieldName, ambiguousStaticFields);
+        return createStaticReference(enclosedElement, type, fieldName);
     }
 
     public String createStaticMethodReference(Element enclosedElement, TypeMirror type, String methodName) {
-        return createStaticReference(enclosedElement, type, methodName, ambiguousStaticMethods);
+        return createStaticReference(enclosedElement, type, methodName);
     }
 
-    private String createStaticReference(Element enclosedElement, TypeMirror type, String name, Set<String> ambiguousSymbols) {
-        if (ambiguousSymbols.contains(name)) {
+    private String createStaticReference(Element enclosedElement, TypeMirror type, String name) {
+        String qualifiedName = staticImportUsage.get(name);
+        if (qualifiedName == null) {
             // ambiguous import
             return createTypeReference(enclosedElement, type) + "." + name;
         } else {
@@ -133,18 +112,13 @@
     }
 
     private String createDeclaredTypeName(Element enclosedElement, DeclaredType type) {
-        String name;
-        name = ElementUtils.fixECJBinaryNameIssue(type.asElement().getSimpleName().toString());
+        String name = ElementUtils.fixECJBinaryNameIssue(type.asElement().getSimpleName().toString());
+        if (classImportUsage.containsKey(name)) {
+            String qualifiedImport = classImportUsage.get(name);
+            String qualifiedName = ElementUtils.getEnclosedQualifiedName(type);
 
-        if (needsImport(enclosedElement, type)) {
-            TypeMirror usedByType = simpleNamesUsed.get(name);
-            if (usedByType == null) {
-                simpleNamesUsed.put(name, type);
-                usedByType = type;
-            }
-
-            if (!typeEquals(type, usedByType)) {
-                name = getQualifiedName(type);
+            if (!qualifiedName.equals(qualifiedImport)) {
+                name = qualifiedName;
             }
         }
 
@@ -169,61 +143,12 @@
     public Set<CodeImport> generateImports() {
         Set<CodeImport> imports = new HashSet<>();
 
-        imports.addAll(generateImports(simpleNamesUsed.values()));
+        imports.addAll(generateImports(classImportUsage));
         imports.addAll(generateStaticImports(staticImportUsage));
 
         return imports;
     }
 
-    boolean processStaticImports(TypeElement element) {
-        Set<String> importedMethods = new HashSet<>();
-        List<ExecutableElement> methods = ElementFilter.methodsIn(element.getEnclosedElements());
-        for (ExecutableElement method : methods) {
-            if (method.getModifiers().contains(Modifier.STATIC)) {
-                importedMethods.add(method.getSimpleName().toString());
-            }
-        }
-
-        boolean allMethodsAmbiguous = processStaticImportElements(importedMethods, this.ambiguousStaticMethods, this.declaredStaticMethods);
-
-        Set<String> importedFields = new HashSet<>();
-        List<VariableElement> fields = ElementFilter.fieldsIn(element.getEnclosedElements());
-        for (VariableElement field : fields) {
-            if (field.getModifiers().contains(Modifier.STATIC)) {
-                importedFields.add(field.getSimpleName().toString());
-            }
-        }
-
-        boolean allFieldsAmbiguous = processStaticImportElements(importedFields, this.ambiguousStaticFields, this.declaredStaticFields);
-
-        return allMethodsAmbiguous && allFieldsAmbiguous;
-    }
-
-    private static boolean processStaticImportElements(Set<String> newElements, Set<String> ambiguousElements, Set<String> declaredElements) {
-        boolean allAmbiguous = false;
-        if (declaredElements.containsAll(newElements)) {
-            // all types already declared -> we can remove the import completely -> they will all
-            // get ambiguous
-            allAmbiguous = true;
-        }
-        Set<String> newAmbiguous = new HashSet<>();
-        Set<String> newDeclared = new HashSet<>();
-
-        for (String newElement : newElements) {
-            if (declaredElements.contains(newElement)) {
-                newAmbiguous.add(newElement);
-            } else if (ambiguousElements.contains(newElement)) {
-                // nothing to do
-            } else {
-                newDeclared.add(newElement);
-            }
-        }
-
-        ambiguousElements.addAll(newAmbiguous);
-        declaredElements.addAll(newDeclared);
-        return allAmbiguous;
-    }
-
     private boolean needsImport(Element enclosed, TypeMirror importType) {
         String importPackagName = getPackageName(importType);
         TypeElement enclosedElement = findNearestEnclosingType(enclosed);
@@ -235,18 +160,18 @@
             return false; // same package name -> no import
         }
 
-        Set<String> autoImportedTypes = autoImportCache.get(enclosedElement.toString());
+        String enclosedElementId = ElementUtils.getUniqueIdentifier(enclosedElement.asType());
+        Set<String> autoImportedTypes = autoImportCache.get(enclosedElementId);
         if (autoImportedTypes == null) {
             List<Element> elements = ElementUtils.getElementHierarchy(enclosedElement);
             autoImportedTypes = new HashSet<>();
             for (Element element : elements) {
-
                 if (element.getKind().isClass()) {
                     collectSuperTypeImports((TypeElement) element, autoImportedTypes);
                     collectInnerTypeImports((TypeElement) element, autoImportedTypes);
                 }
             }
-            autoImportCache.put(enclosedElement.toString(), autoImportedTypes);
+            autoImportCache.put(enclosedElementId, autoImportedTypes);
         }
 
         String qualifiedName = getQualifiedName(importType);
@@ -257,10 +182,13 @@
         return true;
     }
 
-    private static Set<CodeImport> generateImports(Collection<TypeMirror> toGenerate) {
+    private static Set<CodeImport> generateImports(Map<String, String> symbols) {
         TreeSet<CodeImport> importObjects = new TreeSet<>();
-        for (TypeMirror importType : toGenerate) {
-            importObjects.add(new CodeImport(importType, getQualifiedName(importType), false));
+        for (String symbol : symbols.keySet()) {
+            String packageName = symbols.get(symbol);
+            if (packageName != null) {
+                importObjects.add(new CodeImport(packageName, symbol, false));
+            }
         }
         return importObjects;
     }
@@ -282,7 +210,7 @@
         }
     }
 
-    private Set<CodeImport> generateStaticImports(Set<TypeMirror> toGenerate) {
+    private Set<CodeImport> generateStaticImports(Map<String, String> toGenerate) {
         Set<String> autoImportedStaticTypes = new HashSet<>();
 
         // if type is declared inside a super type of this class -> no import
@@ -290,17 +218,18 @@
         autoImportedStaticTypes.addAll(getQualifiedSuperTypeNames(topLevelClass));
 
         TreeSet<CodeImport> importObjects = new TreeSet<>();
-        for (TypeMirror importType : toGenerate) {
-            if (getPackageName(importType) == null) {
-                continue; // no package name -> no import
+        for (String symbol : toGenerate.keySet()) {
+            String qualifiedName = toGenerate.get(symbol);
+            if (qualifiedName == null) {
+                // ambiguous
+                continue;
             }
-
-            String qualifiedName = getQualifiedName(importType);
+            // not not import
             if (autoImportedStaticTypes.contains(qualifiedName)) {
                 continue;
             }
 
-            importObjects.add(new CodeImport(importType, qualifiedName + ".*", true));
+            importObjects.add(new CodeImport(qualifiedName, symbol, true));
         }
 
         return importObjects;
@@ -309,15 +238,15 @@
     private abstract static class TypeReferenceVisitor extends CodeElementScanner<Void, Void> {
 
         @Override
-        public void visitTree(CodeTree e, Void p) {
+        public void visitTree(CodeTree e, Void p, Element enclosing) {
             if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) {
-                visitStaticFieldReference(e, e.getType(), e.getString());
+                visitStaticFieldReference(enclosing, e.getType(), e.getString());
             } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) {
-                visitStaticMethodReference(e, e.getType(), e.getString());
+                visitStaticMethodReference(enclosing, e.getType(), e.getString());
             } else if (e.getType() != null) {
-                visitTypeReference(e, e.getType());
+                visitTypeReference(enclosing, e.getType());
             }
-            super.visitTree(e, p);
+            super.visitTree(e, p, enclosing);
         }
 
         @Override
@@ -477,18 +406,69 @@
 
         @Override
         public void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName) {
-            staticImportUsage.add(type);
+            registerSymbol(staticImportUsage, ElementUtils.getQualifiedName(type), elementName);
         }
 
         @Override
         public void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName) {
-            staticImportUsage.add(type);
+            registerSymbol(staticImportUsage, ElementUtils.getQualifiedName(type), elementName);
         }
 
         @Override
         public void visitTypeReference(Element enclosedType, TypeMirror type) {
             if (type != null) {
-                createTypeReference(enclosedType, type);
+                switch (type.getKind()) {
+                    case BOOLEAN:
+                    case BYTE:
+                    case CHAR:
+                    case DOUBLE:
+                    case FLOAT:
+                    case SHORT:
+                    case INT:
+                    case LONG:
+                    case VOID:
+                        return;
+                    case DECLARED:
+                        if (needsImport(enclosedType, type)) {
+                            DeclaredType declard = (DeclaredType) type;
+                            registerSymbol(classImportUsage, ElementUtils.getEnclosedQualifiedName(declard), ElementUtils.getDeclaredName(declard, false));
+                        }
+                        for (TypeMirror argument : ((DeclaredType) type).getTypeArguments()) {
+                            visitTypeReference(enclosedType, argument);
+                        }
+                        return;
+                    case ARRAY:
+                        visitTypeReference(enclosedType, ((ArrayType) type).getComponentType());
+                        return;
+                    case WILDCARD:
+                        WildcardType wildcard = (WildcardType) type;
+                        if (wildcard.getExtendsBound() != null) {
+                            visitTypeReference(enclosedType, wildcard.getExtendsBound());
+                        } else if (wildcard.getSuperBound() != null) {
+                            visitTypeReference(enclosedType, wildcard.getSuperBound());
+                        }
+                        return;
+                    case TYPEVAR:
+                        return;
+                    default:
+                        throw new RuntimeException("Unknown type specified " + type.getKind() + " mirror: " + type);
+                }
+
+            }
+        }
+
+        private void registerSymbol(Map<String, String> symbolUsage, String elementQualifiedName, String elementName) {
+            if (symbolUsage.containsKey(elementName)) {
+                String otherQualifiedName = symbolUsage.get(elementName);
+                if (otherQualifiedName == null) {
+                    // already registered ambiguous
+                    return;
+                }
+                if (!otherQualifiedName.equals(elementQualifiedName)) {
+                    symbolUsage.put(elementName, null);
+                }
+            } else {
+                symbolUsage.put(elementName, elementQualifiedName);
             }
         }