blob: 47f563ba6ef9316ba02c655f45bc87a8b75610f8 [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>
Jonas Toth74f201c2018-10-22 20:29:15 +000016#include <cctype>
Jonas Toth552b62e2018-10-22 19:20:01 +000017
18namespace clang {
19namespace tidy {
20namespace cppcoreguidelines {
21
22namespace {
23
24bool 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
32class MacroUsageCallbacks : public PPCallbacks {
33public:
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
50private:
51 MacroUsageCheck *Check;
52 StringRef RegExp;
53 bool CheckCapsOnly;
54};
55} // namespace
56
57void MacroUsageCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
58 Options.store(Opts, "AllowedRegexp", AllowedRegexp);
59 Options.store(Opts, "CheckCapsOnly", CheckCapsOnly);
60}
61
62void 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
71void 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
89void 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