• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
3  * Copyright (C) 2011, 2013-2016 The JavaParser Team.
4  *
5  * This file is part of JavaParser.
6  *
7  * JavaParser can be used either under the terms of
8  * a) the GNU Lesser General Public License as published by
9  *     the Free Software Foundation, either version 3 of the License, or
10  *     (at your option) any later version.
11  * b) the terms of the Apache License
12  *
13  * You should have received a copy of both licenses in LICENCE.LGPL and
14  * LICENCE.APACHE. Please refer to those files for details.
15  *
16  * JavaParser is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License for more details.
20  */
21 
22 package com.github.javaparser;
23 
24 import static com.github.javaparser.ParserConfiguration.LanguageLevel.*;
25 import static com.github.javaparser.utils.Utils.*;
26 
27 import java.nio.charset.Charset;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Optional;
31 
32 import com.github.javaparser.ParseResult.PostProcessor;
33 import com.github.javaparser.Providers.PreProcessor;
34 import com.github.javaparser.UnicodeEscapeProcessingProvider.PositionMapping;
35 import com.github.javaparser.ast.CompilationUnit;
36 import com.github.javaparser.ast.Node;
37 import com.github.javaparser.ast.validator.Java10Validator;
38 import com.github.javaparser.ast.validator.Java11Validator;
39 import com.github.javaparser.ast.validator.Java12Validator;
40 import com.github.javaparser.ast.validator.Java1_0Validator;
41 import com.github.javaparser.ast.validator.Java1_1Validator;
42 import com.github.javaparser.ast.validator.Java1_2Validator;
43 import com.github.javaparser.ast.validator.Java1_3Validator;
44 import com.github.javaparser.ast.validator.Java1_4Validator;
45 import com.github.javaparser.ast.validator.Java5Validator;
46 import com.github.javaparser.ast.validator.Java6Validator;
47 import com.github.javaparser.ast.validator.Java7Validator;
48 import com.github.javaparser.ast.validator.Java8Validator;
49 import com.github.javaparser.ast.validator.Java9Validator;
50 import com.github.javaparser.ast.validator.ProblemReporter;
51 import com.github.javaparser.ast.validator.Validator;
52 import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;
53 import com.github.javaparser.resolution.SymbolResolver;
54 import com.github.javaparser.version.Java10PostProcessor;
55 import com.github.javaparser.version.Java11PostProcessor;
56 import com.github.javaparser.version.Java12PostProcessor;
57 
58 /**
59  * The configuration that is used by the parser.
60  * Note that this can be changed even when reusing the same JavaParser instance.
61  * It will pick up the changes.
62  */
63 public class ParserConfiguration {
64     public enum LanguageLevel {
65         /**
66          * Does no post processing or validation. Only for people wanting the fastest parsing.
67          */
68         RAW(null, null),
69         /**
70          * The most used Java version.
71          */
72         POPULAR(new Java8Validator(), null),
73         /**
74          * The latest Java version that is available.
75          */
76         CURRENT(new Java8Validator(), null),
77         /**
78          * The newest Java features supported.
79          */
80         BLEEDING_EDGE(new Java12Validator(), new Java12PostProcessor()),
81         /**
82          * Java 1.0
83          */
84         JAVA_1_0(new Java1_0Validator(), null),
85         /**
86          * Java 1.1
87          */
88         JAVA_1_1(new Java1_1Validator(), null),
89         /**
90          * Java 1.2
91          */
92         JAVA_1_2(new Java1_2Validator(), null),
93         /**
94          * Java 1.3
95          */
96         JAVA_1_3(new Java1_3Validator(), null),
97         /**
98          * Java 1.4
99          */
100         JAVA_1_4(new Java1_4Validator(), null),
101         /**
102          * Java 5
103          */
104         JAVA_5(new Java5Validator(), null),
105         /**
106          * Java 6
107          */
108         JAVA_6(new Java6Validator(), null),
109         /**
110          * Java 7
111          */
112         JAVA_7(new Java7Validator(), null),
113         /**
114          * Java 8
115          */
116         JAVA_8(new Java8Validator(), null),
117         /**
118          * Java 9
119          */
120         JAVA_9(new Java9Validator(), null),
121         /**
122          * Java 10
123          */
124         JAVA_10(new Java10Validator(), new Java10PostProcessor()),
125         /**
126          * Java 11
127          */
128         JAVA_11(new Java11Validator(), new Java11PostProcessor()),
129         /**
130          * Java 12
131          */
132         JAVA_12(new Java12Validator(), new Java12PostProcessor());
133 
134         final Validator validator;
135         final ParseResult.PostProcessor postProcessor;
136 
LanguageLevel(Validator validator, ParseResult.PostProcessor postProcessor)137         LanguageLevel(Validator validator, ParseResult.PostProcessor postProcessor) {
138             this.validator = validator;
139             this.postProcessor = postProcessor;
140         }
141     }
142 
143     private boolean storeTokens = true;
144     private boolean attributeComments = true;
145     private boolean doNotAssignCommentsPrecedingEmptyLines = true;
146     private boolean ignoreAnnotationsWhenAttributingComments = false;
147     private boolean lexicalPreservationEnabled = false;
148     private boolean preprocessUnicodeEscapes = false;
149     private SymbolResolver symbolResolver = null;
150     private int tabSize = 1;
151     private LanguageLevel languageLevel = CURRENT;
152     private Charset characterEncoding = Providers.UTF8;
153 
154     private final List<Providers.PreProcessor> preProcessors = new ArrayList<>();
155     private final List<ParseResult.PostProcessor> postProcessors = new ArrayList<>();
156 
ParserConfiguration()157     public ParserConfiguration() {
158     	class UnicodeEscapeProcessor implements PreProcessor, PostProcessor {
159     		private UnicodeEscapeProcessingProvider _unicodeDecoder;
160 
161 			@Override
162     		public Provider process(Provider innerProvider) {
163 	            if (isPreprocessUnicodeEscapes()) {
164 	                _unicodeDecoder = new UnicodeEscapeProcessingProvider(innerProvider);
165 					return _unicodeDecoder;
166 	            }
167 	            return innerProvider;
168     		}
169 
170 			@Override
171 			public void process(ParseResult<? extends Node> result,
172 					ParserConfiguration configuration) {
173 				if (isPreprocessUnicodeEscapes()) {
174 					result.getResult().ifPresent(
175 						root -> {
176 							PositionMapping mapping = _unicodeDecoder.getPositionMapping();
177 							if (!mapping.isEmpty()) {
178 								root.walk(
179 									node -> node.getRange().ifPresent(
180 										range -> node.setRange(mapping.transform(range))));
181 							}
182 						}
183 					);
184 				}
185 			}
186     	}
187     	UnicodeEscapeProcessor unicodeProcessor = new UnicodeEscapeProcessor();
188     	preProcessors.add(unicodeProcessor);
189 		postProcessors.add(unicodeProcessor);
190         postProcessors.add((result, configuration) -> {
191             if (configuration.isLexicalPreservationEnabled()) {
192                 result.ifSuccessful(LexicalPreservingPrinter::setup);
193             }
194         });
195         postProcessors.add((result, configuration) -> {
196             if (configuration.isAttributeComments()) {
197                 result.ifSuccessful(resultNode -> result
198                         .getCommentsCollection().ifPresent(comments ->
199                                 new CommentsInserter(configuration).insertComments(resultNode, comments.copy().getComments())));
200             }
201         });
202         postProcessors.add((result, configuration) -> {
203             LanguageLevel languageLevel = getLanguageLevel();
204             if (languageLevel.postProcessor != null) {
205                 languageLevel.postProcessor.process(result, configuration);
206             }
207             if (languageLevel.validator != null) {
208                 languageLevel.validator.accept(result.getResult().get(), new ProblemReporter(newProblem -> result.getProblems().add(newProblem)));
209             }
210         });
211         postProcessors.add((result, configuration) -> configuration.getSymbolResolver().ifPresent(symbolResolver ->
212                 result.ifSuccessful(resultNode -> {
213                     if (resultNode instanceof CompilationUnit) {
214                         resultNode.setData(Node.SYMBOL_RESOLVER_KEY, symbolResolver);
215                     }
216                 })
217         ));
218     }
219 
isAttributeComments()220     public boolean isAttributeComments() {
221         return attributeComments;
222     }
223 
224     /**
225      * Whether to run CommentsInserter, which will put the comments that were found in the source code into the comment
226      * and javadoc fields of the nodes it thinks they refer to.
227      */
setAttributeComments(boolean attributeComments)228     public ParserConfiguration setAttributeComments(boolean attributeComments) {
229         this.attributeComments = attributeComments;
230         return this;
231     }
232 
isDoNotAssignCommentsPrecedingEmptyLines()233     public boolean isDoNotAssignCommentsPrecedingEmptyLines() {
234         return doNotAssignCommentsPrecedingEmptyLines;
235     }
236 
setDoNotAssignCommentsPrecedingEmptyLines(boolean doNotAssignCommentsPrecedingEmptyLines)237     public ParserConfiguration setDoNotAssignCommentsPrecedingEmptyLines(boolean doNotAssignCommentsPrecedingEmptyLines) {
238         this.doNotAssignCommentsPrecedingEmptyLines = doNotAssignCommentsPrecedingEmptyLines;
239         return this;
240     }
241 
isIgnoreAnnotationsWhenAttributingComments()242     public boolean isIgnoreAnnotationsWhenAttributingComments() {
243         return ignoreAnnotationsWhenAttributingComments;
244     }
245 
setIgnoreAnnotationsWhenAttributingComments(boolean ignoreAnnotationsWhenAttributingComments)246     public ParserConfiguration setIgnoreAnnotationsWhenAttributingComments(boolean ignoreAnnotationsWhenAttributingComments) {
247         this.ignoreAnnotationsWhenAttributingComments = ignoreAnnotationsWhenAttributingComments;
248         return this;
249     }
250 
setStoreTokens(boolean storeTokens)251     public ParserConfiguration setStoreTokens(boolean storeTokens) {
252         this.storeTokens = storeTokens;
253         if (!storeTokens) {
254             setAttributeComments(false);
255         }
256         return this;
257     }
258 
isStoreTokens()259     public boolean isStoreTokens() {
260         return storeTokens;
261     }
262 
getTabSize()263     public int getTabSize() {
264         return tabSize;
265     }
266 
267     /**
268      * When a TAB character is encountered during parsing, the column position will be increased by this value.
269      * By default it is 1.
270      */
setTabSize(int tabSize)271     public ParserConfiguration setTabSize(int tabSize) {
272         this.tabSize = tabSize;
273         return this;
274     }
275 
276     /**
277      * Disabled by default.
278      * When this is enabled, LexicalPreservingPrinter.print can be used to reproduce
279      * the original formatting of the file.
280      */
setLexicalPreservationEnabled(boolean lexicalPreservationEnabled)281     public ParserConfiguration setLexicalPreservationEnabled(boolean lexicalPreservationEnabled) {
282         this.lexicalPreservationEnabled = lexicalPreservationEnabled;
283         return this;
284     }
285 
isLexicalPreservationEnabled()286     public boolean isLexicalPreservationEnabled() {
287         return lexicalPreservationEnabled;
288     }
289 
290     /**
291      * Retrieve the SymbolResolver to be used while parsing, if any.
292      */
getSymbolResolver()293     public Optional<SymbolResolver> getSymbolResolver() {
294         return Optional.ofNullable(symbolResolver);
295     }
296 
297     /**
298      * Set the SymbolResolver to be injected while parsing.
299      */
setSymbolResolver(SymbolResolver symbolResolver)300     public ParserConfiguration setSymbolResolver(SymbolResolver symbolResolver) {
301         this.symbolResolver = symbolResolver;
302         return this;
303     }
304 
getPreProcessors()305     public List<Providers.PreProcessor> getPreProcessors() {
306         return preProcessors;
307     }
308 
getPostProcessors()309     public List<ParseResult.PostProcessor> getPostProcessors() {
310         return postProcessors;
311     }
312 
setLanguageLevel(LanguageLevel languageLevel)313     public ParserConfiguration setLanguageLevel(LanguageLevel languageLevel) {
314         this.languageLevel = assertNotNull(languageLevel);
315         return this;
316     }
317 
getLanguageLevel()318     public LanguageLevel getLanguageLevel() {
319         return languageLevel;
320     }
321 
322     /**
323      * When set to true, unicode escape handling is done by preprocessing the whole input,
324      * meaning that all unicode escapes are turned into unicode characters before parsing.
325      * That means the AST will never contain literal unicode escapes. However,
326      * positions in the AST will point to the original input, which is exactly the same as without this option.
327      * Without this option enabled, the unicode escapes will not be processed and are transfered intact to the AST.
328      */
setPreprocessUnicodeEscapes(boolean preprocessUnicodeEscapes)329     public ParserConfiguration setPreprocessUnicodeEscapes(boolean preprocessUnicodeEscapes) {
330         this.preprocessUnicodeEscapes = preprocessUnicodeEscapes;
331         return this;
332     }
333 
isPreprocessUnicodeEscapes()334     public boolean isPreprocessUnicodeEscapes() {
335         return preprocessUnicodeEscapes;
336     }
337 
getCharacterEncoding()338     public Charset getCharacterEncoding() {
339         return characterEncoding;
340     }
341 
342     /**
343      * The character encoding used for reading input from files and streams. By default UTF8 is used.
344      */
setCharacterEncoding(Charset characterEncoding)345     public ParserConfiguration setCharacterEncoding(Charset characterEncoding) {
346         this.characterEncoding = characterEncoding;
347         return this;
348     }
349 
350 }
351