Source code: com/puppycrawl/tools/checkstyle/checks/usage/transmogrify/ASTManager.java
1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2003 Oliver Burn
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 package com.puppycrawl.tools.checkstyle.checks.usage.transmogrify;
20
21 import java.io.File;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.IdentityHashMap;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.Set;
28
29 import antlr.collections.AST;
30
31 import com.puppycrawl.tools.checkstyle.checks.usage.AbstractUsageCheck;
32
33 /**
34 * Manages AST trees and nodes. Capable of managing multiple parse trees, which
35 * is useful for inter-file checks.
36 * @author Rick Giles
37 */
38 public final class ASTManager
39 {
40 /** singleton */
41 private static final ASTManager INSTANCE = new ASTManager();
42
43 /** maps DetailASTs to SymTabASTs. */
44 private Map mMap = new IdentityHashMap();
45
46 /** root with subtrees for a set of files */
47 private SymTabAST mCompleteTree = null;
48
49 /** Map for parse trees, keyed on File name */
50 private Map mTrees = new HashMap();
51
52 /** Set of checks and their nodes to check */
53 private Map mCheckNodes = new HashMap();
54
55 /** prevent client creation */
56 private ASTManager()
57 {
58 }
59
60 /**
61 * Returns the singleon ASTManager.
62 * @return the singleon ASTManager.
63 */
64 public static ASTManager getInstance()
65 {
66 return INSTANCE;
67 }
68
69 /**
70 * Add the parse tree for a file to the set of parse trees.
71 * @param aFileName the name of the file.
72 * @param aRoot the root of the AST.
73 */
74 public void addTree(String aFileName, AST aRoot)
75 {
76 mTrees.put(aFileName, aRoot);
77 }
78
79 /**
80 * Builds the complete tree for all added parse trees.
81 * @throws SymbolTableException if there is an error.
82 */
83 private void buildTree()
84 throws SymbolTableException
85 {
86 mCompleteTree = SymTabASTFactory.create(0, "AST Root");
87 final Set keys = mTrees.keySet();
88 final Iterator it = keys.iterator();
89 while (it.hasNext()) {
90 final String fileName = (String) it.next();
91 final File file = new File(fileName);
92 final AST rootAST = (AST) mTrees.get(fileName);
93 addToCompleteTree(file, rootAST);
94 }
95
96 // Walk of the complete tree.
97 // TODO: This is a hack. Find a better way.
98 final SymbolTable table = new TableMaker(mCompleteTree).getTable();
99 }
100
101 /**
102 * Adds a file and a DetailAST to the root SymTabAST tree. Normally, the
103 * DetailAST will be the parse tree for the file.
104 * @param aFile the file to add.
105 * @param aAST the DetailAST to add.
106 */
107 private void addToCompleteTree(File aFile, AST aAST)
108 {
109 // add aFile to the root
110 final SymTabAST fileNode =
111 SymTabASTFactory.create(0, aFile.getAbsolutePath());
112 fileNode.setFile(aFile);
113 mCompleteTree.addChild(fileNode);
114 fileNode.setParent(mCompleteTree);
115
116 // add aAST to aFile
117 final SymTabAST child = SymTabASTFactory.create(aAST);
118 child.setFile(aFile);
119 fileNode.addChild(child);
120 child.setParent(fileNode);
121 fileNode.finishDefinition(aFile, mCompleteTree);
122 }
123
124 /**
125 * Registers a node for checking.
126 * @param aCheck the check to apply.
127 * @param aNode the node to check.
128 */
129 public void registerCheckNode(AbstractUsageCheck aCheck, AST aNode)
130 {
131 Set nodeSet = (Set) mCheckNodes.get(aCheck);
132 if (nodeSet == null) {
133 nodeSet = new HashSet();
134 nodeSet.add(aNode);
135 mCheckNodes.put(aCheck, nodeSet);
136 }
137 else {
138 nodeSet.add(aNode);
139 }
140 }
141
142 /**
143 * Gets the nodes to check with a usage check.
144 * @param aCheck the usage check.
145 * @return the nodes to check with aCheck.
146 * @throws SymbolTableException if there is an error.
147 */
148 public Set getCheckNodes(AbstractUsageCheck aCheck)
149 throws SymbolTableException
150 {
151 // lazy initialization
152 if (mCompleteTree == null) {
153 buildTree();
154 }
155 Set result = (Set) mCheckNodes.get(aCheck);
156 if (result == null) {
157 result = new HashSet();
158 }
159 return result;
160 }
161
162 /**
163 * Maps a AST to its associated SymTabAST.
164 * @param aAST the AST.
165 * @param aSymTabAST the SymTabAST associated with aAST.
166 */
167 public void put(AST aAST, SymTabAST aSymTabAST)
168 {
169 mMap.put(aAST, aSymTabAST);
170 }
171
172 /**
173 * Gets the SymTabAST associated with a AST.
174 * @param aAST the AST.
175 * @return the the SymTabAST associated with aAST.
176 */
177 public SymTabAST get(AST aAST)
178 {
179 return (SymTabAST) mMap.get(aAST);
180 }
181
182 /**
183 * Clears all associations from DetailsASTs to SymTabASTs.
184 */
185 public void clearDetailsMap()
186 {
187 mMap.clear();
188 }
189
190 /**
191 * Determines whether the map from DetailsASTs to SymTabASTs is empty.
192 * @return true if the map is empty.
193 */
194 public boolean isEmptyDetailsMap()
195 {
196 return mMap.isEmpty();
197 }
198
199 /**
200 * Removes a check and its check nodes. Clears all managed elements if
201 * last check removed.
202 * @param aCheck the check to remove.
203 */
204 public void removeCheck(AbstractUsageCheck aCheck)
205 {
206 mCheckNodes.remove(aCheck);
207 if (mCheckNodes.isEmpty()) {
208 mCompleteTree = null;
209 mMap.clear();
210 mTrees.clear();
211 }
212 }
213 }