1/* 2 * Copyright (c) 2011, 2015, 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 7086601 27 * @summary Error message bug: cause for method mismatch is 'null' 28 * @modules jdk.compiler 29 */ 30 31import com.sun.source.util.JavacTask; 32import java.net.URI; 33import java.util.Arrays; 34import java.util.ArrayList; 35import javax.tools.Diagnostic; 36import javax.tools.JavaCompiler; 37import javax.tools.JavaFileObject; 38import javax.tools.SimpleJavaFileObject; 39import javax.tools.StandardJavaFileManager; 40import javax.tools.ToolProvider; 41 42 43public class T7086601b { 44 45 static int checkCount = 0; 46 47 enum TypeKind { 48 STRING("String", false), 49 INTEGER("Integer", false), 50 NUMBER("Number", false), 51 SERIALIZABLE("java.io.Serializable", true), 52 CLONEABLE("Cloneable", true), 53 X("X", false), 54 Y("Y", false), 55 Z("Z", false); 56 57 String typeStr; 58 boolean isInterface; 59 60 private TypeKind(String typeStr, boolean isInterface) { 61 this.typeStr = typeStr; 62 this.isInterface = isInterface; 63 } 64 65 boolean isSubtypeof(TypeKind other) { 66 return (this == INTEGER && other == NUMBER || 67 this == Z && other == Y || 68 this == other); 69 } 70 } 71 72 enum MethodCallKind { 73 ARITY_ONE("m(a1);", 1), 74 ARITY_TWO("m(a1, a2);", 2), 75 ARITY_THREE("m(a1, a2, a3);", 3); 76 77 String invokeString; 78 int arity; 79 80 private MethodCallKind(String invokeString, int arity) { 81 this.invokeString = invokeString; 82 this.arity = arity; 83 } 84 } 85 86 public static void main(String... args) throws Exception { 87 88 //create default shared JavaCompiler - reused across multiple compilations 89 JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 90 try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) { 91 92 for (TypeKind a1 : TypeKind.values()) { 93 for (TypeKind a2 : TypeKind.values()) { 94 for (TypeKind a3 : TypeKind.values()) { 95 for (MethodCallKind mck : MethodCallKind.values()) { 96 new T7086601b(a1, a2, a3, mck).run(comp, fm); 97 } 98 } 99 } 100 } 101 System.out.println("Total check executed: " + checkCount); 102 } 103 } 104 105 TypeKind a1; 106 TypeKind a2; 107 TypeKind a3; 108 MethodCallKind mck; 109 JavaSource source; 110 DiagnosticChecker diagChecker; 111 112 T7086601b(TypeKind a1, TypeKind a2, TypeKind a3, MethodCallKind mck) { 113 this.a1 = a1; 114 this.a2 = a2; 115 this.a3 = a3; 116 this.mck = mck; 117 this.source = new JavaSource(); 118 this.diagChecker = new DiagnosticChecker(); 119 } 120 121 class JavaSource extends SimpleJavaFileObject { 122 123 final String bodyTemplate = "import java.util.List;\n"+ 124 "class Test {\n" + 125 " <Z> void m(List<? super Z> l1) { }\n" + 126 " <Z> void m(List<? super Z> l1, List<? super Z> l2) { }\n" + 127 " <Z> void m(List<? super Z> l1, List<? super Z> l2, List<? super Z> l3) { }\n" + 128 " <X,Y,Z extends Y> void test(List<#A1> a1, List<#A2> a2, List<#A3> a3) { #MC } }"; 129 130 String source; 131 132 public JavaSource() { 133 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 134 source = bodyTemplate.replace("#A1", a1.typeStr) 135 .replace("#A2", a2.typeStr).replace("#A3", a3.typeStr) 136 .replace("#MC", mck.invokeString); 137 } 138 139 @Override 140 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 141 return source; 142 } 143 } 144 145 void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { 146 JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, 147 null, null, Arrays.asList(source)); 148 try { 149 ct.analyze(); 150 } catch (Throwable ex) { 151 throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true)); 152 } 153 check(); 154 } 155 156 void check() { 157 checkCount++; 158 159 boolean errorExpected = false; 160 161 if (mck.arity > 1) { 162 TypeKind[] argtypes = { a1, a2, a3 }; 163 ArrayList<TypeKind> classes = new ArrayList<>(); 164 for (int i = 0 ; i < mck.arity ; i ++ ) { 165 if (!argtypes[i].isInterface) { 166 classes.add(argtypes[i]); 167 } 168 } 169 boolean glb_exists = true; 170 for (TypeKind arg_i : classes) { 171 glb_exists = true; 172 for (TypeKind arg_j : classes) { 173 if (!arg_i.isSubtypeof(arg_j)) { 174 glb_exists = false; 175 break; 176 } 177 } 178 if (glb_exists) break; 179 } 180 errorExpected = !glb_exists; 181 } 182 183 if (errorExpected != diagChecker.errorFound) { 184 throw new Error("invalid diagnostics for source:\n" + 185 source.getCharContent(true) + 186 "\nFound error: " + diagChecker.errorFound + 187 "\nExpected error: " + errorExpected); 188 } 189 } 190 191 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { 192 193 boolean errorFound; 194 195 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 196 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 197 errorFound = true; 198 } 199 } 200 } 201} 202