blob: 5791fd0bf1d0f3cfcb8289808c456418362858ba [file] [log] [blame]
Jonas Toth552b62e2018-10-22 19:20:01 +00001//===--- 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
17namespace clang {
18namespace tidy {
19namespace cppcoreguidelines {
20
21namespace {
22
23bool 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
31class MacroUsageCallbacks : public PPCallbacks {
32public:
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
49private:
50 MacroUsageCheck *Check;
51 StringRef RegExp;
52 bool CheckCapsOnly;
53};
54} // namespace
55
56void MacroUsageCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
57 Options.store(Opts, "AllowedRegexp", AllowedRegexp);
58 Options.store(Opts, "CheckCapsOnly", CheckCapsOnly);
59}
60
61void 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
70void 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
88void 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