clangllvmllvm-clangoclintlibtooling

Get class information from ObjCPropertyDecl


I having some trouble extracting the class information from a clang ObjCPropertyDecl type.

Example Objective-C file:

#import <Foundation/Foundation.h>

@interface Test: NSObject

@property (nonatomic, strong, nullable) NSObject *test;
@property (nonatomic, strong, nullable) NSArray<NSObject *> *test1;

@end

@implementation Test

@end

Dumping the ast gives me this:

...
|-ObjCInterfaceDecl 0x104bbf8e0 <test.m:7:1, line:12:2> line:7:12 Test
| |-super ObjCInterface 0x103962618 'NSObject'
| |-ObjCImplementation 0x104bbff40 'Test'
| |-ObjCPropertyDecl 0x104bbfa20 <line:9:1, col:51> col:51 test 'NSObject * _Nullable':'NSObject *' readwrite nonatomic strong
| |-ObjCPropertyDecl 0x104bbfbe0 <line:10:1, col:62> col:62 test1 'NSArray<NSObject *> * _Nullable':'NSArray<NSObject *> *' readwrite nonatomic strong
| |-ObjCMethodDecl 0x104bbfc50 <line:9:51> col:51 implicit - test 'NSObject * _Nullable':'NSObject *'
| |-ObjCMethodDecl 0x104bbfcd8 <col:51> col:51 implicit - setTest: 'void'
| | `-ParmVarDecl 0x104bbfd60 <col:51> col:51 test 'NSObject * _Nullable':'NSObject *'
| |-ObjCMethodDecl 0x104bbfdc8 <line:10:62> col:62 implicit - test1 'NSArray<NSObject *> * _Nullable':'NSArray<NSObject *> *'
| `-ObjCMethodDecl 0x104bbfe50 <col:62> col:62 implicit - setTest1: 'void'
|   `-ParmVarDecl 0x104bbfed8 <col:62> col:62 test1 'NSArray<NSObject *> * _Nullable':'NSArray<NSObject *> *'
...

Previously, I had an OCLint rule that relied on checking the type to see if it was an NSArray, so I'd use an ASTVisitor and this code:

string propertyType = node->getType().getAsString();
// compare to "NSArray *"

Note that both the nullable keyword and the generics in the code sample above change the qualified type (see the AST dump).

My question is: Is there a way I can get only the Objective-C class type from an ObjCPropertyDecl e.g. NSArray * or NSString * without any of the extra sugar?

I've tried getSplitDesugaredType(); and that works well for removing nullable parts but that doesn't remove generics.

Edit:

My current thinking is that I might be able to get the Type from the SplitQualType then cast to ObjCObjectPointerType and get the ObjCObjectType and that might have the information I want but, I'll try implementing that tomorrow.


Solution

  • Ok, after much digging around, I found an acceptable solution to this:

    std::string propertyType(clang::ObjCPropertyDecl *d) {
      QualType T = d->getType();
      if (auto TypePtr = T.getTypePtr()) {
         if (TypePtr->isObjCObjectPointerType()) {
            if (auto InterfaceType = TypePtr->getAsObjCInterfacePointerType()) {
                return InterfaceType->getObjectType()->getBaseType().getAsString();
            }
        }
      }
      return "";
    }
    

    Examples:

    @property (nonatomic, strong, nullable) NSObject *test; Returns: NSObject

    @property (nonatomic, strong, nullable) NSArray<NSObject *> *test1; Returns: NSArray

    Note: This will only return values for object pointer types, properties for scalar values like NSInteger etc, will return empty string.