1 /*
  2  * Copyright (c) 2005, 2021, 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package com.sun.tools.javac.model;
 27 
 28 import java.util.Collection;
 29 import java.util.Collections;
 30 import java.util.EnumSet;
 31 import java.util.LinkedHashSet;
 32 import java.util.List;
 33 import java.util.Set;
 34 import java.util.stream.Collectors;
 35 
 36 import javax.lang.model.element.*;
 37 import javax.lang.model.type.*;
 38 
 39 import com.sun.tools.javac.code.*;
 40 import com.sun.tools.javac.code.Symbol.*;
 41 import com.sun.tools.javac.util.*;
 42 import com.sun.tools.javac.util.DefinedBy.Api;
 43 
 44 import static com.sun.tools.javac.code.Kinds.Kind.*;
 45 
 46 /**
 47  * Utility methods for operating on types.
 48  *
 49  * <p><b>This is NOT part of any supported API.
 50  * If you write code that depends on this, you do so at your own
 51  * risk.  This code and its internal interfaces are subject to change
 52  * or deletion without notice.</b></p>
 53  */
 54 public class JavacTypes implements javax.lang.model.util.Types {
 55 
 56     private final Symtab syms;
 57     private final Types types;
 58 
 59     public static JavacTypes instance(Context context) {
 60         JavacTypes instance = context.get(JavacTypes.class);
 61         if (instance == null)
 62             instance = new JavacTypes(context);
 63         return instance;
 64     }
 65 
 66     protected JavacTypes(Context context) {
 67         context.put(JavacTypes.class, this);
 68         syms = Symtab.instance(context);
 69         types = Types.instance(context);
 70     }
 71 
 72     @DefinedBy(Api.LANGUAGE_MODEL)
 73     public Element asElement(TypeMirror t) {
 74         switch (t.getKind()) {
 75             case DECLARED:
 76             case INTERSECTION:
 77             case ERROR:
 78             case TYPEVAR:
 79                 Type type = cast(Type.class, t);
 80                 return type.asElement();
 81             default:
 82                 return null;
 83         }
 84     }
 85 
 86     @DefinedBy(Api.LANGUAGE_MODEL)
 87     public boolean isSameType(TypeMirror t1, TypeMirror t2) {
 88         if (t1.getKind() == TypeKind.WILDCARD || t2.getKind() == TypeKind.WILDCARD) {
 89             return false;
 90         }
 91         return types.isSameType((Type) t1, (Type) t2);
 92     }
 93 
 94     @DefinedBy(Api.LANGUAGE_MODEL)
 95     public boolean isSubtype(TypeMirror t1, TypeMirror t2) {
 96         validateTypeNotIn(t1, EXEC_OR_PKG_OR_MOD);
 97         validateTypeNotIn(t2, EXEC_OR_PKG_OR_MOD);
 98         return types.isSubtype((Type) t1, (Type) t2);
 99     }
100 
101     @DefinedBy(Api.LANGUAGE_MODEL)
102     public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
103         validateTypeNotIn(t1, EXEC_OR_PKG_OR_MOD);
104         validateTypeNotIn(t2, EXEC_OR_PKG_OR_MOD);
105         return types.isAssignable((Type) t1, (Type) t2);
106     }
107 
108     @DefinedBy(Api.LANGUAGE_MODEL)
109     public boolean contains(TypeMirror t1, TypeMirror t2) {
110         validateTypeNotIn(t1, EXEC_OR_PKG_OR_MOD);
111         validateTypeNotIn(t2, EXEC_OR_PKG_OR_MOD);
112         return types.containsType((Type) t1, (Type) t2);
113     }
114 
115     @DefinedBy(Api.LANGUAGE_MODEL)
116     public boolean isSubsignature(ExecutableType m1, ExecutableType m2) {
117         return types.isSubSignature((Type) m1, (Type) m2);
118     }
119 
120     @DefinedBy(Api.LANGUAGE_MODEL)
121     public List<Type> directSupertypes(TypeMirror t) {
122         validateTypeNotIn(t, EXEC_OR_PKG_OR_MOD);
123         Type ty = (Type)t;
124         return types.directSupertypes(ty).stream()
125                 .map(Type::stripMetadataIfNeeded)
126                 .toList();
127     }
128 
129     @DefinedBy(Api.LANGUAGE_MODEL)
130     public TypeMirror erasure(TypeMirror t) {
131         TypeKind kind = t.getKind();
132         if (kind == TypeKind.PACKAGE || kind == TypeKind.MODULE)
133             throw new IllegalArgumentException(t.toString());
134         return types.erasure((Type)t).stripMetadataIfNeeded();
135     }
136 
137     @DefinedBy(Api.LANGUAGE_MODEL)
138     public TypeElement boxedClass(PrimitiveType p) {
139         return types.boxedClass((Type) p);
140     }
141 
142     @DefinedBy(Api.LANGUAGE_MODEL)
143     public PrimitiveType unboxedType(TypeMirror t) {
144         if (t.getKind() != TypeKind.DECLARED)
145             throw new IllegalArgumentException(t.toString());
146         Type unboxed = types.unboxedType((Type) t);
147         if (! unboxed.isPrimitive())    // only true primitives, not void
148             throw new IllegalArgumentException(t.toString());
149         return (PrimitiveType)unboxed;
150     }
151 
152     @DefinedBy(Api.LANGUAGE_MODEL)
153     public TypeMirror capture(TypeMirror t) {
154         validateTypeNotIn(t, EXEC_OR_PKG_OR_MOD);
155         return types.capture((Type)t).stripMetadataIfNeeded();
156     }
157 
158     @DefinedBy(Api.LANGUAGE_MODEL)
159     public PrimitiveType getPrimitiveType(TypeKind kind) {
160         switch (kind) {
161         case BOOLEAN:   return syms.booleanType;
162         case BYTE:      return syms.byteType;
163         case SHORT:     return syms.shortType;
164         case INT:       return syms.intType;
165         case LONG:      return syms.longType;
166         case CHAR:      return syms.charType;
167         case FLOAT:     return syms.floatType;
168         case DOUBLE:    return syms.doubleType;
169         default:
170             throw new IllegalArgumentException("Not a primitive type: " + kind);
171         }
172     }
173 
174     @DefinedBy(Api.LANGUAGE_MODEL)
175     public NullType getNullType() {
176         return (NullType) syms.botType;
177     }
178 
179     @DefinedBy(Api.LANGUAGE_MODEL)
180     public NoType getNoType(TypeKind kind) {
181         switch (kind) {
182         case VOID:      return syms.voidType;
183         case NONE:      return Type.noType;
184         default:
185             throw new IllegalArgumentException(kind.toString());
186         }
187     }
188 
189     @DefinedBy(Api.LANGUAGE_MODEL)
190     public ArrayType getArrayType(TypeMirror componentType) {
191         switch (componentType.getKind()) {
192         case VOID:
193         case EXECUTABLE:
194         case WILDCARD:  // heh!
195         case PACKAGE:
196         case MODULE:
197             throw new IllegalArgumentException(componentType.toString());
198         }
199         return new Type.ArrayType((Type) componentType, syms.arrayClass);
200     }
201 
202     @DefinedBy(Api.LANGUAGE_MODEL)
203     public WildcardType getWildcardType(TypeMirror extendsBound,
204                                         TypeMirror superBound) {
205         BoundKind bkind;
206         Type bound;
207         if (extendsBound == null && superBound == null) {
208             bkind = BoundKind.UNBOUND;
209             bound = syms.objectType;
210         } else if (superBound == null) {
211             bkind = BoundKind.EXTENDS;
212             bound = (Type) extendsBound;
213         } else if (extendsBound == null) {
214             bkind = BoundKind.SUPER;
215             bound = (Type) superBound;
216         } else {
217             throw new IllegalArgumentException(
218                     "Extends and super bounds cannot both be provided");
219         }
220         switch (bound.getKind()) {
221         case ARRAY:
222         case DECLARED:
223         case ERROR:
224         case TYPEVAR:
225             return new Type.WildcardType(bound, bkind, syms.boundClass);
226         default:
227             throw new IllegalArgumentException(bound.toString());
228         }
229     }
230 
231     @DefinedBy(Api.LANGUAGE_MODEL)
232     public DeclaredType getDeclaredType(TypeElement typeElem,
233                                         TypeMirror... typeArgs) {
234         ClassSymbol sym = (ClassSymbol) typeElem;
235 
236         if (typeArgs.length == 0)
237             return (DeclaredType) sym.erasure(types);
238         if (sym.type.getEnclosingType().isParameterized())
239             throw new IllegalArgumentException(sym.toString());
240 
241         return getDeclaredType0(sym.type.getEnclosingType(), sym, typeArgs);
242     }
243 
244     @DefinedBy(Api.LANGUAGE_MODEL)
245     public DeclaredType getDeclaredType(DeclaredType enclosing,
246                                         TypeElement typeElem,
247                                         TypeMirror... typeArgs) {
248         if (enclosing == null)
249             return getDeclaredType(typeElem, typeArgs);
250 
251         ClassSymbol sym = (ClassSymbol) typeElem;
252         Type outer = (Type) enclosing;
253 
254         if (outer.tsym != sym.owner.enclClass())
255             throw new IllegalArgumentException(enclosing.toString());
256         if (!outer.isParameterized())
257             return getDeclaredType(typeElem, typeArgs);
258 
259         return getDeclaredType0(outer, sym, typeArgs);
260     }
261     // where
262         private DeclaredType getDeclaredType0(Type outer,
263                                               ClassSymbol sym,
264                                               TypeMirror... typeArgs) {
265             if (typeArgs.length != sym.type.getTypeArguments().length())
266                 throw new IllegalArgumentException(
267                 "Incorrect number of type arguments");
268 
269             ListBuffer<Type> targs = new ListBuffer<>();
270             for (TypeMirror t : typeArgs) {
271                 if (!(t instanceof ReferenceType || t instanceof WildcardType))
272                     throw new IllegalArgumentException(t.toString());
273                 targs.append((Type) t);
274             }
275             // TODO: Would like a way to check that type args match formals.
276 
277             return (DeclaredType) new Type.ClassType(outer, targs.toList(), sym);
278         }
279 
280     /**
281      * Returns the type of an element when that element is viewed as
282      * a member of, or otherwise directly contained by, a given type.
283      * For example,
284      * when viewed as a member of the parameterized type {@code Set<String>},
285      * the {@code Set.add} method is an {@code ExecutableType}
286      * whose parameter is of type {@code String}.
287      *
288      * @param containing  the containing type
289      * @param element     the element
290      * @return the type of the element as viewed from the containing type
291      * @throws IllegalArgumentException if the element is not a valid one
292      *          for the given type
293      */
294     @DefinedBy(Api.LANGUAGE_MODEL)
295     public TypeMirror asMemberOf(DeclaredType containing, Element element) {
296         Type site = (Type)containing;
297         Symbol sym = (Symbol)element;
298         if (types.asSuper(site, sym.getEnclosingElement()) == null)
299             throw new IllegalArgumentException(sym + "@" + site);
300         return types.memberType(site, sym);
301     }
302 
303 
304     private static final Set<TypeKind> EXEC_OR_PKG_OR_MOD =
305         EnumSet.of(TypeKind.EXECUTABLE, TypeKind.PACKAGE, TypeKind.MODULE);
306 
307     /**
308      * Throws an IllegalArgumentException if a type's kind is one of a set.
309      */
310     private void validateTypeNotIn(TypeMirror t, Set<TypeKind> invalidKinds) {
311         if (invalidKinds.contains(t.getKind()))
312             throw new IllegalArgumentException(t.toString());
313     }
314 
315     /**
316      * Returns an object cast to the specified type.
317      * @throws NullPointerException if the object is {@code null}
318      * @throws IllegalArgumentException if the object is of the wrong type
319      */
320     private static <T> T cast(Class<T> clazz, Object o) {
321         if (! clazz.isInstance(o))
322             throw new IllegalArgumentException(o.toString());
323         return clazz.cast(o);
324     }
325 
326     public Set<MethodSymbol> getOverriddenMethods(Element elem) {
327         if (elem.getKind() != ElementKind.METHOD
328                 || elem.getModifiers().contains(Modifier.STATIC)
329                 || elem.getModifiers().contains(Modifier.PRIVATE))
330             return Collections.emptySet();
331 
332         if (!(elem instanceof MethodSymbol methodSymbol))
333             throw new IllegalArgumentException();
334 
335         ClassSymbol origin = (ClassSymbol) methodSymbol.owner;
336 
337         Set<MethodSymbol> results = new LinkedHashSet<>();
338         for (Type t : types.closure(origin.type)) {
339             if (t != origin.type) {
340                 ClassSymbol c = (ClassSymbol) t.tsym;
341                 for (Symbol sym : c.members().getSymbolsByName(methodSymbol.name)) {
342                     if (sym.kind == MTH && methodSymbol.overrides(sym, origin, types, true)) {
343                         results.add((MethodSymbol) sym);
344                     }
345                 }
346             }
347         }
348 
349         return results;
350     }
351 }