1

I would like to extract the types and names of the entire caller object and parameter types of member call expressions made from the A::WriteData method definition.

class ostream {
public:
    void write(char* c, unsigned int i) {
    }
};
struct StringWrapper {
    char c[30];
    void Write(ostream& os) {
        os.write((char*)&c, sizeof(c));
    }
};
struct DoubleWrapper {
    double d;
    void Write(ostream& os) {
        os.write((char*)&d, sizeof(d));
    }
};
struct Data {
    DoubleWrapper dw;
    int i;
    StringWrapper sw;
};
class A {
public:
    void WriteData(ostream& os);
private:
    Data* d;
};
void A::WriteData(ostream& os) {
    os.write((char*)&d->i, sizeof(d->i));
    d->dw.Write(os);
    d->sw.Write(os);
}

The relevant part of clang's AST for the WriteData method is here-

`-CXXMethodDecl 0x1221980 parent 0x1221628 prev 0x12217f8 <line:29:1, line:33:1> line:29:9 WriteData 'void (class ostream &) __attribute__((thiscall))'
  |-ParmVarDecl 0x1221908 <col:19, col:28> col:28 used os 'class ostream &'
  `-CompoundStmt 0x1221d90 <col:32, line:33:1>
    |-CXXMemberCallExpr 0x1221bc8 <line:30:5, col:40> 'void'
    | |-MemberExpr 0x1221a30 <col:5, col:8> '<bound member function type>' .write 0x418a10
    | | `-DeclRefExpr 0x1221a18 <col:5> 'class ostream' lvalue ParmVar 0x1221908 'os' 'class ostream &'
    | |-CStyleCastExpr 0x1221b10 <col:14, col:25> 'char *' <BitCast>
    | | `-UnaryOperator 0x1221ae8 <col:21, col:25> 'int *' prefix '&'
    | |   `-MemberExpr 0x1221aa0 <col:22, col:25> 'int' lvalue ->i 0x12215b0
    | |     `-ImplicitCastExpr 0x1221a90 <col:22> 'struct Data *' <LValueToRValue>
    | |       `-MemberExpr 0x1221a68 <col:22> 'struct Data *' lvalue ->d 0x12218a8
    | |         `-CXXThisExpr 0x1221a58 <col:22> 'class A *' this
    | `-UnaryExprOrTypeTraitExpr 0x1221bb0 <col:28, col:39> 'unsigned int' sizeof
    |   `-ParenExpr 0x1221b98 <col:34, col:39> 'int' lvalue
    |     `-MemberExpr 0x1221b70 <col:35, col:38> 'int' lvalue ->i 0x12215b0
    |       `-ImplicitCastExpr 0x1221b60 <col:35> 'struct Data *' <LValueToRValue>
    |         `-MemberExpr 0x1221b38 <col:35> 'struct Data *' lvalue ->d 0x12218a8
    |           `-CXXThisExpr 0x1221b28 <col:35> 'class A *' this
    |-CXXMemberCallExpr 0x1221ca0 <line:31:5, col:19> 'void'
    | |-MemberExpr 0x1221c60 <col:5, col:11> '<bound member function type>' .Write 0x1221248
    | | `-MemberExpr 0x1221c38 <col:5, col:8> 'struct DoubleWrapper' lvalue ->dw 0x1221570
    | |   `-ImplicitCastExpr 0x1221c28 <col:5> 'struct Data *' <LValueToRValue>
    | |     `-MemberExpr 0x1221c00 <col:5> 'struct Data *' lvalue ->d 0x12218a8
    | |       `-CXXThisExpr 0x1221bf0 <col:5> 'class A *' this
    | `-DeclRefExpr 0x1221c88 <col:17> 'class ostream' lvalue ParmVar 0x1221908 'os' 'class ostream &'
    `-CXXMemberCallExpr 0x1221d70 <line:32:5, col:19> 'void'
      |-MemberExpr 0x1221d30 <col:5, col:11> '<bound member function type>' .Write 0x418d20
      | `-MemberExpr 0x1221d08 <col:5, col:8> 'struct StringWrapper' lvalue ->sw 0x12215e8
      |   `-ImplicitCastExpr 0x1221cf8 <col:5> 'struct Data *' <LValueToRValue>
      |     `-MemberExpr 0x1221cd0 <col:5> 'struct Data *' lvalue ->d 0x12218a8
      |       `-CXXThisExpr 0x1221cc0 <col:5> 'class A *' this
      `-DeclRefExpr 0x1221d58 <col:17> 'class ostream' lvalue ParmVar 0x1221908 'os' 'class ostream &'

In this case, the information I want from my matcher would be:

caller=os: ostream             ; params= &d->i: int*, sizeof(d->i): size_t
caller=d->dw: DoubleWrapper    ; params= os: ostream
caller=d->sw: StringWrapper    ; params= os: ostream

I've tried the following matcher:

cxxMemberCallExpr(
    allOf(
        hasAncestor(
            cxxMethodDecl(isDefinition(),
                          hasName("WriteData"))),
        anyOf(callee(cxxMethodDecl(hasName("WriteData"))),
              callee(cxxMethodDecl(hasName("write"))))
)).bind("write-call-expr")

This gives me the correct statements that I want to extract.

I've extracted the following (invalid c++ follows):

  1. Parameter types by getting the QualType of the parameters as a string:

    cxxMemberCallExpr->getDirectCallee()->parameters()
    
  2. The argument names:

    cxxMemberCallExpr->getArg(i)->printPretty(...)  // **is there a better way to do this?**
    
  3. Type of the object caller:

    cxxMemberCallExpr->getImplicitObjectArgument()->getType().getAsString()
    
  4. Object caller method:

    dyn_cast<MemberExpr>(cxxMemberCallExpr->getCallee())
        ->getMemberNameInfo().getName().getAsString()
    

How do I get the object caller itself? Is there a better way to get the argument names that are passed to the Write methods?

Looking at the AST, I'm not sure where to start.

kushaldsouza
  • 710
  • 5
  • 12
  • 36
  • Regarding the object caller, what is not working with `getImplicitObjectArgument()`? – Some Who Call Me Tim Apr 03 '17 at 14:26
  • @ThoseWhoCallMeTim: The only way I can get the caller is by using printPretty and that gives me something like "(char *)&d->i" instead of "&d->i". I was wondering if there's a better solution than parsing what I need from the result of printPretty. – kushaldsouza Apr 05 '17 at 13:12
  • This question doesn't currently make sense. "How do I get the object[...]?" You already have it, that is what `getImplicitObjectArgument` returns. "Is there a better way to get the argument[...]?" Better in what way? `getArg` gives you the argument expressions. – Scott McPeak Jul 23 '23 at 17:17

0 Answers0