1
2
3
4 package net.sourceforge.pmd.lang.java.symboltable;
5
6 import net.sourceforge.pmd.lang.ast.Node;
7 import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
8 import net.sourceforge.pmd.lang.java.ast.ASTExpression;
9 import net.sourceforge.pmd.lang.java.ast.ASTName;
10 import net.sourceforge.pmd.lang.java.ast.ASTPostfixExpression;
11 import net.sourceforge.pmd.lang.java.ast.ASTPreDecrementExpression;
12 import net.sourceforge.pmd.lang.java.ast.ASTPreIncrementExpression;
13 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
14 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
15 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
16 import net.sourceforge.pmd.lang.java.ast.JavaNode;
17
18 public class NameOccurrence {
19
20 private JavaNode location;
21 private String image;
22 private NameOccurrence qualifiedName;
23
24 private boolean isMethodOrConstructorInvocation;
25 private int argumentCount;
26
27 private final static String THIS = "this";
28 private final static String SUPER = "super";
29
30 private final static String THIS_DOT = "this.";
31 private final static String SUPER_DOT = "super.";
32
33 public NameOccurrence(JavaNode location, String image) {
34 this.location = location;
35 this.image = image;
36 }
37
38 public void setIsMethodOrConstructorInvocation() {
39 isMethodOrConstructorInvocation = true;
40 }
41
42 public void setArgumentCount(int count) {
43 argumentCount = count;
44 }
45
46 public int getArgumentCount() {
47 return argumentCount;
48 }
49
50 public boolean isMethodOrConstructorInvocation() {
51 return isMethodOrConstructorInvocation;
52 }
53
54 public void setNameWhichThisQualifies(NameOccurrence qualifiedName) {
55 this.qualifiedName = qualifiedName;
56 }
57
58 public NameOccurrence getNameForWhichThisIsAQualifier() {
59 return qualifiedName;
60 }
61
62 public boolean isPartOfQualifiedName() {
63 return qualifiedName != null;
64 }
65
66 public JavaNode getLocation() {
67 return location;
68 }
69
70 public boolean isOnRightHandSide() {
71 Node node = location.jjtGetParent().jjtGetParent().jjtGetParent();
72 return node instanceof ASTExpression && node.jjtGetNumChildren() == 3;
73 }
74
75
76 public boolean isOnLeftHandSide() {
77
78 Node primaryExpression;
79 if (location.jjtGetParent() instanceof ASTPrimaryExpression) {
80 primaryExpression = location.jjtGetParent().jjtGetParent();
81 } else if (location.jjtGetParent().jjtGetParent() instanceof ASTPrimaryExpression) {
82 primaryExpression = location.jjtGetParent().jjtGetParent().jjtGetParent();
83 } else {
84 throw new RuntimeException("Found a NameOccurrence that didn't have an ASTPrimary Expression as parent or grandparent. Parent = " + location.jjtGetParent() + " and grandparent = " + location.jjtGetParent().jjtGetParent());
85 }
86
87 if (isStandAlonePostfix(primaryExpression)) {
88 return true;
89 }
90
91 if (primaryExpression.jjtGetNumChildren() <= 1) {
92 return false;
93 }
94
95 if (!(primaryExpression.jjtGetChild(1) instanceof ASTAssignmentOperator)) {
96 return false;
97 }
98
99 if (isPartOfQualifiedName()
100 return false;
101 }
102
103 if (isCompoundAssignment(primaryExpression)) {
104 return false;
105 }
106
107 return true;
108 }
109
110 private boolean isCompoundAssignment(Node primaryExpression) {
111 return ((ASTAssignmentOperator) primaryExpression.jjtGetChild(1)).isCompound();
112 }
113
114 private boolean isStandAlonePostfix(Node primaryExpression) {
115 if (!(primaryExpression instanceof ASTPostfixExpression) || !(primaryExpression.jjtGetParent() instanceof ASTStatementExpression)) {
116 return false;
117 }
118
119 ASTPrimaryPrefix pf = (ASTPrimaryPrefix) ((ASTPrimaryExpression) primaryExpression.jjtGetChild(0)).jjtGetChild(0);
120 if (pf.usesThisModifier()) {
121 return true;
122 }
123
124 return thirdChildHasDottedName(primaryExpression);
125 }
126
127 private boolean thirdChildHasDottedName(Node primaryExpression) {
128 Node thirdChild = primaryExpression.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0);
129 return thirdChild instanceof ASTName && ((ASTName) thirdChild).getImage().indexOf('.') == -1;
130 }
131
132
133
134
135
136
137
138
139
140 @SuppressWarnings("PMD.AvoidBranchingStatementAsLastInLoop")
141 public boolean isSelfAssignment() {
142 Node l = location;
143 while (true) {
144 Node p = l.jjtGetParent();
145 Node gp = p.jjtGetParent();
146 Node node = gp.jjtGetParent();
147 if (node instanceof ASTPreDecrementExpression || node instanceof ASTPreIncrementExpression || node instanceof ASTPostfixExpression) {
148 return true;
149 }
150
151 if (hasAssignmentOperator(gp)) {
152 return isCompoundAssignment(gp);
153 }
154
155 if (hasAssignmentOperator(node)) {
156 return isCompoundAssignment(node);
157 }
158
159
160 if (p instanceof ASTPrimaryPrefix && p.jjtGetNumChildren() == 1 &&
161 gp instanceof ASTPrimaryExpression && gp.jjtGetNumChildren() == 1&&
162 node instanceof ASTExpression && node.jjtGetNumChildren() == 1 &&
163 node.jjtGetParent() instanceof ASTPrimaryPrefix && node.jjtGetParent().jjtGetNumChildren() == 1) {
164 l = node;
165 continue;
166 }
167
168
169 return gp instanceof ASTPreDecrementExpression || gp instanceof ASTPreIncrementExpression || gp instanceof ASTPostfixExpression;
170 }
171 }
172
173 private boolean hasAssignmentOperator(Node node) {
174 if (node instanceof ASTStatementExpression || node instanceof ASTExpression) {
175 if (node.jjtGetNumChildren() >= 2 && node.jjtGetChild(1) instanceof ASTAssignmentOperator) {
176 return true;
177 }
178 }
179 return false;
180 }
181
182
183
184
185
186
187 public boolean isThisOrSuper() {
188 return image.equals(THIS) || image.equals(SUPER);
189 }
190
191
192
193
194
195
196 public boolean useThisOrSuper() {
197 Node node = location.jjtGetParent();
198 if ( node instanceof ASTPrimaryExpression ) {
199 ASTPrimaryExpression primaryExpression = (ASTPrimaryExpression)node;
200 ASTPrimaryPrefix prefix = (ASTPrimaryPrefix) primaryExpression.jjtGetChild(0);
201 if ( prefix != null ) {
202 return prefix.usesSuperModifier() || prefix.usesThisModifier();
203 }
204 }
205 return image.startsWith(THIS_DOT) || image.startsWith(SUPER_DOT);
206 }
207
208 @Override
209 public boolean equals(Object o) {
210 if (o instanceof NameOccurrence) {
211 NameOccurrence n = (NameOccurrence) o;
212 return n.getImage().equals(getImage());
213 }
214 return false;
215 }
216
217 @Override
218 public int hashCode() {
219 return getImage().hashCode();
220 }
221
222 public String getImage() {
223 return image;
224 }
225
226 @Override
227 public String toString() {
228 return getImage() + ":" + location.getBeginLine() + ":" + location.getClass() + (this.isMethodOrConstructorInvocation() ? "(method call)" : "");
229 }
230 }