I'm working on a clang-tidy checker to spot some problematic idioms in a large codebase. I need to look at constant-size arrays declared in structs, and determine whether the size was given as an integer literal, or if the size results from a macro expansion.
For example, in this code:
#define ARRSZ 392
typedef struct Foo {
int a;
int litsz[392];
int macsz[ARRSZ];
} Foo;
Both of the fields litsz
and macsz
have the same size (392). However, my checker needs to treat them differently. In the AST, of course, after preprocessing is done, these FieldDecls appear identical in every respect. Somehow, I have to use the preprocessor to distinguish these.
One way I'm pretty sure would work is to register a preprocessor callback, and cache the SourceLocation for every macro expansion that occurs. Then, when I'm looking at the fields, I can get the SourceLocation of the size Expr, and try to find that location in my cache of macro expansions. If I find the location, it's a macro expansion, and if I don't, it's not. While I think I could get that to work, it seems horribly inefficient.
I tried doing this without building a cache of all macro expansions, by getting the SourceLocation of the size Expr, and then calling Preprocessor::isAtStartOfMacroExpansion()
. But that triggers an assertion for litsz
-- apparently, one can only use that method of the Preprocessor if you already know you have a Macro. Same with Preprocessor::getImmediateMacroName()
...
How can I do this efficiently? (And, ideally, simply...)