本系列临近尾声,科技树到此点满。
语法分析主要用库解决了,代码变成了一棵树,但是变量类型,方法签名之类的东东都不清楚。
如果做IDE插件,可以享受IDE的语义分析能力。为了让程序独立运行,我自己按需实现了语义分析。
比较复杂,就分享一种最典型的吧。贴代码为主,有问题请告诉我,我再改文章。
解析某个变量的声明类型,会上溯当前方法和类,以及祖先类。为了提速(分析大型代码库),可以手动限制范围。
直接贴代码了,已在Exia项目提供。
public class VariableTypeResolver {
private final String symbol;
private final ASTNode minScope;
private boolean methodLevel = true;
private boolean typeLevel = true;
/**
* The found result
*/
private SimpleName declSN;
private final ASTVisitor visitor = new ASTVisitor() {
@Override
public boolean visit(SimpleName sn) {
if (found()) {
return false;
}
if (sn.getIdentifier().equals(symbol) && sn.getParent() instanceof VariableDeclaration) {
declSN = sn;
return false;
}
return true;
}
};
/**
* Starts resolving with the requested symbol
* @param varSymbolNode the variable symbol node to resolve (node must be in the AST)
*/
public VariableTypeResolver(SimpleName varSymbolNode) {
this.symbol = varSymbolNode.getIdentifier();
this.minScope = varSymbolNode;
}
public VariableTypeResolver(String varSymbol, ASTNode minScope) {
this.symbol = varSymbol;
this.minScope = minScope;
}
public VariableTypeResolver disableMethodLevel() {
methodLevel = false;
return this;
}
public VariableTypeResolver disableTypeLevel() {
typeLevel = false;
return this;
}
/**
* Node's parent is instance of {@link VariableDeclarationFragment} or {@link SingleVariableDeclaration}
* @return the SimpleName node of declaration
*/
public SimpleName resolveDeclSimpleName() {
if (!found()) {
resolve();
}
return declSN;
}
private void resolve() {
if(found()) {return;}
if (methodLevel) {
apply(FindUpper.methodScope(minScope));
}
if(found()) {return;}
if (typeLevel) {
AbstractTypeDeclaration typeScope = FindUpper.abstractTypeScope(minScope);
applyInFields(typeScope);
if(found()) {return;}
for (TypeDeclaration superClass : superClasses(typeScope)) {
if(found()) {return;}
applyInFields(superClass);
}
}
}
private boolean found() {
return declSN != null;
}
private void apply(ASTNode scope) {
if (scope == null) {
throw new NullPointerException();
}
scope.accept(visitor);
}
private void applyInFields(AbstractTypeDeclaration typeScope) {
for (Object bd : typeScope.bodyDeclarations()) {
if (bd instanceof FieldDeclaration) {
apply((ASTNode) bd);
}
}
}
private List superClasses(AbstractTypeDeclaration atd) {
if (atd instanceof TypeDeclaration) {
return AstUtils.superClasses((TypeDeclaration) atd);
}
else {
return Collections.EMPTY_LIST;
}
}
}
它依赖的AstUtils, FindUpper, SourcePathCollector设施都在Exia里面,配合使用即可。https://github.com/sorra/exia