blob: 8b893c7c4ab9f83e284497b1d69c05488a31753c [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:
Roman Lebedevc367ba12018-10-30 15:52:36 +000034 MacroUsageCallbacks(MacroUsageCheck *Check, const SourceManager &SM,
35 StringRef RegExp, bool CapsOnly, bool IgnoreCommandLine)
36 : Check(Check), SM(SM), RegExp(RegExp), CheckCapsOnly(CapsOnly),
37 IgnoreCommandLineMacros(IgnoreCommandLine) {}
Jonas Toth552b62e2018-10-22 19:20:01 +000038 void MacroDefined(const Token &MacroNameTok,
39 const MacroDirective *MD) override {
40 if (MD->getMacroInfo()->isUsedForHeaderGuard() ||
41 MD->getMacroInfo()->getNumTokens() == 0)
42 return;
43
Roman Lebedevc367ba12018-10-30 15:52:36 +000044 if (IgnoreCommandLineMacros &&
45 SM.isWrittenInCommandLineFile(MD->getLocation()))
46 return;
47
Jonas Toth552b62e2018-10-22 19:20:01 +000048 StringRef MacroName = MacroNameTok.getIdentifierInfo()->getName();
49 if (!CheckCapsOnly && !llvm::Regex(RegExp).match(MacroName))
Roman Lebedevc367ba12018-10-30 15:52:36 +000050 Check->warnMacro(MD, MacroName);
Jonas Toth552b62e2018-10-22 19:20:01 +000051
52 if (CheckCapsOnly && !isCapsOnly(MacroName))
Roman Lebedevc367ba12018-10-30 15:52:36 +000053 Check->warnNaming(MD, MacroName);
Jonas Toth552b62e2018-10-22 19:20:01 +000054 }
55
56private:
57 MacroUsageCheck *Check;
Roman Lebedevc367ba12018-10-30 15:52:36 +000058 const SourceManager &SM;
Jonas Toth552b62e2018-10-22 19:20:01 +000059 StringRef RegExp;
60 bool CheckCapsOnly;
Roman Lebedevc367ba12018-10-30 15:52:36 +000061 bool IgnoreCommandLineMacros;
Jonas Toth552b62e2018-10-22 19:20:01 +000062};
63} // namespace
64
65void MacroUsageCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
66 Options.store(Opts, "AllowedRegexp", AllowedRegexp);
67 Options.store(Opts, "CheckCapsOnly", CheckCapsOnly);
Roman Lebedevc367ba12018-10-30 15:52:36 +000068 Options.store(Opts, "IgnoreCommandLineMacros", IgnoreCommandLineMacros);
Jonas Toth552b62e2018-10-22 19:20:01 +000069}
70
71void MacroUsageCheck::registerPPCallbacks(CompilerInstance &Compiler) {
72 if (!getLangOpts().CPlusPlus11)
73 return;
74
75 Compiler.getPreprocessor().addPPCallbacks(
Roman Lebedevc367ba12018-10-30 15:52:36 +000076 llvm::make_unique<MacroUsageCallbacks>(this, Compiler.getSourceManager(),
77 AllowedRegexp, CheckCapsOnly,
78 IgnoreCommandLineMacros));
Jonas Toth552b62e2018-10-22 19:20:01 +000079}
80
Roman Lebedevc367ba12018-10-30 15:52:36 +000081void MacroUsageCheck::warnMacro(const MacroDirective *MD, StringRef MacroName) {
Jonas Toth552b62e2018-10-22 19:20:01 +000082 StringRef Message =
Roman Lebedevc367ba12018-10-30 15:52:36 +000083 "macro '%0' used to declare a constant; consider using a 'constexpr' "
Jonas Toth552b62e2018-10-22 19:20:01 +000084 "constant";
85
86 /// A variadic macro is function-like at the same time. Therefore variadic
87 /// macros are checked first and will be excluded for the function-like
88 /// diagnostic.
89 if (MD->getMacroInfo()->isVariadic())
Roman Lebedevc367ba12018-10-30 15:52:36 +000090 Message = "variadic macro '%0' used; consider using a 'constexpr' "
Jonas Toth552b62e2018-10-22 19:20:01 +000091 "variadic template function";
92 else if (MD->getMacroInfo()->isFunctionLike())
Roman Lebedevc367ba12018-10-30 15:52:36 +000093 Message = "function-like macro '%0' used; consider a 'constexpr' template "
Jonas Toth552b62e2018-10-22 19:20:01 +000094 "function";
95
Roman Lebedevc367ba12018-10-30 15:52:36 +000096 diag(MD->getLocation(), Message) << MacroName;
Jonas Toth552b62e2018-10-22 19:20:01 +000097}
98
Roman Lebedevc367ba12018-10-30 15:52:36 +000099void MacroUsageCheck::warnNaming(const MacroDirective *MD,
100 StringRef MacroName) {
Jonas Toth552b62e2018-10-22 19:20:01 +0000101 diag(MD->getLocation(), "macro definition does not define the macro name "
Roman Lebedevc367ba12018-10-30 15:52:36 +0000102 "'%0' using all uppercase characters")
103 << MacroName;
Jonas Toth552b62e2018-10-22 19:20:01 +0000104}
105
106} // namespace cppcoreguidelines
107} // namespace tidy
108} // namespace clang