001: /*
002: * @(#)MemberDependenceAnalyzer.java 1.21 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package dependenceAnalyzer;
029:
030: import util.*;
031: import java.io.FilenameFilter;
032: import java.util.Enumeration;
033: import java.util.Dictionary;
034: import java.util.Hashtable;
035:
036: /*
037: * This is the main class for member-level dependence analysis
038: * of Java code. The most well-developed example of this is, of course,
039: * JavaFilter. See also the class util.DepgenUtil for some
040: * higher-level functions that operate on this class, without
041: * constituting a main program.
042: */
043:
044: public class MemberDependenceAnalyzer extends DependenceAnalyzer {
045: public boolean signatureFlag = false;
046:
047: public MemberDependenceAnalyzer(ClassFileFinder find,
048: FilenameFilter filt) {
049: super ();
050: cdict = new ClassDictionary(find, filt);
051: }
052:
053: public void useSignatureDependence(boolean f) {
054: signatureFlag = f;
055: }
056:
057: /*
058: * This analyzer maintains a name-to-node dictionary of
059: * its graph. This lets you lookup nodes by name. It will
060: * return null if the named entity is not in the graph.
061: * Actually, each class maintains such. Use them.
062: */
063: public DependenceNode nodeByName(Object name) {
064: MemberName mname = (MemberName) name;
065: return mname.classEntry.lookupMember(mname);
066: }
067:
068: /*
069: * To conditionally add a node to the graph. It is not
070: * an error to add something that's already in the graph.
071: * The return value is a DependenceNode. It may be
072: * in any state, but if it was not in the graph previous to
073: * this call, it will certainly be DependenceNode.UNANALYZED.
074: * In other words, this call doesn't cause analysis.
075: */
076: public DependenceNode addNodeByName(Object name) {
077: MemberName mname = (MemberName) name;
078: return mname.classEntry.lookupAddMember(mname, 0);
079: }
080:
081: public Enumeration allNodes() {
082: return new MemberEnumeration(allClasses());
083: }
084:
085: /*
086: * To cause the state of a node to move from UNANALYZED,
087: * one hopes to ANALYZED, but perhaps to ERROR.
088: * Return value is the new state of the node.
089: */
090: public int analyzeDependences(DependenceNode n) {
091: if (n.state() != DependenceNode.UNANALYZED)
092: return n.state();
093: ClassEntry c;
094: if (n instanceof ClassEntry) {
095: c = (ClassEntry) n;
096: } else {
097: c = ((MemberName) (n.nodeName)).classEntry;
098: }
099: if (c.state() == ClassEntry.UNANALYZED) {
100: c.analyzeClass(cdict, signatureFlag);
101: }
102: switch (c.state()) {
103: case ClassEntry.ERROR:
104: return (n.nodeState = DependenceNode.ERROR);
105: case ClassEntry.ANALYZED:
106: return n.nodeState;
107: }
108: // this cannot happen!
109: throw new RuntimeException(Localizer.getString(
110: "memberdependenceanalyzer.class_remains_unanalyzed", c
111: .name()));
112: }
113:
114: public Enumeration allClasses() {
115: if (cdict == null)
116: return EmptyEnumeration.instance;
117: return cdict.elements();
118: }
119:
120: public ClassEntry classByName(String cname) {
121: return cdict.lookupAdd(cname);
122: }
123:
124: public boolean makeInterface(ClassEntry c) {
125: return c.makeInterface(cdict);
126: }
127:
128: /*
129: * Protection loophole.
130: * This exists so that the calling program can add edges
131: * to the dependence graph, in addition to the ones discovered
132: * by the processing in class ClassEntry. JavaFilter, for
133: * example, allows the user to describe the dependences of
134: * native code, which cannot be discovered automatically.
135: * This is because native code might have a dependence on
136: * a data member that is not referenced by any Java code!
137: */
138: public void addDependenceArc(DependenceNode fromNode,
139: DependenceNode toNode, int arcType) {
140: DependenceArc a = new DependenceArc(fromNode, toNode, arcType);
141: fromNode.nodeDependsOn.add(a);
142: toNode.nodeDependedOn.add(a);
143: }
144:
145: /*
146: * State. Not public.
147: */
148: //
149: ClassDictionary cdict; // encapsulation of all class naming and lookup.
150: }
151:
152: class MemberEnumeration implements Enumeration {
153: private Enumeration curEnumeration;
154: private Enumeration classes;
155:
156: MemberEnumeration(Enumeration c) {
157: if (c == null) {
158: curEnumeration = EmptyEnumeration.instance;
159: } else {
160: classes = c;
161: nextEnumeration();
162: }
163: }
164:
165: public boolean hasMoreElements() {
166: if (curEnumeration.hasMoreElements())
167: return true;
168: nextEnumeration();
169: return curEnumeration.hasMoreElements();
170: }
171:
172: public Object nextElement() {
173: while (true) {
174: try {
175: Object o = curEnumeration.nextElement();
176: // got one. Return it.
177: return o;
178: } catch (java.util.NoSuchElementException e) {
179: // user called nextElement without calling
180: // hasMoreElements first. This is unusual,
181: // but not strictly illegal. If this is the
182: // empty enumeration, then there is no more
183: // so we just re-throw the exception. Otherwise
184: // we move on to the next class.
185: if (curEnumeration == EmptyEnumeration.instance)
186: throw e;
187: nextEnumeration();
188: }
189: }
190: }
191:
192: private void nextEnumeration() {
193: while (classes.hasMoreElements()) {
194: ClassEntry v = (ClassEntry) (classes.nextElement());
195: Enumeration e = v.members();
196: if ((e != null) && e.hasMoreElements()) {
197: curEnumeration = e;
198: return;
199: }
200: }
201: curEnumeration = EmptyEnumeration.instance; // bad news.
202: }
203: }
|