Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the signature of a FunctionDecl

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?

like image 497
Fee Avatar asked Oct 16 '25 20:10

Fee


2 Answers

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).

like image 181
Fee Avatar answered Oct 18 '25 11:10

Fee


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.

like image 31
SteeleDynamics Avatar answered Oct 18 '25 11:10

SteeleDynamics



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!