public class TypeAnalyzer
extends org.eclipse.jdt.core.dom.ASTVisitor
This analyzer does a depth-first traversal on the given AST. It tries to assign a type to every expression and sub-expression node a type according to the Java 1.5 semantics (but it is also backward compatible with Java 1.4). This type information can be used later to decide the behavior of each method call and field access.
When other classes are referenced in the AST, this analyzer tries to
load them with the Java reflection mechanism. Once loaded, their names
are assigned to the corresponding nodes as their types. This analyzer
uses LocalClassLoader
to simulate loading a class with its
partial name within another class.
This analyzer assumes that the classes being analyzed (including those classes indirectly referred to) have been compiled with the Java compiler. It does not check for type errors in the AST, but it mimics the typing semantics of the Java compiler.
Red (tfeng) |
Red (tfeng) |
Constructor and Description |
---|
TypeAnalyzer()
Construct an analyzer with no explicit class path for its
class loader (an instanceof
LocalClassLoader ). |
TypeAnalyzer(java.lang.String[] classPaths)
Construct an analyzer with with an array of explicit class
paths for its class loader (an instanceof
LocalClassLoader ). |
Modifier and Type | Method and Description |
---|---|
protected ptolemy.backtrack.eclipse.ast.TypeAnalyzer.TypeAndOwner |
_getFieldTypeAndOwner(java.lang.Class c,
java.lang.String name)
Get the type of a field in a class by its name.
|
protected Type |
_getMethodType(java.lang.Class c,
java.lang.String name,
Type[] args)
Get the type of a method in a class by its name and types of
actural arguments.
|
protected static void |
_sortBodyDeclarations(org.eclipse.jdt.core.dom.AbstractTypeDeclaration node)
Sort the body declarations of an abstract type declaration.
|
protected static void |
_sortBodyDeclarations(org.eclipse.jdt.core.dom.AnonymousClassDeclaration node)
Sort the body declarations of an anonymous class declaration.
|
void |
addCrossAnalyzedType(java.lang.String fullName)
Add a name of a type to the set of types to be cross-analyzed.
|
void |
addCrossAnalyzedTypes(java.lang.String[] fullNames)
Add an array of names of types to the set of types to be
cross-analyzed.
|
void |
endVisit(org.eclipse.jdt.core.dom.AnonymousClassDeclaration node)
End the visit of an anonymous class declaration and close its
scope.
|
void |
endVisit(org.eclipse.jdt.core.dom.ArrayAccess node)
Visit an array access node and set its type to be the type with one
less dimension.
|
void |
endVisit(org.eclipse.jdt.core.dom.ArrayCreation node)
Propagate the type of the array to this node.
|
void |
endVisit(org.eclipse.jdt.core.dom.ArrayType node)
Visit an array type node and set its type to be the type with one
more dimension than its component type.
|
void |
endVisit(org.eclipse.jdt.core.dom.Assignment node)
Propagate the type of the left-hand side of the assignment
to this node.
|
void |
endVisit(org.eclipse.jdt.core.dom.Block node)
End the visit of a block node and close the scope opened by the
previous visit function.
|
void |
endVisit(org.eclipse.jdt.core.dom.BooleanLiteral node)
Visit a literal node and set its type to be the same type as the
literal.
|
void |
endVisit(org.eclipse.jdt.core.dom.CastExpression node)
Propagate the type of the cast class to this node.
|
void |
endVisit(org.eclipse.jdt.core.dom.CharacterLiteral node)
Visit a literal node and set its type to be the same type as the
literal.
|
void |
endVisit(org.eclipse.jdt.core.dom.ClassInstanceCreation node)
Propagate the type of the instantiated class to this node.
|
void |
endVisit(org.eclipse.jdt.core.dom.ConditionalExpression node)
Visit a conditional expression node and set its type to be
the type that is compatible with both the then expression and
the else expression.
|
void |
endVisit(org.eclipse.jdt.core.dom.EnhancedForStatement node)
End the visit of an enhanced for statement and close the scope
opened by the previous visit function.
|
void |
endVisit(org.eclipse.jdt.core.dom.FieldAccess node)
Visit a field access node, resolve it in the current scope, and set
its type to be the type of field referred to.
|
void |
endVisit(org.eclipse.jdt.core.dom.FieldDeclaration node)
Visit a field declaration and set its type to be the same as the
declared type.
|
void |
endVisit(org.eclipse.jdt.core.dom.ForStatement node)
End the visit of a for statement and close the scope opened by
the previous visit function.
|
void |
endVisit(org.eclipse.jdt.core.dom.ImportDeclaration node)
End the visit of an importation declaration and record the
imported class or package in the class loader.
|
void |
endVisit(org.eclipse.jdt.core.dom.InfixExpression node)
Visit an infix expression and compute the type for it.
|
void |
endVisit(org.eclipse.jdt.core.dom.InstanceofExpression node)
Visit an instanceof expression and set its type to
be boolean.
|
void |
endVisit(org.eclipse.jdt.core.dom.MethodDeclaration node)
End the visit of a method declaration and close the scope
opened by the previous visit function.
|
void |
endVisit(org.eclipse.jdt.core.dom.MethodInvocation node)
Visit a method invocation node and resolve the invoked method.
|
void |
endVisit(org.eclipse.jdt.core.dom.NullLiteral node)
Visit a literal node and set its type to be the same type as the
literal.
|
void |
endVisit(org.eclipse.jdt.core.dom.NumberLiteral node)
Visit a literal node and set its type to be the same type as the
literal.
|
void |
endVisit(org.eclipse.jdt.core.dom.PackageDeclaration node)
End the visit of a package declaration and set the current package
to be the full name of that declared package.
|
void |
endVisit(org.eclipse.jdt.core.dom.ParameterizedType node)
Visit a parameterized type and set its type to be the base type.
|
void |
endVisit(org.eclipse.jdt.core.dom.ParenthesizedExpression node)
Propagate the type of the expression between the parentheses
to this node.
|
void |
endVisit(org.eclipse.jdt.core.dom.PostfixExpression node)
Propagate the type of the its sub-expression to this node.
|
void |
endVisit(org.eclipse.jdt.core.dom.PrefixExpression node)
Propagate the type of the its sub-expression to this node.
|
void |
endVisit(org.eclipse.jdt.core.dom.PrimitiveType node)
Visit a primitive type node and set its type to be the corresponding
primitive type.
|
void |
endVisit(org.eclipse.jdt.core.dom.QualifiedName node)
Visit a qualified name, resolve it in the current scope, and set
its type to be the type of object referred to by that name.
|
void |
endVisit(org.eclipse.jdt.core.dom.ReturnStatement node)
Visit a return statement.
|
void |
endVisit(org.eclipse.jdt.core.dom.SimpleName node)
Visit a simple name, and resolve it if possible.
|
void |
endVisit(org.eclipse.jdt.core.dom.SimpleType node)
Visit a simple type node, and propergate the type of its name to it if
it is in a
ClassInstanceCreation . |
void |
endVisit(org.eclipse.jdt.core.dom.SingleVariableDeclaration node)
Visit a single variable declaration and set its type to be the
declared type.
|
void |
endVisit(org.eclipse.jdt.core.dom.StringLiteral node)
Visit a literal node and set its type to be the same type as the
literal.
|
void |
endVisit(org.eclipse.jdt.core.dom.SuperConstructorInvocation node)
Visit a super constructor invocation node and calls the constructor
handlers associated with this type analyzer (if any).
|
void |
endVisit(org.eclipse.jdt.core.dom.SuperFieldAccess node)
Visit a super field access node (super.FieldName), and
resolve the field from the superclass of the given class name
(if any, like ClassName.super.FieldName) or from the
superclass of the class being inspected.
|
void |
endVisit(org.eclipse.jdt.core.dom.SuperMethodInvocation node)
Visit a super method invocation node (super.method(...)
|
void |
endVisit(org.eclipse.jdt.core.dom.ThisExpression node)
Visit a this expression, and set its type to be
the class preceding it (if any) or the class currently being
inspected.
|
void |
endVisit(org.eclipse.jdt.core.dom.TypeDeclaration node)
End the visit of a type declaration and close its scope.
|
void |
endVisit(org.eclipse.jdt.core.dom.TypeLiteral node)
Visit a literal node and set its type to be the same type as the
literal.
|
void |
endVisit(org.eclipse.jdt.core.dom.VariableDeclarationExpression node)
Visit a variable declaration expression and set its type to be
the declared type.
|
void |
endVisit(org.eclipse.jdt.core.dom.VariableDeclarationFragment node)
Visit a variable declaration fragment and set its type to be the
declared type of the node's parent (a variable declaration or field
declaration).
|
HandlerList |
getHandlers()
Get the list of handlers to be called back when traversing the AST.
|
TypeAnalyzerState |
getState()
Get the current state of the analyzer.
|
static void |
main(java.lang.String[] args)
Take a list of Java files as input and type-check all of them.
|
boolean |
visit(org.eclipse.jdt.core.dom.AnonymousClassDeclaration node)
Visit an anonymous class declaration and set the current class to
be the
Class object loaded with the same internal name. |
boolean |
visit(org.eclipse.jdt.core.dom.Block node)
Visit a block and open a scope for variable declarations in it.
|
boolean |
visit(org.eclipse.jdt.core.dom.EnhancedForStatement node)
Visit an enhanced for statement and open a scope for variable
declarations in it.
|
boolean |
visit(org.eclipse.jdt.core.dom.FieldDeclaration node)
Visit a field declaration.
|
boolean |
visit(org.eclipse.jdt.core.dom.ForStatement node)
Visit a for statement and open a scope for variable declarations
in it.
|
boolean |
visit(org.eclipse.jdt.core.dom.ImportDeclaration node)
Override the behavior of visiting an importation declaration.
|
boolean |
visit(org.eclipse.jdt.core.dom.MethodDeclaration node)
Visit a method declaration and open a scope for variable
declarations in it.
|
boolean |
visit(org.eclipse.jdt.core.dom.PackageDeclaration node)
Override the behavior of visiting a package declaration.
|
boolean |
visit(org.eclipse.jdt.core.dom.SimpleType node)
Visit a simple type node and set its type to be the same as the
type associated with its name.
|
boolean |
visit(org.eclipse.jdt.core.dom.TypeDeclaration node)
Visit an type declaration and set the current class to be the
Class object loaded with the same (internal) name. |
endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, endVisit, postVisit, preVisit, preVisit2, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit, visit
public TypeAnalyzer() throws java.net.MalformedURLException
LocalClassLoader
). Such
a class loader cannot resolve classes other than Java
built-in classes.java.net.MalformedURLException
- If a classpath is not a proper URL.public TypeAnalyzer(java.lang.String[] classPaths) throws java.net.MalformedURLException
LocalClassLoader
).classPaths
- The class paths.java.net.MalformedURLException
- If a classpath is not a proper URL.public void addCrossAnalyzedType(java.lang.String fullName)
fullName
- The name of the type to be added.addCrossAnalyzedTypes(String[])
public void addCrossAnalyzedTypes(java.lang.String[] fullNames)
fullNames
- The array of names of types to be added.addCrossAnalyzedType(String)
public void endVisit(org.eclipse.jdt.core.dom.AnonymousClassDeclaration node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ArrayAccess node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ArrayCreation node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ArrayType node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.Assignment node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.Block node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.BooleanLiteral node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.CastExpression node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.CharacterLiteral node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ClassInstanceCreation node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ConditionalExpression node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.EnhancedForStatement node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.FieldAccess node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.FieldDeclaration node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ForStatement node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ImportDeclaration node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.InfixExpression node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.InstanceofExpression node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.MethodDeclaration node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.MethodInvocation node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.NullLiteral node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.NumberLiteral node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.PackageDeclaration node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ParameterizedType node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ParenthesizedExpression node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.PostfixExpression node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.PrefixExpression node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.PrimitiveType node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.QualifiedName node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ReturnStatement node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.SimpleName node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.SimpleType node)
ClassInstanceCreation
.endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.SingleVariableDeclaration node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.StringLiteral node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.SuperConstructorInvocation node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.SuperFieldAccess node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.SuperMethodInvocation node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.ThisExpression node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.TypeDeclaration node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.TypeLiteral node)
A type literal is of the form "CLASSNAME.class", so its
type is always Class
.
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.VariableDeclarationExpression node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public void endVisit(org.eclipse.jdt.core.dom.VariableDeclarationFragment node)
endVisit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public HandlerList getHandlers()
public TypeAnalyzerState getState()
public static void main(java.lang.String[] args) throws java.lang.Exception
args
- Command-line arguments, which is a list of Java files.java.lang.Exception
- If any error occurs.public boolean visit(org.eclipse.jdt.core.dom.AnonymousClassDeclaration node)
Class
object loaded with the same internal name. A
scope is opened for field declarations in it.visit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public boolean visit(org.eclipse.jdt.core.dom.Block node)
visit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public boolean visit(org.eclipse.jdt.core.dom.EnhancedForStatement node)
visit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public boolean visit(org.eclipse.jdt.core.dom.FieldDeclaration node)
visit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public boolean visit(org.eclipse.jdt.core.dom.ForStatement node)
visit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public boolean visit(org.eclipse.jdt.core.dom.ImportDeclaration node)
visit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public boolean visit(org.eclipse.jdt.core.dom.MethodDeclaration node)
visit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public boolean visit(org.eclipse.jdt.core.dom.PackageDeclaration node)
visit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public boolean visit(org.eclipse.jdt.core.dom.SimpleType node)
visit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.public boolean visit(org.eclipse.jdt.core.dom.TypeDeclaration node)
Class
object loaded with the same (internal) name. A
scope is opened for field declarations in it.visit
in class org.eclipse.jdt.core.dom.ASTVisitor
node
- The node to be visited.protected ptolemy.backtrack.eclipse.ast.TypeAnalyzer.TypeAndOwner _getFieldTypeAndOwner(java.lang.Class c, java.lang.String name)
c
- The class from which the field name is resolved.name
- The name of the field._getMethodType(Class, String, Type[])
protected Type _getMethodType(java.lang.Class c, java.lang.String name, Type[] args)
This function always tries to find the best match if multiple methods with the same name and the same number of arguments are defined in the class and interface hierarchy. This is accomplished by computing the compatibility rating between each pair of formal argument and actural argument, and sum those numbers together.
c
- The class from which the method is resolved.name
- The name of the field.args
- The types of actural arguments for a call._getFieldTypeAndOwner(Class, String)
,
Type.compatibility(Type, ClassLoader)
protected static void _sortBodyDeclarations(org.eclipse.jdt.core.dom.AbstractTypeDeclaration node)
The Java compiler takes a depth-first search to generate code for classes and members of classes. When inspecting a class, it first visits all the fields (and their children), then next visits all the nested classes defined in it (and their children), and finally visits all the methods (and their children).
Using a different order to traverse the Eclipse AST does not change the program semantics, but names of anonymous classes would be different because different numbers are assigned to them. This function sorts the declarations in a class in the same order as the Java compiler uses.
node
- The abstract type declaration whose members are to be
sorted.protected static void _sortBodyDeclarations(org.eclipse.jdt.core.dom.AnonymousClassDeclaration node)
The Java compiler takes a depth-first search to generate code for classes and members of classes. When inspecting a class, it first visits all the fields (and their children), then next visits all the nested classes defined in it (and their children), and finally visits all the methods (and their children).
Using a different order to traverse the Eclipse AST does not change the program semantics, but names of anonymous classes would be different because different numbers are assigned to them. This function sorts the declarations in a class in the same order as the Java compiler uses.
node
- The anonymous class declaration whose members are to be
sorted.