Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Differential D141133 Diff 487084 clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCaptureThisWithCaptureDefaultCheck.cpp
Changeset View
Changeset View
Standalone View
Standalone View
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCaptureThisWithCaptureDefaultCheck.cpp
- This file was added.
//===--- AvoidCaptureThisWithCaptureDefaultCheck.cpp - clang-tidy ---------===// | |||||
Lint: Lint: clang-format not found in user’s local PATH; not linting file. | |||||
// | |||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||||
// See https://llvm.org/LICENSE.txt for license information. | |||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||||
// | |||||
//===----------------------------------------------------------------------===// | |||||
#include "AvoidCaptureThisWithCaptureDefaultCheck.h" | |||||
#include "../utils/LexerUtils.h" | |||||
#include "clang/AST/ASTContext.h" | |||||
#include "clang/ASTMatchers/ASTMatchFinder.h" | |||||
#include "llvm/Support/raw_ostream.h" | |||||
using namespace clang::ast_matchers; | |||||
namespace clang { | |||||
namespace tidy { | |||||
namespace cppcoreguidelines { | |||||
void AvoidCaptureThisWithCaptureDefaultCheck::registerMatchers( | |||||
MatchFinder *Finder) { | |||||
Finder->addMatcher(lambdaExpr(hasAnyCapture(capturesThis())).bind("lambda"), | |||||
this); | |||||
} | |||||
static SourceLocation findDefaultCaptureEnd(const LambdaExpr *Lambda, | |||||
ASTContext &Context) { | |||||
for (const LambdaCapture &Capture : Lambda->explicit_captures()) { | |||||
if (Capture.isExplicit()) { | |||||
if (Capture.getCaptureKind() == LCK_ByRef) { | |||||
SourceManager &SourceMgr = Context.getSourceManager(); | |||||
SourceLocation AddressofLoc = utils::lexer::findPreviousTokenKind( | |||||
Should be const SourceManager &. Eugene.Zelenko: Should be `const SourceManager &`. | |||||
Capture.getLocation(), SourceMgr, Context.getLangOpts(), tok::amp); | |||||
llvm::errs() << "FOR REF capture loc= " | |||||
carlosgalvezpUnsubmitted Not Done ReplyInline ActionsNot having being involved in the development of this check I don't quite understand what this error message means, could you provide a more descriptive message? It's also unclear if the program is supposed to abort when entering this branch, or if it's expected that it returns just fine? If it's supposed to return just fine, I think the check should not print anything, to keep the users' logs clean. carlosgalvezp: Not having being involved in the development of this check I don't quite understand what this… | |||||
ccotterAuthorUnsubmitted My bad - I forgot to remove this trace. Both branches are valid branches for normal program execution. ccotter: My bad - I forgot to remove this trace. Both branches are valid branches for normal program… | |||||
<< Capture.getLocation().printToString(SourceMgr) | |||||
<< " addr=" << AddressofLoc.printToString(SourceMgr) | |||||
<< "\n"; | |||||
return AddressofLoc; | |||||
} else { | |||||
return Capture.getLocation(); | |||||
} | |||||
} | |||||
} | |||||
return Lambda->getIntroducerRange().getEnd(); | |||||
} | |||||
static std::string createReplacementText(const LambdaExpr *Lambda) { | |||||
std::string Replacement; | |||||
llvm::raw_string_ostream Stream(Replacement); | |||||
auto AppendName = [&](llvm::StringRef Name) { | |||||
if (Replacement.size() != 0) { | |||||
Stream << ", "; | |||||
} | |||||
if (Lambda->getCaptureDefault() == LCD_ByRef && Name != "this") { | |||||
Stream << "&" << Name; | |||||
} else { | |||||
Stream << Name; | |||||
} | |||||
}; | |||||
for (const LambdaCapture &Capture : Lambda->implicit_captures()) { | |||||
assert(Capture.isImplicit()); | |||||
if (Capture.capturesVariable() && Capture.isImplicit()) { | |||||
AppendName(Capture.getCapturedVar()->getName()); | |||||
} else if (Capture.capturesThis()) { | |||||
AppendName("this"); | |||||
} | |||||
} | |||||
if (Replacement.size() && | |||||
Lambda->explicit_capture_begin() != Lambda->explicit_capture_end()) { | |||||
// Add back separator if we are adding explicit capture variables. | |||||
Stream << ", "; | |||||
} | |||||
return Replacement; | |||||
} | |||||
void AvoidCaptureThisWithCaptureDefaultCheck::check( | |||||
const MatchFinder::MatchResult &Result) { | |||||
if (const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda")) { | |||||
if (Lambda->getCaptureDefault() != LCD_None) { | |||||
auto Diag = diag( | |||||
Lambda->getCaptureDefaultLoc(), | |||||
"lambdas that capture 'this' should not specify a capture default"); | |||||
std::string ReplacementText = createReplacementText(Lambda); | |||||
SourceLocation DefaultCaptureEnd = | |||||
findDefaultCaptureEnd(Lambda, *Result.Context); | |||||
Diag << FixItHint::CreateReplacement( | |||||
CharSourceRange::getCharRange(Lambda->getCaptureDefaultLoc(), | |||||
DefaultCaptureEnd), | |||||
ReplacementText); | |||||
} | |||||
} | |||||
} | |||||
} // namespace cppcoreguidelines | |||||
} // namespace tidy | |||||
} // namespace clang |
clang-format not found in user’s local PATH; not linting file.