# HG changeset patch # User mcimadamore # Date 1245837027 -3600 # Node ID 18e0269f25e35691ee83cd11715d52ec87067be7 # Parent ed989c347b3cf385d716662c529c85541b356554 6822637: ResolveError hierarchy needs to be refactored Summary: Break ResolveError class into a hierarchy representing different kinds of resolution errors Reviewed-by: jjg diff -r ed989c347b3c -r 18e0269f25e3 src/share/classes/com/sun/tools/javac/code/Kinds.java --- a/src/share/classes/com/sun/tools/javac/code/Kinds.java Fri Jun 19 11:40:47 2009 -0700 +++ b/src/share/classes/com/sun/tools/javac/code/Kinds.java Wed Jun 24 10:50:27 2009 +0100 @@ -95,6 +95,7 @@ ANNOTATION("kindname.interface"), CONSTRUCTOR("kindname.constructor"), INTERFACE("kindname.interface"), + ENUM("kindname.enum"), STATIC("kindname.static"), TYPEVAR("kindname.type.variable"), BOUND("kindname.type.variable.bound"), @@ -145,11 +146,15 @@ return KindName.PACKAGE; case ENUM: + return KindName.ENUM; + case ANNOTATION_TYPE: - case INTERFACE: case CLASS: return KindName.CLASS; + case INTERFACE: + return KindName.INTERFACE; + case TYPE_PARAMETER: return KindName.TYPEVAR; @@ -160,8 +165,10 @@ case EXCEPTION_PARAMETER: return KindName.VAR; + case CONSTRUCTOR: + return KindName.CONSTRUCTOR; + case METHOD: - case CONSTRUCTOR: case STATIC_INIT: case INSTANCE_INIT: return KindName.METHOD; diff -r ed989c347b3c -r 18e0269f25e3 src/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Jun 19 11:40:47 2009 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Wed Jun 24 10:50:27 2009 +0100 @@ -82,15 +82,15 @@ syms = Symtab.instance(context); varNotFound = new - ResolveError(ABSENT_VAR, syms.errSymbol, "variable not found"); + SymbolNotFoundError(ABSENT_VAR); wrongMethod = new - ResolveError(WRONG_MTH, syms.errSymbol, "method not found"); + InapplicableSymbolError(syms.errSymbol); wrongMethods = new - ResolveError(WRONG_MTHS, syms.errSymbol, "wrong methods"); + InapplicableSymbolsError(syms.errSymbol); methodNotFound = new - ResolveError(ABSENT_MTH, syms.errSymbol, "method not found"); + SymbolNotFoundError(ABSENT_MTH); typeNotFound = new - ResolveError(ABSENT_TYP, syms.errSymbol, "type not found"); + SymbolNotFoundError(ABSENT_TYP); names = Names.instance(context); log = Log.instance(context); @@ -110,11 +110,11 @@ /** error symbols, which are returned when resolution fails */ - final ResolveError varNotFound; - final ResolveError wrongMethod; - final ResolveError wrongMethods; - final ResolveError methodNotFound; - final ResolveError typeNotFound; + final SymbolNotFoundError varNotFound; + final InapplicableSymbolError wrongMethod; + final InapplicableSymbolsError wrongMethods; + final SymbolNotFoundError methodNotFound; + final SymbolNotFoundError typeNotFound; /* ************************************************************************ * Identifier resolution @@ -710,13 +710,13 @@ return new AmbiguityError(m1, m2); case AMBIGUOUS: AmbiguityError e = (AmbiguityError)m2; - Symbol err1 = mostSpecific(m1, e.sym1, env, site, allowBoxing, useVarargs); + Symbol err1 = mostSpecific(m1, e.sym, env, site, allowBoxing, useVarargs); Symbol err2 = mostSpecific(m1, e.sym2, env, site, allowBoxing, useVarargs); if (err1 == err2) return err1; - if (err1 == e.sym1 && err2 == e.sym2) return m2; + if (err1 == e.sym && err2 == e.sym2) return m2; if (err1 instanceof AmbiguityError && err2 instanceof AmbiguityError && - ((AmbiguityError)err1).sym1 == ((AmbiguityError)err2).sym1) + ((AmbiguityError)err1).sym == ((AmbiguityError)err2).sym) return new AmbiguityError(m1, m2); else return new AmbiguityError(err1, err2); @@ -1192,18 +1192,12 @@ List argtypes, List typeargtypes) { if (sym.kind >= AMBIGUOUS) { -// printscopes(site.tsym.members());//DEBUG + ResolveError errSym = (ResolveError)sym; if (!site.isErroneous() && !Type.isErroneous(argtypes) && (typeargtypes==null || !Type.isErroneous(typeargtypes))) - ((ResolveError)sym).report(log, pos, site, name, argtypes, typeargtypes); - do { - sym = ((ResolveError)sym).sym; - } while (sym.kind >= AMBIGUOUS); - if (sym == syms.errSymbol // preserve the symbol name through errors - || ((sym.kind & ERRONEOUS) == 0 // make sure an error symbol is returned - && (sym.kind & TYP) != 0)) - sym = types.createErrorType(name, qualified ? site.tsym : syms.noSymbol, sym.type).tsym; + logResolveError(errSym, pos, site, name, argtypes, typeargtypes); + sym = errSym.access(name, qualified ? site.tsym : syms.noSymbol); } return sym; } @@ -1583,7 +1577,19 @@ public void logAccessError(Env env, JCTree tree, Type type) { AccessError error = new AccessError(env, type.getEnclosingType(), type.tsym); - error.report(log, tree.pos(), type.getEnclosingType(), null, null, null); + logResolveError(error, tree.pos(), type.getEnclosingType(), null, null, null); + } + //where + private void logResolveError(ResolveError error, + DiagnosticPosition pos, + Type site, + Name name, + List argtypes, + List typeargtypes) { + JCDiagnostic d = error.getDiagnostic(JCDiagnostic.DiagnosticType.ERROR, + pos, site, name, argtypes, typeargtypes); + if (d != null) + log.report(d); } private final LocalizedString noArgs = new LocalizedString("compiler.misc.no.args"); @@ -1592,152 +1598,71 @@ return argtypes.isEmpty() ? noArgs : argtypes; } - /** Root class for resolve errors. - * Instances of this class indicate "Symbol not found". - * Instances of subclass indicate other errors. + /** + * Root class for resolution errors. Subclass of ResolveError + * represent a different kinds of resolution error - as such they must + * specify how they map into concrete compiler diagnostics. */ - private class ResolveError extends Symbol { + private abstract class ResolveError extends Symbol { - ResolveError(int kind, Symbol sym, String debugName) { + /** The name of the kind of error, for debugging only. */ + final String debugName; + + ResolveError(int kind, String debugName) { super(kind, 0, null, null, null); this.debugName = debugName; - this.sym = sym; } - /** The name of the kind of error, for debugging only. - */ - final String debugName; - - /** The symbol that was determined by resolution, or errSymbol if none - * was found. - */ - final Symbol sym; - - /** The symbol that was a close mismatch, or null if none was found. - * wrongSym is currently set if a simgle method with the correct name, but - * the wrong parameters was found. - */ - Symbol wrongSym; - - /** An auxiliary explanation set in case of instantiation errors. - */ - JCDiagnostic explanation; - - + @Override public R accept(ElementVisitor v, P p) { throw new AssertionError(); } - /** Print the (debug only) name of the kind of error. - */ + @Override public String toString() { - return debugName + " wrongSym=" + wrongSym + " explanation=" + explanation; + return debugName; } - /** Update wrongSym and explanation and return this. - */ - ResolveError setWrongSym(Symbol sym, JCDiagnostic explanation) { - this.wrongSym = sym; - this.explanation = explanation; - return this; + @Override + public boolean exists() { + return false; } - /** Update wrongSym and return this. + /** + * Create an external representation for this erroneous symbol to be + * used during attribution - by default this returns the symbol of a + * brand new error type which stores the original type found + * during resolution. + * + * @param name the name used during resolution + * @param location the location from which the symbol is accessed */ - ResolveError setWrongSym(Symbol sym) { - this.wrongSym = sym; - this.explanation = null; - return this; + protected Symbol access(Name name, TypeSymbol location) { + return types.createErrorType(name, location, syms.errSymbol.type).tsym; } - public boolean exists() { - switch (kind) { - case HIDDEN: - case ABSENT_VAR: - case ABSENT_MTH: - case ABSENT_TYP: - return false; - default: - return true; - } - } + /** + * Create a diagnostic representing this resolution error. + * + * @param dkind The kind of the diagnostic to be created (e.g error). + * @param pos The position to be used for error reporting. + * @param site The original type from where the selection took place. + * @param name The name of the symbol to be resolved. + * @param argtypes The invocation's value arguments, + * if we looked for a method. + * @param typeargtypes The invocation's type arguments, + * if we looked for a method. + */ + abstract JCDiagnostic getDiagnostic(JCDiagnostic.DiagnosticType dkind, + DiagnosticPosition pos, + Type site, + Name name, + List argtypes, + List typeargtypes); - /** Report error. - * @param log The error log to be used for error reporting. - * @param pos The position to be used for error reporting. - * @param site The original type from where the selection took place. - * @param name The name of the symbol to be resolved. - * @param argtypes The invocation's value arguments, - * if we looked for a method. - * @param typeargtypes The invocation's type arguments, - * if we looked for a method. - */ - void report(Log log, DiagnosticPosition pos, Type site, Name name, - List argtypes, List typeargtypes) { - if (argtypes == null) - argtypes = List.nil(); - if (typeargtypes == null) - typeargtypes = List.nil(); - if (name != names.error) { - KindName kindname = absentKind(kind); - Name idname = name; - if (kind >= WRONG_MTHS && kind <= ABSENT_MTH) { - if (isOperator(name)) { - log.error(pos, "operator.cant.be.applied", - name, argtypes); - return; - } - if (name == names.init) { - kindname = KindName.CONSTRUCTOR; - idname = site.tsym.name; - } - } - if (kind == WRONG_MTH) { - Symbol ws = wrongSym.asMemberOf(site, types); - log.error(pos, - "cant.apply.symbol" + (explanation != null ? ".1" : ""), - kindname, - ws.name == names.init ? ws.owner.name : ws.name, - methodArguments(ws.type.getParameterTypes()), - methodArguments(argtypes), - kindName(ws.owner), - ws.owner.type, - explanation); - } else if (!site.tsym.name.isEmpty()) { - if (site.tsym.kind == PCK && !site.tsym.exists()) - log.error(pos, "doesnt.exist", site.tsym); - else { - String errKey = getErrorKey("cant.resolve.location", - argtypes, typeargtypes, - kindname); - log.error(pos, errKey, kindname, idname, //symbol kindname, name - typeargtypes, argtypes, //type parameters and arguments (if any) - typeKindName(site), site); //location kindname, type - } - } else { - String errKey = getErrorKey("cant.resolve", - argtypes, typeargtypes, - kindname); - log.error(pos, errKey, kindname, idname, //symbol kindname, name - typeargtypes, argtypes); //type parameters and arguments (if any) - } - } - } - //where - String getErrorKey(String key, List argtypes, List typeargtypes, KindName kindname) { - String suffix = ""; - switch (kindname) { - case METHOD: - case CONSTRUCTOR: { - suffix += ".args"; - suffix += typeargtypes.nonEmpty() ? ".params" : ""; - } - } - return key + suffix; - } - - /** A name designates an operator if it consists - * of a non-empty sequence of operator symbols +-~!/*%&|^<>= + /** + * A name designates an operator if it consists + * of a non-empty sequence of operator symbols +-~!/*%&|^<>= */ boolean isOperator(Name name) { int i = 0; @@ -1747,9 +1672,206 @@ } } - /** Resolve error class indicating that a symbol is not accessible. + /** + * This class is the root class of all resolution errors caused by + * an invalid symbol being found during resolution. */ - class AccessError extends ResolveError { + abstract class InvalidSymbolError extends ResolveError { + + /** The invalid symbol found during resolution */ + Symbol sym; + + InvalidSymbolError(int kind, Symbol sym, String debugName) { + super(kind, debugName); + this.sym = sym; + } + + @Override + public boolean exists() { + return true; + } + + @Override + public String toString() { + return super.toString() + " wrongSym=" + sym; + } + + @Override + public Symbol access(Name name, TypeSymbol location) { + if (sym.kind >= AMBIGUOUS) + return ((ResolveError)sym).access(name, location); + else if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0) + return types.createErrorType(name, location, sym.type).tsym; + else + return sym; + } + } + + /** + * InvalidSymbolError error class indicating that a symbol matching a + * given name does not exists in a given site. + */ + class SymbolNotFoundError extends ResolveError { + + SymbolNotFoundError(int kind) { + super(kind, "symbol not found error"); + } + + @Override + JCDiagnostic getDiagnostic(JCDiagnostic.DiagnosticType dkind, + DiagnosticPosition pos, + Type site, + Name name, + List argtypes, + List typeargtypes) { + argtypes = argtypes == null ? List.nil() : argtypes; + typeargtypes = typeargtypes == null ? List.nil() : typeargtypes; + if (name == names.error) + return null; + + if (isOperator(name)) { + return diags.create(dkind, false, log.currentSource(), pos, + "operator.cant.be.applied", name, argtypes); + } + boolean hasLocation = false; + if (!site.tsym.name.isEmpty()) { + if (site.tsym.kind == PCK && !site.tsym.exists()) { + return diags.create(dkind, false, log.currentSource(), pos, + "doesnt.exist", site.tsym); + } + hasLocation = true; + } + boolean isConstructor = kind == ABSENT_MTH && + name == names.table.names.init; + KindName kindname = isConstructor ? KindName.CONSTRUCTOR : absentKind(kind); + Name idname = isConstructor ? site.tsym.name : name; + String errKey = getErrorKey(kindname, typeargtypes.nonEmpty(), hasLocation); + if (hasLocation) { + return diags.create(dkind, false, log.currentSource(), pos, + errKey, kindname, idname, //symbol kindname, name + typeargtypes, argtypes, //type parameters and arguments (if any) + typeKindName(site), site); //location kindname, type + } + else { + return diags.create(dkind, false, log.currentSource(), pos, + errKey, kindname, idname, //symbol kindname, name + typeargtypes, argtypes); //type parameters and arguments (if any) + } + } + //where + private String getErrorKey(KindName kindname, boolean hasTypeArgs, boolean hasLocation) { + String key = "cant.resolve"; + String suffix = hasLocation ? ".location" : ""; + switch (kindname) { + case METHOD: + case CONSTRUCTOR: { + suffix += ".args"; + suffix += hasTypeArgs ? ".params" : ""; + } + } + return key + suffix; + } + } + + /** + * InvalidSymbolError error class indicating that a given symbol + * (either a method, a constructor or an operand) is not applicable + * given an actual arguments/type argument list. + */ + class InapplicableSymbolError extends InvalidSymbolError { + + /** An auxiliary explanation set in case of instantiation errors. */ + JCDiagnostic explanation; + + InapplicableSymbolError(Symbol sym) { + super(WRONG_MTH, sym, "inapplicable symbol error"); + } + + /** Update sym and explanation and return this. + */ + InapplicableSymbolError setWrongSym(Symbol sym, JCDiagnostic explanation) { + this.sym = sym; + this.explanation = explanation; + return this; + } + + /** Update sym and return this. + */ + InapplicableSymbolError setWrongSym(Symbol sym) { + this.sym = sym; + this.explanation = null; + return this; + } + + @Override + public String toString() { + return super.toString() + " explanation=" + explanation; + } + + @Override + JCDiagnostic getDiagnostic(JCDiagnostic.DiagnosticType dkind, + DiagnosticPosition pos, + Type site, + Name name, + List argtypes, + List typeargtypes) { + if (name == names.error) + return null; + + if (isOperator(name)) { + return diags.create(dkind, false, log.currentSource(), + pos, "operator.cant.be.applied", name, argtypes); + } + else { + Symbol ws = sym.asMemberOf(site, types); + return diags.create(dkind, false, log.currentSource(), pos, + "cant.apply.symbol" + (explanation != null ? ".1" : ""), + kindName(ws), + ws.name == names.init ? ws.owner.name : ws.name, + methodArguments(ws.type.getParameterTypes()), + methodArguments(argtypes), + kindName(ws.owner), + ws.owner.type, + explanation); + } + } + + @Override + public Symbol access(Name name, TypeSymbol location) { + return types.createErrorType(name, location, syms.errSymbol.type).tsym; + } + } + + /** + * ResolveError error class indicating that a set of symbols + * (either methods, constructors or operands) is not applicable + * given an actual arguments/type argument list. + */ + class InapplicableSymbolsError extends ResolveError { + InapplicableSymbolsError(Symbol sym) { + super(WRONG_MTHS, "inapplicable symbols"); + } + + @Override + JCDiagnostic getDiagnostic(JCDiagnostic.DiagnosticType dkind, + DiagnosticPosition pos, + Type site, + Name name, + List argtypes, + List typeargtypes) { + return new SymbolNotFoundError(ABSENT_MTH).getDiagnostic(dkind, pos, + site, name, argtypes, typeargtypes); + } + } + + /** + * An InvalidSymbolError error class indicating that a symbol is not + * accessible from a given site + */ + class AccessError extends InvalidSymbolError { + + private Env env; + private Type site; AccessError(Symbol sym) { this(null, null, sym); @@ -1763,111 +1885,107 @@ log.error("proc.messager", sym + " @ " + site + " is inaccessible."); } - private Env env; - private Type site; + @Override + public boolean exists() { + return false; + } - /** Report error. - * @param log The error log to be used for error reporting. - * @param pos The position to be used for error reporting. - * @param site The original type from where the selection took place. - * @param name The name of the symbol to be resolved. - * @param argtypes The invocation's value arguments, - * if we looked for a method. - * @param typeargtypes The invocation's type arguments, - * if we looked for a method. - */ - void report(Log log, DiagnosticPosition pos, Type site, Name name, - List argtypes, List typeargtypes) { - if (sym.owner.type.tag != ERROR) { - if (sym.name == names.init && sym.owner != site.tsym) - new ResolveError(ABSENT_MTH, sym.owner, "absent method " + sym).report( - log, pos, site, name, argtypes, typeargtypes); - if ((sym.flags() & PUBLIC) != 0 - || (env != null && this.site != null - && !isAccessible(env, this.site))) - log.error(pos, "not.def.access.class.intf.cant.access", - sym, sym.location()); - else if ((sym.flags() & (PRIVATE | PROTECTED)) != 0) - log.error(pos, "report.access", sym, - asFlagSet(sym.flags() & (PRIVATE | PROTECTED)), - sym.location()); - else - log.error(pos, "not.def.public.cant.access", - sym, sym.location()); + @Override + JCDiagnostic getDiagnostic(JCDiagnostic.DiagnosticType dkind, + DiagnosticPosition pos, + Type site, + Name name, + List argtypes, + List typeargtypes) { + if (sym.owner.type.tag == ERROR) + return null; + + if (sym.name == names.init && sym.owner != site.tsym) { + return new SymbolNotFoundError(ABSENT_MTH).getDiagnostic(dkind, + pos, site, name, argtypes, typeargtypes); + } + else if ((sym.flags() & PUBLIC) != 0 + || (env != null && this.site != null + && !isAccessible(env, this.site))) { + return diags.create(dkind, false, log.currentSource(), + pos, "not.def.access.class.intf.cant.access", + sym, sym.location()); + } + else if ((sym.flags() & (PRIVATE | PROTECTED)) != 0) { + return diags.create(dkind, false, log.currentSource(), + pos, "report.access", sym, + asFlagSet(sym.flags() & (PRIVATE | PROTECTED)), + sym.location()); + } + else { + return diags.create(dkind, false, log.currentSource(), + pos, "not.def.public.cant.access", sym, sym.location()); } } } - /** Resolve error class indicating that an instance member was accessed - * from a static context. + /** + * InvalidSymbolError error class indicating that an instance member + * has erroneously been accessed from a static context. */ - class StaticError extends ResolveError { + class StaticError extends InvalidSymbolError { + StaticError(Symbol sym) { super(STATICERR, sym, "static error"); } - /** Report error. - * @param log The error log to be used for error reporting. - * @param pos The position to be used for error reporting. - * @param site The original type from where the selection took place. - * @param name The name of the symbol to be resolved. - * @param argtypes The invocation's value arguments, - * if we looked for a method. - * @param typeargtypes The invocation's type arguments, - * if we looked for a method. - */ - void report(Log log, - DiagnosticPosition pos, - Type site, - Name name, - List argtypes, - List typeargtypes) { + @Override + JCDiagnostic getDiagnostic(JCDiagnostic.DiagnosticType dkind, + DiagnosticPosition pos, + Type site, + Name name, + List argtypes, + List typeargtypes) { Symbol errSym = ((sym.kind == TYP && sym.type.tag == CLASS) ? types.erasure(sym.type).tsym : sym); - log.error(pos, "non-static.cant.be.ref", - kindName(sym), errSym); + return diags.create(dkind, false, log.currentSource(), pos, + "non-static.cant.be.ref", kindName(sym), errSym); } } - /** Resolve error class indicating an ambiguous reference. + /** + * InvalidSymbolError error class indicating that a pair of symbols + * (either methods, constructors or operands) are ambiguous + * given an actual arguments/type argument list. */ - class AmbiguityError extends ResolveError { - Symbol sym1; + class AmbiguityError extends InvalidSymbolError { + + /** The other maximally specific symbol */ Symbol sym2; AmbiguityError(Symbol sym1, Symbol sym2) { super(AMBIGUOUS, sym1, "ambiguity error"); - this.sym1 = sym1; this.sym2 = sym2; } - /** Report error. - * @param log The error log to be used for error reporting. - * @param pos The position to be used for error reporting. - * @param site The original type from where the selection took place. - * @param name The name of the symbol to be resolved. - * @param argtypes The invocation's value arguments, - * if we looked for a method. - * @param typeargtypes The invocation's type arguments, - * if we looked for a method. - */ - void report(Log log, DiagnosticPosition pos, Type site, Name name, - List argtypes, List typeargtypes) { + @Override + JCDiagnostic getDiagnostic(JCDiagnostic.DiagnosticType dkind, + DiagnosticPosition pos, + Type site, + Name name, + List argtypes, + List typeargtypes) { AmbiguityError pair = this; while (true) { - if (pair.sym1.kind == AMBIGUOUS) - pair = (AmbiguityError)pair.sym1; + if (pair.sym.kind == AMBIGUOUS) + pair = (AmbiguityError)pair.sym; else if (pair.sym2.kind == AMBIGUOUS) pair = (AmbiguityError)pair.sym2; else break; } - Name sname = pair.sym1.name; - if (sname == names.init) sname = pair.sym1.owner.name; - log.error(pos, "ref.ambiguous", sname, - kindName(pair.sym1), - pair.sym1, - pair.sym1.location(site, types), + Name sname = pair.sym.name; + if (sname == names.init) sname = pair.sym.owner.name; + return diags.create(dkind, false, log.currentSource(), + pos, "ref.ambiguous", sname, + kindName(pair.sym), + pair.sym, + pair.sym.location(site, types), kindName(pair.sym2), pair.sym2, pair.sym2.location(site, types)); diff -r ed989c347b3c -r 18e0269f25e3 src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java --- a/src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java Fri Jun 19 11:40:47 2009 -0700 +++ b/src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java Wed Jun 24 10:50:27 2009 +0100 @@ -83,7 +83,7 @@ */ public JCDiagnostic error( DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { - return new JCDiagnostic(formatter, ERROR, true, source, pos, qualify(ERROR, key), args); + return create(ERROR, true, source, pos, key, args); } /** @@ -96,7 +96,7 @@ */ public JCDiagnostic mandatoryWarning( DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { - return new JCDiagnostic(formatter, WARNING, true, source, pos, qualify(WARNING, key), args); + return create(WARNING, true, source, pos, key, args); } /** @@ -108,7 +108,7 @@ */ public JCDiagnostic warning( DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { - return new JCDiagnostic(formatter, WARNING, false, source, pos, qualify(WARNING, key), args); + return create(WARNING, false, source, pos, key, args); } /** @@ -118,7 +118,7 @@ * @see MandatoryWarningHandler */ public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) { - return new JCDiagnostic(formatter, NOTE, true, source, null, qualify(NOTE, key), args); + return create(NOTE, true, source, null, key, args); } /** @@ -127,7 +127,7 @@ * @param args Fields of the error message. */ public JCDiagnostic note(String key, Object... args) { - return note(null, null, key, args); + return create(NOTE, false, null, null, key, args); } /** @@ -139,7 +139,7 @@ */ public JCDiagnostic note( DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { - return new JCDiagnostic(formatter, NOTE, false, source, pos, qualify(NOTE, key), args); + return create(NOTE, false, source, pos, key, args); } /** @@ -148,7 +148,21 @@ * @param args Fields of the error message. */ public JCDiagnostic fragment(String key, Object... args) { - return new JCDiagnostic(formatter, FRAGMENT, false, null, null, qualify(FRAGMENT, key), args); + return create(FRAGMENT, false, null, null, key, args); + } + + /** + * Create a new diagnostic of the given kind. + * @param kind The diagnostic kind + * @param isMandatory is diagnostic mandatory? + * @param source The source of the compilation unit, if any, in which to report the note. + * @param pos The source position at which to report the note. + * @param key The key for the localized error message. + * @param args Fields of the error message. + */ + public JCDiagnostic create( + DiagnosticType kind, boolean isMandatory, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { + return new JCDiagnostic(formatter, kind, isMandatory, source, pos, qualify(kind, key), args); } protected String qualify(DiagnosticType t, String key) {