diff options
author | Alexander Kornienko <alexfh@google.com> | 2017-11-24 14:16:29 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2017-11-24 14:16:29 +0000 |
commit | d4ac4afda75c9ef174e85eea7f40a6ae6cc50ab4 (patch) | |
tree | c43c0be034454ea297f0ccdc84302e9636abed63 /clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp | |
parent | 70cdb5b3914803ca89a96a867a47936d049a4b32 (diff) | |
download | bcm5719-llvm-d4ac4afda75c9ef174e85eea7f40a6ae6cc50ab4.tar.gz bcm5719-llvm-d4ac4afda75c9ef174e85eea7f40a6ae6cc50ab4.zip |
[clang-tidy] Move a few more checks from misc to bugprone.
Summary:
clang_tidy/rename_check.py misc-assert-side-effect bugprone-assert-side-effect
clang_tidy/rename_check.py misc-bool-pointer-implicit-conversion bugprone-bool-pointer-implicit-conversion
clang_tidy/rename_check.py misc-fold-init-type bugprone-fold-init-type
clang_tidy/rename_check.py misc-forward-declaration-namespace bugprone-forward-declaration-namespace
clang_tidy/rename_check.py misc-inaccurate-erase bugprone-inaccurate-erase
clang_tidy/rename_check.py misc-move-forwarding-reference bugprone-move-forwarding-reference
clang_tidy/rename_check.py misc-multiple-statement-macro bugprone-multiple-statement-macro
clang_tidy/rename_check.py misc-use-after-move bugprone-use-after-move
clang_tidy/rename_check.py misc-virtual-near-miss bugprone-virtual-near-miss
Manually fixed a reference to UseAfterMoveCheck in the hicpp module.
Manually fixed header guards.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nemanjai, mgorny, javed.absar, xazax.hun, kbarton, cfe-commits
Differential Revision: https://reviews.llvm.org/D40426
llvm-svn: 318950
Diffstat (limited to 'clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp new file mode 100644 index 00000000000..516ee193033 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp @@ -0,0 +1,133 @@ +//===--- MoveForwardingReferenceCheck.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 "MoveForwardingReferenceCheck.h" +#include "clang/Lex/Lexer.h" +#include "llvm/Support/raw_ostream.h" + +#include <algorithm> + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee, + const ParmVarDecl *ParmVar, + const TemplateTypeParmDecl *TypeParmDecl, + DiagnosticBuilder &Diag, + const ASTContext &Context) { + const SourceManager &SM = Context.getSourceManager(); + const LangOptions &LangOpts = Context.getLangOpts(); + + CharSourceRange CallRange = + Lexer::makeFileCharRange(CharSourceRange::getTokenRange( + Callee->getLocStart(), Callee->getLocEnd()), + SM, LangOpts); + + if (CallRange.isValid()) { + const std::string TypeName = + TypeParmDecl->getIdentifier() + ? TypeParmDecl->getName().str() + : (llvm::Twine("decltype(") + ParmVar->getName() + ")").str(); + + const std::string ForwardName = + (llvm::Twine("forward<") + TypeName + ">").str(); + + // Create a replacement only if we see a "standard" way of calling + // std::move(). This will hopefully prevent erroneous replacements if the + // code does unusual things (e.g. create an alias for std::move() in + // another namespace). + NestedNameSpecifier *NNS = Callee->getQualifier(); + if (!NNS) { + // Called as "move" (i.e. presumably the code had a "using std::move;"). + // We still conservatively put a "std::" in front of the forward because + // we don't know whether the code also had a "using std::forward;". + Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName); + } else if (const NamespaceDecl *Namespace = NNS->getAsNamespace()) { + if (Namespace->getName() == "std") { + if (!NNS->getPrefix()) { + // Called as "std::move". + Diag << FixItHint::CreateReplacement(CallRange, + "std::" + ForwardName); + } else if (NNS->getPrefix()->getKind() == NestedNameSpecifier::Global) { + // Called as "::std::move". + Diag << FixItHint::CreateReplacement(CallRange, + "::std::" + ForwardName); + } + } + } + } +} + +void MoveForwardingReferenceCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus11) + return; + + // Matches a ParmVarDecl for a forwarding reference, i.e. a non-const rvalue + // reference of a function template parameter type. + auto ForwardingReferenceParmMatcher = + parmVarDecl( + hasType(qualType(rValueReferenceType(), + references(templateTypeParmType(hasDeclaration( + templateTypeParmDecl().bind("type-parm-decl")))), + unless(references(qualType(isConstQualified())))))) + .bind("parm-var"); + + Finder->addMatcher( + callExpr(callee(unresolvedLookupExpr( + hasAnyDeclaration(namedDecl( + hasUnderlyingDecl(hasName("::std::move"))))) + .bind("lookup")), + argumentCountIs(1), + hasArgument(0, ignoringParenImpCasts(declRefExpr( + to(ForwardingReferenceParmMatcher))))) + .bind("call-move"), + this); +} + +void MoveForwardingReferenceCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move"); + const auto *UnresolvedLookup = + Result.Nodes.getNodeAs<UnresolvedLookupExpr>("lookup"); + const auto *ParmVar = Result.Nodes.getNodeAs<ParmVarDecl>("parm-var"); + const auto *TypeParmDecl = + Result.Nodes.getNodeAs<TemplateTypeParmDecl>("type-parm-decl"); + + // Get the FunctionDecl and FunctionTemplateDecl containing the function + // parameter. + const auto *FuncForParam = dyn_cast<FunctionDecl>(ParmVar->getDeclContext()); + if (!FuncForParam) + return; + const FunctionTemplateDecl *FuncTemplate = + FuncForParam->getDescribedFunctionTemplate(); + if (!FuncTemplate) + return; + + // Check that the template type parameter belongs to the same function + // template as the function parameter of that type. (This implies that type + // deduction will happen on the type.) + const TemplateParameterList *Params = FuncTemplate->getTemplateParameters(); + if (!std::count(Params->begin(), Params->end(), TypeParmDecl)) + return; + + auto Diag = diag(CallMove->getExprLoc(), + "forwarding reference passed to std::move(), which may " + "unexpectedly cause lvalues to be moved; use " + "std::forward() instead"); + + replaceMoveWithForward(UnresolvedLookup, ParmVar, TypeParmDecl, Diag, + *Result.Context); +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang |