Skip to content

Commit 8d24749

Browse files
njames93tru
authored andcommitted
[clang-tidy] Fix crash in modernize-use-ranges (#100427)
Crash seems to be caused by the check function not handling inline namespaces correctly for some instances. Changed how the Replacer is got from the MatchResult now which should alleviate any potential issues Fixes #100406 (cherry picked from commit 0762db6)
1 parent 69555e0 commit 8d24749

File tree

3 files changed

+43
-40
lines changed

3 files changed

+43
-40
lines changed

clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ static constexpr const char ArgName[] = "ArgName";
3939

4040
namespace clang::tidy::utils {
4141

42-
static bool operator==(const UseRangesCheck::Indexes &L,
43-
const UseRangesCheck::Indexes &R) {
44-
return std::tie(L.BeginArg, L.EndArg, L.ReplaceArg) ==
45-
std::tie(R.BeginArg, R.EndArg, R.ReplaceArg);
46-
}
47-
4842
static std::string getFullPrefix(ArrayRef<UseRangesCheck::Indexes> Signature) {
4943
std::string Output;
5044
llvm::raw_string_ostream OS(Output);
@@ -54,15 +48,6 @@ static std::string getFullPrefix(ArrayRef<UseRangesCheck::Indexes> Signature) {
5448
return Output;
5549
}
5650

57-
static llvm::hash_code hash_value(const UseRangesCheck::Indexes &Indexes) {
58-
return llvm::hash_combine(Indexes.BeginArg, Indexes.EndArg,
59-
Indexes.ReplaceArg);
60-
}
61-
62-
static llvm::hash_code hash_value(const UseRangesCheck::Signature &Sig) {
63-
return llvm::hash_combine_range(Sig.begin(), Sig.end());
64-
}
65-
6651
namespace {
6752

6853
AST_MATCHER(Expr, hasSideEffects) {
@@ -123,32 +108,34 @@ makeMatcherPair(StringRef State, const UseRangesCheck::Indexes &Indexes,
123108
}
124109

125110
void UseRangesCheck::registerMatchers(MatchFinder *Finder) {
126-
Replaces = getReplacerMap();
111+
auto Replaces = getReplacerMap();
127112
ReverseDescriptor = getReverseDescriptor();
128113
auto BeginEndNames = getFreeBeginEndMethods();
129114
llvm::SmallVector<StringRef, 4> BeginNames{
130115
llvm::make_first_range(BeginEndNames)};
131116
llvm::SmallVector<StringRef, 4> EndNames{
132117
llvm::make_second_range(BeginEndNames)};
133-
llvm::DenseSet<ArrayRef<Signature>> Seen;
118+
Replacers.clear();
119+
llvm::DenseSet<Replacer *> SeenRepl;
134120
for (auto I = Replaces.begin(), E = Replaces.end(); I != E; ++I) {
135-
const ArrayRef<Signature> &Signatures =
136-
I->getValue()->getReplacementSignatures();
137-
if (!Seen.insert(Signatures).second)
121+
auto Replacer = I->getValue();
122+
if (!SeenRepl.insert(Replacer.get()).second)
138123
continue;
139-
assert(!Signatures.empty() &&
140-
llvm::all_of(Signatures, [](auto Index) { return !Index.empty(); }));
124+
Replacers.push_back(Replacer);
125+
assert(!Replacer->getReplacementSignatures().empty() &&
126+
llvm::all_of(Replacer->getReplacementSignatures(),
127+
[](auto Index) { return !Index.empty(); }));
141128
std::vector<StringRef> Names(1, I->getKey());
142129
for (auto J = std::next(I); J != E; ++J)
143-
if (J->getValue()->getReplacementSignatures() == Signatures)
130+
if (J->getValue() == Replacer)
144131
Names.push_back(J->getKey());
145132

146133
std::vector<ast_matchers::internal::DynTypedMatcher> TotalMatchers;
147134
// As we match on the first matched signature, we need to sort the
148135
// signatures in order of length(longest to shortest). This way any
149136
// signature that is a subset of another signature will be matched after the
150137
// other.
151-
SmallVector<Signature> SigVec(Signatures);
138+
SmallVector<Signature> SigVec(Replacer->getReplacementSignatures());
152139
llvm::sort(SigVec, [](auto &L, auto &R) { return R.size() < L.size(); });
153140
for (const auto &Signature : SigVec) {
154141
std::vector<ast_matchers::internal::DynTypedMatcher> Matchers;
@@ -163,7 +150,8 @@ void UseRangesCheck::registerMatchers(MatchFinder *Finder) {
163150
}
164151
Finder->addMatcher(
165152
callExpr(
166-
callee(functionDecl(hasAnyName(std::move(Names))).bind(FuncDecl)),
153+
callee(functionDecl(hasAnyName(std::move(Names)))
154+
.bind((FuncDecl + Twine(Replacers.size() - 1).str()))),
167155
ast_matchers::internal::DynTypedMatcher::constructVariadic(
168156
ast_matchers::internal::DynTypedMatcher::VO_AnyOf,
169157
ASTNodeKind::getFromNodeKind<CallExpr>(),
@@ -205,21 +193,33 @@ static void removeFunctionArgs(DiagnosticBuilder &Diag, const CallExpr &Call,
205193
}
206194

207195
void UseRangesCheck::check(const MatchFinder::MatchResult &Result) {
208-
const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>(FuncDecl);
209-
std::string Qualified = "::" + Function->getQualifiedNameAsString();
210-
auto Iter = Replaces.find(Qualified);
211-
assert(Iter != Replaces.end());
196+
Replacer *Replacer = nullptr;
197+
const FunctionDecl *Function = nullptr;
198+
for (auto [Node, Value] : Result.Nodes.getMap()) {
199+
StringRef NodeStr(Node);
200+
if (!NodeStr.consume_front(FuncDecl))
201+
continue;
202+
Function = Value.get<FunctionDecl>();
203+
size_t Index;
204+
if (NodeStr.getAsInteger(10, Index)) {
205+
llvm_unreachable("Unable to extract replacer index");
206+
}
207+
assert(Index < Replacers.size());
208+
Replacer = Replacers[Index].get();
209+
break;
210+
}
211+
assert(Replacer && Function);
212212
SmallString<64> Buffer;
213-
for (const Signature &Sig : Iter->getValue()->getReplacementSignatures()) {
213+
for (const Signature &Sig : Replacer->getReplacementSignatures()) {
214214
Buffer.assign({BoundCall, getFullPrefix(Sig)});
215215
const auto *Call = Result.Nodes.getNodeAs<CallExpr>(Buffer);
216216
if (!Call)
217217
continue;
218218
auto Diag = createDiag(*Call);
219-
if (auto ReplaceName = Iter->getValue()->getReplaceName(*Function))
219+
if (auto ReplaceName = Replacer->getReplaceName(*Function))
220220
Diag << FixItHint::CreateReplacement(Call->getCallee()->getSourceRange(),
221221
*ReplaceName);
222-
if (auto Include = Iter->getValue()->getHeaderInclusion(*Function))
222+
if (auto Include = Replacer->getHeaderInclusion(*Function))
223223
Diag << Inserter.createIncludeInsertion(
224224
Result.SourceManager->getFileID(Call->getBeginLoc()), *Include);
225225
llvm::SmallVector<unsigned, 3> ToRemove;

clang-tools-extra/clang-tidy/utils/UseRangesCheck.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class UseRangesCheck : public ClangTidyCheck {
8585
std::optional<TraversalKind> getCheckTraversalKind() const override;
8686

8787
private:
88-
ReplacerMap Replaces;
88+
std::vector<llvm::IntrusiveRefCntPtr<Replacer>> Replacers;
8989
std::optional<ReverseIteratorDescriptor> ReverseDescriptor;
9090
IncludeInserter Inserter;
9191
};

clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-ranges/fake_std.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ template <typename T> class vector {
77
public:
88
using iterator = T *;
99
using const_iterator = const T *;
10-
using reverse_iterator = T*;
11-
using reverse_const_iterator = const T*;
10+
using reverse_iterator = T *;
11+
using reverse_const_iterator = const T *;
1212

1313
constexpr const_iterator begin() const;
1414
constexpr const_iterator end() const;
@@ -72,8 +72,8 @@ template <typename Container> constexpr auto crend(const Container &Cont) {
7272
return Cont.crend();
7373
}
7474
// Find
75-
template< class InputIt, class T >
76-
InputIt find( InputIt first, InputIt last, const T& value );
75+
template <class InputIt, class T>
76+
InputIt find(InputIt first, InputIt last, const T &value);
7777

7878
// Reverse
7979
template <typename Iter> void reverse(Iter begin, Iter end);
@@ -82,6 +82,7 @@ template <typename Iter> void reverse(Iter begin, Iter end);
8282
template <class InputIt1, class InputIt2>
8383
bool includes(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);
8484

85+
inline namespace _V1 {
8586
// IsPermutation
8687
template <class ForwardIt1, class ForwardIt2>
8788
bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2);
@@ -97,9 +98,10 @@ template <class InputIt1, class InputIt2>
9798
bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);
9899

99100
template <class InputIt1, class InputIt2, class BinaryPred>
100-
bool equal(InputIt1 first1, InputIt1 last1,
101-
InputIt2 first2, InputIt2 last2, BinaryPred p) {
102-
// Need a definition to suppress undefined_internal_type when invoked with lambda
101+
bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2,
102+
BinaryPred p) {
103+
// Need a definition to suppress undefined_internal_type when invoked with
104+
// lambda
103105
return true;
104106
}
105107

@@ -108,6 +110,7 @@ void iota(ForwardIt first, ForwardIt last, T value);
108110

109111
template <class ForwardIt>
110112
ForwardIt rotate(ForwardIt first, ForwardIt middle, ForwardIt last);
113+
} // namespace _V1
111114

112115
} // namespace std
113116

0 commit comments

Comments
 (0)