changeset 60794:8695e28d8a77

8247456: JShell: Handling of top-level final, abstract, and static modifiers Reviewed-by: jlahoda
author rfield
date Wed, 02 Sep 2020 09:37:25 -0700
parents e6d88e187940
children 6ab9279c0e99
files src/jdk.jshell/share/classes/jdk/jshell/Corraller.java src/jdk.jshell/share/classes/jdk/jshell/Eval.java src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java src/jdk.jshell/share/classes/jdk/jshell/MethodSnippet.java src/jdk.jshell/share/classes/jdk/jshell/Unit.java src/jdk.jshell/share/classes/jdk/jshell/resources/l10n.properties test/langtools/jdk/jshell/ClassesTest.java test/langtools/jdk/jshell/ErrorTranslationTest.java test/langtools/jdk/jshell/IgnoreTest.java test/langtools/jdk/jshell/MethodsTest.java test/langtools/jdk/jshell/ModifiersTest.java test/langtools/jdk/jshell/ToolBasicTest.java test/langtools/jdk/jshell/ToolSimpleTest.java
diffstat 13 files changed, 149 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java	Wed Sep 02 09:37:25 2020 -0700
@@ -50,6 +50,8 @@
 import jdk.jshell.Wrap.Range;
 import jdk.jshell.Wrap.RangeWrap;
 
+import java.util.Set;
+
 /**
  * Produce a corralled version of the Wrap for a snippet.
  */
@@ -227,17 +229,21 @@
                 bodyBegin = -1;
             }
         }
-        if (bodyBegin > 0) {
-            //debugWrap("-visitMethodDef BEGIN: %d = '%s'\n", bodyBegin,
-            //        source.substring(methodBegin, bodyBegin));
-            Range noBodyRange = new Range(methodBegin, bodyBegin);
-            result = new CompoundWrap(
-                    new RangeWrap(source, noBodyRange),
-                    resolutionExceptionBlock);
+        String adjustedSource;
+        if (bodyBegin < 0) {
+            adjustedSource = new MaskCommentsAndModifiers(source, Set.of("abstract")).cleared();
+            bodyBegin = adjustedSource.charAt(methodEnd - 1) == ';'
+                ? methodEnd - 1
+                : methodEnd;
         } else {
-            Range range = new Range(methodBegin, methodEnd);
-            result = new RangeWrap(source, range);
+            adjustedSource = source;
         }
+        debugWrap("-visitMethodDef BEGIN: %d = '%s'\n", bodyBegin,
+                adjustedSource.substring(methodBegin, bodyBegin));
+        Range noBodyRange = new Range(methodBegin, bodyBegin);
+        result = new CompoundWrap(
+                new RangeWrap(adjustedSource, noBodyRange),
+                resolutionExceptionBlock);
     }
 
     // Remove initializer, if present
--- a/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Wed Sep 02 09:37:25 2020 -0700
@@ -76,6 +76,9 @@
 import static java.util.Collections.singletonList;
 import com.sun.tools.javac.code.Symbol.TypeSymbol;
 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
+import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED;
+import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED;
+import static jdk.jshell.Snippet.Status.VALID;
 import static jdk.jshell.Util.DOIT_METHOD_NAME;
 import static jdk.jshell.Util.PREFIX_PATTERN;
 import static jdk.jshell.Util.expunge;
@@ -777,21 +780,40 @@
                 .map(param -> dis.treeToRange(param.getType()).part(compileSource))
                 .collect(Collectors.joining(","));
         Tree returnType = mt.getReturnType();
-        DiagList modDiag = modifierDiagnostics(mt.getModifiers(), dis, true);
-        MethodKey key = state.keyMap.keyForMethod(name, parameterTypes);
-        // Corralling
-        Wrap corralled = new Corraller(dis, key.index(), compileSource).corralMethod(mt);
-
+        DiagList modDiag = modifierDiagnostics(mt.getModifiers(), dis, false);
         if (modDiag.hasErrors()) {
             return compileFailResult(modDiag, userSource, Kind.METHOD);
         }
