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