2

I got the FunctionDecl for the definition of a function. There is no declaration for this function.

For example:

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

How do I get the signature (qualifier, return type, function name, parametrs) as a valid signature I could use to make a declaration?

Fee
  • 719
  • 9
  • 24
  • 1
    See my example in below! https://stackoverflow.com/questions/45430971/how-to-get-function-definition-signature-as-a-string-in-clang – EIP Passenger Apr 07 '18 at 16:42

2 Answers2

3

I found that the easiest way is to use the lexer to get the signature of the function. Since I wanted to make a declaration out of a definition, I wanted the declaration to look exactly like the definition. Therefore I defined a SourceRange from the start of the function to the beginning of the body of the function (minus the opening "{") and let the lexer give me this range as a string.

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

This solution assums that the FunctionDecl is a definition (has a body).

Fee
  • 719
  • 9
  • 24
  • Thank you for this answer! Unfortunately I have found it produces incorrect results when there are ctor initializers - they are included in the result, though they are not a part of the signature. – fbrereto Sep 27 '18 at 16:09
1

Maybe this is what you were looking for...

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;
}

Sample output:

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> 

You will notice the reinterpret_cast<OtherDecl*>(D) function calls. Decl is the base class for all AST OtherDecl classes like FunctionDecl or ParmVarDecl. So reinterpreting the pointer is allowed and gets you access to that particular AST node's attributes. Since these more-specific AST Nodes inherit the NamedDecl and ValueDecl classes, obtaining the function name and the function type (signature) is simple. The same can be applied to the base class Stmt and other inherited classes like the OtherExpr classes.