克隆检测算法中访问AST节点src字段时出现NoSuchField错误
问题:访问AST节点src字段时出现NoSuchField错误(日志中src字段明确存在)
开发克隆检测算法时,需要获取AST节点的位置信息,尝试通过e.src访问节点的src字段时,触发NoSuchField("src")错误,但AST遍历日志中清晰显示所有节点都带有src位置注解。
日志片段:
method method(int(),"sum",[parameter(int(),"a",0,src=|java+compilationUnit:///src/duplication.java|(225,5,<12,19>,<12,24>),decl=|unresolved:///|,typ=int()),parameter(int(),"b",0,src=|java+compilationUnit:///src/duplication.java|(232,5,<12,26>,<12,31>),decl=|unresolved:///|,typ=int())],[],block([return(infix(simpleName("a",src=|java+compilationUnit:///src/duplication.java|(256,1,<13,15>,<13,16>),decl=|unresolved:///|,typ=int()),"+",simpleName("b",src=|java+compilationUnit:///src/duplication.java|(260,1,<13,19>,<13,20>),decl=|unresolved:///|,typ=int()),src=|java+compilationUnit:///src/duplication.java|(256,5,<13,15>,<13,20>),typ=int()),src=|java+compilationUnit:///src/duplication.java|(249,13,<13,8>,<13,21>)),return(infix(simpleName("a",src=|java+compilationUnit:///src/duplication.java|(279,1,<14,15>,<14,16>),decl=|unresolved:///|,typ=int()),"+",simpleName("b",src=|java+compilationUnit:///src/duplication.java|(283,1,<14,19>,<14,20>),decl=|unresolved:///|,typ=int()),src=|java+compilationUnit:///src/duplication.java|(279,5,<14,15>,<14,20>),typ=int()),src=|java+compilationUnit:///src/duplication.java|(272,13,<14,8>,<14,21>)),return(infix(simpleName("a",src=|java+compilationUnit:///src/duplication.java|(301,1,<15,15>,<15,16>),decl=|unresolved:///|,typ=int()),"+",simpleName("b",src=|java+compilationUnit:///src/duplication.java|(305,1,<15,19>,<15,20>),decl=|unresolved:///|,typ=int()),src=|java+compilationUnit:///src/duplication.java|(301,5,<15,15>,<15,20>),typ=int()),src=|java+compilationUnit:///src/duplication.java|(294,13,<15,8>,<15,21>)),return(infix(simpleName("a",src=|java+compilationUnit:///src/duplication.java|(323,1,<16,15>,<16,16>),decl=|unresolved:///|,typ=int()),"+",simpleName("b",src=|java+compilationUnit:///src/duplication.java|(327,1,<16,19>,<16,20>),decl=|unresolved:///|,typ=int()),src=|java+compilationUnit:///src/duplication.java|(323,5,<16,15>,<16,20>),typ=int()),src=|java+compilationUnit:///src/duplication.java|(316,13,<16,8>,<16,21>)),return(infix(simpleName("a",src=|java+compilationUnit:///src/duplication.java|(345,1,<17,15>,<17,16>),decl=|unresolved:///|,typ=int()),"+",simpleName("b",src=|java+compilationUnit:///src/duplication.java|(349,1,<17,19>,<17,20>),decl=|unresolved:///|,typ=int()),src=|java+compilationUnit:///src/duplication.java|(345,5,<17,15>,<17,20>),typ=int()),src=|java+compilationUnit:///src/duplication.java|(338,13,<17,8>,<17,21>))],src=|java+compilationUnit:///src/duplication.java|(239,118,<12,33>,<18,5>)),modifiers=[public()],src=|java+compilationUnit:///src/duplication.java|(210,147,<12,4>,<18,5>),decl=|unresolved:///|,typ=unresolved())
相关代码:
void main() { M3 model = createM3FromMavenProject(|project://java-benchmark|); list[Declaration] asts = getASTs(model); detectClones(asts); } void detectClones(list[Declaration] asts) { visit(asts) { case node e : { println(getName(e)); println(e.src); // println(e); } } }
错误原因
- 静态类型约束:你声明的
asts是list[Declaration]类型,而Declaration的静态类型定义中并不包含src字段。日志里的src是节点在运行时的动态属性,但静态类型检查会阻止直接用.访问未声明的字段。 - 日志是动态输出:AST日志打印的是节点的完整动态结构,包含所有运行时附加的属性,但静态类型系统不会识别这些未在类型定义中声明的字段。
解决方案
方案1:使用动态字段访问操作符@
在Rascal中,访问动态属性需要用@代替.,绕过静态类型检查直接访问运行时属性:
void detectClones(list[Declaration] asts) { visit(asts) { case node e : { println(getName(e)); println(e@src); // 替换e.src为e@src // println(e); } } }
方案2:先检查字段存在性(避免运行时异常)
如果部分节点可能没有src字段,可先判断再访问:
void detectClones(list[Declaration] asts) { visit(asts) { case node e : { println(getName(e)); if (hasField(e, "src")) { println(e@src); } else { println("No src field found for node: " + getName(e)); } } } }
方案3:使用框架提供的位置API(推荐)
如果使用的Rascal AST框架提供了获取位置的标准函数(比如location()),优先使用这种规范方式,避免直接访问底层字段:
void detectClones(list[Declaration] asts) { visit(asts) { case node e : { println(getName(e)); println(location(e)); // 使用框架API获取位置 } } }
内容的提问来源于stack exchange,提问作者ciyan97
相关产品推荐
相关产品推荐

