如何使用 CDT 解析器获取字段类型

How to get a field's type by using CDT parser

我正在尝试提取 C++ 源代码的信息。 一是字段的类型。

当调用 info.call() 时我想提取信息类型的源代码。

Info info;
//skip
info.call(); //<- from here

通过创建访问 IASTName 节点的访问者,我尝试像下面那样提取类型信息。

public class CDTVisitor extends ASTVisitor {

    public CDTVisitor(boolean visitNodes) {
        super(true);
    }

    public int visit(IASTName node){
        if(node.resolveBinding().getName().toString().equals("info"))
            System.out.println(((IField)node.getBinding()).getType()); 
            // this not work properly. 
            //result is "org.eclipse.cdt.internal.core.dom.parser.ProblemType@86be70a"

        return 3;
    }
}

假设代码实际上是有效的,解析为 ProblemType 的变量类型表明 运行 正在使用此代码的任何工具或插件中的配置问题,或者 project/workspace 包含它所在的代码 运行.

在这种情况下,变量info的类型是Info,推测是class或结构类型,或typedef。要正确解析它,CDT 需要能够看到该类型的声明。

如果此类型未在正在分析的同一文件中声明,而是在该文件包含的头文件中声明,CDT 需要使用项目的 index 找到声明。这意味着:

  • AST 必须是 index-based。例如,如果使用 ITranslationUnit.getAST 创建 AST,则必须使用带有 IIndex 参数的重载,并且必须为其提供 non-null 参数。

  • 由于 IIndex 与 CDT 项目关联,被分析的代码需要是 CDT 项目的一部分,并且该项目需要被索引。

  • 为了让索引器正确解析 #include 指令,需要正确配置项目的包含路径,这样索引器才能真正找到正确的头文件进行解析。

其中任何一个不是这种情况都可能导致类型解析为 ProblemType

自我回应。 我无法获得绑定对象的原因是 AST 的类型。

在尝试解析 C++ 源代码时,我应该使用 ICPPASTTranslationUnit。 没有与此相关的代码,我使用 IASTTranslationUnit 作为 return 类型的 AST。

使用ICPPASTTranslationUnit代替IASTTranslationUnit后,我解决了这个问题。

是的,我想通了!这是完整的代码,它可以索引 cpp 项目的“src”文件夹中的所有文件,并输出所有代码表达式的解析类型绑定,包括低级别 API 的 return 值,例如 memcpy。请注意,以下代码中的 project 变量是通过以编程方式导入现有的手动配置的 cpp 项目来创建的。我经常手动创建一个空的cpp项目,然后通过编程将其导入为一个通用项目(导入后Eclipse会自动检测项目类型并完成CPP项目的相关配置)。这比以编程方式从头开始创建和配置 cpp 项目要方便得多。导入项目时,最好不要将项目或包含结构复制到工作区中,因为这可能会导致在子文件夹中无限复制相同的项目(无限文件夹深度)。该代码适用于 Eclipse-2021-12 版本。我下载 Eclipse-For-cpp 并安装 plugin-development 和 jdt 插件。然后我创建一个 Eclipse 插件项目并扩展“org.eclipse.core.runtime.applications”扩展点。 也就是说,它是一个Eclipse-Application插件项目,几乎可以使用Eclipse的所有特性,但不启动Eclipse的图形界面(UI)。您应该添加所有 cdt 相关的 non-ui 插件作为依赖项,因为新版本的 Eclipse 不会再自动添加缺少的插件。

        ICProject cproject = CoreModel.getDefault().getCModel().getCProject(project.getName());
        // this code creates index for entire project. 
        IIndex index = CCorePlugin.getIndexManager().getIndex(cproject);
        
        IFolder folder = project.getFolder("src");
        IResource[] rcs = folder.members();
        // iterate all source files in src folder and visit all expressions to print the resolved type binding. 
        for (IResource rc : rcs) {
            if (rc instanceof IFile) {
                IFile f = (IFile) rc;
                ITranslationUnit tu= (ITranslationUnit) CoreModel.getDefault().create(f);
                index.acquireReadLock(); // we need a read-lock on the index
                ICPPASTTranslationUnit ast = null;
                try {
                    ast = (ICPPASTTranslationUnit) tu.getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
                } finally {
                    index.releaseReadLock();
                }
                if (ast != null) {
                    ast.accept(new ASTVisitor() {
                        @Override
                        public int visit(IASTExpression expression) {
                            // get the resolved type binding of expression. 
                            IType etp = expression.getExpressionType();
                            System.out.println("IASTExpression type:" + etp + "#expr_str:" + expression.toString());
                            return super.visit(expression);
                        }
                    });
                }
            }
        }