7013272: Automatically generate info about how compiler resource keys are used
authorjjg
Wed, 26 Jan 2011 13:45:25 -0800
changeset 8226 8c2fd7e7bcf3
parent 8225 e9e5670e6a71
child 8227 2a31b2340763
7013272: Automatically generate info about how compiler resource keys are used Reviewed-by: mcimadamore
langtools/make/build.xml
langtools/src/share/classes/com/sun/tools/javac/code/Printer.java
langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java
langtools/test/tools/javac/diags/Example.java
langtools/test/tools/javac/diags/MessageFile.java
langtools/test/tools/javac/diags/MessageInfo.java
langtools/test/tools/javac/diags/RunExamples.java
--- a/langtools/make/build.xml	Wed Jan 26 11:20:19 2011 -0800
+++ b/langtools/make/build.xml	Wed Jan 26 13:45:25 2011 -0800
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
- Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2007, 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
@@ -331,7 +331,7 @@
             executable="${dist.bin.dir}/javac"
             srcdir="test/tools/javac/diags"
             destdir="${build.dir}/diag-examples/classes"
-            includes="Example.java,FileManager.java,HTMLWriter.java,RunExamples.java"
+            includes="ArgTypeCompilerFactory.java,Example.java,FileManager.java,HTMLWriter.java,RunExamples.java"
             sourcepath=""
             classpath="${dist.lib.dir}/javac.jar"
             includeAntRuntime="no"
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java	Wed Jan 26 11:20:19 2011 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java	Wed Jan 26 13:45:25 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -106,7 +106,7 @@
     }
 
     /**
-     * * Get a localized string represenation for all the symbols in the input list.
+     * * Get a localized string representation for all the symbols in the input list.
      *
      * @param ts symbols to be displayed
      * @param locale the locale in which the string is to be rendered
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jan 26 11:20:19 2011 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jan 26 13:45:25 2011 -0800
@@ -23,260 +23,440 @@
 # questions.
 #
 
+# Messages in this file which use "placeholders" for values (e.g. {0}, {1})
+# are preceded by a stylized comment describing the type of the corresponding
+# values.
+# The types currently in use are
+#
+# boolean           true or false
+# file name         the name of an input file; e.g.   MyFile.java
+# message segment   a sub-message; see compiler.misc.*
+# modifier          a Java modifier; e.g. public, private, protected
+# name              a name, typically a Java identifier
+# number            an integer
+# option name       the name of a command line option
+# source version    a source version number, such as 1.5, 1.6, 1.7
+# string            a general string
+# symbol            the name of a declared type
+# symbol kind       a description of the kind of a declaration; see compiler.misc.kindname.*
+# token             the name of a non-terminal in source code; see compiler.misc.token.*
+# type              a Java type; e.g. int, X, X<T>
+# unused            the value is not used in this message
+#
+# list of X         a comma-separated list of items; e.g. list of type
+# X or Y            alternation; e.g. message segment or type
+# set of X          a comma-separated collection of items; e.g. set of modifier
+#
+# These may be composed: e.g.   list of type or message segment
+#
+# These comments are verified by the jtreg test test/tools/javac/diags/MessageInfo,
+# using info derived from the collected set of examples in test/tools/javac/diags/examples.
+# MessageInfo can also be run as a standalone utility providing more facilities
+# for manipulating this file. For more details, see MessageInfo.java.
+
 ##
 ## errors
 ##
 
+# 0: symbol
 compiler.err.abstract.cant.be.instantiated=\
     {0} is abstract; cannot be instantiated
+
 compiler.err.abstract.meth.cant.have.body=\
     abstract methods cannot have a body
+
 compiler.err.already.annotated=\
     {0} {1} has already been annotated
+
+# 0: symbol, 1: symbol
 compiler.err.already.defined=\
     {0} is already defined in {1}
+
+# 0: string
 compiler.err.already.defined.single.import=\
     {0} is already defined in a single-type import
+
+# 0: string
 compiler.err.already.defined.static.single.import=\
     {0} is already defined in a static single-type import
+
 compiler.err.already.defined.this.unit=\
     {0} is already defined in this compilation unit
+
+# 0: type, 1: list of name
 compiler.err.annotation.missing.default.value=\
     annotation {0} is missing value for the attribute {1}
+
+# 0: type, 1: list of name
 compiler.err.annotation.missing.default.value.1=\
     annotation {0} is missing values for attributes {1}
+
+# 0: type
 compiler.err.annotation.not.valid.for.type=\
     annotation not valid for a value of type {0}
+
 compiler.err.annotation.type.not.applicable=\
     annotation type not applicable to this kind of declaration
+
 compiler.err.annotation.value.must.be.annotation=\
     annotation value must be an annotation
+
 compiler.err.annotation.value.must.be.class.literal=\
     annotation value must be a class literal
+
 compiler.err.annotation.value.must.be.name.value=\
     annotation values must be of the form ''name=value''
+
 compiler.err.annotation.value.not.allowable.type=\
     annotation value not of an allowable type
+
 compiler.err.anon.class.impl.intf.no.args=\
     anonymous class implements interface; cannot have arguments
+
 compiler.err.anon.class.impl.intf.no.typeargs=\
     anonymous class implements interface; cannot have type arguments
+
 compiler.err.anon.class.impl.intf.no.qual.for.new=\
     anonymous class implements interface; cannot have qualifier for new
+
+# 0: symbol, 1: symbol, 2: symbol
 compiler.err.array.and.varargs=\
     cannot declare both {0} and {1} in {2}
+
 compiler.err.array.dimension.missing=\
     array dimension missing
+
+# 0: type
 compiler.err.array.req.but.found=\
     array required, but {0} found
 
 compiler.err.assignment.from.super-bound=\
     assigning from wildcard {0}
+
 compiler.err.assignment.to.extends-bound=\
     assigning to wildcard {0}
+
 compiler.err.attribute.value.must.be.constant=\
     attribute value must be constant
 
 compiler.err.break.outside.switch.loop=\
     break outside switch or loop
 
+# 0: name
 compiler.err.call.must.be.first.stmt.in.ctor=\
     call to {0} must be first statement in constructor
+
 compiler.err.cant.apply.symbol=\
     {0} {1} in {4} {5} cannot be applied to given types\n\
     required: {2}\n\
     found: {3}
+
+# 0: symbol kind, 1: name, 2: list of type or message segment, 3: list of type or message segment, 4: symbol kind, 5: type, 6: message segment
 compiler.err.cant.apply.symbol.1=\
     {0} {1} in {4} {5} cannot be applied to given types;\n\
     required: {2}\n\
     found: {3}\n\
     reason: {6}
+
+# 0: symbol kind, 1: name, 2: list of type
 compiler.err.cant.apply.symbols=\
     no suitable {0} found for {1}({2})
+
+# 0: symbol
 compiler.err.cant.assign.val.to.final.var=\
     cannot assign a value to final variable {0}
+
+# 0: type
 compiler.err.cant.deref=\
     {0} cannot be dereferenced
+
 compiler.err.cant.extend.intf.annotation=\
     ''extends'' not allowed for @interfaces
+
+# 0: symbol
 compiler.err.cant.inherit.from.final=\
     cannot inherit from final {0}
+
+# 0: symbol
 compiler.err.cant.ref.before.ctor.called=\
     cannot reference {0} before supertype constructor has been called
+
 compiler.err.cant.ret.val.from.meth.decl.void=\
     cannot return a value from method whose result type is void
+
 compiler.err.cant.select.static.class.from.param.type=\
     cannot select a static class from a parameterized type
+
+# 0: symbol, 1: string, 2: string
 compiler.err.cant.inherit.diff.arg=\
     {0} cannot be inherited with different arguments: <{1}> and <{2}>
+
 compiler.err.catch.without.try=\
     ''catch'' without ''try''
+
+# 0: symbol kind, 1: symbol
 compiler.err.clash.with.pkg.of.same.name=\
     {0} {1} clashes with package of same name
+
 compiler.err.const.expr.req=\
     constant expression required
+
 compiler.err.cont.outside.loop=\
     continue outside of loop
+
+# 0: symbol
 compiler.err.cyclic.inheritance=\
     cyclic inheritance involving {0}
+
 compiler.err.cyclic.annotation.element=\
     cyclic annotation element type
+
+# 0: unused
 compiler.err.call.to.super.not.allowed.in.enum.ctor=\
     call to super not allowed in enum constructor
+
+# 0: type
 compiler.err.no.superclass=\
     {0} has no superclass
 
 compiler.err.wrong.target.for.polymorphic.signature.definition=\
     MethodHandle API building requires -target 7 runtimes or better; current is -target {0}
 
+# 0: symbol, 1: type, 2: symbol, 3: type, 4: unused
 compiler.err.concrete.inheritance.conflict=\
     methods {0} from {1} and {2} from {3} are inherited with the same signature
 
 compiler.err.default.allowed.in.intf.annotation.member=\
     default value only allowed in an @interface member
+
+# 0: symbol
 compiler.err.doesnt.exist=\
     package {0} does not exist
+
 compiler.err.duplicate.annotation=\
     duplicate annotation
+
+# 0: name, 1: type
 compiler.err.duplicate.annotation.member.value=\
     duplicate annotation member value {0} in {1}
+
+# 0: name
 compiler.err.duplicate.class=\
     duplicate class: {0}
+
 compiler.err.duplicate.case.label=\
     duplicate case label
+
 compiler.err.duplicate.default.label=\
     duplicate default label
 
 compiler.err.else.without.if=\
     ''else'' without ''if''
+
 compiler.err.empty.char.lit=\
     empty character literal
+
+# 0: symbol
 compiler.err.encl.class.required=\
     an enclosing instance that contains {0} is required
+
 compiler.err.enum.annotation.must.be.enum.constant=\
     an enum annotation value must be an enum constant
 
 compiler.err.enum.cant.be.instantiated=\
     enum types may not be instantiated
+
 compiler.err.enum.label.must.be.unqualified.enum=\
     an enum switch case label must be the unqualified name of an enumeration constant
+
 compiler.err.enum.no.subclassing=\
     classes cannot directly extend java.lang.Enum
+
 compiler.err.enum.types.not.extensible=\
     enum types are not extensible
+
 compiler.err.enum.no.finalize=\
     enums cannot have finalize methods
+
+# 0: file name, 1: string
 compiler.err.error.reading.file=\
     error reading {0}; {1}
+
+# 0: type
 compiler.err.except.already.caught=\
     exception {0} has already been caught
+
+# 0: type
 compiler.err.except.never.thrown.in.try=\
     exception {0} is never thrown in body of corresponding try statement
 
+# 0: symbol
 compiler.err.final.parameter.may.not.be.assigned=\
     final parameter {0} may not be assigned
+
+# 0: symbol
 compiler.err.try.resource.may.not.be.assigned=\
     auto-closeable resource {0} may not be assigned
+
 compiler.err.try.resource.trailing.semi=\
     illegal trailing semicolon in resources declaration
+
+# 0: symbol
 compiler.err.multicatch.parameter.may.not.be.assigned=\
     multi-catch parameter {0} may not be assigned
+
 compiler.err.finally.without.try=\
     ''finally'' without ''try''
+
+# 0: type, 1: message segment
 compiler.err.foreach.not.applicable.to.type=\
     for-each not applicable to expression type\n\
     required: {1}\n\
     found:    {0}
+
 compiler.err.fp.number.too.large=\
     floating point number too large
+
 compiler.err.fp.number.too.small=\
     floating point number too small
 
 compiler.err.generic.array.creation=\
     generic array creation
+
 compiler.err.generic.throwable=\
     a generic class may not extend java.lang.Throwable
 
+# 0: symbol
 compiler.err.icls.cant.have.static.decl=\
     Illegal static declaration in inner class {0}\n\
     modifier \''static\'' is only allowed in constant variable declarations
+
+# 0: string
 compiler.err.illegal.char=\
     illegal character: \\{0}
+
 compiler.err.illegal.char.for.encoding=\
     unmappable character for encoding {0}
+
+# 0: set of modifier, 1: set of modifier
 compiler.err.illegal.combination.of.modifiers=\
     illegal combination of modifiers: {0} and {1}
+
 compiler.err.illegal.enum.static.ref=\
     illegal reference to static field from initializer
+
 compiler.err.illegal.esc.char=\
     illegal escape character
+
 compiler.err.illegal.forward.ref=\
     illegal forward reference
+
+# 0: symbol
 compiler.warn.forward.ref=\
     reference to variable ''{0}'' before it has been initialized
+
 compiler.err.illegal.self.ref=\
     self-reference in initializer
+
+# 0: symbol
 compiler.warn.self.ref=\
     self-reference in initializer of variable ''{0}''
+
 compiler.err.illegal.generic.type.for.instof=\
     illegal generic type for instanceof
+
+# 0: type
 compiler.err.illegal.initializer.for.type=\
     illegal initializer for {0}
+
 compiler.err.illegal.line.end.in.char.lit=\
     illegal line end in character literal
+
 compiler.err.illegal.nonascii.digit=\
     illegal non-ASCII digit
+
 compiler.err.illegal.underscore=\
     illegal underscore
+
+# 0: symbol
 compiler.err.illegal.qual.not.icls=\
     illegal qualifier; {0} is not an inner class
+
 compiler.err.illegal.start.of.expr=\
     illegal start of expression
+
 compiler.err.illegal.start.of.type=\
     illegal start of type
+
 compiler.err.illegal.unicode.esc=\
     illegal unicode escape
+
+# 0: symbol
 compiler.err.import.requires.canonical=\
     import requires canonical name for {0}
+
 compiler.err.improperly.formed.type.param.missing=\
     improperly formed type, some parameters are missing
+
 compiler.err.improperly.formed.type.inner.raw.param=\
     improperly formed type, type arguments given on a raw type
+
+# 0: type, 1: type
 compiler.err.incomparable.types=\
     incomparable types: {0} and {1}
+
+# 0: number
 compiler.err.int.number.too.large=\
     integer number too large: {0}
+
 compiler.err.internal.error.cant.instantiate=\
     internal error; cannot instantiate {0} at {1} to ({2})
+
 compiler.err.intf.annotation.members.cant.have.params=\
     @interface members may not have parameters
+
 compiler.err.intf.annotation.cant.have.type.params=\
     @interface may not have type parameters
+
 compiler.err.intf.annotation.members.cant.have.type.params=\
     @interface members may not have type parameters
+
+# 0: symbol, 1: type
 compiler.err.intf.annotation.member.clash=\
     @interface member clashes with method ''{0}'' in {1}
+
 compiler.err.intf.expected.here=\
     interface expected here
+
 compiler.err.intf.meth.cant.have.body=\
     interface methods cannot have body
+
 compiler.err.invalid.annotation.member.type=\
     invalid type for annotation member
+
 compiler.err.invalid.binary.number=\
     binary numbers must contain at least one binary digit
+
 compiler.err.invalid.hex.number=\
     hexadecimal numbers must contain at least one hexadecimal digit
+
 compiler.err.invalid.meth.decl.ret.type.req=\
     invalid method declaration; return type required
+
 compiler.err.varargs.and.old.array.syntax=\
     legacy array notation not allowed on variable-arity parameter
 
+# 0: name
 compiler.err.label.already.in.use=\
     label {0} already in use
+
+# 0: symbol
 compiler.err.local.var.accessed.from.icls.needs.final=\
     local variable {0} is accessed from within inner class; needs to be declared final
+
 compiler.err.local.enum=\
     enum types must not be local
+
 compiler.err.cannot.create.array.with.type.arguments=\
     cannot create array with type arguments
 
@@ -287,79 +467,121 @@
 #
 compiler.err.limit.code=\
     code too large
+
 compiler.err.limit.code.too.large.for.try.stmt=\
     code too large for try statement
+
 compiler.err.limit.dimensions=\
     array type has too many dimensions
+
 compiler.err.limit.locals=\
     too many local variables
+
 compiler.err.limit.parameters=\
     too many parameters
+
 compiler.err.limit.pool=\
     too many constants
+
 compiler.err.limit.pool.in.class=\
     too many constants in class {0}
+
 compiler.err.limit.stack=\
     code requires too much stack
+
 compiler.err.limit.string=\
     constant string too long
+
 compiler.err.limit.string.overflow=\
     UTF8 representation for string \"{0}...\" is too long for the constant pool
 
 compiler.err.malformed.fp.lit=\
     malformed floating point literal
+
 compiler.err.method.does.not.override.superclass=\
     method does not override or implement a method from a supertype
+
 compiler.err.missing.meth.body.or.decl.abstract=\
     missing method body, or declare abstract
+
 compiler.err.missing.ret.stmt=\
     missing return statement
+
 compiler.err.missing.ret.val=\
     missing return value
+
+# 0: set of modifier
 compiler.err.mod.not.allowed.here=\
     modifier {0} not allowed here
+
 compiler.err.intf.not.allowed.here=\
     interface not allowed here
+
 compiler.err.enums.must.be.static=\
     enum declarations allowed only in static contexts
 
+# 0: symbol, 1: symbol
 compiler.err.name.clash.same.erasure=\
     name clash: {0} and {1} have the same erasure
+
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.err.name.clash.same.erasure.no.override=\
     name clash: {0} in {1} and {2} in {3} have the same erasure, yet neither overrides the other
+
 compiler.err.name.reserved.for.internal.use=\
     {0} is reserved for internal use
+
 compiler.err.native.meth.cant.have.body=\
     native methods cannot have a body
+
+# 0: type, 1: type
 compiler.err.neither.conditional.subtype=\
-incompatible types for ?: neither is a subtype of the other\n\
-second operand: {0}\n\
-third operand : {1}
+    incompatible types for ?: neither is a subtype of the other\n\
+    second operand: {0}\n\
+    third operand : {1}
+
 compiler.err.new.not.allowed.in.annotation=\
     ''new'' not allowed in an annotation
+
 compiler.err.no.annotation.member=\
     no annotation member {0} in {1}
+
 compiler.err.no.encl.instance.of.type.in.scope=\
     no enclosing instance of type {0} is in scope
+
 compiler.err.no.intf.expected.here=\
     no interface expected here
+
 compiler.err.no.match.entry=\
     {0} has no match in entry in {1}; required {2}
+
 compiler.err.not.annotation.type=\
     {0} is not an annotation type
+
+# 0: symbol, 1: symbol
 compiler.err.not.def.access.class.intf.cant.access=\
     {0} in {1} is defined in an inaccessible class or interface
+
+# 0: symbol, 1: symbol
 compiler.err.not.def.public.cant.access=\
     {0} is not public in {1}; cannot be accessed from outside package
+
+# 0: name
 compiler.err.not.loop.label=\
     not a loop label: {0}
+
 compiler.err.not.stmt=\
     not a statement
+
+# 0: symbol
 compiler.err.not.encl.class=\
     not an enclosing class: {0}
 
+# 0: name, 1: type, 2: unused
 compiler.err.operator.cant.be.applied=\
     bad operand type {1} for unary operator ''{0}''
+
+# 0: name, 1: type, 2: type
 compiler.err.operator.cant.be.applied.1=\
     bad operand types for binary operator ''{0}''\n\
     first type:  {1}\n\
@@ -367,6 +589,8 @@
 
 compiler.err.pkg.annotations.sb.in.package-info.java=\
     package annotations should be in file package-info.java
+
+# 0: symbol
 compiler.err.pkg.clashes.with.class.of.same.name=\
     package {0} clashes with class of same name
 
@@ -376,18 +600,21 @@
 # Errors related to annotation processing
 
 compiler.err.proc.cant.access=\
-cannot access {0}\n\
-{1}\n\
-Consult the following stack trace for details.\n\
-{2}
+    cannot access {0}\n\
+    {1}\n\
+    Consult the following stack trace for details.\n\
+    {2}
 
+# 0: string
 compiler.err.proc.cant.find.class=\
     Could not find class file for ''{0}''.
 
 # Print a client-generated error message; assumed to be localized, no translation required
+# 0: string
 compiler.err.proc.messager=\
     {0}
 
+# 0: list of string
 compiler.err.proc.no.explicit.annotation.processing.requested=\
     Class names, ''{0}'', are only accepted if annotation processing is explicitly requested
 
@@ -398,15 +625,18 @@
 compiler.err.proc.processor.bad.option.name=\
     Bad option name ''{0}'' provided by processor ''{1}''
 
+# 0: string
 compiler.err.proc.processor.cant.instantiate=\
     Could not instantiate an instance of processor ''{0}''
 
 compiler.err.proc.processor.constructor.error=\
     Exception thrown while constructing Processor object: {0}
 
+# 0: string
 compiler.err.proc.processor.not.found=\
     Annotation processor ''{0}'' not found
 
+# 0: string
 compiler.err.proc.processor.wrong.type=\
     Annotation processor ''{0}'' does not implement javax.annotation.processing.Processor
 
@@ -419,127 +649,197 @@
 compiler.err.proc.cant.create.loader=\
     Could not create class loader for annotation processors: {0}
 
+# 0: unused
 compiler.err.qualified.new.of.static.class=\
     qualified new of static class
 
 compiler.err.recursive.ctor.invocation=\
     recursive constructor invocation
+
+# 0: name, 1: symbol kind, 2: symbol, 3: symbol, 4: symbol kind, 5: symbol, 6: symbol
 compiler.err.ref.ambiguous=\
     reference to {0} is ambiguous, both {1} {2} in {3} and {4} {5} in {6} match
+
 compiler.err.repeated.annotation.target=\
     repeated annotation target
+
 compiler.err.repeated.interface=\
     repeated interface
+
 compiler.err.repeated.modifier=\
     repeated modifier
+
+# 0: symbol, 1: set of modifier, 2: symbol
 compiler.err.report.access=\
     {0} has {1} access in {2}
+
 compiler.err.ret.outside.meth=\
     return outside method
 
 compiler.err.signature.doesnt.match.supertype=\
     signature does not match {0}; incompatible supertype
+
 compiler.err.signature.doesnt.match.intf=\
     signature does not match {0}; incompatible interfaces
+
+# 0: symbol, 1: symbol, 2: symbol
 compiler.err.does.not.override.abstract=\
     {0} is not abstract and does not override abstract method {1} in {2}
+
 compiler.err.source.cant.overwrite.input.file=\
     error writing source; cannot overwrite input file {0}
+
 compiler.err.stack.sim.error=\
     Internal error: stack sim error on {0}
+
 compiler.err.static.imp.only.classes.and.interfaces=\
     static import only from classes and interfaces
+
 compiler.err.string.const.req=\
     constant string expression required
+
+# 0: symbol, 1: symbol
 compiler.err.synthetic.name.conflict=\
     the symbol {0} conflicts with a compiler-synthesized symbol in {1}
+
+# 0: symbol, 1: symbol
 compiler.warn.synthetic.name.conflict=\
     the symbol {0} conflicts with a compiler-synthesized symbol in {1}
 
 compiler.err.throws.not.allowed.in.intf.annotation=\
     throws clause not allowed in @interface members
+
 compiler.err.try.without.catch.or.finally=\
     ''try'' without ''catch'' or ''finally''
+
 compiler.err.try.without.catch.finally.or.resource.decls=\
     ''try'' without ''catch'', ''finally'' or resource declarations
+
+# 0: symbol
 compiler.err.type.doesnt.take.params=\
     type {0} does not take parameters
+
 compiler.err.type.var.cant.be.deref=\
     cannot select from a type variable
+
 compiler.err.type.var.may.not.be.followed.by.other.bounds=\
     a type variable may not be followed by other bounds
+
 compiler.err.type.var.more.than.once=\
     type variable {0} occurs more than once in result type of {1}; cannot be left uninstantiated
+
 compiler.err.type.var.more.than.once.in.result=\
     type variable {0} occurs more than once in type of {1}; cannot be left uninstantiated
+
+# 0: type, 1: type, 2: string
 compiler.err.types.incompatible.diff.ret=\
     types {0} and {1} are incompatible; both define {2}, but with unrelated return types
 
 compiler.err.unclosed.char.lit=\
     unclosed character literal
+
 compiler.err.unclosed.comment=\
     unclosed comment
+
 compiler.err.unclosed.str.lit=\
     unclosed string literal
+
 compiler.err.unknown.enum.constant=\
     in class file {0}: unknown enum constant {1}.{2}
+
+# 0: name
 compiler.err.unsupported.encoding=\
     unsupported encoding: {0}
+
 compiler.err.io.exception=\
     error reading source file: {0}
+
+# 0: name
 compiler.err.undef.label=\
     undefined label: {0}
+
 compiler.err.undetermined.type=\
     cannot infer type arguments for {0}
+
+# 0: type, 1: message segment
 compiler.err.undetermined.type.1=\
     cannot infer type arguments for {0};\n\
     reason: {1}
+
+# 0: list of type, 1: message segment
 compiler.err.invalid.inferred.types=\
     invalid inferred types for {0}; {1}
+
+# 0: message segment, 1: unused
 compiler.err.cant.apply.diamond=\
     cannot infer type arguments for {0}
+
+# 0: message segment, 1: message segment
 compiler.err.cant.apply.diamond.1=\
     cannot infer type arguments for {0};\n\
     reason: {1}
+
 compiler.err.unreachable.stmt=\
     unreachable statement
+
 compiler.err.initializer.must.be.able.to.complete.normally=\
     initializer must be able to complete normally
+
+# 0: type
 compiler.err.unreported.exception.need.to.catch.or.throw=\
     unreported exception {0}; must be caught or declared to be thrown
+
+# 0: type
 compiler.err.unreported.exception.default.constructor=\
     unreported exception {0} in default constructor
+
 compiler.err.unsupported.cross.fp.lit=\
     hexadecimal floating-point literals are not supported on this VM
+
 compiler.err.void.not.allowed.here=\
     ''void'' type not allowed here
 
+# 0: string
 compiler.err.wrong.number.type.args=\
     wrong number of type arguments; required {0}
 
+# 0: symbol
 compiler.err.var.might.already.be.assigned=\
     variable {0} might already have been assigned
+
+# 0: symbol
 compiler.err.var.might.not.have.been.initialized=\
     variable {0} might not have been initialized
+
+# 0: symbol
 compiler.err.var.might.be.assigned.in.loop=\
     variable {0} might be assigned in loop
 
+# 0: symbol, 1: message segment
 compiler.err.varargs.invalid.trustme.anno=\
     Invalid {0} annotation. {1}
+
+# 0: type
 compiler.misc.varargs.trustme.on.reifiable.varargs=\
     Varargs element type {0} is reifiable.
+
+# 0: symbol
 compiler.misc.varargs.trustme.on.non.varargs.meth=\
     Method {0} is not a varargs method.
+
+# 0: symbol
 compiler.misc.varargs.trustme.on.virtual.varargs=\
     Instance method {0} is not final.
 
 # In the following string, {1} will always be the detail message from
 # java.io.IOException.
+# 0: symbol, 1: string
 compiler.err.class.cant.write=\
     error while writing {0}: {1}
 
 # In the following string, {0} is the name of the class in the Java source.
 # It really should be used two times..
+# 0: name
 compiler.err.class.public.should.be.in.file=\
     class {0} is public, should be declared in a file named {0}.java
 
@@ -558,12 +858,16 @@
 
 compiler.misc.fatal.err.no.java.lang=\
     Fatal Error: Unable to find package java.lang in classpath or bootclasspath
+
 compiler.misc.fatal.err.cant.locate.meth=\
     Fatal Error: Unable to find method {0}
+
 compiler.misc.fatal.err.cant.locate.field=\
     Fatal Error: Unable to find field {0}
+
 compiler.misc.fatal.err.cant.locate.ctor=\
     Fatal Error: Unable to find constructor for {0}
+
 compiler.misc.fatal.err.cant.close.loader=\
     Fatal Error: Cannot close class loader for annotation processors
 
@@ -575,10 +879,15 @@
 
 compiler.misc.source.unavailable=\
     (source unavailable)
+
 compiler.misc.base.membership=\
     all your base class are belong to us
+
+# 0: string, 1: string, 2: boolean
 compiler.misc.x.print.processor.info=\
     Processor {0} matches {1} and returns {2}.
+
+# 0: number, 1: string, 2: set of symbol, 3: boolean
 compiler.misc.x.print.rounds=\
     Round {0}:\n\tinput files: {1}\n\tannotations: {2}\n\tlast round: {3}
 
@@ -589,61 +898,84 @@
 compiler.note.note=\
     Note:\u0020
 
+# 0: file name
 compiler.note.deprecated.filename=\
     {0} uses or overrides a deprecated API.
+
 compiler.note.deprecated.plural=\
     Some input files use or override a deprecated API.
+
 # The following string may appear after one of the above deprecation
 # messages.
 compiler.note.deprecated.recompile=\
     Recompile with -Xlint:deprecation for details.
 
+# 0: file name
 compiler.note.deprecated.filename.additional=\
     {0} has additional uses or overrides of a deprecated API.
+
 compiler.note.deprecated.plural.additional=\
     Some input files additionally use or override a deprecated API.
 
+# 0: file name
 compiler.note.unchecked.filename=\
     {0} uses unchecked or unsafe operations.
+
 compiler.note.unchecked.plural=\
     Some input files use unchecked or unsafe operations.
+
 # The following string may appear after one of the above deprecation
 # messages.
 compiler.note.unchecked.recompile=\
     Recompile with -Xlint:unchecked for details.
 
+# 0: file name
 compiler.note.unchecked.filename.additional=\
     {0} has additional unchecked or unsafe operations.
+
 compiler.note.unchecked.plural.additional=\
     Some input files additionally use unchecked or unsafe operations.
 
+# 0: file name
 compiler.note.sunapi.filename=\
     {0} uses internal proprietary API that may be removed in a future release.
+
 compiler.note.sunapi.plural=\
     Some input files use internal proprietary API that may be removed in a future release.
+
 # The following string may appear after one of the above sunapi messages.
 compiler.note.sunapi.recompile=\
     Recompile with -Xlint:sunapi for details.
 
+# 0: file name
 compiler.note.sunapi.filename.additional=\
     {0} uses additional internal proprietary API that may be removed in a future release.
+
 compiler.note.sunapi.plural.additional=\
     Some input files additionally use internal proprietary API that may be removed in a future release.
 
 # Notes related to annotation processing
 
 # Print a client-generated note; assumed to be localized, no translation required
+# 0: string
 compiler.note.proc.messager=\
     {0}
 
 #####
 
+# 0: number
 compiler.misc.count.error=\
     {0} error
+
+# 0: number
 compiler.misc.count.error.plural=\
     {0} errors
+
+# 0: number
 compiler.misc.count.warn=\
     {0} warning
+
+# 0: number
 compiler.misc.count.warn.plural=\
     {0} warnings
 
@@ -652,38 +984,53 @@
 
 ## extra output when using -verbose (JavaCompiler)
 
+# 0: symbol
 compiler.misc.verbose.checking.attribution=\
     [checking {0}]
+
+# 0: string
 compiler.misc.verbose.parsing.done=\
     [parsing completed {0}ms]
+
+# 0: file name
 compiler.misc.verbose.parsing.started=\
     [parsing started {0}]
+
+# 0: string
 compiler.misc.verbose.total=\
     [total {0}ms]
+
+# 0: file name
 compiler.misc.verbose.wrote.file=\
     [wrote {0}]
 
 ## extra output when using -verbose (Retro)
 compiler.misc.verbose.retro=\
     [retrofitting {0}]
+
 compiler.misc.verbose.retro.with=\
     \tretrofitting {0} with {1}
+
 compiler.misc.verbose.retro.with.list=\
     \tretrofitting {0} with type parameters {1}, supertype {2}, interfaces {3}
 
 ## extra output when using -verbose (code/ClassReader)
+# 0: string
 compiler.misc.verbose.loading=\
     [loading {0}]
 
+# 0: string
 compiler.misc.verbose.sourcepath=\
     [search path for source files: {0}]
 
+# 0: string
 compiler.misc.verbose.classpath=\
     [search path for class files: {0}]
 
 ## extra output when using -checkclassfile (code/ClassReader)
 compiler.misc.ccf.found.later.version=\
     class file has later version than expected: {0}
+
 compiler.misc.ccf.unrecognized.attribute=\
     unrecognized attribute: {0}
 
@@ -703,103 +1050,135 @@
 
 ## Warning messages may also include the following prefix to identify a
 ## lint option
+# 0: option name
 compiler.warn.lintOption=\
     [{0}]\u0020
 
+# 0: symbol
 compiler.warn.constant.SVUID=\
     serialVersionUID must be constant in class {0}
 
+# 0: file name
 compiler.warn.dir.path.element.not.found=\
     bad path element "{0}": no such directory
 
 compiler.warn.finally.cannot.complete=\
     finally clause cannot complete normally
 
+# 0: symbol, 1: symbol
 compiler.warn.has.been.deprecated=\
     {0} in {1} has been deprecated
 
+# 0: symbol
 compiler.warn.sun.proprietary=\
     {0} is internal proprietary API and may be removed in a future release
 
 compiler.warn.illegal.char.for.encoding=\
     unmappable character for encoding {0}
 
+# 0: symbol
 compiler.warn.improper.SVUID=\
     serialVersionUID must be declared static final in class {0}
 
+# 0: type, 1: type
 compiler.warn.inexact.non-varargs.call=\
-non-varargs call of varargs method with inexact argument type for last parameter;\n\
-cast to {0} for a varargs call\n\
-cast to {1} for a non-varargs call and to suppress this warning
+    non-varargs call of varargs method with inexact argument type for last parameter;\n\
+    cast to {0} for a varargs call\n\
+    cast to {1} for a non-varargs call and to suppress this warning
 
+# 0: symbol
 compiler.warn.long.SVUID=\
     serialVersionUID must be of type long in class {0}
 
+# 0: symbol
 compiler.warn.missing.SVUID=\
     serializable class {0} has no definition of serialVersionUID
 
+# 0: message segment
 compiler.warn.override.varargs.missing=\
     {0}; overridden method has no ''...''
+
+# 0: message segment
 compiler.warn.override.varargs.extra=\
     {0}; overriding method is missing ''...''
+
 compiler.warn.override.bridge=\
     {0}; overridden method is a bridge method
 
+# 0: symbol
 compiler.warn.pkg-info.already.seen=\
     a package-info.java file has already been seen for package {0}
 
+# 0: file name
 compiler.warn.path.element.not.found=\
     bad path element "{0}": no such file or directory
 
 compiler.warn.possible.fall-through.into.case=\
     possible fall-through into case
 
+# 0: type
 compiler.warn.redundant.cast=\
     redundant cast to {0}
 
+# 0: number
 compiler.warn.position.overflow=\
     Position encoding overflows at line {0}
 
+# 0: file name, 1: number, 2: number
 compiler.warn.big.major.version=\
     {0}: major version {1} is newer than {2}, the highest major version supported by this compiler.\n\
     It is recommended that the compiler be upgraded.
 
+# 0: symbol kind, 1: symbol
 compiler.warn.static.not.qualified.by.type=\
     static {0} should be qualified by type name, {1}, instead of by an expression
 
+# 0: string
 compiler.warn.source.no.bootclasspath=\
     bootstrap class path not set in conjunction with -source {0}
 
+# 0: name, 1: number, 2: number, 3: number, 4: number
 compiler.warn.future.attr=\
     {0} attribute introduced in version {1}.{2} class files is ignored in version {3}.{4} class files
 
 # Warnings related to annotation processing
+# 0: name
 compiler.warn.proc.package.does.not.exist=\
     package {0} does not exist
+
+# 0: name
 compiler.warn.proc.file.reopening=\
     Attempt to create a file for ''{0}'' multiple times
 
+# 0: name
 compiler.warn.proc.type.already.exists=\
     A file for type ''{0}'' already exists on the sourcepath or classpath
 
+# 0: name
 compiler.warn.proc.type.recreate=\
     Attempt to create a file for type ''{0}'' multiple times
 
+# 0: string
 compiler.warn.proc.illegal.file.name=\
     Cannot create file for illegal name ''{0}''.
 
+# 0: string, 1: string
 compiler.warn.proc.suspicious.class.name=\
     Creating file for a type whose name ends in {1}: ''{0}''
 
+# 0: name
 compiler.warn.proc.file.create.last.round=\
     File for type ''{0}'' created in the last round will not be subject to annotation processing.
 
+# 0: string, 1: string
 compiler.warn.proc.malformed.supported.string=\
     Malformed string ''{0}'' for a supported annotation type returned by processor ''{1}''
 
+# 0: set of string
 compiler.warn.proc.annotations.without.processors=\
     No processor claimed any of these annotations: {0}
 
+# 0: source version, 1: string, 2: string
 compiler.warn.proc.processor.incompatible.source.version=\
     Supported source version ''{0}'' from annotation processor ''{1}'' less than -source ''{2}''
 
@@ -807,46 +1186,62 @@
     Annotation processing without compilation requested but no processors were found.
 
 compiler.warn.proc.use.implicit=\
-Implicitly compiled files were not subject to annotation processing.\n\
-Use -implicit to specify a policy for implicit compilation.
+    Implicitly compiled files were not subject to annotation processing.\n\
+    Use -implicit to specify a policy for implicit compilation.
 
 compiler.warn.proc.use.proc.or.implicit=\
-Implicitly compiled files were not subject to annotation processing.\n\
-Use -proc:none to disable annotation processing or -implicit to specify a policy for implicit compilation.
+    Implicitly compiled files were not subject to annotation processing.\n\
+    Use -proc:none to disable annotation processing or -implicit to specify a policy for implicit compilation.
 
 # Print a client-generated warning; assumed to be localized, no translation required
+# 0: string
 compiler.warn.proc.messager=\
     {0}
 
+# 0: set of name
 compiler.warn.proc.unclosed.type.files=\
     Unclosed files for the types ''{0}''; these types will not undergo annotation processing
 
+# 0: string
 compiler.warn.proc.unmatched.processor.options=\
     The following options were not recognized by any processor: ''{0}''
 
 compiler.warn.try.explicit.close.call=\
     explicit call to close() on an auto-closeable resource
+
+# 0: symbol
 compiler.warn.try.resource.not.referenced=\
     auto-closeable resource {0} is never referenced in body of corresponding try statement
+
 compiler.warn.unchecked.assign=\
     unchecked assignment: {0} to {1}
+
+# 0: symbol, 1: type
 compiler.warn.unchecked.assign.to.var=\
     unchecked assignment to variable {0} as member of raw type {1}
+
+# 0: symbol, 1: type
 compiler.warn.unchecked.call.mbr.of.raw.type=\
     unchecked call to {0} as a member of the raw type {1}
+
 compiler.warn.unchecked.cast.to.type=\
     unchecked cast to type {0}
+
+# 0: symbol kind, 1: name, 2: list of type, 3: list of type, 4: symbol kind, 5: symbol
 compiler.warn.unchecked.meth.invocation.applied=\
     unchecked method invocation: {0} {1} in {4} {5} is applied to given types\n\
     required: {2}\n\
     found: {3}
 
+# 0: type
 compiler.warn.unchecked.generic.array.creation=\
     unchecked generic array creation for varargs parameter of type {0}
 
+# 0: type
 compiler.warn.unchecked.varargs.non.reifiable.type=\
     Possible heap pollution from parameterized vararg type {0}
 
+# 0: symbol
 compiler.warn.varargs.unsafe.use.varargs.param=\
     Varargs method could cause heap pollution from non-reifiable varargs parameter {0}
 
@@ -871,17 +1266,22 @@
 compiler.warn.annotation.method.not.found.reason=\
     Cannot find annotation method ''{1}()'' in type ''{0}'': {2}
 
+# 0: type, 1: type
 compiler.warn.raw.class.use=\
     found raw type: {0}\n\
     missing type arguments for generic class {1}
 
+# 0: unused, 1: unused
 compiler.warn.diamond.redundant.args=\
     redundant type arguments in new expression (use diamond operator instead).
+
+# 0: type, 1: type
 compiler.warn.diamond.redundant.args.1=\
     redundant type arguments in new expression (use diamond operator instead).\n\
     explicit: {0}\n\
     inferred: {1}
 
+# 0: symbol, 1: message segment
 compiler.warn.varargs.redundant.trustme.anno=\
     Redundant {0} annotation. {1}
 
@@ -891,20 +1291,28 @@
 ## be named as JLS3 calls them when translated to the appropriate language.
 compiler.misc.token.identifier=\
     <identifier>
+
 compiler.misc.token.character=\
     <character>
+
 compiler.misc.token.string=\
     <string>
+
 compiler.misc.token.integer=\
     <integer>
+
 compiler.misc.token.long-integer=\
     <long integer>
+
 compiler.misc.token.float=\
     <float>
+
 compiler.misc.token.double=\
     <double>
+
 compiler.misc.token.bad-symbol=\
     <bad symbol>
+
 compiler.misc.token.end-of-input=\
     <end of input>
 
@@ -917,10 +1325,15 @@
 ## 6. an operator (JLS3.12)
 ##
 ## This is the only place these tokens will be used.
+# 0: token
 compiler.err.expected=\
     {0} expected
+
+# 0: token, 1: token
 compiler.err.expected2=\
     {0} or {1} expected
+
+# 0: token, 1: token, 2: token
 compiler.err.expected3=\
     {0}, {1}, or {2} expected
 
@@ -932,12 +1345,15 @@
     ''.class'' expected
 
 ## The argument to this string will always be either 'case' or 'default'.
+# 0: token
 compiler.err.orphaned=\
     orphaned {0}
 
+# 0: name
 compiler.misc.anonymous.class=\
     <anonymous {0}>
 
+# 0: name, 1: type
 compiler.misc.type.captureof=\
     capture#{0} of {1}
 
@@ -952,54 +1368,73 @@
 
 #####
 
+# 0: symbol, 1: message segment
 compiler.err.cant.access=\
-cannot access {0}\n\
-{1}
+    cannot access {0}\n\
+    {1}
 
 compiler.misc.bad.class.file.header=\
-bad class file: {0}\n\
-{1}\n\
-Please remove or make sure it appears in the correct subdirectory of the classpath.
+    bad class file: {0}\n\
+    {1}\n\
+    Please remove or make sure it appears in the correct subdirectory of the classpath.
+
+# 0: file name, 1: message segment
 compiler.misc.bad.source.file.header=\
-bad source file: {0}\n\
-{1}\n\
-Please remove or make sure it appears in the correct subdirectory of the sourcepath.
+    bad source file: {0}\n\
+    {1}\n\
+    Please remove or make sure it appears in the correct subdirectory of the sourcepath.
 
 ## The following are all possible strings for the second argument ({1}) of the
 ## above strings.
 compiler.misc.bad.class.signature=\
     bad class signature: {0}
+
 compiler.misc.bad.enclosing.method=\
     bad enclosing method attribute: {0}
+
 compiler.misc.bad.runtime.invisible.param.annotations=\
     bad RuntimeInvisibleParameterAnnotations attribute: {0}
+
 compiler.misc.bad.const.pool.tag=\
     bad constant pool tag: {0}
+
 compiler.misc.bad.const.pool.tag.at=\
     bad constant pool tag: {0} at {1}
+
 compiler.misc.bad.signature=\
     bad signature: {0}
+
 compiler.misc.class.file.wrong.class=\
     class file contains wrong class: {0}
+
 compiler.misc.class.file.not.found=\
     class file for {0} not found
+
+# 0: name
 compiler.misc.file.doesnt.contain.class=\
     file does not contain class {0}
+
 compiler.misc.file.does.not.contain.package=\
     file does not contain package {0}
+
 compiler.misc.illegal.start.of.class.file=\
     illegal start of class file
+
 compiler.misc.unable.to.access.file=\
     unable to access file: {0}
+
 compiler.misc.unicode.str.not.supported=\
     unicode string in class file not supported
+
 compiler.misc.undecl.type.var=\
     undeclared type variable: {0}
+
 compiler.misc.wrong.version=\
     class file has wrong version {0}.{1}, should be {2}.{3}
 
 #####
 
+# 0: type, 1: type or symbol
 compiler.err.not.within.bounds=\
     type argument {0} is not within bounds of type-variable {1}
 
@@ -1010,32 +1445,41 @@
 
 #####
 
+# 0: message segment, 1: type, 2: type
 compiler.err.prob.found.req=\
-{0}\n\
-required: {2}\n\
-found:    {1}
+    {0}\n\
+    required: {2}\n\
+    found:    {1}
+
+# 0: message segment, 1: type, 2: type
 compiler.warn.prob.found.req=\
-{0}\n\
-required: {2}\n\
-found:    {1}
+    {0}\n\
+    required: {2}\n\
+    found:    {1}
+
 compiler.err.prob.found.req.1=\
-{0} {3}\n\
-required: {2}\n\
-found:    {1}
+    {0} {3}\n\
+    required: {2}\n\
+    found:    {1}
 
 ## The following are all possible strings for the first argument ({0}) of the
 ## above strings.
 compiler.misc.incompatible.types=\
     incompatible types
+
+# 0: message segment
 compiler.misc.incompatible.types.1=\
     incompatible types; {0}
+
 compiler.misc.inconvertible.types=\
     inconvertible types
+
 compiler.misc.possible.loss.of.precision=\
     possible loss of precision
 
 compiler.misc.unchecked.assign=\
     unchecked conversion
+
 # compiler.misc.storecheck=\
 #     assignment might cause later store checks to fail
 # compiler.misc.unchecked=\
@@ -1045,8 +1489,10 @@
 
 compiler.misc.assignment.from.super-bound=\
     assignment from super-bound type {0}
+
 compiler.misc.assignment.to.extends-bound=\
     assignment to extends-bound type {0}
+
 # compiler.err.star.expected=\
 #     ''*'' expected
 # compiler.err.no.elem.type=\
@@ -1057,23 +1503,30 @@
 
 #####
 
+# 0: message segment or type, 1: message segment
 compiler.err.type.found.req=\
-unexpected type\n\
-required: {1}\n\
-found:    {0}
+    unexpected type\n\
+    required: {1}\n\
+    found:    {0}
 
 ## The following are all possible strings for the first argument ({0}) of the
 ## above string.
 compiler.misc.type.req.class=\
     class
+
 compiler.misc.type.req.class.array=\
     class or array
+
 compiler.misc.type.req.array.or.iterable=\
     array or java.lang.Iterable
+
 compiler.misc.type.req.ref=\
     reference
+
 compiler.misc.type.req.exact=\
     class or interface without bounds
+
+# 0: type
 compiler.misc.type.parameter=\
     type parameter {0}
 
@@ -1083,87 +1536,119 @@
 ## diagnostics whose key ends in ".1"
 compiler.misc.undetermined.type=\
     undetermined type
+
 compiler.misc.type.variable.has.undetermined.type=\
     type variable {0} has undetermined type
+
+# 0: type, 1: list of type
 compiler.misc.no.unique.maximal.instance.exists=\
     no unique maximal instance exists for type variable {0} with upper bounds {1}
+
 compiler.misc.no.unique.minimal.instance.exists=\
     no unique minimal instance exists for type variable {0} with lower bounds {1}
+
+# 0: list of type, 1: type, 2: type
 compiler.misc.infer.no.conforming.instance.exists=\
     no instance(s) of type variable(s) {0} exist so that {1} conforms to {2}
+
+# 0: list of type, 1: type, 2: type
 compiler.misc.infer.no.conforming.assignment.exists=\
     no instance(s) of type variable(s) {0} exist so that argument type {1} conforms to formal parameter type {2}
+
 compiler.misc.infer.arg.length.mismatch=\
     cannot instantiate from arguments because actual and formal argument lists differ in length
+
+# 0: type, 1: list of type
 compiler.misc.inferred.do.not.conform.to.bounds=\
     inferred type does not conform to declared bound(s)\n\
     inferred: {0}\n\
     bound(s): {1}
+
 compiler.misc.inferred.do.not.conform.to.params=\
     actual arguments do not conform to inferred formal arguments\n\
     required: {0}\n\
     found: {1}
+
+# 0: symbol
 compiler.misc.diamond=\
     {0}<>
+
+# 0: list of type, 1: message segment
 compiler.misc.diamond.invalid.arg=\
     type argument {0} inferred for {1} is not allowed in this context
+
+# 0: list of type, 1: message segment
 compiler.misc.diamond.invalid.args=\
     type arguments {0} inferred for {1} are not allowed in this context
 
+# 0: type, 1: list of type
 compiler.misc.explicit.param.do.not.conform.to.bounds=\
     explicit type argument {0} does not conform to declared bound(s) {1}
 
 compiler.misc.arg.length.mismatch=\
     actual and formal argument lists differ in length
+
+# 0: type, 1: type
 compiler.misc.no.conforming.assignment.exists=\
     actual argument {0} cannot be converted to {1} by method invocation conversion
+
+# 0: type, 1: type
 compiler.misc.varargs.argument.mismatch=\
     argument type {0} does not conform to vararg element type {1}
+
 #####
 
 ## The first argument ({0}) is a "kindname".
+# 0: symbol kind, 1: symbol, 2: symbol
 compiler.err.abstract.cant.be.accessed.directly=\
     abstract {0} {1} in {2} cannot be accessed directly
 
 ## The first argument ({0}) is a "kindname".
+# 0: symbol kind, 1: symbol
 compiler.err.non-static.cant.be.ref=\
     non-static {0} {1} cannot be referenced from a static context
 
 ## Both arguments ({0}, {1}) are "kindname"s.  {0} is a comma-separated list
 ## of kindnames (the list should be identical to that provided in source.
 compiler.err.unexpected.type=\
-unexpected type\n\
-required: {0}\n\
-found:    {1}
+    unexpected type\n\
+    required: {0}\n\
+    found:    {1}
 
 ## The first argument {0} is a "kindname" (e.g. 'constructor', 'field', etc.)
 ## The second argument {1} is the non-resolved symbol
 ## The third argument {2} is a list of type parameters (non-empty if {1} is a method)
 ## The fourth argument {3} is a list of argument types (non-empty if {1} is a method)
+# 0: symbol kind, 1: name, 2: unused, 3: unused
 compiler.err.cant.resolve=\
     cannot find symbol\n\
     symbol: {0} {1}
 
+# 0: symbol kind, 1: name, 2: unused, 3: list of type
 compiler.err.cant.resolve.args=\
     cannot find symbol\n\
     symbol: {0} {1}({3})
 
+# 0: symbol kind, 1: name, 2: list of type, 3: list of type
 compiler.err.cant.resolve.args.params=\
     cannot find symbol\n\
     symbol: {0} <{2}>{1}({3})
 
 ## arguments from {0} to {3} have the same meaning as above
 ## The fifth argument {4} is a location subdiagnostic (see below)
+# 0: symbol kind, 1: name, 2: unused, 3: unused, 4: message segment
 compiler.err.cant.resolve.location=\
     cannot find symbol\n\
     symbol:   {0} {1}\n\
     location: {4}
 
+# 0: symbol kind, 1: name, 2: unused, 3: list of type, 4: message segment
 compiler.err.cant.resolve.location.args=\
     cannot find symbol\n\
     symbol:   {0} {1}({3})\n\
     location: {4}
 
+# 0: symbol kind, 1: name, 2: list of type, 3: list, 4: message segment
 compiler.err.cant.resolve.location.args.params=\
     cannot find symbol\n\
     symbol:   {0} <{2}>{1}({3})\n\
@@ -1174,8 +1659,11 @@
 ## The second argument {1} is the location name
 ## The third argument {2} is the location type (only when {1} is a variable name)
 
+# 0: symbol kind, 1: symbol, 2: unused
 compiler.misc.location=\
     {0} {1}
+
+# 0: symbol kind, 1: symbol, 2: type
 compiler.misc.location.1=\
     {0} {1} of type {2}
 
@@ -1186,85 +1674,124 @@
 #     static member
 compiler.misc.kindname.annotation=\
     @interface
+
 compiler.misc.kindname.constructor=\
     constructor
+
 compiler.misc.kindname.enum=\
     enum
+
 compiler.misc.kindname.interface=\
     interface
+
 compiler.misc.kindname.static=\
     static
+
 compiler.misc.kindname.type.variable=\
     type variable
+
 compiler.misc.kindname.type.variable.bound=\
     bound of type variable
+
 compiler.misc.kindname.variable=\
     variable
+
 compiler.misc.kindname.value=\
     value
+
 compiler.misc.kindname.method=\
     method
+
 compiler.misc.kindname.class=\
     class
+
 compiler.misc.kindname.package=\
     package
+
 #####
 
 compiler.misc.no.args=\
     no arguments
 
+# 0: message segment
 compiler.err.override.static=\
     {0}\n\
     overriding method is static
+
+# 0: message segment, 1: set of modifier
 compiler.err.override.meth=\
     {0}\n\
     overridden method is {1}
 
+# 0: message segment, 1: type
 compiler.err.override.meth.doesnt.throw=\
     {0}\n\
     overridden method does not throw {1}
 
 # In the following string {1} is a space separated list of Java Keywords, as
 # they would have been declared in the source code
+# 0: message segment, 1: set of modifier
 compiler.err.override.weaker.access=\
     {0}\n\
     attempting to assign weaker access privileges; was {1}
 
+# 0: message segment, 1: type, 2: type
 compiler.err.override.incompatible.ret=\
     {0}\n\
     return type {1} is not compatible with {2}
 
+# 0: message segment, 1: type, 2: type
 compiler.warn.override.unchecked.ret=\
     {0}\n\
     return type requires unchecked conversion from {1} to {2}
 
+# 0: message segment, 1: type
 compiler.warn.override.unchecked.thrown=\
     {0}\n\
     overridden method does not throw {1}
 
 ## The following are all possible strings for the first argument ({0}) of the
 ## above strings.
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.misc.cant.override=\
     {0} in {1} cannot override {2} in {3}
+
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.misc.cant.implement=\
     {0} in {1} cannot implement {2} in {3}
+
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.misc.clashes.with=\
     {0} in {1} clashes with {2} in {3}
+
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.misc.unchecked.override=\
     {0} in {1} overrides {2} in {3}
+
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.misc.unchecked.implement=\
     {0} in {1} implements {2} in {3}
+
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.misc.unchecked.clash.with=\
     {0} in {1} overrides {2} in {3}
+
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.misc.varargs.override=\
     {0} in {1} overrides {2} in {3}
+
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.misc.varargs.implement=\
     {0} in {1} implements {2} in {3}
+
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.misc.varargs.clash.with=\
     {0} in {1} overrides {2} in {3}
+
 compiler.misc.non.denotable.type=\
     Non-denotable type {0} not allowed here
 
+# 0: symbol kind, 1: symbol, 2: symbol, 3: message segment
 compiler.misc.inapplicable.method=\
     {0} {1}.{2} is not applicable\n\
     ({3})
@@ -1272,77 +1799,90 @@
 ########################################
 # Diagnostics for language feature changes
 ########################################
+# 0: string
 compiler.err.unsupported.fp.lit=\
     hexadecimal floating point literals are not supported in -source {0}\n\
-(use -source 5 or higher to enable hexadecimal floating point literals)
+    (use -source 5 or higher to enable hexadecimal floating point literals)
 
+# 0: string
 compiler.err.unsupported.binary.lit=\
     binary literals are not supported in -source {0}\n\
-(use -source 7 or higher to enable binary literals)
+    (use -source 7 or higher to enable binary literals)
 
+# 0: string
 compiler.err.unsupported.underscore.lit=\
     underscores in literals are not supported in -source {0}\n\
-(use -source 7 or higher to enable underscores in literals)
+    (use -source 7 or higher to enable underscores in literals)
 
+# 0: string
 compiler.err.try.with.resources.not.supported.in.source=\
     try-with-resources is not supported in -source {0}\n\
-(use -source 7 or higher to enable try-with-resources)
+    (use -source 7 or higher to enable try-with-resources)
 
 compiler.warn.enum.as.identifier=\
     as of release 5, ''enum'' is a keyword, and may not be used as an identifier\n\
-(use -source 5 or higher to use ''enum'' as a keyword)
+    (use -source 5 or higher to use ''enum'' as a keyword)
 
 compiler.warn.assert.as.identifier=\
     as of release 1.4, ''assert'' is a keyword, and may not be used as an identifier\n\
-(use -source 1.4 or higher to use ''assert'' as a keyword)
+    (use -source 1.4 or higher to use ''assert'' as a keyword)
 
 compiler.err.enum.as.identifier=\
     as of release 5, ''enum'' is a keyword, and may not be used as an identifier\n\
-(use -source 1.4 or lower to use ''enum'' as an identifier)
+    (use -source 1.4 or lower to use ''enum'' as an identifier)
 
 compiler.err.assert.as.identifier=\
     as of release 1.4, ''assert'' is a keyword, and may not be used as an identifier\n\
-(use -source 1.3 or lower to use ''assert'' as an identifier)
+    (use -source 1.3 or lower to use ''assert'' as an identifier)
 
+# 0: string
 compiler.err.generics.not.supported.in.source=\
     generics are not supported in -source {0}\n\
-(use -source 5 or higher to enable generics)
+    (use -source 5 or higher to enable generics)
 
+# 0: string
 compiler.err.varargs.not.supported.in.source=\
     variable-arity methods are not supported in -source {0}\n\
-(use -source 5 or higher to enable variable-arity methods)
+    (use -source 5 or higher to enable variable-arity methods)
 
+# 0: string
 compiler.err.annotations.not.supported.in.source=\
     annotations are not supported in -source {0}\n\
-(use -source 5 or higher to enable annotations)
+    (use -source 5 or higher to enable annotations)
 
 #308 compiler.err.type.annotations.not.supported.in.source=\
 #308     type annotations are not supported in -source {0}\n\
 #308 (use -source 7 or higher to enable type annotations)
 
+# 0: string
 compiler.err.foreach.not.supported.in.source=\
     for-each loops are not supported in -source {0}\n\
-(use -source 5 or higher to enable for-each loops)
+    (use -source 5 or higher to enable for-each loops)
 
+# 0: string
 compiler.err.static.import.not.supported.in.source=\
     static import declarations are not supported in -source {0}\n\
-(use -source 5 or higher to enable static import declarations)
+    (use -source 5 or higher to enable static import declarations)
 
+# 0: string
 compiler.err.enums.not.supported.in.source=\
     enums are not supported in -source {0}\n\
-(use -source 5 or higher to enable enums)
+    (use -source 5 or higher to enable enums)
 
+# 0: string
 compiler.err.diamond.not.supported.in.source=\
     diamond operator is not supported in -source {0}\n\
-(use -source 7 or higher to enable diamond operator)
+    (use -source 7 or higher to enable diamond operator)
 
+# 0: string
 compiler.err.multicatch.not.supported.in.source=\
     multi-catch statement is not supported in -source {0}\n\
-(use -source 7 or higher to enable multi-catch statement)
+    (use -source 7 or higher to enable multi-catch statement)
 
+# 0: string
 compiler.err.string.switch.not.supported.in.source=\
     strings in switch are not supported in -source {0}\n\
-(use -source 7 or higher to enable strings in switch)
+    (use -source 7 or higher to enable strings in switch)
 
 ########################################
 # Diagnostics for where clause implementation
@@ -1353,29 +1893,35 @@
     <null>
 
 # X#n (where n is an int id) is disambiguated tvar name
+# 0: name, 1: number
 compiler.misc.type.var=\
     {0}#{1}
 
 # CAP#n (where n is an int id) is an abbreviation for 'captured type'
+# 0: number
 compiler.misc.captured.type=\
     CAP#{0}
 
 # <INT#n> (where n is an int id) is an abbreviation for 'intersection type'
+# 0: number
 compiler.misc.intersection.type=\
     INT#{0}
 
 # where clause for captured type: contains upper ('extends {1}') and lower
 # ('super {2}') bound along with the wildcard that generated this captured type ({3})
+# 0: type, 1: type, 2: type, 3: type
 compiler.misc.where.captured=\
     {0} extends {1} super: {2} from capture of {3}
 
 # compact where clause for captured type: contains upper ('extends {1}') along
 # with the wildcard that generated this captured type ({3})
+# 0: type, 1: type, 2: unused, 3: type
 compiler.misc.where.captured.1=\
     {0} extends {1} from capture of {3}
 
 # where clause for type variable: contains upper bound(s) ('extends {1}') along with
 # the kindname ({2}) and location ({3}) in which the typevar has been declared
+# 0: type, 1: list of type, 2: symbol kind, 3: symbol
 compiler.misc.where.typevar=\
     {0} extends {1} declared in {2} {3}
 
@@ -1386,20 +1932,30 @@
 
 # where clause for type variable: contains all the upper bound(s) ('extends {1}')
 # of this intersection type
+# 0: type, 1: list of type
 compiler.misc.where.intersection=\
     {0} extends {1}
 
 ### Where clause headers ###
 compiler.misc.where.description.captured=\
     where {0} is a fresh type-variable:
+
+# 0: set of type
 compiler.misc.where.description.typevar=\
     where {0} is a type-variable:
+
+# 0: set of type
 compiler.misc.where.description.intersection=\
     where {0} is an intersection type:
+
+# 0: set of type
 compiler.misc.where.description.captured.1=\
     where {0} are fresh type-variables:
+
+# 0: set of type
 compiler.misc.where.description.typevar.1=\
     where {0} are type-variables:
+
 compiler.misc.where.description.intersection.1=\
     where {0} are intersection types:
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java	Wed Jan 26 13:45:25 2011 -0800
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+
+import java.io.*;
+import java.util.*;
+import java.util.List;
+import javax.tools.*;
+
+import com.sun.tools.javac.api.*;
+import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.DiagnosticPart;
+import com.sun.tools.javac.api.Formattable.LocalizedString;
+import com.sun.tools.javac.code.Flags.Flag;
+import com.sun.tools.javac.code.Kinds.KindName;
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.file.*;
+import com.sun.tools.javac.main.Main;
+import com.sun.tools.javac.parser.Token;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration;
+import javax.lang.model.SourceVersion;
+
+/**
+ * Compiler factory for instances of Example.Compiler that use custom
+ * DiagnosticFormatter and Messages objects to track the types of args
+ * when when localizing diagnostics.
+ * The compiler objects only support "output" mode, not "check" mode.
+ */
+class ArgTypeCompilerFactory implements Example.Compiler.Factory {
+    // Same code as Example.Compiler.DefaultFactory, but the names resolve differently
+    public Example.Compiler getCompiler(List<String> opts, boolean verbose) {
+        String first;
+        String[] rest;
+        if (opts == null || opts.isEmpty()) {
+            first = null;
+            rest = new String[0];
+        } else {
+            first = opts.get(0);
+            rest = opts.subList(1, opts.size()).toArray(new String[opts.size() - 1]);
+        }
+        if (first == null || first.equals("jsr199"))
+            return new Jsr199Compiler(verbose, rest);
+        else if (first.equals("simple"))
+            return new SimpleCompiler(verbose);
+        else if (first.equals("backdoor"))
+            return new BackdoorCompiler(verbose);
+        else
+            throw new IllegalArgumentException(first);
+    }
+
+    /**
+     * Compile using the JSR 199 API.  The diagnostics generated are
+     * scanned for resource keys.   Not all diagnostic keys are generated
+     * via the JSR 199 API -- for example, rich diagnostics are not directly
+     * accessible, and some diagnostics generated by the file manager may
+     * not be generated (for example, the JSR 199 file manager does not see
+     * -Xlint:path).
+     */
+    static class Jsr199Compiler extends Example.Compiler {
+        List<String> fmOpts;
+
+        Jsr199Compiler(boolean verbose, String... args) {
+            super(verbose);
+            for (int i = 0; i < args.length; i++) {
+                String arg = args[i];
+                if (arg.equals("-filemanager") && (i + 1 < args.length)) {
+                    fmOpts = Arrays.asList(args[++i].split(","));
+                } else
+                    throw new IllegalArgumentException(arg);
+            }
+        }
+
+        @Override
+        boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
+            assert out != null && keys == null;
+
+            if (verbose)
+                System.err.println("run_jsr199: " + opts + " " + files);
+
+            JavacTool tool = JavacTool.create();
+
+            StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null);
+            if (fmOpts != null)
+                fm = new FileManager(fm, fmOpts);
+
+            Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
+
+            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));
+            Boolean ok = t.call();
+
+            return ok;
+        }
+    }
+
+    /**
+     * Run the test using the standard simple entry point.
+     */
+    static class SimpleCompiler extends Example.Compiler {
+        SimpleCompiler(boolean verbose) {
+            super(verbose);
+        }
+
+        @Override
+        boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
+            assert out != null && keys == null;
+
+            if (verbose)
+                System.err.println("run_simple: " + opts + " " + files);
+
+            List<String> args = new ArrayList<String>();
+
+            args.addAll(opts);
+            for (File f: files)
+                args.add(f.getPath());
+
+            Main main = new Main("javac", out);
+            Context c = new Context() {
+                @Override public void clear() {
+                    ((JavacFileManager) get(JavaFileManager.class)).close();
+                    super.clear();
+                }
+            };
+            JavacFileManager.preRegister(c); // can't create it until Log has been set up
+            ArgTypeDiagnosticFormatter.preRegister(c);
+            ArgTypeMessages.preRegister(c);
+            int result = main.compile(args.toArray(new String[args.size()]), c);
+
+            return (result == 0);
+        }
+    }
+
+    static class BackdoorCompiler extends Example.Compiler {
+        BackdoorCompiler(boolean verbose) {
+            super(verbose);
+        }
+
+        @Override
+        boolean run(PrintWriter out, Set<String> keys, boolean raw, List<String> opts, List<File> files) {
+            assert out != null && keys == null;
+
+            if (verbose)
+                System.err.println("run_simple: " + opts + " " + files);
+
+            List<String> args = new ArrayList<String>(opts);
+            for (File f: files)
+                args.add(f.getPath());
+
+            Context c = new Context();
+            JavacFileManager.preRegister(c); // can't create it until Log has been set up
+            ArgTypeDiagnosticFormatter.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);
+
+            return (rc == 0);
+        }
+
+    }
+
+
+    // <editor-fold defaultstate="collapsed" desc="Custom Javac components">
+
+    /**
+     * Diagnostic formatter which reports formats a diag as a series of lines
+     * containing a key, and a possibly empty set of descriptive strings for the
+     * arg types.
+     */
+    static class ArgTypeDiagnosticFormatter extends AbstractDiagnosticFormatter {
+        static void preRegister(final Context context) {
+            context.put(Log.logKey, new Context.Factory<Log>() {
+                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,
+                    EnumSet.of(DiagnosticPart.SUMMARY,
+                    DiagnosticPart.DETAILS,
+                    DiagnosticPart.SUBDIAGNOSTICS)));
+        }
+
+        @Override
+        protected String formatDiagnostic(JCDiagnostic d, Locale locale) {
+            return formatMessage(d, locale);
+        }
+
+        @Override
+        public String formatMessage(JCDiagnostic d, Locale l) {
+            StringBuilder buf = new StringBuilder();
+            formatMessage(d, buf);
+            return buf.toString();
+        }
+
+        private void formatMessage(JCDiagnostic d, StringBuilder buf) {
+            String key = d.getCode();
+            Object[] args = d.getArgs();
+            // report the primary arg types, without recursing into diag fragments
+            buf.append(getKeyArgsString(key, args));
+            // report details for any diagnostic fragments
+            for (Object arg: args) {
+                if (arg instanceof JCDiagnostic) {
+                    buf.append("\n");
+                    formatMessage((JCDiagnostic) arg, buf);
+                }
+            }
+            // report details for any subdiagnostics
+            for (String s: formatSubdiagnostics(d, null)) {
+                buf.append("\n");
+                buf.append(s);
+            }
+        }
+
+        @Override
+        public boolean isRaw() {
+            return true;
+        }
+    }
+
+    /**
+     * 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<JavacMessages>() {
+                public JavacMessages make() {
+                    return new ArgTypeMessages(c) {
+                        @Override
+                        public String getLocalizedString(Locale l, String key, Object... args) {
+                            return getKeyArgsString(key, args);
+                        }
+                    };
+                }
+            });
+        }
+
+        ArgTypeMessages(Context context) {
+            super(context);
+        }
+    }
+
+    /**
+     * Utility method to generate a string for key and args
+     */
+    static String getKeyArgsString(String key, Object... args) {
+        StringBuilder buf = new StringBuilder();
+        buf.append(key);
+        String sep = ": ";
+        for (Object o : args) {
+            buf.append(sep);
+            buf.append(getArgTypeOrStringValue(o));
+            sep = ", ";
+        }
+        return buf.toString();
+    }
+
+    static boolean showStringValues = false;
+
+    static String getArgTypeOrStringValue(Object o) {
+        if (showStringValues && o instanceof String)
+            return "\"" + o + "\"";
+        return getArgType(o);
+    }
+
+    static String getArgType(Object o) {
+        if (o == null)
+            return "null";
+        if (o instanceof Name)
+            return "name";
+        if (o instanceof Boolean)
+            return "boolean";
+        if (o instanceof Integer)
+            return "number";
+        if (o instanceof String)
+            return "string";
+        if (o instanceof Flag)
+            return "modifier";
+        if (o instanceof KindName)
+            return "symbol kind";
+        if (o instanceof Token)
+            return "token";
+        if (o instanceof Symbol)
+            return "symbol";
+        if (o instanceof Type)
+            return "type";
+        if (o instanceof List) {
+            List<?> l = (List<?>) o;
+            if (l.isEmpty())
+                return "list";
+            else
+                return "list of " + getArgType(l.get(0));
+        }
+        if (o instanceof ListBuffer)
+            return getArgType(((ListBuffer) o).toList());
+        if (o instanceof Set) {
+            Set<?> s = (Set<?>) o;
+            if (s.isEmpty())
+                return "set";
+            else
+                return "set of " + getArgType(s.iterator().next());
+        }
+        if (o instanceof SourceVersion)
+            return "source version";
+        if (o instanceof FileObject || o instanceof File)
+            return "file name";
+        if (o instanceof JCDiagnostic)
+            return "message segment";
+        if (o instanceof LocalizedString)
+            return "message segment";  // only instance is "no arguments"
+        String s = o.getClass().getSimpleName();
+        return (s.isEmpty() ? o.getClass().getName() : s);
+    }
+
+    // </editor-fold>
+
+}
--- a/langtools/test/tools/javac/diags/Example.java	Wed Jan 26 11:20:19 2011 -0800
+++ b/langtools/test/tools/javac/diags/Example.java	Wed Jan 26 13:45:25 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -168,7 +168,7 @@
         try {
             run(null, keys, true, verbose);
         } catch (IOException e) {
-            e.printStackTrace();
+            e.printStackTrace(System.err);
         }
         return keys;
     }
