1 /*******************************************************************************
2  * Copyright (c) 2000, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Tom Tromey - Contribution for bug 125961
14  *     Tom Tromey - Contribution for bug 159641
15  *     Benjamin Muskalla - Contribution for bug 239066
16  *     Stephan Herrmann  - Contributions for
17  *     							bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used
18  *     							bug 295551 - Add option to automatically promote all warnings to errors
19  *     							bug 359721 - [options] add command line option for new warning token "resource"
20  *								bug 365208 - [compiler][batch] command line options for annotation based null analysis
21  *								bug 374605 - Unreasonable warning for enum-based switch statements
22  *								bug 375366 - ECJ ignores unusedParameterIncludeDocCommentReference unless enableJavadoc option is set
23  *								bug 388281 - [compiler][null] inheritance of null annotations as an option
24  *								bug 381443 - [compiler][null] Allow parameter widening from @NonNull to unannotated
25  *								Bug 440477 - [null] Infrastructure for feeding external annotations into compilation
26  *								Bug 440687 - [compiler][batch][null] improve command line option for external annotations
27  *								Bug 408815 - [batch][null] Add CLI option for COMPILER_PB_SYNTACTIC_NULL_ANALYSIS_FOR_FIELDS
28  *     Jesper S Moller   - Contributions for
29  *								bug 407297 - [1.8][compiler] Control generation of parameter names by option
30  *    Mat Booth - Contribution for bug 405176
31  *    Frits Jalvingh - fix for bug 533830.
32  *******************************************************************************/
33 package org.eclipse.jdt.internal.compiler.batch;
34 
35 import java.io.BufferedInputStream;
36 import java.io.ByteArrayInputStream;
37 import java.io.File;
38 import java.io.FileInputStream;
39 import java.io.FileNotFoundException;
40 import java.io.FileOutputStream;
41 import java.io.FileReader;
42 import java.io.FilenameFilter;
43 import java.io.IOException;
44 import java.io.InputStreamReader;
45 import java.io.LineNumberReader;
46 import java.io.OutputStreamWriter;
47 import java.io.PrintWriter;
48 import java.io.StringReader;
49 import java.io.StringWriter;
50 import java.io.UnsupportedEncodingException;
51 import java.lang.reflect.Field;
52 import java.lang.reflect.InvocationTargetException;
53 import java.lang.reflect.Method;
54 import java.nio.file.Path;
55 import java.nio.file.Paths;
56 import java.text.DateFormat;
57 import java.text.MessageFormat;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.Collections;
61 import java.util.Comparator;
62 import java.util.Date;
63 import java.util.HashMap;
64 import java.util.HashSet;
65 import java.util.Iterator;
66 import java.util.List;
67 import java.util.Locale;
68 import java.util.Map;
69 import java.util.Map.Entry;
70 import java.util.MissingResourceException;
71 import java.util.Properties;
72 import java.util.ResourceBundle;
73 import java.util.Set;
74 import java.util.StringTokenizer;
75 
76 import org.eclipse.jdt.core.compiler.CategorizedProblem;
77 import org.eclipse.jdt.core.compiler.CharOperation;
78 import org.eclipse.jdt.core.compiler.CompilationProgress;
79 import org.eclipse.jdt.core.compiler.IProblem;
80 import org.eclipse.jdt.core.compiler.batch.BatchCompiler;
81 import org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager;
82 import org.eclipse.jdt.internal.compiler.ClassFile;
83 import org.eclipse.jdt.internal.compiler.CompilationResult;
84 import org.eclipse.jdt.internal.compiler.Compiler;
85 import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
86 import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
87 import org.eclipse.jdt.internal.compiler.IProblemFactory;
88 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
89 import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath;
90 import org.eclipse.jdt.internal.compiler.batch.ModuleFinder.AddExport;
91 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
92 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
93 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
94 import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
95 import org.eclipse.jdt.internal.compiler.env.AccessRule;
96 import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
97 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
98 import org.eclipse.jdt.internal.compiler.env.IModule;
99 import org.eclipse.jdt.internal.compiler.env.IModule.IPackageExport;
100 import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.UpdateKind;
101 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
102 import org.eclipse.jdt.internal.compiler.impl.CompilerStats;
103 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
104 import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
105 import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
106 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
107 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
108 import org.eclipse.jdt.internal.compiler.parser.Parser;
109 import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
110 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
111 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
112 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
113 import org.eclipse.jdt.internal.compiler.util.GenericXMLWriter;
114 import org.eclipse.jdt.internal.compiler.util.HashtableOfInt;
115 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
116 import org.eclipse.jdt.internal.compiler.util.Messages;
117 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
118 import org.eclipse.jdt.internal.compiler.util.Util;
119 
120 public class Main implements ProblemSeverities, SuffixConstants {
121 
122 	public static class Logger {
123 		private PrintWriter err;
124 		private PrintWriter log;
125 		private Main main;
126 		private PrintWriter out;
127 		private HashMap<String, Object> parameters;
128 		int tagBits;
129 		private static final String CLASS = "class"; //$NON-NLS-1$
130 		private static final String CLASS_FILE = "classfile"; //$NON-NLS-1$
131 		private static final String CLASSPATH = "classpath"; //$NON-NLS-1$
132 		private static final String CLASSPATH_FILE = "FILE"; //$NON-NLS-1$
133 		private static final String CLASSPATH_FOLDER = "FOLDER"; //$NON-NLS-1$
134 		private static final String CLASSPATH_ID = "id"; //$NON-NLS-1$
135 		private static final String CLASSPATH_JAR = "JAR"; //$NON-NLS-1$
136 		private static final String CLASSPATHS = "classpaths"; //$NON-NLS-1$
137 		private static final String COMMAND_LINE_ARGUMENT = "argument"; //$NON-NLS-1$
138 		private static final String COMMAND_LINE_ARGUMENTS = "command_line"; //$NON-NLS-1$
139 		private static final String COMPILER = "compiler"; //$NON-NLS-1$
140 		private static final String COMPILER_COPYRIGHT = "copyright"; //$NON-NLS-1$
141 		private static final String COMPILER_NAME = "name"; //$NON-NLS-1$
142 		private static final String COMPILER_VERSION = "version"; //$NON-NLS-1$
143 		public static final int EMACS = 2;
144 		private static final String ERROR = "ERROR"; //$NON-NLS-1$
145 		private static final String ERROR_TAG = "error"; //$NON-NLS-1$
146 		private static final String WARNING_TAG = "warning"; //$NON-NLS-1$
147 		private static final String EXCEPTION = "exception"; //$NON-NLS-1$
148 		private static final String EXTRA_PROBLEM_TAG = "extra_problem"; //$NON-NLS-1$
149 		private static final String EXTRA_PROBLEMS = "extra_problems"; //$NON-NLS-1$
150 		private static final HashtableOfInt FIELD_TABLE = new HashtableOfInt();
151 		private static final String KEY = "key"; //$NON-NLS-1$
152 		private static final String MESSAGE = "message"; //$NON-NLS-1$
153 		private static final String NUMBER_OF_CLASSFILES = "number_of_classfiles"; //$NON-NLS-1$
154 		private static final String NUMBER_OF_ERRORS = "errors"; //$NON-NLS-1$
155 		private static final String NUMBER_OF_LINES = "number_of_lines"; //$NON-NLS-1$
156 		private static final String NUMBER_OF_PROBLEMS = "problems"; //$NON-NLS-1$
157 		private static final String NUMBER_OF_TASKS = "tasks"; //$NON-NLS-1$
158 		private static final String NUMBER_OF_WARNINGS = "warnings"; //$NON-NLS-1$
159 		private static final String NUMBER_OF_INFOS = "infos"; //$NON-NLS-1$
160 		private static final String OPTION = "option"; //$NON-NLS-1$
161 		private static final String OPTIONS = "options"; //$NON-NLS-1$
162 		private static final String OUTPUT = "output"; //$NON-NLS-1$
163 		private static final String PACKAGE = "package"; //$NON-NLS-1$
164 		private static final String PATH = "path"; //$NON-NLS-1$
165 		private static final String PROBLEM_ARGUMENT = "argument"; //$NON-NLS-1$
166 		private static final String PROBLEM_ARGUMENT_VALUE = "value"; //$NON-NLS-1$
167 		private static final String PROBLEM_ARGUMENTS = "arguments"; //$NON-NLS-1$
168 		private static final String PROBLEM_CATEGORY_ID = "categoryID"; //$NON-NLS-1$
169 		private static final String ID = "id"; //$NON-NLS-1$
170 		private static final String PROBLEM_ID = "problemID"; //$NON-NLS-1$
171 		private static final String PROBLEM_LINE = "line"; //$NON-NLS-1$
172 		private static final String PROBLEM_OPTION_KEY = "optionKey"; //$NON-NLS-1$
173 		private static final String PROBLEM_MESSAGE = "message"; //$NON-NLS-1$
174 		private static final String PROBLEM_SEVERITY = "severity"; //$NON-NLS-1$
175 		private static final String PROBLEM_SOURCE_END = "charEnd"; //$NON-NLS-1$
176 		private static final String PROBLEM_SOURCE_START = "charStart"; //$NON-NLS-1$
177 		private static final String PROBLEM_SUMMARY = "problem_summary"; //$NON-NLS-1$
178 		private static final String PROBLEM_TAG = "problem"; //$NON-NLS-1$
179 		private static final String PROBLEMS = "problems"; //$NON-NLS-1$
180 		private static final String SOURCE = "source"; //$NON-NLS-1$
181 		private static final String SOURCE_CONTEXT = "source_context"; //$NON-NLS-1$
182 		private static final String SOURCE_END = "sourceEnd"; //$NON-NLS-1$
183 		private static final String SOURCE_START = "sourceStart"; //$NON-NLS-1$
184 		private static final String SOURCES = "sources"; //$NON-NLS-1$
185 
186 		private static final String STATS = "stats"; //$NON-NLS-1$
187 
188 		private static final String TASK = "task"; //$NON-NLS-1$
189 		private static final String TASKS = "tasks"; //$NON-NLS-1$
190 		private static final String TIME = "time"; //$NON-NLS-1$
191 		private static final String VALUE = "value"; //$NON-NLS-1$
192 		private static final String WARNING = "WARNING"; //$NON-NLS-1$
193 		private static final String INFO = "INFO"; //$NON-NLS-1$
194 
195 		public static final int XML = 1;
196 		private static final String XML_DTD_DECLARATION = "<!DOCTYPE compiler PUBLIC \"-//Eclipse.org//DTD Eclipse JDT 3.2.006 Compiler//EN\" \"http://www.eclipse.org/jdt/core/compiler_32_006.dtd\">"; //$NON-NLS-1$
197 		static {
198 			try {
199 				Class<?> c = IProblem.class;
200 				Field[] fields = c.getFields();
201 				for (int i = 0, max = fields.length; i < max; i++) {
202 					Field field = fields[i];
203 					if (field.getType().equals(Integer.TYPE)) {
204 						Integer value = (Integer) field.get(null);
205 						int key2 = value.intValue() & IProblem.IgnoreCategoriesMask;
206 						if (key2 == 0) {
207 							key2 = Integer.MAX_VALUE;
208 						}
Logger.FIELD_TABLE.put(key2, field.getName())209 						Logger.FIELD_TABLE.put(key2, field.getName());
210 					}
211 				}
212 			} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
213 				e.printStackTrace();
214 			}
215 		}
Logger(Main main, PrintWriter out, PrintWriter err)216 		public Logger(Main main, PrintWriter out, PrintWriter err) {
217 			this.out = out;
218 			this.err = err;
219 			this.parameters = new HashMap<>();
220 			this.main = main;
221 		}
222 
buildFileName( String outputPath, String relativeFileName)223 		public String buildFileName(
224 			String outputPath,
225 			String relativeFileName) {
226 			char fileSeparatorChar = File.separatorChar;
227 			String fileSeparator = File.separator;
228 
229 			outputPath = outputPath.replace('/', fileSeparatorChar);
230 			// To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
231 			StringBuffer outDir = new StringBuffer(outputPath);
232 			if (!outputPath.endsWith(fileSeparator)) {
233 				outDir.append(fileSeparator);
234 			}
235 			StringTokenizer tokenizer =
236 				new StringTokenizer(relativeFileName, fileSeparator);
237 			String token = tokenizer.nextToken();
238 			while (tokenizer.hasMoreTokens()) {
239 				outDir.append(token).append(fileSeparator);
240 				token = tokenizer.nextToken();
241 			}
242 			// token contains the last one
243 			return outDir.append(token).toString();
244 		}
245 
close()246 		public void close() {
247 			if (this.log != null) {
248 				if ((this.tagBits & Logger.XML) != 0) {
249 					endTag(Logger.COMPILER);
250 					flush();
251 				}
252 				this.log.close();
253 			}
254 		}
255 
256 		/**
257 		 *
258 		 */
compiling()259 		public void compiling() {
260 			printlnOut(this.main.bind("progress.compiling")); //$NON-NLS-1$
261 		}
endLoggingExtraProblems()262 		private void endLoggingExtraProblems() {
263 			endTag(Logger.EXTRA_PROBLEMS);
264 		}
265 		/**
266 		 * Used to stop logging problems.
267 		 * Only use in xml mode.
268 		 */
endLoggingProblems()269 		private void endLoggingProblems() {
270 			endTag(Logger.PROBLEMS);
271 		}
endLoggingSource()272 		public void endLoggingSource() {
273 			if ((this.tagBits & Logger.XML) != 0) {
274 				endTag(Logger.SOURCE);
275 			}
276 		}
277 
endLoggingSources()278 		public void endLoggingSources() {
279 			if ((this.tagBits & Logger.XML) != 0) {
280 				endTag(Logger.SOURCES);
281 			}
282 		}
283 
endLoggingTasks()284 		public void endLoggingTasks() {
285 			if ((this.tagBits & Logger.XML) != 0) {
286 				endTag(Logger.TASKS);
287 			}
288 		}
endTag(String name)289 		private void endTag(String name) {
290 			if (this.log != null) {
291 				((GenericXMLWriter) this.log).endTag(name, true, true);
292 			}
293 		}
errorReportSource(CategorizedProblem problem, char[] unitSource, int bits)294 		private String errorReportSource(CategorizedProblem problem, char[] unitSource, int bits) {
295 			//extra from the source the innacurate     token
296 			//and "highlight" it using some underneath ^^^^^
297 			//put some context around too.
298 
299 			//this code assumes that the font used in the console is fixed size
300 
301 			//sanity .....
302 			int startPosition = problem.getSourceStart();
303 			int endPosition = problem.getSourceEnd();
304 			if (unitSource == null) {
305 				if (problem.getOriginatingFileName() != null) {
306 					try {
307 						unitSource = Util.getFileCharContent(new File(new String(problem.getOriginatingFileName())), null);
308 					} catch (IOException e) {
309 						// ignore;
310 					}
311 				}
312 			}
313 			int length;
314 			if ((startPosition > endPosition)
315 				|| ((startPosition < 0) && (endPosition < 0))
316 				|| (unitSource == null)
317 				|| (length = unitSource.length) == 0)
318 				return Messages.problem_noSourceInformation;
319 
320 			StringBuffer errorBuffer = new StringBuffer();
321 			if ((bits & Main.Logger.EMACS) == 0) {
322 				errorBuffer.append(' ').append(Messages.bind(Messages.problem_atLine, String.valueOf(problem.getSourceLineNumber())));
323 				errorBuffer.append(Util.LINE_SEPARATOR);
324 			}
325 			errorBuffer.append('\t');
326 
327 			char c;
328 			final char SPACE = '\u0020';
329 			final char MARK = '^';
330 			final char TAB = '\t';
331 			//the next code tries to underline the token.....
332 			//it assumes (for a good display) that token source does not
333 			//contain any \r \n. This is false on statements !
334 			//(the code still works but the display is not optimal !)
335 
336 			// expand to line limits
337 			int begin;
338 			int end;
339 			for (begin = startPosition >= length ? length - 1 : startPosition; begin > 0; begin--) {
340 				if ((c = unitSource[begin - 1]) == '\n' || c == '\r') break;
341 			}
342 			for (end = endPosition >= length ? length - 1 : endPosition ; end+1 < length; end++) {
343 				if ((c = unitSource[end + 1]) == '\r' || c == '\n') break;
344 			}
345 
346 			// trim left and right spaces/tabs
347 			while ((c = unitSource[begin]) == ' ' || c == '\t') begin++;
348 			//while ((c = unitSource[end]) == ' ' || c == '\t') end--; TODO (philippe) should also trim right, but all tests are to be updated
349 
350 			// copy source
351 			errorBuffer.append(unitSource, begin, end-begin+1);
352 			errorBuffer.append(Util.LINE_SEPARATOR).append("\t"); //$NON-NLS-1$
353 
354 			// compute underline
355 			for (int i = begin; i <startPosition; i++) {
356 				errorBuffer.append((unitSource[i] == TAB) ? TAB : SPACE);
357 			}
358 			for (int i = startPosition; i <= (endPosition >= length ? length - 1 : endPosition); i++) {
359 				errorBuffer.append(MARK);
360 			}
361 			return errorBuffer.toString();
362 		}
363 
extractContext(CategorizedProblem problem, char[] unitSource)364 		private void extractContext(CategorizedProblem problem, char[] unitSource) {
365 			//sanity .....
366 			int startPosition = problem.getSourceStart();
367 			int endPosition = problem.getSourceEnd();
368 			if (unitSource == null) {
369 				if (problem.getOriginatingFileName() != null) {
370 					try {
371 						unitSource = Util.getFileCharContent(new File(new String(problem.getOriginatingFileName())), null);
372 					} catch(IOException e) {
373 						// ignore
374 					}
375 				}
376 			}
377 			int length;
378 			if ((startPosition > endPosition)
379 					|| ((startPosition < 0) && (endPosition < 0))
380 					|| (unitSource == null)
381 					|| ((length = unitSource.length) <= 0)
382 					|| (endPosition > length)) {
383 				this.parameters.put(Logger.VALUE, Messages.problem_noSourceInformation);
384 				this.parameters.put(Logger.SOURCE_START, "-1"); //$NON-NLS-1$
385 				this.parameters.put(Logger.SOURCE_END, "-1"); //$NON-NLS-1$
386 				printTag(Logger.SOURCE_CONTEXT, this.parameters, true, true);
387 				return;
388 			}
389 
390 			char c;
391 			//the next code tries to underline the token.....
392 			//it assumes (for a good display) that token source does not
393 			//contain any \r \n. This is false on statements !
394 			//(the code still works but the display is not optimal !)
395 
396 			// expand to line limits
397 			int begin, end;
398 			for (begin = startPosition >= length ? length - 1 : startPosition; begin > 0; begin--) {
399 				if ((c = unitSource[begin - 1]) == '\n' || c == '\r') break;
400 			}
401 			for (end = endPosition >= length ? length - 1 : endPosition ; end+1 < length; end++) {
402 				if ((c = unitSource[end + 1]) == '\r' || c == '\n') break;
403 			}
404 
405 			// trim left and right spaces/tabs
406 			while ((c = unitSource[begin]) == ' ' || c == '\t') begin++;
407 			while ((c = unitSource[end]) == ' ' || c == '\t') end--;
408 
409 			// copy source
410 			StringBuffer buffer = new StringBuffer();
411 			buffer.append(unitSource, begin, end - begin + 1);
412 
413 			this.parameters.put(Logger.VALUE, String.valueOf(buffer));
414 			this.parameters.put(Logger.SOURCE_START, Integer.toString(startPosition - begin));
415 			this.parameters.put(Logger.SOURCE_END, Integer.toString(endPosition - begin));
416 			printTag(Logger.SOURCE_CONTEXT, this.parameters, true, true);
417 		}
flush()418 		public void flush() {
419 			this.out.flush();
420 			this.err.flush();
421 			if (this.log != null) {
422 				this.log.flush();
423 			}
424 		}
425 
getFieldName(int id)426 		private String getFieldName(int id) {
427 			int key2 = id & IProblem.IgnoreCategoriesMask;
428 			if (key2 == 0) {
429 				key2 = Integer.MAX_VALUE;
430 			}
431 			return (String) Logger.FIELD_TABLE.get(key2);
432 		}
433 
434 		// find out an option name controlling a given problemID
getProblemOptionKey(int problemID)435 		private String getProblemOptionKey(int problemID) {
436 			int irritant = ProblemReporter.getIrritant(problemID);
437 			return CompilerOptions.optionKeyFromIrritant(irritant);
438 		}
439 
logAverage()440 		public void logAverage() {
441 			Arrays.sort(this.main.compilerStats);
442 			long lineCount = this.main.compilerStats[0].lineCount;
443 			final int length = this.main.maxRepetition;
444 			long sum = 0;
445 			long parseSum = 0, resolveSum = 0, analyzeSum = 0, generateSum = 0;
446 			for (int i = 1, max = length - 1; i < max; i++) {
447 				CompilerStats stats = this.main.compilerStats[i];
448 				sum += stats.elapsedTime();
449 				parseSum += stats.parseTime;
450 				resolveSum += stats.resolveTime;
451 				analyzeSum += stats.analyzeTime;
452 				generateSum += stats.generateTime;
453 			}
454 			long time = sum / (length - 2);
455 			long parseTime = parseSum/(length - 2);
456 			long resolveTime = resolveSum/(length - 2);
457 			long analyzeTime = analyzeSum/(length - 2);
458 			long generateTime = generateSum/(length - 2);
459 			printlnOut(this.main.bind(
460 				"compile.averageTime", //$NON-NLS-1$
461 				new String[] {
462 					String.valueOf(lineCount),
463 					String.valueOf(time),
464 					String.valueOf(((int) (lineCount * 10000.0 / time)) / 10.0),
465 				}));
466 			if ((this.main.timing & Main.TIMING_DETAILED) != 0) {
467 				printlnOut(
468 						this.main.bind("compile.detailedTime", //$NON-NLS-1$
469 							new String[] {
470 								String.valueOf(parseTime),
471 								String.valueOf(((int) (parseTime * 1000.0 / time)) / 10.0),
472 								String.valueOf(resolveTime),
473 								String.valueOf(((int) (resolveTime * 1000.0 / time)) / 10.0),
474 								String.valueOf(analyzeTime),
475 								String.valueOf(((int) (analyzeTime * 1000.0 / time)) / 10.0),
476 								String.valueOf(generateTime),
477 								String.valueOf(((int) (generateTime * 1000.0 / time)) / 10.0),
478 							}));
479 			}
480 		}
logClassFile(boolean generatePackagesStructure, String outputPath, String relativeFileName)481 		public void logClassFile(boolean generatePackagesStructure, String outputPath, String relativeFileName) {
482 			if ((this.tagBits & Logger.XML) != 0) {
483 				String fileName = null;
484 				if (generatePackagesStructure) {
485 					fileName = buildFileName(outputPath, relativeFileName);
486 				} else {
487 					char fileSeparatorChar = File.separatorChar;
488 					String fileSeparator = File.separator;
489 					// First we ensure that the outputPath exists
490 					outputPath = outputPath.replace('/', fileSeparatorChar);
491 					// To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
492 					int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar);
493 					if (indexOfPackageSeparator == -1) {
494 						if (outputPath.endsWith(fileSeparator)) {
495 							fileName = outputPath + relativeFileName;
496 						} else {
497 							fileName = outputPath + fileSeparator + relativeFileName;
498 						}
499 					} else {
500 						int length = relativeFileName.length();
501 						if (outputPath.endsWith(fileSeparator)) {
502 							fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length);
503 						} else {
504 							fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length);
505 						}
506 					}
507 				}
508 				File f = new File(fileName);
509 				try {
510 					this.parameters.put(Logger.PATH, f.getCanonicalPath());
511 					printTag(Logger.CLASS_FILE, this.parameters, true, true);
512 				} catch (IOException e) {
513 					logNoClassFileCreated(outputPath, relativeFileName, e);
514 				}
515 			}
516 		}
logClasspath(FileSystem.Classpath[] classpaths)517 		public void logClasspath(FileSystem.Classpath[] classpaths) {
518 			if (classpaths == null) return;
519 			if ((this.tagBits & Logger.XML) != 0) {
520 				final int length = classpaths.length;
521 				if (length != 0) {
522 					// generate xml output
523 					printTag(Logger.CLASSPATHS, null, true, false);
524 					for (int i = 0; i < length; i++) {
525 						String classpath = classpaths[i].getPath();
526 						this.parameters.put(Logger.PATH, classpath);
527 						File f = new File(classpath);
528 						String id = null;
529 						if (f.isFile()) {
530 							int kind = Util.archiveFormat(classpath);
531 							switch (kind) {
532 								case Util.ZIP_FILE:
533 									id = Logger.CLASSPATH_JAR;
534 									break;
535 								default:
536 									id = Logger.CLASSPATH_FILE;
537 									break;
538 							}
539 						} else if (f.isDirectory()) {
540 							id = Logger.CLASSPATH_FOLDER;
541 						}
542 						if (id != null) {
543 							this.parameters.put(Logger.CLASSPATH_ID, id);
544 							printTag(Logger.CLASSPATH, this.parameters, true, true);
545 						}
546 					}
547 					endTag(Logger.CLASSPATHS);
548 				}
549 			}
550 
551 		}
552 
logCommandLineArguments(String[] commandLineArguments)553 		public void logCommandLineArguments(String[] commandLineArguments) {
554 			if (commandLineArguments == null) return;
555 			if ((this.tagBits & Logger.XML) != 0) {
556 				final int length = commandLineArguments.length;
557 				if (length != 0) {
558 					// generate xml output
559 					printTag(Logger.COMMAND_LINE_ARGUMENTS, null, true, false);
560 					for (int i = 0; i < length; i++) {
561 						this.parameters.put(Logger.VALUE, commandLineArguments[i]);
562 						printTag(Logger.COMMAND_LINE_ARGUMENT, this.parameters, true, true);
563 					}
564 					endTag(Logger.COMMAND_LINE_ARGUMENTS);
565 				}
566 			}
567 		}
568 
569 		/**
570 		 * @param e the given exception to log
571 		 */
logException(Exception e)572 		public void logException(Exception e) {
573 			StringWriter writer = new StringWriter();
574 			PrintWriter printWriter = new PrintWriter(writer);
575 			e.printStackTrace(printWriter);
576 			printWriter.flush();
577 			printWriter.close();
578 			final String stackTrace = writer.toString();
579 			if ((this.tagBits & Logger.XML) != 0) {
580 				LineNumberReader reader = new LineNumberReader(new StringReader(stackTrace));
581 				String line;
582 				int i = 0;
583 				StringBuffer buffer = new StringBuffer();
584 				String message = e.getMessage();
585 				if (message != null) {
586 					buffer.append(message).append(Util.LINE_SEPARATOR);
587 				}
588 				try {
589 					while ((line = reader.readLine()) != null && i < 4) {
590 						buffer.append(line).append(Util.LINE_SEPARATOR);
591 						i++;
592 					}
593 					reader.close();
594 				} catch (IOException e1) {
595 					// ignore
596 				}
597 				message = buffer.toString();
598 				this.parameters.put(Logger.MESSAGE, message);
599 				this.parameters.put(Logger.CLASS, e.getClass());
600 				printTag(Logger.EXCEPTION, this.parameters, true, true);
601 			}
602 			String message = e.getMessage();
603 			if (message == null) {
604 				this.printlnErr(stackTrace);
605 			} else {
606 				this.printlnErr(message);
607 			}
608 		}
609 
logExtraProblem(CategorizedProblem problem, int localErrorCount, int globalErrorCount)610 		private void logExtraProblem(CategorizedProblem problem, int localErrorCount, int globalErrorCount) {
611 			char[] originatingFileName = problem.getOriginatingFileName();
612 			if (originatingFileName == null) {
613 				// simplified message output
614 				String severity = problem.isError() ? "requestor.extraerror" //$NON-NLS-1$
615 						: problem.isInfo() ? "requestor.extrainfo" : "requestor.extrawarning"; //$NON-NLS-1$ //$NON-NLS-2$
616 				printErr(this.main.bind(
617 								severity,
618 								Integer.toString(globalErrorCount)));
619 				printErr(" "); //$NON-NLS-1$
620 				this.printlnErr(problem.getMessage());
621 			} else {
622 				String fileName = new String(originatingFileName);
623 				if ((this.tagBits & Logger.EMACS) != 0) {
624 					String severity = problem.isError() ? "output.emacs.error" : //$NON-NLS-1$
625 										problem.isInfo() ? "output.emacs.info" //$NON-NLS-1$
626 													: "output.emacs.warning"; //$NON-NLS-1$
627 					String result = fileName
628 							+ ":" //$NON-NLS-1$
629 							+ problem.getSourceLineNumber()
630 							+ ": " //$NON-NLS-1$
631 							+ this.main.bind(severity)
632 							+ ": " //$NON-NLS-1$
633 							+ problem.getMessage();
634 					this.printlnErr(result);
635 					final String errorReportSource = errorReportSource(problem, null, this.tagBits);
636 					this.printlnErr(errorReportSource);
637 				} else {
638 					if (localErrorCount == 0) {
639 						this.printlnErr("----------"); //$NON-NLS-1$
640 					}
641 					String severity = problem.isError() ? "requestor.error" //$NON-NLS-1$
642 							: problem.isInfo() ? "requestor.info" : "requestor.warning"; //$NON-NLS-1$ //$NON-NLS-2$
643 					printErr(this.main.bind(
644 								severity,
645 								Integer.toString(globalErrorCount),
646 								fileName));
647 					final String errorReportSource = errorReportSource(problem, null, 0);
648 					this.printlnErr(errorReportSource);
649 					this.printlnErr(problem.getMessage());
650 					this.printlnErr("----------"); //$NON-NLS-1$
651 				}
652 			}
653 		}
654 
loggingExtraProblems(Main currentMain)655 		public void loggingExtraProblems(Main currentMain) {
656 			ArrayList<CategorizedProblem> problems = currentMain.extraProblems;
657 			final int count = problems.size();
658 			int localProblemCount = 0;
659 			if (count != 0) {
660 				int errors = 0;
661 				int warnings = 0;
662 				int infos = 0;
663 				for (int i = 0; i < count; i++) {
664 					CategorizedProblem problem = problems.get(i);
665 					if (!this.main.isIgnored(problem)) {
666 						currentMain.globalProblemsCount++;
667 						logExtraProblem(problem, localProblemCount, currentMain.globalProblemsCount);
668 						localProblemCount++;
669 						if (problem.isError()) {
670 							errors++;
671 							currentMain.globalErrorsCount++;
672 						} else if (problem.isInfo()) {
673 							currentMain.globalInfoCount++;
674 							infos++;
675 						} else {
676 							currentMain.globalWarningsCount++;
677 							warnings++;
678 						}
679 					}
680 				}
681 				if ((this.tagBits & Logger.XML) != 0) {
682 					if ((errors + warnings + infos) != 0) {
683 						startLoggingExtraProblems(count);
684 						for (int i = 0; i < count; i++) {
685 							CategorizedProblem problem = problems.get(i);
686 							if (!this.main.isIgnored(problem)) {
687 								if (problem.getID() != IProblem.Task) {
688 									logXmlExtraProblem(problem, localProblemCount, currentMain.globalProblemsCount);
689 								}
690 							}
691 						}
692 						endLoggingExtraProblems();
693 					}
694 				}
695 			}
696 		}
697 
logUnavaibleAPT(String className)698 		public void logUnavaibleAPT(String className) {
699 			if ((this.tagBits & Logger.XML) != 0) {
700 				this.parameters.put(Logger.MESSAGE, this.main.bind("configure.unavailableAPT", className)); //$NON-NLS-1$
701 				printTag(Logger.ERROR_TAG, this.parameters, true, true);
702 			}
703 			this.printlnErr(this.main.bind("configure.unavailableAPT", className)); //$NON-NLS-1$
704 		}
705 
logIncorrectVMVersionForAnnotationProcessing()706 		public void logIncorrectVMVersionForAnnotationProcessing() {
707 			if ((this.tagBits & Logger.XML) != 0) {
708 				this.parameters.put(Logger.MESSAGE, this.main.bind("configure.incorrectVMVersionforAPT")); //$NON-NLS-1$
709 				printTag(Logger.ERROR_TAG, this.parameters, true, true);
710 			}
711 			this.printlnErr(this.main.bind("configure.incorrectVMVersionforAPT")); //$NON-NLS-1$
712 		}
713 
714 		/**
715 		 *
716 		 */
logNoClassFileCreated(String outputDir, String relativeFileName, IOException e)717 		public void logNoClassFileCreated(String outputDir, String relativeFileName, IOException e) {
718 			if ((this.tagBits & Logger.XML) != 0) {
719 				this.parameters.put(Logger.MESSAGE, this.main.bind("output.noClassFileCreated", //$NON-NLS-1$
720 					new String[] {
721 						outputDir,
722 						relativeFileName,
723 						e.getMessage()
724 					}));
725 				printTag(Logger.ERROR_TAG, this.parameters, true, true);
726 			}
727 			this.printlnErr(this.main.bind("output.noClassFileCreated", //$NON-NLS-1$
728 				new String[] {
729 					outputDir,
730 					relativeFileName,
731 					e.getMessage()
732 				}));
733 		}
734 
735 		/**
736 		 * @param exportedClassFilesCounter
737 		 */
logNumberOfClassFilesGenerated(int exportedClassFilesCounter)738 		public void logNumberOfClassFilesGenerated(int exportedClassFilesCounter) {
739 			if ((this.tagBits & Logger.XML) != 0) {
740 				this.parameters.put(Logger.VALUE, Integer.valueOf(exportedClassFilesCounter));
741 				printTag(Logger.NUMBER_OF_CLASSFILES, this.parameters, true, true);
742 			}
743 			if (exportedClassFilesCounter == 1) {
744 				printlnOut(this.main.bind("compile.oneClassFileGenerated")); //$NON-NLS-1$
745 			} else {
746 				printlnOut(this.main.bind("compile.severalClassFilesGenerated", //$NON-NLS-1$
747 					String.valueOf(exportedClassFilesCounter)));
748 			}
749 		}
750 
751 		/**
752 		 * @param options the given compiler options
753 		 */
logOptions(Map<String, String> options)754 		public void logOptions(Map<String, String> options) {
755 			if ((this.tagBits & Logger.XML) != 0) {
756 				printTag(Logger.OPTIONS, null, true, false);
757 				final Set<Map.Entry<String, String>> entriesSet = options.entrySet();
758 				Map.Entry<String, String>[] entries = entriesSet.toArray(new Map.Entry[entriesSet.size()]);
759 				Arrays.sort(entries, new Comparator<Map.Entry<String, String>>() {
760 					@Override
761 					public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
762 						Map.Entry<String, String> entry1 = o1;
763 						Map.Entry<String, String> entry2 = o2;
764 						return entry1.getKey().compareTo(entry2.getKey());
765 					}
766 				});
767 				for (int i = 0, max = entries.length; i < max; i++) {
768 					Map.Entry<String, String> entry = entries[i];
769 					String key = entry.getKey();
770 					this.parameters.put(Logger.KEY, key);
771 					this.parameters.put(Logger.VALUE, entry.getValue());
772 					printTag(Logger.OPTION, this.parameters, true, true);
773 				}
774 				endTag(Logger.OPTIONS);
775 			}
776 		}
777 
778 		/**
779 		 * @param error the given error
780 		 */
logPendingError(String error)781 		public void logPendingError(String error) {
782 			if ((this.tagBits & Logger.XML) != 0) {
783 				this.parameters.put(Logger.MESSAGE, error);
784 				printTag(Logger.ERROR_TAG, this.parameters, true, true);
785 			}
786 			this.printlnErr(error);
787 		}
788 
789 		/**
790 		 * @param message the given message
791 		 */
logWarning(String message)792 		public void logWarning(String message) {
793 			if ((this.tagBits & Logger.XML) != 0) {
794 				this.parameters.put(Logger.MESSAGE, message);
795 				printTag(Logger.WARNING_TAG, this.parameters, true, true);
796 			}
797 			this.printlnOut(message);
798 		}
799 
logProblem(CategorizedProblem problem, int localErrorCount, int globalErrorCount, char[] unitSource)800 		private void logProblem(CategorizedProblem problem, int localErrorCount,
801 			int globalErrorCount, char[] unitSource) {
802 			if(problem instanceof DefaultProblem) {
803 				((DefaultProblem) problem).reportError();
804 			}
805 			if ((this.tagBits & Logger.EMACS) != 0) {
806 				String severity = problem.isError() ? "output.emacs.error" : //$NON-NLS-1$
807 									problem.isInfo() ? "output.emacs.info" //$NON-NLS-1$
808 											: "output.emacs.warning"; //$NON-NLS-1$
809 				String result = (new String(problem.getOriginatingFileName())
810 						+ ":" //$NON-NLS-1$
811 						+ problem.getSourceLineNumber()
812 						+ ": " //$NON-NLS-1$
813 						+ (this.main.bind(severity))
814 						+ ": " //$NON-NLS-1$
815 						+ problem.getMessage());
816 				this.printlnErr(result);
817 				final String errorReportSource = errorReportSource(problem, unitSource, this.tagBits);
818 				if (errorReportSource.length() != 0) this.printlnErr(errorReportSource);
819 			} else {
820 				if (localErrorCount == 0) {
821 					this.printlnErr("----------"); //$NON-NLS-1$
822 				}
823 				String severity = problem.isError() ? "requestor.error" : problem.isInfo() ? "requestor.info" : "requestor.warning";  //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
824 				printErr(this.main.bind(severity,
825 										Integer.toString(globalErrorCount),
826 										new String(problem.getOriginatingFileName())));
827 				try {
828 					final String errorReportSource = errorReportSource(problem, unitSource, 0);
829 					this.printlnErr(errorReportSource);
830 					this.printlnErr(problem.getMessage());
831 				} catch (Exception e) {
832 					this.printlnErr(this.main.bind(
833 						"requestor.notRetrieveErrorMessage", problem.toString())); //$NON-NLS-1$
834 				}
835 				this.printlnErr("----------"); //$NON-NLS-1$
836 			}
837 		}
838 
logProblems(CategorizedProblem[] problems, char[] unitSource, Main currentMain)839 		public int logProblems(CategorizedProblem[] problems, char[] unitSource, Main currentMain) {
840 			final int count = problems.length;
841 			int localErrorCount = 0;
842 			int localProblemCount = 0;
843 			if (count != 0) {
844 				int errors = 0;
845 				int warnings = 0;
846 				int infos = 0;
847 				int tasks = 0;
848 				for (int i = 0; i < count; i++) {
849 					CategorizedProblem problem = problems[i];
850 					if (problem != null) {
851 						currentMain.globalProblemsCount++;
852 						logProblem(problem, localProblemCount, currentMain.globalProblemsCount, unitSource);
853 						localProblemCount++;
854 						if (problem.isError()) {
855 							localErrorCount++;
856 							errors++;
857 							currentMain.globalErrorsCount++;
858 						} else if (problem.getID() == IProblem.Task) {
859 							currentMain.globalTasksCount++;
860 							tasks++;
861 						} else if (problem.isInfo()) {
862 							currentMain.globalInfoCount++;
863 							infos++;
864 						} else {
865 							currentMain.globalWarningsCount++;
866 							warnings++;
867 						}
868 					}
869 				}
870 				if ((this.tagBits & Logger.XML) != 0) {
871 					if ((errors + warnings + infos) != 0) {
872 						startLoggingProblems(errors, warnings, infos);
873 						for (int i = 0; i < count; i++) {
874 							CategorizedProblem problem = problems[i];
875 							if (problem!= null) {
876 								if (problem.getID() != IProblem.Task) {
877 									logXmlProblem(problem, unitSource);
878 								}
879 							}
880 						}
881 						endLoggingProblems();
882 					}
883 					if (tasks != 0) {
884 						startLoggingTasks(tasks);
885 						for (int i = 0; i < count; i++) {
886 							CategorizedProblem problem = problems[i];
887 							if (problem!= null) {
888 								if (problem.getID() == IProblem.Task) {
889 									logXmlTask(problem, unitSource);
890 								}
891 							}
892 						}
893 						endLoggingTasks();
894 					}
895 				}
896 			}
897 			return localErrorCount;
898 		}
899 
900 		/**
901 		 * @param globalProblemsCount
902 		 * @param globalErrorsCount
903 		 * @param globalWarningsCount
904 		 */
logProblemsSummary(int globalProblemsCount, int globalErrorsCount, int globalWarningsCount, int globalInfoCount, int globalTasksCount)905 		public void logProblemsSummary(int globalProblemsCount,
906 			int globalErrorsCount, int globalWarningsCount, int globalInfoCount, int globalTasksCount) {
907 			if ((this.tagBits & Logger.XML) != 0) {
908 				// generate xml
909 				this.parameters.put(Logger.NUMBER_OF_PROBLEMS, Integer.valueOf(globalProblemsCount));
910 				this.parameters.put(Logger.NUMBER_OF_ERRORS, Integer.valueOf(globalErrorsCount));
911 				this.parameters.put(Logger.NUMBER_OF_WARNINGS, Integer.valueOf(globalWarningsCount));
912 				this.parameters.put(Logger.NUMBER_OF_INFOS, Integer.valueOf(globalInfoCount));
913 				this.parameters.put(Logger.NUMBER_OF_TASKS, Integer.valueOf(globalTasksCount));
914 				printTag(Logger.PROBLEM_SUMMARY, this.parameters, true, true);
915 			}
916 			if (globalProblemsCount == 1) {
917 				String message = null;
918 				if (globalErrorsCount == 1) {
919 					message = this.main.bind("compile.oneError"); //$NON-NLS-1$
920 				} else if (globalInfoCount == 1) {
921 					message = this.main.bind("compile.oneInfo"); //$NON-NLS-1$
922 				} else {
923 					message = this.main.bind("compile.oneWarning"); //$NON-NLS-1$
924 				}
925 				printErr(this.main.bind("compile.oneProblem", message)); //$NON-NLS-1$
926 			} else {
927 				String errorMessage = null;
928 				String warningMessage = null;
929 				String infoMessage = null;
930 				if (globalErrorsCount > 0) {
931 					if (globalErrorsCount == 1) {
932 						errorMessage = this.main.bind("compile.oneError"); //$NON-NLS-1$
933 					} else {
934 						errorMessage = this.main.bind("compile.severalErrors", String.valueOf(globalErrorsCount)); //$NON-NLS-1$
935 					}
936 				}
937 				int warningsNumber = globalWarningsCount + globalTasksCount;
938 				if (warningsNumber > 0) {
939 					if (warningsNumber == 1) {
940 						warningMessage = this.main.bind("compile.oneWarning"); //$NON-NLS-1$
941 					} else {
942 						warningMessage = this.main.bind("compile.severalWarnings", String.valueOf(warningsNumber)); //$NON-NLS-1$
943 					}
944 				}
945 				if (globalInfoCount == 1) {
946 					infoMessage = this.main.bind("compile.oneInfo"); //$NON-NLS-1$
947 				} else if (globalInfoCount > 1) {
948 					infoMessage = this.main.bind("compile.severalInfos", String.valueOf(warningsNumber)); //$NON-NLS-1$
949 				}
950 				if (globalProblemsCount == globalInfoCount || globalProblemsCount == globalErrorsCount || globalProblemsCount == globalWarningsCount) {
951 					String msg = errorMessage != null ? errorMessage : warningMessage != null ? warningMessage : infoMessage;
952 					printErr(this.main.bind(
953 						"compile.severalProblemsErrorsOrWarnings", //$NON-NLS-1$
954 						String.valueOf(globalProblemsCount),
955 						msg));
956 				} else {
957 					if (globalInfoCount == 0) {
958 						printErr(this.main.bind(
959 								"compile.severalProblemsErrorsAndWarnings", //$NON-NLS-1$
960 								new String[] {
961 									String.valueOf(globalProblemsCount),
962 									errorMessage,
963 									warningMessage
964 								}));
965 					} else {
966 						if (errorMessage == null) {
967 							errorMessage  = this.main.bind("compile.severalErrors", String.valueOf(globalErrorsCount)); //$NON-NLS-1$
968 						}
969 						if (warningMessage == null) {
970 							warningMessage  = this.main.bind("compile.severalWarnings", String.valueOf(warningsNumber)); //$NON-NLS-1$
971 						}
972 						printErr(this.main.bind(
973 								"compile.severalProblems", //$NON-NLS-1$
974 								new String[] {
975 									String.valueOf(globalProblemsCount),
976 									errorMessage,
977 									warningMessage,
978 									infoMessage
979 								}));
980 					}
981 				}
982 			}
983 			if (this.main.failOnWarning && globalWarningsCount > 0) {
984 				printErr("\n"); //$NON-NLS-1$
985 				printErr(this.main.bind("compile.failOnWarning")); //$NON-NLS-1$
986 			}
987 			if ((this.tagBits & Logger.XML) == 0) {
988 				this.printlnErr();
989 			}
990 		}
991 
992 		/**
993 		 *
994 		 */
logProgress()995 		public void logProgress() {
996 			printOut('.');
997 		}
998 
999 		/**
1000 		 * @param i
1001 		 *            the current repetition number
1002 		 * @param repetitions
1003 		 *            the given number of repetitions
1004 		 */
logRepetition(int i, int repetitions)1005 		public void logRepetition(int i, int repetitions) {
1006 			printlnOut(this.main.bind("compile.repetition", //$NON-NLS-1$
1007 				String.valueOf(i + 1), String.valueOf(repetitions)));
1008 		}
1009 		/**
1010 		 * @param compilerStats
1011 		 */
logTiming(CompilerStats compilerStats)1012 		public void logTiming(CompilerStats compilerStats) {
1013 			long time = compilerStats.elapsedTime();
1014 			long lineCount = compilerStats.lineCount;
1015 			if ((this.tagBits & Logger.XML) != 0) {
1016 				this.parameters.put(Logger.VALUE, Long.valueOf(time));
1017 				printTag(Logger.TIME, this.parameters, true, true);
1018 				this.parameters.put(Logger.VALUE, Long.valueOf(lineCount));
1019 				printTag(Logger.NUMBER_OF_LINES, this.parameters, true, true);
1020 			}
1021 			if (lineCount != 0) {
1022 				printlnOut(
1023 					this.main.bind("compile.instantTime", //$NON-NLS-1$
1024 						new String[] {
1025 							String.valueOf(lineCount),
1026 							String.valueOf(time),
1027 							String.valueOf(((int) (lineCount * 10000.0 / time)) / 10.0),
1028 						}));
1029 			} else {
1030 				printlnOut(
1031 					this.main.bind("compile.totalTime", //$NON-NLS-1$
1032 						new String[] {
1033 							String.valueOf(time),
1034 						}));
1035 			}
1036 			if ((this.main.timing & Main.TIMING_DETAILED) != 0) {
1037 				printlnOut(
1038 						this.main.bind("compile.detailedTime", //$NON-NLS-1$
1039 							new String[] {
1040 								String.valueOf(compilerStats.parseTime),
1041 								String.valueOf(((int) (compilerStats.parseTime * 1000.0 / time)) / 10.0),
1042 								String.valueOf(compilerStats.resolveTime),
1043 								String.valueOf(((int) (compilerStats.resolveTime * 1000.0 / time)) / 10.0),
1044 								String.valueOf(compilerStats.analyzeTime),
1045 								String.valueOf(((int) (compilerStats.analyzeTime * 1000.0 / time)) / 10.0),
1046 								String.valueOf(compilerStats.generateTime),
1047 								String.valueOf(((int) (compilerStats.generateTime * 1000.0 / time)) / 10.0),
1048 							}));
1049 			}
1050 		}
1051 
1052 		/**
1053 		 * Print the usage of the compiler
1054 		 * @param usage
1055 		 */
logUsage(String usage)1056 		public void logUsage(String usage) {
1057 			printlnOut(usage);
1058 		}
1059 
1060 		/**
1061 		 * Print the version of the compiler in the log and/or the out field
1062 		 */
logVersion(final boolean printToOut)1063 		public void logVersion(final boolean printToOut) {
1064 			if (this.log != null && (this.tagBits & Logger.XML) == 0) {
1065 				final String version = this.main.bind("misc.version", //$NON-NLS-1$
1066 					new String[] {
1067 						this.main.bind("compiler.name"), //$NON-NLS-1$
1068 						this.main.bind("compiler.version"), //$NON-NLS-1$
1069 						this.main.bind("compiler.copyright") //$NON-NLS-1$
1070 					}
1071 				);
1072 				this.log.println("# " + version); //$NON-NLS-1$
1073 				if (printToOut) {
1074 					this.out.println(version);
1075 					this.out.flush();
1076 				}
1077 			} else if (printToOut) {
1078 				final String version = this.main.bind("misc.version", //$NON-NLS-1$
1079 					new String[] {
1080 						this.main.bind("compiler.name"), //$NON-NLS-1$
1081 						this.main.bind("compiler.version"), //$NON-NLS-1$
1082 						this.main.bind("compiler.copyright") //$NON-NLS-1$
1083 					}
1084 				);
1085 				this.out.println(version);
1086 				this.out.flush();
1087 			}
1088 		}
1089 
1090 		/**
1091 		 * Print the usage of wrong JDK
1092 		 */
logWrongJDK()1093 		public void logWrongJDK() {
1094 			if ((this.tagBits & Logger.XML) != 0) {
1095 				this.parameters.put(Logger.MESSAGE, this.main.bind("configure.requiresJDK1.2orAbove")); //$NON-NLS-1$
1096 				printTag(Logger.ERROR, this.parameters, true, true);
1097 			}
1098 			this.printlnErr(this.main.bind("configure.requiresJDK1.2orAbove")); //$NON-NLS-1$
1099 		}
1100 
logXmlExtraProblem(CategorizedProblem problem, int globalErrorCount, int localErrorCount)1101 		private void logXmlExtraProblem(CategorizedProblem problem, int globalErrorCount, int localErrorCount) {
1102 			final int sourceStart = problem.getSourceStart();
1103 			final int sourceEnd = problem.getSourceEnd();
1104 			boolean isError = problem.isError();
1105 			this.parameters.put(Logger.PROBLEM_SEVERITY, isError ? Logger.ERROR : (problem.isInfo() ? Logger.INFO : Logger.WARNING));
1106 			this.parameters.put(Logger.PROBLEM_LINE, Integer.valueOf(problem.getSourceLineNumber()));
1107 			this.parameters.put(Logger.PROBLEM_SOURCE_START, Integer.valueOf(sourceStart));
1108 			this.parameters.put(Logger.PROBLEM_SOURCE_END, Integer.valueOf(sourceEnd));
1109 			printTag(Logger.EXTRA_PROBLEM_TAG, this.parameters, true, false);
1110 			this.parameters.put(Logger.VALUE, problem.getMessage());
1111 			printTag(Logger.PROBLEM_MESSAGE, this.parameters, true, true);
1112 			extractContext(problem, null);
1113 			endTag(Logger.EXTRA_PROBLEM_TAG);
1114 		}
1115 		/**
1116 		 * @param problem
1117 		 *            the given problem to log
1118 		 * @param unitSource
1119 		 *            the given unit source
1120 		 */
logXmlProblem(CategorizedProblem problem, char[] unitSource)1121 		private void logXmlProblem(CategorizedProblem problem, char[] unitSource) {
1122 			final int sourceStart = problem.getSourceStart();
1123 			final int sourceEnd = problem.getSourceEnd();
1124 			final int id = problem.getID();
1125 			this.parameters.put(Logger.ID, getFieldName(id)); // ID as field name
1126 			this.parameters.put(Logger.PROBLEM_ID, Integer.valueOf(id)); // ID as numeric value
1127 			boolean isError = problem.isError();
1128 			int severity = isError ? ProblemSeverities.Error : ProblemSeverities.Warning;
1129 			this.parameters.put(Logger.PROBLEM_SEVERITY, isError ? Logger.ERROR : (problem.isInfo() ? Logger.INFO : Logger.WARNING));
1130 			this.parameters.put(Logger.PROBLEM_LINE, Integer.valueOf(problem.getSourceLineNumber()));
1131 			this.parameters.put(Logger.PROBLEM_SOURCE_START, Integer.valueOf(sourceStart));
1132 			this.parameters.put(Logger.PROBLEM_SOURCE_END, Integer.valueOf(sourceEnd));
1133 			String problemOptionKey = getProblemOptionKey(id);
1134 			if (problemOptionKey != null) {
1135 				this.parameters.put(Logger.PROBLEM_OPTION_KEY, problemOptionKey);
1136 			}
1137 			int categoryID = ProblemReporter.getProblemCategory(severity, id);
1138 			this.parameters.put(Logger.PROBLEM_CATEGORY_ID, Integer.valueOf(categoryID));
1139 			printTag(Logger.PROBLEM_TAG, this.parameters, true, false);
1140 			this.parameters.put(Logger.VALUE, problem.getMessage());
1141 			printTag(Logger.PROBLEM_MESSAGE, this.parameters, true, true);
1142 			extractContext(problem, unitSource);
1143 			String[] arguments = problem.getArguments();
1144 			final int length = arguments.length;
1145 			if (length != 0) {
1146 				printTag(Logger.PROBLEM_ARGUMENTS, null, true, false);
1147 				for (int i = 0; i < length; i++) {
1148 					this.parameters.put(Logger.PROBLEM_ARGUMENT_VALUE, arguments[i]);
1149 					printTag(Logger.PROBLEM_ARGUMENT, this.parameters, true, true);
1150 				}
1151 				endTag(Logger.PROBLEM_ARGUMENTS);
1152 			}
1153 			endTag(Logger.PROBLEM_TAG);
1154 		}
1155 		/**
1156 		 * @param problem
1157 		 *            the given problem to log
1158 		 * @param unitSource
1159 		 *            the given unit source
1160 		 */
logXmlTask(CategorizedProblem problem, char[] unitSource)1161 		private void logXmlTask(CategorizedProblem problem, char[] unitSource) {
1162 			this.parameters.put(Logger.PROBLEM_LINE, Integer.valueOf(problem.getSourceLineNumber()));
1163 			this.parameters.put(Logger.PROBLEM_SOURCE_START, Integer.valueOf(problem.getSourceStart()));
1164 			this.parameters.put(Logger.PROBLEM_SOURCE_END, Integer.valueOf(problem.getSourceEnd()));
1165 			String problemOptionKey = getProblemOptionKey(problem.getID());
1166 			if (problemOptionKey != null) {
1167 				this.parameters.put(Logger.PROBLEM_OPTION_KEY, problemOptionKey);
1168 			}
1169 			printTag(Logger.TASK, this.parameters, true, false);
1170 			this.parameters.put(Logger.VALUE, problem.getMessage());
1171 			printTag(Logger.PROBLEM_MESSAGE, this.parameters, true, true);
1172 			extractContext(problem, unitSource);
1173 			endTag(Logger.TASK);
1174 		}
1175 
printErr(String s)1176 		private void printErr(String s) {
1177 			this.err.print(s);
1178 			if ((this.tagBits & Logger.XML) == 0 && this.log != null) {
1179 				this.log.print(s);
1180 			}
1181 		}
1182 
printlnErr()1183 		private void printlnErr() {
1184 			this.err.println();
1185 			if ((this.tagBits & Logger.XML) == 0 && this.log != null) {
1186 				this.log.println();
1187 			}
1188 		}
1189 
printlnErr(String s)1190 		private void printlnErr(String s) {
1191 			this.err.println(s);
1192 			if ((this.tagBits & Logger.XML) == 0 && this.log != null) {
1193 				this.log.println(s);
1194 			}
1195 		}
1196 
printlnOut(String s)1197 		private void printlnOut(String s) {
1198 			this.out.println(s);
1199 			if ((this.tagBits & Logger.XML) == 0 && this.log != null) {
1200 				this.log.println(s);
1201 			}
1202 		}
1203 
1204 		/**
1205 		 *
1206 		 */
printNewLine()1207 		public void printNewLine() {
1208 			this.out.println();
1209 		}
1210 
printOut(char c)1211 		private void printOut(char c) {
1212 			this.out.print(c);
1213 		}
1214 
printStats()1215 		public void printStats() {
1216 			final boolean isTimed = (this.main.timing & TIMING_ENABLED) != 0;
1217 			if ((this.tagBits & Logger.XML) != 0) {
1218 				printTag(Logger.STATS, null, true, false);
1219 			}
1220 			if (isTimed) {
1221 				CompilerStats compilerStats = this.main.batchCompiler.stats;
1222 				compilerStats.startTime = this.main.startTime; // also include batch initialization times
1223 				compilerStats.endTime = System.currentTimeMillis(); // also include batch output times
1224 				logTiming(compilerStats);
1225 			}
1226 			if (this.main.globalProblemsCount > 0) {
1227 				logProblemsSummary(this.main.globalProblemsCount, this.main.globalErrorsCount, this.main.globalWarningsCount,
1228 						this.main.globalInfoCount, this.main.globalTasksCount);
1229 			}
1230 			if (this.main.exportedClassFilesCounter != 0
1231 					&& (this.main.showProgress || isTimed || this.main.verbose)) {
1232 				logNumberOfClassFilesGenerated(this.main.exportedClassFilesCounter);
1233 			}
1234 			if ((this.tagBits & Logger.XML) != 0) {
1235 				endTag(Logger.STATS);
1236 			}
1237 		}
1238 
printTag(String name, HashMap<String, Object> params, boolean insertNewLine, boolean closeTag)1239 		private void printTag(String name, HashMap<String, Object> params, boolean insertNewLine, boolean closeTag) {
1240 			if (this.log != null) {
1241 				((GenericXMLWriter) this.log).printTag(name, this.parameters, true, insertNewLine, closeTag);
1242 			}
1243 			this.parameters.clear();
1244 		}
1245 
setEmacs()1246 		public void setEmacs() {
1247 			this.tagBits |= Logger.EMACS;
1248 		}
setLog(String logFileName)1249 		public void setLog(String logFileName) {
1250 			final Date date = new Date();
1251 			final DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, Locale.getDefault());
1252 			try {
1253 				int index = logFileName.lastIndexOf('.');
1254 				if (index != -1) {
1255 					if (logFileName.substring(index).toLowerCase().equals(".xml")) { //$NON-NLS-1$
1256 						this.log = new GenericXMLWriter(new OutputStreamWriter(new FileOutputStream(logFileName, false), Util.UTF_8), Util.LINE_SEPARATOR, true);
1257 						this.tagBits |= Logger.XML;
1258 						// insert time stamp as comment
1259 						this.log.println("<!-- " + dateFormat.format(date) + " -->");//$NON-NLS-1$//$NON-NLS-2$
1260 						this.log.println(Logger.XML_DTD_DECLARATION);
1261 						this.parameters.put(Logger.COMPILER_NAME, this.main.bind("compiler.name")); //$NON-NLS-1$
1262 						this.parameters.put(Logger.COMPILER_VERSION, this.main.bind("compiler.version")); //$NON-NLS-1$
1263 						this.parameters.put(Logger.COMPILER_COPYRIGHT, this.main.bind("compiler.copyright")); //$NON-NLS-1$
1264 						printTag(Logger.COMPILER, this.parameters, true, false);
1265 					} else {
1266 						this.log = new PrintWriter(new FileOutputStream(logFileName, false));
1267 						this.log.println("# " + dateFormat.format(date));//$NON-NLS-1$
1268 					}
1269 				} else {
1270 					this.log = new PrintWriter(new FileOutputStream(logFileName, false));
1271 					this.log.println("# " + dateFormat.format(date));//$NON-NLS-1$
1272 				}
1273 			} catch (FileNotFoundException e) {
1274 				throw new IllegalArgumentException(this.main.bind("configure.cannotOpenLog", logFileName), e); //$NON-NLS-1$
1275 			} catch (UnsupportedEncodingException e) {
1276 				throw new IllegalArgumentException(this.main.bind("configure.cannotOpenLogInvalidEncoding", logFileName), e); //$NON-NLS-1$
1277 			}
1278 		}
startLoggingExtraProblems(int count)1279 		private void startLoggingExtraProblems(int count) {
1280 			this.parameters.put(Logger.NUMBER_OF_PROBLEMS, Integer.valueOf(count));
1281 			printTag(Logger.EXTRA_PROBLEMS, this.parameters, true, false);
1282 		}
1283 
1284 		/**
1285 		 * Used to start logging problems.
1286 		 * Only use in xml mode.
1287 		 */
startLoggingProblems(int errors, int warnings, int infos)1288 		private void startLoggingProblems(int errors, int warnings, int infos) {
1289 			this.parameters.put(Logger.NUMBER_OF_PROBLEMS, Integer.valueOf(errors + warnings));
1290 			this.parameters.put(Logger.NUMBER_OF_ERRORS, Integer.valueOf(errors));
1291 			this.parameters.put(Logger.NUMBER_OF_WARNINGS, Integer.valueOf(warnings));
1292 			this.parameters.put(Logger.NUMBER_OF_INFOS, Integer.valueOf(infos));
1293 			printTag(Logger.PROBLEMS, this.parameters, true, false);
1294 		}
1295 
startLoggingSource(CompilationResult compilationResult)1296 		public void startLoggingSource(CompilationResult compilationResult) {
1297 			if ((this.tagBits & Logger.XML) != 0) {
1298 				ICompilationUnit compilationUnit = compilationResult.compilationUnit;
1299 				if (compilationUnit != null) {
1300     				char[] fileName = compilationUnit.getFileName();
1301     				File f = new File(new String(fileName));
1302     				if (fileName != null) {
1303     					this.parameters.put(Logger.PATH, f.getAbsolutePath());
1304     				}
1305     				char[][] packageName = compilationResult.packageName;
1306     				if (packageName != null) {
1307     					this.parameters.put(
1308     							Logger.PACKAGE,
1309     							new String(CharOperation.concatWith(packageName, File.separatorChar)));
1310     				}
1311     				CompilationUnit unit = (CompilationUnit) compilationUnit;
1312     				String destinationPath = unit.destinationPath;
1313 					if (destinationPath == null) {
1314 						destinationPath = this.main.destinationPath;
1315 					}
1316 					if (destinationPath != null && destinationPath != NONE) {
1317 						if (File.separatorChar == '/') {
1318 							this.parameters.put(Logger.OUTPUT, destinationPath);
1319 						} else {
1320 							this.parameters.put(Logger.OUTPUT, destinationPath.replace('/', File.separatorChar));
1321 						}
1322 					}
1323 				}
1324 				printTag(Logger.SOURCE, this.parameters, true, false);
1325 			}
1326 		}
1327 
startLoggingSources()1328 		public void startLoggingSources() {
1329 			if ((this.tagBits & Logger.XML) != 0) {
1330 				printTag(Logger.SOURCES, null, true, false);
1331 			}
1332 		}
1333 
startLoggingTasks(int tasks)1334 		public void startLoggingTasks(int tasks) {
1335 			if ((this.tagBits & Logger.XML) != 0) {
1336 				this.parameters.put(Logger.NUMBER_OF_TASKS, Integer.valueOf(tasks));
1337 				printTag(Logger.TASKS, this.parameters, true, false);
1338 			}
1339 		}
1340 	}
1341 
1342 	/**
1343 	 * Resource bundle factory to share bundles for the same locale
1344 	 */
1345 	public static class ResourceBundleFactory {
1346 		private static HashMap<Locale, ResourceBundle> Cache = new HashMap<>();
getBundle(Locale locale)1347 		public static synchronized ResourceBundle getBundle(Locale locale) {
1348 			ResourceBundle bundle = Cache.get(locale);
1349 			if (bundle == null) {
1350 				bundle = ResourceBundle.getBundle(Main.bundleName, locale);
1351 				Cache.put(locale, bundle);
1352 			}
1353 			return bundle;
1354 		}
1355 	}
1356 
1357 	// used with -annotationpath to declare that annotations should be read from the classpath:
1358 	private static final String ANNOTATION_SOURCE_CLASSPATH = "CLASSPATH"; //$NON-NLS-1$
1359 
1360 	// javadoc analysis tuning
1361 	boolean enableJavadocOn;
1362 
1363 	boolean warnJavadocOn;
1364 	boolean warnAllJavadocOn;
1365 
1366 	public Compiler batchCompiler;
1367 	/* Bundle containing messages */
1368 	public ResourceBundle bundle;
1369 	protected FileSystem.Classpath[] checkedClasspaths;
1370 	// For single module mode
1371 	protected IModule module;
1372 	private String moduleVersion;
1373 	// paths to external annotations:
1374 	protected List<String> annotationPaths;
1375 	protected boolean annotationsFromClasspath;
1376 
1377 	private List<String> addonExports = Collections.EMPTY_LIST;
1378 	private List<String> addonReads = Collections.EMPTY_LIST;
1379 	public Set<String> rootModules = Collections.EMPTY_SET;
1380 	public Set<String> limitedModules;
1381 
1382 	public Locale compilerLocale;
1383 	public CompilerOptions compilerOptions; // read-only
1384 	public CompilationProgress progress;
1385 	public String destinationPath;
1386 	public String[] destinationPaths;
1387 	// destination path for compilation units that get no more specific
1388 	// one (through directory arguments or various classpath options);
1389 	// coding is:
1390 	// == null: unspecified, write class files close to their respective
1391 	//          source files;
1392 	// == Main.NONE: absorbent element, do not output class files;
1393 	// else: use as the path of the directory into which class files must
1394 	//       be written.
1395 	protected boolean enablePreview;
1396 	protected String releaseVersion;
1397 	private boolean didSpecifySource;
1398 	private boolean didSpecifyTarget;
1399 	public String[] encodings;
1400 	public int exportedClassFilesCounter;
1401 	public String[] filenames;
1402 	public String[] modNames;
1403 	public String[] classNames;
1404 	// overrides of destinationPath on a directory argument basis
1405 	public int globalErrorsCount;
1406 	public int globalProblemsCount;
1407 	public int globalTasksCount;
1408 	public int globalWarningsCount;
1409 	public int globalInfoCount;
1410 
1411 	private File javaHomeCache;
1412 
1413 	private boolean javaHomeChecked = false;
1414 	private boolean primaryNullAnnotationsSeen = false;
1415 	public long lineCount0;
1416 
1417 	public String log;
1418 
1419 	public Logger logger;
1420 	public int maxProblems;
1421 	public Map<String, String> options;
1422 	protected long complianceLevel;
1423 	public char[][] ignoreOptionalProblemsFromFolders;
1424 	protected PrintWriter out;
1425 	public boolean proceed = true;
1426 	public boolean proceedOnError = false;
1427 	public boolean failOnWarning = false;
1428 	public boolean produceRefInfo = false;
1429 	public int currentRepetition, maxRepetition;
1430 	public boolean showProgress = false;
1431 	public long startTime;
1432 	public ArrayList<String> pendingErrors;
1433 	public boolean systemExitWhenFinished = true;
1434 
1435 	public static final int TIMING_DISABLED = 0;
1436 	public static final int TIMING_ENABLED = 1;
1437 	public static final int TIMING_DETAILED = 2;
1438 
1439 	public int timing = TIMING_DISABLED;
1440 	public CompilerStats[] compilerStats;
1441 	public boolean verbose = false;
1442 	private String[] expandedCommandLine;
1443 
1444 	private PrintWriter err;
1445 
1446 	protected ArrayList<CategorizedProblem> extraProblems;
1447 
1448 	public final static String bundleName = "org.eclipse.jdt.internal.compiler.batch.messages"; //$NON-NLS-1$
1449 	// two uses: recognize 'none' in options; code the singleton none
1450 	// for the '-d none' option (wherever it may be found)
1451 	public static final int DEFAULT_SIZE_CLASSPATH = 4;
1452 
1453 	public static final String NONE = "none"; //$NON-NLS-1$
1454 
1455 /**
1456  * @deprecated - use {@link BatchCompiler#compile(String, PrintWriter, PrintWriter, CompilationProgress)} instead
1457  * 						  e.g. BatchCompiler.compile(commandLine, new PrintWriter(System.out), new PrintWriter(System.err), null);
1458  */
compile(String commandLine)1459 public static boolean compile(String commandLine) {
1460 	return new Main(new PrintWriter(System.out), new PrintWriter(System.err), false /* systemExit */, null /* options */, null /* progress */).compile(tokenize(commandLine));
1461 }
1462 
1463 /**
1464  * @deprecated - use {@link BatchCompiler#compile(String, PrintWriter, PrintWriter, CompilationProgress)} instead
1465  *                       e.g. BatchCompiler.compile(commandLine, outWriter, errWriter, null);
1466  */
compile(String commandLine, PrintWriter outWriter, PrintWriter errWriter)1467 public static boolean compile(String commandLine, PrintWriter outWriter, PrintWriter errWriter) {
1468 	return new Main(outWriter, errWriter, false /* systemExit */, null /* options */, null /* progress */).compile(tokenize(commandLine));
1469 }
1470 
1471 /*
1472  * Internal API for public API BatchCompiler#compile(String[], PrintWriter, PrintWriter, CompilationProgress)
1473  */
compile(String[] commandLineArguments, PrintWriter outWriter, PrintWriter errWriter, CompilationProgress progress)1474 public static boolean compile(String[] commandLineArguments, PrintWriter outWriter, PrintWriter errWriter, CompilationProgress progress) {
1475 	return new Main(outWriter, errWriter, false /* systemExit */, null /* options */, progress).compile(commandLineArguments);
1476 }
getLibrariesFiles(File[] files)1477 public static File[][] getLibrariesFiles(File[] files) {
1478 	FilenameFilter filter = new FilenameFilter() {
1479 		@Override
1480 		public boolean accept(File dir, String name) {
1481 			return Util.archiveFormat(name) > -1;
1482 		}
1483 	};
1484 	final int filesLength = files.length;
1485 	File[][] result = new File[filesLength][];
1486 	for (int i = 0; i < filesLength; i++) {
1487 		File currentFile = files[i];
1488 		if (currentFile.exists() && currentFile.isDirectory()) {
1489 			result[i] = currentFile.listFiles(filter);
1490 		}
1491 	}
1492 	return result;
1493 }
1494 
main(String[] argv)1495 public static void main(String[] argv) {
1496 	new Main(new PrintWriter(System.out), new PrintWriter(System.err), true/*systemExit*/, null/*options*/, null/*progress*/).compile(argv);
1497 }
1498 
tokenize(String commandLine)1499 public static String[] tokenize(String commandLine) {
1500 
1501 	int count = 0;
1502 	String[] arguments = new String[10];
1503 	StringTokenizer tokenizer = new StringTokenizer(commandLine, " \"", true); //$NON-NLS-1$
1504 	String token = Util.EMPTY_STRING;
1505 	boolean insideQuotes = false;
1506 	boolean startNewToken = true;
1507 
1508 	// take care to quotes on the command line
1509 	// 'xxx "aaa bbb";ccc yyy' --->  {"xxx", "aaa bbb;ccc", "yyy" }
1510 	// 'xxx "aaa bbb;ccc" yyy' --->  {"xxx", "aaa bbb;ccc", "yyy" }
1511 	// 'xxx "aaa bbb";"ccc" yyy' --->  {"xxx", "aaa bbb;ccc", "yyy" }
1512 	// 'xxx/"aaa bbb";"ccc" yyy' --->  {"xxx/aaa bbb;ccc", "yyy" }
1513 	while (tokenizer.hasMoreTokens()) {
1514 		token = tokenizer.nextToken();
1515 
1516 		if (token.equals(" ")) { //$NON-NLS-1$
1517 			if (insideQuotes) {
1518 				arguments[count - 1] += token;
1519 				startNewToken = false;
1520 			} else {
1521 				startNewToken = true;
1522 			}
1523 		} else if (token.equals("\"")) { //$NON-NLS-1$
1524 			if (!insideQuotes && startNewToken) {
1525 				if (count == arguments.length)
1526 					System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count);
1527 				arguments[count++] = Util.EMPTY_STRING;
1528 			}
1529 			insideQuotes = !insideQuotes;
1530 			startNewToken = false;
1531 		} else {
1532 			if (insideQuotes) {
1533 				arguments[count - 1] += token;
1534 			} else {
1535 				if (token.length() > 0 && !startNewToken) {
1536 					arguments[count - 1] += token;
1537 				} else {
1538 					if (count == arguments.length)
1539 						System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count);
1540 					String trimmedToken = token.trim();
1541 					if (trimmedToken.length() != 0) {
1542 						arguments[count++] = trimmedToken;
1543 					}
1544 				}
1545 			}
1546 			startNewToken = false;
1547 		}
1548 	}
1549 	System.arraycopy(arguments, 0, arguments = new String[count], 0, count);
1550 	return arguments;
1551 }
1552 
1553 /**
1554  * @deprecated - use {@link #Main(PrintWriter, PrintWriter, boolean, Map, CompilationProgress)} instead
1555  *                       e.g. Main(outWriter, errWriter, systemExitWhenFinished, null, null)
1556  */
Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished)1557 public Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished) {
1558 	this(outWriter, errWriter, systemExitWhenFinished, null /* options */, null /* progress */);
1559 }
1560 
1561 /**
1562  * @deprecated - use {@link #Main(PrintWriter, PrintWriter, boolean, Map, CompilationProgress)} instead
1563  *                       e.g. Main(outWriter, errWriter, systemExitWhenFinished, customDefaultOptions, null)
1564  */
Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished, Map<String, String> customDefaultOptions)1565 public Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished, Map<String, String> customDefaultOptions) {
1566 	this(outWriter, errWriter, systemExitWhenFinished, customDefaultOptions, null /* progress */);
1567 }
1568 
Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished, Map<String, String> customDefaultOptions, CompilationProgress compilationProgress)1569 public Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished, Map<String, String> customDefaultOptions, CompilationProgress compilationProgress) {
1570 	this.initialize(outWriter, errWriter, systemExitWhenFinished, customDefaultOptions, compilationProgress);
1571 	this.relocalize();
1572 }
1573 
addExtraProblems(CategorizedProblem problem)1574 public void addExtraProblems(CategorizedProblem problem) {
1575 	if (this.extraProblems == null) {
1576 		this.extraProblems = new ArrayList<>();
1577 	}
1578 	this.extraProblems.add(problem);
1579 }
addNewEntry(ArrayList<FileSystem.Classpath> paths, String currentClasspathName, ArrayList<String> currentRuleSpecs, String customEncoding, String destPath, boolean isSourceOnly, boolean rejectDestinationPathOnJars)1580 protected void addNewEntry(ArrayList<FileSystem.Classpath> paths, String currentClasspathName,
1581 		ArrayList<String> currentRuleSpecs, String customEncoding,
1582 		String destPath, boolean isSourceOnly,
1583 		boolean rejectDestinationPathOnJars) {
1584 
1585 	int rulesSpecsSize = currentRuleSpecs.size();
1586 	AccessRuleSet accessRuleSet = null;
1587 	if (rulesSpecsSize != 0) {
1588 		AccessRule[] accessRules = new AccessRule[currentRuleSpecs.size()];
1589 		boolean rulesOK = true;
1590 		Iterator<String> i = currentRuleSpecs.iterator();
1591 		int j = 0;
1592 		while (i.hasNext()) {
1593 			String ruleSpec = i.next();
1594 			char key = ruleSpec.charAt(0);
1595 			String pattern = ruleSpec.substring(1);
1596 			if (pattern.length() > 0) {
1597 				switch (key) {
1598 					case '+':
1599 						accessRules[j++] = new AccessRule(pattern
1600 								.toCharArray(), 0);
1601 						break;
1602 					case '~':
1603 						accessRules[j++] = new AccessRule(pattern
1604 								.toCharArray(),
1605 								IProblem.DiscouragedReference);
1606 						break;
1607 					case '-':
1608 						accessRules[j++] = new AccessRule(pattern
1609 								.toCharArray(),
1610 								IProblem.ForbiddenReference);
1611 						break;
1612 					case '?':
1613 						accessRules[j++] = new AccessRule(pattern
1614 								.toCharArray(),
1615 								IProblem.ForbiddenReference, true/*keep looking for accessible type*/);
1616 						break;
1617 					default:
1618 						rulesOK = false;
1619 				}
1620 			} else {
1621 				rulesOK = false;
1622 			}
1623 		}
1624 		if (rulesOK) {
1625     		accessRuleSet = new AccessRuleSet(accessRules, AccessRestriction.COMMAND_LINE, currentClasspathName);
1626 		} else {
1627 			if (currentClasspathName.length() != 0) {
1628 				// we go on anyway
1629 				addPendingErrors(this.bind("configure.incorrectClasspath", currentClasspathName));//$NON-NLS-1$
1630 			}
1631 			return;
1632 		}
1633 	}
1634 	if (NONE.equals(destPath)) {
1635 		destPath = NONE; // keep == comparison valid
1636 	}
1637 
1638 	if (rejectDestinationPathOnJars && destPath != null &&
1639 			Util.archiveFormat(currentClasspathName) > -1) {
1640 		throw new IllegalArgumentException(
1641 			this.bind("configure.unexpectedDestinationPathEntryFile", //$NON-NLS-1$
1642 						currentClasspathName));
1643 	}
1644 	FileSystem.Classpath currentClasspath = FileSystem.getClasspath(
1645 			currentClasspathName,
1646 			customEncoding,
1647 			isSourceOnly,
1648 			accessRuleSet,
1649 			destPath,
1650 			this.options,
1651 			this.releaseVersion);
1652 	if (currentClasspath != null) {
1653 		paths.add(currentClasspath);
1654 	} else if (currentClasspathName.length() != 0) {
1655 		// we go on anyway
1656 		addPendingErrors(this.bind("configure.incorrectClasspath", currentClasspathName));//$NON-NLS-1$
1657 	}
1658 }
addPendingErrors(String message)1659 void addPendingErrors(String message) {
1660 	if (this.pendingErrors == null) {
1661 		this.pendingErrors = new ArrayList<>();
1662 	}
1663 	this.pendingErrors.add(message);
1664 }
1665 /*
1666  * Lookup the message with the given ID in this catalog
1667  */
bind(String id)1668 public String bind(String id) {
1669 	return bind(id, (String[]) null);
1670 }
1671 /*
1672  * Lookup the message with the given ID in this catalog and bind its
1673  * substitution locations with the given string.
1674  */
bind(String id, String binding)1675 public String bind(String id, String binding) {
1676 	return bind(id, new String[] { binding });
1677 }
1678 
1679 /*
1680  * Lookup the message with the given ID in this catalog and bind its
1681  * substitution locations with the given strings.
1682  */
bind(String id, String binding1, String binding2)1683 public String bind(String id, String binding1, String binding2) {
1684 	return bind(id, new String[] { binding1, binding2 });
1685 }
1686 
1687 /*
1688  * Lookup the message with the given ID in this catalog and bind its
1689  * substitution locations with the given string values.
1690  */
bind(String id, String[] arguments)1691 public String bind(String id, String[] arguments) {
1692 	if (id == null)
1693 		return "No message available"; //$NON-NLS-1$
1694 	String message = null;
1695 	try {
1696 		message = this.bundle.getString(id);
1697 	} catch (MissingResourceException e) {
1698 		// If we got an exception looking for the message, fail gracefully by just returning
1699 		// the id we were looking for.  In most cases this is semi-informative so is not too bad.
1700 		return "Missing message: " + id + " in: " + Main.bundleName; //$NON-NLS-2$ //$NON-NLS-1$
1701 	}
1702 	return MessageFormat.format(message, (Object[]) arguments);
1703 }
1704 /**
1705  * Return true if and only if the running VM supports the given minimal version.
1706  *
1707  * <p>This only checks the major version, since the minor version is always 0 (at least for the useful cases).</p>
1708  * <p>The given minimalSupportedVersion is one of the constants:</p>
1709  * <ul>
1710  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_1</code></li>
1711  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_2</code></li>
1712  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_3</code></li>
1713  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_4</code></li>
1714  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_5</code></li>
1715  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_6</code></li>
1716  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_7</code></li>
1717  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_8</code></li>
1718  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK9</code></li>
1719  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK10</code></li>
1720  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK11</code></li>
1721  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK12</code></li>
1722  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK13</code></li>
1723  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK14</code></li>
1724  *
1725  * </ul>
1726  * @param minimalSupportedVersion the given minimal version
1727  * @return true if and only if the running VM supports the given minimal version, false otherwise
1728  */
checkVMVersion(long minimalSupportedVersion)1729 private boolean checkVMVersion(long minimalSupportedVersion) {
1730 	// the format of this property is supposed to be xx.x where x are digits.
1731 	String classFileVersion = System.getProperty("java.class.version"); //$NON-NLS-1$
1732 	if (classFileVersion == null) {
1733 		// by default we don't support a class file version we cannot recognize
1734 		return false;
1735 	}
1736 	int index = classFileVersion.indexOf('.');
1737 	if (index == -1) {
1738 		// by default we don't support a class file version we cannot recognize
1739 		return false;
1740 	}
1741 	int majorVersion;
1742 	try {
1743 		majorVersion = Integer.parseInt(classFileVersion.substring(0, index));
1744 	} catch (NumberFormatException e) {
1745 		// by default we don't support a class file version we cannot recognize
1746 		return false;
1747 	}
1748 	return ClassFileConstants.getComplianceLevelForJavaVersion(majorVersion) >=minimalSupportedVersion;
1749 }
1750 /*
1751  *  Low-level API performing the actual compilation
1752  */
compile(String[] argv)1753 public boolean compile(String[] argv) {
1754 	// decode command line arguments
1755 	try {
1756 		configure(argv);
1757 		if (this.progress != null)
1758 			this.progress.begin(this.filenames == null ? 0 : this.filenames.length * this.maxRepetition);
1759 		if (this.proceed) {
1760 //				if (this.verbose) {
1761 //					System.out.println(new CompilerOptions(this.options));
1762 //				}
1763 			if (this.showProgress) this.logger.compiling();
1764 			for (this.currentRepetition = 0; this.currentRepetition < this.maxRepetition; this.currentRepetition++) {
1765 				this.globalProblemsCount = 0;
1766 				this.globalErrorsCount = 0;
1767 				this.globalWarningsCount = 0;
1768 				this.globalInfoCount = 0;
1769 				this.globalTasksCount = 0;
1770 				this.exportedClassFilesCounter = 0;
1771 
1772 				if (this.maxRepetition > 1) {
1773 					this.logger.flush();
1774 					this.logger.logRepetition(this.currentRepetition, this.maxRepetition);
1775 				}
1776 				// request compilation
1777 				performCompilation();
1778 			}
1779 			if (this.compilerStats != null) {
1780 				this.logger.logAverage();
1781 			}
1782 			if (this.showProgress) this.logger.printNewLine();
1783 		}
1784 		if (this.systemExitWhenFinished) {
1785 			this.logger.flush();
1786 			this.logger.close();
1787 			if (this.failOnWarning && this.globalWarningsCount > 0) {
1788 				System.exit(-1);
1789 			}
1790 			System.exit(this.globalErrorsCount > 0 ? -1 : 0);
1791 		}
1792 	} catch (Exception e) { // internal compiler failure
1793 		this.logger.logException(e);
1794 		if (this.systemExitWhenFinished) {
1795 			this.logger.flush();
1796 			this.logger.close();
1797 			System.exit(-1);
1798 		}
1799 		return false;
1800 	} finally {
1801 		this.logger.flush();
1802 		this.logger.close();
1803 		if (this.progress != null)
1804 			this.progress.done();
1805 	}
1806 	if (this.progress == null || !this.progress.isCanceled()) {
1807 		if (this.failOnWarning && (this.globalWarningsCount > 0))
1808 			return false;
1809 		if (this.globalErrorsCount == 0)
1810 			return true;
1811 	}
1812 
1813 	return false;
1814 }
1815 
1816 /*
1817 Decode the command line arguments
1818  */
configure(String[] argv)1819 public void configure(String[] argv) {
1820 
1821 	if ((argv == null) || (argv.length == 0)) {
1822 		printUsage();
1823 		return;
1824 	}
1825 
1826 	final int INSIDE_CLASSPATH_start = 1;
1827 	final int INSIDE_DESTINATION_PATH = 3;
1828 	final int INSIDE_TARGET = 4;
1829 	final int INSIDE_LOG = 5;
1830 	final int INSIDE_REPETITION = 6;
1831 	final int INSIDE_SOURCE = 7;
1832 	final int INSIDE_DEFAULT_ENCODING = 8;
1833 	final int INSIDE_BOOTCLASSPATH_start = 9;
1834 	final int INSIDE_MAX_PROBLEMS = 11;
1835 	final int INSIDE_EXT_DIRS = 12;
1836 	final int INSIDE_SOURCE_PATH_start = 13;
1837 	final int INSIDE_ENDORSED_DIRS = 15;
1838 	final int INSIDE_SOURCE_DIRECTORY_DESTINATION_PATH = 16;
1839 	final int INSIDE_PROCESSOR_PATH_start = 17;
1840 	final int INSIDE_PROCESSOR_start = 18;
1841 	final int INSIDE_S_start = 19;
1842 	final int INSIDE_CLASS_NAMES = 20;
1843 	final int INSIDE_WARNINGS_PROPERTIES = 21;
1844 	final int INSIDE_ANNOTATIONPATH_start = 22;
1845 	final int INSIDE_MODULEPATH_start = 23;
1846 	final int INSIDE_MODULESOURCEPATH_start = 24;
1847 	final int INSIDE_ADD_EXPORTS = 25;
1848 	final int INSIDE_ADD_READS = 26;
1849 	final int INSIDE_SYSTEM = 27;
1850 	final int INSIDE_PROCESSOR_MODULE_PATH_start = 28;
1851 	final int INSIDE_ADD_MODULES = 29;
1852 	final int INSIDE_RELEASE = 30;
1853 	final int INSIDE_LIMIT_MODULES = 31;
1854 	final int INSIDE_MODULE_VERSION = 32;
1855 
1856 	final int DEFAULT = 0;
1857 	ArrayList<String> bootclasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH);
1858 	String sourcepathClasspathArg = null;
1859 	String modulepathArg = null;
1860 	String moduleSourcepathArg = null;
1861 	ArrayList<String> sourcepathClasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH);
1862 	ArrayList<String> classpaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH);
1863 	ArrayList<String> extdirsClasspaths = null;
1864 	ArrayList<String> endorsedDirClasspaths = null;
1865 	this.annotationPaths = null;
1866 	this.annotationsFromClasspath = false;
1867 
1868 	int index = -1;
1869 	int filesCount = 0;
1870 	int classCount = 0;
1871 	int argCount = argv.length;
1872 	int mode = DEFAULT;
1873 	this.maxRepetition = 0;
1874 	boolean printUsageRequired = false;
1875 	String usageSection = null;
1876 	boolean printVersionRequired = false;
1877 
1878 	boolean didSpecifyDeprecation = false;
1879 	boolean didSpecifyCompliance = false;
1880 	boolean didSpecifyDisabledAnnotationProcessing = false;
1881 
1882 	String customEncoding = null;
1883 	String customDestinationPath = null;
1884 	String currentSourceDirectory = null;
1885 	String currentArg = Util.EMPTY_STRING;
1886 	String moduleName = null;
1887 
1888 	Set<String> specifiedEncodings = null;
1889 
1890 	// expand the command line if necessary
1891 	boolean needExpansion = false;
1892 	loop: for (int i = 0; i < argCount; i++) {
1893 			if (argv[i].startsWith("@")) { //$NON-NLS-1$
1894 				needExpansion = true;
1895 				break loop;
1896 			}
1897 	}
1898 
1899 	String[] newCommandLineArgs = null;
1900 	if (needExpansion) {
1901 		newCommandLineArgs = new String[argCount];
1902 		index = 0;
1903 		for (int i = 0; i < argCount; i++) {
1904 			String[] newArgs = null;
1905 			String arg = argv[i].trim();
1906 			if (arg.startsWith("@")) { //$NON-NLS-1$
1907 				try {
1908 					LineNumberReader reader = new LineNumberReader(new StringReader(new String(Util.getFileCharContent(new File(arg.substring(1)), null))));
1909 					StringBuffer buffer = new StringBuffer();
1910 					String line;
1911 					while((line = reader.readLine()) != null) {
1912 						line = line.trim();
1913 						if (!line.startsWith("#")) { //$NON-NLS-1$
1914 							buffer.append(line).append(" "); //$NON-NLS-1$
1915 						}
1916 					}
1917 					newArgs = tokenize(buffer.toString());
1918 				} catch(IOException e) {
1919 					throw new IllegalArgumentException(
1920 						this.bind("configure.invalidexpansionargumentname", arg)); //$NON-NLS-1$
1921 				}
1922 			}
1923 			if (newArgs != null) {
1924 				int newCommandLineArgsLength = newCommandLineArgs.length;
1925 				int newArgsLength = newArgs.length;
1926 				System.arraycopy(newCommandLineArgs, 0, (newCommandLineArgs = new String[newCommandLineArgsLength + newArgsLength - 1]), 0, index);
1927 				System.arraycopy(newArgs, 0, newCommandLineArgs, index, newArgsLength);
1928 				index += newArgsLength;
1929 			} else {
1930 				newCommandLineArgs[index++] = arg;
1931 			}
1932 		}
1933 		index = -1;
1934 	} else {
1935 		newCommandLineArgs = argv;
1936 		for (int i = 0; i < argCount; i++) {
1937 			newCommandLineArgs[i] = newCommandLineArgs[i].trim();
1938 		}
1939 	}
1940 	argCount = newCommandLineArgs.length;
1941 	this.expandedCommandLine = newCommandLineArgs;
1942 	while (++index < argCount) {
1943 
1944 		if (customEncoding != null) {
1945 			throw new IllegalArgumentException(
1946 				this.bind("configure.unexpectedCustomEncoding", currentArg, customEncoding)); //$NON-NLS-1$
1947 		}
1948 
1949 		currentArg = newCommandLineArgs[index];
1950 
1951 		switch(mode) {
1952 			case DEFAULT :
1953 				if (currentArg.startsWith("-nowarn")) { //$NON-NLS-1$
1954 					switch (currentArg.length()) {
1955 						case 7:
1956 							disableAll(ProblemSeverities.Warning);
1957 							break;
1958 						case 8:
1959 							throw new IllegalArgumentException(this.bind(
1960 									"configure.invalidNowarnOption", currentArg)); //$NON-NLS-1$
1961 						default:
1962 							int foldersStart = currentArg.indexOf('[') + 1;
1963 							int foldersEnd = currentArg.lastIndexOf(']');
1964 							if (foldersStart <= 8 || foldersEnd == -1 || foldersStart > foldersEnd
1965 									|| foldersEnd < currentArg.length() - 1) {
1966 								throw new IllegalArgumentException(this.bind(
1967 										"configure.invalidNowarnOption", currentArg)); //$NON-NLS-1$
1968 							}
1969 							String folders = currentArg.substring(foldersStart, foldersEnd);
1970 							if (folders.length() > 0) {
1971 								char[][] currentFolders = decodeIgnoreOptionalProblemsFromFolders(folders);
1972 								if (this.ignoreOptionalProblemsFromFolders != null) {
1973 									int length = this.ignoreOptionalProblemsFromFolders.length + currentFolders.length;
1974 									char[][] tempFolders = new char[length][];
1975 									System.arraycopy(this.ignoreOptionalProblemsFromFolders, 0, tempFolders, 0, this.ignoreOptionalProblemsFromFolders.length);
1976 									System.arraycopy(currentFolders, 0, tempFolders, this.ignoreOptionalProblemsFromFolders.length, currentFolders.length);
1977 									this.ignoreOptionalProblemsFromFolders = tempFolders;
1978 								} else {
1979 									this.ignoreOptionalProblemsFromFolders = currentFolders;
1980 								}
1981 							} else {
1982 								throw new IllegalArgumentException(this.bind(
1983 										"configure.invalidNowarnOption", currentArg)); //$NON-NLS-1$
1984 							}
1985 					}
1986 					mode = DEFAULT;
1987 					continue;
1988 				}
1989 				if (currentArg.startsWith("[")) { //$NON-NLS-1$
1990 					throw new IllegalArgumentException(
1991 						this.bind("configure.unexpectedBracket", //$NON-NLS-1$
1992 									currentArg));
1993 				}
1994 
1995 				if (currentArg.endsWith("]")) { //$NON-NLS-1$
1996 					// look for encoding specification
1997 					int encodingStart = currentArg.indexOf('[') + 1;
1998 					if (encodingStart <= 1) {
1999 						throw new IllegalArgumentException(
2000 								this.bind("configure.unexpectedBracket", currentArg)); //$NON-NLS-1$
2001 					}
2002 					int encodingEnd = currentArg.length() - 1;
2003 					if (encodingStart >= 1) {
2004 						if (encodingStart < encodingEnd) {
2005 							customEncoding = currentArg.substring(encodingStart, encodingEnd);
2006 							try { // ensure encoding is supported
2007 								new InputStreamReader(new ByteArrayInputStream(new byte[0]), customEncoding);
2008 							} catch (UnsupportedEncodingException e) {
2009 								throw new IllegalArgumentException(
2010 									this.bind("configure.unsupportedEncoding", customEncoding), e); //$NON-NLS-1$
2011 							}
2012 						}
2013 						currentArg = currentArg.substring(0, encodingStart - 1);
2014 					}
2015 				}
2016 
2017 				if (currentArg.endsWith(SuffixConstants.SUFFIX_STRING_java)) {
2018 					if (moduleName == null) {
2019 						// If the module-info.java was supplied via command line, that will be the
2020 						// de facto module for the other source files supplied via command line.
2021 						// TODO: This needs revisit in case a source file specified in command line is
2022 						// part of a --module-source-path
2023 						IModule mod = extractModuleDesc(currentArg);
2024 						if (mod != null) {
2025 							moduleName = new String(mod.name());
2026 							this.module = mod;
2027 						}
2028 					}
2029 					if (this.filenames == null) {
2030 						this.filenames = new String[argCount - index];
2031 						this.encodings = new String[argCount - index];
2032 						this.modNames = new String[argCount - index];
2033 						this.destinationPaths = new String[argCount - index];
2034 					} else if (filesCount == this.filenames.length) {
2035 						int length = this.filenames.length;
2036 						System.arraycopy(
2037 							this.filenames,
2038 							0,
2039 							(this.filenames = new String[length + argCount - index]),
2040 							0,
2041 							length);
2042 						System.arraycopy(
2043 							this.encodings,
2044 							0,
2045 							(this.encodings = new String[length + argCount - index]),
2046 							0,
2047 							length);
2048 						System.arraycopy(
2049 							this.destinationPaths,
2050 							0,
2051 							(this.destinationPaths = new String[length + argCount - index]),
2052 							0,
2053 							length);
2054 						System.arraycopy(
2055 								this.modNames,
2056 								0,
2057 								(this.modNames = new String[length + argCount - index]),
2058 								0,
2059 								length);
2060 					}
2061 					this.filenames[filesCount] = currentArg;
2062 					this.modNames[filesCount] = moduleName;
2063 					this.encodings[filesCount++] = customEncoding;
2064 					// destination path cannot be specified upon an individual file
2065 					customEncoding = null;
2066 					mode = DEFAULT;
2067 					continue;
2068 				}
2069 				if (currentArg.equals("-log")) { //$NON-NLS-1$
2070 					if (this.log != null)
2071 						throw new IllegalArgumentException(
2072 							this.bind("configure.duplicateLog", currentArg)); //$NON-NLS-1$
2073 					mode = INSIDE_LOG;
2074 					continue;
2075 				}
2076 				if (currentArg.equals("-repeat")) { //$NON-NLS-1$
2077 					if (this.maxRepetition > 0)
2078 						throw new IllegalArgumentException(
2079 							this.bind("configure.duplicateRepeat", currentArg)); //$NON-NLS-1$
2080 					mode = INSIDE_REPETITION;
2081 					continue;
2082 				}
2083 				if (currentArg.equals("-maxProblems")) { //$NON-NLS-1$
2084 					if (this.maxProblems > 0)
2085 						throw new IllegalArgumentException(
2086 							this.bind("configure.duplicateMaxProblems", currentArg)); //$NON-NLS-1$
2087 					mode = INSIDE_MAX_PROBLEMS;
2088 					continue;
2089 				}
2090 				if (currentArg.equals("--release")) { //$NON-NLS-1$
2091 					mode = INSIDE_RELEASE;
2092 					continue;
2093 				}
2094 				if (currentArg.equals("-source")) { //$NON-NLS-1$
2095 					mode = INSIDE_SOURCE;
2096 					continue;
2097 				}
2098 				if (currentArg.equals("-encoding")) { //$NON-NLS-1$
2099 					mode = INSIDE_DEFAULT_ENCODING;
2100 					continue;
2101 				}
2102 				if (currentArg.startsWith("-")) { //$NON-NLS-1$
2103 					String version = optionStringToVersion(currentArg.substring(1));
2104 					if (version != null) {
2105 						if (didSpecifyCompliance) {
2106 							throw new IllegalArgumentException(
2107 								this.bind("configure.duplicateCompliance", currentArg));//$NON-NLS-1$
2108 						}
2109 						didSpecifyCompliance = true;
2110 						this.options.put(CompilerOptions.OPTION_Compliance, version);
2111 						mode = DEFAULT;
2112 						continue;
2113 					}
2114 				}
2115 				if (currentArg.equals("-d")) { //$NON-NLS-1$
2116 					if (this.destinationPath != null) {
2117 						StringBuffer errorMessage = new StringBuffer();
2118 						errorMessage.append(currentArg);
2119 						if ((index + 1) < argCount) {
2120 							errorMessage.append(' ');
2121 							errorMessage.append(newCommandLineArgs[index + 1]);
2122 						}
2123 						throw new IllegalArgumentException(
2124 							this.bind("configure.duplicateOutputPath", errorMessage.toString())); //$NON-NLS-1$
2125 					}
2126 					mode = INSIDE_DESTINATION_PATH;
2127 					continue;
2128 				}
2129 				if (currentArg.equals("-classpath") //$NON-NLS-1$
2130 					|| currentArg.equals("-cp")) { //$NON-NLS-1$
2131 					mode = INSIDE_CLASSPATH_start;
2132 					continue;
2133 				}
2134 				if (currentArg.equals("-bootclasspath")) {//$NON-NLS-1$
2135 					if (bootclasspaths.size() > 0) {
2136 						StringBuffer errorMessage = new StringBuffer();
2137 						errorMessage.append(currentArg);
2138 						if ((index + 1) < argCount) {
2139 							errorMessage.append(' ');
2140 							errorMessage.append(newCommandLineArgs[index + 1]);
2141 						}
2142 						throw new IllegalArgumentException(
2143 							this.bind("configure.duplicateBootClasspath", errorMessage.toString())); //$NON-NLS-1$
2144 					}
2145 					mode = INSIDE_BOOTCLASSPATH_start;
2146 					continue;
2147 				}
2148 				if (currentArg.equals("--enable-preview")) { //$NON-NLS-1$
2149 					this.enablePreview = true;
2150 					mode = DEFAULT;
2151 					continue;
2152 				}
2153 				if (currentArg.equals("--system")) { //$NON-NLS-1$
2154 					mode = INSIDE_SYSTEM;
2155 					continue;
2156 				}
2157 				if (currentArg.equals("--module-path") || currentArg.equals("-p") || currentArg.equals("--processor-module-path")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
2158 					mode = INSIDE_MODULEPATH_start;
2159 					continue;
2160 				}
2161 				if (currentArg.equals("--module-source-path")) { //$NON-NLS-1$
2162 					if (sourcepathClasspathArg != null) {
2163 						throw new IllegalArgumentException(this.bind("configure.OneOfModuleOrSourcePath")); //$NON-NLS-1$
2164 					}
2165 					mode = INSIDE_MODULESOURCEPATH_start;
2166 					continue;
2167 				}
2168 				if (currentArg.equals("--add-exports")) { //$NON-NLS-1$
2169 					mode = INSIDE_ADD_EXPORTS;
2170 					continue;
2171 				}
2172 				if (currentArg.equals("--add-reads")) { //$NON-NLS-1$
2173 					mode = INSIDE_ADD_READS;
2174 					continue;
2175 				}
2176 				if (currentArg.equals("--add-modules")) { //$NON-NLS-1$
2177 					mode = INSIDE_ADD_MODULES;
2178 					continue;
2179 				}
2180 				if (currentArg.equals("--limit-modules")) { //$NON-NLS-1$
2181 					mode = INSIDE_LIMIT_MODULES;
2182 					continue;
2183 				}
2184 				if (currentArg.equals("--module-version")) { //$NON-NLS-1$
2185 					mode = INSIDE_MODULE_VERSION;
2186 					continue;
2187 				}
2188 				if (currentArg.equals("-sourcepath")) {//$NON-NLS-1$
2189 					if (sourcepathClasspathArg != null) {
2190 						StringBuffer errorMessage = new StringBuffer();
2191 						errorMessage.append(currentArg);
2192 						if ((index + 1) < argCount) {
2193 							errorMessage.append(' ');
2194 							errorMessage.append(newCommandLineArgs[index + 1]);
2195 						}
2196 						throw new IllegalArgumentException(
2197 							this.bind("configure.duplicateSourcepath", errorMessage.toString())); //$NON-NLS-1$
2198 					}
2199 					if (moduleSourcepathArg != null) {
2200 						throw new IllegalArgumentException(this.bind("configure.OneOfModuleOrSourcePath")); //$NON-NLS-1$
2201 					}
2202 					mode = INSIDE_SOURCE_PATH_start;
2203 					continue;
2204 				}
2205 				if (currentArg.equals("-extdirs")) {//$NON-NLS-1$
2206 					if (extdirsClasspaths != null) {
2207 						StringBuffer errorMessage = new StringBuffer();
2208 						errorMessage.append(currentArg);
2209 						if ((index + 1) < argCount) {
2210 							errorMessage.append(' ');
2211 							errorMessage.append(newCommandLineArgs[index + 1]);
2212 						}
2213 						throw new IllegalArgumentException(
2214 							this.bind("configure.duplicateExtDirs", errorMessage.toString())); //$NON-NLS-1$
2215 					}
2216 					mode = INSIDE_EXT_DIRS;
2217 					continue;
2218 				}
2219 				if (currentArg.equals("-endorseddirs")) { //$NON-NLS-1$
2220 					if (endorsedDirClasspaths != null) {
2221 						StringBuffer errorMessage = new StringBuffer();
2222 						errorMessage.append(currentArg);
2223 						if ((index + 1) < argCount) {
2224 							errorMessage.append(' ');
2225 							errorMessage.append(newCommandLineArgs[index + 1]);
2226 						}
2227 						throw new IllegalArgumentException(
2228 							this.bind("configure.duplicateEndorsedDirs", errorMessage.toString())); //$NON-NLS-1$
2229 					}
2230 					mode = INSIDE_ENDORSED_DIRS;
2231 					continue;
2232 				}
2233 				if (currentArg.equals("-progress")) { //$NON-NLS-1$
2234 					mode = DEFAULT;
2235 					this.showProgress = true;
2236 					continue;
2237 				}
2238 				if (currentArg.startsWith("-proceedOnError")) { //$NON-NLS-1$
2239 					mode = DEFAULT;
2240 					int length = currentArg.length();
2241 					if (length > 15) {
2242 						if (currentArg.equals("-proceedOnError:Fatal")) { //$NON-NLS-1$
2243 							this.options.put(CompilerOptions.OPTION_FatalOptionalError, CompilerOptions.ENABLED);
2244 						} else {
2245 							throw new IllegalArgumentException(
2246 									this.bind("configure.invalidWarningConfiguration", currentArg)); //$NON-NLS-1$
2247 						}
2248 					} else {
2249 						this.options.put(CompilerOptions.OPTION_FatalOptionalError, CompilerOptions.DISABLED);
2250 					}
2251 					this.proceedOnError = true;
2252 					continue;
2253 				}
2254 				if (currentArg.equals("-failOnWarning")) { //$NON-NLS-1$
2255 					mode = DEFAULT;
2256 					this.failOnWarning = true;
2257 					continue;
2258 				}
2259 				if (currentArg.equals("-time")) { //$NON-NLS-1$
2260 					mode = DEFAULT;
2261 					this.timing = TIMING_ENABLED;
2262 					continue;
2263 				}
2264 				if (currentArg.equals("-time:detail")) { //$NON-NLS-1$
2265 					mode = DEFAULT;
2266 					this.timing = TIMING_ENABLED|TIMING_DETAILED;
2267 					continue;
2268 				}
2269 				if (currentArg.equals("-version") //$NON-NLS-1$
2270 						|| currentArg.equals("-v")) { //$NON-NLS-1$
2271 					this.logger.logVersion(true);
2272 					this.proceed = false;
2273 					return;
2274 				}
2275 				if (currentArg.equals("-showversion")) { //$NON-NLS-1$
2276 					printVersionRequired = true;
2277 					mode = DEFAULT;
2278 					continue;
2279 				}
2280 				if ("-deprecation".equals(currentArg)) { //$NON-NLS-1$
2281 					didSpecifyDeprecation = true;
2282 					this.options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
2283 					mode = DEFAULT;
2284 					continue;
2285 				}
2286 				if (currentArg.equals("-help") || currentArg.equals("-?")) { //$NON-NLS-1$ //$NON-NLS-2$
2287 					printUsageRequired = true;
2288 					mode = DEFAULT;
2289 					continue;
2290 				}
2291 				if (currentArg.equals("-help:warn") || //$NON-NLS-1$
2292 						currentArg.equals("-?:warn")) { //$NON-NLS-1$
2293 					printUsageRequired = true;
2294 					usageSection = "misc.usage.warn"; //$NON-NLS-1$
2295 					continue;
2296 				}
2297 				if (currentArg.equals("-noExit")) { //$NON-NLS-1$
2298 					this.systemExitWhenFinished = false;
2299 					mode = DEFAULT;
2300 					continue;
2301 				}
2302 				if (currentArg.equals("-verbose")) { //$NON-NLS-1$
2303 					this.verbose = true;
2304 					mode = DEFAULT;
2305 					continue;
2306 				}
2307 				if (currentArg.equals("-referenceInfo")) { //$NON-NLS-1$
2308 					this.produceRefInfo = true;
2309 					mode = DEFAULT;
2310 					continue;
2311 				}
2312 				if (currentArg.equals("-inlineJSR")) { //$NON-NLS-1$
2313 					mode = DEFAULT;
2314 					this.options.put(
2315 							CompilerOptions.OPTION_InlineJsr,
2316 							CompilerOptions.ENABLED);
2317 					continue;
2318 				}
2319 				if (currentArg.equals("-parameters")) { //$NON-NLS-1$
2320 					mode = DEFAULT;
2321 					this.options.put(
2322 							CompilerOptions.OPTION_MethodParametersAttribute,
2323 							CompilerOptions.GENERATE);
2324 					continue;
2325 				}
2326 				if (currentArg.equals("-genericsignature")) { //$NON-NLS-1$
2327 					mode = DEFAULT;
2328 					this.options.put(
2329 							CompilerOptions.OPTION_LambdaGenericSignature,
2330 							CompilerOptions.GENERATE);
2331 					continue;
2332 				}
2333 				if (currentArg.startsWith("-g")) { //$NON-NLS-1$
2334 					mode = DEFAULT;
2335 					String debugOption = currentArg;
2336 					int length = currentArg.length();
2337 					if (length == 2) {
2338 						this.options.put(
2339 							CompilerOptions.OPTION_LocalVariableAttribute,
2340 							CompilerOptions.GENERATE);
2341 						this.options.put(
2342 							CompilerOptions.OPTION_LineNumberAttribute,
2343 							CompilerOptions.GENERATE);
2344 						this.options.put(
2345 							CompilerOptions.OPTION_SourceFileAttribute,
2346 							CompilerOptions.GENERATE);
2347 						continue;
2348 					}
2349 					if (length > 3) {
2350 						this.options.put(
2351 							CompilerOptions.OPTION_LocalVariableAttribute,
2352 							CompilerOptions.DO_NOT_GENERATE);
2353 						this.options.put(
2354 							CompilerOptions.OPTION_LineNumberAttribute,
2355 							CompilerOptions.DO_NOT_GENERATE);
2356 						this.options.put(
2357 							CompilerOptions.OPTION_SourceFileAttribute,
2358 							CompilerOptions.DO_NOT_GENERATE);
2359 						if (length == 7 && debugOption.equals("-g:" + NONE)) //$NON-NLS-1$
2360 							continue;
2361 						StringTokenizer tokenizer =
2362 							new StringTokenizer(debugOption.substring(3, debugOption.length()), ","); //$NON-NLS-1$
2363 						while (tokenizer.hasMoreTokens()) {
2364 							String token = tokenizer.nextToken();
2365 							if (token.equals("vars")) { //$NON-NLS-1$
2366 								this.options.put(
2367 									CompilerOptions.OPTION_LocalVariableAttribute,
2368 									CompilerOptions.GENERATE);
2369 							} else if (token.equals("lines")) { //$NON-NLS-1$
2370 								this.options.put(
2371 									CompilerOptions.OPTION_LineNumberAttribute,
2372 									CompilerOptions.GENERATE);
2373 							} else if (token.equals("source")) { //$NON-NLS-1$
2374 								this.options.put(
2375 									CompilerOptions.OPTION_SourceFileAttribute,
2376 									CompilerOptions.GENERATE);
2377 							} else {
2378 								throw new IllegalArgumentException(
2379 									this.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$
2380 							}
2381 						}
2382 						continue;
2383 					}
2384 					throw new IllegalArgumentException(
2385 						this.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$
2386 				}
2387 				if (currentArg.startsWith("-info")) { //$NON-NLS-1$
2388 					mode = DEFAULT;
2389 					String infoOption = currentArg;
2390 					int length = currentArg.length();
2391 					if (length == 10 && infoOption.equals("-info:" + NONE)) { //$NON-NLS-1$
2392 						disableAll(ProblemSeverities.Info);
2393 						continue;
2394 					}
2395 					if (length <= 6) {
2396 						throw new IllegalArgumentException(
2397 							this.bind("configure.invalidInfoConfiguration", infoOption)); //$NON-NLS-1$
2398 					}
2399 					int infoTokenStart;
2400 					boolean isEnabling;
2401 					switch (infoOption.charAt(6)) {
2402 						case '+' :
2403 							infoTokenStart = 7;
2404 							isEnabling = true;
2405 							break;
2406 						case '-' :
2407 							infoTokenStart = 7;
2408 							isEnabling = false; // specified warnings are disabled
2409 							break;
2410 						default:
2411 							disableAll(ProblemSeverities.Info);
2412 							infoTokenStart = 6;
2413 							isEnabling = true;
2414 					}
2415 
2416 					StringTokenizer tokenizer =
2417 						new StringTokenizer(infoOption.substring(infoTokenStart, infoOption.length()), ","); //$NON-NLS-1$
2418 					int tokenCounter = 0;
2419 
2420 					while (tokenizer.hasMoreTokens()) {
2421 						String token = tokenizer.nextToken();
2422 						tokenCounter++;
2423 						switch(token.charAt(0)) {
2424 							case '+' :
2425 								isEnabling = true;
2426 								token = token.substring(1);
2427 								break;
2428 							case '-' :
2429 								isEnabling = false;
2430 								token = token.substring(1);
2431 						}
2432 						handleInfoToken(token, isEnabling);
2433 					}
2434 					if (tokenCounter == 0) {
2435 						throw new IllegalArgumentException(
2436 							this.bind("configure.invalidInfoOption", currentArg)); //$NON-NLS-1$
2437 					}
2438 					continue;
2439 				}
2440 				if (currentArg.startsWith("-warn")) { //$NON-NLS-1$
2441 					mode = DEFAULT;
2442 					String warningOption = currentArg;
2443 					int length = currentArg.length();
2444 					if (length == 10 && warningOption.equals("-warn:" + NONE)) { //$NON-NLS-1$
2445 						disableAll(ProblemSeverities.Warning);
2446 						continue;
2447 					}
2448 					if (length <= 6) {
2449 						throw new IllegalArgumentException(
2450 							this.bind("configure.invalidWarningConfiguration", warningOption)); //$NON-NLS-1$
2451 					}
2452 					int warnTokenStart;
2453 					boolean isEnabling;
2454 					switch (warningOption.charAt(6)) {
2455 						case '+' :
2456 							warnTokenStart = 7;
2457 							isEnabling = true;
2458 							break;
2459 						case '-' :
2460 							warnTokenStart = 7;
2461 							isEnabling = false; // specified warnings are disabled
2462 							break;
2463 						default:
2464 							disableAll(ProblemSeverities.Warning);
2465 							warnTokenStart = 6;
2466 							isEnabling = true;
2467 					}
2468 
2469 					StringTokenizer tokenizer =
2470 						new StringTokenizer(warningOption.substring(warnTokenStart, warningOption.length()), ","); //$NON-NLS-1$
2471 					int tokenCounter = 0;
2472 
2473 					if (didSpecifyDeprecation) {  // deprecation could have also been set through -deprecation option
2474 						this.options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
2475 					}
2476 
2477 					while (tokenizer.hasMoreTokens()) {
2478 						String token = tokenizer.nextToken();
2479 						tokenCounter++;
2480 						switch(token.charAt(0)) {
2481 							case '+' :
2482 								isEnabling = true;
2483 								token = token.substring(1);
2484 								break;
2485 							case '-' :
2486 								isEnabling = false;
2487 								token = token.substring(1);
2488 						}
2489 						handleWarningToken(token, isEnabling);
2490 					}
2491 					if (tokenCounter == 0) {
2492 						throw new IllegalArgumentException(
2493 							this.bind("configure.invalidWarningOption", currentArg)); //$NON-NLS-1$
2494 					}
2495 					continue;
2496 				}
2497 				if (currentArg.startsWith("-err")) { //$NON-NLS-1$
2498 					mode = DEFAULT;
2499 					String errorOption = currentArg;
2500 					int length = currentArg.length();
2501 					if (length <= 5) {
2502 						throw new IllegalArgumentException(
2503 							this.bind("configure.invalidErrorConfiguration", errorOption)); //$NON-NLS-1$
2504 					}
2505 					int errorTokenStart;
2506 					boolean isEnabling;
2507 					switch (errorOption.charAt(5)) {
2508 						case '+' :
2509 							errorTokenStart = 6;
2510 							isEnabling = true;
2511 							break;
2512 						case '-' :
2513 							errorTokenStart = 6;
2514 							isEnabling = false; // specified errors are disabled
2515 							break;
2516 						default:
2517 							disableAll(ProblemSeverities.Error);
2518 							errorTokenStart = 5;
2519 							isEnabling = true;
2520 					}
2521 
2522 					StringTokenizer tokenizer =
2523 						new StringTokenizer(errorOption.substring(errorTokenStart, errorOption.length()), ","); //$NON-NLS-1$
2524 					int tokenCounter = 0;
2525 
2526 					while (tokenizer.hasMoreTokens()) {
2527 						String token = tokenizer.nextToken();
2528 						tokenCounter++;
2529 						switch(token.charAt(0)) {
2530 							case '+' :
2531 								isEnabling = true;
2532 								token = token.substring(1);
2533 								break;
2534 							case '-' :
2535 								isEnabling = false;
2536 								token = token.substring(1);
2537 								break;
2538 						}
2539 						handleErrorToken(token, isEnabling);
2540 					}
2541 					if (tokenCounter == 0) {
2542 						throw new IllegalArgumentException(
2543 							this.bind("configure.invalidErrorOption", currentArg)); //$NON-NLS-1$
2544 					}
2545 					continue;
2546 				}
2547 				if (currentArg.equals("-target")) { //$NON-NLS-1$
2548 					mode = INSIDE_TARGET;
2549 					continue;
2550 				}
2551 				if (currentArg.equals("-preserveAllLocals")) { //$NON-NLS-1$
2552 					this.options.put(
2553 						CompilerOptions.OPTION_PreserveUnusedLocal,
2554 						CompilerOptions.PRESERVE);
2555 					mode = DEFAULT;
2556 					continue;
2557 				}
2558 				if (currentArg.equals("-enableJavadoc")) {//$NON-NLS-1$
2559 					mode = DEFAULT;
2560 					this.enableJavadocOn = true;
2561 					continue;
2562 				}
2563 				if (currentArg.equals("-Xemacs")) { //$NON-NLS-1$
2564 					mode = DEFAULT;
2565 					this.logger.setEmacs();
2566 					continue;
2567 				}
2568 				// annotation processing
2569 				if (currentArg.startsWith("-A")) { //$NON-NLS-1$
2570 					mode = DEFAULT;
2571 					continue;
2572 				}
2573 				if (currentArg.equals("-processorpath")) { //$NON-NLS-1$
2574 					mode = INSIDE_PROCESSOR_PATH_start;
2575 					continue;
2576 				}
2577 				if (currentArg.equals("-processor")) { //$NON-NLS-1$
2578 					mode = INSIDE_PROCESSOR_start;
2579 					continue;
2580 				}
2581 				if (currentArg.equals("--processor-module-path")) { //$NON-NLS-1$
2582 					mode = INSIDE_PROCESSOR_MODULE_PATH_start;
2583 					continue;
2584 				}
2585 				if (currentArg.equals("-proc:only")) { //$NON-NLS-1$
2586 					this.options.put(
2587 						CompilerOptions.OPTION_GenerateClassFiles,
2588 						CompilerOptions.DISABLED);
2589 					mode = DEFAULT;
2590 					continue;
2591 				}
2592 				if (currentArg.equals("-proc:none")) { //$NON-NLS-1$
2593 					didSpecifyDisabledAnnotationProcessing = true;
2594 					this.options.put(
2595 						CompilerOptions.OPTION_Process_Annotations,
2596 						CompilerOptions.DISABLED);
2597 					mode = DEFAULT;
2598 					continue;
2599 				}
2600 				if (currentArg.equals("-s")) { //$NON-NLS-1$
2601 					mode = INSIDE_S_start;
2602 					continue;
2603 				}
2604 				if (currentArg.equals("-XprintProcessorInfo") //$NON-NLS-1$
2605 						|| currentArg.equals("-XprintRounds")) { //$NON-NLS-1$
2606 					mode = DEFAULT;
2607 					continue;
2608 				}
2609 				// tolerated javac options - quietly filtered out
2610 				if (currentArg.startsWith("-X")) { //$NON-NLS-1$
2611 					mode = DEFAULT;
2612 					continue;
2613 				}
2614 				if (currentArg.startsWith("-J")) { //$NON-NLS-1$
2615 					mode = DEFAULT;
2616 					continue;
2617 				}
2618 				if (currentArg.equals("-O")) { //$NON-NLS-1$
2619 					mode = DEFAULT;
2620 					continue;
2621 				}
2622 				if (currentArg.equals("-classNames")) { //$NON-NLS-1$
2623 					mode = INSIDE_CLASS_NAMES;
2624 					continue;
2625 				}
2626 				if (currentArg.equals("-properties")) { //$NON-NLS-1$
2627 					mode = INSIDE_WARNINGS_PROPERTIES;
2628 					continue;
2629 				}
2630 				if (currentArg.equals("-missingNullDefault")) { //$NON-NLS-1$
2631 					this.options.put(CompilerOptions.OPTION_ReportMissingNonNullByDefaultAnnotation, CompilerOptions.WARNING);
2632 					continue;
2633 				}
2634 				if (currentArg.equals("-annotationpath")) { //$NON-NLS-1$
2635 					mode = INSIDE_ANNOTATIONPATH_start;
2636 					continue;
2637 				}
2638 				break;
2639 			case INSIDE_TARGET :
2640 				if (this.didSpecifyTarget) {
2641 					throw new IllegalArgumentException(
2642 						this.bind("configure.duplicateTarget", currentArg));//$NON-NLS-1$
2643 				}
2644 				if (this.releaseVersion != null) {
2645 					throw new IllegalArgumentException(
2646 							this.bind("configure.unsupportedWithRelease", "-target"));//$NON-NLS-1$ //$NON-NLS-2$
2647 				}
2648 				this.didSpecifyTarget = true;
2649 				if (currentArg.equals("1.1")) { //$NON-NLS-1$
2650 					this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1);
2651 				} else if (currentArg.equals("1.2")) { //$NON-NLS-1$
2652 					this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2);
2653 				} else if (currentArg.equals("jsr14")) { //$NON-NLS-1$
2654 					this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_JSR14);
2655 				} else if (currentArg.equals("cldc1.1")) { //$NON-NLS-1$
2656 					this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_CLDC1_1);
2657 					this.options.put(CompilerOptions.OPTION_InlineJsr, CompilerOptions.ENABLED);
2658 				} else {
2659 					String version = optionStringToVersion(currentArg);
2660 					if (version != null) {
2661 						this.options.put(CompilerOptions.OPTION_TargetPlatform, version);
2662 					} else {
2663 						throw new IllegalArgumentException(this.bind("configure.targetJDK", currentArg)); //$NON-NLS-1$
2664 					}
2665 				}
2666 				mode = DEFAULT;
2667 				continue;
2668 			case INSIDE_LOG :
2669 				this.log = currentArg;
2670 				mode = DEFAULT;
2671 				continue;
2672 			case INSIDE_REPETITION :
2673 				try {
2674 					this.maxRepetition = Integer.parseInt(currentArg);
2675 					if (this.maxRepetition <= 0) {
2676 						throw new IllegalArgumentException(this.bind("configure.repetition", currentArg)); //$NON-NLS-1$
2677 					}
2678 				} catch (NumberFormatException e) {
2679 					throw new IllegalArgumentException(this.bind("configure.repetition", currentArg), e); //$NON-NLS-1$
2680 				}
2681 				mode = DEFAULT;
2682 				continue;
2683 			case INSIDE_MAX_PROBLEMS :
2684 				try {
2685 					this.maxProblems = Integer.parseInt(currentArg);
2686 					if (this.maxProblems <= 0) {
2687 						throw new IllegalArgumentException(this.bind("configure.maxProblems", currentArg)); //$NON-NLS-1$
2688 					}
2689 					this.options.put(CompilerOptions.OPTION_MaxProblemPerUnit, currentArg);
2690 				} catch (NumberFormatException e) {
2691 					throw new IllegalArgumentException(this.bind("configure.maxProblems", currentArg), e); //$NON-NLS-1$
2692 				}
2693 				mode = DEFAULT;
2694 				continue;
2695 			case INSIDE_RELEASE:
2696 				// If release is < 9, the following are disallowed:
2697 				// bootclasspath, -Xbootclasspath, -Xbootclasspath/a:, -Xbootclasspath/p:,
2698 				// -endorseddirs, -Djava.endorsed.dirs, -extdirs, -Djava.ext.dirs
2699 
2700 				// If release >= 9, the following are disallowed
2701 				// --system and --upgrade-module-path
2702 
2703 				// -source and -target are disallowed for any --release
2704 				this.releaseVersion = currentArg;
2705 				long releaseToJDKLevel = CompilerOptions.releaseToJDKLevel(currentArg);
2706 				if (releaseToJDKLevel == 0) {
2707 					throw new IllegalArgumentException(
2708 							this.bind("configure.unsupportedReleaseVersion", currentArg)); //$NON-NLS-1$
2709 				}
2710 				// Let's treat it as regular compliance mode
2711 				this.complianceLevel = releaseToJDKLevel;
2712 				String versionAsString = CompilerOptions.versionFromJdkLevel(releaseToJDKLevel);
2713 				this.options.put(CompilerOptions.OPTION_Compliance, versionAsString);
2714 				this.options.put(CompilerOptions.OPTION_Source, versionAsString);
2715 				this.options.put(CompilerOptions.OPTION_TargetPlatform, versionAsString);
2716 				mode = DEFAULT;
2717 				continue;
2718 			case INSIDE_SOURCE :
2719 				if (this.didSpecifySource) {
2720 					throw new IllegalArgumentException(
2721 						this.bind("configure.duplicateSource", currentArg));//$NON-NLS-1$
2722 				}
2723 				if (this.releaseVersion != null) {
2724 					throw new IllegalArgumentException(
2725 							this.bind("configure.unsupportedWithRelease", "-source"));//$NON-NLS-1$ //$NON-NLS-2$
2726 				}
2727 				this.didSpecifySource = true;
2728 				String version = optionStringToVersion(currentArg);
2729 				if (version != null) {
2730 					this.options.put(CompilerOptions.OPTION_Source, version);
2731 				} else {
2732 					throw new IllegalArgumentException(this.bind("configure.source", currentArg)); //$NON-NLS-1$
2733 				}
2734 				mode = DEFAULT;
2735 				continue;
2736 			case INSIDE_DEFAULT_ENCODING :
2737 				if (specifiedEncodings != null) {
2738 					// check already defined encoding
2739 					if (!specifiedEncodings.contains(currentArg)) {
2740 						if (specifiedEncodings.size() > 1) {
2741 							this.logger.logWarning(
2742 									this.bind("configure.differentencodings", //$NON-NLS-1$
2743 									currentArg,
2744 									getAllEncodings(specifiedEncodings)));
2745 						} else {
2746 							this.logger.logWarning(
2747 									this.bind("configure.differentencoding", //$NON-NLS-1$
2748 									currentArg,
2749 									getAllEncodings(specifiedEncodings)));
2750 						}
2751 					}
2752 				} else {
2753 					specifiedEncodings = new HashSet<>();
2754 				}
2755 				try { // ensure encoding is supported
2756 					new InputStreamReader(new ByteArrayInputStream(new byte[0]), currentArg);
2757 				} catch (UnsupportedEncodingException e) {
2758 					throw new IllegalArgumentException(
2759 						this.bind("configure.unsupportedEncoding", currentArg), e); //$NON-NLS-1$
2760 				}
2761 				specifiedEncodings.add(currentArg);
2762 				this.options.put(CompilerOptions.OPTION_Encoding, currentArg);
2763 				mode = DEFAULT;
2764 				continue;
2765 			case INSIDE_DESTINATION_PATH :
2766 				setDestinationPath(currentArg.equals(NONE) ? NONE : currentArg);
2767 				mode = DEFAULT;
2768 				continue;
2769 			case INSIDE_SYSTEM:
2770 				mode = DEFAULT;
2771 				setJavaHome(currentArg);
2772 				continue;
2773 			case INSIDE_MODULEPATH_start:
2774 				mode = DEFAULT;
2775 				String[] modulepaths = new String[1];
2776 				index += processPaths(newCommandLineArgs, index, currentArg, modulepaths);
2777 				modulepathArg = modulepaths[0];
2778 				continue;
2779 			case INSIDE_MODULESOURCEPATH_start:
2780 				mode = DEFAULT;
2781 				String[] moduleSourcepaths = new String[1];
2782 				index += processPaths(newCommandLineArgs, index, currentArg, moduleSourcepaths);
2783 				moduleSourcepathArg = moduleSourcepaths[0];
2784 				continue;
2785 			case INSIDE_ADD_EXPORTS:
2786 				mode = DEFAULT;
2787 				// TODO: better to validate the option before processing it further?
2788 				if (this.addonExports == Collections.EMPTY_LIST) {
2789 					this.addonExports = new ArrayList<>();
2790 				}
2791 				this.addonExports.add(currentArg);
2792 				continue;
2793 			case INSIDE_ADD_READS:
2794 				mode = DEFAULT;
2795 				if (this.addonReads == Collections.EMPTY_LIST) {
2796 					this.addonReads = new ArrayList<>();
2797 				}
2798 				this.addonReads.add(currentArg);
2799 				continue;
2800 			case INSIDE_ADD_MODULES:
2801 				mode = DEFAULT;
2802 				if (this.rootModules == Collections.EMPTY_SET) {
2803 					this.rootModules = new HashSet<>();
2804 				}
2805 				StringTokenizer tokenizer = new StringTokenizer(currentArg, ","); //$NON-NLS-1$
2806 				while (tokenizer.hasMoreTokens()) {
2807 					this.rootModules.add(tokenizer.nextToken().trim());
2808 				}
2809 				continue;
2810 			case INSIDE_LIMIT_MODULES:
2811 				mode = DEFAULT;
2812 				tokenizer = new StringTokenizer(currentArg, ","); //$NON-NLS-1$
2813 				while (tokenizer.hasMoreTokens()) {
2814 					if (this.limitedModules == null) {
2815 						this.limitedModules = new HashSet<>();
2816 					}
2817 					this.limitedModules.add(tokenizer.nextToken().trim());
2818 				}
2819 				continue;
2820 			case INSIDE_MODULE_VERSION:
2821 				mode = DEFAULT;
2822 				this.moduleVersion = validateModuleVersion(currentArg);
2823 				continue;
2824 			case INSIDE_CLASSPATH_start:
2825 				mode = DEFAULT;
2826 				index += processPaths(newCommandLineArgs, index, currentArg, classpaths);
2827 				continue;
2828 			case INSIDE_BOOTCLASSPATH_start:
2829 				mode = DEFAULT;
2830 				index += processPaths(newCommandLineArgs, index, currentArg, bootclasspaths);
2831 				continue;
2832 			case INSIDE_SOURCE_PATH_start:
2833 				mode = DEFAULT;
2834 				String[] sourcePaths = new String[1];
2835 				index += processPaths(newCommandLineArgs, index, currentArg, sourcePaths);
2836 				sourcepathClasspathArg = sourcePaths[0];
2837 				continue;
2838 			case INSIDE_EXT_DIRS:
2839 				if (currentArg.indexOf("[-d") != -1) { //$NON-NLS-1$
2840 					throw new IllegalArgumentException(
2841 						this.bind("configure.unexpectedDestinationPathEntry", //$NON-NLS-1$
2842 							"-extdir")); //$NON-NLS-1$
2843 				}
2844 				tokenizer = new StringTokenizer(currentArg,	File.pathSeparator, false);
2845 				extdirsClasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH);
2846 				while (tokenizer.hasMoreTokens())
2847 					extdirsClasspaths.add(tokenizer.nextToken());
2848 				mode = DEFAULT;
2849 				continue;
2850 			case INSIDE_ENDORSED_DIRS:
2851 				if (currentArg.indexOf("[-d") != -1) { //$NON-NLS-1$
2852 					throw new IllegalArgumentException(
2853 						this.bind("configure.unexpectedDestinationPathEntry", //$NON-NLS-1$
2854 							"-endorseddirs")); //$NON-NLS-1$
2855 				}				tokenizer = new StringTokenizer(currentArg,	File.pathSeparator, false);
2856 				endorsedDirClasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH);
2857 				while (tokenizer.hasMoreTokens())
2858 					endorsedDirClasspaths.add(tokenizer.nextToken());
2859 				mode = DEFAULT;
2860 				continue;
2861 			case INSIDE_SOURCE_DIRECTORY_DESTINATION_PATH:
2862 				if (currentArg.endsWith("]")) { //$NON-NLS-1$
2863 					customDestinationPath = currentArg.substring(0,
2864 						currentArg.length() - 1);
2865 				} else {
2866 					throw new IllegalArgumentException(
2867 						this.bind("configure.incorrectDestinationPathEntry", //$NON-NLS-1$
2868 							"[-d " + currentArg)); //$NON-NLS-1$
2869 				}
2870 				break;
2871 			case INSIDE_PROCESSOR_PATH_start :
2872 				// nothing to do here. This is consumed again by the AnnotationProcessorManager
2873 				mode = DEFAULT;
2874 				continue;
2875 			case INSIDE_PROCESSOR_start :
2876 				// nothing to do here. This is consumed again by the AnnotationProcessorManager
2877 				mode = DEFAULT;
2878 				continue;
2879 			case INSIDE_PROCESSOR_MODULE_PATH_start :
2880 				mode = DEFAULT;
2881 				continue;
2882 			case INSIDE_S_start :
2883 				// nothing to do here. This is consumed again by the AnnotationProcessorManager
2884 				mode = DEFAULT;
2885 				continue;
2886 			case INSIDE_CLASS_NAMES :
2887 				tokenizer = new StringTokenizer(currentArg, ","); //$NON-NLS-1$
2888 				if (this.classNames == null) {
2889 					this.classNames = new String[DEFAULT_SIZE_CLASSPATH];
2890 				}
2891 				while (tokenizer.hasMoreTokens()) {
2892 					if (this.classNames.length == classCount) {
2893 						// resize
2894 						System.arraycopy(
2895 							this.classNames,
2896 							0,
2897 							(this.classNames = new String[classCount * 2]),
2898 							0,
2899 							classCount);
2900 					}
2901 					this.classNames[classCount++] = tokenizer.nextToken();
2902 				}
2903 				mode = DEFAULT;
2904 				continue;
2905 			case INSIDE_WARNINGS_PROPERTIES :
2906 				initializeWarnings(currentArg);
2907 				mode = DEFAULT;
2908 				continue;
2909 			case INSIDE_ANNOTATIONPATH_start:
2910 				mode = DEFAULT;
2911 				if (currentArg.isEmpty() || currentArg.charAt(0) == '-')
2912 					throw new IllegalArgumentException(this.bind("configure.missingAnnotationPath", currentArg)); //$NON-NLS-1$
2913 				if (ANNOTATION_SOURCE_CLASSPATH.equals(currentArg)) {
2914 					this.annotationsFromClasspath = true;
2915 				} else {
2916 					if (this.annotationPaths == null)
2917 						this.annotationPaths = new ArrayList<String>();
2918 					StringTokenizer tokens = new StringTokenizer(currentArg, File.pathSeparator);
2919 					while (tokens.hasMoreTokens())
2920 						this.annotationPaths.add(tokens.nextToken());
2921 				}
2922 				continue;
2923 		}
2924 
2925 		// default is input directory, if no custom destination path exists
2926 		if (customDestinationPath == null) {
2927 			if (File.separatorChar != '/') {
2928 				currentArg = currentArg.replace('/', File.separatorChar);
2929 			}
2930 			if (currentArg.endsWith("[-d")) { //$NON-NLS-1$
2931 				currentSourceDirectory = currentArg.substring(0,
2932 					currentArg.length() - 3);
2933 				mode = INSIDE_SOURCE_DIRECTORY_DESTINATION_PATH;
2934 				continue;
2935 			}
2936 			currentSourceDirectory = currentArg;
2937 		}
2938 		File dir = new File(currentSourceDirectory);
2939 		if (!dir.isDirectory()) {
2940 			throw new IllegalArgumentException(
2941 				this.bind("configure.unrecognizedOption", currentSourceDirectory)); //$NON-NLS-1$
2942 		}
2943 		String[] result = FileFinder.find(dir, SuffixConstants.SUFFIX_STRING_java);
2944 		if (NONE.equals(customDestinationPath)) {
2945 			customDestinationPath = NONE; // ensure == comparison
2946 		}
2947 		if (this.filenames != null) {
2948 			// some source files were specified explicitly
2949 			int length = result.length;
2950 			System.arraycopy(
2951 				this.filenames,
2952 				0,
2953 				(this.filenames = new String[length + filesCount]),
2954 				0,
2955 				filesCount);
2956 			System.arraycopy(
2957 				this.encodings,
2958 				0,
2959 				(this.encodings = new String[length + filesCount]),
2960 				0,
2961 				filesCount);
2962 			System.arraycopy(
2963 				this.destinationPaths,
2964 				0,
2965 				(this.destinationPaths = new String[length + filesCount]),
2966 				0,
2967 				filesCount);
2968 			System.arraycopy(
2969 					this.modNames,
2970 					0,
2971 					(this.modNames = new String[length + filesCount]),
2972 					0,
2973 					filesCount);
2974 			System.arraycopy(result, 0, this.filenames, filesCount, length);
2975 			for (int i = 0; i < length; i++) {
2976 				this.encodings[filesCount + i] = customEncoding;
2977 				this.destinationPaths[filesCount + i] = customDestinationPath;
2978 				this.modNames[filesCount + i] = moduleName;
2979 			}
2980 			filesCount += length;
2981 			customEncoding = null;
2982 			customDestinationPath = null;
2983 			currentSourceDirectory = null;
2984 		} else {
2985 			this.filenames = result;
2986 			filesCount = this.filenames.length;
2987 			this.encodings = new String[filesCount];
2988 			this.destinationPaths = new String[filesCount];
2989 			this.modNames = new String[filesCount];
2990 			for (int i = 0; i < filesCount; i++) {
2991 				this.encodings[i] = customEncoding;
2992 				this.destinationPaths[i] = customDestinationPath;
2993 			}
2994 			customEncoding = null;
2995 			customDestinationPath = null;
2996 			currentSourceDirectory = null;
2997 		}
2998 		mode = DEFAULT;
2999 		continue;
3000 	}
3001 	if (this.enablePreview) {
3002 		this.options.put(
3003 				CompilerOptions.OPTION_EnablePreviews,
3004 				CompilerOptions.ENABLED);
3005 	}
3006 
3007 	// set DocCommentSupport, with appropriate side effects on defaults if
3008 	// javadoc is not enabled
3009 	if (this.enableJavadocOn) {
3010 		this.options.put(
3011 			CompilerOptions.OPTION_DocCommentSupport,
3012 			CompilerOptions.ENABLED);
3013 	} else if (this.warnJavadocOn || this.warnAllJavadocOn) {
3014 		this.options.put(
3015 			CompilerOptions.OPTION_DocCommentSupport,
3016 			CompilerOptions.ENABLED);
3017 		// override defaults: references that are embedded in javadoc are ignored
3018 		// from the perspective of parameters and thrown exceptions usage
3019 		this.options.put(
3020 			CompilerOptions.OPTION_ReportUnusedParameterIncludeDocCommentReference,
3021 			CompilerOptions.DISABLED);
3022 		this.options.put(
3023 			CompilerOptions.OPTION_ReportUnusedDeclaredThrownExceptionIncludeDocCommentReference,
3024 			CompilerOptions.DISABLED);
3025 	}
3026 	// configure warnings for javadoc contents
3027 	if (this.warnJavadocOn) {
3028 		this.options.put(
3029 			CompilerOptions.OPTION_ReportInvalidJavadocTags,
3030 			CompilerOptions.ENABLED);
3031 		this.options.put(
3032 			CompilerOptions.OPTION_ReportInvalidJavadocTagsDeprecatedRef,
3033 			CompilerOptions.ENABLED);
3034 		this.options.put(
3035 			CompilerOptions.OPTION_ReportInvalidJavadocTagsNotVisibleRef,
3036 			CompilerOptions.ENABLED);
3037 		this.options.put(
3038 			CompilerOptions.OPTION_ReportMissingJavadocTagsVisibility,
3039 			CompilerOptions.PRIVATE);
3040 	}
3041 	if (printUsageRequired || (filesCount == 0 && classCount == 0)) {
3042 		if (usageSection ==  null) {
3043 			printUsage(); // default
3044 		} else {
3045 			printUsage(usageSection);
3046 		}
3047 		this.proceed = false;
3048 		return;
3049 	}
3050 
3051 	if (this.log != null) {
3052 		this.logger.setLog(this.log);
3053 	} else {
3054 		this.showProgress = false;
3055 	}
3056 	this.logger.logVersion(printVersionRequired);
3057 
3058 	validateOptions(didSpecifyCompliance);
3059 
3060 	// Enable annotation processing by default in batch mode when compliance is at least 1.6
3061 	// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=185768
3062 	if (!didSpecifyDisabledAnnotationProcessing
3063 			&& CompilerOptions.versionToJdkLevel(this.options.get(CompilerOptions.OPTION_Compliance)) >= ClassFileConstants.JDK1_6) {
3064 		this.options.put(CompilerOptions.OPTION_Process_Annotations, CompilerOptions.ENABLED);
3065 	}
3066 
3067 	this.logger.logCommandLineArguments(newCommandLineArgs);
3068 	this.logger.logOptions(this.options);
3069 
3070 	if (this.maxRepetition == 0) {
3071 		this.maxRepetition = 1;
3072 	}
3073 	if (this.maxRepetition >= 3 && (this.timing & TIMING_ENABLED) != 0) {
3074 		this.compilerStats = new CompilerStats[this.maxRepetition];
3075 	}
3076 
3077 	if (filesCount != 0) {
3078 		System.arraycopy(
3079 			this.filenames,
3080 			0,
3081 			(this.filenames = new String[filesCount]),
3082 			0,
3083 			filesCount);
3084 	}
3085 
3086 	if (classCount != 0) {
3087 		System.arraycopy(
3088 			this.classNames,
3089 			0,
3090 			(this.classNames = new String[classCount]),
3091 			0,
3092 			classCount);
3093 	}
3094 
3095 	setPaths(bootclasspaths,
3096 			sourcepathClasspathArg,
3097 			sourcepathClasspaths,
3098 			classpaths,
3099 			modulepathArg,
3100 			moduleSourcepathArg,
3101 			extdirsClasspaths,
3102 			endorsedDirClasspaths,
3103 			customEncoding);
3104 
3105 	if (specifiedEncodings != null && specifiedEncodings.size() > 1) {
3106 		this.logger.logWarning(this.bind("configure.multipleencodings", //$NON-NLS-1$
3107 				this.options.get(CompilerOptions.OPTION_Encoding),
3108 				getAllEncodings(specifiedEncodings)));
3109 	}
3110 	if (this.pendingErrors != null) {
3111 		for (Iterator<String> iterator = this.pendingErrors.iterator(); iterator.hasNext(); ) {
3112 			String message = iterator.next();
3113 			this.logger.logPendingError(message);
3114 		}
3115 		this.pendingErrors = null;
3116 	}
3117 }
3118 /** Translates any supported standarde version starting at 1.3 up-to latest into the corresponding constant from CompilerOptions */
3119 @SuppressWarnings("nls")
optionStringToVersion(String currentArg)3120 private String optionStringToVersion(String currentArg) {
3121 	switch (currentArg) {
3122 		case "1.3": return CompilerOptions.VERSION_1_3;
3123 		case "1.4": return CompilerOptions.VERSION_1_4;
3124 		case "1.5":
3125 		case "5":
3126 		case "5.0":
3127 			return CompilerOptions.VERSION_1_5;
3128 		case "1.6":
3129 		case "6":
3130 		case "6.0":
3131 			return CompilerOptions.VERSION_1_6;
3132 		case "1.7":
3133 		case "7":
3134 		case "7.0":
3135 			return CompilerOptions.VERSION_1_7;
3136 		case "1.8":
3137 		case "8":
3138 		case "8.0":
3139 			return CompilerOptions.VERSION_1_8;
3140 		case "1.9":
3141 		case "9":
3142 		case "9.0":
3143 			return CompilerOptions.VERSION_9;
3144 		case "10":
3145 		case "10.0":
3146 			return CompilerOptions.VERSION_10;
3147 		case "11":
3148 		case "11.0":
3149 			return CompilerOptions.VERSION_11;
3150 		case "12":
3151 		case "12.0":
3152 			return CompilerOptions.VERSION_12;
3153 		case "13":
3154 		case "13.0":
3155 			return CompilerOptions.VERSION_13;
3156 		case "14":
3157 		case "14.0":
3158 			return CompilerOptions.VERSION_14;
3159 		default:
3160 			return null;
3161 	}
3162 }
validateModuleVersion(String versionString)3163 private String validateModuleVersion(String versionString) {
3164 	try {
3165 		Class<?> versionClass = Class.forName("java.lang.module.ModuleDescriptor$Version"); //$NON-NLS-1$
3166 		Method method = versionClass.getMethod("parse", String.class); //$NON-NLS-1$
3167 		try {
3168 			method.invoke(null, versionString);
3169 		} catch (InvocationTargetException e) {
3170 			if (e.getCause() instanceof IllegalArgumentException)
3171 				throw (IllegalArgumentException) e.getCause();
3172 		}
3173 	} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException e) {
3174 		this.logger.logWarning(this.bind("configure.no.ModuleDescriptorVersionparse")); //$NON-NLS-1$
3175 	}
3176 	return versionString;
3177 }
3178 
getNewParser()3179 private Parser getNewParser() {
3180 	return new Parser(new ProblemReporter(getHandlingPolicy(),
3181 			new CompilerOptions(this.options), getProblemFactory()), false);
3182 }
extractModuleDesc(String fileName)3183 private IModule extractModuleDesc(String fileName) {
3184 	IModule mod = null;
3185 	// this.options may not be completely populated yet, and definitely not
3186 	// validated. Make sure the source level is set for the parser
3187 	Map<String,String> opts = new HashMap<String, String>(this.options);
3188 	opts.put(CompilerOptions.OPTION_Source, this.options.get(CompilerOptions.OPTION_Compliance));
3189 	Parser parser = new Parser(new ProblemReporter(getHandlingPolicy(),
3190 			new CompilerOptions(opts), getProblemFactory()), false);
3191 	if (fileName.toLowerCase().endsWith(IModule.MODULE_INFO_JAVA)) {
3192 
3193 		ICompilationUnit cu = new CompilationUnit(null, fileName, null);
3194 		CompilationResult compilationResult = new CompilationResult(cu, 0, 1, 10);
3195 		CompilationUnitDeclaration unit = parser.parse(cu, compilationResult);
3196 		if (unit.isModuleInfo() && unit.moduleDeclaration != null) {
3197 			mod = new BasicModule(unit.moduleDeclaration, null);
3198 		}
3199 	} else if (fileName.toLowerCase().endsWith(IModule.MODULE_INFO_CLASS)) {
3200 		try {
3201 			ClassFileReader reader = ClassFileReader.read(fileName); // Check the absolute path?
3202 			mod = reader.getModuleDeclaration();
3203 		} catch (ClassFormatException | IOException e) {
3204 			e.printStackTrace();
3205 			throw new IllegalArgumentException(
3206 					this.bind("configure.invalidModuleDescriptor", fileName)); //$NON-NLS-1$
3207 		}
3208 	}
3209 	return mod;
3210 }
3211 
decodeIgnoreOptionalProblemsFromFolders(String folders)3212 private static char[][] decodeIgnoreOptionalProblemsFromFolders(String folders) {
3213 	StringTokenizer tokenizer = new StringTokenizer(folders, File.pathSeparator);
3214 	char[][] result = new char[2 * tokenizer.countTokens()][];
3215 	int count = 0;
3216 	while (tokenizer.hasMoreTokens()) {
3217 		String fileName = tokenizer.nextToken();
3218 		// relative folder names are created relative to the current user dir
3219 		File file = new File(fileName);
3220 		if (file.exists()) {
3221 			String absolutePath = file.getAbsolutePath();
3222 			result[count++] = absolutePath.toCharArray();
3223 			// if the file exists, we should try to use its canonical path
3224 			try {
3225 				String canonicalPath = file.getCanonicalPath();
3226 				if (!absolutePath.equals(canonicalPath)) {
3227 					result[count++] = canonicalPath.toCharArray();
3228 				}
3229 			} catch (IOException e) {
3230 				// ignore
3231 			}
3232 		} else {
3233 			// if the file does not exist, use the name that was specified
3234 			result[count++] = fileName.toCharArray();
3235 		}
3236 	}
3237 	if (count < result.length) {
3238 		char[][] shortened = new char[count][];
3239 		System.arraycopy(result, 0, shortened, 0, count);
3240 		result = shortened;
3241 	}
3242 	return result;
3243 }
3244 
getAllEncodings(Set<String> encodings)3245 private static String getAllEncodings(Set<String> encodings) {
3246 	int size = encodings.size();
3247 	String[] allEncodings = new String[size];
3248 	encodings.toArray(allEncodings);
3249 	Arrays.sort(allEncodings);
3250 	StringBuffer buffer = new StringBuffer();
3251 	for (int i = 0; i < size; i++) {
3252 		if (i > 0) {
3253 			buffer.append(", "); //$NON-NLS-1$
3254 		}
3255 		buffer.append(allEncodings[i]);
3256 	}
3257 	return String.valueOf(buffer);
3258 }
3259 @SuppressWarnings("rawtypes")
initializeWarnings(String propertiesFile)3260 private void initializeWarnings(String propertiesFile) {
3261 	File file = new File(propertiesFile);
3262 	if (!file.exists()) {
3263 		throw new IllegalArgumentException(this.bind("configure.missingwarningspropertiesfile", propertiesFile)); //$NON-NLS-1$
3264 	}
3265 	BufferedInputStream stream = null;
3266 	Properties properties = null;
3267 	try {
3268 		stream = new BufferedInputStream(new FileInputStream(propertiesFile));
3269 		properties = new Properties();
3270 		properties.load(stream);
3271 	} catch(IOException e) {
3272 		e.printStackTrace();
3273 		throw new IllegalArgumentException(this.bind("configure.ioexceptionwarningspropertiesfile", propertiesFile)); //$NON-NLS-1$
3274 	} finally {
3275 		if (stream != null) {
3276 			try {
3277 				stream.close();
3278 			} catch(IOException e) {
3279 				// ignore
3280 			}
3281 		}
3282 	}
3283 	for(Iterator iterator = properties.entrySet().iterator(); iterator.hasNext(); ) {
3284 		Map.Entry entry = (Map.Entry) iterator.next();
3285 		final String key = entry.getKey().toString();
3286 		if (key.startsWith("org.eclipse.jdt.core.compiler.")) { //$NON-NLS-1$
3287 			this.options.put(key, entry.getValue().toString());
3288 		}
3289 	}
3290 	// when using a properties file mimic relevant defaults from JavaCorePreferenceInitializer:
3291 	if (!properties.containsKey(CompilerOptions.OPTION_LocalVariableAttribute)) {
3292 		this.options.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE);
3293 	}
3294 	if (!properties.containsKey(CompilerOptions.OPTION_PreserveUnusedLocal)) {
3295 		this.options.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.PRESERVE);
3296 	}
3297 	if (!properties.containsKey(CompilerOptions.OPTION_DocCommentSupport)) {
3298 		this.options.put(CompilerOptions.OPTION_DocCommentSupport, CompilerOptions.ENABLED);
3299 	}
3300 	if (!properties.containsKey(CompilerOptions.OPTION_ReportForbiddenReference)) {
3301 		this.options.put(CompilerOptions.OPTION_ReportForbiddenReference, CompilerOptions.ERROR);
3302 	}
3303 }
enableAll(int severity)3304 protected void enableAll(int severity) {
3305 	String newValue = null;
3306 	switch(severity) {
3307 		case ProblemSeverities.Error :
3308 			newValue = CompilerOptions.ERROR;
3309 			break;
3310 		case ProblemSeverities.Warning :
3311 			newValue = CompilerOptions.WARNING;
3312 			break;
3313 	}
3314 	Map.Entry<String, String>[] entries = this.options.entrySet().toArray(new Map.Entry[this.options.size()]);
3315 	for (int i = 0, max = entries.length; i < max; i++) {
3316 		Map.Entry<String, String> entry = entries[i];
3317 		if (entry.getValue().equals(CompilerOptions.IGNORE)) {
3318 			this.options.put(entry.getKey(), newValue);
3319 		}
3320 	}
3321 	this.options.put(CompilerOptions.OPTION_TaskTags, Util.EMPTY_STRING);
3322 	if (newValue != null) {
3323 		this.options.remove(newValue);
3324 	}
3325 }
disableAll(int severity)3326 protected void disableAll(int severity) {
3327 	String checkedValue = null;
3328 	switch(severity) {
3329 		case ProblemSeverities.Error :
3330 			checkedValue = CompilerOptions.ERROR;
3331 			break;
3332 		case ProblemSeverities.Warning :
3333 			checkedValue = CompilerOptions.WARNING;
3334 			break;
3335 		case ProblemSeverities.Info :
3336 			checkedValue = CompilerOptions.INFO;
3337 			break;
3338 	}
3339 	Set<Entry<String, String>> entrySet = this.options.entrySet();
3340 	for (Entry<String, String> entry : entrySet) {
3341 		if (entry.getValue().equals(checkedValue)) {
3342 			this.options.put(entry.getKey(), CompilerOptions.IGNORE);
3343 		}
3344 	}
3345 	if (checkedValue != null) {
3346 		this.options.put(checkedValue, CompilerOptions.IGNORE);
3347 	}
3348 	if (severity == ProblemSeverities.Warning) {
3349 		disableAll(ProblemSeverities.Info);
3350 	}
3351 }
extractDestinationPathFromSourceFile(CompilationResult result)3352 public String extractDestinationPathFromSourceFile(CompilationResult result) {
3353 	ICompilationUnit compilationUnit = result.compilationUnit;
3354 	if (compilationUnit != null) {
3355 		char[] fileName = compilationUnit.getFileName();
3356 		int lastIndex = CharOperation.lastIndexOf(java.io.File.separatorChar, fileName);
3357 		if (lastIndex != -1) {
3358 			final String outputPathName = new String(fileName, 0, lastIndex);
3359 			final File output = new File(outputPathName);
3360 			if (output.exists() && output.isDirectory()) {
3361 				return outputPathName;
3362 			}
3363 		}
3364 	}
3365 	return System.getProperty("user.dir"); //$NON-NLS-1$
3366 }
3367 /*
3368  * Answer the component to which will be handed back compilation results from the compiler
3369  */
getBatchRequestor()3370 public ICompilerRequestor getBatchRequestor() {
3371     return new BatchCompilerRequestor(this);
3372 }
3373 /*
3374  *  Build the set of compilation source units
3375  */
getCompilationUnits()3376 public CompilationUnit[] getCompilationUnits() {
3377 	int fileCount = this.filenames.length;
3378 	CompilationUnit[] units = new CompilationUnit[fileCount];
3379 	HashtableOfObject knownFileNames = new HashtableOfObject(fileCount);
3380 
3381 	String defaultEncoding = this.options.get(CompilerOptions.OPTION_Encoding);
3382 	if (Util.EMPTY_STRING.equals(defaultEncoding))
3383 		defaultEncoding = null;
3384 
3385 	for (int round = 0; round < 2; round++) {
3386 		for (int i = 0; i < fileCount; i++) {
3387 			char[] charName = this.filenames[i].toCharArray();
3388 			boolean isModuleInfo = CharOperation.endsWith(charName, TypeConstants.MODULE_INFO_FILE_NAME);
3389 			if (isModuleInfo == (round==0)) { // 1st round: modules, 2nd round others (to ensure populating pathToModCU well in time)
3390 				if (knownFileNames.get(charName) != null)
3391 					throw new IllegalArgumentException(this.bind("unit.more", this.filenames[i])); //$NON-NLS-1$
3392 				knownFileNames.put(charName, charName);
3393 				File file = new File(this.filenames[i]);
3394 				if (!file.exists())
3395 					throw new IllegalArgumentException(this.bind("unit.missing", this.filenames[i])); //$NON-NLS-1$
3396 				String encoding = this.encodings[i];
3397 				if (encoding == null)
3398 					encoding = defaultEncoding;
3399 				String fileName;
3400 				try {
3401 					fileName = file.getCanonicalPath();
3402 				} catch (IOException e) {
3403 					// if we got exception during canonicalization, fall back to the name that was specified
3404 					fileName = this.filenames[i];
3405 				}
3406 				units[i] = new CompilationUnit(null, fileName, encoding, this.destinationPaths[i],
3407 						shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, fileName.toCharArray()),
3408 						this.modNames[i]);
3409 			}
3410 		}
3411 	}
3412 	return units;
3413 }
3414 
3415 /*
3416  *  Low-level API performing the actual compilation
3417  */
getHandlingPolicy()3418 public IErrorHandlingPolicy getHandlingPolicy() {
3419 
3420 	// passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match)
3421 	return new IErrorHandlingPolicy() {
3422 		@Override
3423 		public boolean proceedOnErrors() {
3424 			return Main.this.proceedOnError; // stop if there are some errors
3425 		}
3426 		@Override
3427 		public boolean stopOnFirstError() {
3428 			return false;
3429 		}
3430 		@Override
3431 		public boolean ignoreAllErrors() {
3432 			return false;
3433 		}
3434 	};
3435 }
3436 private void setJavaHome(String javaHome) {
3437 	File release = new File(javaHome, "release"); //$NON-NLS-1$
3438 	Properties prop = new Properties();
3439 	try {
3440 		prop.load(new FileReader(release));
3441 		String ver = prop.getProperty("JAVA_VERSION"); //$NON-NLS-1$
3442 		if (ver != null)
3443 			ver = ver.replace("\"", "");  //$NON-NLS-1$//$NON-NLS-2$
3444 		this.javaHomeCache = new File(javaHome);
3445 		this.javaHomeChecked = true;
3446 	} catch (IOException e) {
3447 		throw new IllegalArgumentException(this.bind("configure.invalidSystem", javaHome)); //$NON-NLS-1$
3448 	}
3449 }
3450 /*
3451  * External API
3452  */
3453 public File getJavaHome() {
3454 	if (!this.javaHomeChecked) {
3455 		this.javaHomeChecked = true;
3456 		this.javaHomeCache = Util.getJavaHome();
3457 	}
3458 	return this.javaHomeCache;
3459 }
3460 
3461 public FileSystem getLibraryAccess() {
3462 	FileSystem nameEnvironment = new FileSystem(this.checkedClasspaths, this.filenames,
3463 					this.annotationsFromClasspath && CompilerOptions.ENABLED.equals(this.options.get(CompilerOptions.OPTION_AnnotationBasedNullAnalysis)),
3464 					this.limitedModules);
3465 	nameEnvironment.module = this.module;
3466 	processAddonModuleOptions(nameEnvironment);
3467 	return nameEnvironment;
3468 }
3469 
3470 /*
3471  *  Low-level API performing the actual compilation
3472  */
3473 public IProblemFactory getProblemFactory() {
3474 	return new DefaultProblemFactory(this.compilerLocale);
3475 }
3476 
3477 /*
3478  * External API
3479  */
3480 protected ArrayList<Classpath> handleBootclasspath(ArrayList<String> bootclasspaths, String customEncoding) {
3481  	final int bootclasspathsSize;
3482  	ArrayList<Classpath> result = new ArrayList<>(DEFAULT_SIZE_CLASSPATH);
3483 	if ((bootclasspaths != null)
3484 		&& ((bootclasspathsSize = bootclasspaths.size()) != 0)) {
3485 		result = new ArrayList<>(bootclasspathsSize);
3486 		for (String path : bootclasspaths) {
3487 			processPathEntries(DEFAULT_SIZE_CLASSPATH, result, path, customEncoding, false, true);
3488 		}
3489 	} else {
3490 		try {
3491 			Util.collectVMBootclasspath(result, this.javaHomeCache);
3492 		} catch(IllegalStateException e) {
3493 			throw new IllegalArgumentException(this.bind("configure.invalidSystem", this.javaHomeCache.toString())); //$NON-NLS-1$
3494 		}
3495 	}
3496 	return result;
3497 }
3498 private void processAddonModuleOptions(FileSystem env) {
3499 	Map<String, IPackageExport[]> exports = new HashMap<>();
3500 	for (String option : this.addonExports) {
3501 		AddExport addExport = ModuleFinder.extractAddonExport(option);
3502 		if (addExport != null) {
3503 			String modName = addExport.sourceModuleName;
3504 			IPackageExport export = addExport.export;
3505 			IPackageExport[] existing = exports.get(modName);
3506 			if (existing == null) {
3507 				existing = new IPackageExport[1];
3508 				existing[0] = export;
3509 				exports.put(modName, existing);
3510 			} else {
3511 				for (IPackageExport iPackageExport : existing) {
3512 					if (CharOperation.equals(iPackageExport.name(), export.name())) {
3513 						throw new IllegalArgumentException(this.bind("configure.duplicateExport")); //$NON-NLS-1$
3514 					}
3515 				}
3516 				IPackageExport[] updated = new IPackageExport[existing.length + 1];
3517 				System.arraycopy(existing, 0, updated, 0, existing.length);
3518 				updated[existing.length] = export;
3519 				exports.put(modName, updated);
3520 			}
3521 			env.addModuleUpdate(modName, m -> m.addExports(export.name(), export.targets()), UpdateKind.PACKAGE);
3522 		} else {
3523 			throw new IllegalArgumentException(this.bind("configure.invalidModuleOption", "--add-exports " + option)); //$NON-NLS-1$ //$NON-NLS-2$
3524 		}
3525 	}
3526 	for (String option : this.addonReads) {
3527 		String[] result = ModuleFinder.extractAddonRead(option);
3528 		if (result != null && result.length == 2) {
3529 			env.addModuleUpdate(result[0], m -> m.addReads(result[1].toCharArray()), UpdateKind.MODULE);
3530 		} else {
3531 			throw new IllegalArgumentException(this.bind("configure.invalidModuleOption", "--add-reads " + option)); //$NON-NLS-1$ //$NON-NLS-2$
3532 		}
3533 	}
3534 }
3535 protected ArrayList<FileSystem.Classpath> handleModulepath(String arg) {
3536 	ArrayList<String> modulePaths = processModulePathEntries(arg);
3537 	ArrayList<Classpath> result = new ArrayList<>();
3538 	if ((modulePaths != null && modulePaths.size() > 0)) {
3539 		for (String path : modulePaths) {
3540 			File file = new File(path);
3541 			if (file.isDirectory()) {
3542 				result.addAll(
3543 					ModuleFinder.findModules(file, null, getNewParser(), this.options, true, this.releaseVersion));
3544 			} else {
3545 				Classpath modulePath = ModuleFinder.findModule(file, null, getNewParser(), this.options, true, this.releaseVersion);
3546 				if (modulePath != null)
3547 					result.add(modulePath);
3548 			}
3549 		}
3550 	}
3551 	// TODO: What about chained jars from MANIFEST.MF? Check with spec
3552 	return result;
3553 }
3554 protected ArrayList<FileSystem.Classpath> handleModuleSourcepath(String arg) {
3555 	ArrayList<String> modulePaths = processModulePathEntries(arg);
3556 	ArrayList<FileSystem.Classpath> result = new ArrayList<>();
3557 	if ((modulePaths != null)
3558 		&& (modulePaths.size() != 0)) {
3559 
3560 		if (this.destinationPath == null) {
3561 			addPendingErrors(this.bind("configure.missingDestinationPath"));//$NON-NLS-1$
3562 		}
3563 		String[] paths = new String[modulePaths.size()];
3564 		modulePaths.toArray(paths);
3565 		for (int i = 0; i < paths.length; i++) {
3566 			File dir = new File(paths[i]);
3567 			if (dir.isDirectory()) {
3568 				// 1. Create FileSystem.Classpath for each module
3569 				// 2. Iterator each module in case of directory for source files and add to this.fileNames
3570 
3571 				List<Classpath> modules = ModuleFinder.findModules(dir, this.destinationPath, getNewParser(), this.options, false, this.releaseVersion);
3572 				for (Classpath classpath : modules) {
3573 					result.add(classpath);
3574 					Path modLocation = Paths.get(classpath.getPath()).toAbsolutePath();
3575 					String destPath = classpath.getDestinationPath();
3576 					IModule mod = classpath.getModule();
3577 					String moduleName = mod == null ? null : new String(mod.name());
3578 					for(int j = 0; j < this.filenames.length; j++) {
3579 						Path filePath;
3580 						try {
3581 							// Get canonical path just as the classpath location is stored with the same.
3582 							// To avoid mismatch of /USER_JAY and /USE~1 in windows systems.
3583 							filePath = new File(this.filenames[j]).getCanonicalFile().toPath();
3584 							if (filePath.startsWith(modLocation)) {
3585 								this.modNames[j] = moduleName;
3586 								this.destinationPaths[j] = destPath;
3587 							}
3588 						} catch (IOException e) {
3589 							// Files doesn't exist and perhaps doesn't belong in a module, move on to other files
3590 							// Use empty module name to distinguish from missing module case
3591 							this.modNames[j] = ""; //$NON-NLS-1$
3592 						}
3593 					}
3594 				}
3595 			}
3596 		}
3597 		for(int j = 0; j < this.filenames.length; j++) {
3598 			if (this.modNames[j] == null) {
3599 				throw new IllegalArgumentException(this.bind("configure.notOnModuleSourcePath", new String[] {this.filenames[j]})); //$NON-NLS-1$
3600 			}
3601 		}
3602 	}
3603 	return result;
3604 }
3605 /*
3606  * External API
3607  */
3608 protected ArrayList<FileSystem.Classpath> handleClasspath(ArrayList<String> classpaths, String customEncoding) {
3609 	ArrayList<FileSystem.Classpath> initial = new ArrayList<>(DEFAULT_SIZE_CLASSPATH);
3610 	if (classpaths != null && classpaths.size() > 0) {
3611 		for (String path : classpaths) {
3612 			processPathEntries(DEFAULT_SIZE_CLASSPATH, initial, path, customEncoding, false, true);
3613 		}
3614 	} else {
3615 		// no user classpath specified.
3616 		String classProp = System.getProperty("java.class.path"); //$NON-NLS-1$
3617 		if ((classProp == null) || (classProp.length() == 0)) {
3618 			addPendingErrors(this.bind("configure.noClasspath")); //$NON-NLS-1$
3619 			final Classpath classpath = FileSystem.getClasspath(System.getProperty("user.dir"), customEncoding, null, this.options, this.releaseVersion);//$NON-NLS-1$
3620 			if (classpath != null) {
3621 				initial.add(classpath);
3622 			}
3623 		} else {
3624 			StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator);
3625 			String token;
3626 			while (tokenizer.hasMoreTokens()) {
3627 				token = tokenizer.nextToken();
3628 				FileSystem.Classpath currentClasspath = FileSystem
3629 						.getClasspath(token, customEncoding, null, this.options, this.releaseVersion);
3630 				if (currentClasspath != null) {
3631 					initial.add(currentClasspath);
3632 				} else if (token.length() != 0) {
3633 					addPendingErrors(this.bind("configure.incorrectClasspath", token));//$NON-NLS-1$
3634 				}
3635 			}
3636 		}
3637 	}
3638 	ArrayList<Classpath> result = new ArrayList<>();
3639 	HashMap<String, Classpath> knownNames = new HashMap<>();
3640 	FileSystem.ClasspathSectionProblemReporter problemReporter =
3641 		new FileSystem.ClasspathSectionProblemReporter() {
3642 			@Override
3643 			public void invalidClasspathSection(String jarFilePath) {
3644 				addPendingErrors(bind("configure.invalidClasspathSection", jarFilePath)); //$NON-NLS-1$
3645 			}
3646 			@Override
3647 			public void multipleClasspathSections(String jarFilePath) {
3648 				addPendingErrors(bind("configure.multipleClasspathSections", jarFilePath)); //$NON-NLS-1$
3649 			}
3650 		};
3651 	while (! initial.isEmpty()) {
3652 		Classpath current = initial.remove(0);
3653 		String currentPath = current.getPath();
3654 		if (knownNames.get(currentPath) == null) {
3655 			knownNames.put(currentPath, current);
3656 			result.add(current);
3657 			List<Classpath> linkedJars = current.fetchLinkedJars(problemReporter);
3658 			if (linkedJars != null) {
3659 				initial.addAll(0, linkedJars);
3660 			}
3661 		}
3662 	}
3663 	return result;
3664 }
3665 /*
3666  * External API
3667  */
3668 protected ArrayList<FileSystem.Classpath> handleEndorseddirs(ArrayList<String> endorsedDirClasspaths) {
3669  	final File javaHome = getJavaHome();
3670 	/*
3671 	 * Feed endorsedDirClasspath according to:
3672 	 * - -endorseddirs first if present;
3673 	 * - else java.endorsed.dirs if defined;
3674 	 * - else default extensions directory for the platform. (/lib/endorsed)
3675 	 */
3676 	if (endorsedDirClasspaths == null) {
3677 		endorsedDirClasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH);
3678 		String endorsedDirsStr = System.getProperty("java.endorsed.dirs"); //$NON-NLS-1$
3679 		if (endorsedDirsStr == null) {
3680 			if (javaHome != null) {
3681 				endorsedDirClasspaths.add(javaHome.getAbsolutePath() + "/lib/endorsed"); //$NON-NLS-1$
3682 			}
3683 		} else {
3684 			StringTokenizer tokenizer = new StringTokenizer(endorsedDirsStr, File.pathSeparator);
3685 			while (tokenizer.hasMoreTokens()) {
3686 				endorsedDirClasspaths.add(tokenizer.nextToken());
3687 			}
3688 		}
3689 	}
3690 
3691 	/*
3692 	 * Feed extdirsClasspath with the entries found into the directories listed by
3693 	 * extdirsNames.
3694 	 */
3695 	if (endorsedDirClasspaths.size() != 0) {
3696 		ArrayList<FileSystem.Classpath> result = new ArrayList<>();
3697 		File[] directoriesToCheck = new File[endorsedDirClasspaths.size()];
3698 		for (int i = 0; i < directoriesToCheck.length; i++)
3699 			directoriesToCheck[i] = new File(endorsedDirClasspaths.get(i));
3700 		File[][] endorsedDirsJars = getLibrariesFiles(directoriesToCheck);
3701 		if (endorsedDirsJars != null) {
3702 			for (int i = 0, max = endorsedDirsJars.length; i < max; i++) {
3703 				File[] current = endorsedDirsJars[i];
3704 				if (current != null) {
3705 					for (int j = 0, max2 = current.length; j < max2; j++) {
3706 						FileSystem.Classpath classpath =
3707 							FileSystem.getClasspath(
3708 									current[j].getAbsolutePath(),
3709 									null, null, this.options, this.releaseVersion);
3710 						if (classpath != null) {
3711 							result.add(classpath);
3712 						}
3713 					}
3714 				} else if (directoriesToCheck[i].isFile()) {
3715 					addPendingErrors(
3716 						this.bind(
3717 							"configure.incorrectEndorsedDirsEntry", //$NON-NLS-1$
3718 							directoriesToCheck[i].getAbsolutePath()));
3719 				}
3720 			}
3721 		}
3722 		return result;
3723 	}
3724 	return FileSystem.EMPTY_CLASSPATH;
3725 }
3726 
3727 /*
3728  * External API
3729  * Handle extdirs processing
3730  */
3731 protected ArrayList<FileSystem.Classpath> handleExtdirs(ArrayList<String> extdirsClasspaths) {
3732  	final File javaHome = getJavaHome();
3733 
3734 	/*
3735 	 * Feed extDirClasspath according to:
3736 	 * - -extdirs first if present;
3737 	 * - else java.ext.dirs if defined;
3738 	 * - else default extensions directory for the platform.
3739 	 */
3740 	if (extdirsClasspaths == null) {
3741 		extdirsClasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH);
3742 		String extdirsStr = System.getProperty("java.ext.dirs"); //$NON-NLS-1$
3743 		if (extdirsStr == null) {
3744 			extdirsClasspaths.add(javaHome.getAbsolutePath() + "/lib/ext"); //$NON-NLS-1$
3745 		} else {
3746 			StringTokenizer tokenizer = new StringTokenizer(extdirsStr, File.pathSeparator);
3747 			while (tokenizer.hasMoreTokens())
3748 				extdirsClasspaths.add(tokenizer.nextToken());
3749 		}
3750 	}
3751 
3752 	/*
3753 	 * Feed extdirsClasspath with the entries found into the directories listed by
3754 	 * extdirsNames.
3755 	 */
3756 	if (extdirsClasspaths.size() != 0) {
3757 		ArrayList<FileSystem.Classpath> result = new ArrayList<>();
3758 		File[] directoriesToCheck = new File[extdirsClasspaths.size()];
3759 		for (int i = 0; i < directoriesToCheck.length; i++)
3760 			directoriesToCheck[i] = new File(extdirsClasspaths.get(i));
3761 		File[][] extdirsJars = getLibrariesFiles(directoriesToCheck);
3762 		if (extdirsJars != null) {
3763 			for (int i = 0, max = extdirsJars.length; i < max; i++) {
3764 				File[] current = extdirsJars[i];
3765 				if (current != null) {
3766 					for (int j = 0, max2 = current.length; j < max2; j++) {
3767 						FileSystem.Classpath classpath =
3768 							FileSystem.getClasspath(
3769 									current[j].getAbsolutePath(),
3770 									null, null, this.options, this.releaseVersion);
3771 						if (classpath != null) {
3772 							result.add(classpath);
3773 						}
3774 					}
3775 				} else if (directoriesToCheck[i].isFile()) {
3776 					addPendingErrors(this.bind(
3777 							"configure.incorrectExtDirsEntry", //$NON-NLS-1$
3778 							directoriesToCheck[i].getAbsolutePath()));
3779 				}
3780 			}
3781 		}
3782 		return result;
3783 	}
3784 
3785 	return FileSystem.EMPTY_CLASSPATH;
3786 }
3787 
3788 protected boolean isIgnored(IProblem problem) {
3789 	if (problem == null) {
3790 		return true;
3791 	}
3792 	if (problem.isError()) {
3793 		return false;
3794 	}
3795 	String key = problem.isInfo() ? CompilerOptions.INFO : CompilerOptions.WARNING;
3796 	if (CompilerOptions.IGNORE.equals(this.options.get(key))) {
3797 		return true;
3798 	}
3799 	if (this.ignoreOptionalProblemsFromFolders != null) {
3800 		char[] fileName = problem.getOriginatingFileName();
3801 		if (fileName != null) {
3802 			return shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, fileName);
3803 		}
3804 	}
3805 	return false;
3806 }
3807 
3808 /*
3809  * External API
3810  * Handle a single warning token.
3811 */
3812 protected void handleInfoToken(String token, boolean isEnabling) {
3813 	handleErrorOrWarningToken(token, isEnabling, ProblemSeverities.Info);
3814 }
3815 protected void handleWarningToken(String token, boolean isEnabling) {
3816 	handleErrorOrWarningToken(token, isEnabling, ProblemSeverities.Warning);
3817 }
3818 protected void handleErrorToken(String token, boolean isEnabling) {
3819 	handleErrorOrWarningToken(token, isEnabling, ProblemSeverities.Error);
3820 }
3821 private void setSeverity(String compilerOptions, int severity, boolean isEnabling) {
3822 	if (isEnabling) {
3823 		switch(severity) {
3824 			case ProblemSeverities.Error :
3825 				this.options.put(compilerOptions, CompilerOptions.ERROR);
3826 				break;
3827 			case ProblemSeverities.Warning :
3828 				this.options.put(compilerOptions, CompilerOptions.WARNING);
3829 				break;
3830 			case ProblemSeverities.Info :
3831 				this.options.put(compilerOptions, CompilerOptions.INFO);
3832 				break;
3833 			default:
3834 				this.options.put(compilerOptions, CompilerOptions.IGNORE);
3835 		}
3836 	} else {
3837 		switch(severity) {
3838 			case ProblemSeverities.Error :
3839 				String currentValue = this.options.get(compilerOptions);
3840 				if (CompilerOptions.ERROR.equals(currentValue)) {
3841 					this.options.put(compilerOptions, CompilerOptions.IGNORE);
3842 				}
3843 				break;
3844 			case ProblemSeverities.Warning :
3845 				currentValue = this.options.get(compilerOptions);
3846 				if (CompilerOptions.WARNING.equals(currentValue)) {
3847 					this.options.put(compilerOptions, CompilerOptions.IGNORE);
3848 				}
3849 				break;
3850 			case ProblemSeverities.Info :
3851 				currentValue = this.options.get(compilerOptions);
3852 				if (CompilerOptions.INFO.equals(currentValue)) {
3853 					this.options.put(compilerOptions, CompilerOptions.IGNORE);
3854 				}
3855 				break;
3856 			default:
3857 				this.options.put(compilerOptions, CompilerOptions.IGNORE);
3858 		}
3859 	}
3860 }
3861 private void handleErrorOrWarningToken(String token, boolean isEnabling, int severity) {
3862 	if (token.length() == 0) return;
3863 	switch(token.charAt(0)) {
3864 		case 'a' :
3865 			if (token.equals("allDeprecation")) { //$NON-NLS-1$
3866 				setSeverity(CompilerOptions.OPTION_ReportDeprecation, severity, isEnabling);
3867 				setSeverity(CompilerOptions.OPTION_ReportTerminalDeprecation, severity, isEnabling);
3868 				this.options.put(
3869 					CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode,
3870 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
3871 				this.options.put(
3872 					CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod,
3873 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
3874 				return;
3875 			} else if (token.equals("allJavadoc")) { //$NON-NLS-1$
3876 				this.warnAllJavadocOn = this.warnJavadocOn = isEnabling;
3877 				setSeverity(CompilerOptions.OPTION_ReportInvalidJavadoc, severity, isEnabling);
3878 				setSeverity(CompilerOptions.OPTION_ReportMissingJavadocTags, severity, isEnabling);
3879 				setSeverity(CompilerOptions.OPTION_ReportMissingJavadocComments, severity, isEnabling);
3880 				return;
3881 			} else if (token.equals("assertIdentifier")) { //$NON-NLS-1$
3882 				setSeverity(CompilerOptions.OPTION_ReportAssertIdentifier, severity, isEnabling);
3883 				return;
3884 			} else if (token.equals("allDeadCode")) { //$NON-NLS-1$
3885 				setSeverity(CompilerOptions.OPTION_ReportDeadCode, severity, isEnabling);
3886 				this.options.put(
3887 					CompilerOptions.OPTION_ReportDeadCodeInTrivialIfStatement,
3888 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
3889 				return;
3890 			} else if (token.equals("allOver-ann")) { //$NON-NLS-1$
3891 				setSeverity(CompilerOptions.OPTION_ReportMissingOverrideAnnotation, severity, isEnabling);
3892 				this.options.put(
3893 					CompilerOptions.OPTION_ReportMissingOverrideAnnotationForInterfaceMethodImplementation,
3894 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
3895 				return;
3896 			} else if (token.equals("all-static-method")) { //$NON-NLS-1$
3897 				setSeverity(CompilerOptions.OPTION_ReportMethodCanBeStatic, severity, isEnabling);
3898 				setSeverity(CompilerOptions.OPTION_ReportMethodCanBePotentiallyStatic, severity, isEnabling);
3899 				return;
3900 			} else if (token.equals("all")) { //$NON-NLS-1$
3901 				if (isEnabling) {
3902 					enableAll(severity);
3903 				} else {
3904 					disableAll(severity);
3905 				}
3906 				return;
3907 			}
3908 			break;
3909 		case 'b' :
3910 			if (token.equals("boxing")) { //$NON-NLS-1$
3911 				setSeverity(CompilerOptions.OPTION_ReportAutoboxing, severity, isEnabling);
3912 				return;
3913 			}
3914 			break;
3915 		case 'c' :
3916 			if (token.equals("constructorName")) { //$NON-NLS-1$
3917 				setSeverity(CompilerOptions.OPTION_ReportMethodWithConstructorName, severity, isEnabling);
3918 				return;
3919 			} else if (token.equals("conditionAssign")) { //$NON-NLS-1$
3920 				setSeverity(CompilerOptions.OPTION_ReportPossibleAccidentalBooleanAssignment, severity, isEnabling);
3921 				return;
3922 			} else if (token.equals("compareIdentical")) { //$NON-NLS-1$
3923 				setSeverity(CompilerOptions.OPTION_ReportComparingIdentical, severity, isEnabling);
3924 				return;
3925 			} else if (token.equals("charConcat") /*|| token.equals("noImplicitStringConversion")/*backward compatible*/) {//$NON-NLS-1$
3926 				setSeverity(CompilerOptions.OPTION_ReportNoImplicitStringConversion, severity, isEnabling);
3927 				return;
3928 			}
3929 			break;
3930 		case 'd' :
3931 			if (token.equals("deprecation")) { //$NON-NLS-1$
3932 				setSeverity(CompilerOptions.OPTION_ReportDeprecation, severity, isEnabling);
3933 				this.options.put(
3934 					CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode,
3935 					CompilerOptions.DISABLED);
3936 				this.options.put(
3937 					CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod,
3938 					CompilerOptions.DISABLED);
3939 				return;
3940 			} else if (token.equals("dep-ann")) { //$NON-NLS-1$
3941 				setSeverity(CompilerOptions.OPTION_ReportMissingDeprecatedAnnotation, severity, isEnabling);
3942 				return;
3943 			} else if (token.equals("discouraged")) { //$NON-NLS-1$
3944 				setSeverity(CompilerOptions.OPTION_ReportDiscouragedReference, severity, isEnabling);
3945 				return;
3946 			} else if (token.equals("deadCode")) { //$NON-NLS-1$
3947 				setSeverity(CompilerOptions.OPTION_ReportDeadCode, severity, isEnabling);
3948 				this.options.put(
3949 					CompilerOptions.OPTION_ReportDeadCodeInTrivialIfStatement,
3950 					CompilerOptions.DISABLED);
3951 				return;
3952 			}
3953 			break;
3954 		case 'e' :
3955 			if (token.equals("enumSwitch")) { //$NON-NLS-1$
3956 				setSeverity(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, severity, isEnabling);
3957 				return;
3958 			} else if (token.equals("enumSwitchPedantic")) { //$NON-NLS-1$
3959 				if (isEnabling) {
3960 					switch (severity) {
3961 						case ProblemSeverities.Error:
3962 							setSeverity(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, severity, isEnabling);
3963 							break;
3964 						case ProblemSeverities.Warning:
3965 							if (CompilerOptions.IGNORE.equals(this.options.get(CompilerOptions.OPTION_ReportIncompleteEnumSwitch))) {
3966 								setSeverity(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, severity, isEnabling);
3967 							}
3968 							break;
3969 						default: // no severity update
3970 					}
3971 				}
3972 				this.options.put(CompilerOptions.OPTION_ReportMissingEnumCaseDespiteDefault,
3973 								 isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
3974 				return;
3975 			} else if (token.equals("emptyBlock")) {//$NON-NLS-1$
3976 				setSeverity(CompilerOptions.OPTION_ReportUndocumentedEmptyBlock, severity, isEnabling);
3977 				return;
3978 			} else if (token.equals("enumIdentifier")) { //$NON-NLS-1$
3979 				setSeverity(CompilerOptions.OPTION_ReportEnumIdentifier, severity, isEnabling);
3980 				return;
3981 			} else if (token.equals("exports")) { //$NON-NLS-1$
3982 				setSeverity(CompilerOptions.OPTION_ReportAPILeak, severity, isEnabling);
3983 				return;
3984 			}
3985 			break;
3986 		case 'f' :
3987 			if (token.equals("fieldHiding")) { //$NON-NLS-1$
3988 				setSeverity(CompilerOptions.OPTION_ReportFieldHiding, severity, isEnabling);
3989 				return;
3990 			} else if (token.equals("finalBound")) {//$NON-NLS-1$
3991 				setSeverity(CompilerOptions.OPTION_ReportFinalParameterBound, severity, isEnabling);
3992 				return;
3993 			} else if (token.equals("finally")) { //$NON-NLS-1$
3994 				setSeverity(CompilerOptions.OPTION_ReportFinallyBlockNotCompletingNormally, severity, isEnabling);
3995 				return;
3996 			} else if (token.equals("forbidden")) { //$NON-NLS-1$
3997 				setSeverity(CompilerOptions.OPTION_ReportForbiddenReference, severity, isEnabling);
3998 				return;
3999 			} else if (token.equals("fallthrough")) { //$NON-NLS-1$
4000 				setSeverity(CompilerOptions.OPTION_ReportFallthroughCase, severity, isEnabling);
4001 				return;
4002 			}
4003 			break;
4004 		case 'h' :
4005 			if (token.equals("hiding")) { //$NON-NLS-1$
4006 				setSeverity(CompilerOptions.OPTION_ReportHiddenCatchBlock, severity, isEnabling);
4007 				setSeverity(CompilerOptions.OPTION_ReportLocalVariableHiding, severity, isEnabling);
4008 				setSeverity(CompilerOptions.OPTION_ReportFieldHiding, severity, isEnabling);
4009 				setSeverity(CompilerOptions.OPTION_ReportTypeParameterHiding, severity, isEnabling);
4010 				return;
4011 			} else if (token.equals("hashCode")) { //$NON-NLS-1$
4012 				setSeverity(CompilerOptions.OPTION_ReportMissingHashCodeMethod, severity, isEnabling);
4013 				return;
4014 			}
4015 			break;
4016 		case 'i' :
4017 			if (token.equals("indirectStatic")) { //$NON-NLS-1$
4018 				setSeverity(CompilerOptions.OPTION_ReportIndirectStaticAccess, severity, isEnabling);
4019 				return;
4020 			} else if (token.equals("inheritNullAnnot")) { //$NON-NLS-1$
4021 				this.options.put(
4022 						CompilerOptions.OPTION_InheritNullAnnotations,
4023 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4024 				return;
4025 			} else if (token.equals("intfNonInherited") || token.equals("interfaceNonInherited")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$
4026 				setSeverity(CompilerOptions.OPTION_ReportIncompatibleNonInheritedInterfaceMethod, severity, isEnabling);
4027 				return;
4028 			} else if (token.equals("intfAnnotation")) { //$NON-NLS-1$
4029 				setSeverity(CompilerOptions.OPTION_ReportAnnotationSuperInterface, severity, isEnabling);
4030 				return;
4031 			} else if (token.equals("intfRedundant") /*|| token.equals("redundantSuperinterface")*/) { //$NON-NLS-1$
4032 				setSeverity(CompilerOptions.OPTION_ReportRedundantSuperinterface, severity, isEnabling);
4033 				return;
4034 			} else if (token.equals("includeAssertNull")) { //$NON-NLS-1$
4035 				this.options.put(
4036 						CompilerOptions.OPTION_IncludeNullInfoFromAsserts,
4037 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4038 				return;
4039 			} else if (token.equals("invalidJavadoc")) { //$NON-NLS-1$
4040 				setSeverity(CompilerOptions.OPTION_ReportInvalidJavadoc, severity, isEnabling);
4041 				this.options.put(
4042 					CompilerOptions.OPTION_ReportInvalidJavadocTags,
4043 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4044 				this.options.put(
4045 					CompilerOptions.OPTION_ReportInvalidJavadocTagsDeprecatedRef,
4046 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4047 				this.options.put(
4048 					CompilerOptions.OPTION_ReportInvalidJavadocTagsNotVisibleRef,
4049 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4050 				if (isEnabling) {
4051 					this.options.put(
4052 							CompilerOptions.OPTION_DocCommentSupport,
4053 							CompilerOptions.ENABLED);
4054 					this.options.put(
4055 						CompilerOptions.OPTION_ReportInvalidJavadocTagsVisibility,
4056 						CompilerOptions.PRIVATE);
4057 				}
4058 				return;
4059 			} else if (token.equals("invalidJavadocTag")) { //$NON-NLS-1$
4060 				this.options.put(
4061 					CompilerOptions.OPTION_ReportInvalidJavadocTags,
4062 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4063 				return;
4064 			} else if (token.equals("invalidJavadocTagDep")) { //$NON-NLS-1$
4065 				this.options.put(
4066 						CompilerOptions.OPTION_ReportInvalidJavadocTagsDeprecatedRef,
4067 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4068 				return;
4069 			} else if (token.equals("invalidJavadocTagNotVisible")) { //$NON-NLS-1$
4070 				this.options.put(
4071 						CompilerOptions.OPTION_ReportInvalidJavadocTagsNotVisibleRef,
4072 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4073 				return;
4074 			} else if (token.startsWith("invalidJavadocTagVisibility")) { //$NON-NLS-1$
4075 				int start = token.indexOf('(');
4076 				int end = token.indexOf(')');
4077 				String visibility = null;
4078 				if (isEnabling && start >= 0 && end >= 0 && start < end){
4079 					visibility = token.substring(start+1, end).trim();
4080 				}
4081 				if (visibility != null && visibility.equals(CompilerOptions.PUBLIC)
4082 						|| visibility.equals(CompilerOptions.PRIVATE)
4083 						|| visibility.equals(CompilerOptions.PROTECTED)
4084 						|| visibility.equals(CompilerOptions.DEFAULT)) {
4085 					this.options.put(
4086 							CompilerOptions.OPTION_ReportInvalidJavadocTagsVisibility,
4087 							visibility);
4088 					return;
4089 				} else {
4090 					throw new IllegalArgumentException(this.bind("configure.invalidJavadocTagVisibility", token)); //$NON-NLS-1$
4091 				}
4092 			}
4093 			break;
4094 		case 'j' :
4095 			if (token.equals("javadoc")) {//$NON-NLS-1$
4096 				this.warnJavadocOn = isEnabling;
4097 				setSeverity(CompilerOptions.OPTION_ReportInvalidJavadoc, severity, isEnabling);
4098 				setSeverity(CompilerOptions.OPTION_ReportMissingJavadocTags, severity, isEnabling);
4099 				return;
4100 			}
4101 			break;
4102 		case 'l' :
4103 			if (token.equals("localHiding")) { //$NON-NLS-1$
4104 				setSeverity(CompilerOptions.OPTION_ReportLocalVariableHiding, severity, isEnabling);
4105 				return;
4106 			}
4107 			break;
4108 		case 'm' :
4109 			if (token.equals("maskedCatchBlock") || token.equals("maskedCatchBlocks")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$
4110 				setSeverity(CompilerOptions.OPTION_ReportHiddenCatchBlock, severity, isEnabling);
4111 				return;
4112 			} else if (token.equals("missingJavadocTags")) { //$NON-NLS-1$
4113 				setSeverity(CompilerOptions.OPTION_ReportMissingJavadocTags, severity, isEnabling);
4114 				this.options.put(
4115 					CompilerOptions.OPTION_ReportMissingJavadocTagsOverriding,
4116 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4117 				this.options.put(
4118 					CompilerOptions.OPTION_ReportMissingJavadocTagsMethodTypeParameters,
4119 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4120 				if (isEnabling) {
4121 					this.options.put(
4122 							CompilerOptions.OPTION_DocCommentSupport,
4123 							CompilerOptions.ENABLED);
4124 					this.options.put(
4125 						CompilerOptions.OPTION_ReportMissingJavadocTagsVisibility,
4126 						CompilerOptions.PRIVATE);
4127 				}
4128 				return;
4129 			} else if (token.equals("missingJavadocTagsOverriding")) { //$NON-NLS-1$
4130 				this.options.put(
4131 					CompilerOptions.OPTION_ReportMissingJavadocTagsOverriding,
4132 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4133 				return;
4134 			} else if (token.equals("missingJavadocTagsMethod")) { //$NON-NLS-1$
4135 				this.options.put(
4136 					CompilerOptions.OPTION_ReportMissingJavadocTagsMethodTypeParameters,
4137 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4138 				return;
4139 			} else if (token.startsWith("missingJavadocTagsVisibility")) { //$NON-NLS-1$
4140 				int start = token.indexOf('(');
4141 				int end = token.indexOf(')');
4142 				String visibility = null;
4143 				if (isEnabling && start >= 0 && end >= 0 && start < end){
4144 					visibility = token.substring(start+1, end).trim();
4145 				}
4146 				if (visibility != null && visibility.equals(CompilerOptions.PUBLIC)
4147 						|| visibility.equals(CompilerOptions.PRIVATE)
4148 						|| visibility.equals(CompilerOptions.PROTECTED)
4149 						|| visibility.equals(CompilerOptions.DEFAULT)) {
4150 					this.options.put(
4151 							CompilerOptions.OPTION_ReportMissingJavadocTagsVisibility,
4152 							visibility);
4153 					return;
4154 				} else {
4155 					throw new IllegalArgumentException(this.bind("configure.missingJavadocTagsVisibility", token)); //$NON-NLS-1$
4156 				}
4157 			} else if (token.equals("missingJavadocComments")) { //$NON-NLS-1$
4158 				setSeverity(CompilerOptions.OPTION_ReportMissingJavadocComments, severity, isEnabling);
4159 				this.options.put(
4160 					CompilerOptions.OPTION_ReportMissingJavadocCommentsOverriding,
4161 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4162 				if (isEnabling) {
4163 					this.options.put(
4164 							CompilerOptions.OPTION_DocCommentSupport,
4165 							CompilerOptions.ENABLED);
4166 					this.options.put(
4167 						CompilerOptions.OPTION_ReportMissingJavadocCommentsVisibility,
4168 						CompilerOptions.PRIVATE);
4169 				}
4170 				return;
4171 			} else if (token.equals("missingJavadocCommentsOverriding")) { //$NON-NLS-1$
4172 				setSeverity(CompilerOptions.OPTION_ReportMissingJavadocComments, severity, isEnabling);
4173 				this.options.put(
4174 					CompilerOptions.OPTION_ReportMissingJavadocCommentsOverriding,
4175 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4176 				return;
4177 			} else if (token.startsWith("missingJavadocCommentsVisibility")) { //$NON-NLS-1$
4178 				int start = token.indexOf('(');
4179 				int end = token.indexOf(')');
4180 				String visibility = null;
4181 				if (isEnabling && start >= 0 && end >= 0 && start < end){
4182 					visibility = token.substring(start+1, end).trim();
4183 				}
4184 				if (visibility != null && visibility.equals(CompilerOptions.PUBLIC)
4185 						|| visibility.equals(CompilerOptions.PRIVATE)
4186 						|| visibility.equals(CompilerOptions.PROTECTED)
4187 						|| visibility.equals(CompilerOptions.DEFAULT)) {
4188 					this.options.put(
4189 							CompilerOptions.OPTION_ReportMissingJavadocCommentsVisibility,
4190 							visibility);
4191 					return;
4192 				} else {
4193 					throw new IllegalArgumentException(this.bind("configure.missingJavadocCommentsVisibility", token)); //$NON-NLS-1$
4194 				}
4195 			} else if (token.equals("module")) { //$NON-NLS-1$
4196 				setSeverity(CompilerOptions.OPTION_ReportUnstableAutoModuleName, severity, isEnabling);
4197 				return;
4198 			}
4199 			break;
4200 		case 'n' :
4201 			if (token.equals("nls")) { //$NON-NLS-1$
4202 				setSeverity(CompilerOptions.OPTION_ReportNonExternalizedStringLiteral, severity, isEnabling);
4203 				return;
4204 			} else if (token.equals("noEffectAssign")) { //$NON-NLS-1$
4205 				setSeverity(CompilerOptions.OPTION_ReportNoEffectAssignment, severity, isEnabling);
4206 				return;
4207 			} else if (/*token.equals("charConcat") ||*/ token.equals("noImplicitStringConversion")/*backward compatible*/) {//$NON-NLS-1$
4208 				setSeverity(CompilerOptions.OPTION_ReportNoImplicitStringConversion, severity, isEnabling);
4209 				return;
4210 			} else if (token.equals("null")) { //$NON-NLS-1$
4211 				setSeverity(CompilerOptions.OPTION_ReportNullReference, severity, isEnabling);
4212 				setSeverity(CompilerOptions.OPTION_ReportPotentialNullReference, severity, isEnabling);
4213 				setSeverity(CompilerOptions.OPTION_ReportRedundantNullCheck, severity, isEnabling);
4214 				return;
4215 			} else if (token.equals("nullDereference")) { //$NON-NLS-1$
4216 				setSeverity(CompilerOptions.OPTION_ReportNullReference, severity, isEnabling);
4217 				if (!isEnabling) {
4218 					setSeverity(CompilerOptions.OPTION_ReportPotentialNullReference, ProblemSeverities.Ignore, isEnabling);
4219 					setSeverity(CompilerOptions.OPTION_ReportRedundantNullCheck, ProblemSeverities.Ignore, isEnabling);
4220 				}
4221 				return;
4222 			}else if (token.equals("nullAnnotConflict")) { //$NON-NLS-1$
4223 				setSeverity(CompilerOptions.OPTION_ReportNullAnnotationInferenceConflict, severity, isEnabling);
4224 				return;
4225 			} else if (token.equals("nullAnnotRedundant")) { //$NON-NLS-1$
4226 				setSeverity(CompilerOptions.OPTION_ReportRedundantNullAnnotation, severity, isEnabling);
4227 				return;
4228 			} else if (token.startsWith("nullAnnot")) { //$NON-NLS-1$
4229 				String annotationNames = Util.EMPTY_STRING;
4230 				int start = token.indexOf('(');
4231 				int end = token.indexOf(')');
4232 				String nonNullAnnotName = null, nullableAnnotName = null, nonNullByDefaultAnnotName = null;
4233 				if (isEnabling && start >= 0 && end >= 0 && start < end){
4234 					boolean isPrimarySet = !this.primaryNullAnnotationsSeen;
4235 					annotationNames = token.substring(start+1, end).trim();
4236 					int separator1 = annotationNames.indexOf('|');
4237 					if (separator1 == -1) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$
4238 					nullableAnnotName = annotationNames.substring(0, separator1).trim();
4239 					if (isPrimarySet && nullableAnnotName.length() == 0) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$
4240 					int separator2 = annotationNames.indexOf('|', separator1 + 1);
4241 					if (separator2 == -1) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$
4242 					nonNullAnnotName = annotationNames.substring(separator1 + 1, separator2).trim();
4243 					if (isPrimarySet && nonNullAnnotName.length() == 0) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$
4244 					nonNullByDefaultAnnotName = annotationNames.substring(separator2 + 1).trim();
4245 					if (isPrimarySet && nonNullByDefaultAnnotName.length() == 0) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$
4246 					if (isPrimarySet) {
4247 						this.primaryNullAnnotationsSeen = true;
4248 						this.options.put(CompilerOptions.OPTION_NullableAnnotationName, nullableAnnotName);
4249 						this.options.put(CompilerOptions.OPTION_NonNullAnnotationName, nonNullAnnotName);
4250 						this.options.put(CompilerOptions.OPTION_NonNullByDefaultAnnotationName, nonNullByDefaultAnnotName);
4251 					} else {
4252 						if (nullableAnnotName.length() > 0) {
4253 							String nullableList = this.options.get(CompilerOptions.OPTION_NullableAnnotationSecondaryNames);
4254 							nullableList = nullableList.isEmpty() ? nullableAnnotName : nullableList + ',' + nullableAnnotName;
4255 							this.options.put(CompilerOptions.OPTION_NullableAnnotationSecondaryNames, nullableList);
4256 						}
4257 						if (nonNullAnnotName.length() > 0) {
4258 							String nonnullList = this.options.get(CompilerOptions.OPTION_NonNullAnnotationSecondaryNames);
4259 							nonnullList = nonnullList.isEmpty() ? nonNullAnnotName : nonnullList + ',' + nonNullAnnotName;
4260 							this.options.put(CompilerOptions.OPTION_NonNullAnnotationSecondaryNames, nonnullList);
4261 						}
4262 						if (nonNullByDefaultAnnotName.length() > 0) {
4263 							String nnbdList = this.options.get(CompilerOptions.OPTION_NonNullByDefaultAnnotationSecondaryNames);
4264 							nnbdList = nnbdList.isEmpty() ? nonNullByDefaultAnnotName : nnbdList + ',' + nonNullByDefaultAnnotName;
4265 							this.options.put(CompilerOptions.OPTION_NonNullByDefaultAnnotationSecondaryNames, nnbdList);
4266 						}
4267 					}
4268 				}
4269 				this.options.put(
4270 						CompilerOptions.OPTION_AnnotationBasedNullAnalysis,
4271 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4272 				setSeverity(CompilerOptions.OPTION_ReportNullSpecViolation, severity, isEnabling);
4273 				setSeverity(CompilerOptions.OPTION_ReportNullAnnotationInferenceConflict, severity, isEnabling);
4274 				setSeverity(CompilerOptions.OPTION_ReportNullUncheckedConversion, severity, isEnabling);
4275 				setSeverity(CompilerOptions.OPTION_ReportRedundantNullAnnotation, severity, isEnabling);
4276 				return;
4277 			} else if (token.equals("nullUncheckedConversion")) { //$NON-NLS-1$
4278 				setSeverity(CompilerOptions.OPTION_ReportNullUncheckedConversion, severity, isEnabling);
4279 				return;
4280 			} else if (token.equals("nonnullNotRepeated")) { //$NON-NLS-1$
4281 				setSeverity(CompilerOptions.OPTION_ReportNonnullParameterAnnotationDropped, severity, isEnabling);
4282 				return;
4283 			}
4284 
4285 			break;
4286 		case 'o' :
4287 			if (token.equals("over-sync") /*|| token.equals("syncOverride")*/) { //$NON-NLS-1$
4288 				setSeverity(CompilerOptions.OPTION_ReportMissingSynchronizedOnInheritedMethod, severity, isEnabling);
4289 				return;
4290 			} else if (token.equals("over-ann")) { //$NON-NLS-1$
4291 				setSeverity(CompilerOptions.OPTION_ReportMissingOverrideAnnotation, severity, isEnabling);
4292 				this.options.put(
4293 					CompilerOptions.OPTION_ReportMissingOverrideAnnotationForInterfaceMethodImplementation,
4294 					CompilerOptions.DISABLED);
4295 				return;
4296 			}
4297 			break;
4298 		case 'p' :
4299 			if (token.equals("pkgDefaultMethod") || token.equals("packageDefaultMethod")/*backward compatible*/ ) { //$NON-NLS-1$ //$NON-NLS-2$
4300 				setSeverity(CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod, severity, isEnabling);
4301 				return;
4302 			} else if (token.equals("paramAssign")) { //$NON-NLS-1$
4303 				setSeverity(CompilerOptions.OPTION_ReportParameterAssignment, severity, isEnabling);
4304 				return;
4305 			}
4306 			break;
4307 		case 'r' :
4308 			if (token.equals("raw")) {//$NON-NLS-1$
4309 				setSeverity(CompilerOptions.OPTION_ReportRawTypeReference, severity, isEnabling);
4310 				return;
4311 			} else if (/*token.equals("intfRedundant") ||*/ token.equals("redundantSuperinterface")) { //$NON-NLS-1$
4312 				setSeverity(CompilerOptions.OPTION_ReportRedundantSuperinterface, severity, isEnabling);
4313 				return;
4314 			} else if (token.equals("resource")) { //$NON-NLS-1$
4315 				setSeverity(CompilerOptions.OPTION_ReportUnclosedCloseable, severity, isEnabling);
4316 				setSeverity(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, severity, isEnabling);
4317 				setSeverity(CompilerOptions.OPTION_ReportExplicitlyClosedAutoCloseable, severity, isEnabling);
4318 				return;
4319 			} else if (token.equals("removal")) { //$NON-NLS-1$
4320 				setSeverity(CompilerOptions.OPTION_ReportTerminalDeprecation, severity, isEnabling);
4321 				this.options.put(
4322 					CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode,
4323 					CompilerOptions.DISABLED);
4324 				this.options.put(
4325 					CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod,
4326 					CompilerOptions.DISABLED);
4327 				return;
4328 			}
4329 			break;
4330 		case 's' :
4331 			if (token.equals("specialParamHiding")) { //$NON-NLS-1$
4332 				this.options.put(
4333 					CompilerOptions.OPTION_ReportSpecialParameterHidingField,
4334 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4335 				return;
4336 			} else if (token.equals("syntheticAccess") || token.equals("synthetic-access")) { //$NON-NLS-1$ //$NON-NLS-2$
4337 				setSeverity(CompilerOptions.OPTION_ReportSyntheticAccessEmulation, severity, isEnabling);
4338 				return;
4339 			} else if (token.equals("staticReceiver")) { //$NON-NLS-1$
4340 				setSeverity(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, severity, isEnabling);
4341 				return;
4342 			} else 	if (/*token.equals("over-sync") ||*/ token.equals("syncOverride")) { //$NON-NLS-1$
4343 				setSeverity(CompilerOptions.OPTION_ReportMissingSynchronizedOnInheritedMethod, severity, isEnabling);
4344 				return;
4345 			} else if (token.equals("semicolon")) {//$NON-NLS-1$
4346 				setSeverity(CompilerOptions.OPTION_ReportEmptyStatement, severity, isEnabling);
4347 				return;
4348 			} else if (token.equals("serial")) {//$NON-NLS-1$
4349 				setSeverity(CompilerOptions.OPTION_ReportMissingSerialVersion, severity, isEnabling);
4350 				return;
4351 			} else if (token.equals("suppress")) {//$NON-NLS-1$
4352 				switch(severity) {
4353 					case ProblemSeverities.Warning :
4354 						this.options.put(
4355 								CompilerOptions.OPTION_SuppressWarnings,
4356 								isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4357 						this.options.put(
4358 								CompilerOptions.OPTION_SuppressOptionalErrors,
4359 								CompilerOptions.DISABLED);
4360 						break;
4361 					case ProblemSeverities.Error :
4362 						this.options.put(
4363 								CompilerOptions.OPTION_SuppressWarnings,
4364 								isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4365 						this.options.put(
4366 							CompilerOptions.OPTION_SuppressOptionalErrors,
4367 							isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4368 				}
4369 				return;
4370 			} else if (token.equals("static-access")) { //$NON-NLS-1$
4371 				setSeverity(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, severity, isEnabling);
4372 				setSeverity(CompilerOptions.OPTION_ReportIndirectStaticAccess, severity, isEnabling);
4373 				return;
4374 			} else if (token.equals("super")) { //$NON-NLS-1$
4375 				setSeverity(CompilerOptions.OPTION_ReportOverridingMethodWithoutSuperInvocation, severity, isEnabling);
4376 				return;
4377 			} else if (token.equals("static-method")) { //$NON-NLS-1$
4378 				setSeverity(CompilerOptions.OPTION_ReportMethodCanBeStatic, severity, isEnabling);
4379 				return;
4380 			} else if (token.equals("switchDefault")) { //$NON-NLS-1$
4381 				setSeverity(CompilerOptions.OPTION_ReportMissingDefaultCase, severity, isEnabling);
4382 				return;
4383 			} else if (token.equals("syntacticAnalysis")) { //$NON-NLS-1$
4384 				this.options.put(
4385 						CompilerOptions.OPTION_SyntacticNullAnalysisForFields,
4386 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4387 				return;
4388 			}
4389 			break;
4390 		case 't' :
4391 			if (token.startsWith("tasks")) { //$NON-NLS-1$
4392 				String taskTags = Util.EMPTY_STRING;
4393 				int start = token.indexOf('(');
4394 				int end = token.indexOf(')');
4395 				if (start >= 0 && end >= 0 && start < end){
4396 					taskTags = token.substring(start+1, end).trim();
4397 					taskTags = taskTags.replace('|',',');
4398 				}
4399 				if (taskTags.length() == 0){
4400 					throw new IllegalArgumentException(this.bind("configure.invalidTaskTag", token)); //$NON-NLS-1$
4401 				}
4402 				this.options.put(
4403 					CompilerOptions.OPTION_TaskTags,
4404 					isEnabling ? taskTags : Util.EMPTY_STRING);
4405 
4406 				setSeverity(CompilerOptions.OPTION_ReportTasks, severity, isEnabling);
4407 				return;
4408 			} else if (token.equals("typeHiding")) { //$NON-NLS-1$
4409 				setSeverity(CompilerOptions.OPTION_ReportTypeParameterHiding, severity, isEnabling);
4410 				return;
4411 			}
4412 			break;
4413 		case 'u' :
4414 			if (token.equals("unusedLocal") || token.equals("unusedLocals")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$
4415 				setSeverity(CompilerOptions.OPTION_ReportUnusedLocal, severity, isEnabling);
4416 				return;
4417 			} else if (token.equals("unusedArgument") || token.equals("unusedArguments")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$
4418 				setSeverity(CompilerOptions.OPTION_ReportUnusedParameter, severity, isEnabling);
4419 				return;
4420 			} else if (token.equals("unusedExceptionParam")) { //$NON-NLS-1$
4421 				setSeverity(CompilerOptions.OPTION_ReportUnusedExceptionParameter, severity, isEnabling);
4422 				return;
4423 			} else if (token.equals("unusedImport") || token.equals("unusedImports")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$
4424 				setSeverity(CompilerOptions.OPTION_ReportUnusedImport, severity, isEnabling);
4425 				return;
4426 			} else if (token.equals("unusedAllocation")) { //$NON-NLS-1$
4427 				setSeverity(CompilerOptions.OPTION_ReportUnusedObjectAllocation, severity, isEnabling);
4428 				return;
4429 			} else if (token.equals("unusedPrivate")) { //$NON-NLS-1$
4430 				setSeverity(CompilerOptions.OPTION_ReportUnusedPrivateMember, severity, isEnabling);
4431 				return;
4432 			} else if (token.equals("unusedLabel")) { //$NON-NLS-1$
4433 				setSeverity(CompilerOptions.OPTION_ReportUnusedLabel, severity, isEnabling);
4434 				return;
4435 			} else if (token.equals("uselessTypeCheck")) {//$NON-NLS-1$
4436 				setSeverity(CompilerOptions.OPTION_ReportUnnecessaryTypeCheck, severity, isEnabling);
4437 				return;
4438 			} else if (token.equals("unchecked") || token.equals("unsafe")) {//$NON-NLS-1$ //$NON-NLS-2$
4439 				setSeverity(CompilerOptions.OPTION_ReportUncheckedTypeOperation, severity, isEnabling);
4440 				return;
4441 			} else if (token.equals("unlikelyCollectionMethodArgumentType")) { //$NON-NLS-1$
4442 				setSeverity(CompilerOptions.OPTION_ReportUnlikelyCollectionMethodArgumentType, severity, isEnabling);
4443 				return;
4444 			} else if (token.equals("unlikelyEqualsArgumentType")) { //$NON-NLS-1$
4445 				setSeverity(CompilerOptions.OPTION_ReportUnlikelyEqualsArgumentType, severity, isEnabling);
4446 				return;
4447 			} else if (token.equals("unnecessaryElse")) {//$NON-NLS-1$
4448 				setSeverity(CompilerOptions.OPTION_ReportUnnecessaryElse, severity, isEnabling);
4449 				return;
4450 			} else if (token.equals("unusedThrown")) { //$NON-NLS-1$
4451 				setSeverity(CompilerOptions.OPTION_ReportUnusedDeclaredThrownException, severity, isEnabling);
4452 				return;
4453 			} else if (token.equals("unusedThrownWhenOverriding")) { //$NON-NLS-1$
4454 				this.options.put(
4455 						CompilerOptions.OPTION_ReportUnusedDeclaredThrownExceptionWhenOverriding,
4456 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4457 				return;
4458 			} else if (token.equals("unusedThrownIncludeDocComment")) { //$NON-NLS-1$
4459 				this.options.put(
4460 						CompilerOptions.OPTION_ReportUnusedDeclaredThrownExceptionIncludeDocCommentReference,
4461 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4462 				return;
4463 			} else if (token.equals("unusedThrownExemptExceptionThrowable")) { //$NON-NLS-1$
4464 				this.options.put(
4465 						CompilerOptions.OPTION_ReportUnusedDeclaredThrownExceptionExemptExceptionAndThrowable,
4466 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4467 				return;
4468 			} else if (token.equals("unqualifiedField") || token.equals("unqualified-field-access")) { //$NON-NLS-1$ //$NON-NLS-2$
4469 				setSeverity(CompilerOptions.OPTION_ReportUnqualifiedFieldAccess, severity, isEnabling);
4470 				return;
4471 			} else if (token.equals("unused")) { //$NON-NLS-1$
4472 				setSeverity(CompilerOptions.OPTION_ReportDeadCode, severity, isEnabling);
4473 				setSeverity(CompilerOptions.OPTION_ReportRedundantSuperinterface, severity, isEnabling);
4474 				setSeverity(CompilerOptions.OPTION_ReportRedundantSpecificationOfTypeArguments, severity, isEnabling);
4475 				setSeverity(CompilerOptions.OPTION_ReportUnusedDeclaredThrownException, severity, isEnabling);
4476 				setSeverity(CompilerOptions.OPTION_ReportUnusedExceptionParameter, severity, isEnabling);
4477 				setSeverity(CompilerOptions.OPTION_ReportUnusedImport, severity, isEnabling);
4478 				setSeverity(CompilerOptions.OPTION_ReportUnusedLabel, severity, isEnabling);
4479 				setSeverity(CompilerOptions.OPTION_ReportUnusedLocal, severity, isEnabling);
4480 				setSeverity(CompilerOptions.OPTION_ReportUnusedObjectAllocation, severity,isEnabling);
4481 				setSeverity(CompilerOptions.OPTION_ReportUnusedParameter, severity, isEnabling);
4482 				setSeverity(CompilerOptions.OPTION_ReportUnusedPrivateMember, severity, isEnabling);
4483 				setSeverity(CompilerOptions.OPTION_ReportUnusedTypeArgumentsForMethodInvocation, severity, isEnabling);
4484 				setSeverity(CompilerOptions.OPTION_ReportUnusedTypeParameter, severity,isEnabling);
4485 				return;
4486 			} else if (token.equals("unusedParam")) { //$NON-NLS-1$
4487 				setSeverity(CompilerOptions.OPTION_ReportUnusedParameter, severity, isEnabling);
4488 				return;
4489 			} else if (token.equals("unusedTypeParameter")) { //$NON-NLS-1$
4490 				setSeverity(CompilerOptions.OPTION_ReportUnusedTypeParameter, severity, isEnabling);
4491 				return;
4492 			} else if (token.equals("unusedParamIncludeDoc")) { //$NON-NLS-1$
4493 				this.options.put(
4494 						CompilerOptions.OPTION_ReportUnusedParameterIncludeDocCommentReference,
4495 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4496 				return;
4497 			} else if (token.equals("unusedParamOverriding")) { //$NON-NLS-1$
4498 				this.options.put(
4499 						CompilerOptions.OPTION_ReportUnusedParameterWhenOverridingConcrete,
4500 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4501 				return;
4502 			} else if (token.equals("unusedParamImplementing")) { //$NON-NLS-1$
4503 				this.options.put(
4504 						CompilerOptions.OPTION_ReportUnusedParameterWhenImplementingAbstract,
4505 						isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4506 				return;
4507 			}  else if (token.equals("unusedTypeArgs")) { //$NON-NLS-1$
4508 				setSeverity(CompilerOptions.OPTION_ReportUnusedTypeArgumentsForMethodInvocation, severity, isEnabling);
4509 				setSeverity(CompilerOptions.OPTION_ReportRedundantSpecificationOfTypeArguments, severity, isEnabling);
4510 				return;
4511 			} else if (token.equals("unavoidableGenericProblems")) { //$NON-NLS-1$
4512 				this.options.put(
4513 					CompilerOptions.OPTION_ReportUnavoidableGenericTypeProblems,
4514 					isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
4515 				return;
4516 			}
4517 			break;
4518 		case 'v' :
4519 			if (token.equals("varargsCast")) { //$NON-NLS-1$
4520 				setSeverity(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, severity, isEnabling);
4521 				return;
4522 			}
4523 			break;
4524 		case 'w' :
4525 			if (token.equals("warningToken")) {//$NON-NLS-1$
4526 				setSeverity(CompilerOptions.OPTION_ReportUnhandledWarningToken, severity, isEnabling);
4527 				setSeverity(CompilerOptions.OPTION_ReportUnusedWarningToken, severity, isEnabling);
4528 				return;
4529 			}
4530 			break;
4531 	}
4532 	String message = null;
4533 	switch(severity) {
4534 		case ProblemSeverities.Info:
4535 			message = this.bind("configure.invalidInfo", token); //$NON-NLS-1$
4536 			break;
4537 		case ProblemSeverities.Warning :
4538 			message = this.bind("configure.invalidWarning", token); //$NON-NLS-1$
4539 			break;
4540 		case ProblemSeverities.Error :
4541 			message = this.bind("configure.invalidError", token); //$NON-NLS-1$
4542 	}
4543 	addPendingErrors(message);
4544 }
4545 /**
4546  * @deprecated - use {@link #initialize(PrintWriter, PrintWriter, boolean, Map, CompilationProgress)} instead
4547  *                       e.g. initialize(outWriter, errWriter, systemExit, null, null)
4548  */
4549 protected void initialize(PrintWriter outWriter, PrintWriter errWriter, boolean systemExit) {
4550 	this.initialize(outWriter, errWriter, systemExit, null /* options */, null /* progress */);
4551 }
4552 /**
4553  * @deprecated - use {@link #initialize(PrintWriter, PrintWriter, boolean, Map, CompilationProgress)} instead
4554  *                       e.g. initialize(outWriter, errWriter, systemExit, customDefaultOptions, null)
4555  */
4556 protected void initialize(PrintWriter outWriter, PrintWriter errWriter, boolean systemExit, Map<String, String> customDefaultOptions) {
4557 	this.initialize(outWriter, errWriter, systemExit, customDefaultOptions, null /* progress */);
4558 }
4559 protected void initialize(PrintWriter outWriter, PrintWriter errWriter, boolean systemExit, Map<String, String> customDefaultOptions, CompilationProgress compilationProgress) {
4560 	this.logger = new Logger(this, outWriter, errWriter);
4561 	this.proceed = true;
4562 	this.out = outWriter;
4563 	this.err = errWriter;
4564 	this.systemExitWhenFinished = systemExit;
4565 	this.options = new CompilerOptions().getMap();
4566 	this.ignoreOptionalProblemsFromFolders = null;
4567 
4568 	this.progress = compilationProgress;
4569 	if (customDefaultOptions != null) {
4570 		this.didSpecifySource = customDefaultOptions.get(CompilerOptions.OPTION_Source) != null;
4571 		this.didSpecifyTarget = customDefaultOptions.get(CompilerOptions.OPTION_TargetPlatform) != null;
4572 		for (Iterator<Map.Entry<String, String>> iter = customDefaultOptions.entrySet().iterator(); iter.hasNext();) {
4573 			Map.Entry<String, String> entry = iter.next();
4574 			this.options.put(entry.getKey(), entry.getValue());
4575 		}
4576 	} else {
4577 		this.didSpecifySource = false;
4578 		this.didSpecifyTarget = false;
4579 	}
4580 	this.classNames = null;
4581 }
4582 protected void initializeAnnotationProcessorManager() {
4583 	String className = "org.eclipse.jdt.internal.compiler.apt.dispatch.BatchAnnotationProcessorManager"; //$NON-NLS-1$
4584 	try {
4585 		Class<?> c = Class.forName(className);
4586 		AbstractAnnotationProcessorManager annotationManager = (AbstractAnnotationProcessorManager) c.newInstance();
4587 		annotationManager.configure(this, this.expandedCommandLine);
4588 		annotationManager.setErr(this.err);
4589 		annotationManager.setOut(this.out);
4590 		this.batchCompiler.annotationProcessorManager = annotationManager;
4591 	} catch (ClassNotFoundException | InstantiationException e) {
4592 		this.logger.logUnavaibleAPT(className);
4593 		throw new org.eclipse.jdt.internal.compiler.problem.AbortCompilation();
4594 	} catch (IllegalAccessException e) {
4595 		// should not happen
4596 		throw new org.eclipse.jdt.internal.compiler.problem.AbortCompilation();
4597 	} catch(UnsupportedClassVersionError e) {
4598 		// report a warning
4599 		this.logger.logIncorrectVMVersionForAnnotationProcessing();
4600 	}
4601 }
4602 private static boolean isParentOf(char[] folderName, char[] fileName) {
4603 	if (folderName.length >= fileName.length) {
4604 		return false;
4605 	}
4606 	if (fileName[folderName.length] != '\\' && fileName[folderName.length] != '/') {
4607 		return false;
4608 	}
4609 	for (int i = folderName.length - 1; i >= 0; i--) {
4610 		if (folderName[i] != fileName[i]) {
4611 			return false;
4612 		}
4613 	}
4614 	return true;
4615 }
4616 // Dump classfiles onto disk for all compilation units that where successful
4617 // and do not carry a -d none spec, either directly or inherited from Main.
4618 public void outputClassFiles(CompilationResult unitResult) {
4619 	if (!((unitResult == null) || (unitResult.hasErrors() && !this.proceedOnError))) {
4620 		ClassFile[] classFiles = unitResult.getClassFiles();
4621 		String currentDestinationPath = null;
4622 		boolean generateClasspathStructure = false;
4623 		CompilationUnit compilationUnit =
4624 			(CompilationUnit) unitResult.compilationUnit;
4625 		if (compilationUnit.destinationPath == null) {
4626 			if (this.destinationPath == null) {
4627 				currentDestinationPath =
4628 					extractDestinationPathFromSourceFile(unitResult);
4629 			} else if (this.destinationPath != NONE) {
4630 				currentDestinationPath = this.destinationPath;
4631 				generateClasspathStructure = true;
4632 			} // else leave currentDestinationPath null
4633 		} else if (compilationUnit.destinationPath != NONE) {
4634 			currentDestinationPath = compilationUnit.destinationPath;
4635 			generateClasspathStructure = true;
4636 		} // else leave currentDestinationPath null
4637 		if (currentDestinationPath != null) {
4638 			for (int i = 0, fileCount = classFiles.length; i < fileCount; i++) {
4639 				// retrieve the key and the corresponding classfile
4640 				ClassFile classFile = classFiles[i];
4641 				char[] filename = classFile.fileName();
4642 				int length = filename.length;
4643 				char[] relativeName = new char[length + 6];
4644 				System.arraycopy(filename, 0, relativeName, 0, length);
4645 				System.arraycopy(SuffixConstants.SUFFIX_class, 0, relativeName, length, 6);
4646 				CharOperation.replace(relativeName, '/', File.separatorChar);
4647 				String relativeStringName = new String(relativeName);
4648 				try {
4649 					if (this.compilerOptions.verbose)
4650 						this.out.println(
4651 							Messages.bind(
4652 								Messages.compilation_write,
4653 								new String[] {
4654 									String.valueOf(this.exportedClassFilesCounter+1),
4655 									relativeStringName
4656 								}));
4657 					Util.writeToDisk(
4658 						generateClasspathStructure,
4659 						currentDestinationPath,
4660 						relativeStringName,
4661 						classFile);
4662 					this.logger.logClassFile(
4663 						generateClasspathStructure,
4664 						currentDestinationPath,
4665 						relativeStringName);
4666 					this.exportedClassFilesCounter++;
4667 				} catch (IOException e) {
4668 					this.logger.logNoClassFileCreated(currentDestinationPath, relativeStringName, e);
4669 				}
4670 			}
4671 			this.batchCompiler.lookupEnvironment.releaseClassFiles(classFiles);
4672 		}
4673 	}
4674 }
4675 /*
4676  *  Low-level API performing the actual compilation
4677  */
4678 public void performCompilation() {
4679 	this.startTime = System.currentTimeMillis();
4680 
4681 	FileSystem environment = getLibraryAccess();
4682 	try {
4683 		this.compilerOptions = new CompilerOptions(this.options);
4684 		this.compilerOptions.performMethodsFullRecovery = false;
4685 		this.compilerOptions.performStatementsRecovery = false;
4686 		this.batchCompiler =
4687 				new Compiler(
4688 						environment,
4689 						getHandlingPolicy(),
4690 						this.compilerOptions,
4691 						getBatchRequestor(),
4692 						getProblemFactory(),
4693 						this.out,
4694 						this.progress);
4695 		this.batchCompiler.remainingIterations = this.maxRepetition-this.currentRepetition/*remaining iterations including this one*/;
4696 		// temporary code to allow the compiler to revert to a single thread
4697 		String setting = System.getProperty("jdt.compiler.useSingleThread"); //$NON-NLS-1$
4698 		this.batchCompiler.useSingleThread = setting != null && setting.equals("true"); //$NON-NLS-1$
4699 
4700 		if (this.compilerOptions.complianceLevel >= ClassFileConstants.JDK1_6
4701 				&& this.compilerOptions.processAnnotations) {
4702 			if (checkVMVersion(ClassFileConstants.JDK1_6)) {
4703 				initializeAnnotationProcessorManager();
4704 				if (this.classNames != null) {
4705 					this.batchCompiler.setBinaryTypes(processClassNames(this.batchCompiler.lookupEnvironment));
4706 				}
4707 			} else {
4708 				// report a warning
4709 				this.logger.logIncorrectVMVersionForAnnotationProcessing();
4710 			}
4711 			if (checkVMVersion(ClassFileConstants.JDK9)) {
4712 				initRootModules(this.batchCompiler.lookupEnvironment, environment);
4713 			}
4714 		}
4715 
4716 		// set the non-externally configurable options.
4717 		this.compilerOptions.verbose = this.verbose;
4718 		this.compilerOptions.produceReferenceInfo = this.produceRefInfo;
4719 		try {
4720 			this.logger.startLoggingSources();
4721 			this.batchCompiler.compile(getCompilationUnits());
4722 		} finally {
4723 			this.logger.endLoggingSources();
4724 		}
4725 
4726 		if (this.extraProblems != null) {
4727 			loggingExtraProblems();
4728 			this.extraProblems = null;
4729 		}
4730 		if (this.compilerStats != null) {
4731 			this.compilerStats[this.currentRepetition] = this.batchCompiler.stats;
4732 		}
4733 		this.logger.printStats();
4734 	}
4735 	finally {
4736 	// cleanup
4737 		environment.cleanup();
4738 	}
4739 }
4740 protected void loggingExtraProblems() {
4741 	this.logger.loggingExtraProblems(this);
4742 }
4743 public void printUsage() {
4744 	printUsage("misc.usage"); //$NON-NLS-1$
4745 }
4746 private void printUsage(String sectionID) {
4747 	this.logger.logUsage(
4748 		this.bind(
4749 			sectionID,
4750 			new String[] {
4751 				System.getProperty("path.separator"), //$NON-NLS-1$
4752 				this.bind("compiler.name"), //$NON-NLS-1$
4753 				this.bind("compiler.version"), //$NON-NLS-1$
4754 				this.bind("compiler.copyright") //$NON-NLS-1$
4755 			}));
4756 	this.logger.flush();
4757 }
4758 private void initRootModules(LookupEnvironment environment, FileSystem fileSystem) {
4759 	Map<String, String> map = new HashMap<>();
4760 	for (String m : this.rootModules) {
4761 		ModuleBinding mod = environment.getModule(m.toCharArray());
4762 		if (mod == null) {
4763 			throw new IllegalArgumentException(this.bind("configure.invalidModuleName", m)); //$NON-NLS-1$
4764 		}
4765 		PackageBinding[] exports = mod.getExports();
4766 		for (PackageBinding packageBinding : exports) {
4767 			String qName = CharOperation.toString(packageBinding.compoundName);
4768 			String existing = map.get(qName);
4769 			if (existing != null) {
4770 				throw new IllegalArgumentException(this.bind("configure.packageConflict", new String[] {qName, existing, m})); //$NON-NLS-1$
4771 				// report an error and bail out
4772 			}
4773 			map.put(qName, m);
4774 		}
4775 	}
4776 	if (this.limitedModules != null) {
4777 		for (String m : this.limitedModules) {
4778 			ModuleBinding mod = environment.getModule(m.toCharArray());
4779 			if (mod == null) {
4780 				throw new IllegalArgumentException(this.bind("configure.invalidModuleName", m)); //$NON-NLS-1$
4781 			}
4782 		}
4783 	}
4784 	environment.moduleVersion = this.moduleVersion;
4785 }
4786 private ReferenceBinding[] processClassNames(LookupEnvironment environment) {
4787 	// check for .class file presence in case of apt processing
4788 	int length = this.classNames.length;
4789 	ReferenceBinding[] referenceBindings = new ReferenceBinding[length];
4790 	ModuleBinding[] modules = new ModuleBinding[length];
4791 	Set<ModuleBinding> modSet = new HashSet<>();
4792 	String[] typeNames = new String[length];
4793 	if (this.complianceLevel <= ClassFileConstants.JDK1_8) {
4794 		typeNames = this.classNames;
4795 	} else {
4796 		for (int i = 0; i < length; i++) {
4797 			String currentName = this.classNames[i];
4798 			int idx = currentName.indexOf('/');
4799 			ModuleBinding mod = null;
4800 			if (idx > 0) {
4801 				String m = currentName.substring(0, idx);
4802 				mod = environment.getModule(m.toCharArray());
4803 				if (mod == null) {
4804 					throw new IllegalArgumentException(this.bind("configure.invalidModuleName", m)); //$NON-NLS-1$
4805 				}
4806 				modules[i] = mod;
4807 				modSet.add(mod);
4808 				currentName = currentName.substring(idx + 1);
4809 			}
4810 			typeNames[i] = currentName;
4811 		}
4812 	}
4813 
4814 	for (int i = 0; i < length; i++) {
4815 		char[][] compoundName = null;
4816 		String cls = typeNames[i];
4817 		if (cls.indexOf('.') != -1) {
4818 			// consider names with '.' as fully qualified names
4819 			char[] typeName = cls.toCharArray();
4820 			compoundName = CharOperation.splitOn('.', typeName);
4821 		} else {
4822 			compoundName = new char[][] { cls.toCharArray() };
4823 		}
4824 		ModuleBinding mod = modules[i];
4825 		ReferenceBinding type = mod != null ? environment.getType(compoundName, mod) : environment.getType(compoundName);
4826 		if (type != null && type.isValidBinding()) {
4827 			if (type.isBinaryBinding()) {
4828 				referenceBindings[i] = type;
4829 				type.superclass();
4830 			}
4831 		} else {
4832 			throw new IllegalArgumentException(
4833 					this.bind("configure.invalidClassName", this.classNames[i]));//$NON-NLS-1$
4834 		}
4835 	}
4836 	return referenceBindings;
4837 }
4838 private ArrayList<String> processModulePathEntries(String arg) {
4839 	ArrayList<String> paths = new ArrayList<>();
4840 	if (arg == null)
4841 		return paths;
4842 	StringTokenizer tokenizer = new StringTokenizer(arg, File.pathSeparator, false);
4843 	while (tokenizer.hasMoreTokens()) {
4844 		paths.add(tokenizer.nextToken());
4845 	}
4846 	return paths;
4847 }
4848 /*
4849  * External API
4850  */
4851 public void processPathEntries(final int defaultSize, final ArrayList<FileSystem.Classpath> paths,
4852 			final String currentPath, String customEncoding, boolean isSourceOnly,
4853 			boolean rejectDestinationPathOnJars) {
4854 	String currentClasspathName = null;
4855 	String currentDestinationPath = null;
4856 	ArrayList<String> currentRuleSpecs = new ArrayList<>(defaultSize);
4857 	StringTokenizer tokenizer = new StringTokenizer(currentPath,
4858 			File.pathSeparator + "[]", true); //$NON-NLS-1$
4859 	ArrayList<String> tokens = new ArrayList<>();
4860 	while (tokenizer.hasMoreTokens()) {
4861 		tokens.add(tokenizer.nextToken());
4862 	}
4863 	// state machine
4864 	final int start = 0;
4865 	final int readyToClose = 1;
4866 	// 'path' 'path1[rule];path2'
4867 	final int readyToCloseEndingWithRules = 2;
4868 	// 'path[rule]' 'path1;path2[rule]'
4869 	final int readyToCloseOrOtherEntry = 3;
4870 	// 'path[rule];' 'path;' 'path1;path2;'
4871 	final int rulesNeedAnotherRule = 4;
4872 	// 'path[rule1;'
4873 	final int rulesStart = 5;
4874 	// 'path[' 'path1;path2['
4875 	final int rulesReadyToClose = 6;
4876 	// 'path[rule' 'path[rule1;rule2'
4877 	final int destinationPathReadyToClose = 7;
4878 	// 'path[-d bin'
4879 	final int readyToCloseEndingWithDestinationPath = 8;
4880 	// 'path[-d bin]' 'path[rule][-d bin]'
4881 	final int destinationPathStart = 9;
4882 	// 'path[rule]['
4883 	final int bracketOpened = 10;
4884 	// '.*[.*'
4885 	final int bracketClosed = 11;
4886 	// '.*([.*])+'
4887 
4888 	final int error = 99;
4889 	int state = start;
4890 	String token = null;
4891 	int cursor = 0, tokensNb = tokens.size(), bracket = -1;
4892 	while (cursor < tokensNb && state != error) {
4893 		token = tokens.get(cursor++);
4894 		if (token.equals(File.pathSeparator)) {
4895 			switch (state) {
4896 			case start:
4897 			case readyToCloseOrOtherEntry:
4898 			case bracketOpened:
4899 				break;
4900 			case readyToClose:
4901 			case readyToCloseEndingWithRules:
4902 			case readyToCloseEndingWithDestinationPath:
4903 				state = readyToCloseOrOtherEntry;
4904 				addNewEntry(paths, currentClasspathName, currentRuleSpecs,
4905 						customEncoding, currentDestinationPath, isSourceOnly,
4906 						rejectDestinationPathOnJars);
4907 				currentRuleSpecs.clear();
4908 				break;
4909 			case rulesReadyToClose:
4910 				state = rulesNeedAnotherRule;
4911 				break;
4912 			case destinationPathReadyToClose:
4913 				throw new IllegalArgumentException(
4914 					this.bind("configure.incorrectDestinationPathEntry", //$NON-NLS-1$
4915 						currentPath));
4916 			case bracketClosed:
4917 				cursor = bracket + 1;
4918 				state = rulesStart;
4919 				break;
4920 			default:
4921 				state = error;
4922 			}
4923 		} else if (token.equals("[")) { //$NON-NLS-1$
4924 			switch (state) {
4925 			case start:
4926 				currentClasspathName = ""; //$NON-NLS-1$
4927 				//$FALL-THROUGH$
4928 				case readyToClose:
4929 				bracket = cursor - 1;
4930 				//$FALL-THROUGH$
4931 				case bracketClosed:
4932 				state = bracketOpened;
4933 				break;
4934 			case readyToCloseEndingWithRules:
4935 				state = destinationPathStart;
4936 				break;
4937 			case readyToCloseEndingWithDestinationPath:
4938 				state = rulesStart;
4939 				break;
4940 			case bracketOpened:
4941 			default:
4942 				state = error;
4943 			}
4944 		} else if (token.equals("]")) { //$NON-NLS-1$
4945 			switch (state) {
4946 			case rulesReadyToClose:
4947 				state = readyToCloseEndingWithRules;
4948 				break;
4949 			case destinationPathReadyToClose:
4950 				state = readyToCloseEndingWithDestinationPath;
4951 				break;
4952 			case bracketOpened:
4953 				state = bracketClosed;
4954 				break;
4955 			case bracketClosed:
4956 			default:
4957 				state = error;
4958 			}
4959 		} else {
4960 			// regular word
4961 			switch (state) {
4962 			case start:
4963 			case readyToCloseOrOtherEntry:
4964 				state = readyToClose;
4965 				currentClasspathName = token;
4966 				break;
4967 			case rulesStart:
4968 				if (token.startsWith("-d ")) { //$NON-NLS-1$
4969 					if (currentDestinationPath != null) {
4970 						throw new IllegalArgumentException(
4971 								this.bind("configure.duplicateDestinationPathEntry", //$NON-NLS-1$
4972 										currentPath));
4973 					}
4974 					currentDestinationPath = token.substring(3).trim();
4975 					state = destinationPathReadyToClose;
4976 					break;
4977 				} // else we proceed with a rule
4978 				//$FALL-THROUGH$
4979 			case rulesNeedAnotherRule:
4980 				if (currentDestinationPath != null) {
4981 					throw new IllegalArgumentException(
4982 							this.bind("configure.accessRuleAfterDestinationPath", //$NON-NLS-1$
4983 								currentPath));
4984 				}
4985 				state = rulesReadyToClose;
4986 				currentRuleSpecs.add(token);
4987 				break;
4988 			case destinationPathStart:
4989 				if (!token.startsWith("-d ")) { //$NON-NLS-1$
4990 					state = error;
4991 				} else {
4992 					currentDestinationPath = token.substring(3).trim();
4993 					state = destinationPathReadyToClose;
4994 				}
4995 				break;
4996 			case bracketClosed:
4997 				for (int i = bracket; i < cursor ; i++) {
4998 					currentClasspathName += tokens.get(i);
4999 				}
5000 				state = readyToClose;
5001 				break;
5002 			case bracketOpened:
5003 				break;
5004 			default:
5005 				state = error;
5006 			}
5007 		}
5008 		if (state == bracketClosed && cursor == tokensNb) {
5009 			cursor = bracket + 1;
5010 			state = rulesStart;
5011 		}
5012 	}
5013 	switch(state) {
5014 		case readyToCloseOrOtherEntry:
5015 			break;
5016 		case readyToClose:
5017 		case readyToCloseEndingWithRules:
5018 		case readyToCloseEndingWithDestinationPath:
5019 			addNewEntry(paths, currentClasspathName, currentRuleSpecs,
5020 				customEncoding, currentDestinationPath, isSourceOnly,
5021 				rejectDestinationPathOnJars);
5022 			break;
5023 		case bracketOpened:
5024 		case bracketClosed:
5025 		default :
5026 			// we go on anyway
5027 			if (currentPath.length() != 0) {
5028 				addPendingErrors(this.bind("configure.incorrectClasspath", currentPath));//$NON-NLS-1$
5029 			}
5030 	}
5031 }
5032 
5033 private int processPaths(String[] args, int index, String currentArg, ArrayList<String> paths) {
5034 	int localIndex = index;
5035 	int count = 0;
5036 	for (int i = 0, max = currentArg.length(); i < max; i++) {
5037 		switch(currentArg.charAt(i)) {
5038 			case '[' :
5039 				count++;
5040 				break;
5041 			case ']' :
5042 				count--;
5043 				break;
5044 		}
5045 	}
5046 	if (count == 0) {
5047 		paths.add(currentArg);
5048 	} else if (count > 1) {
5049 		throw new IllegalArgumentException(
5050 				this.bind("configure.unexpectedBracket", //$NON-NLS-1$
5051 							currentArg));
5052 	} else {
5053 		StringBuffer currentPath = new StringBuffer(currentArg);
5054 		while (true) {
5055 			if (localIndex >= args.length) {
5056 				throw new IllegalArgumentException(
5057 						this.bind("configure.unexpectedBracket", //$NON-NLS-1$
5058 								currentArg));
5059 			}
5060 			localIndex++;
5061 			String nextArg = args[localIndex];
5062 			for (int i = 0, max = nextArg.length(); i < max; i++) {
5063 				switch(nextArg.charAt(i)) {
5064 					case '[' :
5065 						if (count > 1) {
5066 							throw new IllegalArgumentException(
5067 									this.bind("configure.unexpectedBracket", //$NON-NLS-1$
5068 											nextArg));
5069 						}
5070 						count++;
5071 						break;
5072 					case ']' :
5073 						count--;
5074 						break;
5075 				}
5076 			}
5077 			if (count == 0) {
5078 				currentPath.append(' ');
5079 				currentPath.append(nextArg);
5080 				paths.add(currentPath.toString());
5081 				return localIndex - index;
5082 			} else if (count < 0) {
5083 				throw new IllegalArgumentException(
5084 						this.bind("configure.unexpectedBracket", //$NON-NLS-1$
5085 									nextArg));
5086 			} else {
5087 				currentPath.append(' ');
5088 				currentPath.append(nextArg);
5089 			}
5090 		}
5091 
5092 	}
5093 	return localIndex - index;
5094 }
5095 private int processPaths(String[] args, int index, String currentArg, String[] paths) {
5096 	int localIndex = index;
5097 	int count = 0;
5098 	for (int i = 0, max = currentArg.length(); i < max; i++) {
5099 		switch(currentArg.charAt(i)) {
5100 			case '[' :
5101 				count++;
5102 				break;
5103 			case ']' :
5104 				count--;
5105 				break;
5106 		}
5107 	}
5108 	if (count == 0) {
5109 		paths[0] = currentArg;
5110 	} else {
5111 		StringBuffer currentPath = new StringBuffer(currentArg);
5112 		while (true) {
5113 			localIndex++;
5114 			if (localIndex >= args.length) {
5115 				throw new IllegalArgumentException(
5116 						this.bind("configure.unexpectedBracket", //$NON-NLS-1$
5117 								currentArg));
5118 			}
5119 			String nextArg = args[localIndex];
5120 			for (int i = 0, max = nextArg.length(); i < max; i++) {
5121 				switch(nextArg.charAt(i)) {
5122 					case '[' :
5123 						if (count > 1) {
5124 							throw new IllegalArgumentException(
5125 									this.bind("configure.unexpectedBracket", //$NON-NLS-1$
5126 											currentArg));
5127 						}
5128 						count++;
5129 						break;
5130 					case ']' :
5131 						count--;
5132 						break;
5133 				}
5134 			}
5135 			if (count == 0) {
5136 				currentPath.append(' ');
5137 				currentPath.append(nextArg);
5138 				paths[0] = currentPath.toString();
5139 				return localIndex - index;
5140 			} else if (count < 0) {
5141 				throw new IllegalArgumentException(
5142 						this.bind("configure.unexpectedBracket", //$NON-NLS-1$
5143 									currentArg));
5144 			} else {
5145 				currentPath.append(' ');
5146 				currentPath.append(nextArg);
5147 			}
5148 		}
5149 
5150 	}
5151 	return localIndex - index;
5152 }
5153 /**
5154  * Creates a NLS catalog for the given locale.
5155  */
5156 public void relocalize() {
5157 	relocalize(Locale.getDefault());
5158 }
5159 
5160 private void relocalize(Locale locale) {
5161 	this.compilerLocale = locale;
5162 	try {
5163 		this.bundle = ResourceBundleFactory.getBundle(locale);
5164 	} catch(MissingResourceException e) {
5165 		System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$
5166 		throw e;
5167 	}
5168 }
5169 /*
5170  * External API
5171  */
5172 public void setDestinationPath(String dest) {
5173 	this.destinationPath = dest;
5174 }
5175 /*
5176  * External API
5177  */
5178 public void setLocale(Locale locale) {
5179 	relocalize(locale);
5180 }
5181 /*
5182  * External API
5183  */
5184 protected void setPaths(ArrayList<String> bootclasspaths,
5185 		String sourcepathClasspathArg,
5186 		ArrayList<String> sourcepathClasspaths,
5187 		ArrayList<String> classpaths,
5188 		String modulePath,
5189 		String moduleSourcepath,
5190 		ArrayList<String> extdirsClasspaths,
5191 		ArrayList<String> endorsedDirClasspaths,
5192 		String customEncoding) {
5193 
5194 	if (this.complianceLevel == 0) {
5195 		String version = this.options.get(CompilerOptions.OPTION_Compliance);
5196 		this.complianceLevel = CompilerOptions.versionToJdkLevel(version);
5197 	}
5198 	// process bootclasspath, classpath and sourcepaths
5199 	ArrayList<Classpath> allPaths = null;
5200 	long jdkLevel = validateClasspathOptions(bootclasspaths, endorsedDirClasspaths, extdirsClasspaths);
5201 
5202 	if (this.releaseVersion != null && this.complianceLevel < jdkLevel) {
5203 		// TODO: Revisit for access rules
5204 		allPaths = new ArrayList<Classpath>();
5205 		allPaths.add(
5206 				FileSystem.getOlderSystemRelease(this.javaHomeCache.getAbsolutePath(), this.releaseVersion, null));
5207 	} else {
5208 		allPaths = handleBootclasspath(bootclasspaths, customEncoding);
5209 	}
5210 
5211 	List<FileSystem.Classpath> cp = handleClasspath(classpaths, customEncoding);
5212 
5213 	List<FileSystem.Classpath> mp = handleModulepath(modulePath);
5214 
5215 	List<FileSystem.Classpath> msp = handleModuleSourcepath(moduleSourcepath);
5216 
5217 	ArrayList<FileSystem.Classpath> sourcepaths = new ArrayList<>();
5218 	if (sourcepathClasspathArg != null) {
5219 		processPathEntries(DEFAULT_SIZE_CLASSPATH, sourcepaths,
5220 			sourcepathClasspathArg, customEncoding, true, false);
5221 	}
5222 
5223 	/*
5224 	 * Feed endorsedDirClasspath according to:
5225 	 * - -extdirs first if present;
5226 	 * - else java.ext.dirs if defined;
5227 	 * - else default extensions directory for the platform.
5228 	 */
5229 	List<FileSystem.Classpath> extdirs = handleExtdirs(extdirsClasspaths);
5230 
5231 	List<FileSystem.Classpath> endorsed = handleEndorseddirs(endorsedDirClasspaths);
5232 
5233 	/*
5234 	 * Concatenate classpath entries
5235 	 * We put the bootclasspath at the beginning of the classpath
5236 	 * entries, followed by the extension libraries, followed by
5237 	 * the sourcepath followed by the classpath.  All classpath
5238 	 * entries are searched for both sources and binaries except
5239 	 * the sourcepath entries which are searched for sources only.
5240 	 */
5241 	allPaths.addAll(0, endorsed);
5242 	allPaths.addAll(extdirs);
5243 	allPaths.addAll(sourcepaths);
5244 	allPaths.addAll(cp);
5245 	allPaths.addAll(mp);
5246 	allPaths.addAll(msp);
5247 	allPaths = FileSystem.ClasspathNormalizer.normalize(allPaths);
5248 	this.checkedClasspaths = new FileSystem.Classpath[allPaths.size()];
5249 	allPaths.toArray(this.checkedClasspaths);
5250 	this.logger.logClasspath(this.checkedClasspaths);
5251 
5252 	if (this.annotationPaths != null && CompilerOptions.ENABLED.equals(this.options.get(CompilerOptions.OPTION_AnnotationBasedNullAnalysis))) {
5253 		for (FileSystem.Classpath c : this.checkedClasspaths) {
5254 			if (c instanceof ClasspathJar)
5255 				((ClasspathJar) c).annotationPaths = this.annotationPaths;
5256 			else if (c instanceof ClasspathJrt)
5257 				((ClasspathJrt) c).annotationPaths = this.annotationPaths;
5258 		}
5259 	}
5260 }
5261 public final static boolean shouldIgnoreOptionalProblems(char[][] folderNames, char[] fileName) {
5262 	if (folderNames == null || fileName == null) {
5263 		return false;
5264 	}
5265 	for (int i = 0, max = folderNames.length; i < max; i++) {
5266 		char[] folderName = folderNames[i];
5267 		if (isParentOf(folderName, fileName)) {
5268 			return true;
5269 		}
5270 	}
5271 	return false;
5272 }
5273 protected long validateClasspathOptions(ArrayList<String> bootclasspaths, ArrayList<String> endorsedDirClasspaths, ArrayList<String> extdirsClasspaths) {
5274 	if (this.complianceLevel > ClassFileConstants.JDK1_8) {
5275 		if (bootclasspaths != null && bootclasspaths.size() > 0)
5276 			throw new IllegalArgumentException(
5277 				this.bind("configure.unsupportedOption", "-bootclasspath")); //$NON-NLS-1$ //$NON-NLS-2$
5278 		if (extdirsClasspaths != null && extdirsClasspaths.size() > 0)
5279 			throw new IllegalArgumentException(
5280 				this.bind("configure.unsupportedOption", "-extdirs")); //$NON-NLS-1$ //$NON-NLS-2$
5281 		if (endorsedDirClasspaths != null && endorsedDirClasspaths.size() > 0)
5282 			throw new IllegalArgumentException(
5283 				this.bind("configure.unsupportedOption", "-endorseddirs")); //$NON-NLS-1$ //$NON-NLS-2$
5284 	}
5285 	long jdkLevel = Util.getJDKLevel(getJavaHome());
5286 	if (jdkLevel < ClassFileConstants.JDK9 && this.releaseVersion != null) {
5287 		throw new IllegalArgumentException(
5288 				this.bind("configure.unsupportedReleaseOption")); //$NON-NLS-1$
5289 	}
5290 	return jdkLevel;
5291 }
5292 protected void validateOptions(boolean didSpecifyCompliance) {
5293 	if (didSpecifyCompliance) {
5294 		String version = this.options.get(CompilerOptions.OPTION_Compliance);
5295 		if (this.releaseVersion != null) {
5296 			throw new IllegalArgumentException(
5297 					this.bind("configure.unsupportedWithRelease", version));//$NON-NLS-1$
5298 		}
5299 		if (CompilerOptions.VERSION_1_3.equals(version)) {
5300 			if (!this.didSpecifySource) this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3);
5301 			if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1);
5302 		} else if (CompilerOptions.VERSION_1_4.equals(version)) {
5303 			if (this.didSpecifySource) {
5304 				Object source = this.options.get(CompilerOptions.OPTION_Source);
5305 				if (CompilerOptions.VERSION_1_3.equals(source)) {
5306 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2);
5307 				} else if (CompilerOptions.VERSION_1_4.equals(source)) {
5308 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
5309 				}
5310 			} else {
5311 				this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3);
5312 				if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2);
5313 			}
5314 		} else if (CompilerOptions.VERSION_1_5.equals(version)) {
5315 			if (this.didSpecifySource) {
5316 				Object source = this.options.get(CompilerOptions.OPTION_Source);
5317 				if (CompilerOptions.VERSION_1_3.equals(source)
5318 						|| CompilerOptions.VERSION_1_4.equals(source)) {
5319 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
5320 				} else if (CompilerOptions.VERSION_1_5.equals(source)) {
5321 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5);
5322 				}
5323 			} else {
5324 				this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5);
5325 				if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5);
5326 			}
5327 		} else if (CompilerOptions.VERSION_1_6.equals(version)) {
5328 			if (this.didSpecifySource) {
5329 				Object source = this.options.get(CompilerOptions.OPTION_Source);
5330 				if (CompilerOptions.VERSION_1_3.equals(source)
5331 						|| CompilerOptions.VERSION_1_4.equals(source)) {
5332 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
5333 				} else if (CompilerOptions.VERSION_1_5.equals(source)
5334 						|| CompilerOptions.VERSION_1_6.equals(source)) {
5335 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
5336 				}
5337 			} else {
5338 				this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6);
5339 				if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
5340 			}
5341 		} else if (CompilerOptions.VERSION_1_7.equals(version)) {
5342 			if (this.didSpecifySource) {
5343 				Object source = this.options.get(CompilerOptions.OPTION_Source);
5344 				if (CompilerOptions.VERSION_1_3.equals(source)
5345 						|| CompilerOptions.VERSION_1_4.equals(source)) {
5346 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
5347 				} else if (CompilerOptions.VERSION_1_5.equals(source)
5348 						|| CompilerOptions.VERSION_1_6.equals(source)) {
5349 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
5350 				} else if (CompilerOptions.VERSION_1_7.equals(source)) {
5351 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7);
5352 				}
5353 			} else {
5354 				this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_7);
5355 				if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7);
5356 			}
5357 		} else if (CompilerOptions.VERSION_1_8.equals(version)) {
5358 			if (this.didSpecifySource) {
5359 				Object source = this.options.get(CompilerOptions.OPTION_Source);
5360 				if (CompilerOptions.VERSION_1_3.equals(source)
5361 						|| CompilerOptions.VERSION_1_4.equals(source)) {
5362 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
5363 				} else if (CompilerOptions.VERSION_1_5.equals(source)
5364 						|| CompilerOptions.VERSION_1_6.equals(source)) {
5365 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
5366 				} else if (CompilerOptions.VERSION_1_7.equals(source)) {
5367 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7);
5368 				} else if (CompilerOptions.VERSION_1_8.equals(source)) {
5369 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8);
5370 				}
5371 			} else {
5372 				this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_8);
5373 				if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8);
5374 			}
5375 		} else if (CompilerOptions.VERSION_9.equals(version)) {
5376 			if (this.didSpecifySource) {
5377 				Object source = this.options.get(CompilerOptions.OPTION_Source);
5378 				if (CompilerOptions.VERSION_1_3.equals(source)
5379 						|| CompilerOptions.VERSION_1_4.equals(source)) {
5380 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
5381 				} else if (CompilerOptions.VERSION_1_5.equals(source)
5382 						|| CompilerOptions.VERSION_1_6.equals(source)) {
5383 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
5384 				} else if (CompilerOptions.VERSION_1_7.equals(source)) {
5385 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7);
5386 				} else if (CompilerOptions.VERSION_1_8.equals(source)) {
5387 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8);
5388 				} else if (CompilerOptions.VERSION_9.equals(source)) {
5389 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9);
5390 				}
5391 			} else {
5392 				this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_9);
5393 				if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9);
5394 			}
5395 		} else if (CompilerOptions.VERSION_10.equals(version)) {
5396 			if (this.didSpecifySource) {
5397 				Object source = this.options.get(CompilerOptions.OPTION_Source);
5398 				if (CompilerOptions.VERSION_1_3.equals(source)
5399 						|| CompilerOptions.VERSION_1_4.equals(source)) {
5400 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
5401 				} else if (CompilerOptions.VERSION_1_5.equals(source)
5402 						|| CompilerOptions.VERSION_1_6.equals(source)) {
5403 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
5404 				} else if (CompilerOptions.VERSION_1_7.equals(source)) {
5405 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7);
5406 				} else if (CompilerOptions.VERSION_1_8.equals(source)) {
5407 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8);
5408 				} else if (CompilerOptions.VERSION_9.equals(source)) {
5409 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9);
5410 				} else if (CompilerOptions.VERSION_10.equals(source)) {
5411 					if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_10);
5412 				}
5413 			} else {
5414 				this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_10);
5415 				if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_10);
5416 			}
5417 		} else {
5418 			if (!this.didSpecifyTarget) {
5419 				if (this.didSpecifySource) {
5420 					String source = this.options.get(CompilerOptions.OPTION_Source);
5421 					if (CompilerOptions.VERSION_1_3.equals(source)
5422 							|| CompilerOptions.VERSION_1_4.equals(source)) {
5423 						if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
5424 					} else if (CompilerOptions.VERSION_1_5.equals(source)
5425 							|| CompilerOptions.VERSION_1_6.equals(source)) {
5426 						this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
5427 					} else {
5428 						// 1.3 is the lowest version that can be specified as -source
5429 						// The following check will ensure '0' is ignored.
5430 						if (CompilerOptions.versionToJdkLevel(source) >= ClassFileConstants.JDK1_7)
5431 							this.options.put(CompilerOptions.OPTION_TargetPlatform, source);
5432 					}
5433 				} else {
5434 					if (CompilerOptions.versionToJdkLevel(version) > ClassFileConstants.JDK10) {
5435 						this.options.put(CompilerOptions.OPTION_Source, version);
5436 						this.options.put(CompilerOptions.OPTION_TargetPlatform, version);
5437 					}
5438 				}
5439 			}
5440 		}
5441 
5442 	} else if (this.didSpecifySource) {
5443 		String version = this.options.get(CompilerOptions.OPTION_Source);
5444 		// default is source 1.3 target 1.2 and compliance 1.4
5445 		if (CompilerOptions.VERSION_1_4.equals(version)) {
5446 			if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4);
5447 			if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
5448 		} else if (CompilerOptions.VERSION_1_5.equals(version)) {
5449 			if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5);
5450 			if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5);
5451 		} else if (CompilerOptions.VERSION_1_6.equals(version)) {
5452 			if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_6);
5453 			if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
5454 		} else if (CompilerOptions.VERSION_1_7.equals(version)) {
5455 			if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_7);
5456 			if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7);
5457 		} else if (CompilerOptions.VERSION_1_8.equals(version)) {
5458 			if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_8);
5459 			if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8);
5460 		} else if (CompilerOptions.VERSION_9.equals(version)) {
5461 			if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_9);
5462 			if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9);
5463 		} else if (CompilerOptions.VERSION_10.equals(version)) {
5464 			if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_10);
5465 			if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_10);
5466 		} else {
5467 			if (CompilerOptions.versionToJdkLevel(version) > ClassFileConstants.JDK10) {
5468 				if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, version);
5469 				if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, version);
5470 			}
5471 		}
5472 	}
5473 
5474 	final String sourceVersion = this.options.get(CompilerOptions.OPTION_Source);
5475 	if (this.complianceLevel == 0) {
5476 		final String compliance = this.options.get(CompilerOptions.OPTION_Compliance);
5477 		this.complianceLevel = CompilerOptions.versionToJdkLevel(compliance);
5478 	}
5479 	if (sourceVersion.equals(CompilerOptions.VERSION_10)
5480 			&& this.complianceLevel < ClassFileConstants.JDK10) {
5481 		// compliance must be 10 if source is 10
5482 		throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_10)); //$NON-NLS-1$
5483 	} else if (sourceVersion.equals(CompilerOptions.VERSION_9)
5484 			&& this.complianceLevel < ClassFileConstants.JDK9) {
5485 		// compliance must be 9 if source is 9
5486 		throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_9)); //$NON-NLS-1$
5487 	} else if (sourceVersion.equals(CompilerOptions.VERSION_1_8)
5488 			&& this.complianceLevel < ClassFileConstants.JDK1_8) {
5489 		// compliance must be 1.8 if source is 1.8
5490 		throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_8)); //$NON-NLS-1$
5491 	} else if (sourceVersion.equals(CompilerOptions.VERSION_1_7)
5492 			&& this.complianceLevel < ClassFileConstants.JDK1_7) {
5493 		// compliance must be 1.7 if source is 1.7
5494 		throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_7)); //$NON-NLS-1$
5495 	} else if (sourceVersion.equals(CompilerOptions.VERSION_1_6)
5496 			&& this.complianceLevel < ClassFileConstants.JDK1_6) {
5497 		// compliance must be 1.6 if source is 1.6
5498 		throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_6)); //$NON-NLS-1$
5499 	} else if (sourceVersion.equals(CompilerOptions.VERSION_1_5)
5500 			&& this.complianceLevel < ClassFileConstants.JDK1_5) {
5501 		// compliance must be 1.5 if source is 1.5
5502 		throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_5)); //$NON-NLS-1$
5503 	} else if (sourceVersion.equals(CompilerOptions.VERSION_1_4)
5504 			&& this.complianceLevel < ClassFileConstants.JDK1_4) {
5505 		// compliance must be 1.4 if source is 1.4
5506 		throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_4)); //$NON-NLS-1$
5507 	} else {
5508 		long ver = CompilerOptions.versionToJdkLevel(sourceVersion);
5509 		if(this.complianceLevel < ver)
5510 			throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), sourceVersion)); //$NON-NLS-1$
5511 	}
5512 	if (this.enablePreview && this.complianceLevel != ClassFileConstants.getLatestJDKLevel()) {
5513 		throw new IllegalArgumentException(this.bind("configure.unsupportedPreview")); //$NON-NLS-1$
5514 	}
5515 
5516 	// check and set compliance/source/target compatibilities
5517 	if (this.didSpecifyTarget) {
5518 		final String targetVersion = this.options.get(CompilerOptions.OPTION_TargetPlatform);
5519 		// tolerate jsr14 target
5520 		if (CompilerOptions.VERSION_JSR14.equals(targetVersion)) {
5521 			// expecting source >= 1.5
5522 			if (CompilerOptions.versionToJdkLevel(sourceVersion) < ClassFileConstants.JDK1_5) {
5523 				throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForGenericSource", targetVersion, sourceVersion)); //$NON-NLS-1$
5524 			}
5525 		} else if (CompilerOptions.VERSION_CLDC1_1.equals(targetVersion)) {
5526 			if (this.didSpecifySource && CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_4) {
5527 				throw new IllegalArgumentException(this.bind("configure.incompatibleSourceForCldcTarget", targetVersion, sourceVersion)); //$NON-NLS-1$
5528 			}
5529 			if (this.complianceLevel >= ClassFileConstants.JDK1_5) {
5530 				throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForCldcTarget", targetVersion, sourceVersion)); //$NON-NLS-1$
5531 			}
5532 		} else {
5533 			// target must be 1.8 if source is 1.8
5534 			if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_8
5535 					&& CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_8){
5536 				throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_8)); //$NON-NLS-1$
5537 			}
5538 			// target must be 1.7 if source is 1.7
5539 			if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_7
5540 					&& CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_7){
5541 				throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_7)); //$NON-NLS-1$
5542 			}
5543 			// target must be 1.6 if source is 1.6
5544 			if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_6
5545 					&& CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_6){
5546 				throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_6)); //$NON-NLS-1$
5547 			}
5548 			// target must be 1.5 if source is 1.5
5549 			if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_5
5550 					&& CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_5){
5551 				throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_5)); //$NON-NLS-1$
5552 			}
5553 			// target must be 1.4 if source is 1.4
5554 			if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_4
5555 					&& CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_4){
5556 				throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_4)); //$NON-NLS-1$
5557 			}
5558 			// target cannot be greater than compliance level
5559 			if (this.complianceLevel < CompilerOptions.versionToJdkLevel(targetVersion)){
5560 				throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForTarget", this.options.get(CompilerOptions.OPTION_Compliance), targetVersion)); //$NON-NLS-1$
5561 			}
5562 		}
5563 	}
5564 }
5565 }
5566