libclang clang_getCursorPlatformAvailability fails often

Hi all,

It seems to me that clang_getCursorPlatformAvailability API in libclang
fails to find availability too often for OSX SDK APIs. Normally, for iOS it
seems to work much better even for the same Foundation APIs.

A few random examples (I have many examples) can be:

  //in NSLayoutConstraint.h
  - (void)layoutIfNeeded NS_AVAILABLE_MAC(10_7);

  //in NSWindow.h
  - (BOOL)preventsApplicationTerminationWhenModal NS_AVAILABLE_MAC(10_6);

I have a simple test Xcode project that reproduces this behaviour here:
http://cl.ly/2B261r2X0H3y
(Just modify your Xcode path if it's not in standard location and build&run)

It's possible that I'm doing something wrong but the exact same code works
pretty well with iOS headers. Also, I'm really not sure about this but it
seems that it fails finding the availability mostly on methods while
classes, enums etc.. work okay.

I'd appreciate any input on this.

Thanks,
Ivan

Have you looked at the preprocessed output in both cases? My guess is that the OS X APIs are mapping the availability macros down to unavailable/deprecated/nothing, rather than Clang’s ‘availability’ attribute.

  • Doug

Hi Doug,

Many thanks for your reply.
I haven't checked but I'll do that and let you know.

Does libclang have the ability to spit out the preprocessed output or would
I need to hook up the LLVM/Clang C++ interface?

Hi Doug,

I ran the preprocessor manually (clang -E vs. doing it from code), with
similar flags it should be the same output I guess.

Anyway, seems you were right. There is a difference in how the compiler sees
OSX and iOS APIs marked with NS_AVAILABLE. This is the original code in the
header file:

- (NSComparisonResult)localizedStandardCompare:(NSString *)string
NS_AVAILABLE(10_6, 4_0);

This is how it resolves for OSX:
- (NSComparisonResult)localizedStandardCompare:(NSString *)string ;

And this is how it resolves for iOS:
- (NSComparisonResult)localizedStandardCompare:(NSString *)string
__attribute__((availability(ios,introduced=4.0)));

It's clear now why clang_getCursorPlatformAvailability doesn't pick it up.
Looking in the headers I found that NS_AVAILABLE is defined as
__OSX_AVAILABLE_STARTING(__MAC_##_mac, __IPHONE_##_ios) on iOS targets and
this macro always works (tried it in my own code). But if TARGET_OS_MAC is
1, the macro is defined as AVAILABLE_MAC_OS_X_VERSION_##_mac##_AND_LATER
which never resolves into an __attribute__

Does this make sense? Not sure if this is a radar candidate or by design.

Hi Doug,

I ran the preprocessor manually (clang -E vs. doing it from code), with
similar flags it should be the same output I guess.

Anyway, seems you were right. There is a difference in how the compiler sees
OSX and iOS APIs marked with NS_AVAILABLE. This is the original code in the
header file:

- (NSComparisonResult)localizedStandardCompare:(NSString *)string
NS_AVAILABLE(10_6, 4_0);

This is how it resolves for OSX:
- (NSComparisonResult)localizedStandardCompare:(NSString *)string ;

And this is how it resolves for iOS:
- (NSComparisonResult)localizedStandardCompare:(NSString *)string
__attribute__((availability(ios,introduced=4.0)));

It's clear now why clang_getCursorPlatformAvailability doesn't pick it up.
Looking in the headers I found that NS_AVAILABLE is defined as
__OSX_AVAILABLE_STARTING(__MAC_##_mac, __IPHONE_##_ios) on iOS targets and
this macro always works (tried it in my own code). But if TARGET_OS_MAC is
1, the macro is defined as AVAILABLE_MAC_OS_X_VERSION_##_mac##_AND_LATER
which never resolves into an __attribute__

Does this make sense? Not sure if this is a radar candidate or by design.

It's not by design; the headers just haven't been updated to match the compiler changes. It's worth a radar.

Many thanks Doug. I filed the rdar:13872912