Mercurial > hg > truffle
diff graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java @ 7291:a748e4d44694
Truffle API to specify type-specalized Node classes; annotation processor for automatic code generation of the type-specialized Node classes during the build process
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Fri, 21 Dec 2012 10:44:31 -0800 |
parents | |
children | 6343a09b2ec1 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java Fri Dec 21 10:44:31 2012 -0800 @@ -0,0 +1,377 @@ +/* + * 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.codegen.processor.codewriter; + +import static com.oracle.truffle.codegen.processor.Utils.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; + +public final class OrganizedImports { + + private final Map<TypeMirror, Integer> importUsage = new HashMap<>(); + private final Map<TypeMirror, Integer> staticImportUsage = new HashMap<>(); + + 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 CodeTypeElement topLevelClass; + + private OrganizedImports(CodeTypeElement topLevelClass) { + this.topLevelClass = topLevelClass; + } + + public static OrganizedImports organize(CodeTypeElement topLevelClass) { + OrganizedImports organized = new OrganizedImports(topLevelClass); + + OrganizedImports.ReferenceCollector reference = new ReferenceCollector(); + topLevelClass.accept(reference, null); + + OrganizedImports.ImportResolver resolver = new ImportResolver(reference, organized); + topLevelClass.accept(resolver, null); + return organized; + } + + public String useImport(TypeMirror type) { + String simpleName = getSimpleName(type); + TypeMirror usedByType = simpleNamesUsed.get(type); + if (usedByType == null) { + simpleNamesUsed.put(simpleName, type); + usedByType = type; + } else if (!typeEquals(type, usedByType)) { + // we need a qualified name + return getQualifiedName(type); + } + + // we can use the simple name + addUsage(type, importUsage); + return simpleName; + } + + public String useStaticFieldImport(TypeMirror type, String fieldName) { + return useStaticImport(type, fieldName, ambiguousStaticFields, declaredStaticFields); + } + + public String useStaticMethodImport(TypeMirror type, String methodName) { + return useStaticImport(type, methodName, ambiguousStaticMethods, declaredStaticMethods); + } + + private String useStaticImport(TypeMirror type, String name, Set<String> ambiguousSymbols, Set<String> declaredSymbols) { + if (ambiguousSymbols.contains(name)) { + // ambiguous import + return useImport(type) + "." + name; + } else if (!declaredSymbols.contains(name)) { + // not imported at all + return useImport(type) + "." + name; + } else { + // import declared and not ambiguous + addUsage(type, staticImportUsage); + return name; + } + } + + public Set<CodeImport> generateImports() { + Set<CodeImport> imports = new HashSet<>(); + + imports.addAll(generateImports(topLevelClass, importUsage.keySet())); + imports.addAll(generateStaticImports(topLevelClass, staticImportUsage.keySet())); + + return imports; + } + + void clearStaticImports() { + declaredStaticFields.clear(); + declaredStaticMethods.clear(); + ambiguousStaticFields.clear(); + ambiguousStaticMethods.clear(); + } + + 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 static Set<CodeImport> generateImports(CodeTypeElement e, Set<TypeMirror> toGenerate) { + Set<String> autoImportedTypes = new HashSet<>(); + + // if type is declared inside a super type of this class -> no import + collectSuperTypeImports(e, autoImportedTypes); + collectInnerTypeImports(e, autoImportedTypes); + + TreeSet<CodeImport> importObjects = new TreeSet<>(); + for (TypeMirror importType : toGenerate) { + String importTypePackageName = getPackageName(importType); + if (importTypePackageName == null) { + continue; // no package name -> no import + } + + if (importTypePackageName.equals("java.lang")) { + continue; // java.lang is automatically imported + } + + if (importTypePackageName.equals(getPackageName(e))) { + continue; // same package name -> no import + } + + String qualifiedName = getQualifiedName(importType); + + if (autoImportedTypes.contains(qualifiedName)) { + continue; + } + + importObjects.add(new CodeImport(importType, getQualifiedName(importType), false)); + } + + return importObjects; + } + + private static void collectInnerTypeImports(TypeElement e, Set<String> autoImportedTypes) { + for (TypeElement innerClass : ElementFilter.typesIn(e.getEnclosedElements())) { + collectSuperTypeImports(innerClass, autoImportedTypes); + 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) { + autoImportedTypes.add(getQualifiedName(declaredType)); + } + } + } + + private static Set<CodeImport> generateStaticImports(CodeTypeElement e, Set<TypeMirror> toGenerate) { + Set<String> autoImportedStaticTypes = new HashSet<>(); + + // if type is declared inside a super type of this class -> no import + autoImportedStaticTypes.add(getQualifiedName(e)); + autoImportedStaticTypes.addAll(getQualifiedSuperTypeNames(e)); + + TreeSet<CodeImport> importObjects = new TreeSet<>(); + for (TypeMirror importType : toGenerate) { + if (getPackageName(importType) == null) { + continue; // no package name -> no import + } + + String qualifiedName = getQualifiedName(importType); + if (autoImportedStaticTypes.contains(qualifiedName)) { + continue; + } + + importObjects.add(new CodeImport(importType, qualifiedName + ".*", true)); + } + + return importObjects; + } + + private static void addUsage(TypeMirror type, Map<TypeMirror, Integer> usageMap) { + if (type != null) { + Integer value = usageMap.get(type); + if (value == null) { + usageMap.put(type, 1); + } else { + usageMap.put(type, value + 1); + } + } + } + + private static class ReferenceCollector extends CodeElementScanner<Void, Void> { + + final Map<TypeMirror, Integer> typeReferences = new HashMap<>(); + final Map<TypeMirror, Integer> staticTypeReferences = new HashMap<>(); + + @Override + public void visitTree(CodeTree e, Void p) { + if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) { + addStaticImport(e.getType()); + } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) { + addStaticImport(e.getType()); + } else { + addImport(e.getType()); + } + super.visitTree(e, p); + } + + @Override + public Void visitExecutable(CodeExecutableElement e, Void p) { + visitAnnotations(e.getAnnotationMirrors()); + if (e.getReturnType() != null) { + addImport(e.getReturnType()); + } + for (TypeMirror type : e.getThrownTypes()) { + addImport(type); + } + return super.visitExecutable(e, p); + } + + @Override + public Void visitType(CodeTypeElement e, Void p) { + visitAnnotations(e.getAnnotationMirrors()); + + addImport(e.getSuperclass()); + for (TypeMirror type : e.getImplements()) { + addImport(type); + } + + return super.visitType(e, p); + } + + @Override + public Void visitVariable(VariableElement f, Void p) { + visitAnnotations(f.getAnnotationMirrors()); + addImport(f.asType()); + return super.visitVariable(f, p); + } + + private void visitAnnotations(List<? extends AnnotationMirror> mirrors) { + for (AnnotationMirror mirror : mirrors) { + visitAnnotation(mirror); + } + } + + public void visitAnnotation(AnnotationMirror e) { + addImport(e.getAnnotationType()); + } + + @Override + public void visitImport(CodeImport e, Void p) { + } + + private void addStaticImport(TypeMirror type) { + addUsage(type, staticTypeReferences); + } + + private void addImport(TypeMirror type) { + addUsage(type, typeReferences); + } + + } + + private static class ImportResolver extends CodeElementScanner<Void, Void> { + + private final ReferenceCollector collector; + private final OrganizedImports organizedImports; + + public ImportResolver(OrganizedImports.ReferenceCollector collector, OrganizedImports organizedImports) { + this.collector = collector; + this.organizedImports = organizedImports; + } + + @Override + public Void visitType(CodeTypeElement e, Void p) { + if (e.isTopLevelClass()) { + organizedImports.clearStaticImports(); + + organizedImports.processStaticImports(e); + List<TypeElement> types = Utils.getSuperTypes(e); + for (TypeElement typeElement : types) { + organizedImports.processStaticImports(typeElement); + } + + for (TypeMirror type : collector.staticTypeReferences.keySet()) { + TypeElement element = fromTypeMirror(type); + if (element != null) { + // already processed by supertype + if (types.contains(element)) { + continue; + } + organizedImports.processStaticImports(element); + } + } + + for (TypeMirror imp : collector.typeReferences.keySet()) { + organizedImports.useImport(imp); + } + } + return super.visitType(e, p); + } + + @Override + public void visitTree(CodeTree e, Void p) { + if (e.getCodeKind() == CodeTreeKind.TYPE) { + organizedImports.useImport(e.getType()); + } else if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) { + organizedImports.useStaticFieldImport(e.getType(), e.getString()); + } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) { + organizedImports.useStaticMethodImport(e.getType(), e.getString()); + } + super.visitTree(e, p); + } + } + +}