Skip to content

Commit bcdbe51

Browse files
5chmidtitmsri
authored andcommitted
[clang-tidy] fix false positive in modernize-min-max-use-initializer-list (llvm#107649)
Previously, whenever a replacement was generated by the analysis, a diagnostic was generated. This became an issue when a call to `std::min` or `std::max` consisted only of an initializer list with at least one argument to the list requiring a type cast. In this case, a single replacement that added a `static_cast` was created, that resulted in a diagnostic being issued but with no nested call to `std::min` or `std::max`. Instead, explicitly track if a nested call was detected and only emit a diagnostic if this is the case. Fixes llvm#107594
1 parent 49ffbd8 commit bcdbe51

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ static FindArgsResult findArgs(const CallExpr *Call) {
7272
return Result;
7373
}
7474

75-
static SmallVector<FixItHint>
75+
// Returns `true` as `first` only if a nested call to `std::min` or
76+
// `std::max` was found. Checking if `FixItHint`s were generated is not enough,
77+
// as the explicit casts that the check introduces may be generated without a
78+
// nested `std::min` or `std::max` call.
79+
static std::pair<bool, SmallVector<FixItHint>>
7680
generateReplacements(const MatchFinder::MatchResult &Match,
7781
const CallExpr *TopCall, const FindArgsResult &Result,
7882
const bool IgnoreNonTrivialTypes,
@@ -91,13 +95,15 @@ generateReplacements(const MatchFinder::MatchResult &Match,
9195
const bool IsResultTypeTrivial = ResultType.isTrivialType(*Match.Context);
9296

9397
if ((!IsResultTypeTrivial && IgnoreNonTrivialTypes))
94-
return FixItHints;
98+
return {false, FixItHints};
9599

96100
if (IsResultTypeTrivial &&
97101
static_cast<std::uint64_t>(
98102
Match.Context->getTypeSizeInChars(ResultType).getQuantity()) >
99103
IgnoreTrivialTypesOfSizeAbove)
100-
return FixItHints;
104+
return {false, FixItHints};
105+
106+
bool FoundNestedCall = false;
101107

102108
for (const Expr *Arg : Result.Args) {
103109
const auto *InnerCall = dyn_cast<CallExpr>(Arg->IgnoreParenImpCasts());
@@ -146,6 +152,9 @@ generateReplacements(const MatchFinder::MatchResult &Match,
146152
*Match.Context))
147153
continue;
148154

155+
// We have found a nested call
156+
FoundNestedCall = true;
157+
149158
// remove the function call
150159
FixItHints.push_back(
151160
FixItHint::CreateRemoval(InnerCall->getCallee()->getSourceRange()));
@@ -168,7 +177,7 @@ generateReplacements(const MatchFinder::MatchResult &Match,
168177
CharSourceRange::getTokenRange(InnerResult.First->getEndLoc())));
169178
}
170179

171-
const SmallVector<FixItHint> InnerReplacements = generateReplacements(
180+
const auto [_, InnerReplacements] = generateReplacements(
172181
Match, InnerCall, InnerResult, IgnoreNonTrivialTypes,
173182
IgnoreTrivialTypesOfSizeAbove);
174183

@@ -189,7 +198,7 @@ generateReplacements(const MatchFinder::MatchResult &Match,
189198
}
190199
}
191200

192-
return FixItHints;
201+
return {FoundNestedCall, FixItHints};
193202
}
194203

195204
MinMaxUseInitializerListCheck::MinMaxUseInitializerListCheck(
@@ -238,11 +247,11 @@ void MinMaxUseInitializerListCheck::check(
238247
const auto *TopCall = Match.Nodes.getNodeAs<CallExpr>("topCall");
239248

240249
const FindArgsResult Result = findArgs(TopCall);
241-
const SmallVector<FixItHint> Replacements =
250+
const auto [FoundNestedCall, Replacements] =
242251
generateReplacements(Match, TopCall, Result, IgnoreNonTrivialTypes,
243252
IgnoreTrivialTypesOfSizeAbove);
244253

245-
if (Replacements.empty())
254+
if (!FoundNestedCall)
246255
return;
247256

248257
const DiagnosticBuilder Diagnostic =

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ Changes in existing checks
136136
<clang-tidy/checks/misc/unconventional-assign-operator>` check to avoid
137137
false positive for C++23 deducing this.
138138

139+
- Improved :doc:`modernize-min-max-use-initializer-list
140+
<clang-tidy/checks/modernize/min-max-use-initializer-list>` check by fixing
141+
a false positive when only an implicit conversion happened inside an
142+
initializer list.
143+
139144
- Improved :doc:`modernize-use-std-print
140145
<clang-tidy/checks/modernize/use-std-print>` check to support replacing
141146
member function calls too.

clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,5 +323,11 @@ struct GH91982 {
323323
}
324324
};
325325

326+
struct GH107594 {
327+
int foo(int a, int b, char c) {
328+
return std::max<int>({a, b, c});
329+
}
330+
};
331+
326332
} // namespace
327333

0 commit comments

Comments
 (0)