1 /*
  2  * Copyright (c) 2020, 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 8235564
 27  * @summary Verify that passing member references to a method not accepting
 28  *          functional interface does not crash the compiler.
 29  * @enablePreview
 30  * @library /tools/lib /tools/javac/lib
 31  * @modules jdk.compiler/com.sun.tools.javac.api
 32  *          jdk.compiler/com.sun.tools.javac.file
 33  *          jdk.compiler/com.sun.tools.javac.main
 34  *          jdk.compiler/com.sun.tools.javac.util
 35  * @build toolbox.ToolBox toolbox.JavacTask
 36  * @build combo.ComboTestHelper
 37  * @compile T8235564.java
 38  * @run main T8235564
 39  */
 40 
 41 import combo.ComboInstance;
 42 import combo.ComboParameter;
 43 import combo.ComboTask;
 44 import combo.ComboTestHelper;
 45 import java.io.StringWriter;
 46 import java.util.ArrayList;
 47 import java.util.List;
 48 import java.util.stream.Collectors;
 49 import javax.tools.Diagnostic;
 50 import toolbox.ToolBox;
 51 
 52 public class T8235564 extends ComboInstance<T8235564> {
 53     protected ToolBox tb;
 54 
 55     T8235564() {
 56         super();
 57         tb = new ToolBox();
 58     }
 59 
 60     public static void main(String... args) throws Exception {
 61         new ComboTestHelper<T8235564>()
 62                 .withDimension("INVOCATION", (x, invocation) -> x.invocation = invocation, Invocation.values())
 63                 .withDimension("PARAM", (x, param) -> x.param = param, Parameter.values())
 64                 .run(T8235564::new);
 65     }
 66 
 67     private Invocation invocation;
 68     private Parameter param;
 69 
 70     private static final String MAIN_TEMPLATE =
 71             """
 72             public class Test {
 73                 static void test() {
 74                     Runnable r = () -> {};
 75                     #{INVOCATION};
 76                 }
 77                 private static void existingWithFunctional(Runnable r) {}
 78                 private static void existingWithoutFunctional(String parameter) {}
 79             }
 80             """;
 81 
 82     @Override
 83     protected void doWork() throws Throwable {
 84         StringWriter out = new StringWriter();
 85 
 86         ComboTask task = newCompilationTask()
 87                 .withSourceFromTemplate(MAIN_TEMPLATE, pname -> switch (pname) {
 88                         case "INVOCATION" -> invocation;
 89                         case "PARAM" -> param;
 90                         default -> throw new UnsupportedOperationException(pname);
 91                     })
 92                 .withOption("-XDshould-stop.at=FLOW")
 93                 .withOption("-XDrawDiagnostics")
 94                 .withOption("-XDdev")
 95                 .withWriter(out);
 96 
 97         task.analyze(result -> {
 98             List<String> diags = result.diagnosticsForKind(Diagnostic.Kind.ERROR)
 99                                        .stream()
100                                        .map(d -> d.getLineNumber() + ":" + d.getCode())
101                                        .collect(Collectors.toList());
102             List<String> expected = new ArrayList<>();
103             switch (param) {
104                 case VALID_VARIABLE, VALID_LAMBDA, VALID_MEMBER_REF -> {}
105                 case UNDEFINED_VARIABLE ->
106                     expected.add("4:compiler.err.cant.resolve.location");
107                 case UNDEFINED_METHOD, UNDEFINED_LAMBDA ->
108                     expected.add("4:compiler.err.cant.resolve.location.args");
109                 case UNDEFINED_MEMBER_REF ->
110                     expected.add("4:compiler.err.invalid.mref");
111                 case UNDEFINED_CONDEXPR -> {
112                     if (invocation != Invocation.EXISTING_WITHOUT_FUNCTIONAL) {
113                         expected.add("4:compiler.err.invalid.mref");
114                         expected.add("4:compiler.err.invalid.mref");
115                     }
116                 }
117             }
118             switch (invocation) {
119                 case EXISTING_WITH_FUNCTIONAL -> {
120                     if (param == Parameter.UNDEFINED_CONDEXPR) {
121                         expected.add("4:compiler.err.cant.apply.symbol");
122                     }
123                 }
124                 case EXISTING_WITHOUT_FUNCTIONAL -> {
125                     if (param != Parameter.UNDEFINED_VARIABLE &&
126                         param != Parameter.UNDEFINED_MEMBER_REF &&
127                         param != Parameter.UNDEFINED_METHOD) {
128                         expected.add("4:compiler.err.cant.apply.symbol");
129                     }
130                 }
131                 case UNDEFINED -> {
132                     if (param != Parameter.UNDEFINED_VARIABLE &&
133                         param != Parameter.UNDEFINED_MEMBER_REF &&
134                         param != Parameter.UNDEFINED_METHOD) {
135                         expected.add("4:compiler.err.cant.resolve.location.args");
136                     }
137                 }
138             }
139             if (!expected.equals(diags)) {
140                 throw new AssertionError("Expected errors not found, expected: " + expected + ", actual: " + diags);
141             }
142             if (out.toString().length() > 0) {
143                 throw new AssertionError("No output expected, but got:\n" + out + "\n\n" + result.compilationInfo());
144             }
145         });
146     }
147 
148     public enum Invocation implements ComboParameter {
149         EXISTING_WITH_FUNCTIONAL("existingWithFunctional(#{PARAM})"),
150         EXISTING_WITHOUT_FUNCTIONAL("existingWithoutFunctional(#{PARAM})"),
151         UNDEFINED("undefined(#{PARAM})");
152         private final String invocation;
153 
154         private Invocation(String invocation) {
155             this.invocation = invocation;
156         }
157 
158         @Override
159         public String expand(String optParameter) {
160             return invocation;
161         }
162     }
163 
164     public enum Parameter implements ComboParameter {
165         VALID_VARIABLE("r"),
166         VALID_LAMBDA("() -> {}"),
167         VALID_MEMBER_REF("Test::test"),
168         UNDEFINED_VARIABLE("undefined"),
169         UNDEFINED_LAMBDA("() -> {undefined();}"),
170         UNDEFINED_MEMBER_REF("Test::undefined"),
171         UNDEFINED_METHOD("undefined()"),
172         UNDEFINED_CONDEXPR("1 == 2 ? Test::undefined : Test::undefined");
173         private final String code;
174 
175         private Parameter(String code) {
176             this.code = code;
177         }
178 
179         @Override
180         public String expand(String optParameter) {
181             return code;
182         }
183     }
184 }