xref: /llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/MacroUsageCheck.cpp (revision 552b62ed1f24dfbed4b5ee733415572ead5b228e)
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