2

我得到了用于定义函数的 FunctionDecl。这个函数没有声明。

例如:

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

如何获取签名(限定符、返回类型、函数名、参数)作为可用于进行声明的有效签名?

4

2 回答 2

2

我发现最简单的方法是使用词法分析器来获取函数的签名。因为我想根据定义进行声明,所以我希望声明看起来与定义完全相同。因此,我定义了SourceRange从函数开头到函数体开头的 a(减去开头的“{”),并让词法分析器将此范围作为字符串提供给我。

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是一个定义(有一个主体)。

于 2018-04-07T18:31:42.433 回答
1

也许这就是你要找的...

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是所有 ASTOtherDecl类的基类,例如FunctionDeclor ParmVarDecl。因此,允许重新解释指针并让您访问该特定 AST 节点的属性。由于这些更具体的 AST 节点继承了NamedDeclValueDecl类,因此获取函数名和函数类型(签名)很简单。同样可以应用于基类Stmt和其他继承的类,如OtherExpr类。

于 2019-03-01T21:30:52.720 回答