8205418: Assorted improvements to source code model
authorjlahoda
Fri, 29 Jun 2018 10:41:10 +0200
changeset 50898 12133a6e2613
parent 50897 a4d7eaf58623
child 50899 4fa199e67e41
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
src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java
src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java
test/langtools/tools/javac/Diagnostics/compressed/T8012003b.out
test/langtools/tools/javac/api/TestGetScopeResult.java
test/langtools/tools/javac/lambda/BadRecovery.out
test/langtools/tools/javac/parser/JavacParserTest.java
test/langtools/tools/javac/positions/TreeEndPosTest.java
--- 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();
+            }
+        }
+    }
 }