Tue, 11 Aug 2009 01:13:14 +0100
6521805: Regression: JDK5/JDK6 javac allows write access to outer class reference
Summary: javac should warn/complain about identifiers with the same name as synthetic symbol
Reviewed-by: jjg
1 /*
2 * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.javadoc;
28 import com.sun.javadoc.*;
30 import com.sun.tools.javac.main.CommandLine;
31 import com.sun.tools.javac.util.Context;
32 import com.sun.tools.javac.util.List;
33 import com.sun.tools.javac.util.ListBuffer;
34 import com.sun.tools.javac.util.Options;
36 import java.io.IOException;
37 import java.io.File;
38 import java.io.FileNotFoundException;
39 import java.io.PrintWriter;
41 import java.util.StringTokenizer;
43 import static com.sun.tools.javac.code.Flags.*;
45 /**
46 * Main program of Javadoc.
47 * Previously named "Main".
48 *
49 * @since 1.2
50 * @author Robert Field
51 * @author Neal Gafter (rewrite)
52 */
53 class Start {
54 /** Context for this invocation. */
55 private final Context context;
57 private final String defaultDocletClassName;
58 private final ClassLoader docletParentClassLoader;
60 private static final String javadocName = "javadoc";
62 private static final String standardDocletClassName =
63 "com.sun.tools.doclets.standard.Standard";
65 private ListBuffer<String[]> options = new ListBuffer<String[]>();
67 private ModifierFilter showAccess = null;
69 private long defaultFilter = PUBLIC | PROTECTED;
71 private Messager messager;
73 String docLocale = "";
75 boolean breakiterator = false;
76 boolean quiet = false;
77 String encoding = null;
79 private DocletInvoker docletInvoker;
81 private static final int F_VERBOSE = 1 << 0;
82 private static final int F_WARNINGS = 1 << 2;
84 /* Treat warnings as errors. */
85 private boolean rejectWarnings = false;
87 Start(String programName,
88 PrintWriter errWriter,
89 PrintWriter warnWriter,
90 PrintWriter noticeWriter,
91 String defaultDocletClassName) {
92 this(programName, errWriter, warnWriter, noticeWriter, defaultDocletClassName, null);
93 }
95 Start(String programName,
96 PrintWriter errWriter,
97 PrintWriter warnWriter,
98 PrintWriter noticeWriter,
99 String defaultDocletClassName,
100 ClassLoader docletParentClassLoader) {
101 context = new Context();
102 messager = new Messager(context, programName, errWriter, warnWriter, noticeWriter);
103 this.defaultDocletClassName = defaultDocletClassName;
104 this.docletParentClassLoader = docletParentClassLoader;
105 }
107 Start(String programName, String defaultDocletClassName) {
108 this(programName, defaultDocletClassName, null);
109 }
111 Start(String programName, String defaultDocletClassName,
112 ClassLoader docletParentClassLoader) {
113 context = new Context();
114 messager = new Messager(context, programName);
115 this.defaultDocletClassName = defaultDocletClassName;
116 this.docletParentClassLoader = docletParentClassLoader;
117 }
119 Start(String programName, ClassLoader docletParentClassLoader) {
120 this(programName, standardDocletClassName, docletParentClassLoader);
121 }
123 Start(String programName) {
124 this(programName, standardDocletClassName);
125 }
127 Start(ClassLoader docletParentClassLoader) {
128 this(javadocName, docletParentClassLoader);
129 }
131 Start() {
132 this(javadocName);
133 }
135 /**
136 * Usage
137 */
138 private void usage() {
139 messager.notice("main.usage");
141 // let doclet print usage information (does nothing on error)
142 if (docletInvoker != null) {
143 docletInvoker.optionLength("-help");
144 }
145 }
147 /**
148 * Exit
149 */
150 private void exit() {
151 messager.exit();
152 }
155 /**
156 * Main program - external wrapper
157 */
158 int begin(String... argv) {
159 boolean failed = false;
161 try {
162 failed = !parseAndExecute(argv);
163 } catch(Messager.ExitJavadoc exc) {
164 // ignore, we just exit this way
165 } catch (OutOfMemoryError ee) {
166 messager.error(null, "main.out.of.memory");
167 failed = true;
168 } catch (Error ee) {
169 ee.printStackTrace();
170 messager.error(null, "main.fatal.error");
171 failed = true;
172 } catch (Exception ee) {
173 ee.printStackTrace();
174 messager.error(null, "main.fatal.exception");
175 failed = true;
176 } finally {
177 messager.exitNotice();
178 messager.flush();
179 }
180 failed |= messager.nerrors() > 0;
181 failed |= rejectWarnings && messager.nwarnings() > 0;
182 return failed ? 1 : 0;
183 }
185 private void addToList(ListBuffer<String> list, String str){
186 StringTokenizer st = new StringTokenizer(str, ":");
187 String current;
188 while(st.hasMoreTokens()){
189 current = st.nextToken();
190 list.append(current);
191 }
192 }
194 /**
195 * Main program - internal
196 */
197 private boolean parseAndExecute(String... argv) throws IOException {
198 long tm = System.currentTimeMillis();
200 ListBuffer<String> javaNames = new ListBuffer<String>();
202 // Preprocess @file arguments
203 try {
204 argv = CommandLine.parse(argv);
205 } catch (FileNotFoundException e) {
206 messager.error(null, "main.cant.read", e.getMessage());
207 exit();
208 } catch (IOException e) {
209 e.printStackTrace();
210 exit();
211 }
213 setDocletInvoker(argv);
214 ListBuffer<String> subPackages = new ListBuffer<String>();
215 ListBuffer<String> excludedPackages = new ListBuffer<String>();
216 Options compOpts = Options.instance(context);
217 boolean docClasses = false;
219 // Parse arguments
220 for (int i = 0 ; i < argv.length ; i++) {
221 String arg = argv[i];
222 if (arg.equals("-subpackages")) {
223 oneArg(argv, i++);
224 addToList(subPackages, argv[i]);
225 } else if (arg.equals("-exclude")){
226 oneArg(argv, i++);
227 addToList(excludedPackages, argv[i]);
228 } else if (arg.equals("-verbose")) {
229 setOption(arg);
230 compOpts.put("-verbose", "");
231 } else if (arg.equals("-encoding")) {
232 oneArg(argv, i++);
233 encoding = argv[i];
234 compOpts.put("-encoding", argv[i]);
235 } else if (arg.equals("-breakiterator")) {
236 breakiterator = true;
237 setOption("-breakiterator");
238 } else if (arg.equals("-quiet")) {
239 quiet = true;
240 setOption("-quiet");
241 } else if (arg.equals("-help")) {
242 usage();
243 exit();
244 } else if (arg.equals("-Xclasses")) {
245 setOption(arg);
246 docClasses = true;
247 } else if (arg.equals("-Xwerror")) {
248 setOption(arg);
249 rejectWarnings = true;
250 } else if (arg.equals("-private")) {
251 setOption(arg);
252 setFilter(ModifierFilter.ALL_ACCESS);
253 } else if (arg.equals("-package")) {
254 setOption(arg);
255 setFilter(PUBLIC | PROTECTED |
256 ModifierFilter.PACKAGE );
257 } else if (arg.equals("-protected")) {
258 setOption(arg);
259 setFilter(PUBLIC | PROTECTED );
260 } else if (arg.equals("-public")) {
261 setOption(arg);
262 setFilter(PUBLIC);
263 } else if (arg.equals("-source")) {
264 oneArg(argv, i++);
265 if (compOpts.get("-source") != null) {
266 usageError("main.option.already.seen", arg);
267 }
268 compOpts.put("-source", argv[i]);
269 } else if (arg.equals("-prompt")) {
270 compOpts.put("-prompt", "-prompt");
271 messager.promptOnError = true;
272 } else if (arg.equals("-sourcepath")) {
273 oneArg(argv, i++);
274 if (compOpts.get("-sourcepath") != null) {
275 usageError("main.option.already.seen", arg);
276 }
277 compOpts.put("-sourcepath", argv[i]);
278 } else if (arg.equals("-classpath")) {
279 oneArg(argv, i++);
280 if (compOpts.get("-classpath") != null) {
281 usageError("main.option.already.seen", arg);
282 }
283 compOpts.put("-classpath", argv[i]);
284 } else if (arg.equals("-sysclasspath")) {
285 oneArg(argv, i++);
286 if (compOpts.get("-bootclasspath") != null) {
287 usageError("main.option.already.seen", arg);
288 }
289 compOpts.put("-bootclasspath", argv[i]);
290 } else if (arg.equals("-bootclasspath")) {
291 oneArg(argv, i++);
292 if (compOpts.get("-bootclasspath") != null) {
293 usageError("main.option.already.seen", arg);
294 }
295 compOpts.put("-bootclasspath", argv[i]);
296 } else if (arg.equals("-extdirs")) {
297 oneArg(argv, i++);
298 if (compOpts.get("-extdirs") != null) {
299 usageError("main.option.already.seen", arg);
300 }
301 compOpts.put("-extdirs", argv[i]);
302 } else if (arg.equals("-overview")) {
303 oneArg(argv, i++);
304 } else if (arg.equals("-doclet")) {
305 i++; // handled in setDocletInvoker
306 } else if (arg.equals("-docletpath")) {
307 i++; // handled in setDocletInvoker
308 } else if (arg.equals("-locale")) {
309 if (i != 0)
310 usageError("main.locale_first");
311 oneArg(argv, i++);
312 docLocale = argv[i];
313 } else if (arg.startsWith("-XD")) {
314 String s = arg.substring("-XD".length());
315 int eq = s.indexOf('=');
316 String key = (eq < 0) ? s : s.substring(0, eq);
317 String value = (eq < 0) ? s : s.substring(eq+1);
318 compOpts.put(key, value);
319 }
320 // call doclet for its options
321 // other arg starts with - is invalid
322 else if ( arg.startsWith("-") ) {
323 int optionLength;
324 optionLength = docletInvoker.optionLength(arg);
325 if (optionLength < 0) {
326 // error already displayed
327 exit();
328 } else if (optionLength == 0) {
329 // option not found
330 usageError("main.invalid_flag", arg);
331 } else {
332 // doclet added option
333 if ((i + optionLength) > argv.length) {
334 usageError("main.requires_argument", arg);
335 }
336 ListBuffer<String> args = new ListBuffer<String>();
337 for (int j = 0; j < optionLength-1; ++j) {
338 args.append(argv[++i]);
339 }
340 setOption(arg, args.toList());
341 }
342 } else {
343 javaNames.append(arg);
344 }
345 }
347 if (javaNames.isEmpty() && subPackages.isEmpty()) {
348 usageError("main.No_packages_or_classes_specified");
349 }
351 if (!docletInvoker.validOptions(options.toList())) {
352 // error message already displayed
353 exit();
354 }
356 JavadocTool comp = JavadocTool.make0(context);
357 if (comp == null) return false;
359 if (showAccess == null) {
360 setFilter(defaultFilter);
361 }
363 LanguageVersion languageVersion = docletInvoker.languageVersion();
364 RootDocImpl root = comp.getRootDocImpl(
365 docLocale, encoding, showAccess,
366 javaNames.toList(), options.toList(), breakiterator,
367 subPackages.toList(), excludedPackages.toList(),
368 docClasses,
369 // legacy?
370 languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1, quiet);
372 // pass off control to the doclet
373 boolean ok = root != null;
374 if (ok) ok = docletInvoker.start(root);
376 // We're done.
377 if (compOpts.get("-verbose") != null) {
378 tm = System.currentTimeMillis() - tm;
379 messager.notice("main.done_in", Long.toString(tm));
380 }
382 return ok;
383 }
385 private void setDocletInvoker(String[] argv) {
386 String docletClassName = null;
387 String docletPath = null;
389 // Parse doclet specifying arguments
390 for (int i = 0 ; i < argv.length ; i++) {
391 String arg = argv[i];
392 if (arg.equals("-doclet")) {
393 oneArg(argv, i++);
394 if (docletClassName != null) {
395 usageError("main.more_than_one_doclet_specified_0_and_1",
396 docletClassName, argv[i]);
397 }
398 docletClassName = argv[i];
399 } else if (arg.equals("-docletpath")) {
400 oneArg(argv, i++);
401 if (docletPath == null) {
402 docletPath = argv[i];
403 } else {
404 docletPath += File.pathSeparator + argv[i];
405 }
406 }
407 }
409 if (docletClassName == null) {
410 docletClassName = defaultDocletClassName;
411 }
413 // attempt to find doclet
414 docletInvoker = new DocletInvoker(messager,
415 docletClassName, docletPath,
416 docletParentClassLoader);
417 }
419 private void setFilter(long filterBits) {
420 if (showAccess != null) {
421 messager.error(null, "main.incompatible.access.flags");
422 usage();
423 exit();
424 }
425 showAccess = new ModifierFilter(filterBits);
426 }
428 /**
429 * Set one arg option.
430 * Error and exit if one argument is not provided.
431 */
432 private void oneArg(String[] args, int index) {
433 if ((index + 1) < args.length) {
434 setOption(args[index], args[index+1]);
435 } else {
436 usageError("main.requires_argument", args[index]);
437 }
438 }
440 private void usageError(String key) {
441 messager.error(null, key);
442 usage();
443 exit();
444 }
446 private void usageError(String key, String a1) {
447 messager.error(null, key, a1);
448 usage();
449 exit();
450 }
452 private void usageError(String key, String a1, String a2) {
453 messager.error(null, key, a1, a2);
454 usage();
455 exit();
456 }
458 /**
459 * indicate an option with no arguments was given.
460 */
461 private void setOption(String opt) {
462 String[] option = { opt };
463 options.append(option);
464 }
466 /**
467 * indicate an option with one argument was given.
468 */
469 private void setOption(String opt, String argument) {
470 String[] option = { opt, argument };
471 options.append(option);
472 }
474 /**
475 * indicate an option with the specified list of arguments was given.
476 */
477 private void setOption(String opt, List<String> arguments) {
478 String[] args = new String[arguments.length() + 1];
479 int k = 0;
480 args[k++] = opt;
481 for (List<String> i = arguments; i.nonEmpty(); i=i.tail) {
482 args[k++] = i.head;
483 }
484 options = options.append(args);
485 }
487 }