# HG changeset patch # User jjg # Date 1298664573 28800 # Node ID 8f0dcb9499db4973db22b6c0558463286960ee2e # Parent 3e30c95da3c6f618100aea69cc11900c3f4ed7af 7021650: fix Context issues Reviewed-by: mcimadamore diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/apt/util/Bark.java --- a/src/share/classes/com/sun/tools/apt/util/Bark.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/apt/util/Bark.java Fri Feb 25 12:09:33 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,15 +48,15 @@ * Preregisters factories to create and use a Bark object for use as * both a Log and a Bark. */ - public static void preRegister(final Context context) { + public static void preRegister(Context context) { context.put(barkKey, new Context.Factory() { - public Bark make() { - return new Bark(context); + public Bark make(Context c) { + return new Bark(c); } }); context.put(Log.logKey, new Context.Factory() { - public Log make() { - return Bark.instance(context); + public Log make(Context c) { + return Bark.instance(c); } }); } diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javac/api/JavacTool.java --- a/src/share/classes/com/sun/tools/javac/api/JavacTool.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTool.java Fri Feb 25 12:09:33 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,19 +157,19 @@ /** * Register that a compilation is about to start. */ - void beginContext(final Context context) { + void beginContext(Context context) { if (compilationInProgress) throw new IllegalStateException("Compilation in progress"); compilationInProgress = true; final JavaFileManager givenFileManager = context.get(JavaFileManager.class); context.put(JavaFileManager.class, (JavaFileManager)null); context.put(JavaFileManager.class, new Context.Factory() { - public JavaFileManager make() { + public JavaFileManager make(Context c) { if (givenFileManager != null) { - context.put(JavaFileManager.class, givenFileManager); + c.put(JavaFileManager.class, givenFileManager); return givenFileManager; } else { - return new JavacFileManager(context, true, null); + return new JavacFileManager(c, true, null); } } }); diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javac/file/CacheFSInfo.java --- a/src/share/classes/com/sun/tools/javac/file/CacheFSInfo.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/file/CacheFSInfo.java Fri Feb 25 12:09:33 2011 -0800 @@ -44,13 +44,13 @@ public class CacheFSInfo extends FSInfo { /** - * Register a Context.Factory to create a singleton CacheFSInfo. + * Register a Context.Factory to create a CacheFSInfo. */ - public static void preRegister(final Context context) { + public static void preRegister(Context context) { context.put(FSInfo.class, new Context.Factory() { - public FSInfo make() { + public FSInfo make(Context c) { FSInfo instance = new CacheFSInfo(); - context.put(FSInfo.class, instance); + c.put(FSInfo.class, instance); return instance; } }); diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javac/file/JavacFileManager.java --- a/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Fri Feb 25 12:09:33 2011 -0800 @@ -129,10 +129,10 @@ /** * Register a Context.Factory to create a JavacFileManager. */ - public static void preRegister(final Context context) { + public static void preRegister(Context context) { context.put(JavaFileManager.class, new Context.Factory() { - public JavaFileManager make() { - return new JavacFileManager(context, true, null); + public JavaFileManager make(Context c) { + return new JavacFileManager(c, true, null); } }); } diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javac/main/JavaCompiler.java --- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Fri Feb 25 12:09:33 2011 -0800 @@ -312,7 +312,7 @@ /** Construct a new compiler using a shared context. */ - public JavaCompiler(final Context context) { + public JavaCompiler(Context context) { this.context = context; context.put(compilerKey, this); diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java --- a/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Fri Feb 25 12:09:33 2011 -0800 @@ -1045,7 +1045,7 @@ * other values are implicitly reset. */ private Context nextContext() { - Context next = new Context(); + Context next = new Context(context); Options options = Options.instance(context); Assert.checkNonNull(options); diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javac/util/Context.java --- a/src/share/classes/com/sun/tools/javac/util/Context.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javac/util/Context.java Fri Feb 25 12:09:33 2011 -0800 @@ -108,7 +108,7 @@ * instance. */ public static interface Factory { - T make(); + T make(Context c); }; /** @@ -124,6 +124,8 @@ Object old = ht.put(key, fac); if (old != null) throw new AssertionError("duplicate context value"); + checkState(ft); + ft.put(key, fac); // cannot be duplicate if unique in ht } /** Set the value for the key in this context. */ @@ -142,7 +144,7 @@ Object o = ht.get(key); if (o instanceof Factory) { Factory fac = (Factory)o; - o = fac.make(); + o = fac.make(this); if (o instanceof Factory) throw new AssertionError("T extends Context.Factory"); Assert.check(ht.get(key) == o); @@ -158,6 +160,20 @@ public Context() {} + /** + * The table of preregistered factories. + */ + private Map,Factory> ft = new HashMap,Factory>(); + + public Context(Context prev) { + kt.putAll(prev.kt); // retain all implicit keys + ft.putAll(prev.ft); // retain all factory objects + ht.putAll(prev.ft); // init main table with factories + } + + /* + * The key table, providing a unique Key for each Class. + */ private Map, Key> kt = new HashMap, Key>(); private Key key(Class clss) { @@ -198,6 +214,7 @@ public void clear() { ht = null; kt = null; + ft = null; } private static void checkState(Map t) { diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javadoc/JavadocClassReader.java --- a/src/share/classes/com/sun/tools/javadoc/JavadocClassReader.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javadoc/JavadocClassReader.java Fri Feb 25 12:09:33 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,10 +44,10 @@ return (JavadocClassReader)instance; } - public static void preRegister(final Context context) { + public static void preRegister(Context context) { context.put(classReaderKey, new Context.Factory() { - public ClassReader make() { - return new JavadocClassReader(context); + public ClassReader make(Context c) { + return new JavadocClassReader(c); } }); } diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javadoc/JavadocEnter.java --- a/src/share/classes/com/sun/tools/javadoc/JavadocEnter.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javadoc/JavadocEnter.java Fri Feb 25 12:09:33 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,10 +48,10 @@ return (JavadocEnter)instance; } - public static void preRegister(final Context context) { + public static void preRegister(Context context) { context.put(enterKey, new Context.Factory() { - public Enter make() { - return new JavadocEnter(context); + public Enter make(Context c) { + return new JavadocEnter(c); } }); } diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javadoc/JavadocMemberEnter.java --- a/src/share/classes/com/sun/tools/javadoc/JavadocMemberEnter.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javadoc/JavadocMemberEnter.java Fri Feb 25 12:09:33 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,10 +46,10 @@ return (JavadocMemberEnter)instance; } - public static void preRegister(final Context context) { + public static void preRegister(Context context) { context.put(memberEnterKey, new Context.Factory() { - public MemberEnter make() { - return new JavadocMemberEnter(context); + public MemberEnter make(Context c) { + return new JavadocMemberEnter(c); } }); } diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javadoc/JavadocTodo.java --- a/src/share/classes/com/sun/tools/javadoc/JavadocTodo.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javadoc/JavadocTodo.java Fri Feb 25 12:09:33 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,10 +34,10 @@ * @author Neal Gafter */ public class JavadocTodo extends Todo { - public static void preRegister(final Context context) { + public static void preRegister(Context context) { context.put(todoKey, new Context.Factory() { - public Todo make() { - return new JavadocTodo(context); + public Todo make(Context c) { + return new JavadocTodo(c); } }); } diff -r 3e30c95da3c6 -r 8f0dcb9499db src/share/classes/com/sun/tools/javadoc/Messager.java --- a/src/share/classes/com/sun/tools/javadoc/Messager.java Thu Feb 24 08:40:49 2011 -0800 +++ b/src/share/classes/com/sun/tools/javadoc/Messager.java Fri Feb 25 12:09:33 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,23 +57,23 @@ return (Messager)instance; } - public static void preRegister(final Context context, + public static void preRegister(Context context, final String programName) { context.put(logKey, new Context.Factory() { - public Log make() { - return new Messager(context, + public Log make(Context c) { + return new Messager(c, programName); } }); } - public static void preRegister(final Context context, + public static void preRegister(Context context, final String programName, final PrintWriter errWriter, final PrintWriter warnWriter, final PrintWriter noticeWriter) { context.put(logKey, new Context.Factory() { - public Log make() { - return new Messager(context, + public Log make(Context c) { + return new Messager(c, programName, errWriter, warnWriter, diff -r 3e30c95da3c6 -r 8f0dcb9499db test/tools/javac/diags/ArgTypeCompilerFactory.java --- a/test/tools/javac/diags/ArgTypeCompilerFactory.java Thu Feb 24 08:40:49 2011 -0800 +++ b/test/tools/javac/diags/ArgTypeCompilerFactory.java Fri Feb 25 12:09:33 2011 -0800 @@ -34,6 +34,7 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.file.*; import com.sun.tools.javac.main.Main; +import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.parser.Token; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration; @@ -107,8 +108,7 @@ JavacTaskImpl t = (JavacTaskImpl) tool.getTask(out, fm, null, opts, null, fos); Context c = t.getContext(); ArgTypeMessages.preRegister(c); - Options options = Options.instance(c); - Log.instance(c).setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options)); + ArgTypeJavaCompiler.preRegister(c); Boolean ok = t.call(); return ok; @@ -144,7 +144,7 @@ } }; JavacFileManager.preRegister(c); // can't create it until Log has been set up - ArgTypeDiagnosticFormatter.preRegister(c); + ArgTypeJavaCompiler.preRegister(c); ArgTypeMessages.preRegister(c); int result = main.compile(args.toArray(new String[args.size()]), c); @@ -170,7 +170,7 @@ Context c = new Context(); JavacFileManager.preRegister(c); // can't create it until Log has been set up - ArgTypeDiagnosticFormatter.preRegister(c); + ArgTypeJavaCompiler.preRegister(c); ArgTypeMessages.preRegister(c); com.sun.tools.javac.main.Main m = new com.sun.tools.javac.main.Main("javac", out); int rc = m.compile(args.toArray(new String[args.size()]), c); @@ -189,17 +189,6 @@ * arg types. */ static class ArgTypeDiagnosticFormatter extends AbstractDiagnosticFormatter { - static void preRegister(final Context context) { - context.put(Log.logKey, new Context.Factory() { - public Log make() { - Log log = new Log(context) { }; - Options options = Options.instance(context); - log.setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options)); - return log; - } - }); - - } ArgTypeDiagnosticFormatter(Options options) { super(null, new SimpleConfiguration(options, @@ -246,14 +235,37 @@ } /** + * Trivial subtype of JavaCompiler to get access to the protected compilerKey field. + * The factory is used to ensure that the log is initialized with an instance of + * ArgTypeDiagnosticFormatter before we create the required JavaCompiler. + */ + static class ArgTypeJavaCompiler extends JavaCompiler { + static void preRegister(Context context) { + context.put(compilerKey, new Context.Factory() { + public JavaCompiler make(Context c) { + Log log = Log.instance(c); + Options options = Options.instance(c); + log.setDiagnosticFormatter(new ArgTypeDiagnosticFormatter(options)); + return new JavaCompiler(c); + } + }); + } + + // not used + private ArgTypeJavaCompiler() { + super(null); + } + } + + /** * Diagnostic formatter which "localizes" a message as a line * containing a key, and a possibly empty set of descriptive strings for the * arg types. */ static class ArgTypeMessages extends JavacMessages { - static void preRegister(final Context c) { - c.put(JavacMessages.messagesKey, new Context.Factory() { - public JavacMessages make() { + static void preRegister(Context context) { + context.put(JavacMessages.messagesKey, new Context.Factory() { + public JavacMessages make(Context c) { return new ArgTypeMessages(c) { @Override public String getLocalizedString(Locale l, String key, Object... args) { diff -r 3e30c95da3c6 -r 8f0dcb9499db test/tools/javac/diags/Example.java --- a/test/tools/javac/diags/Example.java Thu Feb 24 08:40:49 2011 -0800 +++ b/test/tools/javac/diags/Example.java Fri Feb 25 12:09:33 2011 -0800 @@ -522,10 +522,10 @@ super(context); } - static void preRegister(final Context c, final Set keys) { + static void preRegister(Context c, final Set keys) { if (keys != null) { c.put(JavacMessages.messagesKey, new Context.Factory() { - public JavacMessages make() { + public JavacMessages make(Context c) { return new MessageTracker(c) { @Override public String getLocalizedString(Locale l, String key, Object... args) { diff -r 3e30c95da3c6 -r 8f0dcb9499db test/tools/javac/util/context/T7021650.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/util/context/T7021650.java Fri Feb 25 12:09:33 2011 -0800 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 7021650 + * @summary Fix Context issues + * @library ../../lib + * @build JavacTestingAbstractProcessor T7021650 + * @run main T7021650 + */ + +import java.io.*; +import java.net.*; +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.tools.*; + +import com.sun.tools.javac.comp.Attr; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.main.Main; +import com.sun.tools.javac.processing.JavacProcessingEnvironment; +import com.sun.tools.javac.util.Context; + +public class T7021650 extends JavacTestingAbstractProcessor { + public static void main(String... args) throws Exception { + new T7021650().run(); + } + + static File testSrc = new File(System.getProperty("test.src")); + static final int MAX_ROUNDS = 3; + + /** + * Perform a compilation with custom factories registered in the context, + * and verify that corresponding objects are created in each round. + */ + void run() throws Exception { + Counter demoCounter = new Counter(); + Counter myAttrCounter = new Counter(); + + Context context = new Context(); + // Use a custom file manager which creates classloaders for annotation + // processors with a sensible delegation parent, so that all instances + // of test classes come from the same class loader. This is important + // because the test performs class checks on the instances of classes + // found in the context for each round or processing. + context.put(JavaFileManager.class, new Context.Factory() { + public JavaFileManager make(Context c) { + return new JavacFileManager(c, true, null) { + @Override + protected ClassLoader getClassLoader(URL[] urls) { + return new URLClassLoader(urls, T7021650.class.getClassLoader()); + } + }; + } + }); + + Demo.preRegister(context, demoCounter); + MyAttr.preRegister(context, myAttrCounter); + + String[] args = { + "-d", ".", + "-processor", T7021650.class.getName(), + "-XprintRounds", + new File(testSrc, T7021650.class.getName() + ".java").getPath() + }; + + compile(context, args); + + // Expect to create Demo for initial round, then MAX_ROUNDS in which + // GenX files are generated, then standard final round of processing. + checkEqual("demoCounter", demoCounter.count, MAX_ROUNDS + 2); + + // Expect to create MyAttr for same processing rounds as for Demo, + // plus additional context for final compilation. + checkEqual("myAttrCounter", myAttrCounter.count, MAX_ROUNDS + 3); + } + + void compile(Context context, String... args) throws Exception { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + Main m = new Main("javac", pw); + int rc = m.compile(args, context); + pw.close(); + String out = sw.toString(); + if (!out.isEmpty()) + System.err.println(out); + if (rc != 0) + throw new Exception("compilation failed unexpectedly: rc=" + rc); + } + + void checkEqual(String label, int found, int expect) throws Exception { + if (found != expect) + throw new Exception("unexpected value for " + label + + ": expected " + expect + + ": found " + found); + } + + //--------------- + + /* + * A custom class unknown to javac but nonetheless registered in the context. + */ + static class Demo { + static void preRegister(Context context, final Counter counter) { + context.put(Demo.class, new Context.Factory() { + public Demo make(Context c) { + counter.count++; + return new Demo(c); + } + }); + } + + Demo(Context c) { + c.put(Demo.class, this); + } + + static Demo instance(Context context) { + return context.get(Demo.class); + } + } + + /** + * A custom version of a standard javac component. + */ + static class MyAttr extends Attr { + static void preRegister(Context context, final Counter counter) { + context.put(attrKey, new Context.Factory() { + public Attr make(Context c) { + counter.count++; + return new MyAttr(c); + } + }); + } + + MyAttr(Context c) { + super(c); + } + } + + static class Counter { + int count; + } + + //--------------- + + int round = 0; + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + round++; + + Context context = ((JavacProcessingEnvironment) processingEnv).getContext(); + + // verify items in context as expected + check("Demo", Demo.instance(context), Demo.class); + check("Attr", Attr.instance(context), MyAttr.class); + + // For a few rounds, generate new source files, so that we can check whether + // values in the context are correctly handled in subsequent processing rounds + if (round <= MAX_ROUNDS) { + String pkg = "p"; + String currClass = "Gen" + round; + String curr = pkg + "." + currClass; + String next = (pkg + ".Gen" + (round + 1)); + StringBuilder text = new StringBuilder(); + text.append("package ").append(pkg).append(";\n"); + text.append("public class ").append(currClass).append(" {\n"); + if (round < MAX_ROUNDS) + text.append(" ").append(next).append(" x;\n"); + text.append("}\n"); + + try { + JavaFileObject fo = filer.createSourceFile(curr); + Writer out = fo.openWriter(); + try { + out.write(text.toString()); + } finally { + out.close(); + } + } catch (IOException e) { + throw new Error(e); + } + } + + return true; + } + + void check(String label, Object o, Class clazz) { + if (o == null) + throw new IllegalStateException(label + ": no item found"); + if (!clazz.isAssignableFrom(o.getClass())) + throw new IllegalStateException(label + ": unexpected class: " + o.getClass()); + } +}