8205418: Assorted improvements to source code model
Improving tree positions, better error recovery, fixing Trees.getScope for possibly erroneous lambdas. Reviewed-by: jjg, mcimadamore, vromero
This commit is contained in:
parent
69191fc4cc
commit
eaf0364068
@ -1659,7 +1659,7 @@ public class Types {
|
||||
private TypeRelation isCastable = new TypeRelation() {
|
||||
|
||||
public Boolean visitType(Type t, Type s) {
|
||||
if (s.hasTag(ERROR))
|
||||
if (s.hasTag(ERROR) || t.hasTag(NONE))
|
||||
return true;
|
||||
|
||||
switch (t.getTag()) {
|
||||
|
@ -586,8 +586,11 @@ public class Attr extends JCTree.Visitor {
|
||||
class RecoveryInfo extends ResultInfo {
|
||||
|
||||
public RecoveryInfo(final DeferredAttr.DeferredAttrContext deferredAttrContext) {
|
||||
super(KindSelector.VAL, Type.recoveryType,
|
||||
new Check.NestedCheckContext(chk.basicHandler) {
|
||||
this(deferredAttrContext, Type.recoveryType);
|
||||
}
|
||||
|
||||
public RecoveryInfo(final DeferredAttr.DeferredAttrContext deferredAttrContext, Type pt) {
|
||||
super(KindSelector.VAL, pt, new Check.NestedCheckContext(chk.basicHandler) {
|
||||
@Override
|
||||
public DeferredAttr.DeferredAttrContext deferredAttrContext() {
|
||||
return deferredAttrContext;
|
||||
@ -598,8 +601,10 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
@Override
|
||||
public void report(DiagnosticPosition pos, JCDiagnostic details) {
|
||||
if (pt == Type.recoveryType) {
|
||||
chk.basicHandler.report(pos, details);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -656,7 +661,7 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
if (tree == breakTree &&
|
||||
resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
|
||||
throw new BreakAttr(copyEnv(env));
|
||||
breakTreeFound(copyEnv(env));
|
||||
}
|
||||
return result;
|
||||
} catch (CompletionFailure ex) {
|
||||
@ -668,6 +673,10 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
}
|
||||
|
||||
protected void breakTreeFound(Env<AttrContext> env) {
|
||||
throw new BreakAttr(env);
|
||||
}
|
||||
|
||||
Env<AttrContext> copyEnv(Env<AttrContext> env) {
|
||||
Env<AttrContext> newEnv =
|
||||
env.dup(env.tree, env.info.dup(copyScope(env.info.scope)));
|
||||
@ -2506,8 +2515,7 @@ public class Attr extends JCTree.Visitor {
|
||||
//lambda only allowed in assignment or method invocation/cast context
|
||||
log.error(that.pos(), Errors.UnexpectedLambda);
|
||||
}
|
||||
result = that.type = types.createErrorType(pt());
|
||||
return;
|
||||
resultInfo = recoveryInfo;
|
||||
}
|
||||
//create an environment for attribution of the lambda expression
|
||||
final Env<AttrContext> localEnv = lambdaEnv(that, env);
|
||||
@ -2595,6 +2603,10 @@ public class Attr extends JCTree.Visitor {
|
||||
attribTree(that.getBody(), localEnv, bodyResultInfo);
|
||||
} else {
|
||||
JCBlock body = (JCBlock)that.body;
|
||||
if (body == breakTree &&
|
||||
resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
|
||||
breakTreeFound(copyEnv(localEnv));
|
||||
}
|
||||
attribStats(body.stats, localEnv);
|
||||
}
|
||||
|
||||
@ -4126,8 +4138,8 @@ public class Attr extends JCTree.Visitor {
|
||||
typeargtypes,
|
||||
noteWarner);
|
||||
|
||||
DeferredAttr.DeferredTypeMap checkDeferredMap =
|
||||
deferredAttr.new DeferredTypeMap(DeferredAttr.AttrMode.CHECK, sym, env.info.pendingResolutionPhase);
|
||||
DeferredAttr.DeferredTypeMap<Void> checkDeferredMap =
|
||||
deferredAttr.new DeferredTypeMap<>(DeferredAttr.AttrMode.CHECK, sym, env.info.pendingResolutionPhase);
|
||||
|
||||
argtypes = argtypes.map(checkDeferredMap);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
@ -28,6 +28,8 @@ package com.sun.tools.javac.comp;
|
||||
import com.sun.source.tree.LambdaExpressionTree.BodyKind;
|
||||
import com.sun.source.tree.NewClassTree;
|
||||
import com.sun.tools.javac.code.*;
|
||||
import com.sun.tools.javac.code.Type.ErrorType;
|
||||
import com.sun.tools.javac.code.Type.MethodType;
|
||||
import com.sun.tools.javac.code.Type.StructuralTypeMapping;
|
||||
import com.sun.tools.javac.code.Types.TypeMapping;
|
||||
import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
|
||||
@ -59,6 +61,7 @@ import java.util.WeakHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.sun.source.tree.MemberReferenceTree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMemberReference.OverloadKind;
|
||||
|
||||
import static com.sun.tools.javac.code.TypeTag.*;
|
||||
@ -1002,7 +1005,7 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||
* where T is computed by retrieving the type that has already been
|
||||
* computed for D during a previous deferred attribution round of the given kind.
|
||||
*/
|
||||
class DeferredTypeMap extends StructuralTypeMapping<Void> {
|
||||
class DeferredTypeMap<T> extends StructuralTypeMapping<T> {
|
||||
DeferredAttrContext deferredAttrContext;
|
||||
|
||||
protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
|
||||
@ -1011,16 +1014,16 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitType(Type t, Void _unused) {
|
||||
public Type visitType(Type t, T p) {
|
||||
if (!t.hasTag(DEFERRED)) {
|
||||
return super.visitType(t, null);
|
||||
return super.visitType(t, p);
|
||||
} else {
|
||||
DeferredType dt = (DeferredType)t;
|
||||
return typeOf(dt);
|
||||
return typeOf(dt, p);
|
||||
}
|
||||
}
|
||||
|
||||
protected Type typeOf(DeferredType dt) {
|
||||
protected Type typeOf(DeferredType dt, T p) {
|
||||
switch (deferredAttrContext.mode) {
|
||||
case CHECK:
|
||||
return dt.tree.type == null ? Type.noType : dt.tree.type;
|
||||
@ -1039,17 +1042,35 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||
* attribution round (as before), or (ii) by synthesizing a new type R for D
|
||||
* (the latter step is useful in a recovery scenario).
|
||||
*/
|
||||
public class RecoveryDeferredTypeMap extends DeferredTypeMap {
|
||||
public class RecoveryDeferredTypeMap extends DeferredTypeMap<Type> {
|
||||
|
||||
public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
|
||||
super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Type typeOf(DeferredType dt) {
|
||||
Type owntype = super.typeOf(dt);
|
||||
protected Type typeOf(DeferredType dt, Type pt) {
|
||||
Type owntype = super.typeOf(dt, pt);
|
||||
return owntype == Type.noType ?
|
||||
recover(dt) : owntype;
|
||||
recover(dt, pt) : owntype;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitMethodType(Type.MethodType t, Type pt) {
|
||||
if (t.hasTag(METHOD) && deferredAttrContext.mode == AttrMode.CHECK) {
|
||||
Type mtype = deferredAttrContext.msym.type;
|
||||
mtype = mtype.hasTag(ERROR) ? ((ErrorType)mtype).getOriginalType() : null;
|
||||
if (mtype != null && mtype.hasTag(METHOD)) {
|
||||
List<Type> argtypes1 = map(t.getParameterTypes(), mtype.getParameterTypes());
|
||||
Type restype1 = visit(t.getReturnType(), mtype.getReturnType());
|
||||
List<Type> thrown1 = map(t.getThrownTypes(), mtype.getThrownTypes());
|
||||
if (argtypes1 == t.getParameterTypes() &&
|
||||
restype1 == t.getReturnType() &&
|
||||
thrown1 == t.getThrownTypes()) return t;
|
||||
else return new MethodType(argtypes1, restype1, thrown1, t.tsym);
|
||||
}
|
||||
}
|
||||
return super.visitMethodType(t, pt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1059,8 +1080,8 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||
* representation. Remaining deferred types are attributed using
|
||||
* a default expected type (j.l.Object).
|
||||
*/
|
||||
private Type recover(DeferredType dt) {
|
||||
dt.check(attr.new RecoveryInfo(deferredAttrContext) {
|
||||
private Type recover(DeferredType dt, Type pt) {
|
||||
dt.check(attr.new RecoveryInfo(deferredAttrContext, pt != null ? pt : Type.recoveryType) {
|
||||
@Override
|
||||
protected Type check(DiagnosticPosition pos, Type found) {
|
||||
return chk.checkNonVoid(pos, super.check(pos, found));
|
||||
@ -1068,6 +1089,16 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||
});
|
||||
return super.visit(dt);
|
||||
}
|
||||
|
||||
private List<Type> map(List<Type> ts, List<Type> pts) {
|
||||
if (ts.nonEmpty()) {
|
||||
List<Type> tail1 = map(ts.tail, pts != null ? pts.tail : null);
|
||||
Type t = visit(ts.head, pts != null && pts.nonEmpty() ? pts.head : null);
|
||||
if (tail1 != ts.tail || t != ts.head)
|
||||
return tail1.prepend(t);
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -602,7 +602,7 @@ public class Infer {
|
||||
return mtype;
|
||||
}
|
||||
//where
|
||||
class ImplicitArgType extends DeferredAttr.DeferredTypeMap {
|
||||
class ImplicitArgType extends DeferredAttr.DeferredTypeMap<Void> {
|
||||
|
||||
public ImplicitArgType(Symbol msym, Resolve.MethodResolutionPhase phase) {
|
||||
(rs.deferredAttr).super(AttrMode.SPECULATIVE, msym, phase);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2018, 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
|
||||
@ -210,7 +210,7 @@ public class Operators {
|
||||
* Report an operator lookup error.
|
||||
*/
|
||||
private OperatorSymbol reportErrorIfNeeded(DiagnosticPosition pos, Tag tag, Type... args) {
|
||||
if (Stream.of(args).noneMatch(Type::isErroneous)) {
|
||||
if (Stream.of(args).noneMatch(t -> t.isErroneous() || t.hasTag(TypeTag.NONE))) {
|
||||
Name opName = operatorName(tag);
|
||||
JCDiagnostic.Error opError = (args.length) == 1 ?
|
||||
Errors.OperatorCantBeApplied(opName, args[0]) :
|
||||
|
@ -2560,8 +2560,8 @@ public class Resolve {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Type typeOf(DeferredType dt) {
|
||||
Type res = super.typeOf(dt);
|
||||
protected Type typeOf(DeferredType dt, Type pt) {
|
||||
Type res = super.typeOf(dt, pt);
|
||||
if (!res.isErroneous()) {
|
||||
switch (TreeInfo.skipParens(dt.tree).getTag()) {
|
||||
case LAMBDA:
|
||||
@ -3992,7 +3992,12 @@ public class Resolve {
|
||||
|
||||
@Override
|
||||
public Symbol access(Name name, TypeSymbol location) {
|
||||
return types.createErrorType(name, location, syms.errSymbol.type).tsym;
|
||||
Symbol sym = bestCandidate();
|
||||
return types.createErrorType(name, location, sym != null ? sym.type : syms.errSymbol.type).tsym;
|
||||
}
|
||||
|
||||
protected Symbol bestCandidate() {
|
||||
return errCandidate().fst;
|
||||
}
|
||||
|
||||
protected Pair<Symbol, JCDiagnostic> errCandidate() {
|
||||
@ -4123,6 +4128,16 @@ public class Resolve {
|
||||
//conform to source order
|
||||
return details;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Symbol bestCandidate() {
|
||||
Map<Symbol, JCDiagnostic> candidatesMap = mapCandidates();
|
||||
Map<Symbol, JCDiagnostic> filteredCandidates = filterCandidates(candidatesMap);
|
||||
if (filteredCandidates.size() == 1) {
|
||||
return filteredCandidates.keySet().iterator().next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2018, 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
|
||||
@ -674,7 +674,7 @@ public class JavaTokenizer {
|
||||
scanNumber(pos, 10);
|
||||
} else if (reader.bp == reader.buflen || reader.ch == EOI && reader.bp + 1 == reader.buflen) { // JLS 3.5
|
||||
tk = TokenKind.EOF;
|
||||
pos = reader.buflen;
|
||||
pos = reader.realLength;
|
||||
} else {
|
||||
String arg;
|
||||
|
||||
|
@ -1516,6 +1516,7 @@ public class JavacParser implements Parser {
|
||||
ParensResult analyzeParens() {
|
||||
int depth = 0;
|
||||
boolean type = false;
|
||||
ParensResult defaultResult = ParensResult.PARENS;
|
||||
outer: for (int lookahead = 0 ; ; lookahead++) {
|
||||
TokenKind tk = S.token(lookahead).kind;
|
||||
switch (tk) {
|
||||
@ -1568,7 +1569,7 @@ public class JavacParser implements Parser {
|
||||
case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
|
||||
return ParensResult.CAST;
|
||||
default:
|
||||
return ParensResult.PARENS;
|
||||
return defaultResult;
|
||||
}
|
||||
case UNDERSCORE:
|
||||
case ASSERT:
|
||||
@ -1580,6 +1581,8 @@ public class JavacParser implements Parser {
|
||||
} else if (peekToken(lookahead, RPAREN, ARROW)) {
|
||||
// Identifier, ')' '->' -> implicit lambda
|
||||
return ParensResult.IMPLICIT_LAMBDA;
|
||||
} else if (depth == 0 && peekToken(lookahead, COMMA)) {
|
||||
defaultResult = ParensResult.IMPLICIT_LAMBDA;
|
||||
}
|
||||
type = false;
|
||||
break;
|
||||
@ -1665,7 +1668,7 @@ public class JavacParser implements Parser {
|
||||
break;
|
||||
default:
|
||||
//this includes EOF
|
||||
return ParensResult.PARENS;
|
||||
return defaultResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3753,10 +3756,16 @@ public class JavacParser implements Parser {
|
||||
return defs;
|
||||
} else {
|
||||
pos = token.pos;
|
||||
List<JCTree> err = isVoid
|
||||
? List.of(toP(F.at(pos).MethodDef(mods, name, type, typarams,
|
||||
List.nil(), List.nil(), null, null)))
|
||||
: null;
|
||||
List<JCTree> err;
|
||||
if (isVoid || typarams.nonEmpty()) {
|
||||
JCMethodDecl m =
|
||||
toP(F.at(pos).MethodDef(mods, name, type, typarams,
|
||||
List.nil(), List.nil(), null, null));
|
||||
attach(m, dc);
|
||||
err = List.of(m);
|
||||
} else {
|
||||
err = List.nil();
|
||||
}
|
||||
return List.of(syntaxError(token.pos, err, Errors.Expected(LPAREN)));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2018, 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
|
||||
@ -70,6 +70,7 @@ public class UnicodeReader {
|
||||
/** A character buffer for saved chars.
|
||||
*/
|
||||
protected char[] sbuf = new char[128];
|
||||
protected int realLength;
|
||||
protected int sp;
|
||||
|
||||
/**
|
||||
@ -89,6 +90,7 @@ public class UnicodeReader {
|
||||
protected UnicodeReader(ScannerFactory sf, char[] input, int inputLength) {
|
||||
log = sf.log;
|
||||
names = sf.names;
|
||||
realLength = inputLength;
|
||||
if (inputLength == input.length) {
|
||||
if (input.length > 0 && Character.isWhitespace(input[input.length - 1])) {
|
||||
inputLength--;
|
||||
|
@ -3,6 +3,6 @@ T8012003b.java:31:16: compiler.err.prob.found.req: (compiler.misc.stat.expr.expe
|
||||
T8012003b.java:32:22: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.conditional.target.cant.be.void))
|
||||
T8012003b.java:33:12: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.String)))
|
||||
T8012003b.java:34:12: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.mref: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer))
|
||||
T8012003b.java:35:12: compiler.err.invalid.mref: kindname.method, (compiler.misc.cant.resolve.location.args: kindname.method, k, , , (compiler.misc.location: kindname.class, T8012003b, null))
|
||||
T8012003b.java:35:12: compiler.err.invalid.mref: kindname.method, (compiler.misc.cant.resolve.location.args: kindname.method, k, , java.lang.String, (compiler.misc.location: kindname.class, T8012003b, null))
|
||||
- compiler.note.compressed.diags
|
||||
6 errors
|
||||
|
155
test/langtools/tools/javac/api/TestGetScopeResult.java
Normal file
155
test/langtools/tools/javac/api/TestGetScopeResult.java
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 8205418
|
||||
* @summary Test the outcomes from Trees.getScope
|
||||
* @modules jdk.compiler
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.source.tree.Scope;
|
||||
import com.sun.source.util.JavacTask;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.TreePathScanner;
|
||||
import com.sun.source.util.Trees;
|
||||
|
||||
import static javax.tools.JavaFileObject.Kind.SOURCE;
|
||||
|
||||
public class TestGetScopeResult {
|
||||
public static void main(String... args) throws IOException {
|
||||
new TestGetScopeResult().run();
|
||||
}
|
||||
|
||||
public void run() throws IOException {
|
||||
String[] simpleLambda = {
|
||||
"s:java.lang.String",
|
||||
"i:Test.I",
|
||||
"super:java.lang.Object",
|
||||
"this:Test"
|
||||
};
|
||||
doTest("class Test { void test() { I i = s -> { }; } interface I { public void test(String s); } }",
|
||||
simpleLambda);
|
||||
doTest("class Test { void test() { I i = s -> { }; } interface I { public int test(String s); } }",
|
||||
simpleLambda);
|
||||
doTest("class Test { void test() { I i = s -> { }; } interface I { public String test(String s); } }",
|
||||
simpleLambda);
|
||||
doTest("class Test { void test() { I i; inv(s -> { }); } void inv(I i) { } interface I { public void test(String s); } }",
|
||||
simpleLambda);
|
||||
doTest("class Test { void test() { I i; inv(s -> { }); } void inv(I i) { } interface I { public int test(String s); } }",
|
||||
simpleLambda);
|
||||
doTest("class Test { void test() { I i; inv(s -> { }); } void inv(I i) { } interface I { public String test(String s); } }",
|
||||
simpleLambda);
|
||||
String[] dualLambda = {
|
||||
"s:java.lang.String",
|
||||
"i:Test.I1",
|
||||
"super:java.lang.Object",
|
||||
"this:Test",
|
||||
"s:java.lang.CharSequence",
|
||||
"i:Test.I1",
|
||||
"super:java.lang.Object",
|
||||
"this:Test"
|
||||
};
|
||||
doTest("class Test { void test() { I1 i; inv(s -> { }, s -> { }); } void inv(I1 i, I2 i) { } interface I1 { public String test(String s); } interface I2 { public void test(CharSequence s); } }",
|
||||
dualLambda);
|
||||
doTest("class Test { void test() { I1 i; inv(s -> { }, s -> { }); } void inv(I1 i, I2 i) { } interface I1 { public String test(String s); } interface I2 { public int test(CharSequence s); } }",
|
||||
dualLambda);
|
||||
String[] brokenType = {
|
||||
"s:<any>",
|
||||
"u:Undefined",
|
||||
"super:java.lang.Object",
|
||||
"this:Test"
|
||||
};
|
||||
doTest("class Test { void test() { Undefined u = s -> { }; } }",
|
||||
brokenType);
|
||||
String[] multipleCandidates1 = {
|
||||
"s:<any>",
|
||||
"super:java.lang.Object",
|
||||
"this:Test"
|
||||
};
|
||||
doTest("class Test { void test() { cand1(s -> { }); } void cand1(I1 i) { } void cand1(I2 i) { } interface I1 { public String test(String s); } interface I2 { public int test(CharSequence s); } }",
|
||||
multipleCandidates1);
|
||||
String[] multipleCandidates2 = {
|
||||
"s:java.lang.String",
|
||||
"super:java.lang.Object",
|
||||
"this:Test"
|
||||
};
|
||||
doTest("class Test { void test() { cand1(s -> { }); } void cand1(I1 i) { } void cand1(I2 i, int i) { } interface I1 { public String test(String s); } interface I2 { public int test(CharSequence s); } }",
|
||||
multipleCandidates2);
|
||||
}
|
||||
|
||||
public void doTest(String code, String... expected) throws IOException {
|
||||
JavaCompiler c = ToolProvider.getSystemJavaCompiler();
|
||||
try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) {
|
||||
class MyFileObject extends SimpleJavaFileObject {
|
||||
MyFileObject() {
|
||||
super(URI.create("myfo:///Test.java"), SOURCE);
|
||||
}
|
||||
@Override
|
||||
public String getCharContent(boolean ignoreEncodingErrors) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, List.of(new MyFileObject()));
|
||||
CompilationUnitTree cut = t.parse().iterator().next();
|
||||
t.analyze();
|
||||
|
||||
List<String> actual = new ArrayList<>();
|
||||
|
||||
new TreePathScanner<Void, Void>() {
|
||||
@Override
|
||||
public Void visitLambdaExpression(LambdaExpressionTree node, Void p) {
|
||||
Scope scope = Trees.instance(t).getScope(new TreePath(getCurrentPath(), node.getBody()));
|
||||
while (scope.getEnclosingClass() != null) {
|
||||
for (Element el : scope.getLocalElements()) {
|
||||
actual.add(el.getSimpleName() + ":" +el.asType().toString());
|
||||
}
|
||||
scope = scope.getEnclosingScope();
|
||||
}
|
||||
return super.visitLambdaExpression(node, p);
|
||||
}
|
||||
}.scan(cut, null);
|
||||
|
||||
List<String> expectedList = List.of(expected);
|
||||
|
||||
if (!expectedList.equals(actual)) {
|
||||
throw new IllegalStateException("Unexpected scope content: " + actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
BadRecovery.java:17:9: compiler.err.cant.apply.symbol: kindname.method, m, BadRecovery.SAM1, @11, kindname.class, BadRecovery, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda))
|
||||
BadRecovery.java:17:38: compiler.err.cant.resolve.location.args: kindname.method, someMemberOfReceiver, , @60, (compiler.misc.location.1: kindname.variable, receiver, java.lang.Object)
|
||||
BadRecovery.java:17:77: compiler.err.cant.resolve.location: kindname.variable, f, , , (compiler.misc.location: kindname.class, BadRecovery, null)
|
||||
2 errors
|
||||
3 errors
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7073631 7159445 7156633 8028235 8065753 8205913
|
||||
* @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913
|
||||
* @summary tests error and diagnostics positions
|
||||
* @author Jan Lahoda
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
@ -51,6 +51,7 @@ import com.sun.source.tree.VariableTree;
|
||||
import com.sun.source.tree.WhileLoopTree;
|
||||
import com.sun.source.util.JavacTask;
|
||||
import com.sun.source.util.SourcePositions;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.TreePathScanner;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import com.sun.source.util.Trees;
|
||||
@ -1037,6 +1038,105 @@ public class JavacParserTest extends TestCase {
|
||||
assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTypeParamsWithoutMethod() throws IOException {
|
||||
assert tool != null;
|
||||
|
||||
String code = "package test; class Test { /**javadoc*/ |public <T> |}";
|
||||
String[] parts = code.split("\\|");
|
||||
|
||||
code = parts[0] + parts[1] + parts[2];
|
||||
|
||||
JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
|
||||
null, Arrays.asList(new MyFileObject(code)));
|
||||
Trees trees = Trees.instance(ct);
|
||||
SourcePositions pos = trees.getSourcePositions();
|
||||
CompilationUnitTree cut = ct.parse().iterator().next();
|
||||
ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
|
||||
ErroneousTree err = (ErroneousTree) clazz.getMembers().get(0);
|
||||
MethodTree method = (MethodTree) err.getErrorTrees().get(0);
|
||||
|
||||
final int methodStart = parts[0].length();
|
||||
final int methodEnd = parts[0].length() + parts[1].length();
|
||||
assertEquals("testTypeParamsWithoutMethod",
|
||||
methodStart, pos.getStartPosition(cut, method));
|
||||
assertEquals("testTypeParamsWithoutMethod",
|
||||
methodEnd, pos.getEndPosition(cut, method));
|
||||
|
||||
TreePath path2Method = new TreePath(new TreePath(new TreePath(cut), clazz), method);
|
||||
String javadoc = trees.getDocComment(path2Method);
|
||||
|
||||
if (!"javadoc".equals(javadoc)) {
|
||||
throw new AssertionError("Expected javadoc not found, actual javadoc: " + javadoc);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAnalyzeParensWithComma1() throws IOException {
|
||||
assert tool != null;
|
||||
|
||||
String code = "package test; class Test { FI fi = |(s, |";
|
||||
String[] parts = code.split("\\|", 3);
|
||||
|
||||
code = parts[0] + parts[1] + parts[2];
|
||||
|
||||
JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
|
||||
null, Arrays.asList(new MyFileObject(code)));
|
||||
Trees trees = Trees.instance(ct);
|
||||
SourcePositions pos = trees.getSourcePositions();
|
||||
CompilationUnitTree cut = ct.parse().iterator().next();
|
||||
boolean[] found = new boolean[1];
|
||||
|
||||
new TreeScanner<Void, Void>() {
|
||||
@Override
|
||||
public Void visitLambdaExpression(LambdaExpressionTree tree, Void v) {
|
||||
found[0] = true;
|
||||
int lambdaStart = parts[0].length();
|
||||
int lambdaEnd = parts[0].length() + parts[1].length();
|
||||
assertEquals("testAnalyzeParensWithComma1",
|
||||
lambdaStart, pos.getStartPosition(cut, tree));
|
||||
assertEquals("testAnalyzeParensWithComma1",
|
||||
lambdaEnd, pos.getEndPosition(cut, tree));
|
||||
return null;
|
||||
}
|
||||
}.scan(cut, null);
|
||||
|
||||
assertTrue("testAnalyzeParensWithComma1", found[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAnalyzeParensWithComma2() throws IOException {
|
||||
assert tool != null;
|
||||
|
||||
String code = "package test; class Test { FI fi = |(s, o)|";
|
||||
String[] parts = code.split("\\|", 3);
|
||||
|
||||
code = parts[0] + parts[1] + parts[2];
|
||||
|
||||
JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null,
|
||||
null, Arrays.asList(new MyFileObject(code)));
|
||||
Trees trees = Trees.instance(ct);
|
||||
SourcePositions pos = trees.getSourcePositions();
|
||||
CompilationUnitTree cut = ct.parse().iterator().next();
|
||||
boolean[] found = new boolean[1];
|
||||
|
||||
new TreeScanner<Void, Void>() {
|
||||
@Override
|
||||
public Void visitLambdaExpression(LambdaExpressionTree tree, Void v) {
|
||||
found[0] = true;
|
||||
int lambdaStart = parts[0].length();
|
||||
int lambdaEnd = parts[0].length() + parts[1].length();
|
||||
assertEquals("testAnalyzeParensWithComma2",
|
||||
lambdaStart, pos.getStartPosition(cut, tree));
|
||||
assertEquals("testAnalyzeParensWithComma2",
|
||||
lambdaEnd, pos.getEndPosition(cut, tree));
|
||||
return null;
|
||||
}
|
||||
}.scan(cut, null);
|
||||
|
||||
assertTrue("testAnalyzeParensWithComma2", found[0]);
|
||||
}
|
||||
|
||||
void run(String[] args) throws Exception {
|
||||
int passed = 0, failed = 0;
|
||||
final Pattern p = (args != null && args.length > 0)
|
||||
@ -1082,6 +1182,12 @@ abstract class TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
void assertTrue(String message, boolean bvalue) {
|
||||
if (bvalue == false) {
|
||||
fail(message);
|
||||
}
|
||||
}
|
||||
|
||||
void assertEquals(String message, int i, long l) {
|
||||
if (i != l) {
|
||||
fail(message + ":" + i + ":" + l);
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8017216 8019422 8019421 8054956
|
||||
* @bug 8017216 8019422 8019421 8054956 8205418
|
||||
* @summary verify start and end positions
|
||||
* @modules java.compiler
|
||||
* jdk.compiler
|
||||
@ -44,6 +44,13 @@ import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import javax.tools.ToolProvider;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import com.sun.source.util.JavacTask;
|
||||
import com.sun.source.util.SourcePositions;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import com.sun.source.util.Trees;
|
||||
|
||||
public class TreeEndPosTest {
|
||||
private static JavaFileManager getJavaFileManager(JavaCompiler compiler,
|
||||
@ -99,6 +106,15 @@ public class TreeEndPosTest {
|
||||
js.endPos = end;
|
||||
return js;
|
||||
}
|
||||
|
||||
static JavaSource createFullJavaSource(String code) {
|
||||
final String name = "Bug";
|
||||
String[] parts = code.split("\\|", 3);
|
||||
JavaSource js = new JavaSource(name + ".java", parts[0] + parts[1] + parts[2]);
|
||||
js.startPos = parts[0].length();
|
||||
js.endPos = parts[0].length() + parts[1].length();
|
||||
return js;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String... args) throws IOException {
|
||||
@ -107,6 +123,7 @@ public class TreeEndPosTest {
|
||||
testUnresolvableAnnotationAttribute();
|
||||
testFinalVariableWithDefaultConstructor();
|
||||
testFinalVariableWithConstructor();
|
||||
testWholeTextSpan();
|
||||
}
|
||||
|
||||
static void testUninitializedVariable() throws IOException {
|
||||
@ -133,6 +150,10 @@ public class TreeEndPosTest {
|
||||
"{}"));
|
||||
}
|
||||
|
||||
static void testWholeTextSpan() throws IOException {
|
||||
treeSpan(JavaSource.createFullJavaSource("|class X |"));
|
||||
}
|
||||
|
||||
static void compile(JavaSource src) throws IOException {
|
||||
ByteArrayOutputStream ba = new ByteArrayOutputStream();
|
||||
PrintWriter writer = new PrintWriter(ba);
|
||||
@ -169,4 +190,46 @@ public class TreeEndPosTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void treeSpan(JavaSource src) throws IOException {
|
||||
ByteArrayOutputStream ba = new ByteArrayOutputStream();
|
||||
PrintWriter writer = new PrintWriter(ba);
|
||||
File tempDir = new File(".");
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
DiagnosticCollector dc = new DiagnosticCollector();
|
||||
try (JavaFileManager javaFileManager = getJavaFileManager(compiler, dc)) {
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add("-cp");
|
||||
options.add(tempDir.getPath());
|
||||
options.add("-d");
|
||||
options.add(tempDir.getPath());
|
||||
options.add("--should-stop=at=GENERATE");
|
||||
|
||||
List<JavaFileObject> sources = new ArrayList<>();
|
||||
sources.add(src);
|
||||
JavacTask task = (JavacTask) compiler.getTask(writer, javaFileManager,
|
||||
dc, options, null,
|
||||
sources);
|
||||
SourcePositions sp = Trees.instance(task).getSourcePositions();
|
||||
boolean[] found = new boolean[1];
|
||||
new TreeScanner<Void, Void>() {
|
||||
CompilationUnitTree cut;
|
||||
@Override
|
||||
public Void scan(Tree tree, Void p) {
|
||||
if (tree == null)
|
||||
return null;
|
||||
if (tree.getKind() == Kind.COMPILATION_UNIT) {
|
||||
cut = (CompilationUnitTree) tree;
|
||||
}
|
||||
found[0] |= (sp.getStartPosition(cut, tree) == src.startPos) &&
|
||||
(sp.getEndPosition(cut, tree) == src.endPos);
|
||||
return super.scan(tree, p);
|
||||
}
|
||||
}.scan(task.parse(), null);
|
||||
|
||||
if (!found[0]) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user