8205418: Assorted improvements to source code model
Summary: Improving tree positions, better error recovery, fixing Trees.getScope for possibly erroneous lambdas.
Reviewed-by: jjg, mcimadamore, vromero
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Thu Jun 28 17:49:13 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Fri Jun 29 10:41:10 2018 +0200
@@ -1659,7 +1659,7 @@
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()) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Thu Jun 28 17:49:13 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Fri Jun 29 10:41:10 2018 +0200
@@ -586,8 +586,11 @@
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,7 +601,9 @@
}
@Override
public void report(DiagnosticPosition pos, JCDiagnostic details) {
- chk.basicHandler.report(pos, details);
+ if (pt == Type.recoveryType) {
+ chk.basicHandler.report(pos, details);
+ }
}
});
}
@@ -656,7 +661,7 @@
}
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 @@
}
}
+ 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 @@
//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 @@
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 @@
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);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Thu Jun 28 17:49:13 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Fri Jun 29 10:41:10 2018 +0200
@@ -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 @@
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.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 @@
* 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 @@
}
@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 @@
* 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 @@
* 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 @@
});
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;
+ }
}
/**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Thu Jun 28 17:49:13 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Fri Jun 29 10:41:10 2018 +0200
@@ -602,7 +602,7 @@
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);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java Thu Jun 28 17:49:13 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java Fri Jun 29 10:41:10 2018 +0200
@@ -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 @@
* 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]) :
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Thu Jun 28 17:49:13 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Jun 29 10:41:10 2018 +0200
@@ -2560,8 +2560,8 @@
}
@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 @@
@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 @@
//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;
+ }
}
/**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java Thu Jun 28 17:49:13 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java Fri Jun 29 10:41:10 2018 +0200
@@ -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 @@
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;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Jun 28 17:49:13 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Jun 29 10:41:10 2018 +0200
@@ -1516,6 +1516,7 @@
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 @@
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 @@
} 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 @@
break;
default:
//this includes EOF
- return ParensResult.PARENS;
+ return defaultResult;
}
}
}
@@ -3753,10 +3756,16 @@
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)));
}
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java Thu Jun 28 17:49:13 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java Fri Jun 29 10:41:10 2018 +0200
@@ -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 @@
/** A character buffer for saved chars.
*/
protected char[] sbuf = new char[128];
+ protected int realLength;
protected int sp;
/**
@@ -89,6 +90,7 @@
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--;
--- a/test/langtools/tools/javac/Diagnostics/compressed/T8012003b.out Thu Jun 28 17:49:13 2018 -0700
+++ b/test/langtools/tools/javac/Diagnostics/compressed/T8012003b.out Fri Jun 29 10:41:10 2018 +0200
@@ -3,6 +3,6 @@
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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/api/TestGetScopeResult.java Fri Jun 29 10:41:10 2018 +0200
@@ -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);
+ }
+ }
+ }
+
+}
+
--- a/test/langtools/tools/javac/lambda/BadRecovery.out Thu Jun 28 17:49:13 2018 -0700
+++ b/test/langtools/tools/javac/lambda/BadRecovery.out Fri Jun 29 10:41:10 2018 +0200
@@ -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
--- a/test/langtools/tools/javac/parser/JavacParserTest.java Thu Jun 28 17:49:13 2018 -0700
+++ b/test/langtools/tools/javac/parser/JavacParserTest.java Fri Jun 29 10:41:10 2018 +0200
@@ -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.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 @@
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 @@
}
}
+ 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);
--- a/test/langtools/tools/javac/positions/TreeEndPosTest.java Thu Jun 28 17:49:13 2018 -0700
+++ b/test/langtools/tools/javac/positions/TreeEndPosTest.java Fri Jun 29 10:41:10 2018 +0200
@@ -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.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 @@
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 @@
testUnresolvableAnnotationAttribute();
testFinalVariableWithDefaultConstructor();
testFinalVariableWithConstructor();
+ testWholeTextSpan();
}
static void testUninitializedVariable() throws IOException {
@@ -133,6 +150,10 @@
"{}"));
}
+ 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 @@
}
}
}
+
+ 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();
+ }
+ }
+ }
}