Clang 如何以字符串的形式获取函数定义/签名?

Clang 如何以字符串的形式获取函数定义/签名?,clang,libclang,Clang,Libclang,假设我有一个CXCursor左右,如何使用Clang/Libclang将函数的签名(或至少整个定义?)作为字符串获取 我认为可以通过使用游标的区段以某种方式获得定义,但我真的不知道如何(使用什么函数)。您可以使用此简单代码获得函数原型(名称、返回类型、参数计数和参数[名称、数据类型]) 字符串转换(常量CXString&s) { 字符串结果=clang_getCString(s); 叮当作响的处置; 返回结果; } 无效打印功能原型(CXCursor) { //TODO:打印数据! 自动类型=c

假设我有一个CXCursor左右,如何使用Clang/Libclang将函数的签名(或至少整个定义?)作为字符串获取


我认为可以通过使用游标的区段以某种方式获得定义,但我真的不知道如何(使用什么函数)。

您可以使用此简单代码获得函数原型(名称、返回类型、参数计数和参数[名称、数据类型])

字符串转换(常量CXString&s)
{
字符串结果=clang_getCString(s);
叮当作响的处置;
返回结果;
}
无效打印功能原型(CXCursor)
{
//TODO:打印数据!
自动类型=clang_getCursorType(光标);
自动函数_name=Convert(clang_getCursorSpelling(游标));
自动返回类型=转换(clanggettypespelling(clanggetresulttype(type));
int num_args=clang_Cursor_getNumArguments(Cursor);
对于(int i=0;i
您可以尝试使用
clang\u Cursor\u getMangling()
并对结果进行demangle处理,以获得完整的定义。

我将以下内容用于我正在进行的一个项目,它对定义非常有用。TL&DR clang_getCursorPrettyPrinted,策略TerseOutput设置为true



    std::string getStdString(const CXString &s)
    {
        std::string rv = clang_getCString(s);
        clang_disposeString(s);
        return rv;
    }
    
    bool isFunctionImplementation(CXCursor &cursor,std::string &decl,std::string &filename,unsigned &lineno)
    {
        std::string cs = getStdString(clang_getCursorPrettyPrinted(cursor,nullptr));
        if (cs.find('{') == std::string::npos) // Just a declaration, not the "meat" of the function, so we dont care
            return false;
        clang::LangOptions lo;
        struct clang::PrintingPolicy pol(lo);
        pol.adjustForCPlusPlus();
        pol.TerseOutput = true;
        pol.FullyQualifiedName = true;
        decl = getStdString(clang_getCursorPrettyPrinted(cursor,&pol));
        CXSourceLocation location = clang_getCursorLocation( cursor );
        CXFile f;
        lineno = 0;
        filename = "(None)";
        clang_getSpellingLocation(location,&f,&lineno,nullptr,nullptr);
        if (lineno)
        {
            filename = getStdString(clang_File_tryGetRealPathName(f));
        }
        return isAllowedDirectory(filename);
    }


这个函数检查函数调用是“meat”还是仅仅是一个定义。显然,您可以根据需要进行调整,包括编写自己的isAllowedDirectory函数。当您点击声明类型时,只需在AST中传递光标、两个字符串和一个未签名的字符即可。

我使用以下简短的方法处理clang 10(尽管它使用的是匹配器,而不是光标): 这两个helper函数是将代码段作为字符串获取的常规帮助程序

// helper function 1: find position of end of token    
SourceLocation
end_of_the_end(SourceLocation const & start_of_end, SourceManager & sm)
{
  using namespace clang;
  LangOptions lopt;
  return Lexer::getLocForEndOfToken(start_of_end, 0, sm, lopt);
}

  // helper function 2: 
  std::string getSymbolString(clang::SourceManager & sm,
                              const clang::SourceRange & range)
  {
    return std::string(sm.getCharacterData(range.getBegin()),
                       sm.getCharacterData(end_of_the_end(range.getEnd(), sm)));
  }
获取函数声明字符串的实际代码段为:

// ... in run() of a matcher:
  virtual void run(corct::result_t const & result) override
  {
    using namespace clang;
    FunctionDecl * f_decl = const_cast<FunctionDecl *>(
        result.Nodes.getNodeAs<FunctionDecl>(fd_bd_name_));

    if(f_decl) {
      SourceManager & sm(result.Context->getSourceManager());
      FunctionDecl * f_decl = const_cast<FunctionDecl *>(
          result.Nodes.getNodeAs<FunctionDecl>(fd_bd_name_));
      auto full_decl_string =
          getSymbolString(sm, f_decl->DeclaratorDecl::getSourceRange());
    }
 }
/。。。在匹配器的run()中:
虚拟无效运行(corct::result\t const&result)覆盖
{
使用名称空间铿锵;
函数decl*f_decl=const_cast(
result.Nodes.getNodeAs(fd_bd_name);
如果(f_decl){
SourceManager&sm(result.Context->getSourceManager());
函数decl*f_decl=const_cast(
result.Nodes.getNodeAs(fd_bd_name);
自动满decl字符串=
getSymbolString(sm,f_decl->DeclaratorDecl::getSourceRange());
}
}
这将为以下函数输出
内联bool test2(std::string const&str,std::vector&sss)

  inline bool test2(std::string const & str, std::vector<std::string> & sss)
  {
    return true;
  }
inline bool test2(std::string const&str,std::vector&sss)
{
返回true;
}

C不是像javaI那样的解释语言,我不明白你的意思,对不起。但是为什么解释Java?我在主帖中将“cursor”改为“CXCursor”,我指的是叮当作响的cursor。是的,但将其全部组合回函数签名似乎不是一件简单的工作(以函数指针为例)特别是考虑到它已经完成并且函数签名已经存在于源文件中。@Predelnik hmm你能给我一个例子吗[以函数指针为例]?我的意思是如果你有类似于
void f(void(*arg)(int,int))
的东西,你可以提取
arg
void(*)(int,int)
但将它们组合回签名将需要计算出将
arg
放在类型中的确切位置,这并不容易。@Predelnik是的,这个示例很难在libclang中提取arg,但我认为我们可以使用clang libtools来完成。请参阅此链接,非常感谢。很遗憾,我不再使用clang,但我希望如此如果我再次使用你的答案,你的答案将对其他人甚至我有用:)。
  inline bool test2(std::string const & str, std::vector<std::string> & sss)
  {
    return true;
  }