This commit is contained in:
Tim Bell 2009-06-24 17:34:13 -07:00
commit c76e1a308a
9 changed files with 482 additions and 246 deletions

View File

@ -95,6 +95,7 @@ public class Kinds {
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 @@ public class Kinds {
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 @@ public class Kinds {
case EXCEPTION_PARAMETER:
return KindName.VAR;
case METHOD:
case CONSTRUCTOR:
return KindName.CONSTRUCTOR;
case METHOD:
case STATIC_INIT:
case INSTANCE_INIT:
return KindName.METHOD;

View File

@ -303,7 +303,7 @@ public class Attr extends JCTree.Visitor {
public Env<AttrContext> attribExprToTree(JCTree expr, Env<AttrContext> env, JCTree tree) {
breakTree = tree;
JavaFileObject prev = log.useSource(null);
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
try {
attribExpr(expr, env);
} catch (BreakAttr b) {
@ -317,7 +317,7 @@ public class Attr extends JCTree.Visitor {
public Env<AttrContext> attribStatToTree(JCTree stmt, Env<AttrContext> env, JCTree tree) {
breakTree = tree;
JavaFileObject prev = log.useSource(null);
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
try {
attribStat(stmt, env);
} catch (BreakAttr b) {

View File

@ -82,15 +82,15 @@ public class Resolve {
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 @@ public class Resolve {
/** 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 @@ public class Resolve {
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 @@ public class Resolve {
List<Type> argtypes,
List<Type> 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 class Resolve {
public void logAccessError(Env<AttrContext> 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<Type> argtypes,
List<Type> 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 @@ public class Resolve {
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) {
super(kind, 0, null, null, null);
this.debugName = debugName;
this.sym = sym;
}
/** The name of the kind of error, for debugging only.
*/
/** 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;
ResolveError(int kind, String debugName) {
super(kind, 0, null, null, null);
this.debugName = debugName;
}
@Override
public <R, P> R accept(ElementVisitor<R, P> 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;
}
/** Update wrongSym and explanation and return this.
*/
ResolveError setWrongSym(Symbol sym, JCDiagnostic explanation) {
this.wrongSym = sym;
this.explanation = explanation;
return this;
}
/** Update wrongSym and return this.
*/
ResolveError setWrongSym(Symbol sym) {
this.wrongSym = sym;
this.explanation = null;
return this;
return debugName;
}
@Override
public boolean exists() {
switch (kind) {
case HIDDEN:
case ABSENT_VAR:
case ABSENT_MTH:
case ABSENT_TYP:
return false;
default:
return true;
}
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.
/**
* 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
*/
void report(Log log, DiagnosticPosition pos, Type site, Name name,
List<Type> argtypes, List<Type> 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<Type> argtypes, List<Type> typeargtypes, KindName kindname) {
String suffix = "";
switch (kindname) {
case METHOD:
case CONSTRUCTOR: {
suffix += ".args";
suffix += typeargtypes.nonEmpty() ? ".params" : "";
}
}
return key + suffix;
protected Symbol access(Name name, TypeSymbol location) {
return types.createErrorType(name, location, syms.errSymbol.type).tsym;
}
/** A name designates an operator if it consists
* of a non-empty sequence of operator symbols +-~!/*%&|^<>=
/**
* 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<Type> argtypes,
List<Type> typeargtypes);
/**
* 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 @@ public class Resolve {
}
}
/** 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<Type> argtypes,
List<Type> typeargtypes) {
argtypes = argtypes == null ? List.<Type>nil() : argtypes;
typeargtypes = typeargtypes == null ? List.<Type>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<Type> argtypes,
List<Type> 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<Type> argtypes,
List<Type> 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<AttrContext> env;
private Type site;
AccessError(Symbol sym) {
this(null, null, sym);
@ -1763,111 +1885,107 @@ public class Resolve {
log.error("proc.messager", sym + " @ " + site + " is inaccessible.");
}
private Env<AttrContext> 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<Type> argtypes, List<Type> 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<Type> argtypes,
List<Type> 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<Type> argtypes,
List<Type> typeargtypes) {
@Override
JCDiagnostic getDiagnostic(JCDiagnostic.DiagnosticType dkind,
DiagnosticPosition pos,
Type site,
Name name,
List<Type> argtypes,
List<Type> 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<Type> argtypes, List<Type> typeargtypes) {
@Override
JCDiagnostic getDiagnostic(JCDiagnostic.DiagnosticType dkind,
DiagnosticPosition pos,
Type site,
Name name,
List<Type> argtypes,
List<Type> 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));

View File

@ -109,7 +109,7 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter
return formatDiagnostic(d, locale);
}
abstract String formatDiagnostic(JCDiagnostic d, Locale locale);
protected abstract String formatDiagnostic(JCDiagnostic d, Locale locale);
public String formatPosition(JCDiagnostic d, PositionKind pk,Locale l) {
assert (d.getPosition() != Position.NOPOS);

View File

@ -58,7 +58,7 @@ public abstract class AbstractLog {
protected DiagnosticSource getSource(JavaFileObject file) {
if (file == null)
return null;
return DiagnosticSource.NO_SOURCE;
DiagnosticSource s = sourceMap.get(file);
if (s == null) {
s = new DiagnosticSource(file, this);

View File

@ -46,11 +46,22 @@ import static com.sun.tools.javac.util.LayoutCharacters.*;
* deletion without notice.</b>
*/
public class DiagnosticSource {
/* constant DiagnosticSource to be used when sourcefile is missing */
public static final DiagnosticSource NO_SOURCE = new DiagnosticSource() {
@Override
protected boolean findLine(int pos) {
return false;
}
};
public DiagnosticSource(JavaFileObject fo, AbstractLog log) {
this.fileObject = fo;
this.log = log;
}
private DiagnosticSource() {}
/** Return the underlying file object handled by this
* DiagnosticSource object.
*/
@ -134,7 +145,7 @@ public class DiagnosticSource {
/** Find the line in the buffer that contains the current position
* @param pos Character offset into the buffer
*/
private boolean findLine(int pos) {
protected boolean findLine(int pos) {
if (pos == Position.NOPOS)
return false;

View File

@ -83,7 +83,7 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
*/
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 class JCDiagnostic implements Diagnostic<JavaFileObject> {
*/
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 class JCDiagnostic implements Diagnostic<JavaFileObject> {
*/
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 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
* @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 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
* @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 class JCDiagnostic implements Diagnostic<JavaFileObject> {
*/
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 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
* @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) {

View File

@ -68,7 +68,10 @@ public class RichDiagnosticFormatter extends
final JavacMessages messages;
/* name simplifier used by this formatter */
ClassNameSimplifier nameSimplifier;
protected ClassNameSimplifier nameSimplifier;
/* type/symbol printer used by this formatter */
private RichPrinter printer;
/* map for keeping track of a where clause associated to a given type */
Map<WhereClauseKind, Map<Type, JCDiagnostic>> whereClauses;
@ -83,7 +86,7 @@ public class RichDiagnosticFormatter extends
protected RichDiagnosticFormatter(Context context) {
super((AbstractDiagnosticFormatter)Log.instance(context).getDiagnosticFormatter());
this.formatter.setPrinter(printer);
setRichPrinter(new RichPrinter());
this.syms = Symtab.instance(context);
this.diags = JCDiagnostic.Factory.instance(context);
this.types = Types.instance(context);
@ -116,6 +119,23 @@ public class RichDiagnosticFormatter extends
return sb.toString();
}
/**
* Sets the type/symbol printer used by this formatter.
* @param printer the rich printer to be set
*/
protected void setRichPrinter(RichPrinter printer) {
this.printer = printer;
formatter.setPrinter(printer);
}
/**
* Gets the type/symbol printer used by this formatter.
* @return type/symbol rich printer
*/
protected RichPrinter getRichPrinter() {
return printer;
}
/**
* Preprocess a given diagnostic by looking both into its arguments and into
* its subdiagnostics (if any). This preprocessing is responsible for
@ -217,7 +237,7 @@ public class RichDiagnosticFormatter extends
* name belong to different packages - in this case the formatter reverts
* to fullnames as compact names might lead to a confusing diagnostic.
*/
class ClassNameSimplifier {
protected class ClassNameSimplifier {
/* table for keeping track of all short name usages */
Map<Name, List<Symbol>> nameClashes = new HashMap<Name, List<Symbol>>();
@ -272,7 +292,7 @@ public class RichDiagnosticFormatter extends
* discovered during type/symbol preprocessing. This printer is set on the delegate
* formatter so that rich type/symbol info can be properly rendered.
*/
protected Printer printer = new Printer() {
protected class RichPrinter extends Printer {
@Override
public String localize(Locale locale, String key, Object... args) {

View File

@ -0,0 +1,66 @@
/*
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6852595
* @summary Accessing scope using JSR199 API on erroneous tree causes Illegal Argument Exception
* @author mcimadamore
*/
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import com.sun.source.util.JavacTask;
import com.sun.source.tree.*;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.tree.JCTree.*;
import static javax.tools.JavaFileObject.Kind;
public class T6852595 {
public static void main(String[] args) throws IOException {
JavaFileObject sfo = new SimpleJavaFileObject(URI.create("myfo:/Test.java"),Kind.SOURCE) {
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return "class BadName { Object o = j; }";
}
};
List<? extends JavaFileObject> files = Arrays.asList(sfo);
JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
JavacTask ct = (JavacTask)tool.getTask(null, null, null, null, null, files);
Iterable<? extends CompilationUnitTree> compUnits = ct.parse();
CompilationUnitTree cu = compUnits.iterator().next();
ClassTree cdef = (ClassTree)cu.getTypeDecls().get(0);
JCVariableDecl vdef = (JCVariableDecl)cdef.getMembers().get(0);
TreePath path = TreePath.getPath(cu, vdef.init);
Trees.instance(ct).getScope(path);
}
}