获取FunctionDecl的签名

时间:2018-04-04 19:48:42

标签: clang llvm libclang libtooling

我得到了函数定义的FunctionDecl。此功能没有声明。

例如:

int foo(char c, double d)
{
   ...
}

如何将签名(限定符,返回类型,函数名称,参数)作为可用于声明的有效签名?

2 个答案:

答案 0 :(得分:1)

我发现最简单的方法是使用词法分析器获取函数的签名。由于我想从定义中做出声明,我希望声明看起来与定义完全一样。 因此,我从函数的开头到函数体的开头(减去开头“{”)定义了一个SourceRange,让lexer给我这个范围作为字符串。

static std::string getDeclaration(const clang::FunctionDecl* D)
{
  clang::ASTContext& ctx = D->getASTContext();
  clang::SourceManager& mgr = ctx.getSourceManager();

  clang::SourceRange range = clang::SourceRange(D->getSourceRange().getBegin(), D->getBody()->getSourceRange().getBegin());
  StringRef s = clang::Lexer::getSourceText(clang::CharSourceRange::getTokenRange(range), mgr, ctx.getLangOpts());

  return s.substr(0, s.size() - 2).str().append(";");
}

此解决方案确定FunctionDecl是一个定义(有一个正文)。

答案 1 :(得分:0)

也许这就是您想要的...

bool VisitDecl(Decl* D) {
  auto k = D->getDeclKindName();
  auto r = D->getSourceRange();
  auto b = r.getBegin();
  auto e = r.getEnd();
  auto& srcMgr = Context->getSourceManager();
  if (srcMgr.isInMainFile(b)) {
    auto d = depth - 2u;
    auto fname = srcMgr.getFilename(b);
    auto bOff = srcMgr.getFileOffset(b);
    auto eOff = srcMgr.getFileOffset(e);
    llvm::outs() << std::string(2*d,' ') << k << "Decl ";
    llvm::outs() << "<" << fname << ", " << bOff << ", " << eOff << "> ";
    if (D->getKind() == Decl::Kind::Function) {
      auto fnDecl = reinterpret_cast<FunctionDecl*>(D);
      llvm::outs() << fnDecl->getNameAsString() << " ";
      llvm::outs() << "'" << fnDecl->getType().getAsString() << "' ";
    } else if (D->getKind() == Decl::Kind::ParmVar) {
      auto pvDecl = reinterpret_cast<ParmVarDecl*>(D);
      llvm::outs() << pvDecl->getNameAsString() << " ";
      llvm::outs() << "'" << pvDecl->getType().getAsString() << "' ";
    }
    llvm::outs() << "\n";
  }
  return true;
}

示例输出:

FunctionDecl <foo.c, 48, 94> foo 'int (unsigned int)' 
  ParmVarDecl <foo.c, 56, 69> x 'unsigned int' 
  CompoundStmt <foo.c, 72, 94> 
    ReturnStmt <foo.c, 76, 91> 
      ParenExpr <foo.c, 83, 91> 
        BinaryOperator <foo.c, 84, 17> 
          ImplicitCastExpr <foo.c, 84, 84> 
            DeclRefExpr <foo.c, 84, 84> 
          ParenExpr <foo.c, 28, 45> 
            BinaryOperator <foo.c, 29, 43> 
              ParenExpr <foo.c, 29, 39> 
                BinaryOperator <foo.c, 30, 12> 
                  IntegerLiteral <foo.c, 30, 30> 
                  IntegerLiteral <foo.c, 12, 12> 
              IntegerLiteral <foo.c, 43, 43> 

您会注意到reinterpret_cast<OtherDecl*>(D)函数调用。 Decl是所有AST OtherDecl类(例如FunctionDeclParmVarDecl)的基类。因此,允许重新解释指针,并使您可以访问该特定AST节点的属性。由于这些更特定的AST节点继承了NamedDeclValueDecl类,因此获得函数名称和函数类型(签名)非常简单。可以将同样的方法应用于基类Stmt和其他继承的类,例如OtherExpr类。