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