Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

libclang returns too much info about function declarations

I have the following code that uses the clang-c API.

#include <iostream>
#include <string>
#include <clang-c/Index.h>

CXChildVisitResult printVisitor(CXCursor cursor, CXCursor parent, CXClientData client_data) 
{       
    CXCursor cursor1 = clang_getCursorReferenced(cursor);

    CXType type = clang_getCursorType(cursor1);
    CXCursorKind kind = clang_getCursorKind(cursor1);
    CXString str = clang_getTypeSpelling(type);
    CXString str1 = clang_getCursorSpelling(cursor1);
    std::string cstr = clang_getCString(str);
    std::string cstr1 = clang_getCString(str1);

    if(type.kind != 0 && kind == CXCursorKind::CXCursor_FunctionDecl)
    {
        std::cout << "Declaration!\n" << "type is: " << cstr << std::endl;
        std::cout << "name is: " << cstr1 << std::endl;
    }

    return CXChildVisit_Recurse;
}

int main (int argc, char** argv)
{
 CXIndex index = clang_createIndex (
         false, // excludeDeclarationFromPCH
         true   // displayDiagnostics
 );
 CXTranslationUnit unit = clang_parseTranslationUnit (
         index,                           // CIdx
         "main1.cpp",                      // source_filename
         argv + 1 ,                        // command_line_args
         argc - 1 ,                        // num_command_line_args
         0,                                // unsave_files
         0,                                // num_unsaved_files
         CXTranslationUnit_None           // options
 );
 if (unit != 0 )
         std::cout << "Translation unit successfully created" << std::endl;
 else
         std::cout << "Translation unit was not created" << std::endl;

 CXCursor rootCursor = clang_getTranslationUnitCursor(unit);

    clang_visitChildren(rootCursor, printVisitor, NULL);


 clang_disposeTranslationUnit(unit);
 clang_disposeIndex(index);
}

This code parses the following.

double getSum(double a, float b)
{
    return a + b;
}

int main(void)
{
    int a = 5;
    float b = 6;
    double c = a + b;
    return getSum(c, b);
}

When the program runs, I see the following.

    Translation unit successfully created
    Declaration!
    type is: double (double, float)
    name is: getSum
    Declaration!
    type is: int ()
    name is: main
    Declaration!
    type is: double (double, float)
    name is: getSum
    Declaration!
    type is: double (double, float)
    name is: getSum
    Declaration!
    type is: double (double, float)
    name is: getSum
    Declaration!
    type is: double (double, float)
    name is: getSum

Why do I get so much declarations of getSum(), when in the code I have a single declaration?

like image 850
user3016814 Avatar asked Nov 29 '13 07:11

user3016814


2 Answers

When you use clang_getCursorReferenced, you get the CXCursor which is referenced at the current location. For example, a function declaration references itself, and is referenced by the corresponding function call(s). In your example, you will thus get positive matches for every reference to a function declaration (either a function declaration itself or a function call).

Now the other thing is that each CXCursor represents a part of the AST, either a leaf or a more complex part with subparts. For example, while traversing the AST, you'll find in turn the following cursors:

  • return getSum (c, b)
  • getSum (c, b)
  • getSum

All these cursors reference the getSum function declaration, and my guess is that these are the cursors which trigger multiple references to getSum.

You can check which part of the source code corresponds to the current cursor by calling clang_getCursorExtent

like image 141
François Févotte Avatar answered Nov 05 '22 05:11

François Févotte


I've never used clang, but based on the documentation of CXCursor it seems that the CXCursorKind will always be Declaration whenever the cursor is somewhere in a function (main may get special treatment I suppose). This may explain why you have multiple reports of a declaration of Sum.

I base my conjecture on the definition of CXCursorKind, found here:

enum CXCursorKind {
  /* Declarations */
  /**
   * \brief A declaration whose specific kind is not exposed via this
   * interface.
   *
   * Unexposed declarations have the same operations as any other kind
   * of declaration; one can extract their location information,
   * spelling, find their definitions, etc. However, the specific kind
   * of the declaration is not reported.
   */
...
}
like image 42
Marc Claesen Avatar answered Nov 05 '22 04:11

Marc Claesen