gt:             List<TypeElement> declaredTypes = getDeclaredTypes(superType);
context: /*
   * 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) {
  