You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

克隆检测算法中访问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);
        }
    }
}

错误原因

  1. 静态类型约束:你声明的asts是list[Declaration]类型,而Declaration的静态类型定义中并不包含src字段。日志里的src是节点在运行时的动态属性,但静态类型检查会阻止直接用.访问未声明的字段。
  2. 日志是动态输出: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 19:27:34