I'm writing (my first) clang-tidy check. It should detect when macros define types, like:
#define MY_INT int
#define MY_STRING std::string
class MyClass {}
#define MY_CLASS MyClass
#define MY_INT_ARRAY std::array<int>
template <typename T> class MyTemplateClass {};
#define MY_TEMPLATE_TYPE MyTemplateClass<int>
The goal is to flag macros that define types and suggest using typedef or using instead.
I started using the existing cppcoreguidelines-macro-usage and stripped it down to only get the existing Macros via a registerPPCallbacks, which works fine. Since I figured out I need an ASTContext to process the type information, I also registered some random Matcher via registerMatchers(MatchFinder *Finder), so I'm able to get the ASTContext from Result.Context.
User-defined types like MyClass can now be detected using:
IdentifierInfo &II = Context->Idents.get(Identifier);
DeclContext::lookup_result Result = Context->getTranslationUnitDecl()->lookup(&II);
// Iterate through the lookup result to find a TypeDecl
for (NamedDecl *ND : Result) {
if (TypeDecl *TD = dyn_cast<TypeDecl>(ND)) {
return Context->getTypeDeclType(TD); // User-defined type!
}
}
Unfortunatley fhis approach fails for built-in types (int, uint8_t) and standard types (std::string, std::array<int>), where the lookup result is empty. For such types a tried to just use string comparisons, but I feel this is a very brittle approach:
if (Identifier == "int") return Context->IntTy;
if (Identifier == "float") return Context->FloatTy;
For more advanced types like the mentioned template classes or arrays I'm out of ideas...
Is there a robust way to detect if a macro defines a type (especially for built-in, standard, and template types). Any suggestions on improving this approach or other alternatives?