-        Wrap guts = Wrap.classMemberWrap(compileSource);
+        MethodKey key = state.keyMap.keyForMethod(name, parameterTypes);
+
+        Wrap corralled;
+        Wrap guts;
+        String unresolvedSelf;
+        if (mt.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
+            if (mt.getBody() == null) {
+                // abstract method -- pre-corral
+                corralled = null; // no fall-back
+                guts = new Corraller(dis, key.index(), compileSource).corralMethod(mt);
+                unresolvedSelf = "method " + name + "(" + parameterTypes + ")";
+            } else {
+                // abstract with body, don't pollute the error message
+                corralled = null;
+                guts = Wrap.simpleWrap(compileSource);
+                unresolvedSelf = null;
+            }
+        } else {
+            // normal method
+            corralled = new Corraller(dis, key.index(), compileSource).corralMethod(mt);
+            guts = Wrap.classMemberWrap(compileSource);
+            unresolvedSelf = null;
+        }
         Range typeRange = dis.treeToRange(returnType);
         String signature = "(" + parameterTypes + ")" + typeRange.part(compileSource);
 
         Snippet snip = new MethodSnippet(key, userSource, guts,
                 name, signature,
-                corralled, tds.declareReferences(), tds.bodyReferences(), modDiag);
+                corralled, tds.declareReferences(), tds.bodyReferences(),
+                unresolvedSelf, modDiag);
         return singletonList(snip);
     }
 
@@ -891,6 +913,18 @@
         ins.add(c);
         Set<Unit> outs = compileAndLoad(ins);
 
+        if (si.status().isActive() && si instanceof MethodSnippet) {
+            // special processing for abstract methods
+            MethodSnippet msi = (MethodSnippet) si;
+            String unresolvedSelf = msi.unresolvedSelf;
+            if (unresolvedSelf != null) {
+                List<String> unresolved = new ArrayList<>(si.unresolved());
+                unresolved.add(unresolvedSelf);
+                si.setCompilationStatus(si.status() == VALID ? RECOVERABLE_DEFINED : si.status(),
+                        unresolved, si.diagnostics());
+            }
+        }
+
         if (!si.status().isDefined()
                 && si.diagnostics().isEmpty()
                 && si.unresolved().isEmpty()) {
@@ -1251,6 +1285,9 @@
                     fatal = true;
                     break;
                 case ABSTRACT:
+                    // for classes, abstract is valid
+                    // for variables, generate an error message
+                    // for methods, we generate a placeholder method
                     if (isAbstractProhibited) {
                         list.add(mod);
                         fatal = true;
@@ -1266,7 +1303,7 @@
                     //final classes needed for sealed classes
                     break;
                 case STATIC:
-                    list.add(mod);
+                    // everything is static -- warning just adds noise when pasting
                     break;
             }
         }
--- a/src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java	Wed Sep 02 09:37:25 2020 -0700
@@ -40,8 +40,11 @@
             Stream.of( "public", "protected", "private", "static" )
                     .collect( Collectors.toSet() );
 
-    private final static Set<String> OTHER_MODIFIERS =
-            Stream.of( "abstract", "strictfp", "transient", "volatile", "synchronized", "native", "default", "final" )
+    private final static Set<String> ALL_MODIFIERS =
+            Stream.of(
+                    "public", "protected", "private",
+                    "static", "abstract", "final",
+                    "strictfp", "transient", "volatile", "synchronized", "native", "default" )
                     .collect( Collectors.toSet() );
 
     // Builder to accumulate non-masked characters
@@ -56,6 +59,9 @@
     // Entire input string length
     private final int length;
 
+    // Which modifiers to mask-out
+    private final Set<String> ignoredModifiers;
+
     // The next character position
     private int next = 0;
 
