如何在Clang中将函数定义/签名作为字符串?

时间:2017-08-01 06:57:30

标签: clang libclang

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

我认为定义可以通过使用光标的范围以某种方式获得,但我不知道如何(使用什么功能)。

4 个答案:

答案 0 :(得分:3)

您可以使用这个简单的代码来获取函数的原型(名称,返回类型,参数计数和参数[名称,数据类型])。

 string Convert(const CXString& s)
{
    string result = clang_getCString(s);
    clang_disposeString(s);
    return result;
}
void print_function_prototype(CXCursor cursor)
{
    // TODO : Print data! 
    auto type = clang_getCursorType(cursor);


    auto function_name = Convert(clang_getCursorSpelling(cursor));
    auto return_type   = Convert(clang_getTypeSpelling(clang_getResultType(type)));

    int num_args = clang_Cursor_getNumArguments(cursor);
    for (int i = 0; i < num_args; ++i)
    {
        auto arg_cursor = clang_Cursor_getArgument(cursor, i);
        auto arg_name = Convert(clang_getCursorSpelling(arg_cursor));
        if (arg_name.empty())
        {
            arg_name = "no name!";
        }

        auto arg_data_type = Convert(clang_getTypeSpelling(clang_getArgType(type, i)));
    }
}
CXChildVisitResult functionVisitor(CXCursor cursor, CXCursor /* parent */, CXClientData /* clientData */)
{
    if (clang_Location_isFromMainFile(clang_getCursorLocation(cursor)) == 0)
        return CXChildVisit_Continue;

    CXCursorKind kind = clang_getCursorKind(cursor);
    if ((kind == CXCursorKind::CXCursor_FunctionDecl || kind == CXCursorKind::CXCursor_CXXMethod || kind == CXCursorKind::CXCursor_FunctionTemplate || \
         kind == CXCursorKind::CXCursor_Constructor))
    {
        print_function_prototype(cursor);
    }

    return CXChildVisit_Continue;
}

答案 1 :(得分:0)

您可以尝试使用clang_Cursor_getMangling()并对结果进行解密以获取完整的定义。

答案 2 :(得分:0)

我正在为我正在处理的项目使用以下内容,它对于定义非常有用。 TL&DR clang_getCursorPrettyPrint,将策略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);
    }

此函数检查函数调用是“肉”还是仅是定义。显然,您可以根据需要进行调整,包括编写自己的isAllowedDirectory函数。遇到声明类型时,在遍历AST时只需传递游标,两个字符串和一个无符号即可。

答案 3 :(得分:0)

我在 clang 10 中使用了以下更短的方法(尽管它使用的是匹配器,而不是游标): 2 个辅助函数是将代码片段作为字符串获取的通用辅助函数。

// 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());
    }
 }

这将为以下函数输出 inline bool test2(std::string const & str, std::vector<std::string> & sss)

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