1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.Reader;
25 import java.io.StringReader;
26 import java.nio.charset.StandardCharsets;
27 import java.util.Locale;
28
29 import antlr.CommonHiddenStreamToken;
30 import antlr.RecognitionException;
31 import antlr.Token;
32 import antlr.TokenStreamException;
33 import antlr.TokenStreamHiddenTokenFilter;
34 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
35 import com.puppycrawl.tools.checkstyle.api.DetailAST;
36 import com.puppycrawl.tools.checkstyle.api.FileContents;
37 import com.puppycrawl.tools.checkstyle.api.FileText;
38 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
39 import com.puppycrawl.tools.checkstyle.grammar.GeneratedJavaLexer;
40 import com.puppycrawl.tools.checkstyle.grammar.GeneratedJavaRecognizer;
41 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
42
43
44
45
46
47 public final class JavaParser {
48
49
50
51
52 public enum Options {
53
54
55
56
57 WITH_COMMENTS,
58
59
60
61
62 WITHOUT_COMMENTS,
63
64 }
65
66
67 private JavaParser() {
68 }
69
70
71
72
73
74
75
76 public static DetailAST parse(FileContents contents)
77 throws CheckstyleException {
78 final String fullText = contents.getText().getFullText().toString();
79 final Reader reader = new StringReader(fullText);
80 final GeneratedJavaLexer lexer = new GeneratedJavaLexer(reader);
81 lexer.setCommentListener(contents);
82 lexer.setTokenObjectClass("antlr.CommonHiddenStreamToken");
83
84 final TokenStreamHiddenTokenFilter filter = new TokenStreamHiddenTokenFilter(lexer);
85 filter.hide(TokenTypes.SINGLE_LINE_COMMENT);
86 filter.hide(TokenTypes.BLOCK_COMMENT_BEGIN);
87
88 final GeneratedJavaRecognizer parser = new GeneratedJavaRecognizer(filter) {
89 @Override
90 public void reportError(RecognitionException ex) {
91 throw new IllegalStateException(ex);
92 }
93 };
94 parser.setFilename(contents.getFileName());
95 parser.setASTNodeClass(DetailAST.class.getName());
96 try {
97 parser.compilationUnit();
98 }
99 catch (RecognitionException | TokenStreamException | IllegalStateException ex) {
100 final String exceptionMsg = String.format(Locale.ROOT,
101 "%s occurred while parsing file %s.",
102 ex.getClass().getSimpleName(), contents.getFileName());
103 throw new CheckstyleException(exceptionMsg, ex);
104 }
105
106 return (DetailAST) parser.getAST();
107 }
108
109
110
111
112
113
114
115
116 public static DetailAST parseFileText(FileText text, Options options)
117 throws CheckstyleException {
118 final FileContents contents = new FileContents(text);
119 DetailAST ast = parse(contents);
120 if (options == Options.WITH_COMMENTS) {
121 ast = appendHiddenCommentNodes(ast);
122 }
123 return ast;
124 }
125
126
127
128
129
130
131
132
133
134 public static DetailAST parseFile(File file, Options options)
135 throws IOException, CheckstyleException {
136 final FileText text = new FileText(file.getAbsoluteFile(),
137 System.getProperty("file.encoding", StandardCharsets.UTF_8.name()));
138 return parseFileText(text, options);
139 }
140
141
142
143
144
145
146
147
148 public static DetailAST appendHiddenCommentNodes(DetailAST root) {
149 DetailAST result = root;
150 DetailAST curNode = root;
151 DetailAST lastNode = root;
152
153 while (curNode != null) {
154 lastNode = curNode;
155
156 CommonHiddenStreamToken tokenBefore = curNode.getHiddenBefore();
157 DetailAST currentSibling = curNode;
158 while (tokenBefore != null) {
159 final DetailAST newCommentNode =
160 createCommentAstFromToken(tokenBefore);
161
162 currentSibling.addPreviousSibling(newCommentNode);
163
164 if (currentSibling == result) {
165 result = newCommentNode;
166 }
167
168 currentSibling = newCommentNode;
169 tokenBefore = tokenBefore.getHiddenBefore();
170 }
171
172 DetailAST toVisit = curNode.getFirstChild();
173 while (curNode != null && toVisit == null) {
174 toVisit = curNode.getNextSibling();
175 curNode = curNode.getParent();
176 }
177 curNode = toVisit;
178 }
179 if (lastNode != null) {
180 CommonHiddenStreamToken tokenAfter = lastNode.getHiddenAfter();
181 DetailAST currentSibling = lastNode;
182 while (tokenAfter != null) {
183 final DetailAST newCommentNode =
184 createCommentAstFromToken(tokenAfter);
185
186 currentSibling.addNextSibling(newCommentNode);
187
188 currentSibling = newCommentNode;
189 tokenAfter = tokenAfter.getHiddenAfter();
190 }
191 }
192 return result;
193 }
194
195
196
197
198
199
200
201 private static DetailAST createCommentAstFromToken(Token token) {
202 final DetailAST commentAst;
203 if (token.getType() == TokenTypes.SINGLE_LINE_COMMENT) {
204 commentAst = createSlCommentNode(token);
205 }
206 else {
207 commentAst = CommonUtil.createBlockCommentNode(token);
208 }
209 return commentAst;
210 }
211
212
213
214
215
216
217 private static DetailAST createSlCommentNode(Token token) {
218 final DetailAST slComment = new DetailAST();
219 slComment.setType(TokenTypes.SINGLE_LINE_COMMENT);
220 slComment.setText("//");
221
222
223 slComment.setColumnNo(token.getColumn() - 1);
224 slComment.setLineNo(token.getLine());
225
226 final DetailAST slCommentContent = new DetailAST();
227 slCommentContent.setType(TokenTypes.COMMENT_CONTENT);
228
229
230
231 slCommentContent.setColumnNo(token.getColumn() - 1 + 2);
232 slCommentContent.setLineNo(token.getLine());
233 slCommentContent.setText(token.getText());
234
235 slComment.addChild(slCommentContent);
236 return slComment;
237 }
238
239 }