Skip to content

Commit dd65b90

Browse files
committed
go back to the hacky string manipulation
on-behalf-of: @amd <[email protected]>
1 parent 51aa182 commit dd65b90

File tree

1 file changed

+26
-96
lines changed

1 file changed

+26
-96
lines changed

clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp

Lines changed: 26 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -20,45 +20,6 @@ AST_MATCHER(LambdaExpr, hasDefaultCapture) {
2020
return Node.getCaptureDefault() != LCD_None;
2121
}
2222

23-
// Find the source range of the default capture token (= or &)
24-
SourceRange getDefaultCaptureRange(const LambdaExpr *Lambda,
25-
const SourceManager &SM,
26-
const LangOptions &LangOpts) {
27-
SourceLocation DefaultLoc = Lambda->getCaptureDefaultLoc();
28-
if (DefaultLoc.isInvalid())
29-
return SourceRange();
30-
31-
// The default capture is a single token
32-
SourceLocation EndLoc =
33-
Lexer::getLocForEndOfToken(DefaultLoc, 0, SM, LangOpts);
34-
return SourceRange(DefaultLoc, EndLoc);
35-
}
36-
37-
// Find where to insert implicit captures
38-
SourceLocation getImplicitCaptureInsertionLoc(const LambdaExpr *Lambda,
39-
const SourceManager &SM,
40-
const LangOptions &LangOpts) {
41-
// If there are explicit captures, insert after the last one
42-
if (Lambda->explicit_capture_begin() != Lambda->explicit_capture_end()) {
43-
// Find the location after the last explicit capture
44-
const auto *LastExplicit = Lambda->explicit_capture_end() - 1;
45-
SourceLocation LastLoc = LastExplicit->getLocation();
46-
if (LastLoc.isValid()) {
47-
return Lexer::getLocForEndOfToken(LastLoc, 0, SM, LangOpts);
48-
}
49-
}
50-
51-
// If no explicit captures, insert after the default capture
52-
SourceLocation DefaultLoc = Lambda->getCaptureDefaultLoc();
53-
if (DefaultLoc.isValid()) {
54-
return Lexer::getLocForEndOfToken(DefaultLoc, 0, SM, LangOpts);
55-
}
56-
57-
// Fallback: insert at the beginning of the capture list
58-
return Lambda->getIntroducerRange().getBegin().getLocWithOffset(1);
59-
}
60-
61-
// Generate the text for an implicit capture
6223
std::optional<std::string>
6324
generateImplicitCaptureText(const LambdaCapture &Capture) {
6425
if (Capture.capturesThis()) {
@@ -74,15 +35,13 @@ generateImplicitCaptureText(const LambdaCapture &Capture) {
7435
return Result;
7536
}
7637

77-
// TODO: handle VLAs and other weird captures
78-
return std::nullopt;
79-
}
38+
if (Capture.capturesVLAType()) {
39+
// VLA captures are rare and complex - for now we skip them
40+
// A full implementation would need to handle the VLA type properly
41+
return std::nullopt;
42+
}
8043

81-
// Check if we need a comma before inserting captures
82-
bool needsCommaBefore(const LambdaExpr *Lambda, SourceLocation InsertLoc,
83-
const SourceManager &SM, const LangOptions &LangOpts) {
84-
// If there are explicit captures, we need a comma
85-
return Lambda->explicit_capture_begin() != Lambda->explicit_capture_end();
44+
return std::nullopt;
8645
}
8746

8847
} // namespace
@@ -96,9 +55,6 @@ void AvoidDefaultLambdaCaptureCheck::check(
9655
const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
9756
assert(Lambda);
9857

99-
const SourceManager &SM = *Result.SourceManager;
100-
const LangOptions &LangOpts = Result.Context->getLangOpts();
101-
10258
const SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc();
10359
if (DefaultCaptureLoc.isInvalid())
10460
return;
@@ -107,61 +63,35 @@ void AvoidDefaultLambdaCaptureCheck::check(
10763
"lambda default captures are discouraged; "
10864
"prefer to capture specific variables explicitly");
10965

110-
// Get the range of the default capture token to remove
111-
SourceRange DefaultRange = getDefaultCaptureRange(Lambda, SM, LangOpts);
112-
if (!DefaultRange.isValid())
113-
return;
66+
// Build the complete replacement capture list
67+
std::vector<std::string> AllCaptures;
11468

115-
// Collect all implicit captures that need to be made explicit
116-
std::vector<std::string> ImplicitCaptureTexts;
117-
for (const auto &Capture : Lambda->implicit_captures()) {
69+
// Add explicit captures first (preserve their order)
70+
for (const auto &Capture : Lambda->explicit_captures()) {
11871
if (const auto CaptureText = generateImplicitCaptureText(Capture)) {
119-
ImplicitCaptureTexts.push_back(CaptureText.value());
72+
AllCaptures.push_back(CaptureText.value());
12073
}
12174
}
12275

123-
// If there are no implicit captures, just remove the default capture
124-
if (ImplicitCaptureTexts.empty()) {
125-
// Also remove any trailing comma if it exists
126-
SourceLocation AfterDefault = DefaultRange.getEnd();
127-
SourceLocation CommaLoc = Lexer::findLocationAfterToken(
128-
AfterDefault, tok::comma, SM, LangOpts, false);
129-
130-
if (CommaLoc.isValid()) {
131-
// Remove default capture and the comma
132-
SourceRange RemovalRange(DefaultRange.getBegin(), CommaLoc);
133-
Diag << FixItHint::CreateRemoval(RemovalRange);
134-
} else {
135-
// Just remove the default capture
136-
Diag << FixItHint::CreateRemoval(DefaultRange);
76+
// Add implicit captures (convert to explicit)
77+
for (const auto &Capture : Lambda->implicit_captures()) {
78+
if (const auto CaptureText = generateImplicitCaptureText(Capture)) {
79+
AllCaptures.push_back(CaptureText.value());
13780
}
138-
return;
13981
}
14082

141-
// Find where to insert the implicit captures
142-
SourceLocation InsertLoc =
143-
getImplicitCaptureInsertionLoc(Lambda, SM, LangOpts);
144-
if (!InsertLoc.isValid())
145-
return;
146-
147-
// Apply the transformations:
148-
// 1. Remove the default capture
149-
Diag << FixItHint::CreateRemoval(DefaultRange);
150-
151-
// 2. Insert the explicit captures if any
152-
if (!ImplicitCaptureTexts.empty()) {
153-
// Build the insertion text for implicit captures
154-
std::string InsertionText;
155-
bool NeedsComma = needsCommaBefore(Lambda, InsertLoc, SM, LangOpts);
156-
157-
for (size_t I = 0; I < ImplicitCaptureTexts.size(); ++I) {
158-
if (NeedsComma || I > 0) {
159-
InsertionText += ", ";
160-
}
161-
InsertionText += ImplicitCaptureTexts[I];
162-
}
83+
// Build the final capture list
84+
std::string ReplacementText;
85+
if (AllCaptures.empty()) {
86+
ReplacementText = "[]";
87+
} else {
88+
ReplacementText = "[" + llvm::join(AllCaptures, ", ") + "]";
89+
}
16390

164-
Diag << FixItHint::CreateInsertion(InsertLoc, InsertionText);
91+
// Replace the entire capture list with the explicit version
92+
SourceRange IntroducerRange = Lambda->getIntroducerRange();
93+
if (IntroducerRange.isValid()) {
94+
Diag << FixItHint::CreateReplacement(IntroducerRange, ReplacementText);
16595
}
16696
}
16797

0 commit comments

Comments
 (0)