View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2017 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   * @author Oliver Burn
37   * @see TokenTypes#DOT
38   * @see TokenTypes#IDENT
39   **/
40  public final class FullIdent {
41      /** The list holding subsequent elements of identifier. **/
42      private final List<String> elements = new ArrayList<>();
43      /** The line number. **/
44      private int lineNo;
45      /** The column number. **/
46      private int columnNo;
47  
48      /** Hide default constructor. */
49      private FullIdent() {
50      }
51  
52      /**
53       * Creates a new FullIdent starting from the specified node.
54       * @param ast the node to start from
55       * @return a {@code FullIdent} value
56       */
57      public static FullIdent createFullIdent(DetailAST ast) {
58          final FullIdent ident = new FullIdent();
59          extractFullIdent(ident, ast);
60          return ident;
61      }
62  
63      /**
64       * Creates a new FullIdent starting from the child of the specified node.
65       * @param ast the parent node from where to start from
66       * @return a {@code FullIdent} value
67       */
68      public static FullIdent createFullIdentBelow(DetailAST ast) {
69          return createFullIdent(ast.getFirstChild());
70      }
71  
72      /**
73       * Gets the text.
74       * @return the text
75       */
76      public String getText() {
77          return String.join("", elements);
78      }
79  
80      /**
81       * Gets the line number.
82       * @return the line number
83       */
84      public int getLineNo() {
85          return lineNo;
86      }
87  
88      /**
89       * Gets the column number.
90       * @return the column number
91       */
92      public int getColumnNo() {
93          return columnNo;
94      }
95  
96      @Override
97      public String toString() {
98          return String.join("", elements) + "[" + lineNo + "x" + columnNo + "]";
99      }
100 
101     /**
102      * Recursively extract a FullIdent.
103      *
104      * @param full the FullIdent to add to
105      * @param ast the node to recurse from
106      */
107     private static void extractFullIdent(FullIdent full, DetailAST ast) {
108         if (ast != null) {
109             if (ast.getType() == TokenTypes.DOT) {
110                 extractFullIdent(full, ast.getFirstChild());
111                 full.append(".");
112                 extractFullIdent(
113                     full, ast.getFirstChild().getNextSibling());
114             }
115             else {
116                 full.append(ast);
117             }
118         }
119     }
120 
121     /**
122      * Append the specified text.
123      * @param text the text to append
124      */
125     private void append(String text) {
126         elements.add(text);
127     }
128 
129     /**
130      * Append the specified token and also recalibrate the first line and
131      * column.
132      * @param ast the token to append
133      */
134     private void append(DetailAST ast) {
135         elements.add(ast.getText());
136         if (lineNo == 0) {
137             lineNo = ast.getLineNo();
138         }
139         else if (ast.getLineNo() > 0) {
140             lineNo = Math.min(lineNo, ast.getLineNo());
141         }
142         if (columnNo == 0) {
143             columnNo = ast.getColumnNo();
144         }
145         else if (ast.getColumnNo() > 0) {
146             columnNo = Math.min(columnNo, ast.getColumnNo());
147         }
148     }
149 }