Skip to content

Commit f022a5a

Browse files
committed
Adds fixit hints to the -Wrange-loop-analysis
Differential Revision: https://reviews.llvm.org/D68913
1 parent 8dc7b98 commit f022a5a

File tree

4 files changed

+57
-3
lines changed

4 files changed

+57
-3
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ class DeclaratorDecl : public ValueDecl {
752752
ArrayRef<TemplateParameterList *> TPLists);
753753

754754
SourceLocation getTypeSpecStartLoc() const;
755+
SourceLocation getTypeSpecEndLoc() const;
755756

756757
// Implement isa/cast/dyncast/etc.
757758
static bool classof(const Decl *D) { return classofKind(D->getKind()); }

clang/lib/AST/Decl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,6 +1820,12 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
18201820
return SourceLocation();
18211821
}
18221822

1823+
SourceLocation DeclaratorDecl::getTypeSpecEndLoc() const {
1824+
TypeSourceInfo *TSI = getTypeSourceInfo();
1825+
if (TSI) return TSI->getTypeLoc().getEndLoc();
1826+
return SourceLocation();
1827+
}
1828+
18231829
void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
18241830
if (QualifierLoc) {
18251831
// Make sure the extended decl info is allocated.

clang/lib/Sema/SemaStmt.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2762,7 +2762,8 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
27622762
QualType NewReferenceType =
27632763
SemaRef.Context.getLValueReferenceType(E->getType().withConst());
27642764
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_type_or_non_reference)
2765-
<< NonReferenceType << NewReferenceType << VD->getSourceRange();
2765+
<< NonReferenceType << NewReferenceType << VD->getSourceRange()
2766+
<< FixItHint::CreateRemoval(VD->getTypeSpecEndLoc());
27662767
} else {
27672768
// The range always returns a copy, so a temporary is always created.
27682769
// Suggest removing the reference from the loop variable.
@@ -2771,7 +2772,8 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
27712772
QualType NonReferenceType = VariableType.getNonReferenceType();
27722773
NonReferenceType.removeLocalConst();
27732774
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_non_reference_type)
2774-
<< NonReferenceType << VD->getSourceRange();
2775+
<< NonReferenceType << VD->getSourceRange()
2776+
<< FixItHint::CreateRemoval(VD->getTypeSpecEndLoc());
27752777
}
27762778
}
27772779

@@ -2808,7 +2810,8 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
28082810
<< VD << VariableType << InitExpr->getType();
28092811
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_reference_type)
28102812
<< SemaRef.Context.getLValueReferenceType(VariableType)
2811-
<< VD->getSourceRange();
2813+
<< VD->getSourceRange()
2814+
<< FixItHint::CreateInsertion(VD->getLocation(), "&");
28122815
}
28132816

28142817
/// DiagnoseForRangeVariableCopies - Diagnose three cases and fixes for them.

clang/test/SemaCXX/warn-range-loop-analysis.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wloop-analysis -verify %s
22
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wrange-loop-analysis -verify %s
3+
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wloop-analysis -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
34

45
template <typename return_type>
56
struct Iterator {
@@ -67,14 +68,17 @@ void test0() {
6768
for (const int &x : int_non_ref_container) {}
6869
// expected-warning@-1 {{loop variable 'x' is always a copy because the range of type 'Container<int>' does not return a reference}}
6970
// expected-note@-2 {{use non-reference type 'int'}}
71+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
7072

7173
for (const double &x : int_container) {}
7274
// expected-warning@-1 {{loop variable 'x' has type 'const double &' but is initialized with type 'int' resulting in a copy}}
7375
// expected-note@-2 {{use non-reference type 'double' to keep the copy or type 'const int &' to prevent copying}}
76+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:22}:""
7477

7578
for (const Bar x : bar_container) {}
7679
// expected-warning@-1 {{loop variable 'x' of type 'const Bar' creates a copy from type 'const Bar'}}
7780
// expected-note@-2 {{use reference type 'const Bar &' to prevent copying}}
81+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:18}:"&"
7882
}
7983

