diff truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java @ 21951:9c8c0937da41

Moving all sources into truffle subdirectory
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Wed, 17 Jun 2015 10:58:08 +0200
parents graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java@0ec5f5a2e720
children dc83cc1f94f2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java	Wed Jun 17 10:58:08 2015 +0200
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.dsl.processor.java.transform;
+
+import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
+
+import java.util.*;
+
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+import javax.lang.model.util.*;
+
+import com.oracle.truffle.dsl.processor.java.*;
+import com.oracle.truffle.dsl.processor.java.model.*;
+
+public final class OrganizedImports {
+
+    private final Map<String, String> classImportUsage = new HashMap<>();
+    private final Map<String, Set<String>> autoImportCache = new HashMap<>();
+
+    private final CodeTypeElement topLevelClass;
+
+    private OrganizedImports(CodeTypeElement topLevelClass) {
+        this.topLevelClass = topLevelClass;
+    }
+
+    public static OrganizedImports organize(CodeTypeElement topLevelClass) {
+        OrganizedImports organized = new OrganizedImports(topLevelClass);
+        organized.organizeImpl();
+        return organized;
+    }
+
+    private void organizeImpl() {
+        ImportTypeReferenceVisitor reference = new ImportTypeReferenceVisitor();
+        topLevelClass.accept(reference, null);
+    }
+
+    public String createTypeReference(Element enclosedElement, TypeMirror type) {
+        switch (type.getKind()) {
+            case BOOLEAN:
+            case BYTE:
+            case CHAR:
+            case DOUBLE:
+            case FLOAT:
+            case SHORT:
+            case INT:
+            case LONG:
+            case VOID:
+                return ElementUtils.getSimpleName(type);
+            case DECLARED:
+                return createDeclaredTypeName(enclosedElement, (DeclaredType) type);
+            case ARRAY:
+                return createTypeReference(enclosedElement, ((ArrayType) type).getComponentType()) + "[]";
+            case WILDCARD:
+                return createWildcardName(enclosedElement, (WildcardType) type);
+            case TYPEVAR:
+                return "?";
+            default:
+                throw new RuntimeException("Unknown type specified " + type.getKind() + " mirror: " + type);
+        }
+    }
+
+    public String createStaticFieldReference(Element enclosedElement, TypeMirror type, String fieldName) {
+        return createStaticReference(enclosedElement, type, fieldName);
+    }
+
+    public String createStaticMethodReference(Element enclosedElement, TypeMirror type, String methodName) {
+        return createStaticReference(enclosedElement, type, methodName);
+    }
+
+    private String createStaticReference(Element enclosedElement, TypeMirror type, String name) {
+        // ambiguous import
+        return createTypeReference(enclosedElement, type) + "." + name;
+    }
+
+    private String createWildcardName(Element enclosedElement, WildcardType type) {
+        StringBuilder b = new StringBuilder();
+        if (type.getExtendsBound() != null) {
+            b.append("? extends ").append(createTypeReference(enclosedElement, type.getExtendsBound()));
+        } else if (type.getSuperBound() != null) {
+            b.append("? super ").append(createTypeReference(enclosedElement, type.getExtendsBound()));
+        } else {
+            b.append("?");
+        }
+        return b.toString();
+    }
+
+    private String createDeclaredTypeName(Element enclosedElement, DeclaredType type) {
+        String name = ElementUtils.fixECJBinaryNameIssue(type.asElement().getSimpleName().toString());
+        if (classImportUsage.containsKey(name)) {
+            String qualifiedImport = classImportUsage.get(name);
+            String qualifiedName = ElementUtils.getEnclosedQualifiedName(type);
+
+            if (!qualifiedName.equals(qualifiedImport)) {
+                name = qualifiedName;
+            }
+        }
+
+        List<? extends TypeMirror> genericTypes = type.getTypeArguments();
+        if (genericTypes.size() == 0) {
+            return name;
+        }
+
+        StringBuilder b = new StringBuilder(name);
+        b.append("<");
+        for (int i = 0; i < genericTypes.size(); i++) {
+            TypeMirror genericType = i < genericTypes.size() ? genericTypes.get(i) : null;
+            if (genericType != null) {
+                b.append(createTypeReference(enclosedElement, genericType));
+            } else {
+                b.append("?");
+            }
+
+            if (i < genericTypes.size() - 1) {
+                b.append(", ");
+            }
+        }
+        b.append(">");
+        return b.toString();
+    }
+
+    public Set<CodeImport> generateImports() {
+        Set<CodeImport> imports = new HashSet<>();
+
+        imports.addAll(generateImports(classImportUsage));
+
+        return imports;
+    }
+
+    private boolean needsImport(Element enclosed, TypeMirror importType) {
+        String importPackagName = getPackageName(importType);
+        TypeElement enclosedElement = findNearestEnclosingType(enclosed);
+        if (importPackagName == null) {
+            return false;
+        } else if (importPackagName.equals("java.lang")) {
+            return false;
+        } else if (importPackagName.equals(getPackageName(topLevelClass)) && ElementUtils.isTopLevelClass(importType)) {
+            return false; // same package name -> no import
+        }
+
+        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(enclosedElementId, autoImportedTypes);
+        }
+
+        String qualifiedName = getQualifiedName(importType);
+        if (autoImportedTypes.contains(qualifiedName)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private static Set<CodeImport> generateImports(Map<String, String> symbols) {
+        TreeSet<CodeImport> importObjects = new TreeSet<>();
+        for (String symbol : symbols.keySet()) {
+            String packageName = symbols.get(symbol);
+            if (packageName != null) {
+                importObjects.add(new CodeImport(packageName, symbol, false));
+            }
+        }
+        return importObjects;
+    }
+
+    private static void collectInnerTypeImports(TypeElement e, Set<String> autoImportedTypes) {
+        autoImportedTypes.add(getQualifiedName(e));
+        for (TypeElement innerClass : ElementFilter.typesIn(e.getEnclosedElements())) {
+            collectInnerTypeImports(innerClass, autoImportedTypes);
+        }
+    }
+
+    private static void collectSuperTypeImports(TypeElement e, Set<String> autoImportedTypes) {
+        List<TypeElement> superTypes = getSuperTypes(e);
+        for (TypeElement superType : superTypes) {
+            List<TypeElement> declaredTypes = getDeclaredTypes(superType);
+            for (TypeElement declaredType : declaredTypes) {
+                if (!superTypes.contains(declaredType)) {
+                    autoImportedTypes.add(getQualifiedName(declaredType));
+                }
+            }
+        }
+    }
+
+    private abstract static class TypeReferenceVisitor extends CodeElementScanner<Void, Void> {
+
+        @Override
+        public void visitTree(CodeTree e, Void p, Element enclosing) {
+            if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) {
+                visitStaticFieldReference(enclosing, e.getType(), e.getString());
+            } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) {
+                visitStaticMethodReference(enclosing, e.getType(), e.getString());
+            } else if (e.getType() != null) {
+                visitTypeReference(enclosing, e.getType());
+            }
+            super.visitTree(e, p, enclosing);
+        }
+
+        @Override
+        public Void visitExecutable(CodeExecutableElement e, Void p) {
+            visitAnnotations(e, e.getAnnotationMirrors());
+            if (e.getReturnType() != null) {
+                visitTypeReference(e, e.getReturnType());
+            }
+            for (TypeMirror type : e.getThrownTypes()) {
+                visitTypeReference(e, type);
+            }
+            return super.visitExecutable(e, p);
+        }
+
+        @Override
+        public Void visitType(CodeTypeElement e, Void p) {
+            visitAnnotations(e, e.getAnnotationMirrors());
+
+            visitTypeReference(e, e.getSuperclass());
+            for (TypeMirror type : e.getImplements()) {
+                visitTypeReference(e, type);
+            }
+
+            return super.visitType(e, p);
+        }
+
+        private void visitAnnotations(Element enclosingElement, List<? extends AnnotationMirror> mirrors) {
+            for (AnnotationMirror mirror : mirrors) {
+                visitAnnotation(enclosingElement, mirror);
+            }
+        }
+
+        public void visitAnnotation(Element enclosingElement, AnnotationMirror e) {
+            visitTypeReference(enclosingElement, e.getAnnotationType());
+            if (!e.getElementValues().isEmpty()) {
+                Map<? extends ExecutableElement, ? extends AnnotationValue> values = e.getElementValues();
+                Set<? extends ExecutableElement> methodsSet = values.keySet();
+                List<ExecutableElement> methodsList = new ArrayList<>();
+                for (ExecutableElement method : methodsSet) {
+                    if (values.get(method) == null) {
+                        continue;
+                    }
+                    methodsList.add(method);
+                }
+
+                for (int i = 0; i < methodsList.size(); i++) {
+                    AnnotationValue value = values.get(methodsList.get(i));
+                    visitAnnotationValue(enclosingElement, value);
+                }
+            }
+        }
+
+        public void visitAnnotationValue(Element enclosingElement, AnnotationValue e) {
+            e.accept(new AnnotationValueReferenceVisitor(enclosingElement), null);
+        }
+
+        private class AnnotationValueReferenceVisitor extends AbstractAnnotationValueVisitor7<Void, Void> {
+
+            private final Element enclosingElement;
+
+            public AnnotationValueReferenceVisitor(Element enclosedElement) {
+                this.enclosingElement = enclosedElement;
+            }
+
+            @Override
+            public Void visitBoolean(boolean b, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitByte(byte b, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitChar(char c, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitDouble(double d, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitFloat(float f, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitInt(int i, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitLong(long i, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitShort(short s, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitString(String s, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitType(TypeMirror t, Void p) {
+                visitTypeReference(enclosingElement, t);
+                return null;
+            }
+
+            @Override
+            public Void visitEnumConstant(VariableElement c, Void p) {
+                visitTypeReference(enclosingElement, c.asType());
+                return null;
+            }
+
+            @Override
+            public Void visitAnnotation(AnnotationMirror a, Void p) {
+                TypeReferenceVisitor.this.visitAnnotation(enclosingElement, a);
+                return null;
+            }
+
+            @Override
+            public Void visitArray(List<? extends AnnotationValue> vals, Void p) {
+                for (int i = 0; i < vals.size(); i++) {
+                    TypeReferenceVisitor.this.visitAnnotationValue(enclosingElement, vals.get(i));
+                }
+                return null;
+            }
+        }
+
+        @Override
+        public Void visitVariable(VariableElement f, Void p) {
+            visitAnnotations(f, f.getAnnotationMirrors());
+            visitTypeReference(f, f.asType());
+            return super.visitVariable(f, p);
+        }
+
+        @Override
+        public void visitImport(CodeImport e, Void p) {
+        }
+
+        public abstract void visitTypeReference(Element enclosedType, TypeMirror type);
+
+        public abstract void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName);
+
+        public abstract void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName);
+
+    }
+
+    private class ImportTypeReferenceVisitor extends TypeReferenceVisitor {
+
+        @Override
+        public void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName) {
+            visitTypeReference(enclosedType, type);
+        }
+
+        @Override
+        public void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName) {
+            visitTypeReference(enclosedType, type);
+        }
+
+        @Override
+        public void visitTypeReference(Element enclosedType, TypeMirror type) {
+            if (type != null) {
+                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);
+            }
+        }
+
+    }
+
+}