View Javadoc

    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      public NameOccurrence(SimpleNode location, String image) {
    28          this.location = location;
    29          this.image = image;
    30      }
    31
    32      public void setIsMethodOrConstructorInvocation() {
    33          isMethodOrConstructorInvocation = true;
    34      }
    35
    36      public void setArgumentCount(int count) {
    37          argumentCount = count;
    38      }
    39
    40      public int getArgumentCount() {
    41          return argumentCount;
    42      }
    43
    44      public boolean isMethodOrConstructorInvocation() {
    45          return isMethodOrConstructorInvocation;
    46      }
    47
    48      public void setNameWhichThisQualifies(NameOccurrence qualifiedName) {
    49          this.qualifiedName = qualifiedName;
    50      }
    51
    52      public NameOccurrence getNameForWhichThisIsAQualifier() {
    53          return qualifiedName;
    54      }
    55
    56      public boolean isPartOfQualifiedName() {
    57          return qualifiedName != null;
    58      }
    59
    60      public SimpleNode getLocation() {
    61          return location;
    62      }
    63
    64      public boolean isOnRightHandSide() {
    65          SimpleNode node = (SimpleNode) location.jjtGetParent().jjtGetParent().jjtGetParent();
    66          return node instanceof ASTExpression && node.jjtGetNumChildren() == 3;
    67      }
    68
    69
    70      public boolean isOnLeftHandSide() {
    71          // I detest this method with every atom of my being
    72          SimpleNode primaryExpression;
    73          if (location.jjtGetParent() instanceof ASTPrimaryExpression) {
    74              primaryExpression = (SimpleNode) location.jjtGetParent().jjtGetParent();
    75          } else if (location.jjtGetParent().jjtGetParent() instanceof ASTPrimaryExpression) {
    76              primaryExpression = (SimpleNode) location.jjtGetParent().jjtGetParent().jjtGetParent();
    77          } else {
    78              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());
    79          }
    80
    81          if (isStandAlonePostfix(primaryExpression)) {
    82              return true;
    83          }
    84
    85          if (primaryExpression.jjtGetNumChildren() <= 1) {
    86              return false;
    87          }
    88
    89          if (!(primaryExpression.jjtGetChild(1) instanceof ASTAssignmentOperator)) {
    90              return false;
    91          }
    92
    93          if (isPartOfQualifiedName() /* or is an array type */) {
    94              return false;
    95          }
    96
    97          if (isCompoundAssignment(primaryExpression)) {
    98              return false;
    99          }
    100
    101         return true;
    102     }
    103
    104     private boolean isCompoundAssignment(SimpleNode primaryExpression) {
    105         return ((ASTAssignmentOperator) (primaryExpression.jjtGetChild(1))).isCompound();
    106     }
    107
    108     private boolean isStandAlonePostfix(SimpleNode primaryExpression) {
    109         if (!(primaryExpression instanceof ASTPostfixExpression) || !(primaryExpression.jjtGetParent() instanceof ASTStatementExpression)) {
    110             return false;
    111         }
    112
    113         ASTPrimaryPrefix pf = (ASTPrimaryPrefix) ((ASTPrimaryExpression) primaryExpression.jjtGetChild(0)).jjtGetChild(0);
    114         if (pf.usesThisModifier()) {
    115             return true;
    116         }
    117
    118         return thirdChildHasDottedName(primaryExpression);
    119     }
    120
    121     private boolean thirdChildHasDottedName(SimpleNode primaryExpression) {
    122         Node thirdChild = primaryExpression.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0);
    123         return thirdChild instanceof ASTName && ((ASTName) thirdChild).getImage().indexOf('.') == -1;
    124     }
    125
    126     public boolean isSelfAssignment() {
    127         Node l = location;
    128         while (true) {
    129             Node p = l.jjtGetParent();
    130             Node gp = p.jjtGetParent();
    131             Node node = gp.jjtGetParent();
    132             if (node instanceof ASTPreDecrementExpression || node instanceof ASTPreIncrementExpression || node instanceof ASTPostfixExpression) {
    133                 return true;
    134             }
    135
    136             if (node instanceof ASTStatementExpression) {
    137                 ASTStatementExpression exp = (ASTStatementExpression) node;
    138                 if (exp.jjtGetNumChildren() >= 2 && exp.jjtGetChild(1) instanceof ASTAssignmentOperator) {
    139                     ASTAssignmentOperator op = (ASTAssignmentOperator) exp.jjtGetChild(1);
    140                     if (op.isCompound()) {
    141                         return true;
    142                     }
    143                 }
    144             }
    145
    146             // deal with extra parenthesis: "(i)++"
    147             if (p instanceof ASTPrimaryPrefix && p.jjtGetNumChildren() == 1 &&
    148                     gp instanceof ASTPrimaryExpression && gp.jjtGetNumChildren() == 1&&
    149                     node instanceof ASTExpression && node.jjtGetNumChildren() == 1 &&
    150                     node.jjtGetParent() instanceof ASTPrimaryPrefix && node.jjtGetParent().jjtGetNumChildren() == 1) {
    151                 l = node;
    152                 continue;
    153             }
    154
    155             return false;
    156         }
    157     }
    158
    159     public boolean isThisOrSuper() {
    160         return image.equals("this") || image.equals("super");
    161     }
    162
    163     public boolean equals(Object o) {
    164         NameOccurrence n = (NameOccurrence) o;
    165         return n.getImage().equals(getImage());
    166     }
    167
    168     public int hashCode() {
    169         return getImage().hashCode();
    170     }
    171
    172     public String getImage() {
    173         return image;
    174     }
    175
    176     public String toString() {
    177         return getImage() + ":" + location.getBeginLine() + ":" + location.getClass() + (this.isMethodOrConstructorInvocation() ? "(method call)" : "");
    178     }
    179 }