@@ -20,45 +20,6 @@ AST_MATCHER(LambdaExpr, hasDefaultCapture) {
20
20
return Node.getCaptureDefault () != LCD_None;
21
21
}
22
22
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
62
23
std::optional<std::string>
63
24
generateImplicitCaptureText (const LambdaCapture &Capture) {
64
25
if (Capture.capturesThis ()) {
@@ -74,15 +35,13 @@ generateImplicitCaptureText(const LambdaCapture &Capture) {
74
35
return Result;
75
36
}
76
37
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
+ }
80
43
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 ;
86
45
}
87
46
88
47
} // namespace
@@ -96,9 +55,6 @@ void AvoidDefaultLambdaCaptureCheck::check(
96
55
const auto *Lambda = Result.Nodes .getNodeAs <LambdaExpr>(" lambda" );
97
56
assert (Lambda);
98
57
99
- const SourceManager &SM = *Result.SourceManager ;
100
- const LangOptions &LangOpts = Result.Context ->getLangOpts ();
101
-
102
58
const SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc ();
103
59
if (DefaultCaptureLoc.isInvalid ())
104
60
return ;
@@ -107,61 +63,35 @@ void AvoidDefaultLambdaCaptureCheck::check(
107
63
" lambda default captures are discouraged; "
108
64
" prefer to capture specific variables explicitly" );
109
65
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;
114
68
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 ()) {
118
71
if (const auto CaptureText = generateImplicitCaptureText (Capture)) {
119
- ImplicitCaptureTexts .push_back (CaptureText.value ());
72
+ AllCaptures .push_back (CaptureText.value ());
120
73
}
121
74
}
122
75
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 ());
137
80
}
138
- return ;
139
81
}
140
82
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
+ }
163
90
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);
165
95
}
166
96
}
167
97
0 commit comments