@@ -70,9 +76,18 @@
     private boolean openToken = false;
 
     MaskCommentsAndModifiers(String s, boolean maskModifiers) {
+        this(s, maskModifiers, IGNORED_MODIFIERS);
+    }
+
+    MaskCommentsAndModifiers(String s, Set<String> ignoredModifiers) {
+        this(s, true, ignoredModifiers);
+    }
+
+    MaskCommentsAndModifiers(String s, boolean maskModifiers, Set<String> ignoredModifiers) {
         this.str = s;
         this.length = s.length();
         this.maskModifiers = maskModifiers;
+        this.ignoredModifiers = ignoredModifiers;
         read();
         while (c >= 0) {
             next();
@@ -250,11 +265,11 @@
                     } while (Character.isJavaIdentifierPart(c));
                     unread();
                     String id = sb.toString();
-                    if (maskModifiers && IGNORED_MODIFIERS.contains(id)) {
+                    if (maskModifiers && ignoredModifiers.contains(id)) {
                         writeMask(sb);
                     } else {
                         write(sb);
-                        if (maskModifiers && !OTHER_MODIFIERS.contains(id)) {
+                        if (maskModifiers && !ALL_MODIFIERS.contains(id)) {
                             maskModifiers = false;
                         }
                     }
--- a/src/jdk.jshell/share/classes/jdk/jshell/MethodSnippet.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/MethodSnippet.java	Wed Sep 02 09:37:25 2020 -0700
@@ -42,15 +42,18 @@
 public class MethodSnippet extends DeclarationSnippet {
 
     final String signature;
+    final String unresolvedSelf;
     private String qualifiedParameterTypes;
 
     MethodSnippet(MethodKey key, String userSource, Wrap guts,
             String name, String signature, Wrap corralled,
             Collection<String> declareReferences, Collection<String> bodyReferences,
+            String unresolvedSelf,
             DiagList syntheticDiags) {
         super(key, userSource, guts, name, SubKind.METHOD_SUBKIND, corralled,
                 declareReferences, bodyReferences, syntheticDiags);
         this.signature = signature;
+        this.unresolvedSelf = unresolvedSelf;
     }
 
     /**
--- a/src/jdk.jshell/share/classes/jdk/jshell/Unit.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Unit.java	Wed Sep 02 09:37:25 2020 -0700
@@ -237,7 +237,6 @@
             if (dl.hasErrors()) {
                 setDiagnostics(dl);
                 status = RECOVERABLE_NOT_DEFINED;
-                // overwrite orginal bytes
                 state.debug(DBG_GEN, "++smashingErrorDiagnostics %s\n%s\n-- diags: %s\n",
                         si, si.outerWrap().wrapped(), dl);
                 return true;
--- a/src/jdk.jshell/share/classes/jdk/jshell/resources/l10n.properties	Wed Sep 02 09:29:31 2020 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/resources/l10n.properties	Wed Sep 02 09:37:25 2020 -0700
@@ -23,10 +23,10 @@
 # questions.
 #
 
-jshell.diag.modifier.plural.fatal = Modifiers {0} not permitted in top-level declarations
-jshell.diag.modifier.plural.ignore = Modifiers {0} not permitted in top-level declarations, ignored
-jshell.diag.modifier.single.fatal = Modifier {0} not permitted in top-level declarations
-jshell.diag.modifier.single.ignore = Modifier {0} not permitted in top-level declarations, ignored
+jshell.diag.modifier.plural.fatal = Modifiers {0} not permitted
+jshell.diag.modifier.plural.ignore = Modifiers {0} not permitted, ignored
+jshell.diag.modifier.single.fatal = Modifier {0} not permitted
+jshell.diag.modifier.single.ignore = Modifier {0} not permitted, ignored
 jshell.diag.object.method.fatal = JShell method names must not match Object methods: {0}
 
 jshell.exc.null = Snippet must not be null
--- a/test/langtools/jdk/jshell/ClassesTest.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/test/langtools/jdk/jshell/ClassesTest.java	Wed Sep 02 09:37:25 2020 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020, 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
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8145239 8129559 8080354 8189248 8010319 8246353
+ * @bug 8145239 8129559 8080354 8189248 8010319 8246353 8247456
  * @summary Tests for EvaluationState.classes
  * @build KullaTesting TestingInputStream ExpectedDiagnostic
  * @run testng ClassesTest
@@ -249,29 +249,23 @@
 
     public void classesIgnoredModifiers() {
         assertEval("public interface A { }");
-        assertDeclareWarn1("static class B implements A { }",
-                new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.WARNING));
-        assertDeclareWarn1("static interface C extends A { }",
-                new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.WARNING));
+        assertEval("static class B implements A { }");
+        assertEval("static interface C extends A { }");
         assertActiveKeys();
     }
 
     public void classesIgnoredModifiersAnnotation() {
         assertEval("public @interface X { }");
         assertEval("@X public interface A { }");
-        assertDeclareWarn1("@X static class B implements A { }",
-                new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 9, 0, -1, -1, Diagnostic.Kind.WARNING));
-        assertDeclareWarn1("@X static interface C extends A { }",
-                new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 9, 0, -1, -1, Diagnostic.Kind.WARNING));
+        assertEval("@X static class B implements A { }");
+        assertEval("@X static interface C extends A { }");
         assertActiveKeys();
     }
 
     public void classesIgnoredModifiersOtherModifiers() {
         assertEval("strictfp public interface A { }");
-        assertDeclareWarn1("strictfp static class B implements A { }",
-                new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 15, 0, -1, -1, Diagnostic.Kind.WARNING));
-        assertDeclareWarn1("strictfp static interface C extends A { }",
-                new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 15, 0, -1, -1, Diagnostic.Kind.WARNING));
+        assertEval("strictfp static class B implements A { }");
+        assertEval("strictfp static interface C extends A { }");
         assertActiveKeys();
     }
 
--- a/test/langtools/jdk/jshell/ErrorTranslationTest.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/test/langtools/jdk/jshell/ErrorTranslationTest.java	Wed Sep 02 09:37:25 2020 -0700
@@ -73,21 +73,6 @@
         );
     }
 
-    public void testWarnings() {
-        List<ReplTest> list = new ArrayList<>();
-        ExpectedDiagnostic[] diagnostics = new ExpectedDiagnostic[]{
-                newExpectedDiagnostic(0, 6, 0, -1, -1, Diagnostic.Kind.WARNING),
-                newExpectedDiagnostic(0, 5, 0, -1, -1, Diagnostic.Kind.WARNING)};
-        String[] mods = {"static"};
-        for (int i = 0; i < mods.length; ++i) {
-            for (String code : new String[] {"class A {}", "void f() {}", "int a;"}) {
-                final int finalI = i;
-                list.add(a -> assertDiagnostic(a, mods[finalI] + " " + code, diagnostics[finalI]));
-            }
-        }
-        test(list.toArray(new ReplTest[list.size()]));
-    }
-
     @Test(enabled = false) // TODO 8132147
     public void stressTest() {
         Compiler compiler = new Compiler();
--- a/test/langtools/jdk/jshell/IgnoreTest.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/test/langtools/jdk/jshell/IgnoreTest.java	Wed Sep 02 09:37:25 2020 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020, 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
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8129559 8246353
+ * @bug 8129559 8246353 8247456
  * @summary Test the ignoring of comments and certain modifiers
  * @build KullaTesting TestingInputStream
  * @run testng IgnoreTest
@@ -65,8 +65,8 @@
         assertVariableDeclSnippet(x2, "x2", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
         VarSnippet x3 = varKey(assertEval("private int x3;"));
         assertVariableDeclSnippet(x3, "x3", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
-        VarSnippet x4 = (VarSnippet) assertDeclareWarn1("static int x4;", "jdk.eval.warn.illegal.modifiers");
-        assertVariableDeclSnippet(x4, "x4", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1);
+        VarSnippet x4 = varKey(assertEval("static int x4;"));
+        assertVariableDeclSnippet(x4, "x4", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
         VarSnippet x5 = varKey(assertEval("final int x5;"));
         assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
     }
@@ -79,8 +79,8 @@
         assertVariableDeclSnippet(x2, "x2", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
         VarSnippet x3 = varKey(assertEval("@A(value=111)private int x3;"));
         assertVariableDeclSnippet(x3, "x3", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
-        VarSnippet x4 = (VarSnippet) assertDeclareWarn1("@A static int x4;", "jdk.eval.warn.illegal.modifiers");
-        assertVariableDeclSnippet(x4, "x4", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1);
+        VarSnippet x4 = varKey(assertEval("@A static int x4;"));
+        assertVariableDeclSnippet(x4, "x4", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
         VarSnippet x5 = varKey(assertEval("@A(1111) final int x5;"));
         assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
     }
@@ -92,8 +92,8 @@
         assertVariableDeclSnippet(x2, "x2", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
         VarSnippet x3 = varKey(assertEval("transient private int x3;"));
         assertVariableDeclSnippet(x3, "x3", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
-        VarSnippet x4 = (VarSnippet) assertDeclareWarn1("volatile static int x4;", "jdk.eval.warn.illegal.modifiers");
-        assertVariableDeclSnippet(x4, "x4", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1);
+        VarSnippet x4 = varKey(assertEval("volatile static int x4;"));
+        assertVariableDeclSnippet(x4, "x4", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
         VarSnippet x5 = varKey(assertEval("transient final int x5;"));
         assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0);
     }
@@ -105,23 +105,23 @@
     }
 
     public void testMethodModifier() {
-        MethodSnippet m4 = (MethodSnippet) assertDeclareWarn1("static void m4() {}", "jdk.eval.warn.illegal.modifiers");
-        assertMethodDeclSnippet(m4, "m4", "()void", VALID, 0, 1);
+        MethodSnippet m4 = methodKey(assertEval("static void m4() {}"));
+        assertMethodDeclSnippet(m4, "m4", "()void", VALID, 0, 0);
         MethodSnippet m5 = methodKey(assertEval("final void m5() {}"));
         assertMethodDeclSnippet(m5, "m5", "()void", VALID, 0, 0);
     }
 
     public void testMethodModifierAnnotation() {
         assertEval("@interface A { int value() default 0; }");
-        MethodSnippet m4 = (MethodSnippet) assertDeclareWarn1("@A static void m4() {}", "jdk.eval.warn.illegal.modifiers");
-        assertMethodDeclSnippet(m4, "m4", "()void", VALID, 0, 1);
+        MethodSnippet m4 = methodKey(assertEval("@A static void m4() {}"));
+        assertMethodDeclSnippet(m4, "m4", "()void", VALID, 0, 0);
         MethodSnippet m5 = methodKey(assertEval("@A(value=66)final void m5() {}"));
         assertMethodDeclSnippet(m5, "m5", "()void", VALID, 0, 0);
     }
 
     public void testClassModifier() {
-        TypeDeclSnippet c4 = (TypeDeclSnippet) assertDeclareWarn1("static class C4 {}", "jdk.eval.warn.illegal.modifiers");
-        assertTypeDeclSnippet(c4, "C4", VALID, CLASS_SUBKIND, 0, 1);
+        TypeDeclSnippet c4 = classKey(assertEval("static class C4 {}"));
+        assertTypeDeclSnippet(c4, "C4", VALID, CLASS_SUBKIND, 0, 0);
         TypeDeclSnippet c5 = classKey(assertEval("final class C5 {}"));
         assertTypeDeclSnippet(c5, "C5", VALID, CLASS_SUBKIND, 0, 0);
     }
--- a/test/langtools/jdk/jshell/MethodsTest.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/test/langtools/jdk/jshell/MethodsTest.java	Wed Sep 02 09:37:25 2020 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020, 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
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8080357 8167643 8187359 8199762 8080353 8246353
+ * @bug 8080357 8167643 8187359 8199762 8080353 8246353 8247456
  * @summary Tests for EvaluationState.methods
  * @build KullaTesting TestingInputStream ExpectedDiagnostic
  * @run testng MethodsTest
@@ -36,7 +36,11 @@
 import jdk.jshell.Snippet.Status;
 import org.testng.annotations.Test;
 
+import java.util.List;
+import java.util.stream.Collectors;
+
 import static jdk.jshell.Snippet.Status.*;
+import static org.testng.Assert.assertEquals;
 
 @Test
 public class MethodsTest extends KullaTesting {
@@ -216,17 +220,28 @@
         assertActiveKeys();
     }
 
+    public void methodsAbstract() {
+        MethodSnippet m1 = methodKey(assertEval("abstract String f();",
+                ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_DEFINED, true, null)));
+        assertEquals(getState().unresolvedDependencies(m1).collect(Collectors.toList()),
+                List.of("method f()"));
+        MethodSnippet m2 = methodKey(assertEval("abstract int mm(Blah b);",
+                ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_NOT_DEFINED, false, null)));
+        List<String> unr = getState().unresolvedDependencies(m2).collect(Collectors.toList());
+        assertEquals(unr.size(), 2);
+        unr.remove("class Blah");
+        unr.remove("method mm(Blah)");
+        assertEquals(unr.size(), 0, "unexpected entry: " + unr);
+        assertNumberOfActiveMethods(2);
+        assertActiveKeys();
+    }
+
     public void methodsErrors() {
         assertDeclareFail("String f();",
                 new ExpectedDiagnostic("compiler.err.missing.meth.body.or.decl.abstract", 0, 11, 7, -1, -1, Diagnostic.Kind.ERROR));
         assertNumberOfActiveMethods(0);
         assertActiveKeys();
 
-        assertDeclareFail("abstract String f();",
-                new ExpectedDiagnostic("jdk.eval.error.illegal.modifiers", 0, 8, 0, -1, -1, Diagnostic.Kind.ERROR));
-        assertNumberOfActiveMethods(0);
-        assertActiveKeys();
-
         assertDeclareFail("native String f();",
                 new ExpectedDiagnostic("jdk.eval.error.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.ERROR));
         assertNumberOfActiveMethods(0);
@@ -290,10 +305,8 @@
         assertActiveKeys();
     }
 
-    public void methodsWarn() {
-        Snippet f = assertDeclareWarn1("static String f() {return null;}",
-                new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.WARNING),
-                added(VALID));
+    public void methodsIgnoredModifiers() {
+        Snippet f = methodKey(assertEval("static String f() {return null;}"));
         assertNumberOfActiveMethods(1);
         assertActiveKeys();
 
--- a/test/langtools/jdk/jshell/ModifiersTest.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/test/langtools/jdk/jshell/ModifiersTest.java	Wed Sep 02 09:37:25 2020 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020, 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
@@ -22,7 +22,7 @@
  */
 
 /*
- * @test 8167643 8129559
+ * @test 8167643 8129559 8247456
  * @summary Tests for modifiers
  * @build KullaTesting TestingInputStream ExpectedDiagnostic
  * @run testng ModifiersTest
@@ -44,10 +44,9 @@
     public Object[][] getTestCases() {
         List<Object[]> testCases = new ArrayList<>();
         String[] ignoredModifiers = new String[] {
-            "static"
         };
         String[] silentlyIgnoredModifiers = new String[] {
-            "public", "protected", "private"
+            "public", "protected", "private", "static"
         };
         String[] before = new String[] {
             "strictfp", "abstract", "final", "@X", "@X(value=9)"
--- a/test/langtools/jdk/jshell/ToolBasicTest.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/test/langtools/jdk/jshell/ToolBasicTest.java	Wed Sep 02 09:37:25 2020 -0700
@@ -699,8 +699,7 @@
                     a -> assertCommand(a, "/set feedback " + off, ""),
                     a -> assertCommand(a, "int a", ""),
                     a -> assertCommand(a, "void f() {}", ""),
-                    a -> assertCommandCheckOutput(a, "aaaa", assertStartsWith("|  Error:")),
-                    a -> assertCommandCheckOutput(a, "static void f() {}", assertStartsWith("|  Warning:"))
+                    a -> assertCommandCheckOutput(a, "aaaa", assertStartsWith("|  Error:"))
             );
         }
     }
--- a/test/langtools/jdk/jshell/ToolSimpleTest.java	Wed Sep 02 09:29:31 2020 -0700
+++ b/test/langtools/jdk/jshell/ToolSimpleTest.java	Wed Sep 02 09:37:25 2020 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103  8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466 8172154 8192979 8191842 8198573 8198801 8210596 8210959 8215099 8199623 8236715 8239536
+ * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103  8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466 8172154 8192979 8191842 8198573 8198801 8210596 8210959 8215099 8199623 8236715 8239536 8247456
  * @summary Simple jshell tool tests
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -270,6 +270,18 @@
         );
     }
 
+    @Test
+    public void testAbstractMethod() {
+        test(
+                (a) -> assertCommand(a, "abstract int f(int x);",
+                        "|  created method f(int), however, it cannot be invoked until method f(int) is declared"),
+                (a) -> assertCommand(a, "f(13)",
+                        "|  attempted to call method f(int) which cannot be invoked until method f(int) is declared"),
+                (a) -> assertCommand(a, " abstract void m(Blah b);",
+                        "|  created method m(Blah), however, it cannot be referenced until class Blah, and method m(Blah) are declared")
+        );
+    }
+
     // 8199623
     @Test
     public void testTwoForkedDrop() {