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