public class BaseTypeVisitor<Checker extends BaseTypeChecker> extends SourceVisitor<@Nullable Void,@Nullable Void>
SourceVisitor
that performs assignment and pseudo-assignment
checking, method invocation checking, and assignability checking.
This implementation uses the AnnotatedTypeFactory
implementation
provided by an associated BaseTypeChecker
; its visitor methods will
invoke this factory on parts of the AST to determine the "annotated type" of
an expression. Then, the visitor methods will check the types in assignments
and pseudo-assignments using commonAssignmentCheck(com.sun.source.tree.Tree, com.sun.source.tree.ExpressionTree, java.lang.String)
, which
ultimately calls the BaseTypeChecker#isSubtype
method and reports
errors that violate Java's rules of assignment.
Note that since this implementation only performs assignment and
pseudo-assignment checking, other rules for custom type systems must be added
in subclasses (e.g., dereference checking in the NullnessChecker
is
implemented in the NullnessChecker
's
TreeScanner.visitMemberSelect(com.sun.source.tree.MemberSelectTree, P)
method).
This implementation does the following checks:
1. Assignment and Pseudo-Assignment Check:
It verifies that any assignment type check, using
Checker.isSubtype
method. This includes method invocation and
method overriding checks.
2. Type Validity Check:
It verifies that any user-supplied type is a valid type, using
isValidUse
method.
3. (Re-)Assignability Check:
It verifies that any assignment is valid, using
Checker.isAssignable
method.
BaseTypeChecker#isSubtype(AnnotatedTypeMirror, AnnotatedTypeMirror)
,
AnnotatedTypeFactory
Modifier and Type | Class and Description |
---|---|
protected class |
BaseTypeVisitor.TypeValidator |
Modifier and Type | Field and Description |
---|---|
protected AnnotationUtils |
annoFactory
The annotation factory to use for creating annotations.
|
protected AnnotatedTypes |
annoTypes
utilities class for annotated types
|
protected Checker |
checker
The checker corresponding to this visitor.
|
protected Map<@ReadOnly String,@ReadOnly String> |
options
The options that were provided to the checker using this visitor.
|
protected BaseTypeVisitor.TypeValidator |
typeValidator |
protected VisitorState |
visitorState
For storing visitor state
|
atypeFactory, elements, root, trees, types
Constructor and Description |
---|
BaseTypeVisitor(Checker checker,
@Nullable CompilationUnitTree root) |
Modifier and Type | Method and Description |
---|---|
protected void |
checkAccess(IdentifierTree node,
@Nullable Void p) |
protected void |
checkArguments(List<? extends @Mutable AnnotatedTypeMirror> requiredArgs,
List<? extends ExpressionTree> passedArgs)
A helper method to check that each passed argument is a subtype of the
corresponding required argument, and issues "argument.invalid" error
for each passed argument that not a subtype of the required one.
|
protected void |
checkArrayInitialization(@Mutable AnnotatedTypeMirror type,
List<? extends ExpressionTree> initializers) |
protected void |
checkAssignability(@Mutable AnnotatedTypeMirror varType,
@Nullable Tree varTree)
Tests, for a re-assignment, whether the variable is assignable or not.
|
protected boolean |
checkConstructorInvocation(AnnotatedTypeMirror.AnnotatedDeclaredType dt,
AnnotatedTypeMirror.AnnotatedExecutableType constructor,
@Nullable Tree src) |
protected void |
checkDefaultConstructor(@Nullable ClassTree node) |
protected void |
checkForAnnotatedJdk()
Warn if the annotated JDK is not being used.
|
protected boolean |
checkMethodInvocability(AnnotatedTypeMirror.AnnotatedExecutableType method,
MethodInvocationTree node)
Tests whether the method can be invoked using the receiver of the 'node'
method invocation, and issues a "method.invocation.invalid" if the
invocation is invalid.
|
protected boolean |
checkOverride(@Nullable MethodTree overriderTree,
AnnotatedTypeMirror.AnnotatedDeclaredType enclosingType,
AnnotatedTypeMirror.AnnotatedExecutableType overridden,
AnnotatedTypeMirror.AnnotatedDeclaredType overriddenType,
@Nullable Void p)
Checks that an overriding method's return type, parameter types, and
receiver type are correct with respect to the annotations on the
overridden method's return type, parameter types, and receiver type.
|
protected void |
checkTypeArguments(@Nullable Tree toptree,
List<? extends AnnotatedTypeMirror.AnnotatedTypeVariable> typevars,
List<? extends @Mutable AnnotatedTypeMirror> typeargs,
List<? extends @Nullable Tree> typeargTrees)
Checks that the annotations on the type arguments supplied to a type or a
method invocation are within the bounds of the type variables as
declared, and issues the "generic.argument.invalid" error if they are
not.
|
protected void |
checkTypecastRedundancy(TypeCastTree node,
@Nullable Void p) |
protected void |
checkTypecastSafety(TypeCastTree node,
@Nullable Void p) |
protected void |
commonAssignmentCheck(@Mutable AnnotatedTypeMirror varType,
@Mutable AnnotatedTypeMirror valueType,
@Nullable Tree valueTree,
@ReadOnly String errorKey)
Checks the validity of an assignment (or pseudo-assignment) from a value
to a variable and emits an error message (through the compiler's
messaging interface) if it is not valid.
|
protected void |
commonAssignmentCheck(@Mutable AnnotatedTypeMirror varType,
ExpressionTree valueExp,
@ReadOnly String errorKey)
Checks the validity of an assignment (or pseudo-assignment) from a value
to a variable and emits an error message (through the compiler's
messaging interface) if it is not valid.
|
protected void |
commonAssignmentCheck(@Nullable Tree varTree,
ExpressionTree valueExp,
@ReadOnly String errorKey)
Checks the validity of an assignment (or pseudo-assignment) from a value
to a variable and emits an error message (through the compiler's
messaging interface) if it is not valid.
|
protected BaseTypeVisitor.TypeValidator |
createTypeValidator() |
protected MemberSelectTree |
enclosingMemberSelect() |
protected @Nullable Tree |
enclosingStatement(@Nullable Tree tree) |
protected boolean |
isAccessAllowed(@Nullable Element field,
@Mutable AnnotatedTypeMirror receiver,
ExpressionTree accessTree) |
protected boolean |
isAssignable(@Mutable AnnotatedTypeMirror varType,
@Mutable AnnotatedTypeMirror receiverType,
@Nullable Tree variable)
Tests whether the variable accessed is an assignable variable or not,
given the current scope
TODO: document which parameters are nullable; e.g.
|
boolean |
isValidUse(AnnotatedTypeMirror.AnnotatedArrayType type)
Tests that the qualifiers present on the array type are valid.
|
boolean |
isValidUse(AnnotatedTypeMirror.AnnotatedDeclaredType declarationType,
AnnotatedTypeMirror.AnnotatedDeclaredType useType)
Tests that the qualifiers present on the useType are valid qualifiers,
given the qualifiers on the declaration of the type, declarationType.
|
boolean |
isValidUse(AnnotatedTypeMirror.AnnotatedPrimitiveType type)
Tests that the qualifiers present on the primitive type are valid.
|
protected boolean |
isVectorCopyInto(AnnotatedTypeMirror.AnnotatedExecutableType method)
Returns true if the method symbol represents
Vector.copyInto |
@Nullable Void |
scan(@Nullable Tree tree,
@Nullable Void p) |
protected boolean |
shouldSkipUses(ExpressionTree exprTree)
Tests whether the expression should not be checked because of the tree
referring to unannotated classes, as specified in
the
checker.skipUses property. |
protected void |
typeCheckVectorCopyIntoArgument(MethodInvocationTree node,
List<? extends @Mutable AnnotatedTypeMirror> params)
Type checks the method arguments of
Vector.copyInto() . |
boolean |
validateTypeOf(@Nullable Tree tree)
Tests whether the tree expressed by the passed type tree is a valid type,
and emits an error if that is not the case (e.g.
|
@Nullable Void |
visitAnnotation(AnnotationTree node,
@Nullable Void p)
Ensure that the annotation arguments comply to their declarations.
|
@Nullable Void |
visitArrayAccess(ArrayAccessTree node,
@Nullable Void p) |
@Nullable Void |
visitAssignment(AssignmentTree node,
@Nullable Void p)
Performs two checks: subtyping and assignability checks, using
commonAssignmentCheck(Tree, ExpressionTree, String) . |
@Nullable Void |
visitClass(@Nullable ClassTree node,
@Nullable Void p) |
@Nullable Void |
visitCompilationUnit(@Nullable CompilationUnitTree node,
@Nullable Void p)
Override Compilation Unit so we won't visit package names or imports
|
@Nullable Void |
visitCompoundAssignment(CompoundAssignmentTree node,
@Nullable Void p)
Performs assignability check using
checkAssignability(AnnotatedTypeMirror, Tree) . |
@Nullable Void |
visitConditionalExpression(ConditionalExpressionTree node,
@Nullable Void p)
If the computation of the type of the ConditionalExpressionTree in
checkers.types.TypeFromTree.TypeFromExpression.visitConditionalExpression(ConditionalExpressionTree, AnnotatedTypeFactory)
is correct, the following checks are redundant.
|
@Nullable Void |
visitEnhancedForLoop(EnhancedForLoopTree node,
@Nullable Void p)
Performs a subtype check, to test whether the node expression
iterable type is a subtype of the variable type in the enhanced for
loop.
|
@Nullable Void |
visitIdentifier(IdentifierTree node,
@Nullable Void p) |
@Nullable Void |
visitInstanceOf(InstanceOfTree node,
@Nullable Void p) |
@Nullable Void |
visitMethod(@Nullable MethodTree node,
@Nullable Void p)
Performs pseudo-assignment check: checks that the method obeys override
and subtype rules to all overridden methods.
|
@Nullable Void |
visitMethodInvocation(MethodInvocationTree node,
@Nullable Void p)
Performs a method invocation check.
|
@Nullable Void |
visitNewArray(NewArrayTree node,
@Nullable Void p) |
@Nullable Void |
visitNewClass(NewClassTree node,
@Nullable Void p)
Performs a new class invocation check.
|
@Nullable Void |
visitParameterizedType(ParameterizedTypeTree node,
@Nullable Void p)
Do not override this method!
Previously, this method contained some logic, but the main modifier of types was missing.
|
@Nullable Void |
visitReturn(ReturnTree node,
@Nullable Void p)
Checks that the type of the return expression is a subtype of the
enclosing method required return type.
|
@Nullable Void |
visitTypeCast(TypeCastTree node,
@Nullable Void p) |
@Nullable Void |
visitTypeParameter(TypeParameterTree node,
@Nullable Void p) |
@Nullable Void |
visitUnary(UnaryTree node,
@Nullable Void p)
Performs assignability check using
checkAssignability(AnnotatedTypeMirror, Tree) . |
@Nullable Void |
visitVariable(VariableTree node,
@Nullable Void p) |
getCurrentPath, scan
reduce, scan, visitAnnotatedType, visitArrayType, visitAssert, visitBinary, visitBlock, visitBreak, visitCase, visitCatch, visitContinue, visitDoWhileLoop, visitEmptyStatement, visitErroneous, visitExpressionStatement, visitForLoop, visitIf, visitImport, visitLabeledStatement, visitLambdaExpression, visitLiteral, visitMemberReference, visitMemberSelect, visitModifiers, visitOther, visitParenthesized, visitPrimitiveType, visitSwitch, visitSynchronized, visitThrow, visitTry, visitUnionType, visitWhileLoop, visitWildcard
protected final Checker extends BaseTypeChecker checker
protected final AnnotationUtils annoFactory
protected final Map<@ReadOnly String,@ReadOnly String> options
protected final AnnotatedTypes annoTypes
protected final VisitorState visitorState
protected final BaseTypeVisitor.TypeValidator typeValidator
public BaseTypeVisitor(Checker checker, @Nullable CompilationUnitTree root)
checker
- the typechecker associated with this visitor (for
callbacks to BaseTypeChecker#isSubtype
)root
- the root of the AST that this visitor operates onpublic @Nullable Void visitClass(@Nullable ClassTree node, @Nullable Void p)
visitClass
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitClass
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitMethod(@Nullable MethodTree node, @Nullable Void p)
visitMethod
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitMethod
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitTypeParameter(TypeParameterTree node, @Nullable Void p)
visitTypeParameter
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitTypeParameter
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitVariable(VariableTree node, @Nullable Void p)
visitVariable
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitVariable
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitAssignment(AssignmentTree node, @Nullable Void p)
commonAssignmentCheck(Tree, ExpressionTree, String)
.
If the subtype check fails, it issues a "assignment.type.incompatible" error.visitAssignment
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitAssignment
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitEnhancedForLoop(EnhancedForLoopTree node, @Nullable Void p)
visitEnhancedForLoop
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitEnhancedForLoop
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitMethodInvocation(MethodInvocationTree node, @Nullable Void p)
visitMethodInvocation
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitMethodInvocation
in class TreeScanner<@Nullable Void,@Nullable Void>
protected boolean isVectorCopyInto(AnnotatedTypeMirror.AnnotatedExecutableType method)
Vector.copyInto
protected void typeCheckVectorCopyIntoArgument(MethodInvocationTree node, List<? extends @Mutable AnnotatedTypeMirror> params)
Vector.copyInto()
.
The Checker Framework special-cases the method invocation, as it is
type safety cannot be expressed by Java's type system.
For a Vector v
of type Vectory<E>
, the method
invocation v.copyInto(arr)
is type-safe iff arr
is a array of type T[]
, where T
is a subtype of
E
.
In other words, this method checks that the type argument of the
receiver method is a subtype of the component type of the passed array
argument.node
- a method invocation of Vector.copyInto()
params
- the types of the parameters of Vectory.copyInto()
public @Nullable Void visitNewClass(NewClassTree node, @Nullable Void p)
visitNewClass
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitNewClass
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitReturn(ReturnTree node, @Nullable Void p)
visitReturn
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitReturn
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitAnnotation(AnnotationTree node, @Nullable Void p)
visitAnnotation
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitAnnotation
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitConditionalExpression(ConditionalExpressionTree node, @Nullable Void p)
visitConditionalExpression
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitConditionalExpression
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitUnary(UnaryTree node, @Nullable Void p)
checkAssignability(AnnotatedTypeMirror, Tree)
.visitUnary
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitUnary
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitCompoundAssignment(CompoundAssignmentTree node, @Nullable Void p)
checkAssignability(AnnotatedTypeMirror, Tree)
.visitCompoundAssignment
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitCompoundAssignment
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitNewArray(NewArrayTree node, @Nullable Void p)
visitNewArray
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitNewArray
in class TreeScanner<@Nullable Void,@Nullable Void>
public final @Nullable Void visitParameterizedType(ParameterizedTypeTree node, @Nullable Void p)
visitParameterizedType
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitParameterizedType
in class TreeScanner<@Nullable Void,@Nullable Void>
protected void checkTypecastRedundancy(TypeCastTree node, @Nullable Void p)
protected void checkTypecastSafety(TypeCastTree node, @Nullable Void p)
public @Nullable Void visitTypeCast(TypeCastTree node, @Nullable Void p)
visitTypeCast
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitTypeCast
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitInstanceOf(InstanceOfTree node, @Nullable Void p)
visitInstanceOf
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitInstanceOf
in class TreeScanner<@Nullable Void,@Nullable Void>
public @Nullable Void visitArrayAccess(ArrayAccessTree node, @Nullable Void p)
visitArrayAccess
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitArrayAccess
in class TreeScanner<@Nullable Void,@Nullable Void>
protected void commonAssignmentCheck(@Nullable Tree varTree, ExpressionTree valueExp, @ReadOnly String errorKey)
varTree
- the AST node for the variablevalueExp
- the AST node for the valueerrorKey
- the error message to use if the check failsprotected void commonAssignmentCheck(@Mutable AnnotatedTypeMirror varType, ExpressionTree valueExp, @ReadOnly String errorKey)
varType
- the annotated type of the variablevalueExp
- the AST node for the valueerrorKey
- the error message to use if the check failsprotected void commonAssignmentCheck(@Mutable AnnotatedTypeMirror varType, @Mutable AnnotatedTypeMirror valueType, @Nullable Tree valueTree, @ReadOnly String errorKey)
varType
- the annotated type of the variablevalueType
- the annotated type of the valuevalueTree
- the location to use when reporting the error messageerrorKey
- the error message to use if the check failsprotected void checkArrayInitialization(@Mutable AnnotatedTypeMirror type, List<? extends ExpressionTree> initializers)
protected void checkTypeArguments(@Nullable Tree toptree, List<? extends AnnotatedTypeMirror.AnnotatedTypeVariable> typevars, List<? extends @Mutable AnnotatedTypeMirror> typeargs, List<? extends @Nullable Tree> typeargTrees)
toptree
- the tree for error reporting, only used for inferred type argumentstypevars
- the type variables from a class or method declarationtypeargs
- the type arguments from the type or method invocationtypeargTrees
- the type arguments as trees, used for error reportingprotected boolean checkMethodInvocability(AnnotatedTypeMirror.AnnotatedExecutableType method, MethodInvocationTree node)
method
- the type of the invoked methodnode
- the method invocation nodeprotected boolean checkConstructorInvocation(AnnotatedTypeMirror.AnnotatedDeclaredType dt, AnnotatedTypeMirror.AnnotatedExecutableType constructor, @Nullable Tree src)
protected void checkArguments(List<? extends @Mutable AnnotatedTypeMirror> requiredArgs, List<? extends ExpressionTree> passedArgs)
requiredArgs
- the required typespassedArgs
- the expressions passed to the corresponding typesprotected boolean checkOverride(@Nullable MethodTree overriderTree, AnnotatedTypeMirror.AnnotatedDeclaredType enclosingType, AnnotatedTypeMirror.AnnotatedExecutableType overridden, AnnotatedTypeMirror.AnnotatedDeclaredType overriddenType, @Nullable Void p)
This method returns the result of the check, but also emits error messages as a side effect.
overriderTree
- the AST node of the overriding methodenclosingType
- the declared type enclosing the overrider methodoverridden
- the type of the overridden methodoverriddenType
- the declared type enclosing the overridden methodp
- an optional parameter (as supplied to visitor methods)protected void checkAssignability(@Mutable AnnotatedTypeMirror varType, @Nullable Tree varTree)
varType
- the type of the variable being re-assignedvarTree
- the tree used to access the variable in the assignmentprotected boolean isAssignable(@Mutable AnnotatedTypeMirror varType, @Mutable AnnotatedTypeMirror receiverType, @Nullable Tree variable)
varType
- the annotated variable typevariable
- tree used to access the variableprotected MemberSelectTree enclosingMemberSelect()
public @Nullable Void visitIdentifier(IdentifierTree node, @Nullable Void p)
visitIdentifier
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitIdentifier
in class TreeScanner<@Nullable Void,@Nullable Void>
protected void checkAccess(IdentifierTree node, @Nullable Void p)
protected boolean isAccessAllowed(@Nullable Element field, @Mutable AnnotatedTypeMirror receiver, ExpressionTree accessTree)
public boolean isValidUse(AnnotatedTypeMirror.AnnotatedDeclaredType declarationType, AnnotatedTypeMirror.AnnotatedDeclaredType useType)
The check is shallow, as it does not descend into generic or array
types (i.e. only performing the validity check on the raw type or
outermost array dimension). validateTypeOf(Tree)
would call this for each type argument or array dimension separately.
For instance, in the IGJ type system, a @Mutable
is an invalid
qualifier for String
, as String
is declared as
@Immutable String
.
In most cases, useType
simply needs to be a subtype of
declarationType
, but there are exceptions. In IGJ, a variable may be
declared @ReadOnly String
, even though String
is
@Immutable String
; ReadOnly
is not a subtype of
Immutable
.
declarationType
- the type of the class (TypeElement)useType
- the use of the class (instance type)public boolean isValidUse(AnnotatedTypeMirror.AnnotatedPrimitiveType type)
public boolean isValidUse(AnnotatedTypeMirror.AnnotatedArrayType type)
public boolean validateTypeOf(@Nullable Tree tree)
tree
- the AST type supplied by the userprotected BaseTypeVisitor.TypeValidator createTypeValidator()
protected final boolean shouldSkipUses(ExpressionTree exprTree)
checker.skipUses
property.
It returns true if exprTree is a method invocation or a field access
to a class whose qualified name matches @{link checker.skipUses}
expression.exprTree
- any expression treepublic @Nullable Void visitCompilationUnit(@Nullable CompilationUnitTree node, @Nullable Void p)
visitCompilationUnit
in interface TreeVisitor<@Nullable Void,@Nullable Void>
visitCompilationUnit
in class TreeScanner<@Nullable Void,@Nullable Void>
protected void checkForAnnotatedJdk()