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.ASTAssignmentOperator;
7 import net.sourceforge.pmd.ast.ASTExpression;
8 import net.sourceforge.pmd.ast.ASTName;
9 import net.sourceforge.pmd.ast.ASTPostfixExpression;
10 import net.sourceforge.pmd.ast.ASTPreDecrementExpression;
11 import net.sourceforge.pmd.ast.ASTPreIncrementExpression;
12 import net.sourceforge.pmd.ast.ASTPrimaryExpression;
13 import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
14 import net.sourceforge.pmd.ast.ASTStatementExpression;
15 import net.sourceforge.pmd.ast.Node;
16 import net.sourceforge.pmd.ast.SimpleNode;
17
18 public class NameOccurrence {
19
20 private SimpleNode 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(SimpleNode 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 SimpleNode getLocation() {
67 return location;
68 }
69
70 public boolean isOnRightHandSide() {
71 SimpleNode node = (SimpleNode) location.jjtGetParent().jjtGetParent().jjtGetParent();
72 return node instanceof ASTExpression && node.jjtGetNumChildren() == 3;
73 }
74
75
76 public boolean isOnLeftHandSide() {
77
78 SimpleNode primaryExpression;
79 if (location.jjtGetParent() instanceof ASTPrimaryExpression) {
80 primaryExpression = (SimpleNode) location.jjtGetParent().jjtGetParent();
81 } else if (location.jjtGetParent().jjtGetParent() instanceof ASTPrimaryExpression) {
82 primaryExpression = (SimpleNode) 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(SimpleNode primaryExpression) {
111 return ((ASTAssignmentOperator) (primaryExpression.jjtGetChild(1))).isCompound();
112 }
113
114 private boolean isStandAlonePostfix(SimpleNode 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(SimpleNode 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 * Assert it the occurrence is a self assignment such as:
134 * <code>
135 * i += 3;
136 * </code>
137 *
138 * @return true, if the occurrence is self-assignment, false, otherwise.
139 */
140 public boolean isSelfAssignment() {
141 Node l = location;
142 while (true) {
143 Node p = l.jjtGetParent();
144 Node gp = p.jjtGetParent();
145 Node node = gp.jjtGetParent();
146 if (node instanceof ASTPreDecrementExpression || node instanceof ASTPreIncrementExpression || node instanceof ASTPostfixExpression) {
147 return true;
148 }
149
150 if (node instanceof ASTStatementExpression) {
151 ASTStatementExpression exp = (ASTStatementExpression) node;
152 if (exp.jjtGetNumChildren() >= 2 && exp.jjtGetChild(1) instanceof ASTAssignmentOperator) {
153 ASTAssignmentOperator op = (ASTAssignmentOperator) exp.jjtGetChild(1);
154 if (op.isCompound()) {
155 return true;
156 }
157 }
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 if (gp instanceof ASTPreDecrementExpression || gp instanceof ASTPreIncrementExpression || gp instanceof ASTPostfixExpression) {
171 return true;
172 }
173
174 return false;
175 }
176 }
177
178 /**
179 * Simply return true is the image is equal to keyword 'this' or 'super'.
180 *
181 * @return return true if image equal to 'this' or 'super'.
182 */
183 public boolean isThisOrSuper() {
184 return image.equals(THIS) || image.equals(SUPER);
185 }
186
187 /**
188 * Simply return if the image start with keyword 'this' or 'super'.
189 *
190 * @return true, if keyword is used, false otherwise.
191 */
192 public boolean useThisOrSuper() {
193 Node node = location.jjtGetParent();
194 if ( node instanceof ASTPrimaryExpression ) {
195 ASTPrimaryExpression primaryExpression = (ASTPrimaryExpression)node;
196 ASTPrimaryPrefix prefix = primaryExpression.getFirstChildOfType(ASTPrimaryPrefix.class);
197 if ( prefix != null )
198 return (prefix.usesSuperModifier() || prefix.usesThisModifier());
199 }
200 return image.startsWith(THIS_DOT) || image.startsWith(SUPER_DOT);
201 }
202
203 @Override
204 public boolean equals(Object o) {
205 NameOccurrence n = (NameOccurrence) o;
206 return n.getImage().equals(getImage());
207 }
208
209 @Override
210 public int hashCode() {
211 return getImage().hashCode();
212 }
213
214 public String getImage() {
215 return image;
216 }
217
218 @Override
219 public String toString() {
220 return getImage() + ":" + location.getBeginLine() + ":" + location.getClass() + (this.isMethodOrConstructorInvocation() ? "(method call)" : "");
221 }
222 }