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