Skip to content

Commit 0c85592

Browse files
committed
Create a new check to look for mis-use in calls that take iterators
Looks for various patterns of functions that take arguments calling begin/end or similar for common mistakes
1 parent f18dd9e commit 0c85592

File tree

8 files changed

+1173
-0
lines changed

8 files changed

+1173
-0
lines changed

clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "InaccurateEraseCheck.h"
3434
#include "IncDecInConditionsCheck.h"
3535
#include "IncorrectEnableIfCheck.h"
36+
#include "IncorrectIteratorsCheck.h"
3637
#include "IncorrectRoundingsCheck.h"
3738
#include "InfiniteLoopCheck.h"
3839
#include "IntegerDivisionCheck.h"
@@ -139,6 +140,8 @@ class BugproneModule : public ClangTidyModule {
139140
"bugprone-inaccurate-erase");
140141
CheckFactories.registerCheck<IncorrectEnableIfCheck>(
141142
"bugprone-incorrect-enable-if");
143+
CheckFactories.registerCheck<IncorrectIteratorsCheck>(
144+
"bugprone-incorrect-iterators");
142145
CheckFactories.registerCheck<ReturnConstRefFromParameterCheck>(
143146
"bugprone-return-const-ref-from-parameter");
144147
CheckFactories.registerCheck<SwitchMissingDefaultCaseCheck>(

clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ add_clang_library(clangTidyBugproneModule
2626
ImplicitWideningOfMultiplicationResultCheck.cpp
2727
InaccurateEraseCheck.cpp
2828
IncorrectEnableIfCheck.cpp
29+
IncorrectIteratorsCheck.cpp
2930
ReturnConstRefFromParameterCheck.cpp
3031
SuspiciousStringviewDataUsageCheck.cpp
3132
SwitchMissingDefaultCaseCheck.cpp

clang-tools-extra/clang-tidy/bugprone/IncorrectIteratorsCheck.cpp

Lines changed: 756 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===--- IncorrectIteratorsCheck.h - clang-tidy -----------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCORRECTITERATORSCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCORRECTITERATORSCHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
#include "llvm/ADT/StringRef.h"
14+
15+
namespace clang::tidy::bugprone {
16+
17+
/// Detects calls to iterator algorithms where they are called with potentially
18+
/// invalid arguments.
19+
///
20+
/// For the user-facing documentation see:
21+
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/incorrect-iterators.html
22+
class IncorrectIteratorsCheck : public ClangTidyCheck {
23+
public:
24+
IncorrectIteratorsCheck(StringRef Name, ClangTidyContext *Context);
25+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
26+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
27+
void storeOptions(ClangTidyOptions::OptionMap &Options) override;
28+
std::optional<TraversalKind> getCheckTraversalKind() const override;
29+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
30+
31+
private:
32+
std::vector<StringRef> BeginFree;
33+
std::vector<StringRef> EndFree;
34+
std::vector<StringRef> BeginMethod;
35+
std::vector<StringRef> EndMethod;
36+
std::vector<StringRef> RBeginFree;
37+
std::vector<StringRef> REndFree;
38+
std::vector<StringRef> RBeginMethod;
39+
std::vector<StringRef> REndMethod;
40+
std::vector<StringRef> MakeReverseIterator;
41+
};
42+
43+
} // namespace clang::tidy::bugprone
44+
45+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCORRECTITERATORSCHECK_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ Improvements to clang-tidy
9898
New checks
9999
^^^^^^^^^^
100100

101+
- New :doc:`bugprone-incorrect-iterators
102+
<clang-tidy/checks/bugprone/incorrect-iterators>` check.
103+
104+
Detects calls to iterator algorithms where they are called with potentially
105+
invalid arguments.
106+
101107
New check aliases
102108
^^^^^^^^^^^^^^^^^
103109

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
.. title:: clang-tidy - bugprone-incorrect-iterators
2+
3+
bugprone-incorrect-iterators
4+
============================
5+
6+
Detects calls to iterator algorithms where they are called with potentially
7+
invalid arguments.
8+
9+
Different ranges
10+
================
11+
12+
Looks for calls where the range for the ``begin`` argument is different to the
13+
``end`` argument.
14+
15+
.. code-block:: c++
16+
17+
std::find(a.begin(), b.end(), 0);
18+
std::find(std::begin(a), std::end(b));
19+
20+
Mismatched Begin/end
21+
====================
22+
23+
Looks for calls where the ``begin`` parameter is passed an ``end`` argument or
24+
vice versa.
25+
26+
.. code-block:: c++
27+
28+
std::find(a.begin(), a.begin(), 0); // Second argument should be a.end().
29+
30+
Container Methods
31+
=================
32+
33+
Looks for calls to methods on containers that expect an iterator inside the
34+
container but are given a different container.
35+
36+
.. code-block:: c++
37+
38+
vec.insert(other.begin(), 5); // The iterator is invalid for this container.
39+
std::find(a.end(), a.end(), 0); // First argument should be a.begin().
40+
41+
Output Iterators
42+
================
43+
44+
Looks for calls which accept a single output iterator but are passed the end of
45+
a container.
46+
47+
.. code-block:: c++
48+
49+
std::copy(correct.begin(), correct.end(), incorrect.end());
50+
51+
Reverse Iteration
52+
=================
53+
54+
The check understands ``rbegin`` and ``rend`` and ensures they are in the
55+
correct places.
56+
57+
.. code-block:: c++
58+
59+
std::find(a.rbegin(), a.rend(), 0); // OK.
60+
std::find(a.rend(), a.rbegin(), 0); // Arguments are swapped.
61+
62+
Manually creating a reverse iterator using the ``std::make_reverse_iterator`` is
63+
also supported, In this case the check looks for calls to ``end`` for the
64+
``begin`` parameter and vice versa. The name of functions for creating reverse
65+
iterator can be configured with the option :option:`MakeReverseIterator`.
66+
67+
.. code-block:: c++
68+
69+
std::find(std::make_reverse_iterator(a.begin()),
70+
std::make_reverse_iterator(a.end()), 0); // Arguments are swapped.
71+
std::find(std::make_reverse_iterator(a.end()),
72+
std::make_reverse_iterator(a.begin()), 0); // OK.
73+
// Understands this spaghetti looking code is actually doing the correct thing.
74+
std::find(a.rbegin(), std::make_reverse_iterator(a.begin()), 0);
75+
76+
Options
77+
-------
78+
79+
.. option:: BeginFree
80+
81+
A semi-colon seperated list of free function names that return an iterator to
82+
the start of a range. Default value is `::std::begin;std::cbegin`.
83+
84+
.. option:: EndFree
85+
86+
A semi-colon seperated list of free function names that return an iterator to
87+
the end of a range. Default value is `::std::end;std::cend`.
88+
89+
.. option:: BeginMethod
90+
91+
A semi-colon seperated list of method names that return an iterator to
92+
the start of a range. Default value is `begin;cbegin`.
93+
94+
.. option:: EndMethod
95+
96+
A semi-colon seperated list of method names that return an iterator to
97+
the end of a range. Default value is `end;cend`.
98+
99+
.. option:: RBeginFree
100+
101+
A semi-colon seperated list of free function names that return a reverse
102+
iterator to the start of a range. Default value is `::std::rbegin;std::crbegin`.
103+
104+
.. option:: REndFree
105+
106+
A semi-colon seperated list of free function names that return a reverse
107+
iterator to the end of a range. Default value is `::std::rend;std::crend`.
108+
109+
.. option:: RBeginMethod
110+
111+
A semi-colon seperated list of method names that return a reverse
112+
iterator to the start of a range. Default value is `rbegin;crbegin`.
113+
114+
.. option:: REndMethod
115+
116+
A semi-colon seperated list of method names that return a reverse
117+
iterator to the end of a range. Default value is `rend;crend`.
118+
119+
.. option:: MakeReverseIterator
120+
121+
A semi-colon seperated list of free functions that convert an interator into a
122+
reverse iterator. Default value is `::std::make_reverse_iterator`.

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ Clang-Tidy Checks
100100
:doc:`bugprone-inaccurate-erase <bugprone/inaccurate-erase>`, "Yes"
101101
:doc:`bugprone-inc-dec-in-conditions <bugprone/inc-dec-in-conditions>`,
102102
:doc:`bugprone-incorrect-enable-if <bugprone/incorrect-enable-if>`, "Yes"
103+
:doc:`bugprone-incorrect-iterators <bugprone/incorrect-iterators>`,
103104
:doc:`bugprone-incorrect-roundings <bugprone/incorrect-roundings>`,
104105
:doc:`bugprone-infinite-loop <bugprone/infinite-loop>`,
105106
:doc:`bugprone-integer-division <bugprone/integer-division>`,

0 commit comments

Comments
 (0)