diff options
author | Daniel Marjamaki <daniel.marjamaki@evidente.se> | 2015-06-17 14:19:35 +0000 |
---|---|---|
committer | Daniel Marjamaki <daniel.marjamaki@evidente.se> | 2015-06-17 14:19:35 +0000 |
commit | 71c9257f0781dcaf56462071b5107e11e937271f (patch) | |
tree | 7905bb9ba5641e5af20b65213573bda6531cc2d7 /clang-tools-extra/clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp | |
parent | b19f5cfee6cef30eed9d6b384dba8294c53690e5 (diff) | |
download | bcm5719-llvm-71c9257f0781dcaf56462071b5107e11e937271f.tar.gz bcm5719-llvm-71c9257f0781dcaf56462071b5107e11e937271f.zip |
clang-tidy: Add checker that warn when macro argument with side effects is repeated in the macro
llvm-svn: 239909
Diffstat (limited to 'clang-tools-extra/clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp b/clang-tools-extra/clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp new file mode 100644 index 00000000000..4e601642634 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp @@ -0,0 +1,143 @@ +//===--- MacroRepeatedSideEffectsCheck.cpp - clang-tidy--------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MacroRepeatedSideEffectsCheck.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/MacroArgs.h" + +namespace clang { +namespace tidy { +namespace misc { + +namespace { +class MacroRepeatedPPCallbacks : public PPCallbacks { +public: + MacroRepeatedPPCallbacks(ClangTidyCheck &Check, SourceManager &SM, + Preprocessor &PP) + : Check(Check), SM(SM), PP(PP) {} + + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override; + +private: + ClangTidyCheck &Check; + SourceManager &SM; + Preprocessor &PP; + + unsigned CountArgumentExpansions(const MacroInfo *MI, + const IdentifierInfo *Arg) const; + + bool HasSideEffects(const Token *ResultArgToks) const; +}; +} // namespace + +void MacroRepeatedPPCallbacks::MacroExpands(const Token &MacroNameTok, + const MacroDefinition &MD, + SourceRange Range, + const MacroArgs *Args) { + // Ignore macro argument expansions. + if (!Range.getBegin().isFileID()) + return; + + const MacroInfo *MI = MD.getMacroInfo(); + + // Bail out if the contents of the macro are containing keywords that are + // making the macro too complex. + if (std::find_if( + MI->tokens().begin(), MI->tokens().end(), [](const Token &T) { + return T.isOneOf(tok::question, tok::kw_if, tok::kw_else, + tok::kw_switch, tok::kw_case, tok::kw_break, + tok::kw_while, tok::kw_do, tok::kw_for, + tok::kw_continue, tok::kw_goto, tok::kw_return); + }) != MI->tokens().end()) + return; + + for (unsigned ArgNo = 0U; ArgNo < MI->getNumArgs(); ++ArgNo) { + const IdentifierInfo *Arg = *(MI->arg_begin() + ArgNo); + const Token *ResultArgToks = Args->getUnexpArgument(ArgNo); + + if (HasSideEffects(ResultArgToks) && + CountArgumentExpansions(MI, Arg) >= 2) { + Check.diag(ResultArgToks->getLocation(), + "side effects in the %ordinal0 macro argument '%1' are " + "repeated in macro expansion") + << (ArgNo + 1) << Arg->getName(); + Check.diag(MI->getDefinitionLoc(), "macro %0 defined here", + DiagnosticIDs::Note) + << MacroNameTok.getIdentifierInfo(); + } + } +} + +unsigned MacroRepeatedPPCallbacks::CountArgumentExpansions( + const MacroInfo *MI, const IdentifierInfo *Arg) const { + unsigned CountInMacro = 0; + bool SkipParen = false; + int SkipParenCount = 0; + for (const auto &T : MI->tokens()) { + // If current token is a parenthesis, skip it. + if (SkipParen) { + if (T.is(tok::l_paren)) + SkipParenCount++; + else if (T.is(tok::r_paren)) + SkipParenCount--; + SkipParen = (SkipParenCount != 0); + if (SkipParen) + continue; + } + + IdentifierInfo *TII = T.getIdentifierInfo(); + // If not existent, skip it. + if (TII == nullptr) + continue; + + // If a builtin is found within the macro definition, skip next + // parenthesis. + if (TII->getBuiltinID() != 0) { + SkipParen = true; + continue; + } + + // If another macro is found within the macro definition, skip the macro + // and the eventual arguments. + if (TII->hasMacroDefinition()) { + const MacroInfo *M = PP.getMacroDefinition(TII).getMacroInfo(); + if (M != nullptr && M->isFunctionLike()) + SkipParen = true; + continue; + } + + // Count argument. + if (TII == Arg) + CountInMacro++; + } + return CountInMacro; +} + +bool MacroRepeatedPPCallbacks::HasSideEffects( + const Token *ResultArgToks) const { + for (; ResultArgToks->isNot(tok::eof); ++ResultArgToks) { + if (ResultArgToks->isOneOf(tok::plusplus, tok::minusminus)) + return true; + } + return false; +} + +void MacroRepeatedSideEffectsCheck::registerPPCallbacks( + CompilerInstance &Compiler) { + Compiler.getPreprocessor().addPPCallbacks( + ::llvm::make_unique<MacroRepeatedPPCallbacks>( + *this, Compiler.getSourceManager(), Compiler.getPreprocessor())); +} + +} // namespace misc +} // namespace tidy +} // namespace clang |