KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > source > pretty > ImportAnalysis


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.java.source.pretty;
20
21 import com.sun.tools.javac.code.*;
22 import com.sun.tools.javac.code.Symbol.*;
23 import com.sun.tools.javac.tree.JCTree.*;
24 import com.sun.tools.javac.tree.JCTree;
25 import com.sun.tools.javac.tree.TreeInfo;
26 import com.sun.tools.javac.tree.TreeScanner;
27 import com.sun.tools.javac.util.List;
28
29 import java.util.Set JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.logging.Logger JavaDoc;
32
33 public class ImportAnalysis extends TreeScanner {
34     int starThreshhold;
35     int useThreshhold;
36     private static final int implicitImport = 9999;
37     SymRefStats usedClasses, usedClassOwners;
38     public PackageSymbol containingPackage;
39     public ClassSymbol containingClass;
40     Symtab syms;
41     boolean includeExplicit;
42
43     public ImportAnalysis (int st, int ut, JCCompilationUnit t, Symtab syms, Types types) {
44         this(st, ut, t, syms, types, true);
45     }
46     
47     public ImportAnalysis (int st, int ut, JCCompilationUnit t, Symtab syms, Types types, boolean explicit) {
48     starThreshhold = st;
49     useThreshhold = ut;
50     this.syms = syms;
51         includeExplicit = explicit;
52         containingPackage = t.packge;
53         if (containingPackage == null)
54             Logger.getLogger("org.netbeans.modules.java.source").warning(
55                     "null package element in " + t.getSourceFile().toUri().getPath());
56         usedClassOwners = setImplicit(usedClassOwners, containingPackage);
57     usedClassOwners = setImplicit(usedClassOwners, syms.objectType.tsym.owner); // java.lang
58
if(t!=null) t.accept(this);
59     }
60     public boolean starred(Symbol s) {
61     for (SymRefStats p = usedClassOwners; p != null; p = p.next)
62         if (p.clazz == s)
63         return p.imported;
64     return false;
65     }
66     public boolean imported(Symbol s) {
67     for (SymRefStats p = usedClasses; p != null; p = p.next)
68         if (p.clazz == s)
69         return p.imported;
70     if(starred(s.owner)) return true;
71     return false;
72     }
73     
74     /**
75      * Return set of symbols which are not resolved by the existing list of
76      * imports.
77      */

78     public Set JavaDoc<Symbol> neededImports(List<JCImport> imports) {
79         // Create two sets consisting of the explicit and starred wildcard symbols.
80
Set JavaDoc<Symbol> starred = new HashSet JavaDoc<Symbol>(8);
81         Set JavaDoc<Symbol> explicit = new HashSet JavaDoc<Symbol>(8);
82         while (imports.nonEmpty()) {
83             JCTree qualid = imports.head.qualid;
84             if (qualid.tag == JCTree.SELECT) {
85                 JCFieldAccess s = (JCFieldAccess)qualid;
86                 Symbol sym = s.sym;
87                 if (sym == null) {
88                     JCTree selected = s.selected;
89                     sym = selected.tag == JCTree.SELECT ?
90                         ((JCFieldAccess)selected).sym : ((JCIdent)selected).sym;
91                     //assert sym != null;
92
if (sym != null) {
93                         starred.add(sym);
94                     }
95                 } else
96                     explicit.add(sym);
97             }
98             else if (qualid.tag == JCTree.IDENT)
99                 explicit.add(((JCIdent)qualid).sym);
100             else
101                 throw new AssertionError JavaDoc("unknown qualid tree type");
102             imports = imports.tail;
103         }
104         
105         // add implicitly imported packages
106
starred.add(containingPackage);
107         starred.add(syms.objectType.tsym.owner); // java.lang
108

109         Set JavaDoc<Symbol> missing = new HashSet JavaDoc<Symbol>();
110     for (SymRefStats p = usedClasses; p != null; p = p.next) {
111             boolean alreadyImported = p.implicitlyImported() ||
112                     explicit.contains(p.clazz) || starred.contains(p.clazz.owner);
113             p.imported = alreadyImported || p.used >= useThreshhold;
114             if (!alreadyImported) {
115                 if (p.imported)
116                     for (SymRefStats q = usedClasses; q != null; q = q.next)
117                         if (q != p && q.clazz.name == p.clazz.name) {
118                             p.imported = false;
119                             break;
120                         }
121                 if (p.imported && otherPackageHasClassName(p))
122                     p.imported = false;
123                 if (p.imported && !alreadyImported)
124                     missing.add(p.clazz);
125             }
126         }
127         return missing;
128     }
129     
130     public void decideImports() {
131     for (SymRefStats p = usedClassOwners; p != null; p = p.next)
132         p.imported = p.used >= starThreshhold;
133     for (SymRefStats p = usedClasses; p != null; p = p.next) {
134         boolean imported = false;
135         if (p.used >= useThreshhold || starred(p.clazz.owner)) {
136         imported = true;
137                 for (SymRefStats q = usedClasses; q != p; q = q.next)
138                     if (q.clazz.name == p.clazz.name) {
139                         /* Duplicate class name found in two packages -
140                         don't import one of them */

141                         if (p.implicitlyImported())
142                             q.imported = false;
143                         else imported = false;
144                         break;
145                     }
146                 if (otherPackageHasClassName(p))
147                     imported = false;
148         }
149         p.imported = imported;
150     }
151     }
152     
153     private boolean otherPackageHasClassName(SymRefStats p) {
154         for(SymRefStats r = usedClassOwners; r!=null; r=r.next)
155             if(r.imported && r.clazz != p.clazz.owner) {
156                 Scope sc = r.clazz.members();
157                 if(sc==null) continue;
158                 Scope.Entry alt = sc.lookup(p.clazz.name);
159                 if(alt.scope==sc && alt.sym.kind==Kinds.TYP)
160                     return false;
161             }
162         return true;
163     }
164             
165     private void found2(Symbol s) {
166     if (s instanceof ClassSymbol
167         && (s.owner instanceof PackageSymbol
168             || s.owner instanceof ClassSymbol)
169         && s.owner != syms.rootPackage
170         && s.owner != syms.unnamedPackage) {
171         SymRefStats ns = incref(usedClasses, s);
172         if (ns != usedClasses && s.owner != null)
173         usedClassOwners = incref(usedClassOwners, s.owner);
174         usedClasses = ns;
175     }
176     }
177     private void found(Type t) {
178     while (t instanceof Type.ArrayType)
179         t = ((Type.ArrayType) t).elemtype;
180     if (t != null && t.tag == TypeTags.CLASS)
181         found2(t.tsym);
182     if (t instanceof Type.ClassType) {
183         List < Type > typarams = ((Type.ClassType) t).typarams_field;
184         if (typarams != null)
185         for (; typarams.nonEmpty(); typarams = typarams.tail)
186             found(typarams.head);
187     }
188     }
189     private SymRefStats setImplicit(SymRefStats set, Symbol cs) {
190     for (SymRefStats p = set; p != null; p = p.next)
191         if (p.clazz == cs) {
192         p.setImplicit();
193         return set;
194         }
195     set = new SymRefStats(cs, set);
196     set.setImplicit();
197     return set;
198     }
199     private SymRefStats incref(SymRefStats set, Symbol cs) {
200     for (SymRefStats p = set; p != null; p = p.next)
201         if (p.clazz == cs) {
202         if(!p.implicitlyImported())
203             p.used++;
204         return set;
205         }
206     return new SymRefStats(cs, set);
207     }
208     public int used(SymRefStats set, Symbol cs) {
209     for (SymRefStats p = set; p != null; p = p.next)
210         if (p.clazz == cs)
211         return p.used;
212     return 0;
213     }
214     
215     @Override JavaDoc
216     public void visitTopLevel(JCCompilationUnit tree) {
217     scan(tree.defs);
218     }
219     @Override JavaDoc
220     public void visitImport(JCImport tree) {
221         // ignore existing import statements (and their qualids)
222
}
223     @Override JavaDoc
224     public void visitClassDef(JCClassDecl tree) {
225     if (tree.sym == null) return; // class wasn't parsed or in classpath
226
usedClasses = setImplicit(usedClasses, tree.sym);
227         usedClassOwners = setImplicit(usedClassOwners, tree.sym);
228         // set containing class to either the public class or first non-public.
229
if ((tree.mods.flags & Flags.PUBLIC) != 0 || containingClass == null)
230             containingClass = tree.sym;
231     super.visitClassDef(tree);
232     }
233     @Override JavaDoc
234     public void visitSelect(JCFieldAccess tree) {
235     Symbol ssym = TreeInfo.symbol(tree.selected);
236     if (ssym != null && ssym.kind == Kinds.TYP && !explicitReference(tree)) {
237         found(tree.selected.type);
238     } else if (includeExplicit || !explicitReference(tree))
239         super.visitSelect(tree);
240     }
241     @Override JavaDoc
242     public void visitIdent(JCIdent tree) {
243     if (tree.sym instanceof ClassSymbol)
244         found(tree.type);
245     }
246     @Override JavaDoc
247     public void visitErroneous(JCErroneous tree) {
248         scan(tree.errs);
249     }
250
251     /** Returns true if a select is an explicit reference, such as java.util.Set. */
252     private boolean explicitReference(JCFieldAccess tree) {
253     Symbol ssym = TreeInfo.symbol(tree.selected);
254     if (ssym != null && ssym.kind == Kinds.PCK)
255             return true;
256         return ssym != null && tree.selected.tag == JCTree.SELECT
257             ? explicitReference((JCFieldAccess)tree.selected) : false;
258     }
259
260
261     static class SymRefStats {
262     int used = 1;
263     boolean imported = false;
264     final Symbol clazz;
265     final SymRefStats next;
266     public final void setImplicit() {
267         used = implicitImport;
268     }
269     public final boolean implicitlyImported() {
270         return used == implicitImport;
271     }
272     SymRefStats (Symbol cs, SymRefStats n) {
273         clazz = cs;
274         next = n;
275     }
276     }
277 }
278
Popular Tags