Domanda

I am trying to extract the class name of a parameter to a method call in objective-C. The code I am parsing is:

- (void)testAddConcreteDataModel:(DFDemoDataModelOne*)helpmeh {
    [self.dataModels addObject:helpmeh];
}

And the result I need is the type of class of helpmeh, which is "DFDemoDataModelOne".

So far I have the following code, which outputs: "[(DFDataModelContainer).dataModels addObject:helpmeh]"

    if (cursor.kind == CXCursor_ObjCMessageExpr) {
        __block NSString* memberName = nil;
        __block NSString* ownerClassName = nil;
        __block NSString* methodName = [NSString stringWithUTF8String:clang_getCString(clang_getCursorDisplayName(cursor))];

        clang_visitChildrenWithBlock(cursor, ^enum CXChildVisitResult(CXCursor cursor, CXCursor parent) {
            if (cursor.kind == CXCursor_MemberRefExpr) {
                memberName = [NSString stringWithUTF8String:clang_getCString(clang_getCursorDisplayName(cursor))];
                ownerClassName = [NSString stringWithUTF8String:clang_getCString(clang_getCursorDisplayName(clang_getCursorSemanticParent(clang_getCursorReferenced(cursor))))];
            } else {
                if (memberName) {
                    NSString* param = [NSString stringWithUTF8String:clang_getCString(clang_getCursorDisplayName(cursor))];
                    NSLog(@"[(%@).%@ %@%@]", ownerClassName, memberName, methodName, param);
                    clang_visitChildrenWithBlock(cursor, ^enum CXChildVisitResult(CXCursor cursor, CXCursor parent) {

                         // test
                         if ([param isEqualToString:@"helpmeh"] && cursor.kind == CXCursor_DeclRefExpr) {
                            // found the interesting part.. what now?
                         }
                         return CXChildVisit_Recurse;
                     }
                }
            }
            return CXChildVisit_Continue;
        }
    }

I'm just a bit lost as to how to extract information from cursors- when I AST dump my class I can see the information I need is all there (see the last line):

|-ObjCMethodDecl 0x112790f90 <line:32:1, line:34:1> - testAddConcreteDataModel: 'void'
  | |-ImplicitParamDecl 0x112791960 <<invalid sloc>> self 'DFDataModelContainer *const __strong'
  | |-ImplicitParamDecl 0x1127919c0 <<invalid sloc>> _cmd 'SEL':'SEL *'
  | |-ParmVarDecl 0x112791040 <line:32:35, col:55> helpmeh 'DFDemoDataModelOne *__strong'
  | `-CompoundStmt 0x112791bf0 <col:63, line:34:1>
  |   `-ExprWithCleanups 0x112791bd8 <line:33:5, col:39> 'void'
  |     `-ObjCMessageExpr 0x112791ba0 <col:5, col:39> 'void' selector=addObject:
  |       |-PseudoObjectExpr 0x112791b48 <col:6, col:11> 'NSMutableArray *'
  |       | |-ObjCPropertyRefExpr 0x112791ad0 <col:6, col:11> '<pseudo-object type>' lvalue objcproperty Kind=PropertyRef Property="dataModels" Messaging=Getter
  |       | | `-OpaqueValueExpr 0x112791ab0 <col:6> 'DFDataModelContainer *'
  |       | |   `-ImplicitCastExpr 0x112791a40 <col:6> 'DFDataModelContainer *' <LValueToRValue>
  |       | |     `-DeclRefExpr 0x112791a18 <col:6> 'DFDataModelContainer *const __strong' lvalue ImplicitParam 0x112791960 'self' 'DFDataModelContainer *const __strong'
  |       | |-OpaqueValueExpr 0x112791ab0 <col:6> 'DFDataModelContainer *'
  |       | | `-ImplicitCastExpr 0x112791a40 <col:6> 'DFDataModelContainer *' <LValueToRValue>
  |       | |   `-DeclRefExpr 0x112791a18 <col:6> 'DFDataModelContainer *const __strong' lvalue ImplicitParam 0x112791960 'self' 'DFDataModelContainer *const __strong'
  |       | `-ImplicitCastExpr 0x112791b30 <col:11> 'NSMutableArray *' <ARCReclaimReturnedObject>
  |       |   `-ObjCMessageExpr 0x112791b00 <col:11> 'NSMutableArray *' selector=dataModels
  |       |     `-OpaqueValueExpr 0x112791ab0 <col:6> 'DFDataModelContainer *'
  |       |       `-ImplicitCastExpr 0x112791a40 <col:6> 'DFDataModelContainer *' <LValueToRValue>
  |       |         `-DeclRefExpr 0x112791a18 <col:6> 'DFDataModelContainer *const __strong' lvalue ImplicitParam 0x112791960 'self' 'DFDataModelContainer *const __strong'
  |       `-ImplicitCastExpr 0x112791b88 <col:32> 'id':'id' <BitCast>
  |         `-ImplicitCastExpr 0x112791b70 <col:32> 'DFDemoDataModelOne *' <LValueToRValue>
  |           `-DeclRefExpr 0x112791a88 <col:32> 'DFDemoDataModelOne *__strong' lvalue ParmVar 0x112791040 'helpmeh' 'DFDemoDataModelOne *__strong'

Any pointers greatly appreciated!

È stato utile?

Soluzione 2

I think I found a solution-

  • Get the definition of the cursor (in the above case it was CXCursor_ParmDecl but it could be anything, like CXCursor_VarDecl, etc.
  • Get the first child of this cursor

Here is my updated code- it's hacky and needs some cleanup/clarification, but posting here for posterity.

- (void)processMethodDeclaration:(const CXIdxDeclInfo *)declaration {
    clang_visitChildrenWithBlock(declaration->cursor, ^enum CXChildVisitResult(CXCursor cursor, CXCursor parent) {

        if (cursor.kind == CXCursor_ObjCMessageExpr) {
            __block NSString* memberName = nil;
            __block NSString* referencedObjectName = nil;

            clang_visitChildrenWithBlock(cursor, ^enum CXChildVisitResult(CXCursor cursor, CXCursor parent) {
                if (cursor.kind == CXCursor_MemberRefExpr) {
                    memberName = [NSString stringWithUTF8String:clang_getCString(clang_getCursorDisplayName(cursor))];
                    referencedObjectName = [NSString stringWithUTF8String:clang_getCString(clang_getCursorDisplayName(clang_getCursorSemanticParent(clang_getCursorReferenced(cursor))))];
                } else {
                    if (memberName) {
                        __block NSString* passedClassName = nil;

                        clang_visitChildrenWithBlock(cursor, ^enum CXChildVisitResult(CXCursor cursor, CXCursor parent) {
                            if (cursor.kind == CXCursor_DeclRefExpr) {
                                CXCursor def = clang_getCursorDefinition(cursor);
                                clang_visitChildrenWithBlock(def, ^enum CXChildVisitResult(CXCursor cursor, CXCursor parent) {
                                    passedClassName = [NSString stringWithUTF8String:clang_getCString(clang_getCursorDisplayName(cursor))];
                                    return CXChildVisit_Break;
                                });
                            }

                            return CXChildVisit_Recurse;
                        });

                        return CXChildVisit_Break;
                    }
                }
                return CXChildVisit_Continue;
            });
        }
        return CXChildVisit_Recurse;
    });
}

Altri suggerimenti

Have you tried looking at the clang_getCursorSemanticParent function?

I can't help you with ObjC code, but the general idea should be something like :

  1. call clang_getCursorSemanticParent to get a cursor for the class declaration
  2. call clang_getCursorSpelling or clang_getCursorDisplayName on the class declaration cursor to get the class name
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top