SourceRange for a macro-expanded function definition?

Hi, I am traversing the AST for an obj-c file using a clang plugin. I have a code snippet like the following:

#define JK_ATTRIBUTES(attr, …) attribute((attr, ##VA_ARGS))
#define JK_STATIC_INLINE static inline JK_ATTRIBUTES(always_inline)

JK_STATIC_INLINE int jk_parse_skip_newline();

@implementation Hello

  • (void)say:(int)i {
    if (i > 0) {
    NSLog(@“Hello, world! (%d)”, i);
    }

// Example of selector with unknown method declaration.
[(id)@“Anything” length];
}
@end

JK_STATIC_INLINE int jk_parse_skip_newline() {
return 0;
}

so while traversing the AST, I am trying to find the SourceRange of the jk_parse_skip_newline() definition at the bottom of the file. For non-macro expanded functions, this is very straightforward. But due to the macro expansion, I get a SourceRange that spans from the start of the macro to the end of my code snippet. That means that it also includes the Hello class, which has nothing to do with jk_parse_skip_newline(). This is a problem because I am trying to use the AST to determine where jk_parse_skip_newline is defined so I can comment it out of the source file.

Is it possible for me to get the necessary SourceRange from the clang API? Ideally, I would get a SourceRange that identifies only the last three lines of my code sample.

Thank you,
Michael

Hi, I am traversing the AST for an obj-c file using a clang plugin. I have
a code snippet like the following:

#define JK_ATTRIBUTES(attr, ...) __attribute__((attr,
##__VA_ARGS__))
#define JK_STATIC_INLINE static __inline__ JK_ATTRIBUTES(always_inline)

JK_STATIC_INLINE int jk_parse_skip_newline();

@implementation Hello
- (void)say:(int)i {
  if (i > 0) {
    NSLog(@"Hello, world! (%d)", i);
  }

  // Example of selector with unknown method declaration.
  [(id)@"Anything" length];
}
@end

JK_STATIC_INLINE int jk_parse_skip_newline() {
  return 0;
}

so while traversing the AST, I am trying to find the SourceRange of the
jk_parse_skip_newline() definition at the bottom of the file. For non-macro
expanded functions, this is very straightforward. But due to the macro
expansion, I get a SourceRange that spans from the start of the macro to
the end of my code snippet.

How do you get that? If you only use functions that handle SourceRanges
(and never combine locations you get from getBegin() getEnd()) that should
not be possible.
Take a look at Lexer::makeFileCharRange and Lexer::getSourceText for how to
deal with macro-ized ranges.

Here is a better example:

https://gist.github.com/bolinfest/9984257

Here are the key lines in the output:


>-FunctionDecl 0x10450ca90 <./example.h:15:1, /System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:137:72> someFunction1 'NSString *(void)' extern

>-FunctionDecl 0x10450cc00 <./example.h:16:1, /System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:137:72> someFunction2 'NSString *(void)' extern

Ideally, I would like to be able to get the following instead:


>-FunctionDecl 0x10450ca90 <./example.h:15:1, ./example.h:15:61> someFunction1 'NSString *(void)' extern
>-FunctionDecl 0x10450cc00 <./example.h:16:1, ./example.h:16:61> someFunction2 'NSString *(void)' extern

That is, I would like to be able to extract a SourceRange from a single file that I could delete (or comment out) to remove the definition or someFunction1 or someFunction2. Obviously the existing SourceRange that I get from the AST makes that hard to do.

Is it possible to get my desired SourceRange?

Thank you,
Michael

Also, I just tried the following on the FunctionDecl that corresponds to extern NSString *someFunction1(void) NS_RETURNS_NOT_RETAINED;:

// const FunctionDecl *decl;
CharSourceRange range = CharSourceRange::getCharRange(decl->getSourceRange());
LangOptions *opts = new LangOptions();
StringRef sourceText = Lexer::getSourceText(range, *sourceManager, *opts);

The sourceText that I get back is an empty string. For other, non-macro FunctionDecl nodes that I tried (specifically ones with bodies), I seem to get the right thing, though the closing curly braces often appears to be missing.

Also sourceManager->getFilename(decl->getSourceRange().getEnd()) prints out the empty string whereas sourceManager->getFilename(decl->getSourceRange().getBegin()) prints out the filename. This isn’t true for other Decls that do not involve macros.

I may just have incorrect expectations for SourceRange.

+argyrios

+argyrios

It should be:

Also note that I think we don’t keep track of the semicolon at the end of the FunctionDecl.

-Argyrios