private CompilationUnitTree addImports()

in java/java.source.base/src/org/netbeans/api/java/source/GeneratorUtilities.java [1091:1406]


    private CompilationUnitTree addImports(CompilationUnitTree cut, List<? extends ImportTree> cutImports, Set<? extends Element> toImport) {
        assert cut != null && toImport != null && toImport.size() > 0;

        ArrayList<Element> elementsToImport = new ArrayList<Element>(toImport.size());
        Set<String> staticImportNames = new HashSet<String>();
        for (Element e : toImport) {
            if (e == null) {
                continue;
            }
            switch (e.getKind()) {
                case METHOD:
                case ENUM_CONSTANT:
                case FIELD:
                    String name = new StringBuilder(((TypeElement)e.getEnclosingElement()).getQualifiedName()).append('.').append(e.getSimpleName()).toString();
                    // skip default static imports
                    if ("java.lang.StringTemplate.STR".equals(name)) {
                        break;
                    }
                    if (!staticImportNames.add(name))
                        break;
                default:
                    elementsToImport.add(e);
            }
        }

        Trees trees = copy.getTrees();
        Elements elements = copy.getElements();
        ElementUtilities elementUtilities = copy.getElementUtilities();
                
        CodeStyle cs = DiffContext.getCodeStyle(copy);
        
        // check weather any conversions to star imports are needed
        int treshold = cs.useSingleClassImport() ? cs.countForUsingStarImport() : 1;
        int staticTreshold = cs.countForUsingStaticStarImport();        
        Map<PackageElement, Integer> pkgCounts = new LinkedHashMap<PackageElement, Integer>();
        PackageElement pkg = elements.getPackageElement("java.lang"); //NOI18N
        if (pkg != null) {
            pkgCounts.put(pkg, -2);
        }
        ExpressionTree packageName = cut.getPackageName();
        pkg = packageName != null ? (PackageElement)trees.getElement(TreePath.getPath(cut, packageName)) : null;
        if (pkg == null && packageName != null) {
            pkg = elements.getPackageElement(elements.getName(packageName.toString()));
        }
        if (pkg == null) {
            pkg = elements.getPackageElement(elements.getName("")); //NOI18N
        }
        pkgCounts.put(pkg, -2);
        Map<TypeElement, Integer> typeCounts = new LinkedHashMap<TypeElement, Integer>();
        // initially the import scope has no symbols. We must fill it in by:
        // existing CUT named imports, package members AND then star imports, in this specific order
        JCCompilationUnit jcut = (JCCompilationUnit)cut;
        StarImportScope importScope = new StarImportScope((Symbol)pkg);
        if (jcut.starImportScope != null) {
            importScope.prependSubScope(((JCCompilationUnit)cut).starImportScope);
        }
        if (jcut.packge != null) {
            importScope.prependSubScope(jcut.packge.members_field);
        }
        for (Element e : elementsToImport) {
            boolean isStatic = false;
            Element el = null;
            switch (e.getKind()) {
                case PACKAGE:
                    el = e;
                    break;
                case ANNOTATION_TYPE:
                case CLASS:
                case ENUM:
                case INTERFACE:
                case RECORD:
                    if (e.getEnclosingElement().getKind() == ElementKind.PACKAGE)
                        el = e.getEnclosingElement();
                    break;
                case METHOD:
                case ENUM_CONSTANT:
                case FIELD:
                    isStatic = true;
                    el = e.getEnclosingElement();
                    break;
                default:
                    assert false : "Illegal element kind: " + e.getKind(); //NOI18N
            }
            if (el != null) {
                Integer cnt = isStatic ? typeCounts.get((TypeElement)el) : pkgCounts.get((PackageElement)el);
                if (cnt == null)
                    cnt = 0;
                if (cnt >= 0) {
                    if (el == e) {
                        cnt = -1;
                    } else {
                        cnt++;
                        if (isStatic) {
                            if (cnt >= staticTreshold)
                                cnt = -1;
                        } else if (cnt >= treshold || checkPackagesForStarImport(((PackageElement)el).getQualifiedName().toString(), cs)) {
                            cnt = -1;
                        }
                    }
                }
                if (isStatic) {
                    typeCounts.put((TypeElement)el, cnt);
                } else {
                    pkgCounts.put((PackageElement)el, cnt);
                }
            }
        }
        List<ImportTree> imports = new ArrayList<ImportTree>(cutImports);
        for (ImportTree imp : imports) {
            Element e = getImportedElement(cut, imp);
            if (!elementsToImport.contains(e)) {
                if (imp.isStatic()) {
                    if (e.getKind().isClass() || e.getKind().isInterface()) {
                        Element el = e;
                        while (el != null) {
                            Integer cnt = typeCounts.get((TypeElement)el);
                            if (cnt != null && staticTreshold == Integer.MAX_VALUE) {
                                typeCounts.put((TypeElement)el, -2);
                            }
                            TypeMirror tm = ((TypeElement)el).getSuperclass();
                            el = tm.getKind() == TypeKind.DECLARED ? ((DeclaredType)tm).asElement() : null;
                        }
                    } else {
                        Element el = elementUtilities.enclosingTypeElement(e);
                        if (el != null) {
                            Integer cnt = typeCounts.get((TypeElement)el);
                            if (cnt != null) {
                                if (cnt >= 0) {
                                    cnt++;
                                    if (cnt >= staticTreshold)
                                        cnt = -1;
                                }
                                typeCounts.put((TypeElement)el, cnt);
                            }
                        }
                    }
                } else {
                    Element el = e.getKind() == ElementKind.PACKAGE ? e : (e.getKind().isClass() || e.getKind().isInterface()) && e.getEnclosingElement().getKind() == ElementKind.PACKAGE ? e.getEnclosingElement() : null;
                    if (el != null) {
                        Integer cnt = pkgCounts.get((PackageElement)el);
                        if (cnt != null) {
                            if (el == e) { // this is only true for package element, that is for package-star import.
                                if (treshold == Integer.MAX_VALUE) {
                                    // do not touch the star import
                                    cnt = -2;
                                }
                            } else if (cnt >= 0) {
                                cnt++;
                                if (cnt >= treshold)
                                    cnt = -1;
                            }
                            pkgCounts.put((PackageElement)el, cnt);
                        }
                    }
                }
            } else if (treshold == Integer.MAX_VALUE || staticTreshold == Integer.MAX_VALUE) {
                // disable any manipulations (optimization) for existing star imports iff the "Count" feature is disabled.
                int threshold = imp.isStatic() ? staticTreshold : treshold;
                if (isStarImport(imp) && threshold == Integer.MAX_VALUE) {
                    Map map = imp.isStatic() ? typeCounts : pkgCounts;
                    Integer cnt = (Integer)map.get(e);
                    if (cnt != null) {
                        map.put(e, -2);
                    }
                }
            }
        }
        // remove those star imports that do not satisfy the thresholds
        for (Iterator<ImportTree> ii = imports.iterator(); ii.hasNext();) {
            ImportTree imp = ii.next();
            if (!isStarImport(imp)) {
                continue;
            }
            Element e = getImportedElement(cut, imp);
            Integer cnt;
            if (imp.isStatic()) {
                cnt = typeCounts.get(e);
            } else {
                cnt = pkgCounts.get(e);
            }
            if (cnt != null && cnt >= 0) {
                ii.remove();
            }
        }
        
        // check for possible name clashes originating from adding the package imports
        Set<Element> explicitNamedImports = new HashSet<Element>();
        for (Element element : elementsToImport) {
            if (element.getEnclosingElement() != pkg && (element.getKind().isClass() || element.getKind().isInterface())) {
                for (Symbol sym : importScope.getSymbolsByName((com.sun.tools.javac.util.Name)element.getSimpleName())) {
                    if (sym.getKind().isClass() || sym.getKind().isInterface()) {
                        if (sym != element) {
                            explicitNamedImports.add(element);
                            break;// break if explicitNameImport was added
                        }
                    }
                }
            }
        }
        Map<Name, TypeElement> usedTypes = null;
        for (Map.Entry<PackageElement, Integer> entry : pkgCounts.entrySet()) {
            if (entry.getValue() == -1) {
                for (Element element : entry.getKey().getEnclosedElements()) {
                    if (element.getKind().isClass() || element.getKind().isInterface()) {
                        for (Symbol sym : importScope.getSymbolsByName((com.sun.tools.javac.util.Name)element.getSimpleName())) {
                            if (sym != element) {
                                TypeElement te = null;
                                for (Element e : elementsToImport) {
                                    if ((e.getKind().isClass() || e.getKind().isInterface()) && element.getSimpleName() == e.getSimpleName()) {
                                        te = (TypeElement) e;
                                        break;
                                    }
                                }
                                if (te != null) {
                                    explicitNamedImports.add(te);
                                } else {
                                    if (usedTypes == null) {
                                        usedTypes = getUsedTypes(cut);
                                    }
                                    if (te != null) {
                                        explicitNamedImports.add(te);
                                    } else {
                                        if (usedTypes == null) {
                                            usedTypes = getUsedTypes(cut);
                                        }
                                        te = usedTypes.get(element.getSimpleName());
                                        if (te != null) {
                                            elementsToImport.add(te);
                                            explicitNamedImports.add(te);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (entry.getValue() < 0 && entry.getKey() instanceof Symbol)
                importScope.prependSubScope(((Symbol)entry.getKey()).members());
        }

        // sort the elements to import
        ImportsComparator comparator = new ImportsComparator(cs);
        elementsToImport.sort(comparator);
        
        // merge the elements to import with the existing import statemetns
        TreeMaker make = copy.getTreeMaker();
        int currentToImport = elementsToImport.size() - 1;
        int currentExisting = imports.size() - 1;
        while (currentToImport >= 0) {
            Element currentToImportElement = elementsToImport.get(currentToImport);
            boolean isStatic = false;
            Element el = null;
            switch (currentToImportElement.getKind()) {
                case PACKAGE:
                    el = currentToImportElement;
                    break;
                case ANNOTATION_TYPE:
                case CLASS:
                case ENUM:
                case INTERFACE:
                case RECORD:
                    if (currentToImportElement.getEnclosingElement().getKind() == ElementKind.PACKAGE)
                        el = currentToImportElement.getEnclosingElement();
                    break;
                case METHOD:
                case ENUM_CONSTANT:
                case FIELD:
                    isStatic = true;
                    el = currentToImportElement.getEnclosingElement();
                    break;
            }
            Integer cnt = el == null ? Integer.valueOf(0) : isStatic ? typeCounts.get((TypeElement)el) : pkgCounts.get((PackageElement)el);
            if (explicitNamedImports.contains(currentToImportElement))
                cnt = 0;
            if (cnt == -2) {
                currentToImport--;
            } else {
                if (cnt == -1) {
                    currentToImportElement = el;
                    if (isStatic) {
                        typeCounts.put((TypeElement)el, -2);
                    } else {
                        pkgCounts.put((PackageElement)el, -2);
                    }
                }
                boolean isStar = currentToImportElement.getKind() == ElementKind.PACKAGE
                        || isStatic && (currentToImportElement.getKind().isClass() || currentToImportElement.getKind().isInterface());
                ExpressionTree qualIdent = qualIdentFor(currentToImportElement);
                if (isStar) {
                    qualIdent = make.MemberSelect(qualIdent, elements.getName("*")); //NOI18N
                }
                ImportTree nImport = make.Import(qualIdent, isStatic);
                while (currentExisting >= 0) {
                    ImportTree imp = imports.get(currentExisting);
                    Element impElement = getImportedElement(cut, imp);
                    el = imp.isStatic()
                            ? impElement.getKind().isClass() || impElement.getKind().isInterface() ? impElement : elementUtilities.enclosingTypeElement(impElement)
                            : impElement.getKind() == ElementKind.PACKAGE ? impElement : (impElement.getKind().isClass() || impElement.getKind().isInterface()) && impElement.getEnclosingElement().getKind() == ElementKind.PACKAGE ? impElement.getEnclosingElement() : null;
                    if (isStatic == imp.isStatic() && (currentToImportElement == impElement || isStar && currentToImportElement == el)) {
                        imports.remove(currentExisting);                        
                    } else {
                        if (comparator.compare(nImport, imp) > 0) {
                            break;
                        }
                    }
                    currentExisting--;
                }
                imports.add(currentExisting + 1, nImport);
                currentToImport--;
            }
        }
        
        // return a copy of the unit with changed imports section
        return make.CompilationUnit(cut.getPackage(), imports, cut.getTypeDecls(), cut.getSourceFile());
    }