1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 import java.util.stream.Collectors;
26
27 import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent;
28 import com.puppycrawl.tools.checkstyle.TreeWalkerFilter;
29 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
30 import com.puppycrawl.tools.checkstyle.xpath.AbstractNode;
31 import com.puppycrawl.tools.checkstyle.xpath.RootNode;
32 import net.sf.saxon.om.Item;
33 import net.sf.saxon.sxpath.XPathDynamicContext;
34 import net.sf.saxon.sxpath.XPathEvaluator;
35 import net.sf.saxon.sxpath.XPathExpression;
36 import net.sf.saxon.trans.XPathException;
37
38
39
40
41
42
43 public class XpathFilterElement implements TreeWalkerFilter {
44
45
46 private final Pattern fileRegexp;
47
48
49 private final String filePattern;
50
51
52 private final Pattern checkRegexp;
53
54
55 private final String checkPattern;
56
57
58 private final Pattern messageRegexp;
59
60
61 private final String messagePattern;
62
63
64 private final String moduleId;
65
66
67 private final XPathExpression xpathExpression;
68
69
70 private final String xpathQuery;
71
72
73
74
75
76
77
78
79
80 public XpathFilterElement(String files, String checks,
81 String message, String moduleId, String query) {
82 filePattern = files;
83 if (files == null) {
84 fileRegexp = null;
85 }
86 else {
87 fileRegexp = Pattern.compile(files);
88 }
89 checkPattern = checks;
90 if (checks == null) {
91 checkRegexp = null;
92 }
93 else {
94 checkRegexp = CommonUtil.createPattern(checks);
95 }
96 messagePattern = message;
97 if (message == null) {
98 messageRegexp = null;
99 }
100 else {
101 messageRegexp = Pattern.compile(message);
102 }
103 this.moduleId = moduleId;
104 xpathQuery = query;
105 if (xpathQuery == null) {
106 xpathExpression = null;
107 }
108 else {
109 final XPathEvaluator xpathEvaluator = new XPathEvaluator();
110 try {
111 xpathExpression = xpathEvaluator.createExpression(xpathQuery);
112 }
113 catch (XPathException ex) {
114 throw new IllegalArgumentException("Unexpected xpath query: " + xpathQuery, ex);
115 }
116 }
117 }
118
119
120
121
122
123
124
125
126
127 public XpathFilterElement(Pattern files, Pattern checks, Pattern message,
128 String moduleId, String query) {
129 if (files == null) {
130 filePattern = null;
131 fileRegexp = null;
132 }
133 else {
134 filePattern = files.pattern();
135 fileRegexp = files;
136 }
137 if (checks == null) {
138 checkPattern = null;
139 checkRegexp = null;
140 }
141 else {
142 checkPattern = checks.pattern();
143 checkRegexp = checks;
144 }
145 if (message == null) {
146 messagePattern = null;
147 messageRegexp = null;
148 }
149 else {
150 messagePattern = message.pattern();
151 messageRegexp = message;
152 }
153 this.moduleId = moduleId;
154 xpathQuery = query;
155 if (xpathQuery == null) {
156 xpathExpression = null;
157 }
158 else {
159 final XPathEvaluator xpathEvaluator = new XPathEvaluator();
160 try {
161 xpathExpression = xpathEvaluator.createExpression(xpathQuery);
162 }
163 catch (XPathException ex) {
164 throw new IllegalArgumentException("Incorrect xpath query: " + xpathQuery, ex);
165 }
166 }
167 }
168
169 @Override
170 public boolean accept(TreeWalkerAuditEvent event) {
171 return !isFileNameAndModuleAndModuleNameMatching(event)
172 || !isMessageNameMatching(event)
173 || !isXpathQueryMatching(event);
174 }
175
176
177
178
179
180
181 private boolean isFileNameAndModuleAndModuleNameMatching(TreeWalkerAuditEvent event) {
182 return event.getFileName() != null
183 && (fileRegexp == null || fileRegexp.matcher(event.getFileName()).find())
184 && event.getLocalizedMessage() != null
185 && (moduleId == null || moduleId.equals(event.getModuleId()))
186 && (checkRegexp == null || checkRegexp.matcher(event.getSourceName()).find());
187 }
188
189
190
191
192
193
194 private boolean isMessageNameMatching(TreeWalkerAuditEvent event) {
195 return messageRegexp == null || messageRegexp.matcher(event.getMessage()).find();
196 }
197
198
199
200
201
202
203 private boolean isXpathQueryMatching(TreeWalkerAuditEvent event) {
204 boolean isMatching;
205 if (xpathExpression == null) {
206 isMatching = true;
207 }
208 else {
209 isMatching = false;
210 final List<AbstractNode> nodes = getItems(event)
211 .stream().map(item -> (AbstractNode) item).collect(Collectors.toList());
212 for (AbstractNode abstractNode : nodes) {
213 isMatching = abstractNode.getTokenType() == event.getTokenType()
214 && abstractNode.getLineNumber() == event.getLine()
215 && abstractNode.getColumnNumber() == event.getColumnCharIndex();
216 if (isMatching) {
217 break;
218 }
219 }
220 }
221 return isMatching;
222 }
223
224
225
226
227
228
229 private List<Item<?>> getItems(TreeWalkerAuditEvent event) {
230 final RootNode rootNode;
231 if (event.getRootAst() == null) {
232 rootNode = null;
233 }
234 else {
235 rootNode = new RootNode(event.getRootAst());
236 }
237 final List<Item<?>> items;
238 try {
239 final XPathDynamicContext xpathDynamicContext =
240 xpathExpression.createDynamicContext(rootNode);
241 items = xpathExpression.evaluate(xpathDynamicContext);
242 }
243 catch (XPathException ex) {
244 throw new IllegalStateException("Cannot initialize context and evaluate query: "
245 + xpathQuery, ex);
246 }
247 return items;
248 }
249
250 @Override
251 public int hashCode() {
252 return Objects.hash(filePattern, checkPattern, messagePattern, moduleId, xpathQuery);
253 }
254
255 @Override
256 public boolean equals(Object other) {
257 if (this == other) {
258 return true;
259 }
260 if (other == null || getClass() != other.getClass()) {
261 return false;
262 }
263 final XpathFilterElement xpathFilter = (XpathFilterElement) other;
264 return Objects.equals(filePattern, xpathFilter.filePattern)
265 && Objects.equals(checkPattern, xpathFilter.checkPattern)
266 && Objects.equals(messagePattern, xpathFilter.messagePattern)
267 && Objects.equals(moduleId, xpathFilter.moduleId)
268 && Objects.equals(xpathQuery, xpathFilter.xpathQuery);
269 }
270
271 }