Skip to content

Commit 32bcd41

Browse files
authored
[clang-tidy] use correct template type in std::min and std::max when operand is integer literal for readability-use-std-min-max (#122296)
When comparing with integer literal, integer promote will happen to promote type which has less bit width than int to int or unsigned int. It will let auto-fix provide correct but out of expected fix. e.g. ```c++ short a; if ( a > 10 ) a = 10; ``` will be ```c++ short a; if ( (int)a > 10 ) a = (short)10; ``` which will be fixed as ```c++ short a; a = std::max<int>(a, 10); ``` but actually it can be ```c++ short a; a = std::max<short>(a, 10); ``` Fixed: #121676
1 parent 642e493 commit 32bcd41

File tree

3 files changed

+48
-12
lines changed

3 files changed

+48
-12
lines changed

clang-tools-extra/clang-tidy/readability/UseStdMinMaxCheck.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,27 @@ static QualType getNonTemplateAlias(QualType QT) {
7979
return QT;
8080
}
8181

82+
static QualType getReplacementCastType(const Expr *CondLhs, const Expr *CondRhs,
83+
QualType ComparedType) {
84+
QualType LhsType = CondLhs->getType();
85+
QualType RhsType = CondRhs->getType();
86+
QualType LhsCanonicalType =
87+
LhsType.getCanonicalType().getNonReferenceType().getUnqualifiedType();
88+
QualType RhsCanonicalType =
89+
RhsType.getCanonicalType().getNonReferenceType().getUnqualifiedType();
90+
QualType GlobalImplicitCastType;
91+
if (LhsCanonicalType != RhsCanonicalType) {
92+
if (llvm::isa<IntegerLiteral>(CondRhs)) {
93+
GlobalImplicitCastType = getNonTemplateAlias(LhsType);
94+
} else if (llvm::isa<IntegerLiteral>(CondLhs)) {
95+
GlobalImplicitCastType = getNonTemplateAlias(RhsType);
96+
} else {
97+
GlobalImplicitCastType = getNonTemplateAlias(ComparedType);
98+
}
99+
}
100+
return GlobalImplicitCastType;
101+
}
102+
82103
static std::string createReplacement(const Expr *CondLhs, const Expr *CondRhs,
83104
const Expr *AssignLhs,
84105
const SourceManager &Source,
@@ -92,18 +113,8 @@ static std::string createReplacement(const Expr *CondLhs, const Expr *CondRhs,
92113
const llvm::StringRef AssignLhsStr = Lexer::getSourceText(
93114
Source.getExpansionRange(AssignLhs->getSourceRange()), Source, LO);
94115

95-
QualType GlobalImplicitCastType;
96-
QualType LhsType = CondLhs->getType()
97-
.getCanonicalType()
98-
.getNonReferenceType()
99-
.getUnqualifiedType();
100-
QualType RhsType = CondRhs->getType()
101-
.getCanonicalType()
102-
.getNonReferenceType()
103-
.getUnqualifiedType();
104-
if (LhsType != RhsType) {
105-
GlobalImplicitCastType = getNonTemplateAlias(BO->getLHS()->getType());
106-
}
116+
QualType GlobalImplicitCastType =
117+
getReplacementCastType(CondLhs, CondRhs, BO->getLHS()->getType());
107118

108119
return (AssignLhsStr + " = " + FunctionName +
109120
(!GlobalImplicitCastType.isNull()

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ Changes in existing checks
369369
<clang-tidy/checks/readability/redundant-smartptr-get>` check to
370370
remove `->`, when redundant `get()` is removed.
371371

372+
- Improved :doc:`readability-use-std-min-max
373+
<clang-tidy/checks/readability/use-std-min-max>` check to use correct template
374+
type in ``std::min`` and ``std::max`` when operand is integer literal.
375+
372376
Removed checks
373377
^^^^^^^^^^^^^^
374378

clang-tools-extra/test/clang-tidy/checkers/readability/use-std-min-max.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,24 @@ void testVectorSizeType() {
252252
if (value < v.size())
253253
value = v.size();
254254
}
255+
256+
namespace gh121676 {
257+
258+
void useLeft() {
259+
using U16 = unsigned short;
260+
U16 I = 0;
261+
// CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` [readability-use-std-min-max]
262+
// CHECK-FIXES: I = std::max<U16>(I, 16U);
263+
if (I < 16U)
264+
I = 16U;
265+
}
266+
void useRight() {
267+
using U16 = unsigned short;
268+
U16 I = 0;
269+
// CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` [readability-use-std-min-max]
270+
// CHECK-FIXES: I = std::min<U16>(16U, I);
271+
if (16U < I)
272+
I = 16U;
273+
}
274+
275+
} // namespace gh121676

0 commit comments

Comments
 (0)