@@ -293,10 +293,15 @@
     }
 
     abstract static class Compiler {
-        static Compiler getCompiler(List<String> opts, boolean verbose) {
+        interface Factory {
+            Compiler getCompiler(List<String> opts, boolean verbose);
+        }
+
+        static class DefaultFactory implements Factory {
+            public Compiler getCompiler(List<String> opts, boolean verbose) {
             String first;
             String[] rest;
-            if (opts == null || opts.size() == 0) {
+                if (opts == null || opts.isEmpty()) {
                 first = null;
                 rest = new String[0];
             } else {
@@ -311,6 +316,16 @@
                 return new BackdoorCompiler(verbose);
             else
                 throw new IllegalArgumentException(first);
+                }
+        }
+
+        static Factory factory;
+
+        static Compiler getCompiler(List<String> opts, boolean verbose) {
+            if (factory == null)
+                factory = new DefaultFactory();
+
+            return factory.getCompiler(opts, verbose);
         }
 
         protected Compiler(boolean verbose) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/MessageFile.java	Wed Jan 26 13:45:25 2011 -0800
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Class to facilitate manipulating compiler.properties.
+ */
+class MessageFile {
+    static final Pattern emptyOrCommentPattern = Pattern.compile("( *#.*)?");
+    static final Pattern infoPattern = Pattern.compile("# ([0-9]+: [-A-Za-z ]+, )*[0-9]+: [-A-Za-z ]+");
+
+    /**
+     * A line of text within the message file.
+     * The lines form a doubly linked list for simple navigation.
+     */
+    class Line {
+        String text;
+        Line prev;
+        Line next;
+
+        Line(String text) {
+            this.text = text;
+        }
+
+        boolean isEmptyOrComment() {
+            return emptyOrCommentPattern.matcher(text).matches();
+        }
+
+        boolean isInfo() {
+            return infoPattern.matcher(text).matches();
+        }
+
+        boolean hasContinuation() {
+            return (next != null) && text.endsWith("\\");
+        }
+
+        Line insertAfter(String text) {
+            Line l = new Line(text);
+            insertAfter(l);
+            return l;
+        }
+
+        void insertAfter(Line l) {
+            assert prev == null && next == null;
+            l.prev = this;
+            l.next = next;
+            if (next == null)
+                lastLine = l;
+            else
+                next.prev = l;
+            next = l;
+        }
+
+        Line insertBefore(String text) {
+            Line l = new Line(text);
+            insertBefore(l);
+            return l;
+        }
+
+        void insertBefore(Line l) {
+            assert prev == null && next == null;
+            l.prev = prev;
+            l.next = this;
+            if (prev == null)
+                firstLine = l;
+            else
+                prev.next = l;
+            prev = l;
+        }
+
+        void remove() {
+            if (prev == null)
+                firstLine = next;
+            else
+                prev.next = next;
+            if (next == null)
+                lastLine = prev;
+            else
+                next.prev = prev;
+            prev = null;
+            next = null;
+        }
+    }
+
+    /**
+     * A message within the message file.
+     * A message is a series of lines containing a "name=value" property,
+     * optionally preceded by a comment describing the use of placeholders
+     * such as {0}, {1}, etc within the property value.
+     */
+    static final class Message {
+        final Line firstLine;
+        private Info info;
+
+        Message(Line l) {
+            firstLine = l;
+        }
+
+        boolean needInfo() {
+            Line l = firstLine;
+            while (true) {
+                if (l.text.matches(".*\\{[0-9]+\\}.*"))
+                    return true;
+                if (!l.hasContinuation())
+                    return false;
+                l = l.next;
+            }
+        }
+
+        Set<Integer> getPlaceholders() {
+            Pattern p = Pattern.compile("\\{([0-9]+)\\}");
+            Set<Integer> results = new TreeSet<Integer>();
+            Line l = firstLine;
+            while (true) {
+                Matcher m = p.matcher(l.text);
+                while (m.find())
+                    results.add(Integer.parseInt(m.group(1)));
+                if (!l.hasContinuation())
+                    return results;
+                l = l.next;
+            }
+        }
+
+        /**
+         * Get the Info object for this message. It may be empty if there
+         * if no comment preceding the property specification.
+         */
+        Info getInfo() {
+            if (info == null) {
+                Line l = firstLine.prev;
+                if (l != null && l.isInfo())
+                    info = new Info(l.text);
+                else
+                    info = new Info();
+            }
+            return info;
+        }
+
+        /**
+         * Set the Info for this message.
+         * If there was an info comment preceding the property specification,
+         * it will be updated; otherwise, one will be inserted.
+         */
+        void setInfo(Info info) {
+            this.info = info;
+            Line l = firstLine.prev;
+            if (l != null && l.isInfo())
+                l.text = info.toComment();
+            else
+                firstLine.insertBefore(info.toComment());
+        }
+
+        /**
+         * Get all the lines pertaining to this message.
+         */
+        List<Line> getLines(boolean includeAllPrecedingComments) {
+            List<Line> lines = new ArrayList<Line>();
+            Line l = firstLine;
+            if (includeAllPrecedingComments) {
+                // scan back to find end of prev message
+                while (l.prev != null && l.prev.isEmptyOrComment())
+                    l = l.prev;
+                // skip leading blank lines
+                while (l.text.isEmpty())
+                    l = l.next;
+            } else {
+                if (l.prev != null && l.prev.isInfo())
+                    l = l.prev;
+            }
+
+            // include any preceding lines
+            for ( ; l != firstLine; l = l.next)
+                lines.add(l);
+
+            // include message lines
+            for (l = firstLine; l != null && l.hasContinuation(); l = l.next)
+                lines.add(l);
+            lines.add(l);
+
+            // include trailing blank line if present
+            l = l.next;
+            if (l != null && l.text.isEmpty())
+                lines.add(l);
+
+            return lines;
+        }
+    }
+
+    /**
+     * An object to represent the comment that may precede the property
+     * specification in a Message.
+     * The comment is modelled as a list of fields, where the fields correspond
+     * to the placeholder values (e.g. {0}, {1}, etc) within the message value.
+     */
+    static final class Info {
+        /**
+         * An ordered set of descriptions for a placeholder value in a
+         * message.
+         */
+        static class Field {
+            boolean unused;
+            Set<String> values;
+            boolean listOfAny = false;
+            boolean setOfAny = false;
+            Field(String s) {
+                s = s.substring(s.indexOf(": ") + 2);
+                values = new LinkedHashSet<String>(Arrays.asList(s.split(" or ")));
+                for (String v: values) {
+                    if (v.startsWith("list of"))
+                        listOfAny = true;
+                    if (v.startsWith("set of"))
+                        setOfAny = true;
+                }
+            }
+
+            /**
+             * Return true if this field logically contains all the values of
+             * another field.
+             */
+            boolean contains(Field other) {
+                if (unused != other.unused)
+                    return false;
+
+                for (String v: other.values) {
+                    if (values.contains(v))
+                        continue;
+                    if (v.equals("null") || v.equals("string"))
+                        continue;
+                    if (v.equals("list") && listOfAny)
+                        continue;
+                    if (v.equals("set") && setOfAny)
+                        continue;
+                    return false;
+                }
+                return true;
+            }
+
+            /**
+             * Merge the values of another field into this field.
+             */
+            void merge(Field other) {
+                unused |= other.unused;
+                values.addAll(other.values);
+
+                // cleanup unnecessary entries
+
+                if (values.contains("null") && values.size() > 1) {
+                    // "null" is superceded by anything else
+                    values.remove("null");
+                }
+
+                if (values.contains("string") && values.size() > 1) {
+                    // "string" is superceded by anything else
+                    values.remove("string");
+                }
+
+                if (values.contains("list")) {
+                    // list is superceded by "list of ..."
+                    for (String s: values) {
+                        if (s.startsWith("list of ")) {
+                            values.remove("list");
+                            break;
+                        }
+                    }
+                }
+
+                if (values.contains("set")) {
+                    // set is superceded by "set of ..."
+                    for (String s: values) {
+                        if (s.startsWith("set of ")) {
+                            values.remove("set");
+                            break;
+                        }
+                    }
+                }
+
+                if (other.values.contains("unused")) {
+                    values.clear();
+                    values.add("unused");
+                }
+            }
+
+            void markUnused() {
+                values = new LinkedHashSet<String>();
+                values.add("unused");
+                listOfAny = false;
+                setOfAny = false;
+            }
+
+            @Override
+            public String toString() {
+                return values.toString();
+            }
+        }
+
+        /** The fields of the Info object. */
+        List<Field> fields = new ArrayList<Field>();
+
+        Info() { }
+
+        Info(String text) throws IllegalArgumentException {
+            if (!text.startsWith("# "))
+                throw new IllegalArgumentException();
+            String[] segs = text.substring(2).split(", ");
+            fields = new ArrayList<Field>();
+            for (String seg: segs) {
+                fields.add(new Field(seg));
+            }
+        }
+
+        Info(Set<String> infos) throws IllegalArgumentException {
+            for (String s: infos)
+                merge(new Info(s));
+        }
+
+        boolean isEmpty() {
+            return fields.isEmpty();
+        }
+
+        boolean contains(Info other) {
+            if (other.isEmpty())
+                return true;
+
+            if (fields.size() != other.fields.size())
+                return false;
+
+            Iterator<Field> oIter = other.fields.iterator();
+            for (Field values: fields) {
+                if (!values.contains(oIter.next()))
+                    return false;
+            }
+
+            return true;
+        }
+
+        void merge(Info other) {
+            if (fields.isEmpty()) {
+                fields.addAll(other.fields);
+                return;
+            }
+
+            if (other.fields.size() != fields.size())
+                throw new IllegalArgumentException();
+
+            Iterator<Field> oIter = other.fields.iterator();
+            for (Field d: fields) {
+                d.merge(oIter.next());
+            }
+        }
+
+        void markUnused(Set<Integer> used) {
+            for (int i = 0; i < fields.size(); i++) {
+                if (!used.contains(i))
+                    fields.get(i).markUnused();
+            }
+        }
+
+        @Override
+        public String toString() {
+            return fields.toString();
+        }
+
+        String toComment() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("# ");
+            String sep = "";
+            int i = 0;
+            for (Field f: fields) {
+                sb.append(sep);
+                sb.append(i++);
+                sb.append(": ");
+                sep = "";
+                for (String s: f.values) {
+                    sb.append(sep);
+                    sb.append(s);
+                    sep = " or ";
+                }
+                sep = ", ";
+            }
+            return sb.toString();
+        }
+    }
+
+    Line firstLine;
+    Line lastLine;
+    Map<String, Message> messages = new TreeMap<String, Message>();
+
+    MessageFile(File file) throws IOException {
+        Reader in = new FileReader(file);
+        try {
+            read(in);
+        } finally {
+            in.close();
+        }
+    }
+
+    MessageFile(Reader in) throws IOException {
+        read(in);
+    }
+
+    final void read(Reader in) throws IOException {
+        BufferedReader br = (in instanceof BufferedReader)
+                ? (BufferedReader) in
+                : new BufferedReader(in);
+        String line;
+        while ((line = br.readLine()) != null) {
+            Line l;
+            if (firstLine == null)
+                l = firstLine = lastLine = new Line(line);
+            else
+                l = lastLine.insertAfter(line);
+            if (line.startsWith("compiler.")) {
+                int eq = line.indexOf("=");
+                if (eq > 0)
+                    messages.put(line.substring(0, eq), new Message(l));
+            }
+        }
+    }
+
+    void write(File file) throws IOException {
+        Writer out = new FileWriter(file);
+        try {
+            write(out);
+        } finally {
+            out.close();
+        }
+    }
+
+    void write(Writer out) throws IOException {
+        BufferedWriter bw = (out instanceof BufferedWriter)
+                ? (BufferedWriter) out
+                : new BufferedWriter(out);
+        for (Line l = firstLine; l != null; l = l.next) {
+            bw.write(l.text);
+            bw.write("\n"); // always use Unix line endings
+        }
+        bw.flush();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/MessageInfo.java	Wed Jan 26 13:45:25 2011 -0800
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2010, 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 7013272
+ * @summary Automatically generate info about how compiler resource keys are used
+ * @build Example ArgTypeCompilerFactory MessageFile MessageInfo
+ * @run main MessageInfo
+ */
+
+import java.io.*;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * Utility to manipulate compiler.properties, and suggest info comments based
+ * on information derived from running examples.
+ *
+ * Options:
+ *   -examples dir   location of examples directory
+ *   -o file         output file
+ *   -check          just check message file
+ *   -ensureNewlines ensure newline after each entry
+ *   -fixIndent      fix indentation of continuation lines
+ *   -sort           sort messages
+ *   -verbose        verbose output
+ *   -replace        replace comments instead of merging comments
+ *   file            javac compiler.properties file
+ *
+ */
+public class MessageInfo {
+    public static void main(String... args) throws Exception {
+        jtreg = (System.getProperty("test.src") != null);
+        File tmpDir;
+        if (jtreg) {
+            // use standard jtreg scratch directory: the current directory
+            tmpDir = new File(System.getProperty("user.dir"));
+        } else {
+            tmpDir = new File(System.getProperty("java.io.tmpdir"),
+                    MessageInfo.class.getName()
+                    + (new SimpleDateFormat("yyMMddHHmmss")).format(new Date()));
+        }
+        Example.setTempDir(tmpDir);
+        Example.Compiler.factory = new ArgTypeCompilerFactory();
+
+        MessageInfo mi = new MessageInfo();
+
+        try {
+            if (mi.run(args))
+                return;
+        } finally {
+            /* VERY IMPORTANT NOTE. In jtreg mode, tmpDir is set to the
+             * jtreg scratch directory, which is the current directory.
+             * In case someone is faking jtreg mode, make sure to only
+             * clean tmpDir when it is reasonable to do so.
+             */
+            if (tmpDir.isDirectory() &&
+                    tmpDir.getName().startsWith(MessageInfo.class.getName())) {
+                if (clean(tmpDir))
+                    tmpDir.delete();
+            }
+        }
+
+        if (jtreg)
+            throw new Exception(mi.errors + " errors occurred");
+        else
+            System.exit(1);
+    }
+
+    void usage() {
+        System.out.println("Usage:");
+        System.out.println("    java MessageInfo [options] [file]");
+        System.out.println("where options include");
+        System.out.println("    -examples dir   location of examples directory");
+        System.out.println("    -o file         output file");
+        System.out.println("    -check          just check message file");
+        System.out.println("    -ensureNewlines ensure newline after each entry");
+        System.out.println("    -fixIndent      fix indentation of continuation lines");
+        System.out.println("    -sort           sort messages");
+        System.out.println("    -verbose        verbose output");
+        System.out.println("    -replace        replace comments instead of merging comments");
+        System.out.println("    file            javac compiler.properties file");
+    }
+
+    boolean run(String... args) {
+        File testSrc = new File(System.getProperty("test.src", "."));
+        File examplesDir = new File(testSrc, "examples");
+        File notYetFile = null;
+        File msgFile = null;
+        File outFile = null;
+        boolean verbose = false;
+        boolean ensureNewlines = false;
+        boolean fixIndent = false;
+        boolean sort = false;
+        boolean replace = false;
+        boolean check = jtreg; // default true in jtreg mode
+
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.equals("-examples") && (i + 1) < args.length)
+                examplesDir = new File(args[++i]);
+            else if(arg.equals("-notyet") && (i + 1) < args.length)
+                notYetFile = new File(args[++i]);
+            else if (arg.equals("-ensureNewlines"))
+                ensureNewlines = true;
+            else if (arg.equals("-fixIndent"))
+                fixIndent = true;
+            else if (arg.equals("-sort"))
+                sort = true;
+            else if (arg.equals("-verbose"))
+                verbose = true;
+            else if (arg.equals("-replace"))
+                replace = true;
+            else if (arg.equals("-check"))
+                check = true;
+            else if (arg.equals("-o") && (i + 1) < args.length)
+                outFile = new File(args[++i]);
+            else if (arg.startsWith("-")) {
+                error("unknown option: " + arg);
+                return false;
+            } else if (i == args.length - 1) {
+                msgFile = new File(arg);
+            } else {
+                error("unknown arg: " + arg);
+                return false;
+            }
+        }
+
+        if (!check && outFile == null) {
+            usage();
+            return true;
+        }
+
+        if ((ensureNewlines || fixIndent || sort) && outFile == null) {
+            error("must set output file for these options");
+            return false;
+        }
+
+        if (notYetFile == null) {
+            notYetFile = new File(examplesDir.getParentFile(), "examples.not-yet.txt");
+        }
+
+        if (msgFile == null) {
+            for (File d = testSrc; d != null; d = d.getParentFile()) {
+                if (new File(d, "TEST.ROOT").exists()) {
+                    d = d.getParentFile();
+                    File f = new File(d, "src/share/classes/com/sun/tools/javac/resources/compiler.properties");
+                    if (f.exists()) {
+                        msgFile = f;
+                        break;
+                    }
+                }
+            }
+            if (msgFile == null) {
+                error("no message file available");
+                return false;
+            }
+        }
+
+        MessageFile mf;
+        try {
+            mf = new MessageFile(msgFile);
+        } catch (IOException e) {
+            error("problem reading message file: " + e);
+            return false;
+        }
+
+        Map<String, Set<String>> msgInfo = runExamples(examplesDir, verbose);
+
+        if (ensureNewlines)
+            ensureNewlines(mf);
+
+        if (fixIndent)
+            fixIndent(mf);
+
+        if (sort)
+            sort(mf, true);
+
+        for (Map.Entry<String, Set<String>> e: msgInfo.entrySet()) {
+            String k = e.getKey();
+            Set<String> suggestions = e.getValue();
+            MessageFile.Message m = mf.messages.get(k);
+            if (m == null) {
+                error("Can't find message for " + k + " in message file");
+                continue;
+            }
+
+            MessageFile.Info info = m.getInfo();
+            Set<Integer> placeholders = m.getPlaceholders();
+            MessageFile.Info suggestedInfo = new MessageFile.Info(suggestions);
+            suggestedInfo.markUnused(placeholders);
+
+            if (!info.isEmpty()) {
+                if (info.contains(suggestedInfo))
+                    continue;
+                if (!replace) {
+                    if (info.fields.size() != suggestedInfo.fields.size())
+                        error("Cannot merge info for " + k);
+                    else
+                        suggestedInfo.merge(info);
+                }
+            }
+
+            if (outFile == null) {
+                System.err.println("suggest for " + k);
+                System.err.println(suggestedInfo.toComment());
+            }  else
+                m.setInfo(suggestedInfo);
+        }
+
+        if (check)
+            check(mf, notYetFile);
+
+        try {
+            if (outFile != null)
+                mf.write(outFile);
+        } catch (IOException e) {
+            error("problem writing file: " + e);
+            return false;
+        }
+
+        return (errors == 0);
+    }
+
+    void check(MessageFile mf, File notYetFile) {
+        Set<String> notYetList = null;
+        for (Map.Entry<String, MessageFile.Message> e: mf.messages.entrySet()) {
+            String key = e.getKey();
+            MessageFile.Message m = e.getValue();
+            if (m.needInfo() && m.getInfo().isEmpty()) {
+                if (notYetList == null)
+                    notYetList = getNotYetList(notYetFile);
+                if (notYetList.contains(key))
+                    System.err.println("Warning: no info for " + key);
+                else
+                    error("no info for " + key);
+            }
+        }
+
+    }
+
+    void ensureNewlines(MessageFile mf) {
+        for (MessageFile.Message m: mf.messages.values()) {
+            MessageFile.Line l = m.firstLine;
+            while (l.text.endsWith("\\"))
+                l = l.next;
+            if (l.next != null && !l.next.text.isEmpty())
+                l.insertAfter("");
+        }
+    }
+
+    void fixIndent(MessageFile mf) {
+        for (MessageFile.Message m: mf.messages.values()) {
+            MessageFile.Line l = m.firstLine;
+            while (l.text.endsWith("\\") && l.next != null) {
+                if (!l.next.text.matches("^    \\S.*"))
+                    l.next.text = "    " + l.next.text.trim();
+                l = l.next;
+            }
+        }
+    }
+
+    void sort(MessageFile mf, boolean includePrecedingNewlines) {
+        for (MessageFile.Message m: mf.messages.values()) {
+            for (MessageFile.Line l: m.getLines(includePrecedingNewlines)) {
+                l.remove();
+                mf.lastLine.insertAfter(l);
+            }
+        }
+    }
+
+    Map<String, Set<String>> runExamples(File examplesDir, boolean verbose) {
+        Map<String, Set<String>> map = new TreeMap<String, Set<String>>();
+        for (Example e: getExamples(examplesDir)) {
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            e.run(pw, true, verbose);
+            pw.close();
+            String[] lines = sw.toString().split("\n");
+            for (String line: lines) {
+                if (!line.startsWith("compiler."))
+                    continue;
+                int colon = line.indexOf(":");
+                if (colon == -1)
+                    continue;
+                String key = line.substring(0, colon);
+                StringBuilder sb = new StringBuilder();
+                sb.append("# ");
+                int i = 0;
+                String[] descs = line.substring(colon + 1).split(", *");
+                for (String desc: descs) {
+                    if (i > 0) sb.append(", ");
+                    sb.append(i++);
+                    sb.append(": ");
+                    sb.append(desc.trim());
+                }
+                Set<String> set = map.get(key);
+                if (set == null)
+                    map.put(key, set = new TreeSet<String>());
+                set.add(sb.toString());
+            }
+        }
+
+        return map;
+    }
+
+    /**
+     * Get the complete set of examples to be checked.
+     */
+    Set<Example> getExamples(File examplesDir) {
+        Set<Example> results = new TreeSet<Example>();
+        for (File f: examplesDir.listFiles()) {
+            if (isValidExample(f))
+                results.add(new Example(f));
+        }
+        return results;
+    }
+
+    boolean isValidExample(File f) {
+        return (f.isDirectory() && (!jtreg || f.list().length > 0)) ||
+                (f.isFile() && f.getName().endsWith(".java"));
+    }
+
+    /**
+     * Get the contents of the "not-yet" list.
+     */
+    Set<String> getNotYetList(File file) {
+        Set<String> results = new TreeSet<String>();
+        try {
+            String[] lines = read(file).split("[\r\n]");
+            for (String line: lines) {
+                int hash = line.indexOf("#");
+                if (hash != -1)
+                    line = line.substring(0, hash).trim();
+                if (line.matches("[A-Za-z0-9-_.]+"))
+                    results.add(line);
+            }
+        } catch (IOException e) {
+            throw new Error(e);
+        }
+        return results;
+    }
+
+    /**
+     * Read the contents of a file.
+     */
+    String read(File f) throws IOException {
+        byte[] bytes = new byte[(int) f.length()];
+        DataInputStream in = new DataInputStream(new FileInputStream(f));
+        try {
+            in.readFully(bytes);
+        } finally {
+            in.close();
+        }
+        return new String(bytes);
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    static boolean jtreg;
+
+    int errors;
+
+    /**
+     * Clean the contents of a directory.
+     */
+    static boolean clean(File dir) {
+        boolean ok = true;
+        for (File f: dir.listFiles()) {
+            if (f.isDirectory())
+                ok &= clean(f);
+            ok &= f.delete();
+        }
+        return ok;
+    }
+
+}
+
+
--- a/langtools/test/tools/javac/diags/RunExamples.java	Wed Jan 26 11:20:19 2011 -0800
+++ b/langtools/test/tools/javac/diags/RunExamples.java	Wed Jan 26 13:45:25 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -25,7 +25,7 @@
  * @test
  * @bug 6968063
  * @summary provide examples of code that generate diagnostics
- * @build Example HTMLWriter RunExamples
+ * @build ArgTypeCompilerFactory Example HTMLWriter RunExamples
  * @run main RunExamples
  */
 
@@ -97,6 +97,7 @@
         boolean raw = false;
         boolean showFiles = false;
         boolean verbose = false;
+        boolean argTypes = false;
         String title = null;
 
         for (int i = 0; i < args.length; i++) {
@@ -115,6 +116,8 @@
                 outFile = new File(args[++i]);
             else if (arg.equals("-title") && (i + 1) < args.length)
                 title = args[++i];
+            else if (arg.equals("-argtypes"))
+                argTypes = true;
             else if (arg.startsWith("-")) {
                 error("unknown option: " + arg);
                 return false;
@@ -127,6 +130,11 @@
             }
         }
 
+        // special mode to show message keys and the types of the args that
+        // are used.
+        if (argTypes)
+            Example.Compiler.factory = new ArgTypeCompilerFactory();
+
         if (selectedKeys.size() > 0) {
             Set<Example> examples = getExamples(examplesDir);
         nextKey:
@@ -138,7 +146,7 @@
                 error("Key " + k + ": no examples found");
             }
         } else {
-            if (selectedExamples.size() == 0)
+            if (selectedExamples.isEmpty())
                 selectedExamples = getExamples(examplesDir);
         }