001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2015 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 025import org.apache.commons.lang3.StringUtils; 026 027/** 028 * Represents a full identifier, including dots, with associated 029 * position information. 030 * 031 * <p> 032 * Identifiers such as {@code java.util.HashMap} are spread across 033 * multiple AST nodes in the syntax tree (three IDENT nodes, two DOT nodes). 034 * A FullIdent represents the whole String (excluding any intermediate 035 * whitespace), which is often easier to work with in Checks. 036 * </p> 037 * 038 * @author Oliver Burn 039 * @see TokenTypes#DOT 040 * @see TokenTypes#IDENT 041 **/ 042public final class FullIdent { 043 /** The list holding subsequent elements of identifier. **/ 044 private final List<String> elements = new ArrayList<>(); 045 /** The line number. **/ 046 private int lineNo; 047 /** The column number. **/ 048 private int columnNo; 049 050 /** Hide default constructor. */ 051 private FullIdent() { 052 } 053 054 /** 055 * Gets the text. 056 * @return the text 057 */ 058 public String getText() { 059 return StringUtils.join(elements, ""); 060 } 061 062 /** 063 * Gets the line number. 064 * @return the line number 065 */ 066 public int getLineNo() { 067 return lineNo; 068 } 069 070 /** 071 * Gets the column number. 072 * @return the column number 073 */ 074 public int getColumnNo() { 075 return columnNo; 076 } 077 078 /** 079 * Append the specified text. 080 * @param text the text to append 081 */ 082 private void append(String text) { 083 elements.add(text); 084 } 085 086 /** 087 * Append the specified token and also recalibrate the first line and 088 * column. 089 * @param ast the token to append 090 */ 091 private void append(DetailAST ast) { 092 elements.add(ast.getText()); 093 if (lineNo == 0) { 094 lineNo = ast.getLineNo(); 095 } 096 else if (ast.getLineNo() > 0) { 097 lineNo = Math.min(lineNo, ast.getLineNo()); 098 } 099 if (columnNo == 0) { 100 columnNo = ast.getColumnNo(); 101 } 102 else if (ast.getColumnNo() > 0) { 103 columnNo = Math.min(columnNo, ast.getColumnNo()); 104 } 105 } 106 107 /** 108 * Creates a new FullIdent starting from the specified node. 109 * @param ast the node to start from 110 * @return a {@code FullIdent} value 111 */ 112 public static FullIdent createFullIdent(DetailAST ast) { 113 final FullIdent ident = new FullIdent(); 114 extractFullIdent(ident, ast); 115 return ident; 116 } 117 118 /** 119 * Creates a new FullIdent starting from the child of the specified node. 120 * @param ast the parent node from where to start from 121 * @return a {@code FullIdent} value 122 */ 123 public static FullIdent createFullIdentBelow(DetailAST ast) { 124 return createFullIdent(ast.getFirstChild()); 125 } 126 127 /** 128 * Recursively extract a FullIdent. 129 * 130 * @param full the FullIdent to add to 131 * @param ast the node to recurse from 132 */ 133 private static void extractFullIdent(FullIdent full, DetailAST ast) { 134 if (ast == null) { 135 return; 136 } 137 138 if (ast.getType() == TokenTypes.DOT) { 139 extractFullIdent(full, ast.getFirstChild()); 140 full.append("."); 141 extractFullIdent( 142 full, ast.getFirstChild().getNextSibling()); 143 } 144 else { 145 full.append(ast); 146 } 147 } 148 149 @Override 150 public String toString() { 151 return getText() + "[" + lineNo + "x" + columnNo + "]"; 152 } 153 154}