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.api; 21 22 import java.util.ArrayList; 23 import java.util.List; 24 25 /** 26 * Represents a full identifier, including dots, with associated 27 * position information. 28 * 29 * <p> 30 * Identifiers such as {@code java.util.HashMap} are spread across 31 * multiple AST nodes in the syntax tree (three IDENT nodes, two DOT nodes). 32 * A FullIdent represents the whole String (excluding any intermediate 33 * whitespace), which is often easier to work with in Checks. 34 * </p> 35 * 36 * @see TokenTypes#DOT 37 * @see TokenTypes#IDENT 38 **/ 39 public final class FullIdent { 40 41 /** The list holding subsequent elements of identifier. **/ 42 private final List<String> elements = new ArrayList<>(); 43 /** The topmost and leftmost AST of the full identifier. */ 44 private DetailAST detailAst; 45 46 /** Hide default constructor. */ 47 private FullIdent() { 48 } 49 50 /** 51 * Creates a new FullIdent starting from the specified node. 52 * @param ast the node to start from 53 * @return a {@code FullIdent} value 54 */ 55 public static FullIdent createFullIdent(DetailAST ast) { 56 final FullIdent ident = new FullIdent(); 57 extractFullIdent(ident, ast); 58 return ident; 59 } 60 61 /** 62 * Creates a new FullIdent starting from the child of the specified node. 63 * @param ast the parent node from where to start from 64 * @return a {@code FullIdent} value 65 */ 66 public static FullIdent createFullIdentBelow(DetailAST ast) { 67 return createFullIdent(ast.getFirstChild()); 68 } 69 70 /** 71 * Gets the text. 72 * @return the text 73 */ 74 public String getText() { 75 return String.join("", elements); 76 } 77 78 /** 79 * Gets the topmost leftmost DetailAST for this FullIdent. 80 * @return the topmost leftmost ast 81 */ 82 public DetailAST getDetailAst() { 83 return detailAst; 84 } 85 86 /** 87 * Gets the line number. 88 * @return the line number 89 */ 90 public int getLineNo() { 91 return detailAst.getLineNo(); 92 } 93 94 /** 95 * Gets the column number. 96 * @return the column number 97 */ 98 public int getColumnNo() { 99 return detailAst.getColumnNo(); 100 } 101 102 @Override 103 public String toString() { 104 return String.join("", elements) 105 + "[" + detailAst.getLineNo() + "x" + detailAst.getColumnNo() + "]"; 106 } 107 108 /** 109 * Recursively extract a FullIdent. 110 * 111 * @param full the FullIdent to add to 112 * @param ast the node to recurse from 113 */ 114 private static void extractFullIdent(FullIdent full, DetailAST ast) { 115 if (ast != null) { 116 if (ast.getType() == TokenTypes.DOT) { 117 extractFullIdent(full, ast.getFirstChild()); 118 full.append("."); 119 extractFullIdent( 120 full, ast.getFirstChild().getNextSibling()); 121 } 122 else if (ast.getType() == TokenTypes.ARRAY_DECLARATOR) { 123 extractFullIdent(full, ast.getFirstChild()); 124 full.append("[]"); 125 } 126 else { 127 full.append(ast); 128 } 129 } 130 } 131 132 /** 133 * Append the specified text. 134 * @param text the text to append 135 */ 136 private void append(String text) { 137 elements.add(text); 138 } 139 140 /** 141 * Append the specified token and also recalibrate the first line and 142 * column. 143 * @param ast the token to append 144 */ 145 private void append(DetailAST ast) { 146 elements.add(ast.getText()); 147 if (detailAst == null) { 148 detailAst = ast; 149 } 150 } 151 152 }