1

我想从 A::WriteData 方法定义中提取整个调用者对象的类型和名称以及成员调用表达式的参数类型。

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

用于 WriteData 方法的 clang AST 的相关部分在这里-

`-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 &'

在这种情况下,我想从我的匹配器获得的信息是:

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

我尝试了以下匹配器:

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

这给了我想要提取的正确陈述。

我提取了以下内容(下面是无效的 c++):

  1. 通过将参数的 QualType 作为字符串获取参数类型:

    cxxMemberCallExpr->getDirectCallee()->parameters()
    
  2. 参数名称:

    cxxMemberCallExpr->getArg(i)->printPretty(...)  // **is there a better way to do this?**
    
  3. 对象调用者的类型:

    cxxMemberCallExpr->getImplicitObjectArgument()->getType().getAsString()
    
  4. 对象调用方法:

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

如何获取对象调用者本身? 有没有更好的方法来获取传递给 Write 方法的参数名称?

看着 AST,我不知道从哪里开始。

4

0 回答 0