提交 91d18753 编写于 作者: M mcimadamore

6970584: Flow.java should be more error-friendly

Summary: Added a post-attribution visitor that fixup uninitialized types/symbol in AST after erroneous attribution
Reviewed-by: jjg
上级 81150693
...@@ -93,6 +93,10 @@ public class Symtab { ...@@ -93,6 +93,10 @@ public class Symtab {
*/ */
public final ClassSymbol errSymbol; public final ClassSymbol errSymbol;
/** The unknown symbol.
*/
public final ClassSymbol unknownSymbol;
/** A value for the errType, with a originalType of noType */ /** A value for the errType, with a originalType of noType */
public final Type errType; public final Type errType;
...@@ -354,6 +358,7 @@ public class Symtab { ...@@ -354,6 +358,7 @@ public class Symtab {
// create the error symbols // create the error symbols
errSymbol = new ClassSymbol(PUBLIC|STATIC|ACYCLIC, names.any, null, rootPackage); errSymbol = new ClassSymbol(PUBLIC|STATIC|ACYCLIC, names.any, null, rootPackage);
unknownSymbol = new ClassSymbol(PUBLIC|STATIC|ACYCLIC, names.fromString("<any?>"), null, rootPackage);
errType = new ErrorType(errSymbol, Type.noType); errType = new ErrorType(errSymbol, Type.noType);
// initialize builtin types // initialize builtin types
...@@ -368,7 +373,7 @@ public class Symtab { ...@@ -368,7 +373,7 @@ public class Symtab {
initType(voidType, "void", "Void"); initType(voidType, "void", "Void");
initType(botType, "<nulltype>"); initType(botType, "<nulltype>");
initType(errType, errSymbol); initType(errType, errSymbol);
initType(unknownType, "<any?>"); initType(unknownType, unknownSymbol);
// the builtin class of all arrays // the builtin class of all arrays
arrayClass = new ClassSymbol(PUBLIC|ACYCLIC, names.Array, noSymbol); arrayClass = new ClassSymbol(PUBLIC|ACYCLIC, names.Array, noSymbol);
......
...@@ -182,6 +182,7 @@ public class Annotate { ...@@ -182,6 +182,7 @@ public class Annotate {
if (!method.type.isErroneous()) if (!method.type.isErroneous())
buf.append(new Pair<MethodSymbol,Attribute> buf.append(new Pair<MethodSymbol,Attribute>
((MethodSymbol)method, value)); ((MethodSymbol)method, value));
t.type = result;
} }
return new Attribute.Compound(a.type, buf.toList()); return new Attribute.Compound(a.type, buf.toList());
} }
...@@ -234,6 +235,7 @@ public class Annotate { ...@@ -234,6 +235,7 @@ public class Annotate {
l.head, l.head,
env)); env));
} }
na.type = expected;
return new Attribute. return new Attribute.
Array(expected, buf.toArray(new Attribute[buf.length()])); Array(expected, buf.toArray(new Attribute[buf.length()]));
} }
......
...@@ -3201,4 +3201,104 @@ public class Attr extends JCTree.Visitor { ...@@ -3201,4 +3201,104 @@ public class Attr extends JCTree.Visitor {
super.visitMethodDef(tree); super.visitMethodDef(tree);
} }
}; };
// <editor-fold desc="post-attribution visitor">
/**
* Handle missing types/symbols in an AST. This routine is useful when
* the compiler has encountered some errors (which might have ended up
* terminating attribution abruptly); if the compiler is used in fail-over
* mode (e.g. by an IDE) and the AST contains semantic errors, this routine
* prevents NPE to be progagated during subsequent compilation steps.
*/
public void postAttr(Env<AttrContext> env) {
new PostAttrAnalyzer().scan(env.tree);
}
class PostAttrAnalyzer extends TreeScanner {
private void initTypeIfNeeded(JCTree that) {
if (that.type == null) {
that.type = syms.unknownType;
}
}
@Override
public void scan(JCTree tree) {
if (tree == null) return;
if (tree instanceof JCExpression) {
initTypeIfNeeded(tree);
}
super.scan(tree);
}
@Override
public void visitIdent(JCIdent that) {
if (that.sym == null) {
that.sym = syms.unknownSymbol;
}
}
@Override
public void visitSelect(JCFieldAccess that) {
if (that.sym == null) {
that.sym = syms.unknownSymbol;
}
super.visitSelect(that);
}
@Override
public void visitClassDef(JCClassDecl that) {
initTypeIfNeeded(that);
if (that.sym == null) {
that.sym = new ClassSymbol(0, that.name, that.type, syms.noSymbol);
}
super.visitClassDef(that);
}
@Override
public void visitMethodDef(JCMethodDecl that) {
initTypeIfNeeded(that);
if (that.sym == null) {
that.sym = new MethodSymbol(0, that.name, that.type, syms.noSymbol);
}
super.visitMethodDef(that);
}
@Override
public void visitVarDef(JCVariableDecl that) {
initTypeIfNeeded(that);
if (that.sym == null) {
that.sym = new VarSymbol(0, that.name, that.type, syms.noSymbol);
that.sym.adr = 0;
}
super.visitVarDef(that);
}
@Override
public void visitNewClass(JCNewClass that) {
if (that.constructor == null) {
that.constructor = new MethodSymbol(0, names.init, syms.unknownType, syms.noSymbol);
}
if (that.constructorType == null) {
that.constructorType = syms.unknownType;
}
super.visitNewClass(that);
}
@Override
public void visitBinary(JCBinary that) {
if (that.operator == null)
that.operator = new OperatorSymbol(names.empty, syms.unknownType, -1, syms.noSymbol);
super.visitBinary(that);
}
@Override
public void visitUnary(JCUnary that) {
if (that.operator == null)
that.operator = new OperatorSymbol(names.empty, syms.unknownType, -1, syms.noSymbol);
super.visitUnary(that);
}
}
// </editor-fold>
} }
...@@ -408,7 +408,9 @@ public class Flow extends TreeScanner { ...@@ -408,7 +408,9 @@ public class Flow extends TreeScanner {
tree = TreeInfo.skipParens(tree); tree = TreeInfo.skipParens(tree);
if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) { if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) {
Symbol sym = TreeInfo.symbol(tree); Symbol sym = TreeInfo.symbol(tree);
letInit(tree.pos(), (VarSymbol)sym); if (sym.kind == VAR) {
letInit(tree.pos(), (VarSymbol)sym);
}
} }
} }
...@@ -481,12 +483,13 @@ public class Flow extends TreeScanner { ...@@ -481,12 +483,13 @@ public class Flow extends TreeScanner {
/** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
*/ */
void split() { void split(boolean setToNull) {
initsWhenFalse = inits.dup(); initsWhenFalse = inits.dup();
uninitsWhenFalse = uninits.dup(); uninitsWhenFalse = uninits.dup();
initsWhenTrue = inits; initsWhenTrue = inits;
uninitsWhenTrue = uninits; uninitsWhenTrue = uninits;
inits = uninits = null; if (setToNull)
inits = uninits = null;
} }
/** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets. /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
...@@ -568,9 +571,11 @@ public class Flow extends TreeScanner { ...@@ -568,9 +571,11 @@ public class Flow extends TreeScanner {
uninitsWhenTrue = uninits; uninitsWhenTrue = uninits;
} else { } else {
scan(tree); scan(tree);
if (inits != null) split(); if (inits != null)
split(tree.type != syms.unknownType);
} }
inits = uninits = null; if (tree.type != syms.unknownType)
inits = uninits = null;
} }
/* ------------ Visitor methods for various sorts of trees -------------*/ /* ------------ Visitor methods for various sorts of trees -------------*/
...@@ -1007,7 +1012,7 @@ public class Flow extends TreeScanner { ...@@ -1007,7 +1012,7 @@ public class Flow extends TreeScanner {
List.of(resource.type); List.of(resource.type);
for (Type sup : closeableSupertypes) { for (Type sup : closeableSupertypes) {
if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) { if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
Symbol closeMethod = rs.resolveInternalMethod(tree, Symbol closeMethod = rs.resolveQualifiedMethod(tree,
attrEnv, attrEnv,
sup, sup,
names.close, names.close,
...@@ -1050,20 +1055,22 @@ public class Flow extends TreeScanner { ...@@ -1050,20 +1055,22 @@ public class Flow extends TreeScanner {
List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry); List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
for (JCExpression ct : subClauses) { for (JCExpression ct : subClauses) {
Type exc = ct.type; Type exc = ct.type;
ctypes = ctypes.append(exc); if (exc != syms.unknownType) {
if (types.isSameType(exc, syms.objectType)) ctypes = ctypes.append(exc);
continue; if (types.isSameType(exc, syms.objectType))
if (chk.subset(exc, caughtInTry)) { continue;
log.error(l.head.pos(), if (chk.subset(exc, caughtInTry)) {
"except.already.caught", exc); log.error(l.head.pos(),
} else if (!chk.isUnchecked(l.head.pos(), exc) && "except.already.caught", exc);
exc.tsym != syms.throwableType.tsym && } else if (!chk.isUnchecked(l.head.pos(), exc) &&
exc.tsym != syms.exceptionType.tsym && exc.tsym != syms.throwableType.tsym &&
!chk.intersects(exc, thrownInTry)) { exc.tsym != syms.exceptionType.tsym &&
log.error(l.head.pos(), !chk.intersects(exc, thrownInTry)) {
"except.never.thrown.in.try", exc); log.error(l.head.pos(),
"except.never.thrown.in.try", exc);
}
caughtInTry = chk.incl(exc, caughtInTry);
} }
caughtInTry = chk.incl(exc, caughtInTry);
} }
inits = initsTry.dup(); inits = initsTry.dup();
uninits = uninitsTry.dup(); uninits = uninitsTry.dup();
......
...@@ -1144,6 +1144,11 @@ public class JavaCompiler implements ClassReader.SourceCompleter { ...@@ -1144,6 +1144,11 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
env.toplevel.sourcefile); env.toplevel.sourcefile);
try { try {
attr.attribClass(env.tree.pos(), env.enclClass.sym); attr.attribClass(env.tree.pos(), env.enclClass.sym);
if (errorCount() > 0 && !shouldStop(CompileState.ATTR)) {
//if in fail-over mode, ensure that AST expression nodes
//are correctly initialized (e.g. they have a type/symbol)
attr.postAttr(env);
}
compileStates.put(env, CompileState.ATTR); compileStates.put(env, CompileState.ATTR);
} }
finally { finally {
......
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver01.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver01.java
*/
class Test { { x = "" } }
FailOver01.java:10:22: compiler.err.expected: ';'
FailOver01.java:10:16: compiler.err.cant.resolve.location: kindname.variable, x, , , kindname.class, Test
2 errors
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver02.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver02.java
*/
class Test implements AutoCloseable {
void test() {
try(Test t = null) {}
}
}
FailOver02.java:10:1: compiler.err.does.not.override.abstract: Test, close(), java.lang.AutoCloseable
FailOver02.java:12:9: compiler.err.cant.resolve.location.args: kindname.method, close, , , kindname.class, Test
2 errors
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver03.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver03.java
*/
class Test extends Test {
Test i;
}
FailOver03.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver04.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver04.java
*/
class Test {
{ new Unknown() {}; }
}
FailOver04.java:11:10: compiler.err.cant.resolve.location: kindname.class, Unknown, , , kindname.class, Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver05.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver05.java
*/
class Test extends Test {
{ for ( Integer x : null) {} }
}
FailOver05.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver06.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver06.java
*/
class Test extends Test {
Inference x = 1;
{ if (x == 1) { } else { } }
}
FailOver06.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver07.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver07.java
*/
class Test extends Test {
Integer x = 1;
{ do {} while (x); }
}
FailOver07.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver08.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver08.java
*/
class Test extends Test {
Integer x = 1;
{ while (x) {}; }
}
FailOver08.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver09.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver09.java
*/
class Test extends Test {
Integer x = 1;
{ for (x = 0 ; x ; x++) {}; }
}
FailOver09.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver10.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver10.java
*/
class Test extends Test {
boolean cond;
{ Object o = null; }
}
FailOver10.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver11.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver11.java
*/
class Test extends Test {
boolean cond;
void m(Object o) {}
{ m(cond ? null : null); }
}
FailOver11.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver12.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver12.java
*/
class Test extends Test {
Integer x = 1;
{ try {} catch (Exception e) {} }
}
FailOver12.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver13.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver13.java
*/
class Test extends Test {
Integer x = 1;
{ x = (Object)o; }
}
FailOver13.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
/*
* @test /nodynamiccopyright/
* @bug 6970584
* @summary Flow.java should be more error-friendly
* @author mcimadamore
*
* @compile/fail/ref=FailOver14.out -XDrawDiagnostics -XDshouldStopPolicy=FLOW -XDdev FailOver14.java
*/
class Test extends Test {
{ for (Integer x : !x) { } }
}
FailOver14.java:10:1: compiler.err.cyclic.inheritance: Test
1 error
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册