NameOccurrence.java
001 /**
002  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003  */
004 package net.sourceforge.pmd.lang.java.symboltable;
005 
006 import net.sourceforge.pmd.lang.ast.Node;
007 import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
008 import net.sourceforge.pmd.lang.java.ast.ASTExpression;
009 import net.sourceforge.pmd.lang.java.ast.ASTName;
010 import net.sourceforge.pmd.lang.java.ast.ASTPostfixExpression;
011 import net.sourceforge.pmd.lang.java.ast.ASTPreDecrementExpression;
012 import net.sourceforge.pmd.lang.java.ast.ASTPreIncrementExpression;
013 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
014 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
015 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
016 import net.sourceforge.pmd.lang.java.ast.JavaNode;
017 
018 public class NameOccurrence {
019 
020     private JavaNode location;
021     private String image;
022     private NameOccurrence qualifiedName;
023 
024     private boolean isMethodOrConstructorInvocation;
025     private int argumentCount;
026 
027     private final static String THIS = "this";
028     private final static String SUPER = "super";
029 
030     private final static String THIS_DOT = "this.";
031     private final static String SUPER_DOT = "super.";
032 
033     public NameOccurrence(JavaNode location, String image) {
034         this.location = location;
035         this.image = image;
036     }
037 
038     public void setIsMethodOrConstructorInvocation() {
039         isMethodOrConstructorInvocation = true;
040     }
041 
042     public void setArgumentCount(int count) {
043         argumentCount = count;
044     }
045 
046     public int getArgumentCount() {
047         return argumentCount;
048     }
049 
050     public boolean isMethodOrConstructorInvocation() {
051         return isMethodOrConstructorInvocation;
052     }
053 
054     public void setNameWhichThisQualifies(NameOccurrence qualifiedName) {
055         this.qualifiedName = qualifiedName;
056     }
057 
058     public NameOccurrence getNameForWhichThisIsAQualifier() {
059         return qualifiedName;
060     }
061 
062     public boolean isPartOfQualifiedName() {
063         return qualifiedName != null;
064     }
065 
066     public JavaNode getLocation() {
067         return location;
068     }
069 
070     public boolean isOnRightHandSide() {
071   Node node = location.jjtGetParent().jjtGetParent().jjtGetParent();
072         return node instanceof ASTExpression && node.jjtGetNumChildren() == 3;
073     }
074 
075 
076     public boolean isOnLeftHandSide() {
077         // I detest this method with every atom of my being
078   Node primaryExpression;
079         if (location.jjtGetParent() instanceof ASTPrimaryExpression) {
080             primaryExpression = location.jjtGetParent().jjtGetParent();
081         else if (location.jjtGetParent().jjtGetParent() instanceof ASTPrimaryExpression) {
082             primaryExpression = location.jjtGetParent().jjtGetParent().jjtGetParent();
083         else {
084             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());
085         }
086 
087         if (isStandAlonePostfix(primaryExpression)) {
088             return true;
089         }
090 
091         if (primaryExpression.jjtGetNumChildren() <= 1) {
092             return false;
093         }
094 
095         if (!(primaryExpression.jjtGetChild(1instanceof ASTAssignmentOperator)) {
096             return false;
097         }
098 
099         if (isPartOfQualifiedName() /* or is an array type */) {
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 ((ASTAssignmentOperatorprimaryExpression.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) ((ASTPrimaryExpressionprimaryExpression.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 && ((ASTNamethirdChild).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     @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 (node instanceof ASTStatementExpression) {
152                 ASTStatementExpression exp = (ASTStatementExpressionnode;
153                 if (exp.jjtGetNumChildren() >= && exp.jjtGetChild(1instanceof ASTAssignmentOperator) {
154                     ASTAssignmentOperator op = (ASTAssignmentOperatorexp.jjtGetChild(1);
155                     if (op.isCompound()) {
156                         return true;
157                     }
158                 }
159             }
160 
161             // deal with extra parenthesis: "(i)++"
162             if (instanceof ASTPrimaryPrefix && p.jjtGetNumChildren() == &&
163                     gp instanceof ASTPrimaryExpression && gp.jjtGetNumChildren() == 1&&
164                     node instanceof ASTExpression && node.jjtGetNumChildren() == &&
165                     node.jjtGetParent() instanceof ASTPrimaryPrefix && node.jjtGetParent().jjtGetNumChildren() == 1) {
166                 l = node;
167                 continue;
168             }
169 
170             // catch this.i++ or ++this.i
171             return gp instanceof ASTPreDecrementExpression || gp instanceof ASTPreIncrementExpression || gp instanceof ASTPostfixExpression;
172         }
173     }
174 
175     /**
176      * Simply return true is the image is equal to keyword 'this' or 'super'.
177      *
178      @return return true if image equal to 'this' or 'super'.
179      */
180     public boolean isThisOrSuper() {
181         return image.equals(THIS|| image.equals(SUPER);
182     }
183 
184     /**
185      * Simply return if the image start with keyword 'this' or 'super'.
186      *
187      @return true, if keyword is used, false otherwise.
188      */
189     public boolean useThisOrSuper() {
190     Node node = location.jjtGetParent();
191     if node instanceof ASTPrimaryExpression ) {
192       ASTPrimaryExpression primaryExpression = (ASTPrimaryExpression)node;
193       ASTPrimaryPrefix prefix = (ASTPrimaryPrefixprimaryExpression.jjtGetChild(0);
194       if prefix != null ) {
195           return prefix.usesSuperModifier() || prefix.usesThisModifier();
196       }
197     }
198       return image.startsWith(THIS_DOT|| image.startsWith(SUPER_DOT);
199     }
200 
201     @Override
202     public boolean equals(Object o) {
203         NameOccurrence n = (NameOccurrenceo;
204         return n.getImage().equals(getImage());
205     }
206 
207     @Override
208     public int hashCode() {
209         return getImage().hashCode();
210     }
211 
212     public String getImage() {
213         return image;
214     }
215 
216     @Override
217     public String toString() {
218         return getImage() ":" + location.getBeginLine() ":" + location.getClass() (this.isMethodOrConstructorInvocation() "(method call)" "");
219     }
220 }