8084
void test1() {
@@ -83,6 +87,7 @@ void test1() {
8387
for (const int &x : A) {}
8488
// expected-warning@-1 {{always a copy}}
8589
// expected-note@-2 {{'int'}}
90+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
8691
for (const int x : A) {}
8792
// No warning, non-reference type indicates copy is made
8893
//for (int &x : A) {}
@@ -93,6 +98,7 @@ void test1() {
9398
for (const double &x : A) {}
9499
// expected-warning@-1 {{always a copy}}
95100
// expected-note@-2 {{'double'}}
101+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:22}:""
96102
for (const double x : A) {}
97103
// No warning, non-reference type indicates copy is made
98104
//for (double &x : A) {}
@@ -103,6 +109,7 @@ void test1() {
103109
for (const Bar &x : A) {}
104110
// expected-warning@-1 {{always a copy}}
105111
// expected-note@-2 {{'Bar'}}
112+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
106113
for (const Bar x : A) {}
107114
// No warning, non-reference type indicates copy is made
108115
//for (Bar &x : A) {}
@@ -126,6 +133,7 @@ void test2() {
126133
for (const double &x : B) {}
127134
// expected-warning@-1 {{resulting in a copy}}
128135
// expected-note-re@-2 {{'double'{{.*}}'const int &'}}
136+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:21-[[@LINE-3]]:22}:""
129137
for (const double x : B) {}
130138
//for (double &x : B) {}
131139
// Binding error
@@ -135,6 +143,7 @@ void test2() {
135143
for (const Bar &x : B) {}
136144
// expected-warning@-1 {{resulting in a copy}}
137145
// expected-note@-2 {{'Bar'}}
146+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
138147
for (const Bar x : B) {}
139148
//for (Bar &x : B) {}
140149
// Binding error
@@ -148,6 +157,7 @@ void test3() {
148157
for (const Bar &x : C) {}
149158
// expected-warning@-1 {{always a copy}}
150159
// expected-note@-2 {{'Bar'}}
160+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
151161
for (const Bar x : C) {}
152162
// No warning, non-reference type indicates copy is made
153163
//for (Bar &x : C) {}
@@ -158,6 +168,7 @@ void test3() {
158168
for (const int &x : C) {}
159169
// expected-warning@-1 {{always a copy}}
160170
// expected-note@-2 {{'int'}}
171+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
161172
for (const int x : C) {}
162173
// No warning, copy made
163174
//for (int &x : C) {}
@@ -174,6 +185,7 @@ void test4() {
174185
for (const Bar x : D) {}
175186
// expected-warning@-1 {{creates a copy}}
176187
// expected-note@-2 {{'const Bar &'}}
188+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:18}:"&"
177189
for (Bar &x : D) {}
178190
// No warning
179191
for (Bar x : D) {}
@@ -182,6 +194,7 @@ void test4() {
182194
for (const int &x : D) {}
183195
// expected-warning@-1 {{resulting in a copy}}
184196
// expected-note-re@-2 {{'int'{{.*}}'const Bar &'}}
197+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
185198
for (const int x : D) {}
186199
// No warning
187200
//for (int &x : D) {}
@@ -196,6 +209,7 @@ void test5() {
196209
for (const Bar &x : E) {}
197210
// expected-warning@-1 {{always a copy}}
198211
// expected-note@-2 {{'Bar'}}
212+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
199213
for (const Bar x : E) {}
200214
// No warning, non-reference type indicates copy is made
201215
//for (Bar &x : E) {}
@@ -210,6 +224,7 @@ void test6() {
210224
for (const Bar &x : F) {}
211225
// expected-warning@-1 {{resulting in a copy}}
212226
// expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}}
227+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
213228
for (const Bar x : F) {}
214229
// No warning.
215230
//for (Bar &x : F) {}
@@ -233,6 +248,7 @@ void test7() {
233248
for (const int &x : G) {}
234249
// expected-warning@-1 {{resulting in a copy}}
235250
// expected-note-re@-2 {{'int'{{.*}}'const double &'}}
251+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
236252
for (const int x : G) {}
237253
// No warning
238254
//for (int &x : G) {}
@@ -243,6 +259,7 @@ void test7() {
243259
for (const Bar &x : G) {}
244260
// expected-warning@-1 {{resulting in a copy}}
245261
// expected-note-re@-2 {{'Bar'{{.*}}'const double &'}}
262+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
246263
for (const Bar x : G) {}
247264
// No warning
248265
//for (int &Bar : G) {}
@@ -266,6 +283,7 @@ void test8() {
266283
for (const Bar &x : H) {}
267284
// expected-warning@-1 {{resulting in a copy}}
268285
// expected-note-re@-2 {{'Bar'{{.*}}'const Foo &'}}
286+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
269287
for (const Bar x : H) {}
270288
// No warning
271289
//for (Bar &x: H) {}
@@ -282,6 +300,7 @@ void test9() {
282300
for (const Bar x : I) {}
283301
// expected-warning@-1 {{creates a copy}}
284302
// expected-note@-2 {{'const Bar &'}}
303+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:18}:"&"
285304
for (Bar &x : I) {}
286305
// No warning
287306
for (Bar x : I) {}
@@ -290,10 +309,35 @@ void test9() {
290309
for (const int &x : I) {}
291310
// expected-warning@-1 {{resulting in a copy}}
292311
// expected-note-re@-2 {{'int'{{.*}}'const Bar &'}}
312+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
293313
for (const int x : I) {}
294314
// No warning
295315
//for (int &x : I) {}
296316
// Binding error
297317
for (int x : I) {}
298318
// No warning
299319
}
320+
321+
void test10() {
322+
Container<Bar> C;
323+
324+
for (const Bar &x : C) {}
325+
// expected-warning@-1 {{always a copy}}
326+
// expected-note@-2 {{'Bar'}}
327+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
328+
329+
for (const Bar& x : C) {}
330+
// expected-warning@-1 {{always a copy}}
331+
// expected-note@-2 {{'Bar'}}
332+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:18}:""
333+
334+
for (const Bar & x : C) {}
335+
// expected-warning@-1 {{always a copy}}
336+
// expected-note@-2 {{'Bar'}}
337+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:20}:""
338+
339+
for (const Bar&x : C) {}
340+
// expected-warning@-1 {{always a copy}}
341+
// expected-note@-2 {{'Bar'}}
342+
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:18}:" "
343+
}

0 commit comments

Comments
 (0)