Class TypeSystem
- java.lang.Object
-
- net.sourceforge.pmd.lang.java.types.TypeSystem
-
public final class TypeSystem extends Object
Root context object for type analysis. Type systems own a globalSymbolResolver
, which creates and caches external symbols. Methods of this class promote symbols to types, and compose types together.TypeOps
andTypeConversion
have some more operations on types.Some special types are presented as constant fields, eg
OBJECT
orNULL_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 thebox
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
Fields Modifier and Type Field Description Set<JPrimitiveType>
allPrimitives
The set of all primitive types.JPrimitiveType
BOOLEAN
Primitive typeboolean
.JClassType
BOXED_VOID
This is the boxed type ofVoid.class
, not to be confused withvoid.class
, which in this framework is represented byNO_TYPE
.JPrimitiveType
BYTE
Primitive typebyte
.JPrimitiveType
CHAR
Primitive typechar
.JClassType
CLONEABLE
The interface Cloneable.JPrimitiveType
DOUBLE
Primitive typedouble
.JTypeMirror
ERROR
A constant to represent a typing error.JPrimitiveType
FLOAT
Primitive typefloat
.JPrimitiveType
INT
Primitive typeint
.JPrimitiveType
LONG
Primitive typelong
.JTypeMirror
NO_TYPE
A constant to represent the normal absence of a type.JTypeMirror
NULL_TYPE
The bottom type of the reference type system.JClassType
OBJECT
Top type of the reference type system.JClassType
SERIALIZABLE
The interface Serializable.JPrimitiveType
SHORT
Primitive typeshort
.JWildcardType
UNBOUNDED_WILD
The unbounded wildcard, "?".JTypeMirror
UNKNOWN
A constant to represent an unresolved type.JMethodSig
UNRESOLVED_METHOD
Sentinel value for an unresolved method.
-
Constructor Summary
Constructors Constructor Description TypeSystem(Function<TypeSystem,? extends SymbolResolver> symResolverMaker)
Builds a new type system.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description JArrayType
arrayType(@NonNull JTypeMirror component)
LikearrayType(JTypeMirror, int)
, with one dimension.JTypeMirror
arrayType(@NonNull JTypeMirror element, int numDimensions)
Creates a new array type from an arbitrary element type.SymbolResolver
bootstrapResolver()
Returns the bootstrap symbol resolver.JTypeMirror
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.JTypeMirror
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.JTypeMirror
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).JTypeVar
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.JTypeMirror
rawType(@Nullable JTypeDeclSymbol klass)
LiketypeOf(JTypeDeclSymbol, boolean)
, defaulting the erased parameter to true.JMethodSig
sigOf(JExecutableSymbol methodSym)
JMethodSig
sigOf(JExecutableSymbol methodSym, Substitution subst)
JVariableSig
sigOf(JClassType decl, JFormalParamSymbol fieldSym)
JVariableSig
sigOf(JClassType decl, JLocalVariableSymbol fieldSym)
JVariableSig.FieldSig
sigOf(JTypeMirror decl, JFieldSymbol fieldSym)
JTypeMirror
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.JWildcardType
wildcard(boolean isUpperBound, @NonNull JTypeMirror bound)
Builds a wildcard type with a single bound.
-
-
-
Field Detail
-
OBJECT
public final JClassType 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
public final JTypeMirror 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
public final JPrimitiveType BOOLEAN
Primitive typeboolean
.
-
CHAR
public final JPrimitiveType CHAR
Primitive typechar
.
-
BYTE
public final JPrimitiveType BYTE
Primitive typebyte
.
-
SHORT
public final JPrimitiveType SHORT
Primitive typeshort
.
-
INT
public final JPrimitiveType INT
Primitive typeint
.
-
LONG
public final JPrimitiveType LONG
Primitive typelong
.
-
FLOAT
public final JPrimitiveType FLOAT
Primitive typefloat
.
-
DOUBLE
public final JPrimitiveType DOUBLE
Primitive typedouble
.
-
allPrimitives
public final Set<JPrimitiveType> allPrimitives
The set of all primitive types. SeegetPrimitive(PrimitiveTypeKind)
.
-
NO_TYPE
public final JTypeMirror 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
public final JTypeMirror 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
public final JTypeMirror 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
public final JMethodSig UNRESOLVED_METHOD
-
UNBOUNDED_WILD
public final JWildcardType UNBOUNDED_WILD
The unbounded wildcard, "?".
-
CLONEABLE
public final JClassType CLONEABLE
The interface Cloneable. This is included because it is a supertype of array types.
-
SERIALIZABLE
public final JClassType SERIALIZABLE
The interface Serializable. This is included because it is a supertype of array types.
-
BOXED_VOID
public final JClassType 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 Detail
-
TypeSystem
public TypeSystem(Function<TypeSystem,? extends SymbolResolver> symResolverMaker)
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 Detail
-
usingClassLoaderClasspath
public static TypeSystem usingClassLoaderClasspath(ClassLoader bootstrapResourceLoader)
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
public SymbolResolver bootstrapResolver()
Returns the bootstrap symbol resolver. Concrete analysis passes may decorate this with different resolvers.
-
getClassSymbol
public @Nullable JClassSymbol getClassSymbol(@Nullable Class<?> clazz)
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
public @Nullable JClassSymbol getClassSymbol(String binaryName)
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
public @Nullable JClassSymbol getClassSymbolFromCanonicalName(String canonicalName)
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
public @Nullable JModuleSymbol getModuleSymbol(String moduleName)
- Since:
- 7.5.0
-
typeOf
public JTypeMirror typeOf(@Nullable JTypeDeclSymbol symbol, boolean isErased)
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
public JTypeMirror rawType(@Nullable JTypeDeclSymbol klass)
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
public JTypeMirror declaration(@Nullable JClassSymbol klass)
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
public JTypeMirror arrayType(@NonNull JTypeMirror element, int numDimensions)
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
public JArrayType arrayType(@NonNull JTypeMirror component)
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
public JMethodSig sigOf(JExecutableSymbol methodSym)
-
sigOf
public JMethodSig sigOf(JExecutableSymbol methodSym, Substitution subst)
-
sigOf
public JVariableSig.FieldSig sigOf(JTypeMirror decl, JFieldSymbol fieldSym)
-
sigOf
public JVariableSig sigOf(JClassType decl, JLocalVariableSymbol fieldSym)
-
sigOf
public JVariableSig sigOf(JClassType decl, JFormalParamSymbol fieldSym)
-
wildcard
public JWildcardType wildcard(boolean isUpperBound, @NonNull JTypeMirror bound)
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
public @NonNull JPrimitiveType getPrimitive(@NonNull JPrimitiveType.PrimitiveTypeKind kind)
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
public JTypeMirror 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).- Throws:
IllegalArgumentException
- If types is emptyNullPointerException
- If types is null
-
glb
public JTypeMirror glb(Collection<? extends JTypeMirror> types)
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
public JTypeVar newTypeVar(JTypeParameterSymbol symbol)
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.
-
-