1 /*
   2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 8145239 8129559 8080354 8189248 8010319
  27  * @summary Tests for EvaluationState.classes
  28  * @build KullaTesting TestingInputStream ExpectedDiagnostic
  29  * @run testng ClassesTest
  30  */
  31 
  32 import java.util.ArrayList;
  33 import java.util.List;
  34 
  35 import javax.tools.Diagnostic;
  36 
  37 import jdk.jshell.Snippet;
  38 import jdk.jshell.TypeDeclSnippet;
  39 import jdk.jshell.VarSnippet;
  40 import org.testng.annotations.DataProvider;
  41 import org.testng.annotations.Test;
  42 
  43 import jdk.jshell.Diag;
  44 import jdk.jshell.Snippet.Status;
  45 import static java.util.stream.Collectors.toList;
  46 import static jdk.jshell.Snippet.Status.VALID;
  47 import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED;
  48 import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED;
  49 import static jdk.jshell.Snippet.Status.DROPPED;
  50 import static jdk.jshell.Snippet.Status.REJECTED;
  51 import static jdk.jshell.Snippet.Status.OVERWRITTEN;
  52 import static jdk.jshell.Snippet.Status.NONEXISTENT;
  53 import static jdk.jshell.Snippet.SubKind.*;
  54 import static org.testng.Assert.assertEquals;
  55 import static org.testng.Assert.assertTrue;
  56 
  57 @Test
  58 public class ClassesTest extends KullaTesting {
  59 
  60     public void noClasses() {
  61         assertNumberOfActiveClasses(0);
  62     }
  63 
  64     public void testSignature1() {
  65         TypeDeclSnippet c1 = classKey(assertEval("class A extends B {}", added(RECOVERABLE_NOT_DEFINED)));
  66         assertTypeDeclSnippet(c1, "A", RECOVERABLE_NOT_DEFINED, CLASS_SUBKIND, 1, 0);
  67         TypeDeclSnippet c2 = classKey(assertEval("@interface A { Class<B> f() default B.class; }",
  68                 ste(MAIN_SNIPPET, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, null),
  69                 ste(c1, RECOVERABLE_NOT_DEFINED, OVERWRITTEN, false, MAIN_SNIPPET)));
  70         assertTypeDeclSnippet(c2, "A", RECOVERABLE_NOT_DEFINED, ANNOTATION_TYPE_SUBKIND, 1, 0);
  71         TypeDeclSnippet c3 = classKey(assertEval("enum A {; private A(B b) {} }",
  72                 ste(MAIN_SNIPPET, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, null),
  73                 ste(c2, RECOVERABLE_NOT_DEFINED, OVERWRITTEN, false, MAIN_SNIPPET)));
  74         assertTypeDeclSnippet(c3, "A", RECOVERABLE_NOT_DEFINED, ENUM_SUBKIND, 1, 0);
  75         TypeDeclSnippet c4 = classKey(assertEval("interface A extends B {}",
  76                 ste(MAIN_SNIPPET, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, null),
  77                 ste(c3, RECOVERABLE_NOT_DEFINED, OVERWRITTEN, false, MAIN_SNIPPET)));
  78         assertTypeDeclSnippet(c4, "A", RECOVERABLE_NOT_DEFINED, INTERFACE_SUBKIND, 1, 0);
  79         TypeDeclSnippet c5 = classKey(assertEval("class A { void f(B b) {} }",
  80                 ste(MAIN_SNIPPET, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, null),
  81                 ste(c4, RECOVERABLE_NOT_DEFINED, OVERWRITTEN, false, MAIN_SNIPPET)));
  82         assertTypeDeclSnippet(c5, "A", RECOVERABLE_NOT_DEFINED, CLASS_SUBKIND, 1, 0);
  83     }
  84 
  85     public void testSignature2() {
  86         TypeDeclSnippet c1 = (TypeDeclSnippet) assertDeclareFail("class A { void f() { return g(); } }", "compiler.err.prob.found.req");
  87         assertTypeDeclSnippet(c1, "A", REJECTED, CLASS_SUBKIND, 0, 2);
  88         TypeDeclSnippet c2 = classKey(assertEval("class A { int f() { return g(); } }",
  89                 ste(c1, NONEXISTENT, RECOVERABLE_DEFINED, true, null)));
  90         assertTypeDeclSnippet(c2, "A", RECOVERABLE_DEFINED, CLASS_SUBKIND, 1, 0);
  91         assertDrop(c2,
  92                 ste(c2, RECOVERABLE_DEFINED, DROPPED, true, null));
  93     }
  94 
  95     public void classDeclaration() {
  96         assertEval("class A { }");
  97         assertClasses(clazz(KullaTesting.ClassType.CLASS, "A"));
  98     }
  99 
 100 
 101     public void interfaceDeclaration() {
 102         assertEval("interface A { }");
 103         assertClasses(clazz(KullaTesting.ClassType.INTERFACE, "A"));
 104     }
 105 
 106     public void annotationDeclaration() {
 107         assertEval("@interface A { }");
 108         assertClasses(clazz(KullaTesting.ClassType.ANNOTATION, "A"));
 109     }
 110 
 111     public void enumDeclaration() {
 112         assertEval("enum A { }");
 113         assertClasses(clazz(KullaTesting.ClassType.ENUM, "A"));
 114     }
 115 
 116     public void classesDeclaration() {
 117         assertEval("interface A { }");
 118         assertEval("class B implements A { }");
 119         assertEval("interface C extends A { }");
 120         assertEval("enum D implements C { }");
 121         assertEval("@interface E { }");
 122         assertClasses(
 123                 clazz(KullaTesting.ClassType.INTERFACE, "A"),
 124                 clazz(KullaTesting.ClassType.CLASS, "B"),
 125                 clazz(KullaTesting.ClassType.INTERFACE, "C"),
 126                 clazz(KullaTesting.ClassType.ENUM, "D"),
 127                 clazz(KullaTesting.ClassType.ANNOTATION, "E"));
 128         assertActiveKeys();
 129     }
 130 
 131     public void classesRedeclaration1() {
 132         Snippet a = classKey(assertEval("class A { }"));
 133         Snippet b = classKey(assertEval("interface B { }"));
 134         assertClasses(clazz(KullaTesting.ClassType.CLASS, "A"), clazz(KullaTesting.ClassType.INTERFACE, "B"));
 135         assertActiveKeys();
 136 
 137         assertEval("interface A { }",
 138                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
 139                 ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
 140         assertClasses(clazz(KullaTesting.ClassType.INTERFACE, "A"),
 141                 clazz(KullaTesting.ClassType.INTERFACE, "B"));
 142         assertActiveKeys();
 143 
 144         assertEval("interface B { } //again",
 145                 ste(MAIN_SNIPPET, VALID, VALID, false, null),
 146                 ste(b, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
 147         assertClasses(clazz(KullaTesting.ClassType.INTERFACE, "A"),
 148                 clazz(KullaTesting.ClassType.INTERFACE, "B"));
 149         assertActiveKeys();
 150     }
 151 
 152     public void classesRedeclaration2() {
 153         assertEval("class A { }");
 154         assertClasses(clazz(KullaTesting.ClassType.CLASS, "A"));
 155         assertActiveKeys();
 156 
 157         Snippet b = classKey(assertEval("class B extends A { }"));
 158         assertClasses(clazz(KullaTesting.ClassType.CLASS, "A"),
 159                 clazz(KullaTesting.ClassType.CLASS, "B"));
 160         assertActiveKeys();
 161 
 162         Snippet c = classKey(assertEval("class C extends B { }"));
 163         assertClasses(clazz(KullaTesting.ClassType.CLASS, "A"),
 164                 clazz(KullaTesting.ClassType.CLASS, "B"), clazz(KullaTesting.ClassType.CLASS, "C"));
 165         assertActiveKeys();
 166 
 167         assertEval("interface B { }",
 168                 DiagCheck.DIAG_OK,
 169                 DiagCheck.DIAG_ERROR,
 170                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
 171                 ste(b, VALID, OVERWRITTEN, false, MAIN_SNIPPET),
 172                 ste(c, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET));
 173         assertClasses(clazz(KullaTesting.ClassType.CLASS, "A"),
 174                 clazz(KullaTesting.ClassType.INTERFACE, "B"), clazz(KullaTesting.ClassType.CLASS, "C"));
 175         assertEval("new C();",
 176                 DiagCheck.DIAG_ERROR,
 177                 DiagCheck.DIAG_ERROR,
 178                 added(REJECTED));
 179         assertActiveKeys();
 180     }
 181 
 182     //8154496: test3 update: sig change should false
 183     public void classesRedeclaration3() {
 184         Snippet a = classKey(assertEval("class A { }"));
 185         assertClasses(clazz(KullaTesting.ClassType.CLASS, "A"));
 186         assertActiveKeys();
 187 
 188         Snippet test1 = methodKey(assertEval("A test() { return null; }"));
 189         Snippet test2 = methodKey(assertEval("void test(A a) { }"));
 190         Snippet test3 = methodKey(assertEval("void test(int n) {A a;}"));
 191         assertActiveKeys();
 192 
 193         assertEval("interface A { }",
 194                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
 195                 ste(test1, VALID, VALID, true, MAIN_SNIPPET),
 196                 ste(test2, VALID, VALID, true, MAIN_SNIPPET),
 197                 ste(test3, VALID, VALID, true, MAIN_SNIPPET),
 198                 ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
 199         assertClasses(clazz(KullaTesting.ClassType.INTERFACE, "A"));
 200         assertMethods(method("()A", "test"), method("(A)void", "test"), method("(int)void", "test"));
 201         assertActiveKeys();
 202     }
 203 
 204     public void classesCyclic1() {
 205         Snippet b = classKey(assertEval("class B extends A { }",
 206                 added(RECOVERABLE_NOT_DEFINED)));
 207         Snippet a = classKey(assertEval("class A extends B { }", DiagCheck.DIAG_IGNORE, DiagCheck.DIAG_IGNORE,
 208                 added(REJECTED)));
 209         /***
 210         assertDeclareFail("class A extends B { }", "****",
 211                 added(REJECTED),
 212                 ste(b, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, MAIN_SNIPPET));
 213         ***/
 214         // It is random which one it shows up in, but cyclic error should be there
 215         List<Diag> diagsA = getState().diagnostics(a).collect(toList());
 216         List<Diag> diagsB = getState().diagnostics(b).collect(toList());
 217         List<Diag> diags;
 218         if (diagsA.isEmpty()) {
 219             diags = diagsB;
 220         } else {
 221             diags = diagsA;
 222             assertTrue(diagsB.isEmpty());
 223         }
 224         assertEquals(diags.size(), 1, "Expected one error");
 225         assertEquals(diags.get(0).getCode(), "compiler.err.cyclic.inheritance", "Expected cyclic inheritance error");
 226         assertActiveKeys();
 227     }
 228 
 229     public void classesCyclic2() {
 230         Snippet d = classKey(assertEval("class D extends E { }", added(RECOVERABLE_NOT_DEFINED)));
 231         assertEval("class E { D d; }",
 232                 added(VALID),
 233                 ste(d, RECOVERABLE_NOT_DEFINED, VALID, true, MAIN_SNIPPET));
 234         assertActiveKeys();
 235     }
 236 
 237     public void classesCyclic3() {
 238         Snippet outer = classKey(assertEval("class Outer { class Inner extends Foo { } }",
 239                 added(RECOVERABLE_NOT_DEFINED)));
 240         Snippet foo = classKey(assertEval("class Foo { } ",
 241                 added(VALID),
 242                 ste(outer, RECOVERABLE_NOT_DEFINED, VALID, true, MAIN_SNIPPET)));
 243         assertEval(" class Foo extends Outer { }",
 244                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
 245                 ste(foo, VALID, OVERWRITTEN, false, MAIN_SNIPPET),
 246                 ste(outer, VALID, VALID, true, MAIN_SNIPPET));
 247         assertActiveKeys();
 248     }
 249 
 250     public void classesIgnoredModifiers() {
 251         assertEval("public interface A { }");
 252         assertDeclareWarn1("static class B implements A { }",
 253                 new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.WARNING));
 254         assertDeclareWarn1("final interface C extends A { }",
 255                 new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 5, 0, -1, -1, Diagnostic.Kind.WARNING));
 256         assertActiveKeys();
 257     }
 258 
 259     public void classesIgnoredModifiersAnnotation() {
 260         assertEval("public @interface X { }");
 261         assertEval("@X public interface A { }");
 262         assertDeclareWarn1("@X static class B implements A { }",
 263                 new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 9, 0, -1, -1, Diagnostic.Kind.WARNING));
 264         assertDeclareWarn1("@X final interface C extends A { }",
 265                 new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 8, 0, -1, -1, Diagnostic.Kind.WARNING));
 266         assertActiveKeys();
 267     }
 268 
 269     public void classesIgnoredModifiersOtherModifiers() {
 270         assertEval("strictfp public interface A { }");
 271         assertDeclareWarn1("strictfp static class B implements A { }",
 272                 new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 15, 0, -1, -1, Diagnostic.Kind.WARNING));
 273         assertDeclareWarn1("strictfp final interface C extends A { }",
 274                 new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 14, 0, -1, -1, Diagnostic.Kind.WARNING));
 275         assertActiveKeys();
 276     }
 277 
 278     public void ignoreModifierSpaceIssue() {
 279         assertEval("interface I { void f(); } ");
 280         // there should not be a space between 'I' and '{' to reproduce the failure
 281         assertEval("class C implements I{ public void f() {}}");
 282         assertClasses(clazz(KullaTesting.ClassType.CLASS, "C"), clazz(KullaTesting.ClassType.INTERFACE, "I"));
 283         assertActiveKeys();
 284     }
 285 
 286     @DataProvider(name = "innerClasses")
 287     public Object[][] innerClasses() {
 288         List<Object[]> list = new ArrayList<>();
 289         for (ClassType outerClassType : ClassType.values()) {
 290             for (ClassType innerClassType : ClassType.values()) {
 291                 list.add(new Object[]{outerClassType, innerClassType});
 292             }
 293         }
 294         return list.toArray(new Object[list.size()][]);
 295     }
 296 
 297     @Test(dataProvider = "innerClasses")
 298     public void innerClasses(ClassType outerClassType, ClassType innerClassType) {
 299         String source =
 300                 outerClassType + " A {" + (outerClassType == ClassType.ENUM ? ";" : "") +
 301                 innerClassType + " B { }" +
 302                 "}";
 303         assertEval(source);
 304         assertNumberOfActiveClasses(1);
 305         assertActiveKeys();
 306     }
 307 
 308     public void testInnerClassesCrash() {
 309         Snippet a = classKey(assertEval("class A { class B extends A {} }"));
 310         Snippet a2 = classKey(assertEval("class A { interface I1 extends I2 {} interface I2 {} }",
 311                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
 312                 ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET)));
 313         assertEval("class A { A a = new A() {}; }",
 314                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
 315                 ste(a2, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
 316     }
 317 
 318     public void testInnerClassesCrash1() {
 319         assertEval("class A { class B extends A {} B getB() { return new B();} }");
 320         assertEquals(varKey(assertEval("A a = new A();")).name(), "a");
 321         VarSnippet variableKey = varKey(assertEval("a.getB();"));
 322         assertEquals(variableKey.typeName(), "A.B");
 323     }
 324 
 325     public void testInnerClassesCrash2() {
 326         assertEval("class A { interface I1 extends I2 {} interface I2 {} I1 x; }");
 327         assertEquals(varKey(assertEval("A a = new A();")).name(), "a");
 328         VarSnippet variableKey = varKey(assertEval("a.x;"));
 329         assertEquals(variableKey.typeName(), "A.I1");
 330     }
 331 
 332     public void testCircular() {
 333         assertEval("import java.util.function.Supplier;");
 334         TypeDeclSnippet aClass =
 335                 classKey(assertEval("public class A<T> {\n" +
 336                                     "  private class SomeClass {}\n" +
 337                                     "  public Supplier<T> m() {\n" +
 338                                     "    return new B<>(this);\n" +
 339                                     "  }\n" +
 340                                     "}",
 341                                    added(RECOVERABLE_DEFINED)));
 342         assertEval("public class B<T> implements Supplier<T> {\n" +
 343                    "  public B(A<T> a) {}\n" +
 344                    "  public T get() {return null;}\n" +
 345                    "}",
 346                    added(VALID),
 347                    ste(aClass, Status.RECOVERABLE_DEFINED, Status.VALID, true, null));
 348         assertEval("new A()");
 349     }
 350 
 351 }