View Javadoc

    1   /***
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.rules;
    5
    6   import net.sourceforge.pmd.CommonAbstractRule;
    7   import net.sourceforge.pmd.RuleContext;
    8   import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
    9   import net.sourceforge.pmd.ast.Node;
    10  import net.sourceforge.pmd.ast.SimpleNode;
    11  import net.sourceforge.pmd.jaxen.DocumentNavigator;
    12  import net.sourceforge.pmd.jaxen.MatchesFunction;
    13  import org.jaxen.BaseXPath;
    14  import org.jaxen.JaxenException;
    15  import org.jaxen.SimpleVariableContext;
    16  import org.jaxen.XPath;
    17
    18  import java.io.PrintStream;
    19  import java.io.PrintWriter;
    20  import java.util.Iterator;
    21  import java.util.List;
    22  import java.util.Map.Entry;
    23
    24  /***
    25   * Rule that tries to match an XPath expression against a DOM
    26   * view of the AST of a "compilation unit".
    27   * <p/>
    28   * This rule needs a property "xpath".
    29   */
    30  public class XPathRule extends CommonAbstractRule {
    31
    32      private XPath xpath;
    33      private boolean regexpFunctionRegistered;
    34
    35      /***
    36       * Evaluate the AST with compilationUnit as root-node, against
    37       * the XPath expression found as property with name "xpath".
    38       * All matches are reported as violations.
    39       *
    40       * @param compilationUnit the Node that is the root of the AST to be checked
    41       * @param data
    42       * @return
    43       */
    44      public void evaluate(Node compilationUnit, RuleContext data) {
    45          try {
    46              initializeXPathExpression();
    47              List results = xpath.selectNodes(compilationUnit);
    48              for (Iterator i = results.iterator(); i.hasNext();) {
    49                  SimpleNode n = (SimpleNode) i.next();
    50                  if (n instanceof ASTVariableDeclaratorId && getBooleanProperty("pluginname")) {
    51                      addViolation(data, n, n.getImage());
    52                  } else {
    53                      addViolation(data, (SimpleNode) n, getMessage());
    54                  }
    55              }
    56          } catch (JaxenException ex) {
    57              throwJaxenAsRuntime(ex);
    58          }
    59      }
    60
    61      private void initializeXPathExpression() throws JaxenException {
    62          if (xpath != null) {
    63              return;
    64          }
    65
    66          if (!regexpFunctionRegistered) {
    67              MatchesFunction.registerSelfInSimpleContext();
    68              regexpFunctionRegistered = true;
    69          }
    70
    71          xpath = new BaseXPath(getStringProperty("xpath"), new DocumentNavigator());
    72          if (properties.size() > 1) {
    73              SimpleVariableContext vc = new SimpleVariableContext();
    74              for (Iterator i = properties.entrySet().iterator(); i.hasNext();) {
    75                  Entry e = (Entry) i.next();
    76                  if (!"xpath".equals(e.getKey())) {
    77                      vc.setVariableValue((String) e.getKey(), e.getValue());
    78                  }
    79              }
    80              xpath.setVariableContext(vc);
    81          }
    82      }
    83
    84      private static void throwJaxenAsRuntime(final JaxenException ex) {
    85          throw new RuntimeException() {
    86              public void printStackTrace() {
    87                  super.printStackTrace();
    88                  ex.printStackTrace();
    89              }
    90
    91              public void printStackTrace(PrintWriter writer) {
    92                  super.printStackTrace(writer);
    93                  ex.printStackTrace(writer);
    94              }
    95
    96              public void printStackTrace(PrintStream stream) {
    97                  super.printStackTrace(stream);
    98                  ex.printStackTrace(stream);
    99              }
    100
    101             public String getMessage() {
    102                 return super.getMessage() + ex.getMessage();
    103             }
    104         };
    105     }
    106
    107     /***
    108      * Apply the rule to all compilation units.
    109      */
    110     public void apply(List astCompilationUnits, RuleContext ctx) {
    111         for (Iterator i = astCompilationUnits.iterator(); i.hasNext();) {
    112             evaluate((Node) i.next(), ctx);
    113         }
    114     }
    115 }