Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 180 |  | Methods: | 14
| NCLOC: | 128 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
ClassScope.java | 68.4% | 76.5% | 92.9% | 75.8% |

1 |  | /**
2 |  | * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 |  | */
4 |  | package net.sourceforge.pmd.symboltable;
5 |  |
6 |  | import net.sourceforge.pmd.ast.ASTName;
7 |  | import net.sourceforge.pmd.ast.SimpleNode;
8 |  | import net.sourceforge.pmd.util.Applier;
9 |  |
10 |  | import java.util.ArrayList;
11 |  | import java.util.HashMap;
12 |  | import java.util.Iterator;
13 |  | import java.util.List;
14 |  | import java.util.Map;
15 |  |
16 |  | public class ClassScope extends AbstractScope {
17 |  |
18 |  | protected Map classNames = new HashMap();
19 |  | protected Map methodNames = new HashMap();
20 |  | protected Map variableNames = new HashMap();
21 |  |
22 |  | // FIXME - this breaks given sufficiently nested code
23 |  | private static int anonymousInnerClassCounter = 1;
24 |  | private String className;
25 |  |
26 | 1389 | public ClassScope(String className) {
27 | 1389 | this.className = className;
28 | 1389 | anonymousInnerClassCounter = 1;
29 |  | }
30 |  |
31 |  | /**
32 |  | * This is only for anonymous inner classes
33 |  | * <p/>
34 |  | * FIXME - should have name like Foo$1, not Anonymous$1
35 |  | * to get this working right, the parent scope needs
36 |  | * to be passed in when instantiating a ClassScope
37 |  | */
38 | 16 | public ClassScope() {
39 |  | //this.className = getParent().getEnclosingClassScope().getClassName() + "$" + String.valueOf(anonymousInnerClassCounter);
40 | 16 | this.className = "Anonymous$" + anonymousInnerClassCounter;
41 | 16 | anonymousInnerClassCounter++;
42 |  | }
43 |  |
44 | 437 | public void addDeclaration(VariableNameDeclaration variableDecl) {
45 | 437 | if (variableNames.containsKey(variableDecl)) {
46 | 0 | throw new RuntimeException(variableDecl + " is already in the symbol table");
47 |  | }
48 | 437 | variableNames.put(variableDecl, new ArrayList());
49 |  | }
50 |  |
51 | 340 | public NameDeclaration addVariableNameOccurrence(NameOccurrence occurrence) {
52 | 340 | NameDeclaration decl = findVariableHere(occurrence);
53 | 340 | if (decl != null && occurrence.isMethodOrConstructorInvocation()) {
54 | 82 | List nameOccurrences = (List) methodNames.get(decl);
55 | 82 | if (nameOccurrences == null) {
56 |  | // TODO may be a class name: Foo.this.super();
57 |  | } else {
58 | 82 | nameOccurrences.add(occurrence);
59 | 82 | SimpleNode n = occurrence.getLocation();
60 | 82 | if (n instanceof ASTName) {
61 | 57 | ((ASTName) n).setNameDeclaration(decl);
62 |  | } // TODO what to do with PrimarySuffix case?
63 |  | }
64 |  |
65 | 258 | } else if (decl != null && !occurrence.isThisOrSuper()) {
66 | 188 | List nameOccurrences = (List) variableNames.get(decl);
67 | 188 | if (nameOccurrences == null) {
68 |  | // TODO may be a class name
69 |  | } else {
70 | 188 | nameOccurrences.add(occurrence);
71 | 188 | SimpleNode n = occurrence.getLocation();
72 | 188 | if (n instanceof ASTName) {
73 | 159 | ((ASTName) n).setNameDeclaration(decl);
74 |  | } // TODO what to do with PrimarySuffix case?
75 |  | }
76 |  | }
77 | 340 | return decl;
78 |  | }
79 |  |
80 | 87 | public Map getVariableDeclarations() {
81 | 87 | VariableUsageFinderFunction f = new VariableUsageFinderFunction(variableNames);
82 | 87 | Applier.apply(f, variableNames.keySet().iterator());
83 | 87 | return f.getUsed();
84 |  | }
85 |  |
86 | 39 | public Map getMethodDeclarations() {
87 | 39 | return methodNames;
88 |  | }
89 |  |
90 | 1 | public Map getClassDeclarations() {
91 | 1 | return classNames;
92 |  | }
93 |  |
94 | 2675 | public ClassScope getEnclosingClassScope() {
95 | 2675 | return this;
96 |  | }
97 |  |
98 | 1130 | public String getClassName() {
99 | 1130 | return this.className;
100 |  | }
101 |  |
102 | 1090 | public void addDeclaration(MethodNameDeclaration decl) {
103 | 1090 | methodNames.put(decl, new ArrayList());
104 |  | }
105 |  |
106 | 70 | public void addDeclaration(ClassNameDeclaration decl) {
107 | 70 | classNames.put(decl, new ArrayList());
108 |  | }
109 |  |
110 | 2044 | protected NameDeclaration findVariableHere(NameOccurrence occurrence) {
111 | 2044 | if (occurrence.isThisOrSuper() || occurrence.getImage().equals(className)) {
112 | 234 | if (variableNames.isEmpty() && methodNames.isEmpty()) {
113 |  | // this could happen if you do this:
114 |  | // public class Foo {
115 |  | // private String x = super.toString();
116 |  | // }
117 | 0 | return null;
118 |  | }
119 |  | // return any name declaration, since all we really want is to get the scope
120 |  | // for example, if there's a
121 |  | // public class Foo {
122 |  | // private static final int X = 2;
123 |  | // private int y = Foo.X;
124 |  | // }
125 |  | // we'll look up Foo just to get a handle to the class scope
126 |  | // and then we'll look up X.
127 | 234 | if (!variableNames.isEmpty()) {
128 | 120 | return (NameDeclaration) variableNames.keySet().iterator().next();
129 |  | }
130 | 114 | return (NameDeclaration) methodNames.keySet().iterator().next();
131 |  | }
132 |  |
133 | 1810 | if (occurrence.isMethodOrConstructorInvocation()) {
134 | 925 | for (Iterator i = methodNames.keySet().iterator(); i.hasNext();) {
135 | 925 | MethodNameDeclaration mnd = (MethodNameDeclaration) i.next();
136 | 925 | if (mnd.getImage().equals(occurrence.getImage())) {
137 | 255 | int args = occurrence.getArgumentCount();
138 | 255 | if (args == mnd.getParameterCount()) {
139 |  | // FIXME if several methods have the same name
140 |  | // and parameter count, only one will get caught here
141 |  | // we need to make some attempt at type lookup and discrimination
142 |  | // or, failing that, mark this as a usage of all those methods
143 | 246 | return mnd;
144 |  | }
145 |  | }
146 |  | }
147 | 679 | return null;
148 |  | }
149 |  |
150 | 885 | List images = new ArrayList();
151 | 885 | images.add(occurrence.getImage());
152 | 885 | if (occurrence.getImage().startsWith(className)) {
153 | 1 | images.add(clipClassName(occurrence.getImage()));
154 |  | }
155 | 885 | ImageFinderFunction finder = new ImageFinderFunction(images);
156 | 885 | Applier.apply(finder, variableNames.keySet().iterator());
157 | 885 | return finder.getDecl();
158 |  | }
159 |  |
160 | 0 | public String toString() {
161 | 0 | String res = "ClassScope (" + className + "): ";
162 | 0 | if (!classNames.isEmpty()) res += "(" + glomNames(classNames.keySet().iterator()) + ")";
163 | 0 | if (!methodNames.isEmpty()) {
164 | 0 | Iterator i = methodNames.keySet().iterator();
165 | 0 | while (i.hasNext()) {
166 | 0 | MethodNameDeclaration mnd = (MethodNameDeclaration) i.next();
167 | 0 | res += mnd.toString();
168 | 0 | int usages = ((List) methodNames.get(mnd)).size();
169 | 0 | res += "(begins at line " + mnd.getNode().getBeginLine() + ", " + usages + " usages)";
170 | 0 | res += ",";
171 |  | }
172 |  | }
173 | 0 | if (!variableNames.isEmpty()) res += "(" + glomNames(variableNames.keySet().iterator()) + ")";
174 | 0 | return res;
175 |  | }
176 |  |
177 | 1 | private String clipClassName(String in) {
178 | 1 | return in.substring(in.indexOf('.') + 1);
179 |  | }
180 |  | }