Wed, 26 Jan 2011 13:45:25 -0800
7013272: Automatically generate info about how compiler resource keys are used
Reviewed-by: mcimadamore
mcimadamore@792 | 1 | /* |
mcimadamore@792 | 2 | * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. |
mcimadamore@792 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
mcimadamore@792 | 4 | * |
mcimadamore@792 | 5 | * This code is free software; you can redistribute it and/or modify it |
mcimadamore@792 | 6 | * under the terms of the GNU General Public License version 2 only, as |
mcimadamore@792 | 7 | * published by the Free Software Foundation. |
mcimadamore@792 | 8 | * |
mcimadamore@792 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
mcimadamore@792 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
mcimadamore@792 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
mcimadamore@792 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
mcimadamore@792 | 13 | * accompanied this code). |
mcimadamore@792 | 14 | * |
mcimadamore@792 | 15 | * You should have received a copy of the GNU General Public License version |
mcimadamore@792 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
mcimadamore@792 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
mcimadamore@792 | 18 | * |
mcimadamore@792 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
mcimadamore@792 | 20 | * or visit www.oracle.com if you need additional information or have any |
mcimadamore@792 | 21 | * questions. |
mcimadamore@792 | 22 | */ |
mcimadamore@792 | 23 | |
mcimadamore@792 | 24 | import com.sun.tools.javac.code.BoundKind; |
mcimadamore@792 | 25 | import com.sun.tools.javac.code.Flags; |
mcimadamore@792 | 26 | import com.sun.tools.javac.util.Context; |
mcimadamore@792 | 27 | import com.sun.tools.javac.code.Types; |
mcimadamore@792 | 28 | import com.sun.tools.javac.code.Symtab; |
mcimadamore@792 | 29 | import com.sun.tools.javac.code.Type; |
mcimadamore@792 | 30 | import com.sun.tools.javac.code.Type.*; |
mcimadamore@792 | 31 | import com.sun.tools.javac.code.Symbol.*; |
mcimadamore@821 | 32 | import com.sun.tools.javac.comp.Check; |
mcimadamore@792 | 33 | import com.sun.tools.javac.util.List; |
mcimadamore@792 | 34 | import com.sun.tools.javac.util.ListBuffer; |
mcimadamore@792 | 35 | import com.sun.tools.javac.util.Name; |
mcimadamore@792 | 36 | import com.sun.tools.javac.util.Names; |
mcimadamore@792 | 37 | import com.sun.tools.javac.file.JavacFileManager; |
mcimadamore@792 | 38 | |
mcimadamore@792 | 39 | /** |
mcimadamore@792 | 40 | * Test harness whose goal is to simplify the task of writing type-system |
mcimadamore@792 | 41 | * regression test. It provides functionalities to build custom types as well |
mcimadamore@792 | 42 | * as to access the underlying javac's symbol table in order to retrieve |
mcimadamore@792 | 43 | * predefined types. Among the features supported by the harness are: type |
mcimadamore@792 | 44 | * substitution, type containment, subtyping, cast-conversion, assigment |
mcimadamore@792 | 45 | * conversion. |
mcimadamore@792 | 46 | * |
mcimadamore@792 | 47 | * This class is meant to be a common super class for all concrete type test |
mcimadamore@792 | 48 | * classes. A subclass can access the type-factory and the test methods so as |
mcimadamore@792 | 49 | * to write compact tests. An example is reported below: |
mcimadamore@792 | 50 | * |
mcimadamore@792 | 51 | * <pre> |
mcimadamore@792 | 52 | * Type X = fac.TypeVariable(); |
mcimadamore@792 | 53 | * Type Y = fac.TypeVariable(); |
mcimadamore@792 | 54 | * Type A_X_Y = fac.Class(0, X, Y); |
mcimadamore@792 | 55 | * Type A_Obj_Obj = fac.Class(0, |
mcimadamore@792 | 56 | * predef.objectType, |
mcimadamore@792 | 57 | * predef.objectType); |
mcimadamore@792 | 58 | * checkSameType(A_Obj_Obj, subst(A_X_Y, |
mcimadamore@792 | 59 | * Mapping(X, predef.objectType), |
mcimadamore@792 | 60 | * Mapping(Y, predef.objectType))); |
mcimadamore@792 | 61 | * </pre> |
mcimadamore@792 | 62 | * |
mcimadamore@792 | 63 | * The above code is used to create two class types, namely {@code A<X,Y>} and |
mcimadamore@792 | 64 | * {@code A<Object,Object>} where both {@code X} and {@code Y} are type-variables. |
mcimadamore@792 | 65 | * The code then verifies that {@code [X:=Object,Y:=Object]A<X,Y> == A<Object,Object>}. |
mcimadamore@792 | 66 | * |
mcimadamore@792 | 67 | * @author mcimadamore |
mcimadamore@792 | 68 | */ |
mcimadamore@792 | 69 | public class TypeHarness { |
mcimadamore@792 | 70 | |
mcimadamore@792 | 71 | protected Types types; |
mcimadamore@821 | 72 | protected Check chk; |
mcimadamore@792 | 73 | protected Symtab predef; |
mcimadamore@792 | 74 | protected Names names; |
mcimadamore@792 | 75 | protected Factory fac; |
mcimadamore@792 | 76 | |
mcimadamore@792 | 77 | protected TypeHarness() { |
mcimadamore@792 | 78 | Context ctx = new Context(); |
mcimadamore@792 | 79 | JavacFileManager.preRegister(ctx); |
mcimadamore@792 | 80 | types = Types.instance(ctx); |
mcimadamore@821 | 81 | chk = Check.instance(ctx); |
mcimadamore@792 | 82 | predef = Symtab.instance(ctx); |
mcimadamore@792 | 83 | names = Names.instance(ctx); |
mcimadamore@792 | 84 | fac = new Factory(); |
mcimadamore@792 | 85 | } |
mcimadamore@792 | 86 | |
mcimadamore@792 | 87 | // <editor-fold defaultstate="collapsed" desc="type assertions"> |
mcimadamore@792 | 88 | |
mcimadamore@792 | 89 | /** assert that 's' is a subtype of 't' */ |
mcimadamore@792 | 90 | public void assertSubtype(Type s, Type t) { |
mcimadamore@792 | 91 | assertSubtype(s, t, true); |
mcimadamore@792 | 92 | } |
mcimadamore@792 | 93 | |
mcimadamore@792 | 94 | /** assert that 's' is/is not a subtype of 't' */ |
mcimadamore@792 | 95 | public void assertSubtype(Type s, Type t, boolean expected) { |
mcimadamore@792 | 96 | if (types.isSubtype(s, t) != expected) { |
mcimadamore@792 | 97 | String msg = expected ? |
mcimadamore@792 | 98 | " is not a subtype of " : |
mcimadamore@792 | 99 | " is a subtype of "; |
mcimadamore@792 | 100 | error(s + msg + t); |
mcimadamore@792 | 101 | } |
mcimadamore@792 | 102 | } |
mcimadamore@792 | 103 | |
mcimadamore@792 | 104 | /** assert that 's' is the same type as 't' */ |
mcimadamore@792 | 105 | public void assertSameType(Type s, Type t) { |
mcimadamore@792 | 106 | assertSameType(s, t, true); |
mcimadamore@792 | 107 | } |
mcimadamore@792 | 108 | |
mcimadamore@792 | 109 | /** assert that 's' is/is not the same type as 't' */ |
mcimadamore@792 | 110 | public void assertSameType(Type s, Type t, boolean expected) { |
mcimadamore@792 | 111 | if (types.isSameType(s, t) != expected) { |
mcimadamore@792 | 112 | String msg = expected ? |
mcimadamore@792 | 113 | " is not the same type as " : |
mcimadamore@792 | 114 | " is the same type as "; |
mcimadamore@792 | 115 | error(s + msg + t); |
mcimadamore@792 | 116 | } |
mcimadamore@792 | 117 | } |
mcimadamore@792 | 118 | |
mcimadamore@792 | 119 | /** assert that 's' is castable to 't' */ |
mcimadamore@792 | 120 | public void assertCastable(Type s, Type t) { |
mcimadamore@792 | 121 | assertCastable(s, t, true); |
mcimadamore@792 | 122 | } |
mcimadamore@792 | 123 | |
mcimadamore@792 | 124 | /** assert that 's' is/is not castable to 't' */ |
mcimadamore@792 | 125 | public void assertCastable(Type s, Type t, boolean expected) { |
mcimadamore@792 | 126 | if (types.isCastable(s, t) != expected) { |
mcimadamore@792 | 127 | String msg = expected ? |
mcimadamore@792 | 128 | " is not castable to " : |
mcimadamore@792 | 129 | " is castable to "; |
mcimadamore@792 | 130 | error(s + msg + t); |
mcimadamore@792 | 131 | } |
mcimadamore@792 | 132 | } |
mcimadamore@792 | 133 | |
mcimadamore@792 | 134 | /** assert that 's' is convertible (method invocation conversion) to 't' */ |
mcimadamore@792 | 135 | public void assertConvertible(Type s, Type t) { |
mcimadamore@792 | 136 | assertCastable(s, t, true); |
mcimadamore@792 | 137 | } |
mcimadamore@792 | 138 | |
mcimadamore@792 | 139 | /** assert that 's' is/is not convertible (method invocation conversion) to 't' */ |
mcimadamore@792 | 140 | public void assertConvertible(Type s, Type t, boolean expected) { |
mcimadamore@792 | 141 | if (types.isConvertible(s, t) != expected) { |
mcimadamore@792 | 142 | String msg = expected ? |
mcimadamore@792 | 143 | " is not convertible to " : |
mcimadamore@792 | 144 | " is convertible to "; |
mcimadamore@792 | 145 | error(s + msg + t); |
mcimadamore@792 | 146 | } |
mcimadamore@792 | 147 | } |
mcimadamore@792 | 148 | |
mcimadamore@792 | 149 | /** assert that 's' is assignable to 't' */ |
mcimadamore@792 | 150 | public void assertAssignable(Type s, Type t) { |
mcimadamore@792 | 151 | assertCastable(s, t, true); |
mcimadamore@792 | 152 | } |
mcimadamore@792 | 153 | |
mcimadamore@792 | 154 | /** assert that 's' is/is not assignable to 't' */ |
mcimadamore@792 | 155 | public void assertAssignable(Type s, Type t, boolean expected) { |
mcimadamore@792 | 156 | if (types.isAssignable(s, t) != expected) { |
mcimadamore@792 | 157 | String msg = expected ? |
mcimadamore@792 | 158 | " is not assignable to " : |
mcimadamore@792 | 159 | " is assignable to "; |
mcimadamore@792 | 160 | error(s + msg + t); |
mcimadamore@792 | 161 | } |
mcimadamore@792 | 162 | } |
mcimadamore@821 | 163 | |
mcimadamore@821 | 164 | /** assert that generic type 't' is well-formed */ |
mcimadamore@821 | 165 | public void assertValidGenericType(Type t) { |
mcimadamore@821 | 166 | assertValidGenericType(t, true); |
mcimadamore@821 | 167 | } |
mcimadamore@821 | 168 | |
mcimadamore@821 | 169 | /** assert that 's' is/is not assignable to 't' */ |
mcimadamore@821 | 170 | public void assertValidGenericType(Type t, boolean expected) { |
mcimadamore@821 | 171 | if (chk.checkValidGenericType(t) != expected) { |
mcimadamore@821 | 172 | String msg = expected ? |
mcimadamore@821 | 173 | " is not a valid generic type" : |
mcimadamore@821 | 174 | " is a valid generic type"; |
mcimadamore@821 | 175 | error(t + msg + " " + t.tsym.type); |
mcimadamore@821 | 176 | } |
mcimadamore@821 | 177 | } |
mcimadamore@792 | 178 | // </editor-fold> |
mcimadamore@792 | 179 | |
mcimadamore@792 | 180 | private void error(String msg) { |
mcimadamore@792 | 181 | throw new AssertionError("Unexpected result: " + msg); |
mcimadamore@792 | 182 | } |
mcimadamore@792 | 183 | |
mcimadamore@792 | 184 | // <editor-fold defaultstate="collapsed" desc="type functions"> |
mcimadamore@792 | 185 | |
mcimadamore@792 | 186 | /** compute the erasure of a type 't' */ |
mcimadamore@792 | 187 | public Type erasure(Type t) { |
mcimadamore@792 | 188 | return types.erasure(t); |
mcimadamore@792 | 189 | } |
mcimadamore@792 | 190 | |
mcimadamore@792 | 191 | /** compute the capture of a type 't' */ |
mcimadamore@792 | 192 | public Type capture(Type t) { |
mcimadamore@792 | 193 | return types.capture(t); |
mcimadamore@792 | 194 | } |
mcimadamore@792 | 195 | |
mcimadamore@792 | 196 | /** compute the boxed type associated with 't' */ |
mcimadamore@792 | 197 | public Type box(Type t) { |
mcimadamore@792 | 198 | if (!t.isPrimitive()) { |
mcimadamore@792 | 199 | throw new AssertionError("Cannot box non-primitive type: " + t); |
mcimadamore@792 | 200 | } |
mcimadamore@792 | 201 | return types.boxedClass(t).type; |
mcimadamore@792 | 202 | } |
mcimadamore@792 | 203 | |
mcimadamore@792 | 204 | /** compute the unboxed type associated with 't' */ |
mcimadamore@792 | 205 | public Type unbox(Type t) { |
mcimadamore@792 | 206 | Type u = types.unboxedType(t); |
mcimadamore@792 | 207 | if (t == null) { |
mcimadamore@792 | 208 | throw new AssertionError("Cannot unbox reference type: " + t); |
mcimadamore@792 | 209 | } else { |
mcimadamore@792 | 210 | return u; |
mcimadamore@792 | 211 | } |
mcimadamore@792 | 212 | } |
mcimadamore@792 | 213 | |
mcimadamore@792 | 214 | /** compute a type substitution on 't' given a list of type mappings */ |
mcimadamore@792 | 215 | public Type subst(Type t, Mapping... maps) { |
mcimadamore@792 | 216 | ListBuffer<Type> from = ListBuffer.lb(); |
mcimadamore@792 | 217 | ListBuffer<Type> to = ListBuffer.lb(); |
mcimadamore@792 | 218 | for (Mapping tm : maps) { |
mcimadamore@792 | 219 | from.append(tm.from); |
mcimadamore@792 | 220 | to.append(tm.to); |
mcimadamore@792 | 221 | } |
mcimadamore@792 | 222 | return types.subst(t, from.toList(), to.toList()); |
mcimadamore@792 | 223 | } |
mcimadamore@792 | 224 | |
mcimadamore@792 | 225 | /** create a fresh type mapping from a type to another */ |
mcimadamore@792 | 226 | public Mapping Mapping(Type from, Type to) { |
mcimadamore@792 | 227 | return new Mapping(from, to); |
mcimadamore@792 | 228 | } |
mcimadamore@792 | 229 | |
mcimadamore@792 | 230 | public static class Mapping { |
mcimadamore@792 | 231 | Type from; |
mcimadamore@792 | 232 | Type to; |
mcimadamore@792 | 233 | private Mapping(Type from, Type to) { |
mcimadamore@792 | 234 | this.from = from; |
mcimadamore@792 | 235 | this.to = to; |
mcimadamore@792 | 236 | } |
mcimadamore@792 | 237 | } |
mcimadamore@792 | 238 | // </editor-fold> |
mcimadamore@792 | 239 | |
mcimadamore@792 | 240 | // <editor-fold defaultstate="collapsed" desc="type factory"> |
mcimadamore@792 | 241 | |
mcimadamore@792 | 242 | /** |
mcimadamore@792 | 243 | * This class is used to create Java types in a simple way. All main |
mcimadamore@792 | 244 | * kinds of type are supported: primitive, reference, non-denotable. The |
mcimadamore@792 | 245 | * factory also supports creation of constant types (used by the compiler |
mcimadamore@792 | 246 | * to represent the type of a literal). |
mcimadamore@792 | 247 | */ |
mcimadamore@792 | 248 | public class Factory { |
mcimadamore@792 | 249 | |
mcimadamore@792 | 250 | private int synthNameCount = 0; |
mcimadamore@792 | 251 | |
mcimadamore@792 | 252 | private Name syntheticName() { |
mcimadamore@792 | 253 | return names.fromString("A$" + synthNameCount++); |
mcimadamore@792 | 254 | } |
mcimadamore@792 | 255 | |
mcimadamore@792 | 256 | public ClassType Class(long flags, Type... typeArgs) { |
mcimadamore@792 | 257 | ClassSymbol csym = new ClassSymbol(flags, syntheticName(), predef.noSymbol); |
mcimadamore@792 | 258 | csym.type = new ClassType(Type.noType, List.from(typeArgs), csym); |
mcimadamore@792 | 259 | ((ClassType)csym.type).supertype_field = predef.objectType; |
mcimadamore@792 | 260 | return (ClassType)csym.type; |
mcimadamore@792 | 261 | } |
mcimadamore@792 | 262 | |
mcimadamore@792 | 263 | public ClassType Class(Type... typeArgs) { |
mcimadamore@792 | 264 | return Class(0, typeArgs); |
mcimadamore@792 | 265 | } |
mcimadamore@792 | 266 | |
mcimadamore@792 | 267 | public ClassType Interface(Type... typeArgs) { |
mcimadamore@792 | 268 | return Class(Flags.INTERFACE, typeArgs); |
mcimadamore@792 | 269 | } |
mcimadamore@792 | 270 | |
mcimadamore@792 | 271 | public ClassType Interface(long flags, Type... typeArgs) { |
mcimadamore@792 | 272 | return Class(Flags.INTERFACE | flags, typeArgs); |
mcimadamore@792 | 273 | } |
mcimadamore@792 | 274 | |
mcimadamore@792 | 275 | public Type Constant(byte b) { |
mcimadamore@792 | 276 | return predef.byteType.constType(b); |
mcimadamore@792 | 277 | } |
mcimadamore@792 | 278 | |
mcimadamore@792 | 279 | public Type Constant(short s) { |
mcimadamore@792 | 280 | return predef.shortType.constType(s); |
mcimadamore@792 | 281 | } |
mcimadamore@792 | 282 | |
mcimadamore@792 | 283 | public Type Constant(int i) { |
mcimadamore@792 | 284 | return predef.intType.constType(i); |
mcimadamore@792 | 285 | } |
mcimadamore@792 | 286 | |
mcimadamore@792 | 287 | public Type Constant(long l) { |
mcimadamore@792 | 288 | return predef.longType.constType(l); |
mcimadamore@792 | 289 | } |
mcimadamore@792 | 290 | |
mcimadamore@792 | 291 | public Type Constant(float f) { |
mcimadamore@792 | 292 | return predef.floatType.constType(f); |
mcimadamore@792 | 293 | } |
mcimadamore@792 | 294 | |
mcimadamore@792 | 295 | public Type Constant(double d) { |
mcimadamore@792 | 296 | return predef.doubleType.constType(d); |
mcimadamore@792 | 297 | } |
mcimadamore@792 | 298 | |
mcimadamore@792 | 299 | public Type Constant(char c) { |
mcimadamore@792 | 300 | return predef.charType.constType(c + 0); |
mcimadamore@792 | 301 | } |
mcimadamore@792 | 302 | |
mcimadamore@792 | 303 | public ArrayType Array(Type elemType) { |
mcimadamore@792 | 304 | return new ArrayType(elemType, predef.arrayClass); |
mcimadamore@792 | 305 | } |
mcimadamore@792 | 306 | |
mcimadamore@792 | 307 | public TypeVar TypeVariable() { |
mcimadamore@792 | 308 | return TypeVariable(predef.objectType); |
mcimadamore@792 | 309 | } |
mcimadamore@792 | 310 | |
mcimadamore@792 | 311 | public TypeVar TypeVariable(Type bound) { |
mcimadamore@792 | 312 | TypeSymbol tvsym = new TypeSymbol(0, syntheticName(), null, predef.noSymbol); |
mcimadamore@792 | 313 | tvsym.type = new TypeVar(tvsym, bound, null); |
mcimadamore@792 | 314 | return (TypeVar)tvsym.type; |
mcimadamore@792 | 315 | } |
mcimadamore@792 | 316 | |
mcimadamore@792 | 317 | public WildcardType Wildcard(BoundKind bk, Type bound) { |
mcimadamore@792 | 318 | return new WildcardType(bound, bk, predef.boundClass); |
mcimadamore@792 | 319 | } |
mcimadamore@792 | 320 | |
mcimadamore@792 | 321 | public CapturedType CapturedVariable(Type upper, Type lower) { |
mcimadamore@792 | 322 | return new CapturedType(syntheticName(), predef.noSymbol, upper, lower, null); |
mcimadamore@792 | 323 | } |
mcimadamore@792 | 324 | |
mcimadamore@792 | 325 | public ClassType Intersection(Type classBound, Type... intfBounds) { |
mcimadamore@792 | 326 | ClassType ct = Class(Flags.COMPOUND); |
mcimadamore@792 | 327 | ct.supertype_field = classBound; |
mcimadamore@792 | 328 | ct.interfaces_field = List.from(intfBounds); |
mcimadamore@792 | 329 | return ct; |
mcimadamore@792 | 330 | } |
mcimadamore@792 | 331 | } |
mcimadamore@792 | 332 | // </editor-fold> |
mcimadamore@792 | 333 | } |