clang-tools 3.8.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

MacroRepeatedSideEffectsCheck.cpp
Go to the documentation of this file.
1 //===--- MacroRepeatedSideEffectsCheck.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 "MacroRepeatedSideEffectsCheck.h"
11 #include "clang/Frontend/CompilerInstance.h"
12 #include "clang/Lex/PPCallbacks.h"
13 #include "clang/Lex/Preprocessor.h"
14 #include "clang/Lex/MacroArgs.h"
15
16 namespace clang {
17 namespace tidy {
18 namespace misc {
19
20 namespace {
21 class MacroRepeatedPPCallbacks : public PPCallbacks {
22 public:
23 MacroRepeatedPPCallbacks(ClangTidyCheck &Check, Preprocessor &PP)
24 : Check(Check), PP(PP) {}
25
26 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
27 SourceRange Range, const MacroArgs *Args) override;
28
29 private:
30 ClangTidyCheck &Check;
31 Preprocessor &PP;
32
33 unsigned countArgumentExpansions(const MacroInfo *MI,
34 const IdentifierInfo *Arg) const;
35
36 bool hasSideEffects(const Token *ResultArgToks) const;
37 };
38 } // End of anonymous namespace.
39
40 void MacroRepeatedPPCallbacks::MacroExpands(const Token &MacroNameTok,
41 const MacroDefinition &MD,
42 SourceRange Range,
43 const MacroArgs *Args) {
44 // Ignore macro argument expansions.
45 if (!Range.getBegin().isFileID())
46 return;
47
48 const MacroInfo *MI = MD.getMacroInfo();
49
50 // Bail out if the contents of the macro are containing keywords that are
51 // making the macro too complex.
52 if (std::find_if(
53 MI->tokens().begin(), MI->tokens().end(), [](const Token &T) {
54 return T.isOneOf(tok::kw_if, tok::kw_else, tok::kw_switch,
55 tok::kw_case, tok::kw_break, tok::kw_while,
56 tok::kw_do, tok::kw_for, tok::kw_continue,
57 tok::kw_goto, tok::kw_return);
58 }) != MI->tokens().end())
59 return;
60
61 for (unsigned ArgNo = 0U; ArgNo < MI->getNumArgs(); ++ArgNo) {
62 const IdentifierInfo *Arg = *(MI->arg_begin() + ArgNo);
63 const Token *ResultArgToks = Args->getUnexpArgument(ArgNo);
64
65 if (hasSideEffects(ResultArgToks) &&
66 countArgumentExpansions(MI, Arg) >= 2) {
67 Check.diag(ResultArgToks->getLocation(),
68 "side effects in the %ordinal0 macro argument '%1' are "
69 "repeated in macro expansion")
70 << (ArgNo + 1) << Arg->getName();
71 Check.diag(MI->getDefinitionLoc(), "macro %0 defined here",
72 DiagnosticIDs::Note)
73 << MacroNameTok.getIdentifierInfo();
74 }
75 }
76 }
77
78 unsigned MacroRepeatedPPCallbacks::countArgumentExpansions(
79 const MacroInfo *MI, const IdentifierInfo *Arg) const {
80 // Current argument count. When moving forward to a different control-flow
81 // path this can decrease.
82 unsigned Current = 0;
83 // Max argument count.
84 unsigned Max = 0;
85 bool SkipParen = false;
86 int SkipParenCount = 0;
87 // Has a __builtin_constant_p been found?
88 bool FoundBuiltin = false;
89 // Count when "?" is reached. The "Current" will get this value when the ":"
90 // is reached.
91 std::stack<unsigned, SmallVector<unsigned, 8>> CountAtQuestion;
92 for (const auto &T : MI->tokens()) {
93 // The result of __builtin_constant_p(x) is 0 if x is a macro argument
94 // with side effects. If we see a __builtin_constant_p(x) followed by a
95 // "?" "&&" or "||", then we need to reason about control flow to report
96 // warnings correctly. Until such reasoning is added, bail out when this
97 // happens.
98 if (FoundBuiltin && T.isOneOf(tok::question, tok::ampamp, tok::pipepipe))
99 return Max;
100
101 // Handling of ? and :.
102 if (T.is(tok::question)) {
103 CountAtQuestion.push(Current);
104 } else if (T.is(tok::colon)) {
105 if (CountAtQuestion.empty())
106 return 0;
107 Current = CountAtQuestion.top();
108 CountAtQuestion.pop();
109 }
110
111 // If current token is a parenthesis, skip it.
112 if (SkipParen) {
113 if (T.is(tok::l_paren))
114 SkipParenCount++;
115 else if (T.is(tok::r_paren))
116 SkipParenCount--;
117 SkipParen = (SkipParenCount != 0);
118 if (SkipParen)
119 continue;
120 }
121
122 IdentifierInfo *TII = T.getIdentifierInfo();
123 // If not existent, skip it.
124 if (TII == nullptr)
125 continue;
126
127 // If a __builtin_constant_p is found within the macro definition, don't
128 // count arguments inside the parentheses and remember that it has been
129 // seen in case there are "?", "&&" or "||" operators later.
130 if (TII->getBuiltinID() == Builtin::BI__builtin_constant_p) {
131 FoundBuiltin = true;
132 SkipParen = true;
133 continue;
134 }
135
136 // If another macro is found within the macro definition, skip the macro
137 // and the eventual arguments.
138 if (TII->hasMacroDefinition()) {
139 const MacroInfo *M = PP.getMacroDefinition(TII).getMacroInfo();
140 if (M != nullptr && M->isFunctionLike())
141 SkipParen = true;
142 continue;
143 }
144
145 // Count argument.
146 if (TII == Arg) {
147 Current++;
148 if (Current > Max)
149 Max = Current;
150 }
151 }
152 return Max;
153 }
154
155 bool MacroRepeatedPPCallbacks::hasSideEffects(
156 const Token *ResultArgToks) const {
157 for (; ResultArgToks->isNot(tok::eof); ++ResultArgToks) {
158 if (ResultArgToks->isOneOf(tok::plusplus, tok::minusminus))
159 return true;
160 }
161 return false;
162 }
163
164 void MacroRepeatedSideEffectsCheck::registerPPCallbacks(
165 CompilerInstance &Compiler) {
166 Compiler.getPreprocessor().addPPCallbacks(
167 ::llvm::make_unique<MacroRepeatedPPCallbacks>(
168 *this, Compiler.getPreprocessor()));
169 }
170
171 } // namespace misc
172 } // namespace tidy
173 } // namespace clang
MacroRepeatedSideEffectsCheck.h
clang::tidy::misc::MacroRepeatedSideEffectsCheck::registerPPCallbacks
void registerPPCallbacks(CompilerInstance &Compiler) override
Override this to register PPCallbacks with Compiler.
Definition: MacroRepeatedSideEffectsCheck.cpp:164
PP
Preprocessor & PP
Definition: MacroRepeatedSideEffectsCheck.cpp:31
PPCallbacks
Check
ClangTidyCheck & Check
Definition: MacroRepeatedSideEffectsCheck.cpp:30
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:35