1 //////////////////////////////////////////////////////////////////////////////// 2 // checkstyle: Checks Java source code for adherence to a set of rules. 3 // Copyright (C) 2001-2019 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.utils; 21 22 import java.util.Arrays; 23 import java.util.List; 24 25 import com.puppycrawl.tools.checkstyle.api.DetailAST; 26 import com.puppycrawl.tools.checkstyle.api.TokenTypes; 27 28 /** 29 * Contains utility methods for xpath. 30 * 31 */ 32 public final class XpathUtil { 33 34 /** 35 * List of token types which support text attribute. 36 * These token types were selected based on analysis that all others do not match required 37 * criteria - text attribute of the token must be useful and help to retrieve more precise 38 * results. 39 * There are three types of AST tokens: 40 * 1. Tokens for which the texts are equal to the name of the token. Or in other words, 41 * nodes for which the following expression is always true: 42 * <pre> 43 * detailAst.getText().equals(TokenUtil.getTokenName(detailAst.getType())) 44 * </pre> 45 * For example: 46 * <pre> 47 * //MODIFIERS[@text='MODIFIERS'] 48 * //OBJBLOCK[@text='OBJBLOCK'] 49 * </pre> 50 * These tokens do not match required criteria because their texts do not carry any additional 51 * information, they do not affect the xpath requests and do not help to get more accurate 52 * results. The texts of these nodes are useless. No matter what code you analyze, these 53 * texts are always the same. 54 * In addition, they make xpath queries more complex, less readable and verbose. 55 * 2. Tokens for which the texts differ from token names, but texts are always constant. 56 * For example: 57 * <pre> 58 * //LITERAL_VOID[@text='void'] 59 * //RCURLY[@text='}'] 60 * </pre> 61 * These tokens are not used for the same reasons as were described in the previous part. 62 * 3. Tokens for which texts are not constant. The texts of these nodes are closely related 63 * to a concrete class, method, variable and so on. 64 * For example: 65 * <pre> 66 * String greeting = "HelloWorld"; 67 * //STRING_LITERAL[@text='HelloWorld'] 68 * </pre> 69 * <pre> 70 * int year = 2017; 71 * //NUM_INT[@text=2017] 72 * </pre> 73 * <pre> 74 * int age = 23; 75 * //NUM_INT[@text=23] 76 * </pre> 77 * As you can see same {@code NUM_INT} token type can have different texts, depending on 78 * context. 79 * <pre> 80 * public class MyClass {} 81 * //IDENT[@text='MyClass'] 82 * </pre> 83 * Only these tokens support text attribute because they make our xpath queries more accurate. 84 * These token types are listed below. 85 * */ 86 private static final List<Integer> TOKEN_TYPES_WITH_TEXT_ATTRIBUTE = Arrays.asList( 87 TokenTypes.IDENT, TokenTypes.STRING_LITERAL, TokenTypes.CHAR_LITERAL, 88 TokenTypes.NUM_LONG, TokenTypes.NUM_INT, TokenTypes.NUM_DOUBLE, TokenTypes.NUM_FLOAT); 89 90 /** Stop instances being created. **/ 91 private XpathUtil() { 92 } 93 94 /** 95 * Checks, if specified node can have {@code @text} attribute. 96 * 97 * @param ast {@code DetailAst} element 98 * @return true if element supports {@code @text} attribute, false otherwise 99 */ 100 public static boolean supportsTextAttribute(DetailAST ast) { 101 return TOKEN_TYPES_WITH_TEXT_ATTRIBUTE.contains(ast.getType()); 102 } 103 104 /** 105 * Returns content of the text attribute of the ast element. 106 * 107 * @param ast {@code DetailAst} element 108 * @return text attribute of the ast element 109 */ 110 public static String getTextAttributeValue(DetailAST ast) { 111 String text = ast.getText(); 112 if (ast.getType() == TokenTypes.STRING_LITERAL) { 113 text = text.substring(1, text.length() - 1); 114 } 115 return text; 116 } 117 118 }