public class BaseTypeVisitor<Checker extends BaseTypeChecker> extends SourceVisitor<Void,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 Checker |
checker
The checker corresponding to this visitor.
|
protected Map<String,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,
CompilationUnitTree root) |
Modifier and Type | Method and Description |
---|---|
protected void |
checkAccess(IdentifierTree node,
Void p) |
protected void |
checkArguments(List<? extends 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(AnnotatedTypeMirror type,
List<? extends ExpressionTree> initializers) |
protected void |
checkAssignability(AnnotatedTypeMirror varType,
Tree varTree)
Tests, for a re-assignment, whether the variable is assignable or not.
|
protected boolean |
checkConstructorInvocation(AnnotatedTypeMirror.AnnotatedDeclaredType dt,
AnnotatedTypeMirror.AnnotatedExecutableType constructor,
Tree src) |
protected void |
checkDefaultConstructor(ClassTree node) |
protected void |
checkForAnnotatedJdk()
Warn if the annotated JDK is not being used.
|
protected void |
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(MethodTree overriderTree,
AnnotatedTypeMirror.AnnotatedDeclaredType enclosingType,
AnnotatedTypeMirror.AnnotatedExecutableType overridden,
AnnotatedTypeMirror.AnnotatedDeclaredType overriddenType,
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(Tree toptree,
List<? extends AnnotatedTypeMirror.AnnotatedTypeVariable> typevars,
List<? extends AnnotatedTypeMirror> typeargs,
List<? extends 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,
Void p) |
protected void |
checkTypecastSafety(TypeCastTree node,
Void p) |
protected void |
commonAssignmentCheck(AnnotatedTypeMirror varType,
AnnotatedTypeMirror valueType,
Tree valueTree,
@CompilerMessageKey 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(AnnotatedTypeMirror varType,
ExpressionTree valueExp,
@CompilerMessageKey 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(Tree varTree,
ExpressionTree valueExp,
@CompilerMessageKey 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 Tree |
enclosingStatement(Tree tree) |
protected boolean |
isAccessAllowed(Element field,
AnnotatedTypeMirror receiver,
ExpressionTree accessTree) |
protected boolean |
isAssignable(AnnotatedTypeMirror varType,
AnnotatedTypeMirror receiverType,
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 |
Void |
scan(Tree tree,
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 AnnotatedTypeMirror> params)
Type checks the method arguments of
Vector.copyInto() . |
boolean |
validateTypeOf(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.
|
Void |
visitAnnotation(AnnotationTree node,
Void p)
Ensure that the annotation arguments comply to their declarations.
|
Void |
visitArrayAccess(ArrayAccessTree node,
Void p) |
Void |
visitAssignment(AssignmentTree node,
Void p)
Performs two checks: subtyping and assignability checks, using
commonAssignmentCheck(Tree, ExpressionTree, String) . |
Void |
visitClass(ClassTree node,
Void p) |
Void |
visitCompilationUnit(CompilationUnitTree node,
Void p)
Override Compilation Unit so we won't visit package names or imports
|
Void |
visitCompoundAssignment(CompoundAssignmentTree node,
Void p)
Performs assignability check using
checkAssignability(AnnotatedTypeMirror, Tree) . |
Void |
visitConditionalExpression(ConditionalExpressionTree node,
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.
|
Void |
visitEnhancedForLoop(EnhancedForLoopTree node,
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.
|
Void |
visitIdentifier(IdentifierTree node,
Void p) |
Void |
visitInstanceOf(InstanceOfTree node,
Void p) |
Void |
visitMethod(MethodTree node,
Void p)
Performs pseudo-assignment check: checks that the method obeys override
and subtype rules to all overridden methods.
|
Void |
visitMethodInvocation(MethodInvocationTree node,
Void p)
Performs a method invocation check.
|
Void |
visitNewArray(NewArrayTree node,
Void p) |
Void |
visitNewClass(NewClassTree node,
Void p)
Performs a new class invocation check.
|
Void |
visitParameterizedType(ParameterizedTypeTree node,
Void p)
Do not override this method!
Previously, this method contained some logic, but the main modifier of types was missing.
|
Void |
visitReturn(ReturnTree node,
Void p)
Checks that the type of the return expression is a subtype of the
enclosing method required return type.
|
Void |
visitTypeCast(TypeCastTree node,
Void p) |
Void |
visitTypeParameter(TypeParameterTree node,
Void p) |
Void |
visitUnary(UnaryTree node,
Void p)
Performs assignability check using
checkAssignability(AnnotatedTypeMirror, Tree) . |
Void |
visitVariable(VariableTree node,
Void p) |
getCurrentPath, scan
reduce, scan, visitAnnotatedType, visitArrayType, visitAssert, visitBinary, visitBlock, visitBreak, visitCase, visitCatch, visitContinue, visitDoWhileLoop, visitEmptyStatement, visitErroneous, visitExpressionStatement, visitForLoop, visitIf, visitImport, visitIntersectionType, visitLabeledStatement, visitLambdaExpression, visitLiteral, visitMemberReference, visitMemberSelect, visitModifiers, visitOther, visitParenthesized, visitPrimitiveType, visitSwitch, visitSynchronized, visitThrow, visitTry, visitUnionType, visitWhileLoop, visitWildcard
protected final Checker extends BaseTypeChecker checker
protected final Map<String,String> options
protected final VisitorState visitorState
protected final BaseTypeVisitor.TypeValidator typeValidator
public BaseTypeVisitor(Checker checker, 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 Void visitClass(ClassTree node, Void p)
visitClass
in interface TreeVisitor<Void,Void>
visitClass
in class TreeScanner<Void,Void>
protected void checkDefaultConstructor(ClassTree node)
public Void visitMethod(MethodTree node, Void p)
visitMethod
in interface TreeVisitor<Void,Void>
visitMethod
in class TreeScanner<Void,Void>
public Void visitTypeParameter(TypeParameterTree node, Void p)
visitTypeParameter
in interface TreeVisitor<Void,Void>
visitTypeParameter
in class TreeScanner<Void,Void>
public Void visitVariable(VariableTree node, Void p)
visitVariable
in interface TreeVisitor<Void,Void>
visitVariable
in class TreeScanner<Void,Void>
public Void visitAssignment(AssignmentTree node, Void p)
commonAssignmentCheck(Tree, ExpressionTree, String)
.
If the subtype check fails, it issues a "assignment.type.incompatible" error.visitAssignment
in interface TreeVisitor<Void,Void>
visitAssignment
in class TreeScanner<Void,Void>
public Void visitEnhancedForLoop(EnhancedForLoopTree node, Void p)
visitEnhancedForLoop
in interface TreeVisitor<Void,Void>
visitEnhancedForLoop
in class TreeScanner<Void,Void>
public Void visitMethodInvocation(MethodInvocationTree node, Void p)
visitMethodInvocation
in interface TreeVisitor<Void,Void>
visitMethodInvocation
in class TreeScanner<Void,Void>
protected boolean isVectorCopyInto(AnnotatedTypeMirror.AnnotatedExecutableType method)
Vector.copyInto
protected void typeCheckVectorCopyIntoArgument(MethodInvocationTree node, List<? extends 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 Void visitNewClass(NewClassTree node, Void p)
visitNewClass
in interface TreeVisitor<Void,Void>
visitNewClass
in class TreeScanner<Void,Void>
public Void visitReturn(ReturnTree node, Void p)
visitReturn
in interface TreeVisitor<Void,Void>
visitReturn
in class TreeScanner<Void,Void>
public Void visitAnnotation(AnnotationTree node, Void p)
visitAnnotation
in interface TreeVisitor<Void,Void>
visitAnnotation
in class TreeScanner<Void,Void>
public Void visitConditionalExpression(ConditionalExpressionTree node, Void p)
visitConditionalExpression
in interface TreeVisitor<Void,Void>
visitConditionalExpression
in class TreeScanner<Void,Void>
public Void visitUnary(UnaryTree node, Void p)
checkAssignability(AnnotatedTypeMirror, Tree)
.visitUnary
in interface TreeVisitor<Void,Void>
visitUnary
in class TreeScanner<Void,Void>
public Void visitCompoundAssignment(CompoundAssignmentTree node, Void p)
checkAssignability(AnnotatedTypeMirror, Tree)
.visitCompoundAssignment
in interface TreeVisitor<Void,Void>
visitCompoundAssignment
in class TreeScanner<Void,Void>
public Void visitNewArray(NewArrayTree node, Void p)
visitNewArray
in interface TreeVisitor<Void,Void>
visitNewArray
in class TreeScanner<Void,Void>
public final Void visitParameterizedType(ParameterizedTypeTree node, Void p)
visitParameterizedType
in interface TreeVisitor<Void,Void>
visitParameterizedType
in class TreeScanner<Void,Void>
protected void checkTypecastRedundancy(TypeCastTree node, Void p)
protected void checkTypecastSafety(TypeCastTree node, Void p)
public Void visitTypeCast(TypeCastTree node, Void p)
visitTypeCast
in interface TreeVisitor<Void,Void>
visitTypeCast
in class TreeScanner<Void,Void>
public Void visitInstanceOf(InstanceOfTree node, Void p)
visitInstanceOf
in interface TreeVisitor<Void,Void>
visitInstanceOf
in class TreeScanner<Void,Void>
public Void visitArrayAccess(ArrayAccessTree node, Void p)
visitArrayAccess
in interface TreeVisitor<Void,Void>
visitArrayAccess
in class TreeScanner<Void,Void>
protected void commonAssignmentCheck(Tree varTree, ExpressionTree valueExp, @CompilerMessageKey String errorKey)
varTree
- the AST node for the variablevalueExp
- the AST node for the valueerrorKey
- the error message to use if the check fails (must be a
compiler message key, see CompilerMessageKey
)protected void commonAssignmentCheck(AnnotatedTypeMirror varType, ExpressionTree valueExp, @CompilerMessageKey String errorKey)
varType
- the annotated type of the variablevalueExp
- the AST node for the valueerrorKey
- the error message to use if the check fails (must be a
compiler message key, see CompilerMessageKey
)protected void commonAssignmentCheck(AnnotatedTypeMirror varType, AnnotatedTypeMirror valueType, Tree valueTree, @CompilerMessageKey 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 fails (must be a
compiler message key, see CompilerMessageKey
)protected void checkArrayInitialization(AnnotatedTypeMirror type, List<? extends ExpressionTree> initializers)
protected void checkTypeArguments(Tree toptree, List<? extends AnnotatedTypeMirror.AnnotatedTypeVariable> typevars, List<? extends AnnotatedTypeMirror> typeargs, List<? extends 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 void 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, Tree src)
protected void checkArguments(List<? extends AnnotatedTypeMirror> requiredArgs, List<? extends ExpressionTree> passedArgs)
requiredArgs
- the required typespassedArgs
- the expressions passed to the corresponding typesprotected boolean checkOverride(MethodTree overriderTree, AnnotatedTypeMirror.AnnotatedDeclaredType enclosingType, AnnotatedTypeMirror.AnnotatedExecutableType overridden, AnnotatedTypeMirror.AnnotatedDeclaredType overriddenType, 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(AnnotatedTypeMirror varType, Tree varTree)
varType
- the type of the variable being re-assignedvarTree
- the tree used to access the variable in the assignmentprotected boolean isAssignable(AnnotatedTypeMirror varType, AnnotatedTypeMirror receiverType, Tree variable)
varType
- the annotated variable typevariable
- tree used to access the variableprotected MemberSelectTree enclosingMemberSelect()
public Void visitIdentifier(IdentifierTree node, Void p)
visitIdentifier
in interface TreeVisitor<Void,Void>
visitIdentifier
in class TreeScanner<Void,Void>
protected void checkAccess(IdentifierTree node, Void p)
protected boolean isAccessAllowed(Element field, 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(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 Void visitCompilationUnit(CompilationUnitTree node, Void p)
visitCompilationUnit
in interface TreeVisitor<Void,Void>
visitCompilationUnit
in class TreeScanner<Void,Void>
protected void checkForAnnotatedJdk()