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