使用 Clang LibTooling 扫描在模板化父 class 中调用本地 class 的 C++ 源代码

Use Clang LibTooling to scan C++ source that has call to local class in a templated parent class

要扫描的源代码:

template <typename T>
class HB {
    T m;
public:
    void HBfunc1();
};

template <typename T>
void HB<T>::HBfunc1() {  
    class HC {      
    public:
        void HCfunc2() { };
    };    
    HC().HCfunc2();
}

void TestTemplate() { HB<int>().HBfunc1(); };

以上代码在VS2019中运行良好,使用Clang LibTooling扫描AST时:

virtual bool VisitCallExpr(CallExpr *call) {

    std::cout << "VisitCallExpr: ";
    if (call->getDirectCallee()) {
        std::cout << " "<<call->getDirectCallee()->getQualifiedNameAsString();
    }
    else {
        Decl *callee = call->getCalleeDecl();
        if (!callee) {
            std::cout << "\nNow dump call:\n";
            call->dump();
        }
    }
    std::cout<<"\n";
    return true;
}

在扫描源中访问此行的 CallExpr 时:

HC().HCfunc2();

被调用者为空,CallExpr 的转储为:

VisitCallExpr:
Now dump call:
CallExpr 0x1c2ef83b3a0 '<dependent type>'
`-CXXDependentScopeMemberExpr 0x1c2ef83b348 '<dependent type>' lvalue .HCfunc2
  `-CXXUnresolvedConstructExpr 0x1c2ef83b320 'class HC' 'class HC'

Clang 不会在扫描过程中报告错误(因为代码工作正常)。

在 LLVM 源代码中有:

// This represents the type of an expression whose type is
// totally unknown, e.g. 'T::foo'.  It is permitted for this to
// appear in situations where the structure of the type is
// theoretically deducible.
BUILTIN_TYPE(Dependent, DependentTy)

为什么 HC 类型被认为是未知的?在不发出任何 warning/erroe 的情况下扫描 AST 时是否有任何类型未知?如何访问这样的调用并提取有关其被调用者的信息?扫码有问题吗?

Clang 在这种情况下比较保守,将函数调用标记为 unresolved(又名 dependent)。 Dependent 事物只出现在模板中。这意味着某些语法结构 可能 取决于模板参数。

HC class 不是通常的 class,您将有与 HC class 一样多的独立 HC classes,作为 HB。因此,如果 HC 不使用 T,则将它放在 HBfunc1 中几乎没有意义。否则,它确实是依赖的。当 smth 在 dependent context.

中定义时,Clang 更倾向于安全并且避免假设 smth 不是 dependent

由于这些原因,绝对 有这样的 AST 节点是正常的。这不是解析器错误,一切都按预期工作。根据有关被调用者的确切信息,简短的回答是——在分析模板时没有办法。但是,clang 会为每个实例化生成 AST。那些有通常的AST结构,可以很容易地访问。

希望这些信息对您有所帮助!