001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.api; 021 022import java.util.ArrayList; 023import java.util.List; 024 025/** 026 * Represents a full identifier, including dots, with associated 027 * position information. 028 * 029 * <p> 030 * Identifiers such as {@code java.util.HashMap} are spread across 031 * multiple AST nodes in the syntax tree (three IDENT nodes, two DOT nodes). 032 * A FullIdent represents the whole String (excluding any intermediate 033 * whitespace), which is often easier to work with in Checks. 034 * </p> 035 * 036 * @see TokenTypes#DOT 037 * @see TokenTypes#IDENT 038 **/ 039public final class FullIdent { 040 041 /** The list holding subsequent elements of identifier. **/ 042 private final List<String> elements = new ArrayList<>(); 043 /** The topmost and leftmost AST of the full identifier. */ 044 private DetailAST detailAst; 045 046 /** Hide default constructor. */ 047 private FullIdent() { 048 } 049 050 /** 051 * Creates a new FullIdent starting from the child of the specified node. 052 * @param ast the parent node from where to start from 053 * @return a {@code FullIdent} value 054 */ 055 public static FullIdent createFullIdentBelow(DetailAST ast) { 056 return createFullIdent(ast.getFirstChild()); 057 } 058 059 /** 060 * Creates a new FullIdent starting from the specified node. 061 * 062 * @param ast the node to start from 063 * @return a {@code FullIdent} value 064 */ 065 public static FullIdent createFullIdent(DetailAST ast) { 066 final FullIdent ident = new FullIdent(); 067 extractFullIdent(ident, ast); 068 return ident; 069 } 070 071 /** 072 * Recursively extract a FullIdent. 073 * 074 * @param full the FullIdent to add to 075 * @param ast the node to recurse from 076 */ 077 private static void extractFullIdent(FullIdent full, DetailAST ast) { 078 if (ast != null) { 079 if (ast.getType() == TokenTypes.DOT) { 080 extractFullIdent(full, ast.getFirstChild()); 081 full.append("."); 082 extractFullIdent( 083 full, ast.getFirstChild().getNextSibling()); 084 } 085 else if (ast.getType() == TokenTypes.ARRAY_DECLARATOR) { 086 extractFullIdent(full, ast.getFirstChild()); 087 full.append("[]"); 088 } 089 else { 090 full.append(ast); 091 } 092 } 093 } 094 095 /** 096 * Gets the text. 097 * 098 * @return the text 099 */ 100 public String getText() { 101 return String.join("", elements); 102 } 103 104 /** 105 * Gets the topmost leftmost DetailAST for this FullIdent. 106 * 107 * @return the topmost leftmost ast 108 */ 109 public DetailAST getDetailAst() { 110 return detailAst; 111 } 112 113 /** 114 * Gets the line number. 115 * 116 * @return the line number 117 */ 118 public int getLineNo() { 119 return detailAst.getLineNo(); 120 } 121 122 /** 123 * Gets the column number. 124 * 125 * @return the column number 126 */ 127 public int getColumnNo() { 128 return detailAst.getColumnNo(); 129 } 130 131 @Override 132 public String toString() { 133 return String.join("", elements) 134 + "[" + detailAst.getLineNo() + "x" + detailAst.getColumnNo() + "]"; 135 } 136 137 /** 138 * Append the specified text. 139 * 140 * @param text the text to append 141 */ 142 private void append(String text) { 143 elements.add(text); 144 } 145 146 /** 147 * Append the specified token and also recalibrate the first line and 148 * column. 149 * 150 * @param ast the token to append 151 */ 152 private void append(DetailAST ast) { 153 elements.add(ast.getText()); 154 if (detailAst == null) { 155 detailAst = ast; 156 } 157 } 158 159}