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, scanreduce, 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, visitWildcardprotected 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.copyIntoprotected 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()