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 8246353
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 
noClasses()60     public void noClasses() {
61         assertNumberOfActiveClasses(0);
62     }
63 
testSignature1()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 
testSignature2()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 
classDeclaration()95     public void classDeclaration() {
96         assertEval("class A { }");
97         assertClasses(clazz(KullaTesting.ClassType.CLASS, "A"));
98     }
99 
100 
interfaceDeclaration()101     public void interfaceDeclaration() {
102         assertEval("interface A { }");
103         assertClasses(clazz(KullaTesting.ClassType.INTERFACE, "A"));
104     }
105 
annotationDeclaration()106     public void annotationDeclaration() {
107         assertEval("@interface A { }");
108         assertClasses(clazz(KullaTesting.ClassType.ANNOTATION, "A"));
109     }
110 
enumDeclaration()111     public void enumDeclaration() {
112         assertEval("enum A { }");
113         assertClasses(clazz(KullaTesting.ClassType.ENUM, "A"));
114     }
115 
classesDeclaration()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 
classesRedeclaration1()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 
classesRedeclaration2()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
classesRedeclaration3()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 
classesCyclic1()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 
classesCyclic2()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 
classesCyclic3()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 
classesIgnoredModifiers()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("static interface C extends A { }",
255                 new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.WARNING));
256         assertActiveKeys();
257     }
258 
classesIgnoredModifiersAnnotation()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 static interface C extends A { }",
265                 new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 9, 0, -1, -1, Diagnostic.Kind.WARNING));
266         assertActiveKeys();
267     }
268 
classesIgnoredModifiersOtherModifiers()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 static interface C extends A { }",
274                 new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 15, 0, -1, -1, Diagnostic.Kind.WARNING));
275         assertActiveKeys();
276     }
277 
ignoreModifierSpaceIssue()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")
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")
innerClasses(ClassType outerClassType, ClassType innerClassType)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 
testInnerClassesCrash()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 
testInnerClassesCrash1()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 
testInnerClassesCrash2()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 
testCircular()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, false, null));
348         assertEval("new A()");
349     }
350 
351 }
352