Coverage Report - com.puppycrawl.tools.checkstyle.filters.XpathFilter
 
Classes in this File Line Coverage Branch Coverage Complexity
XpathFilter
100%
66/66
100%
64/64
5.125
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2017 the original author or authors.
 4  
 //
 5  
 // This library is free software; you can redistribute it and/or
 6  
 // modify it under the terms of the GNU Lesser General Public
 7  
 // License as published by the Free Software Foundation; either
 8  
 // version 2.1 of the License, or (at your option) any later version.
 9  
 //
 10  
 // This library is distributed in the hope that it will be useful,
 11  
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 // Lesser General Public License for more details.
 14  
 //
 15  
 // You should have received a copy of the GNU Lesser General Public
 16  
 // License along with this library; if not, write to the Free Software
 17  
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18  
 ////////////////////////////////////////////////////////////////////////////////
 19  
 
 20  
 package com.puppycrawl.tools.checkstyle.filters;
 21  
 
 22  
 import java.util.List;
 23  
 import java.util.Objects;
 24  
 import java.util.regex.Pattern;
 25  
 
 26  
 import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent;
 27  
 import com.puppycrawl.tools.checkstyle.TreeWalkerFilter;
 28  
 import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
 29  
 import com.puppycrawl.tools.checkstyle.xpath.AbstractNode;
 30  
 import com.puppycrawl.tools.checkstyle.xpath.RootNode;
 31  
 import net.sf.saxon.om.Item;
 32  
 import net.sf.saxon.sxpath.XPathDynamicContext;
 33  
 import net.sf.saxon.sxpath.XPathEvaluator;
 34  
 import net.sf.saxon.sxpath.XPathExpression;
 35  
 import net.sf.saxon.trans.XPathException;
 36  
 
 37  
 /**
 38  
  * This filter processes {@link TreeWalkerAuditEvent}
 39  
  * objects based on the criteria of file, check, module id, xpathQuery.
 40  
  *
 41  
  * @author Timur Tibeyev.
 42  
  */
 43  
 public class XpathFilter implements TreeWalkerFilter {
 44  
     /** The regexp to match file names against. */
 45  
     private final Pattern fileRegexp;
 46  
 
 47  
     /** The pattern for file names. */
 48  
     private final String filePattern;
 49  
 
 50  
     /** The regexp to match check names against. */
 51  
     private final Pattern checkRegexp;
 52  
 
 53  
     /** The pattern for check class names. */
 54  
     private final String checkPattern;
 55  
 
 56  
     /** The regexp to match message names against. */
 57  
     private final Pattern messageRegexp;
 58  
 
 59  
     /** The pattern for message names. */
 60  
     private final String messagePattern;
 61  
 
 62  
     /** Module id filter. */
 63  
     private final String moduleId;
 64  
 
 65  
     /** Xpath expression. */
 66  
     private final XPathExpression xpathExpression;
 67  
 
 68  
     /** Xpath query. */
 69  
     private final String xpathQuery;
 70  
 
 71  
     /**
 72  
      * Creates a {@code XpathElement} instance.
 73  
      * @param files regular expression for names of filtered files
 74  
      * @param checks regular expression for filtered check classes
 75  
      * @param message regular expression for messages.
 76  
      * @param moduleId the module id
 77  
      * @param query the xpath query
 78  
      */
 79  
     public XpathFilter(String files, String checks,
 80  28
                        String message, String moduleId, String query) {
 81  28
         filePattern = files;
 82  28
         if (files == null) {
 83  4
             fileRegexp = null;
 84  
         }
 85  
         else {
 86  24
             fileRegexp = Pattern.compile(files);
 87  
         }
 88  26
         checkPattern = checks;
 89  26
         if (checks == null) {
 90  9
             checkRegexp = null;
 91  
         }
 92  
         else {
 93  17
             checkRegexp = CommonUtils.createPattern(checks);
 94  
         }
 95  26
         messagePattern = message;
 96  26
         if (message == null) {
 97  22
             messageRegexp = null;
 98  
         }
 99  
         else {
 100  4
             messageRegexp = Pattern.compile(message);
 101  
         }
 102  26
         this.moduleId = moduleId;
 103  26
         xpathQuery = query;
 104  26
         if (xpathQuery == null) {
 105  4
             xpathExpression = null;
 106  
         }
 107  
         else {
 108  22
             final XPathEvaluator xpathEvaluator = new XPathEvaluator();
 109  
             try {
 110  22
                 xpathExpression = xpathEvaluator.createExpression(xpathQuery);
 111  
             }
 112  1
             catch (XPathException ex) {
 113  1
                 throw new IllegalStateException("Unexpected xpath query: " + xpathQuery, ex);
 114  21
             }
 115  
         }
 116  25
     }
 117  
 
 118  
     @Override
 119  
     public boolean accept(TreeWalkerAuditEvent event) {
 120  41
         return !isFileNameAndModuleAndCheckNameMatching(event)
 121  14
                 || !isMessageNameMatching(event)
 122  13
                 || !isXpathQueryMatching(event);
 123  
     }
 124  
 
 125  
     /**
 126  
      * Is matching by file name, moduleId and Check name.
 127  
      * @param event event
 128  
      * @return true if it is matching
 129  
      */
 130  
     private boolean isFileNameAndModuleAndCheckNameMatching(TreeWalkerAuditEvent event) {
 131  42
         return event.getFileName() != null
 132  18
                 && (fileRegexp == null || fileRegexp.matcher(event.getFileName()).find())
 133  19
                 && event.getLocalizedMessage() != null
 134  4
                 && (moduleId == null || moduleId.equals(event.getModuleId()))
 135  12
                 && (checkRegexp == null || checkRegexp.matcher(event.getSourceName()).find());
 136  
     }
 137  
 
 138  
     /**
 139  
      * Is matching by message.
 140  
      * @param event event
 141  
      * @return true is matching or not set.
 142  
      */
 143  
     private boolean isMessageNameMatching(TreeWalkerAuditEvent event) {
 144  14
         return messageRegexp == null || messageRegexp.matcher(event.getMessage()).find();
 145  
     }
 146  
 
 147  
     /**
 148  
      * Is matching by xpath query.
 149  
      * @param event event
 150  
      * @return true is matching
 151  
      */
 152  
     private boolean isXpathQueryMatching(TreeWalkerAuditEvent event) {
 153  
         boolean isMatching;
 154  13
         if (xpathExpression == null) {
 155  2
             isMatching = true;
 156  
         }
 157  
         else {
 158  11
             isMatching = false;
 159  11
             final List<Item> items = getItems(event);
 160  10
             for (Item item : items) {
 161  11
                 final AbstractNode abstractNode = (AbstractNode) item;
 162  11
                 isMatching = abstractNode.getTokenType() == event.getTokenType()
 163  10
                         && abstractNode.getLineNumber() == event.getLine()
 164  6
                         && abstractNode.getColumnNumber() == event.getColumnCharIndex();
 165  11
                 if (isMatching) {
 166  5
                     break;
 167  
                 }
 168  6
             }
 169  
         }
 170  12
         return isMatching;
 171  
     }
 172  
 
 173  
     /**
 174  
      * Returns list of nodes matching xpath expression given event.
 175  
      * @param event {@code TreeWalkerAuditEvent} object
 176  
      * @return list of nodes matching xpath expression given event
 177  
      */
 178  
     private List<Item> getItems(TreeWalkerAuditEvent event) {
 179  
         final RootNode rootNode;
 180  11
         if (event.getRootAst() == null) {
 181  1
             rootNode = null;
 182  
         }
 183  
         else {
 184  10
             rootNode = new RootNode(event.getRootAst());
 185  
         }
 186  
         final List<Item> items;
 187  
         try {
 188  11
             final XPathDynamicContext xpathDynamicContext =
 189  11
                     xpathExpression.createDynamicContext(rootNode);
 190  11
             items = xpathExpression.evaluate(xpathDynamicContext);
 191  
         }
 192  1
         catch (XPathException ex) {
 193  1
             throw new IllegalStateException("Cannot initialize context and evaluate query: "
 194  
                     + xpathQuery, ex);
 195  10
         }
 196  10
         return items;
 197  
     }
 198  
 
 199  
     @Override
 200  
     public int hashCode() {
 201  62
         return Objects.hash(filePattern, checkPattern, messagePattern, moduleId, xpathQuery);
 202  
     }
 203  
 
 204  
     @Override
 205  
     public boolean equals(Object other) {
 206  188
         if (this == other) {
 207  2
             return true;
 208  
         }
 209  186
         if (other == null || getClass() != other.getClass()) {
 210  5
             return false;
 211  
         }
 212  181
         final XpathFilter xpathFilter = (XpathFilter) other;
 213  362
         return Objects.equals(filePattern, xpathFilter.filePattern)
 214  154
                 && Objects.equals(checkPattern, xpathFilter.checkPattern)
 215  144
                 && Objects.equals(messagePattern, xpathFilter.messagePattern)
 216  135
                 && Objects.equals(moduleId, xpathFilter.moduleId)
 217  126
                 && Objects.equals(xpathQuery, xpathFilter.xpathQuery);
 218  
     }
 219  
 }