Skip to content

Commit

Permalink
[clang-tidy] modernize-loop-convert: impl const cast iter
Browse files Browse the repository at this point in the history
Summary:
modernize-loop-convert was not detecting implicit casts to
const_iterator as convertible to range-based loops:

    std::vector<int> vec{1,2,3,4}
    for(std::vector<int>::const_iterator i = vec.begin();
        i != vec.end();
        ++i) { }

Thanks to Don Hinton for advice.

As well, this change adds a note for this check's applicability to code
targeting OpenMP prior to version 5 as this check will continue breaking
compilation with `-fopenmp`. Thanks to Roman Lebedev for pointing this
out.

Fixes PR#35082

Reviewed By: hintonda

Tags: #clang-tools-extra, #clang

Differential Revision: https://reviews.llvm.org/D61827

llvm-svn: 360785
  • Loading branch information
donhinton committed May 15, 2019
1 parent 6ebb785 commit 42d28be
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 13 deletions.
5 changes: 0 additions & 5 deletions clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
Expand Up @@ -791,11 +791,6 @@ bool LoopConvertCheck::isConvertible(ASTContext *Context,
CanonicalBeginType->getPointeeType(),
CanonicalInitVarType->getPointeeType()))
return false;
} else if (!Context->hasSameType(CanonicalInitVarType,
CanonicalBeginType)) {
// Check for qualified types to avoid conversions from non-const to const
// iterator types.
return false;
}
} else if (FixerKind == LFK_PseudoArray) {
// This call is required to obtain the container.
Expand Down
Expand Up @@ -253,3 +253,15 @@ below ends up being performed at the `safe` level.
flag = true;
}
}
OpenMP
^^^^^^

As range-based for loops are only available since OpenMP 5, this check should
not been used on code with a compatibility requirements of OpenMP prior to
version 5. It is **intentional** that this check does not make any attempts to
exclude incorrect diagnostics on OpenMP for loops prior to OpenMP 5.

To prevent this check to be applied (and to break) OpenMP for loops but still be
applied to non-OpenMP for loops the usage of ``NOLINT`` (see
:ref:`clang-tidy-nolint`) on the specific for loops is recommended.
2 changes: 2 additions & 0 deletions clang-tools-extra/docs/clang-tidy/index.rst
Expand Up @@ -258,6 +258,8 @@ An overview of all the command-line options:
value: 'some value'
...
.. _clang-tidy-nolint:

Suppressing Undesired Diagnostics
=================================

Expand Down
Expand Up @@ -369,7 +369,7 @@ void f() {
// CHECK-FIXES: for (auto Val_int_ptr : Val_int_ptrs)
}

// This container uses an iterator where the derefence type is a typedef of
// This container uses an iterator where the dereference type is a typedef of
// a reference type. Make sure non-const auto & is still used. A failure here
// means canonical types aren't being tested.
{
Expand Down Expand Up @@ -431,19 +431,22 @@ void different_type() {
// CHECK-FIXES: for (auto P : *Ps)
// CHECK-FIXES-NEXT: printf("s has value %d\n", P.X);

// V.begin() returns a user-defined type 'iterator' which, since it's
// different from const_iterator, disqualifies these loops from
// transformation.
dependent<int> V;
for (dependent<int>::const_iterator It = V.begin(), E = V.end();
It != E; ++It) {
printf("Fibonacci number is %d\n", *It);
}
// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int It : V)
// CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);

for (dependent<int>::const_iterator It(V.begin()), E = V.end();
It != E; ++It) {
printf("Fibonacci number is %d\n", *It);
}
// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int It : V)
// CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
}

// Tests to ensure that an implicit 'this' is picked up as the container.
Expand Down
19 changes: 15 additions & 4 deletions clang-tools-extra/test/clang-tidy/modernize-loop-convert-extra.cpp
Expand Up @@ -776,17 +776,20 @@ void different_type() {
// CHECK-FIXES: for (auto P : *Ps)
// CHECK-FIXES-NEXT: printf("s has value %d\n", P.X);

// V.begin() returns a user-defined type 'iterator' which, since it's
// different from const_iterator, disqualifies these loops from
// transformation.
dependent<int> V;
for (dependent<int>::const_iterator It = V.begin(); It != V.end(); ++It) {
printf("Fibonacci number is %d\n", *It);
}
// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int It : V)
// CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);

for (dependent<int>::const_iterator It(V.begin()); It != V.end(); ++It) {
printf("Fibonacci number is %d\n", *It);
}
// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int It : V)
// CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
}

} // namespace SingleIterator
Expand Down Expand Up @@ -991,18 +994,26 @@ void iterators() {
// CHECK-FIXES: for (int & I : Dep)
// CHECK-FIXES-NEXT: auto H2 = [&]() { int R = I + 2; };

// FIXME: It doesn't work with const iterators.
for (dependent<int>::const_iterator I = Dep.begin(), E = Dep.end();
I != E; ++I)
auto H3 = [I]() { int R = *I; };
// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int I : Dep)
// CHECK-FIXES-NEXT: auto H3 = [&I]() { int R = I; };

for (dependent<int>::const_iterator I = Dep.begin(), E = Dep.end();
I != E; ++I)
auto H4 = [&]() { int R = *I + 1; };
// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int I : Dep)
// CHECK-FIXES-NEXT: auto H4 = [&]() { int R = I + 1; };

for (dependent<int>::const_iterator I = Dep.begin(), E = Dep.end();
I != E; ++I)
auto H5 = [=]() { int R = *I; };
// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
// CHECK-FIXES: for (int R : Dep)
// CHECK-FIXES-NEXT: auto H5 = [=]() { };
}

void captureByValue() {
Expand Down

0 comments on commit 42d28be

Please sign in to comment.