1 //===--- MacroUsageCheck.cpp - clang-tidy----------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "MacroUsageCheck.h" 11 #include "clang/Frontend/CompilerInstance.h" 12 #include "clang/Lex/PPCallbacks.h" 13 #include "llvm/ADT/STLExtras.h" 14 #include "llvm/Support/Regex.h" 15 #include <algorithm> 16 #include <cctype> 17 18 namespace clang { 19 namespace tidy { 20 namespace cppcoreguidelines { 21 22 namespace { 23 24 bool isCapsOnly(StringRef Name) { 25 return std::all_of(Name.begin(), Name.end(), [](const char c) { 26 if (std::isupper(c) || std::isdigit(c) || c == '_') 27 return true; 28 return false; 29 }); 30 } 31 32 class MacroUsageCallbacks : public PPCallbacks { 33 public: 34 MacroUsageCallbacks(MacroUsageCheck *Check, StringRef RegExp, bool CapsOnly) 35 : Check(Check), RegExp(RegExp), CheckCapsOnly(CapsOnly) {} 36 void MacroDefined(const Token &MacroNameTok, 37 const MacroDirective *MD) override { 38 if (MD->getMacroInfo()->isUsedForHeaderGuard() || 39 MD->getMacroInfo()->getNumTokens() == 0) 40 return; 41 42 StringRef MacroName = MacroNameTok.getIdentifierInfo()->getName(); 43 if (!CheckCapsOnly && !llvm::Regex(RegExp).match(MacroName)) 44 Check->warnMacro(MD); 45 46 if (CheckCapsOnly && !isCapsOnly(MacroName)) 47 Check->warnNaming(MD); 48 } 49 50 private: 51 MacroUsageCheck *Check; 52 StringRef RegExp; 53 bool CheckCapsOnly; 54 }; 55 } // namespace 56 57 void MacroUsageCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { 58 Options.store(Opts, "AllowedRegexp", AllowedRegexp); 59 Options.store(Opts, "CheckCapsOnly", CheckCapsOnly); 60 } 61 62 void MacroUsageCheck::registerPPCallbacks(CompilerInstance &Compiler) { 63 if (!getLangOpts().CPlusPlus11) 64 return; 65 66 Compiler.getPreprocessor().addPPCallbacks( 67 llvm::make_unique<MacroUsageCallbacks>(this, AllowedRegexp, 68 CheckCapsOnly)); 69 } 70 71 void MacroUsageCheck::warnMacro(const MacroDirective *MD) { 72 StringRef Message = 73 "macro used to declare a constant; consider using a 'constexpr' " 74 "constant"; 75 76 /// A variadic macro is function-like at the same time. Therefore variadic 77 /// macros are checked first and will be excluded for the function-like 78 /// diagnostic. 79 if (MD->getMacroInfo()->isVariadic()) 80 Message = "variadic macro used; consider using a 'constexpr' " 81 "variadic template function"; 82 else if (MD->getMacroInfo()->isFunctionLike()) 83 Message = "function-like macro used; consider a 'constexpr' template " 84 "function"; 85 86 diag(MD->getLocation(), Message); 87 } 88 89 void MacroUsageCheck::warnNaming(const MacroDirective *MD) { 90 diag(MD->getLocation(), "macro definition does not define the macro name " 91 "using all uppercase characters"); 92 } 93 94 } // namespace cppcoreguidelines 95 } // namespace tidy 96 } // namespace clang 97