Files
TheRock/compiler/amd-llvm/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

174 lines
6.6 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "UseIntegerSignComparisonCheck.h"
#include "clang/AST/Expr.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"
using namespace clang::ast_matchers;
using namespace clang::ast_matchers::internal;
namespace clang::tidy::modernize {
/// Find if the passed type is the actual "char" type,
/// not applicable to explicit "signed char" or "unsigned char" types.
static bool isActualCharType(const QualType &Ty) {
using namespace clang;
const Type *DesugaredType = Ty->getUnqualifiedDesugaredType();
if (const auto *BT = dyn_cast<BuiltinType>(DesugaredType))
return (BT->getKind() == BuiltinType::Char_U ||
BT->getKind() == BuiltinType::Char_S);
return false;
}
namespace {
AST_MATCHER(QualType, isActualChar) { return isActualCharType(Node); }
} // namespace
static BindableMatcher<Stmt> intCastExpression(bool IsSigned,
StringRef CastBindName = {}) {
// std::cmp_{} functions trigger a compile-time error if either LHS or RHS
// is a non-integer type, char, enum or bool
// (unsigned char/ signed char are Ok and can be used).
auto IntTypeExpr = expr(hasType(hasCanonicalType(qualType(
IsSigned ? isSignedInteger() : isUnsignedInteger(),
unless(isActualChar()), unless(booleanType()), unless(enumType())))));
const auto ImplicitCastExpr =
CastBindName.empty() ? implicitCastExpr(hasSourceExpression(IntTypeExpr))
: implicitCastExpr(hasSourceExpression(IntTypeExpr))
.bind(CastBindName);
const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
return expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr,
FunctionalCastExpr));
}
static StringRef parseOpCode(BinaryOperator::Opcode Code) {
switch (Code) {
case BO_LT:
return "cmp_less";
case BO_GT:
return "cmp_greater";
case BO_LE:
return "cmp_less_equal";
case BO_GE:
return "cmp_greater_equal";
case BO_EQ:
return "cmp_equal";
case BO_NE:
return "cmp_not_equal";
default:
llvm_unreachable("invalid opcode");
}
}
UseIntegerSignComparisonCheck::UseIntegerSignComparisonCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
utils::IncludeSorter::IS_LLVM),
areDiagsSelfContained()),
EnableQtSupport(Options.get("EnableQtSupport", false)) {}
void UseIntegerSignComparisonCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
Options.store(Opts, "EnableQtSupport", EnableQtSupport);
}
void UseIntegerSignComparisonCheck::registerMatchers(MatchFinder *Finder) {
const auto SignedIntCastExpr = intCastExpression(true, "sIntCastExpression");
const auto UnSignedIntCastExpr = intCastExpression(false);
// Flag all operators "==", "<=", ">=", "<", ">", "!="
// that are used between signed/unsigned
const auto CompareOperator =
binaryOperator(hasAnyOperatorName("==", "<=", ">=", "<", ">", "!="),
hasOperands(SignedIntCastExpr, UnSignedIntCastExpr),
unless(isInTemplateInstantiation()))
.bind("intComparison");
Finder->addMatcher(CompareOperator, this);
}
void UseIntegerSignComparisonCheck::registerPPCallbacks(
const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
IncludeInserter.registerPreprocessor(PP);
}
void UseIntegerSignComparisonCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *SignedCastExpression =
Result.Nodes.getNodeAs<ImplicitCastExpr>("sIntCastExpression");
assert(SignedCastExpression);
// Ignore the match if we know that the signed int value is not negative.
Expr::EvalResult EVResult;
if (!SignedCastExpression->isValueDependent() &&
SignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
*Result.Context) &&
EVResult.Val.getInt().isNonNegative())
return;
const auto *BinaryOp =
Result.Nodes.getNodeAs<BinaryOperator>("intComparison");
assert(BinaryOp);
const Expr *LHS = BinaryOp->getLHS()->IgnoreImpCasts();
const Expr *RHS = BinaryOp->getRHS()->IgnoreImpCasts();
const Expr *SubExprLHS = nullptr;
const Expr *SubExprRHS = nullptr;
SourceRange R1(LHS->getBeginLoc());
SourceRange R2(BinaryOp->getOperatorLoc());
SourceRange R3(Lexer::getLocForEndOfToken(
RHS->getEndLoc(), 0, *Result.SourceManager, getLangOpts()));
if (const auto *LHSCast = dyn_cast<ExplicitCastExpr>(LHS)) {
SubExprLHS = LHSCast->getSubExpr();
R1.setEnd(SubExprLHS->getBeginLoc().getLocWithOffset(-1));
R2.setBegin(Lexer::getLocForEndOfToken(
SubExprLHS->getEndLoc(), 0, *Result.SourceManager, getLangOpts()));
}
if (const auto *RHSCast = dyn_cast<ExplicitCastExpr>(RHS)) {
SubExprRHS = RHSCast->getSubExpr();
R2.setEnd(SubExprRHS->getBeginLoc().getLocWithOffset(-1));
R3.setBegin(Lexer::getLocForEndOfToken(
SubExprRHS->getEndLoc(), 0, *Result.SourceManager, getLangOpts()));
}
const DiagnosticBuilder Diag =
diag(BinaryOp->getBeginLoc(),
"comparison between 'signed' and 'unsigned' integers");
StringRef CmpNamespace;
StringRef CmpHeader;
if (getLangOpts().CPlusPlus20) {
CmpHeader = "<utility>";
CmpNamespace = "std::";
} else if (getLangOpts().CPlusPlus17 && EnableQtSupport) {
CmpHeader = "<QtCore/q20utility.h>";
CmpNamespace = "q20::";
}
// Prefer modernize-use-integer-sign-comparison when C++20 is available!
Diag << FixItHint::CreateReplacement(
CharSourceRange(R1, SubExprLHS != nullptr),
Twine(CmpNamespace + parseOpCode(BinaryOp->getOpcode()) + "(").str());
Diag << FixItHint::CreateReplacement(R2, ",");
Diag << FixItHint::CreateReplacement(CharSourceRange::getCharRange(R3), ")");
// If there is no include for cmp_{*} functions, we'll add it.
Diag << IncludeInserter.createIncludeInsertion(
Result.SourceManager->getFileID(BinaryOp->getBeginLoc()), CmpHeader);
}
} // namespace clang::tidy::modernize