Class TypeSystem
SymbolResolver
, which creates and caches external symbols.
Methods of this class promote symbols to types, and compose types together.
TypeOps
and TypeConversion
have some more operations on types.
Some special types are presented as constant fields, eg OBJECT
or NULL_TYPE
. These are always comparable by reference.
Note that the primitive wrapper types are not exposed as constants
here, but can be accessed by using the box
method on some primitive constant.
The lifetime of a type system is the analysis: it is shared by all compilation units. TODO this is hacked together by comparing the ClassLoader, but this should be in the language instance
Nodes have a reference to the type system they were created for:
JavaNode.getTypeSystem()
.
-
Field Summary
FieldsModifier and TypeFieldDescriptionfinal Set
<JPrimitiveType> The set of all primitive types.final JPrimitiveType
Primitive typeboolean
.final JClassType
This is the boxed type ofVoid.class
, not to be confused withvoid.class
, which in this framework is represented byNO_TYPE
.final JPrimitiveType
Primitive typebyte
.final JPrimitiveType
Primitive typechar
.final JClassType
The interface Cloneable.final JPrimitiveType
Primitive typedouble
.final JTypeMirror
A constant to represent a typing error.final JPrimitiveType
Primitive typefloat
.final JPrimitiveType
Primitive typeint
.final JPrimitiveType
Primitive typelong
.final JTypeMirror
A constant to represent the normal absence of a type.final JTypeMirror
The bottom type of the reference type system.final JClassType
Top type of the reference type system.final JClassType
The interface Serializable.final JPrimitiveType
Primitive typeshort
.final JWildcardType
The unbounded wildcard, "?".final JTypeMirror
A constant to represent an unresolved type.final JMethodSig
Sentinel value for an unresolved method. -
Constructor Summary
ConstructorsConstructorDescriptionTypeSystem
(Function<TypeSystem, ? extends SymbolResolver> symResolverMaker) Builds a new type system. -
Method Summary
Modifier and TypeMethodDescriptionarrayType
(@NonNull JTypeMirror component) LikearrayType(JTypeMirror, int)
, with one dimension.arrayType
(@NonNull JTypeMirror element, int numDimensions) Creates a new array type from an arbitrary element type.Returns the bootstrap symbol resolver.declaration
(@Nullable JClassSymbol klass) LiketypeOf(JTypeDeclSymbol, boolean)
, defaulting the erased parameter to false.@Nullable JClassSymbol
getClassSymbol
(@Nullable Class<?> clazz) Returns the class symbol for the given reflected class.@Nullable JClassSymbol
getClassSymbol
(String binaryName) Returns a symbol for the binary name.@Nullable JClassSymbol
getClassSymbolFromCanonicalName
(String canonicalName) Returns a symbol for the canonical name.@Nullable JModuleSymbol
getModuleSymbol
(String moduleName) @NonNull JPrimitiveType
getPrimitive
(@NonNull JPrimitiveType.PrimitiveTypeKind kind) Gets the primitive type identified by the given kind.glb
(Collection<? extends JTypeMirror> types) Returns the greatest lower bound of the given set of types.void
logStats()
Called at the end of the analysis to log statistics about the loaded types.lub
(Collection<? extends JTypeMirror> types) The least upper bound, or "lub", of a set of reference types is a shared supertype that is more specific than any other shared supertype (that is, no other shared supertype is a subtype of the least upper bound).newTypeVar
(JTypeParameterSymbol symbol) Returns a new type variable for the given symbol.@NonNull JTypeMirror
parameterise
(@NonNull JClassSymbol klass, @NonNull List<? extends JTypeMirror> typeArgs) Produce a parameterized type with the given symbol and type arguments.rawType
(@Nullable JTypeDeclSymbol klass) LiketypeOf(JTypeDeclSymbol, boolean)
, defaulting the erased parameter to true.sigOf
(JExecutableSymbol methodSym) sigOf
(JExecutableSymbol methodSym, Substitution subst) sigOf
(JClassType decl, JFormalParamSymbol fieldSym) sigOf
(JClassType decl, JLocalVariableSymbol fieldSym) sigOf
(JTypeMirror decl, JFieldSymbol fieldSym) typeOf
(@Nullable JTypeDeclSymbol symbol, boolean isErased) Returns a type mirror for the given symbol.static TypeSystem
usingClassLoaderClasspath
(ClassLoader bootstrapResourceLoader) Builds a new type system.static TypeSystem
usingClasspath
(net.sourceforge.pmd.lang.java.symbols.internal.asm.Classpath bootstrapResourceLoader) Builds a new type system.wildcard
(boolean isUpperBound, @NonNull JTypeMirror bound) Builds a wildcard type with a single bound.
-
Field Details
-
OBJECT
Top type of the reference type system. This is the type for theObject
class. Note that even interfaces have this type as a supertype (JTypeMirror.getSuperTypeSet()
). -
NULL_TYPE
The bottom type of the reference type system. This is named the null type in the JLS and is not denotable in Java programs.This implementation uses this as the type of the 'null' literal.
The null type has no symbol.
-
BOOLEAN
Primitive typeboolean
. -
CHAR
Primitive typechar
. -
BYTE
Primitive typebyte
. -
SHORT
Primitive typeshort
. -
INT
Primitive typeint
. -
LONG
Primitive typelong
. -
FLOAT
Primitive typefloat
. -
DOUBLE
Primitive typedouble
. -
allPrimitives
The set of all primitive types. SeegetPrimitive(PrimitiveTypeKind)
. -
NO_TYPE
A constant to represent the normal absence of a type. The primitivevoid.class
represents that type, and this is the return type of a void method.Note that the type of the class literal
void.class
isClass<java.lang.Void>
, not NO_TYPE.java.lang.Void
is represented byBOXED_VOID
. Note thatBOXED_VOID.unbox() != NO_TYPE
,NO_TYPE.box() != BOXED_VOID
.NO_TYPE.isPrimitive()
returns false, even thoughvoid.class.isPrimitive()
returns true. -
UNKNOWN
A constant to represent an unresolved type. This means, that resolution was attempted but failed and shouldn't be tried again. The symbol is aJClassSymbol
.Note that
TypeOps.isConvertible(JTypeMirror, JTypeMirror)
considers this type a subtype of anything, even primitive types. -
ERROR
A constant to represent a typing error. This would have been reported by a compiler, and is used to propagate errors.Note that
TypeOps.isConvertible(JTypeMirror, JTypeMirror)
considers this type a subtype of anything, even primitive types. -
UNRESOLVED_METHOD
-
UNBOUNDED_WILD
The unbounded wildcard, "?". -
CLONEABLE
The interface Cloneable. This is included because it is a supertype of array types. -
SERIALIZABLE
The interface Serializable. This is included because it is a supertype of array types. -
BOXED_VOID
This is the boxed type ofVoid.class
, not to be confused withvoid.class
, which in this framework is represented byNO_TYPE
.Note that
BOXED_VOID.unbox() != NO_TYPE
,NO_TYPE.box() != BOXED_VOID
.
-
-
Constructor Details
-
TypeSystem
Builds a new type system. Its public fields will be initialized with fresh types, unrelated to other types.- Parameters:
symResolverMaker
- A function that creates a new symbol resolver, which will be owned by the new type system. Because of cyclic dependencies, the new type system is leaked before its initialization completes, so fields of the type system are unusable at that time. The resolver is used to create some shared types:OBJECT
,CLONEABLE
,SERIALIZABLE
,BOXED_VOID
.
-
-
Method Details
-
usingClassLoaderClasspath
Builds a new type system. Its public fields will be initialized with fresh types, unrelated to other types.- Parameters:
bootstrapResourceLoader
- Classloader used to resolve class files to populate the fields of the new type system
-
usingClasspath
public static TypeSystem usingClasspath(net.sourceforge.pmd.lang.java.symbols.internal.asm.Classpath bootstrapResourceLoader) Builds a new type system. Its public fields will be initialized with fresh types, unrelated to other types.- Parameters:
bootstrapResourceLoader
- Classpath used to resolve class files to populate the fields of the new type system
-
bootstrapResolver
Returns the bootstrap symbol resolver. Concrete analysis passes may decorate this with different resolvers. -
getClassSymbol
Returns the class symbol for the given reflected class. This asks the classloader of this type system. Returns null if the parameter is null, or the class is not available in the analysis classpath.- Parameters:
clazz
- Class
-
getClassSymbol
Returns a symbol for the binary name. Returns null if the name is null or the symbol is not found on the classpath. The class must not be an array.- Parameters:
binaryName
- Binary name- Returns:
- A symbol, or null
- Throws:
IllegalArgumentException
- if the argument is not a binary name
-
getClassSymbolFromCanonicalName
Returns a symbol for the canonical name. Returns null if the name is null or the symbol is not found on the classpath. The class must not be an array.Canonical names separate nested classes with
.
(periods) instead of$
(dollars) as the JVM does. Users usually use canonical names, but lookup is much more costly.- Parameters:
canonicalName
- Canonical name- Returns:
- A symbol, or null
- Throws:
IllegalArgumentException
- if the argument is not a binary name
-
getModuleSymbol
- Since:
- 7.5.0
-
typeOf
Returns a type mirror for the given symbol. If the symbol declares type parameters, then the resulting type is raw (differs from the behaviour ofdeclaration(JClassSymbol)
), meaning all its supertypes are erased.If the symbol is a
type parameter
, returns aJTypeVar
.If the symbol is a
JClassSymbol
, then:- If it represents a primitive type, the corresponding
JPrimitiveType
is returned (one ofINT
,CHAR
, etc.). - If it represents an array type, a new
JArrayType
is returned. The component type will be built with a recursive call. - If it represents a class or interface type, a
JClassType
is returned.- If the parameter
isErased
is true, and if the symbol declares type parameters, then it will be a raw type. This means, which means all its generic supertypes are erased. - Otherwise, the generic supertypes are preserved. In particular, if the symbol declares type parameters itself, then it will be a generic type declaration.
- If the parameter
- Parameters:
symbol
- Symbol for the type declarationisErased
- Whether the type should be consider erased, if it represents a class or interface type. This does not erase type variables, or array types for that matter.- Returns:
- A type, or null if the symbol is null
- If it represents a primitive type, the corresponding
-
rawType
LiketypeOf(JTypeDeclSymbol, boolean)
, defaulting the erased parameter to true. If the symbol is not generic, the returned symbol is not actually raw.- Parameters:
klass
- Symbol- Returns:
- An erased class type
-
declaration
LiketypeOf(JTypeDeclSymbol, boolean)
, defaulting the erased parameter to false. If the symbol is not generic, the returned symbol is not actually a generic type declaration.- Parameters:
klass
- Symbol- Returns:
- An erased class type
-
parameterise
public @NonNull JTypeMirror parameterise(@NonNull JClassSymbol klass, @NonNull List<? extends JTypeMirror> typeArgs) Produce a parameterized type with the given symbol and type arguments. The type argument list must match the declared formal type parameters in length. Non-generic symbols are accepted by this method, provided the argument list is empty. If the symbol is unresolved, any type argument list is accepted.This method is equivalent to
rawType(klass).withTypeArguments(typeArgs)
, but that code would require a cast.- Parameters:
klass
- A symboltypeArgs
- List of type arguments- Throws:
IllegalArgumentException
- seeJClassType.withTypeArguments(List)
-
arrayType
Creates a new array type from an arbitrary element type.arrayType(T, 0) = T arrayType(T, 1) = T[] arrayType(T, 3) = T[][][] arrayType(T[], 2) = T[][][]
- Parameters:
element
- Element typenumDimensions
- Number of dimensions- Returns:
- A new array type
- Throws:
IllegalArgumentException
- If numDimensions is negativeIllegalArgumentException
- If the element type is aJWildcardType
, the null type, orvoid
.NullPointerException
- If the element type is null
-
arrayType
LikearrayType(JTypeMirror, int)
, with one dimension.- Parameters:
component
- Component type- Returns:
- An array type
- Throws:
IllegalArgumentException
- If the element type is aJWildcardType
, the null type, orvoid
.NullPointerException
- If the element type is null
-
sigOf
-
sigOf
-
sigOf
-
sigOf
-
sigOf
-
wildcard
Builds a wildcard type with a single bound.wildcard(true, T) = ? extends T wildcard(false, T) = ? super T wildcard(true, OBJECT) = ?
- Parameters:
isUpperBound
- If true, this is an "extends" wildcard, otherwise a "super"bound
- Bound of the wildcard- Returns:
- A wildcard
- Throws:
NullPointerException
- If the bound is nullIllegalArgumentException
- If the bound is a primitive type, or a wildcard typeIllegalArgumentException
- If the bound is OBJECT and this is a lower-bounded wildcard (? super Object)
-
getPrimitive
Gets the primitive type identified by the given kind.- Parameters:
kind
- Kind of primitive type- Returns:
- A primitive type
- Throws:
NullPointerException
- if kind is null
-
lub
The least upper bound, or "lub", of a set of reference types is a shared supertype that is more specific than any other shared supertype (that is, no other shared supertype is a subtype of the least upper bound).- Throws:
IllegalArgumentException
- If types is emptyNullPointerException
- If types is null
-
glb
Returns the greatest lower bound of the given set of types. This is defined in JLS§5.1.10 (Capture Conversion):glb(V1,...,Vm) = V1 & ... & Vm glb(V) = V
This may alter the components, so that:
- No intersection type is a component:
((A & B) & C) = (A & (B & C)) = (A & B & C)
- No two types in the intersection are subtypes of one another
(the intersection is minimal):
A <: B => (A & B) = A
, in particular,(A & A) = A
- The intersection has a single component that is a
class, array, or type variable. If all components are interfaces,
then that component is
OBJECT
. - If several components are arrays, then their components
are intersected:
A[] & B[] = (A & B)[]
If after these transformations, only a single component remains, then that is the returned type. Otherwise a
JIntersectionType
is created. Note that the intersection may be unsatisfiable (egA[] & Runnable
), but we don't attempt to minimize this toNULL_TYPE
. Similarly, we do not attempt to minimize valid intersections. For instanceList<?> & Collection<Number>
can technically be minimized toList<Number>
, but doing this requires inference of a fitting parameterization in general, which is complex, and not necessary in the internal tasks where intersection types are useful. In fact intersection types are precisely useful because they are simple to build.See also JLS§4.9 (Intersection types).
- Throws:
IllegalArgumentException
- If some component is not a class, interface, array, or type variableIllegalArgumentException
- If there is more than one minimal class or array typeIllegalArgumentException
- If types is emptyNullPointerException
- If types is null
- No intersection type is a component:
-
newTypeVar
Returns a new type variable for the given symbol. This is only intended to be used by the implementor ofJTypeParameterSymbol
. -
logStats
public void logStats()Called at the end of the analysis to log statistics about the loaded types.
-