From 3ef4feb748551806c863529306fefb2bd914e5be Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 17:17:06 -0400 Subject: [PATCH 01/38] AvoidFundamentalIntegerTypesCheck --- .../AvoidFundamentalIntegerTypesCheck.cpp | 183 ++++++++++++++++++ .../AvoidFundamentalIntegerTypesCheck.h | 46 +++++ .../clang-tidy/modernize/CMakeLists.txt | 1 + .../modernize/ModernizeTidyModule.cpp | 3 + .../avoid-fundamental-integer-types.cpp | 108 +++++++++++ 5 files changed, 341 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp new file mode 100644 index 0000000000000..8a393bc894cfe --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp @@ -0,0 +1,183 @@ +//===--- AvoidFundamentalIntegerTypesCheck.cpp - clang-tidy ---------------===// +// +// 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 "AvoidFundamentalIntegerTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { + +AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) { + return Node.getBeginLoc().isValid(); +} + +AST_MATCHER_P(clang::TypeLoc, hasType, + clang::ast_matchers::internal::Matcher, + InnerMatcher) { + const clang::Type *TypeNode = Node.getTypePtr(); + return TypeNode != nullptr && + InnerMatcher.matches(*TypeNode, Finder, Builder); +} + +} // namespace + +AvoidFundamentalIntegerTypesCheck::AvoidFundamentalIntegerTypesCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IgnoreTypedefs(Options.get("IgnoreTypedefs", false)) {} + +void AvoidFundamentalIntegerTypesCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreTypedefs", IgnoreTypedefs); +} + +bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( + const Type *T) const { + if (!T->isBuiltinType()) + return false; + + const auto *BT = T->getAs(); + if (!BT) + return false; + + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: + return true; + default: + return false; + } +} + +bool AvoidFundamentalIntegerTypesCheck::isSemanticType(const Type *T) const { + if (!T->isBuiltinType()) + return false; + + const auto *BT = T->getAs(); + if (!BT) + return false; + + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: + return true; + default: + return false; + } +} + +void AvoidFundamentalIntegerTypesCheck::registerMatchers(MatchFinder *Finder) { + // Match variable declarations with fundamental integer types + Finder->addMatcher( + varDecl().bind("var_decl"), + this); + + // Match function declarations with fundamental integer return types + Finder->addMatcher( + functionDecl().bind("func_decl"), + this); + + // Match function parameters with fundamental integer types + Finder->addMatcher( + parmVarDecl().bind("param_decl"), + this); + + // Match field declarations with fundamental integer types + Finder->addMatcher( + fieldDecl().bind("field_decl"), + this); + + // Match typedef declarations if not ignoring them + if (!IgnoreTypedefs) { + Finder->addMatcher( + typedefDecl().bind("typedef_decl"), + this); + + Finder->addMatcher( + typeAliasDecl().bind("alias_decl"), + this); + } +} + +void AvoidFundamentalIntegerTypesCheck::check( + const MatchFinder::MatchResult &Result) { + SourceLocation Loc; + QualType QT; + std::string DeclType; + + if (const auto *VD = Result.Nodes.getNodeAs("var_decl")) { + Loc = VD->getLocation(); + QT = VD->getType(); + DeclType = "variable"; + } else if (const auto *FD = Result.Nodes.getNodeAs("func_decl")) { + Loc = FD->getLocation(); + QT = FD->getReturnType(); + DeclType = "function return type"; + } else if (const auto *PD = Result.Nodes.getNodeAs("param_decl")) { + Loc = PD->getLocation(); + QT = PD->getType(); + DeclType = "function parameter"; + } else if (const auto *FD = Result.Nodes.getNodeAs("field_decl")) { + Loc = FD->getLocation(); + QT = FD->getType(); + DeclType = "field"; + } else if (const auto *TD = Result.Nodes.getNodeAs("typedef_decl")) { + Loc = TD->getLocation(); + QT = TD->getUnderlyingType(); + DeclType = "typedef"; + } else if (const auto *AD = Result.Nodes.getNodeAs("alias_decl")) { + Loc = AD->getLocation(); + QT = AD->getUnderlyingType(); + DeclType = "type alias"; + } else { + return; + } + + if (Loc.isInvalid() || QT.isNull()) + return; + + const Type *T = QT.getCanonicalType().getTypePtr(); + if (!T) + return; + + // Skip if not a fundamental integer type + if (!isFundamentalIntegerType(T)) + return; + + // Skip semantic types + if (isSemanticType(T)) + return; + + // Get the type name for the diagnostic + std::string TypeName = QT.getAsString(); + + diag(Loc, "avoid using platform-dependent fundamental integer type '%0'; " + "consider using a typedef or fixed-width type instead") + << TypeName; +} + +} // namespace clang::tidy::modernize \ No newline at end of file diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h new file mode 100644 index 0000000000000..41e8cd5ceb87e --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h @@ -0,0 +1,46 @@ +//===--- AvoidFundamentalIntegerTypesCheck.h - clang-tidy -------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOIDFUNDAMENTALINTEGERTYPESCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOIDFUNDAMENTALINTEGERTYPESCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::modernize { + +/// Find fundamental integer types and recommend using typedefs or fixed-width types. +/// +/// Detects fundamental integer types (int, short, long, long long, and their +/// unsigned variants) and warns against their use due to platform-dependent +/// behavior. Excludes semantic types like char, bool, wchar_t, char16_t, +/// char32_t, size_t, and ptrdiff_t. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/avoid-fundamental-integer-types.html +class AvoidFundamentalIntegerTypesCheck : public ClangTidyCheck { +public: + AvoidFundamentalIntegerTypesCheck(StringRef Name, ClangTidyContext *Context); + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus11; + } + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } + +private: + const bool IgnoreTypedefs; + bool isFundamentalIntegerType(const Type *T) const; + bool isSemanticType(const Type *T) const; +}; + +} // namespace clang::tidy::modernize + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOIDFUNDAMENTALINTEGERTYPESCHECK_H \ No newline at end of file diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index 619a27b2f9bb6..deb37c1ad9fb3 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangTidyModernizeModule STATIC AvoidBindCheck.cpp AvoidCArraysCheck.cpp + AvoidFundamentalIntegerTypesCheck.cpp ConcatNestedNamespacesCheck.cpp DeprecatedHeadersCheck.cpp DeprecatedIosBaseAliasesCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index fdf38bc4b6308..a42d55b26a311 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -11,6 +11,7 @@ #include "../ClangTidyModuleRegistry.h" #include "AvoidBindCheck.h" #include "AvoidCArraysCheck.h" +#include "AvoidFundamentalIntegerTypesCheck.h" #include "ConcatNestedNamespacesCheck.h" #include "DeprecatedHeadersCheck.h" #include "DeprecatedIosBaseAliasesCheck.h" @@ -63,6 +64,8 @@ class ModernizeModule : public ClangTidyModule { void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck("modernize-avoid-bind"); CheckFactories.registerCheck("modernize-avoid-c-arrays"); + CheckFactories.registerCheck( + "modernize-avoid-fundamental-integer-types"); CheckFactories.registerCheck( "modernize-concat-nested-namespaces"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp new file mode 100644 index 0000000000000..7d4860d95a3ce --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp @@ -0,0 +1,108 @@ +// RUN: %check_clang_tidy %s modernize-avoid-fundamental-integer-types %t + +// Test fundamental integer types that should trigger warnings +int global_int = 42; +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +short global_short = 10; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +long global_long = 100L; +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +long long global_long_long = 1000LL; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent fundamental integer type 'long long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +unsigned int global_unsigned_int = 42U; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: avoid using platform-dependent fundamental integer type 'unsigned int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +unsigned short global_unsigned_short = 10U; +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: avoid using platform-dependent fundamental integer type 'unsigned short'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +unsigned long global_unsigned_long = 100UL; +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: avoid using platform-dependent fundamental integer type 'unsigned long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +unsigned long long global_unsigned_long_long = 1000ULL; +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: avoid using platform-dependent fundamental integer type 'unsigned long long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +// Test semantic types that should NOT trigger warnings +char global_char = 'a'; +signed char global_signed_char = 'b'; +unsigned char global_unsigned_char = 'c'; +bool global_bool = true; +wchar_t global_wchar = L'w'; + +// Test function parameters +void function_with_int_param(int param) { +// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +} + +void function_with_short_param(short param) { +// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +} + +// Test function return types +int function_returning_int() { +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + return 42; +} + +long function_returning_long() { +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + return 100L; +} + +// Test local variables +void test_local_variables() { + int local_int = 10; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + + short local_short = 5; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + + unsigned long local_unsigned_long = 200UL; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: avoid using platform-dependent fundamental integer type 'unsigned long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + + // These should not trigger warnings + char local_char = 'x'; + bool local_bool = false; +} + +// Test struct/class members +struct TestStruct { + int member_int; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + + long member_long; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + + // These should not trigger warnings + char member_char; + bool member_bool; +}; + +class TestClass { +public: + unsigned int public_member; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: avoid using platform-dependent fundamental integer type 'unsigned int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +private: + short private_member; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +}; + +// Test typedefs and type aliases +typedef int MyInt; +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +using MyLong = long; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + +// Test template parameters +template +void template_function(T param) {} + +template<> +void template_function(int param) { +// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +} \ No newline at end of file From 48598ef4bd01a096a5bde29515df3e472cae2e0f Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 17:33:54 -0400 Subject: [PATCH 02/38] Test typedefs properly --- .../AvoidFundamentalIntegerTypesCheck.cpp | 32 ++++++++--------- .../AvoidFundamentalIntegerTypesCheck.h | 4 +-- .../avoid-fundamental-integer-types.cpp | 35 ++++++++++++++++++- 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp index 8a393bc894cfe..b5e2484e6396a 100644 --- a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp @@ -33,13 +33,7 @@ AST_MATCHER_P(clang::TypeLoc, hasType, AvoidFundamentalIntegerTypesCheck::AvoidFundamentalIntegerTypesCheck( StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), - IgnoreTypedefs(Options.get("IgnoreTypedefs", false)) {} - -void AvoidFundamentalIntegerTypesCheck::storeOptions( - ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "IgnoreTypedefs", IgnoreTypedefs); -} + : ClangTidyCheck(Name, Context) {} bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( const Type *T) const { @@ -111,16 +105,14 @@ void AvoidFundamentalIntegerTypesCheck::registerMatchers(MatchFinder *Finder) { fieldDecl().bind("field_decl"), this); - // Match typedef declarations if not ignoring them - if (!IgnoreTypedefs) { - Finder->addMatcher( - typedefDecl().bind("typedef_decl"), - this); + // Match typedef declarations to check their underlying types + Finder->addMatcher( + typedefDecl().bind("typedef_decl"), + this); - Finder->addMatcher( - typeAliasDecl().bind("alias_decl"), - this); - } + Finder->addMatcher( + typeAliasDecl().bind("alias_decl"), + this); } void AvoidFundamentalIntegerTypesCheck::check( @@ -160,6 +152,12 @@ void AvoidFundamentalIntegerTypesCheck::check( if (Loc.isInvalid() || QT.isNull()) return; + // Check if the type is already a typedef - if so, don't warn + // since the user is already using a typedef (which is what we want) + if (QT->getAs()) { + return; + } + const Type *T = QT.getCanonicalType().getTypePtr(); if (!T) return; @@ -180,4 +178,4 @@ void AvoidFundamentalIntegerTypesCheck::check( << TypeName; } -} // namespace clang::tidy::modernize \ No newline at end of file +} // namespace clang::tidy::modernize diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h index 41e8cd5ceb87e..c1e4fb4748e5d 100644 --- a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h @@ -27,7 +27,6 @@ class AvoidFundamentalIntegerTypesCheck : public ClangTidyCheck { AvoidFundamentalIntegerTypesCheck(StringRef Name, ClangTidyContext *Context); void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - void storeOptions(ClangTidyOptions::OptionMap &Opts) override; bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus11; } @@ -36,11 +35,10 @@ class AvoidFundamentalIntegerTypesCheck : public ClangTidyCheck { } private: - const bool IgnoreTypedefs; bool isFundamentalIntegerType(const Type *T) const; bool isSemanticType(const Type *T) const; }; } // namespace clang::tidy::modernize -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOIDFUNDAMENTALINTEGERTYPESCHECK_H \ No newline at end of file +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOIDFUNDAMENTALINTEGERTYPESCHECK_H diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp index 7d4860d95a3ce..ad2c4e6884e57 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp @@ -1,5 +1,17 @@ // RUN: %check_clang_tidy %s modernize-avoid-fundamental-integer-types %t +// Mock fixed-width integer types +// NOLINTBEGIN(modernize-avoid-fundamental-integer-types) +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned long long uint64_t; +typedef long long int64_t; + +// Mock standard library semantic types +typedef unsigned long size_t; +typedef long ptrdiff_t; +// NOLINTEND(modernize-avoid-fundamental-integer-types) + // Test fundamental integer types that should trigger warnings int global_int = 42; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] @@ -32,6 +44,16 @@ unsigned char global_unsigned_char = 'c'; bool global_bool = true; wchar_t global_wchar = L'w'; +// Test fixed-width types that should NOT trigger warnings +uint32_t global_uint32 = 42U; +int32_t global_int32 = 42; +uint64_t global_uint64 = 100ULL; +int64_t global_int64 = 100LL; + +// Test semantic standard library types that should NOT trigger warnings +size_t global_size = 100; +ptrdiff_t global_ptrdiff = 50; + // Test function parameters void function_with_int_param(int param) { // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] @@ -66,6 +88,14 @@ void test_local_variables() { // These should not trigger warnings char local_char = 'x'; bool local_bool = false; + + // Fixed-width types should not trigger warnings + uint32_t local_uint32 = 42U; + int64_t local_int64 = 100LL; + + // Standard library semantic types should not trigger warnings + size_t local_size = 200; + ptrdiff_t local_ptrdiff = 10; } // Test struct/class members @@ -98,6 +128,9 @@ typedef int MyInt; using MyLong = long; // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +typedef long long customType; +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: avoid using platform-dependent fundamental integer type 'long long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + // Test template parameters template void template_function(T param) {} @@ -105,4 +138,4 @@ void template_function(T param) {} template<> void template_function(int param) { // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] -} \ No newline at end of file +} From 524fdd8c480cb3f3652c354a305b27a34fe53e45 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 18:26:31 -0400 Subject: [PATCH 03/38] Document properly --- .../docs/clang-tidy/checks/list.rst | 1 + .../avoid-fundamental-integer-types.rst | 111 ++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-fundamental-integer-types.rst diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 5098582d0c42b..33c2911fd9ae5 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -280,6 +280,7 @@ Clang-Tidy Checks :doc:`misc-use-internal-linkage `, "Yes" :doc:`modernize-avoid-bind `, "Yes" :doc:`modernize-avoid-c-arrays `, + :doc:`modernize-avoid-fundamental-integer-types `, :doc:`modernize-concat-nested-namespaces `, "Yes" :doc:`modernize-deprecated-headers `, "Yes" :doc:`modernize-deprecated-ios-base-aliases `, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-fundamental-integer-types.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-fundamental-integer-types.rst new file mode 100644 index 0000000000000..df511e084701f --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-fundamental-integer-types.rst @@ -0,0 +1,111 @@ +.. title:: clang-tidy - modernize-avoid-fundamental-integer-types + +modernize-avoid-fundamental-integer-types +========================================== + +Finds fundamental integer types and recommends using typedefs or fixed-width types instead. + +This check detects fundamental integer types (``int``, ``short``, ``long``, ``long long``, and their +``unsigned`` variants) and warns against their use due to non-standard platform-dependent behavior. +For example, ``long`` is 64 bits on Linux but 32 bits on Windows. There is no standard rationale or +intent for the sizes of these types. + +Instead of fundamental types, use fixed-width types such as ``int32_t`` or implementation-defined +types with standard semantics, e.g. ``int_fast32_t`` for the fastest integer type greater than or +equal to 32 bits. + +Examples +-------- + +.. code-block:: c++ + + // Bad: platform-dependent fundamental types + int global_int = 42; + short global_short = 10; + long global_long = 100L; + unsigned long global_unsigned_long = 100UL; + + void function_with_int_param(int param) { + // ... + } + + int function_returning_int() { + return 42; + } + + struct MyStruct { + int member_int; + long member_long; + }; + +.. code-block:: c++ + + // Good: use fixed-width types or typedefs + #include + + int32_t global_int32 = 42; + int16_t global_int16 = 10; + int64_t global_int64 = 100L; + uint64_t global_uint64 = 100UL; + + void function_with_int32_param(int32_t param) { + // ... + } + + int32_t function_returning_int32() { + return 42; + } + + struct MyStruct { + int32_t member_int32; + int64_t member_int64; + }; + +The check will also warn about typedef declarations that use fundamental types as their underlying type: + +.. code-block:: c++ + + // Bad: typedef using fundamental type + typedef long long MyLongType; + using MyIntType = int; + +.. code-block:: c++ + + // Good: use descriptive names or fixed-width types + typedef int64_t TimestampType; + using CounterType = uint32_t; + +Rationale +--------- + +Fundamental integer types have platform-dependent sizes and behavior: + +- ``int`` is typically 32 bits on modern platforms but is only guaranteed to be 16 bits by the spec +- ``long int`` is 32 bits on Windows but 64 bits on most Unix systems + +The C++ specification does not define these types beyond their minimum sizes. That means they can +communicate intent in non-standard ways and are often needlessly incompatible. For example, ``int`` +was traditionally the word size of a given processor in 16-bit and 32-bit computing and was a +reasonable default for performance. This is no longer true on modern 64-bit computers, but the size +of ``int`` remains fixed at 32 bits for backwards compatibility with code that relied on a 32-bit +implementation of ``int``. + +If code is explicitly relying on the size of an ``int`` being 32 bits, it is better to say so in +the typename with ``int32_t``. Otherwise, use an appropriate implementation-defined type that +communicates your intent. + +Types Not Flagged +----------------- + +The following types are intentionally not flagged: + +- ``char``, ``signed char``, ``unsigned char`` (character types) +- ``bool`` (boolean type) +- Standard library typedefs like ``size_t``, ``ptrdiff_t``, or ``uint32_t``. +- Already typedef'd types, though the check will flag the typedef itself + +``char`` is excluded because it is implementation-defined to always be 1 byte, regardless of the +platform's definition of a byte. + +``bool`` is excluded because it can only be true or false, and is not vulnerable to overflow or +narrowing issues that occur as a result of using implementation-defined types. From d5fd2e798ecc6e9fcfd1863f37995c3f179d56c7 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 21:50:01 -0400 Subject: [PATCH 04/38] Rename files --- .../AvoidPlatformSpecificFundamentalTypesCheck.cpp} | 0 .../AvoidPlatformSpecificFundamentalTypesCheck.h} | 0 .../avoid-platform-specific-fundamental-types.rst} | 0 .../avoid-platform-specific-fundamental-types.cpp} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename clang-tools-extra/clang-tidy/{modernize/AvoidFundamentalIntegerTypesCheck.cpp => portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp} (100%) rename clang-tools-extra/clang-tidy/{modernize/AvoidFundamentalIntegerTypesCheck.h => portability/AvoidPlatformSpecificFundamentalTypesCheck.h} (100%) rename clang-tools-extra/docs/clang-tidy/checks/{modernize/avoid-fundamental-integer-types.rst => portability/avoid-platform-specific-fundamental-types.rst} (100%) rename clang-tools-extra/test/clang-tidy/checkers/{modernize/avoid-fundamental-integer-types.cpp => portability/avoid-platform-specific-fundamental-types.cpp} (100%) diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp similarity index 100% rename from clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.cpp rename to clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h similarity index 100% rename from clang-tools-extra/clang-tidy/modernize/AvoidFundamentalIntegerTypesCheck.h rename to clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-fundamental-integer-types.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst similarity index 100% rename from clang-tools-extra/docs/clang-tidy/checks/modernize/avoid-fundamental-integer-types.rst rename to clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp similarity index 100% rename from clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-fundamental-integer-types.cpp rename to clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp From 25425cc0f12d96d86619d83222d0222bc1d17538 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 22:27:08 -0400 Subject: [PATCH 05/38] Other renaming for portability change --- .../clang-tidy/modernize/CMakeLists.txt | 1 - .../modernize/ModernizeTidyModule.cpp | 3 -- ...dPlatformSpecificFundamentalTypesCheck.cpp | 18 +++---- ...oidPlatformSpecificFundamentalTypesCheck.h | 18 +++---- .../clang-tidy/portability/CMakeLists.txt | 1 + .../portability/PortabilityTidyModule.cpp | 3 ++ .../docs/clang-tidy/checks/list.rst | 2 +- ...id-platform-specific-fundamental-types.rst | 6 +-- ...id-platform-specific-fundamental-types.cpp | 52 +++++++++---------- 9 files changed, 52 insertions(+), 52 deletions(-) diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index deb37c1ad9fb3..619a27b2f9bb6 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -6,7 +6,6 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangTidyModernizeModule STATIC AvoidBindCheck.cpp AvoidCArraysCheck.cpp - AvoidFundamentalIntegerTypesCheck.cpp ConcatNestedNamespacesCheck.cpp DeprecatedHeadersCheck.cpp DeprecatedIosBaseAliasesCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index a42d55b26a311..fdf38bc4b6308 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -11,7 +11,6 @@ #include "../ClangTidyModuleRegistry.h" #include "AvoidBindCheck.h" #include "AvoidCArraysCheck.h" -#include "AvoidFundamentalIntegerTypesCheck.h" #include "ConcatNestedNamespacesCheck.h" #include "DeprecatedHeadersCheck.h" #include "DeprecatedIosBaseAliasesCheck.h" @@ -64,8 +63,6 @@ class ModernizeModule : public ClangTidyModule { void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck("modernize-avoid-bind"); CheckFactories.registerCheck("modernize-avoid-c-arrays"); - CheckFactories.registerCheck( - "modernize-avoid-fundamental-integer-types"); CheckFactories.registerCheck( "modernize-concat-nested-namespaces"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index b5e2484e6396a..7eb9619577200 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -1,4 +1,4 @@ -//===--- AvoidFundamentalIntegerTypesCheck.cpp - clang-tidy ---------------===// +//===--- AvoidPlatformSpecificFundamentalTypesCheck.cpp - clang-tidy ---------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,14 +6,14 @@ // //===----------------------------------------------------------------------===// -#include "AvoidFundamentalIntegerTypesCheck.h" +#include "AvoidPlatformSpecificFundamentalTypesCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" using namespace clang::ast_matchers; -namespace clang::tidy::modernize { +namespace clang::tidy::portability { namespace { @@ -31,11 +31,11 @@ AST_MATCHER_P(clang::TypeLoc, hasType, } // namespace -AvoidFundamentalIntegerTypesCheck::AvoidFundamentalIntegerTypesCheck( +AvoidPlatformSpecificFundamentalTypesCheck::AvoidPlatformSpecificFundamentalTypesCheck( StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} -bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( +bool AvoidPlatformSpecificFundamentalTypesCheck::isFundamentalIntegerType( const Type *T) const { if (!T->isBuiltinType()) return false; @@ -59,7 +59,7 @@ bool AvoidFundamentalIntegerTypesCheck::isFundamentalIntegerType( } } -bool AvoidFundamentalIntegerTypesCheck::isSemanticType(const Type *T) const { +bool AvoidPlatformSpecificFundamentalTypesCheck::isSemanticType(const Type *T) const { if (!T->isBuiltinType()) return false; @@ -84,7 +84,7 @@ bool AvoidFundamentalIntegerTypesCheck::isSemanticType(const Type *T) const { } } -void AvoidFundamentalIntegerTypesCheck::registerMatchers(MatchFinder *Finder) { +void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers(MatchFinder *Finder) { // Match variable declarations with fundamental integer types Finder->addMatcher( varDecl().bind("var_decl"), @@ -115,7 +115,7 @@ void AvoidFundamentalIntegerTypesCheck::registerMatchers(MatchFinder *Finder) { this); } -void AvoidFundamentalIntegerTypesCheck::check( +void AvoidPlatformSpecificFundamentalTypesCheck::check( const MatchFinder::MatchResult &Result) { SourceLocation Loc; QualType QT; @@ -178,4 +178,4 @@ void AvoidFundamentalIntegerTypesCheck::check( << TypeName; } -} // namespace clang::tidy::modernize +} // namespace clang::tidy::portability diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index c1e4fb4748e5d..0b5c8053b5bfe 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -1,4 +1,4 @@ -//===--- AvoidFundamentalIntegerTypesCheck.h - clang-tidy -------*- C++ -*-===// +//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOIDFUNDAMENTALINTEGERTYPESCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOIDFUNDAMENTALINTEGERTYPESCHECK_H +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H #include "../ClangTidyCheck.h" -namespace clang::tidy::modernize { +namespace clang::tidy::portability { /// Find fundamental integer types and recommend using typedefs or fixed-width types. /// @@ -21,10 +21,10 @@ namespace clang::tidy::modernize { /// char32_t, size_t, and ptrdiff_t. /// /// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/avoid-fundamental-integer-types.html -class AvoidFundamentalIntegerTypesCheck : public ClangTidyCheck { +/// http://clang.llvm.org/extra/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.html +class AvoidPlatformSpecificFundamentalTypesCheck : public ClangTidyCheck { public: - AvoidFundamentalIntegerTypesCheck(StringRef Name, ClangTidyContext *Context); + AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, ClangTidyContext *Context); void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { @@ -39,6 +39,6 @@ class AvoidFundamentalIntegerTypesCheck : public ClangTidyCheck { bool isSemanticType(const Type *T) const; }; -} // namespace clang::tidy::modernize +} // namespace clang::tidy::portability -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOIDFUNDAMENTALINTEGERTYPESCHECK_H +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H diff --git a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt index 73d74a550afc0..014c1ea883547 100644 --- a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt @@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS ) add_clang_library(clangTidyPortabilityModule STATIC + AvoidPlatformSpecificFundamentalTypesCheck.cpp AvoidPragmaOnceCheck.cpp PortabilityTidyModule.cpp RestrictSystemIncludesCheck.cpp diff --git a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp index 98853556588b3..2e2ddb91934f3 100644 --- a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "AvoidPlatformSpecificFundamentalTypesCheck.h" #include "AvoidPragmaOnceCheck.h" #include "RestrictSystemIncludesCheck.h" #include "SIMDIntrinsicsCheck.h" @@ -21,6 +22,8 @@ namespace portability { class PortabilityModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "portability-avoid-platform-specific-fundamental-types"); CheckFactories.registerCheck( "portability-avoid-pragma-once"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 33c2911fd9ae5..73d9ef7039ac4 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -280,7 +280,6 @@ Clang-Tidy Checks :doc:`misc-use-internal-linkage `, "Yes" :doc:`modernize-avoid-bind `, "Yes" :doc:`modernize-avoid-c-arrays `, - :doc:`modernize-avoid-fundamental-integer-types `, :doc:`modernize-concat-nested-namespaces `, "Yes" :doc:`modernize-deprecated-headers `, "Yes" :doc:`modernize-deprecated-ios-base-aliases `, "Yes" @@ -354,6 +353,7 @@ Clang-Tidy Checks :doc:`performance-type-promotion-in-math-fn `, "Yes" :doc:`performance-unnecessary-copy-initialization `, "Yes" :doc:`performance-unnecessary-value-param `, "Yes" + :doc:`portability-avoid-platform-specific-fundamental-types `, :doc:`portability-avoid-pragma-once `, :doc:`portability-restrict-system-includes `, "Yes" :doc:`portability-simd-intrinsics `, diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst index df511e084701f..3da0b19658343 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst @@ -1,9 +1,9 @@ -.. title:: clang-tidy - modernize-avoid-fundamental-integer-types +.. title:: clang-tidy - portability-avoid-platform-specific-fundamental-types -modernize-avoid-fundamental-integer-types +portability-avoid-platform-specific-fundamental-types ========================================== -Finds fundamental integer types and recommends using typedefs or fixed-width types instead. +Finds fundamental types and recommends using typedefs or fixed-width types instead. This check detects fundamental integer types (``int``, ``short``, ``long``, ``long long``, and their ``unsigned`` variants) and warns against their use due to non-standard platform-dependent behavior. diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp index ad2c4e6884e57..3eb2b3b8a3074 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp @@ -1,7 +1,7 @@ -// RUN: %check_clang_tidy %s modernize-avoid-fundamental-integer-types %t +// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t // Mock fixed-width integer types -// NOLINTBEGIN(modernize-avoid-fundamental-integer-types) +// NOLINTBEGIN(portability-avoid-platform-specific-fundamental-types) typedef unsigned int uint32_t; typedef int int32_t; typedef unsigned long long uint64_t; @@ -10,32 +10,32 @@ typedef long long int64_t; // Mock standard library semantic types typedef unsigned long size_t; typedef long ptrdiff_t; -// NOLINTEND(modernize-avoid-fundamental-integer-types) +// NOLINTEND(portability-avoid-platform-specific-fundamental-types) // Test fundamental integer types that should trigger warnings int global_int = 42; -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] short global_short = 10; -// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] long global_long = 100L; -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] long long global_long_long = 1000LL; -// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent fundamental integer type 'long long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent fundamental integer type 'long long'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] unsigned int global_unsigned_int = 42U; -// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: avoid using platform-dependent fundamental integer type 'unsigned int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: avoid using platform-dependent fundamental integer type 'unsigned int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] unsigned short global_unsigned_short = 10U; -// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: avoid using platform-dependent fundamental integer type 'unsigned short'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: avoid using platform-dependent fundamental integer type 'unsigned short'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] unsigned long global_unsigned_long = 100UL; -// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: avoid using platform-dependent fundamental integer type 'unsigned long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: avoid using platform-dependent fundamental integer type 'unsigned long'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] unsigned long long global_unsigned_long_long = 1000ULL; -// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: avoid using platform-dependent fundamental integer type 'unsigned long long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: avoid using platform-dependent fundamental integer type 'unsigned long long'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] // Test semantic types that should NOT trigger warnings char global_char = 'a'; @@ -56,34 +56,34 @@ ptrdiff_t global_ptrdiff = 50; // Test function parameters void function_with_int_param(int param) { -// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] } void function_with_short_param(short param) { -// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] } // Test function return types int function_returning_int() { -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] return 42; } long function_returning_long() { -// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] return 100L; } // Test local variables void test_local_variables() { int local_int = 10; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] short local_short = 5; - // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] unsigned long local_unsigned_long = 200UL; - // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: avoid using platform-dependent fundamental integer type 'unsigned long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: avoid using platform-dependent fundamental integer type 'unsigned long'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] // These should not trigger warnings char local_char = 'x'; @@ -101,10 +101,10 @@ void test_local_variables() { // Test struct/class members struct TestStruct { int member_int; - // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] long member_long; - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] // These should not trigger warnings char member_char; @@ -114,22 +114,22 @@ struct TestStruct { class TestClass { public: unsigned int public_member; - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: avoid using platform-dependent fundamental integer type 'unsigned int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: avoid using platform-dependent fundamental integer type 'unsigned int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] private: short private_member; - // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent fundamental integer type 'short'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] }; // Test typedefs and type aliases typedef int MyInt; -// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] using MyLong = long; -// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent fundamental integer type 'long'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] typedef long long customType; -// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: avoid using platform-dependent fundamental integer type 'long long'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: avoid using platform-dependent fundamental integer type 'long long'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] // Test template parameters template @@ -137,5 +137,5 @@ void template_function(T param) {} template<> void template_function(int param) { -// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [modernize-avoid-fundamental-integer-types] +// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] } From 86787ec25d3ebba2afeb570f930e0a3eb5ced730 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 22:29:08 -0400 Subject: [PATCH 06/38] Formatting fix --- ...dPlatformSpecificFundamentalTypesCheck.cpp | 50 +++++++++---------- ...oidPlatformSpecificFundamentalTypesCheck.h | 9 ++-- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 7eb9619577200..2c04e8020ff3a 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -1,4 +1,5 @@ -//===--- AvoidPlatformSpecificFundamentalTypesCheck.cpp - clang-tidy ---------------===// +//===--- AvoidPlatformSpecificFundamentalTypesCheck.cpp - clang-tidy +//---------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -31,8 +32,9 @@ AST_MATCHER_P(clang::TypeLoc, hasType, } // namespace -AvoidPlatformSpecificFundamentalTypesCheck::AvoidPlatformSpecificFundamentalTypesCheck( - StringRef Name, ClangTidyContext *Context) +AvoidPlatformSpecificFundamentalTypesCheck:: + AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, + ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} bool AvoidPlatformSpecificFundamentalTypesCheck::isFundamentalIntegerType( @@ -59,7 +61,8 @@ bool AvoidPlatformSpecificFundamentalTypesCheck::isFundamentalIntegerType( } } -bool AvoidPlatformSpecificFundamentalTypesCheck::isSemanticType(const Type *T) const { +bool AvoidPlatformSpecificFundamentalTypesCheck::isSemanticType( + const Type *T) const { if (!T->isBuiltinType()) return false; @@ -84,35 +87,24 @@ bool AvoidPlatformSpecificFundamentalTypesCheck::isSemanticType(const Type *T) c } } -void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers(MatchFinder *Finder) { +void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( + MatchFinder *Finder) { // Match variable declarations with fundamental integer types - Finder->addMatcher( - varDecl().bind("var_decl"), - this); + Finder->addMatcher(varDecl().bind("var_decl"), this); // Match function declarations with fundamental integer return types - Finder->addMatcher( - functionDecl().bind("func_decl"), - this); + Finder->addMatcher(functionDecl().bind("func_decl"), this); // Match function parameters with fundamental integer types - Finder->addMatcher( - parmVarDecl().bind("param_decl"), - this); + Finder->addMatcher(parmVarDecl().bind("param_decl"), this); // Match field declarations with fundamental integer types - Finder->addMatcher( - fieldDecl().bind("field_decl"), - this); + Finder->addMatcher(fieldDecl().bind("field_decl"), this); // Match typedef declarations to check their underlying types - Finder->addMatcher( - typedefDecl().bind("typedef_decl"), - this); + Finder->addMatcher(typedefDecl().bind("typedef_decl"), this); - Finder->addMatcher( - typeAliasDecl().bind("alias_decl"), - this); + Finder->addMatcher(typeAliasDecl().bind("alias_decl"), this); } void AvoidPlatformSpecificFundamentalTypesCheck::check( @@ -125,11 +117,13 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( Loc = VD->getLocation(); QT = VD->getType(); DeclType = "variable"; - } else if (const auto *FD = Result.Nodes.getNodeAs("func_decl")) { + } else if (const auto *FD = + Result.Nodes.getNodeAs("func_decl")) { Loc = FD->getLocation(); QT = FD->getReturnType(); DeclType = "function return type"; - } else if (const auto *PD = Result.Nodes.getNodeAs("param_decl")) { + } else if (const auto *PD = + Result.Nodes.getNodeAs("param_decl")) { Loc = PD->getLocation(); QT = PD->getType(); DeclType = "function parameter"; @@ -137,11 +131,13 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( Loc = FD->getLocation(); QT = FD->getType(); DeclType = "field"; - } else if (const auto *TD = Result.Nodes.getNodeAs("typedef_decl")) { + } else if (const auto *TD = + Result.Nodes.getNodeAs("typedef_decl")) { Loc = TD->getLocation(); QT = TD->getUnderlyingType(); DeclType = "typedef"; - } else if (const auto *AD = Result.Nodes.getNodeAs("alias_decl")) { + } else if (const auto *AD = + Result.Nodes.getNodeAs("alias_decl")) { Loc = AD->getLocation(); QT = AD->getUnderlyingType(); DeclType = "type alias"; diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index 0b5c8053b5bfe..7c446328c8ea0 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -1,4 +1,5 @@ -//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -------*- C++ -*-===// +//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -------*- C++ +//-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,7 +14,8 @@ namespace clang::tidy::portability { -/// Find fundamental integer types and recommend using typedefs or fixed-width types. +/// Find fundamental integer types and recommend using typedefs or fixed-width +/// types. /// /// Detects fundamental integer types (int, short, long, long long, and their /// unsigned variants) and warns against their use due to platform-dependent @@ -24,7 +26,8 @@ namespace clang::tidy::portability { /// http://clang.llvm.org/extra/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.html class AvoidPlatformSpecificFundamentalTypesCheck : public ClangTidyCheck { public: - AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, ClangTidyContext *Context); + AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, + ClangTidyContext *Context); void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { From c66668e825213c540c7e6d7de0eefcd283b2defd Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 22:40:12 -0400 Subject: [PATCH 07/38] Make matchers more specific --- ...dPlatformSpecificFundamentalTypesCheck.cpp | 99 +++++++++---------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 2c04e8020ff3a..b1b2dde523428 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -16,22 +16,6 @@ using namespace clang::ast_matchers; namespace clang::tidy::portability { -namespace { - -AST_MATCHER(clang::TypeLoc, hasValidBeginLoc) { - return Node.getBeginLoc().isValid(); -} - -AST_MATCHER_P(clang::TypeLoc, hasType, - clang::ast_matchers::internal::Matcher, - InnerMatcher) { - const clang::Type *TypeNode = Node.getTypePtr(); - return TypeNode != nullptr && - InnerMatcher.matches(*TypeNode, Finder, Builder); -} - -} // namespace - AvoidPlatformSpecificFundamentalTypesCheck:: AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, ClangTidyContext *Context) @@ -89,22 +73,55 @@ bool AvoidPlatformSpecificFundamentalTypesCheck::isSemanticType( void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( MatchFinder *Finder) { - // Match variable declarations with fundamental integer types - Finder->addMatcher(varDecl().bind("var_decl"), this); - - // Match function declarations with fundamental integer return types - Finder->addMatcher(functionDecl().bind("func_decl"), this); - - // Match function parameters with fundamental integer types - Finder->addMatcher(parmVarDecl().bind("param_decl"), this); - - // Match field declarations with fundamental integer types - Finder->addMatcher(fieldDecl().bind("field_decl"), this); - - // Match typedef declarations to check their underlying types - Finder->addMatcher(typedefDecl().bind("typedef_decl"), this); - - Finder->addMatcher(typeAliasDecl().bind("alias_decl"), this); + // Create a matcher for platform-specific fundamental integer types + // This should only match direct uses of builtin types, not typedefs + auto PlatformSpecificFundamentalType = qualType( + allOf( + // Must be a builtin type directly (not through typedef) + builtinType(), + // Only match the specific fundamental integer types we care about + anyOf( + asString("int"), + asString("unsigned int"), + asString("short"), + asString("unsigned short"), + asString("long"), + asString("unsigned long"), + asString("long long"), + asString("unsigned long long") + ) + ) + ); + + // Match variable declarations with platform-specific fundamental integer types + Finder->addMatcher( + varDecl(hasType(PlatformSpecificFundamentalType)).bind("var_decl"), + this); + + // Match function declarations with platform-specific fundamental integer return types + Finder->addMatcher( + functionDecl(returns(PlatformSpecificFundamentalType)).bind("func_decl"), + this); + + // Match function parameters with platform-specific fundamental integer types + Finder->addMatcher( + parmVarDecl(hasType(PlatformSpecificFundamentalType)).bind("param_decl"), + this); + + // Match field declarations with platform-specific fundamental integer types + Finder->addMatcher( + fieldDecl(hasType(PlatformSpecificFundamentalType)).bind("field_decl"), + this); + + // Match typedef declarations with platform-specific fundamental underlying types + Finder->addMatcher( + typedefDecl(hasUnderlyingType(PlatformSpecificFundamentalType)).bind("typedef_decl"), + this); + + // Match type alias declarations with platform-specific fundamental underlying types + Finder->addMatcher( + typeAliasDecl(hasType(PlatformSpecificFundamentalType)).bind("alias_decl"), + this); } void AvoidPlatformSpecificFundamentalTypesCheck::check( @@ -148,24 +165,6 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( if (Loc.isInvalid() || QT.isNull()) return; - // Check if the type is already a typedef - if so, don't warn - // since the user is already using a typedef (which is what we want) - if (QT->getAs()) { - return; - } - - const Type *T = QT.getCanonicalType().getTypePtr(); - if (!T) - return; - - // Skip if not a fundamental integer type - if (!isFundamentalIntegerType(T)) - return; - - // Skip semantic types - if (isSemanticType(T)) - return; - // Get the type name for the diagnostic std::string TypeName = QT.getAsString(); From 1b314bbe3a6705e5e95cc2945a985416231f0568 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 22:45:33 -0400 Subject: [PATCH 08/38] Remove dead code --- ...dPlatformSpecificFundamentalTypesCheck.cpp | 115 +++++------------- ...oidPlatformSpecificFundamentalTypesCheck.h | 4 - 2 files changed, 30 insertions(+), 89 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index b1b2dde523428..e7efa2fde6564 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -21,84 +21,33 @@ AvoidPlatformSpecificFundamentalTypesCheck:: ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} -bool AvoidPlatformSpecificFundamentalTypesCheck::isFundamentalIntegerType( - const Type *T) const { - if (!T->isBuiltinType()) - return false; - - const auto *BT = T->getAs(); - if (!BT) - return false; - - switch (BT->getKind()) { - case BuiltinType::Int: - case BuiltinType::UInt: - case BuiltinType::Short: - case BuiltinType::UShort: - case BuiltinType::Long: - case BuiltinType::ULong: - case BuiltinType::LongLong: - case BuiltinType::ULongLong: - return true; - default: - return false; - } -} - -bool AvoidPlatformSpecificFundamentalTypesCheck::isSemanticType( - const Type *T) const { - if (!T->isBuiltinType()) - return false; - - const auto *BT = T->getAs(); - if (!BT) - return false; - - switch (BT->getKind()) { - case BuiltinType::Bool: - case BuiltinType::Char_S: - case BuiltinType::Char_U: - case BuiltinType::SChar: - case BuiltinType::UChar: - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: - case BuiltinType::Char8: - case BuiltinType::Char16: - case BuiltinType::Char32: - return true; - default: - return false; - } -} - void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( MatchFinder *Finder) { // Create a matcher for platform-specific fundamental integer types // This should only match direct uses of builtin types, not typedefs - auto PlatformSpecificFundamentalType = qualType( - allOf( - // Must be a builtin type directly (not through typedef) - builtinType(), - // Only match the specific fundamental integer types we care about - anyOf( - asString("int"), - asString("unsigned int"), - asString("short"), - asString("unsigned short"), - asString("long"), - asString("unsigned long"), - asString("long long"), - asString("unsigned long long") - ) - ) - ); - - // Match variable declarations with platform-specific fundamental integer types + auto PlatformSpecificFundamentalType = qualType(allOf( + // Must be a builtin type directly (not through typedef) + builtinType(), + // Only match the specific fundamental integer types we care about + anyOf(asString("short"), asString("short int"), asString("signed short"), + asString("signed short int"), asString("unsigned short"), + asString("unsigned short int"), asString("int"), asString("signed"), + asString("signed int"), asString("unsigned"), + asString("unsigned int"), asString("long"), asString("long int"), + asString("signed long"), asString("signed long int"), + asString("unsigned long"), asString("unsigned long int"), + asString("long long"), asString("long long int"), + asString("signed long long"), asString("signed long long int"), + asString("unsigned long long"), + asString("unsigned long long int")))); + + // Match variable declarations with platform-specific fundamental integer + // types Finder->addMatcher( - varDecl(hasType(PlatformSpecificFundamentalType)).bind("var_decl"), - this); + varDecl(hasType(PlatformSpecificFundamentalType)).bind("var_decl"), this); - // Match function declarations with platform-specific fundamental integer return types + // Match function declarations with platform-specific fundamental integer + // return types Finder->addMatcher( functionDecl(returns(PlatformSpecificFundamentalType)).bind("func_decl"), this); @@ -113,51 +62,47 @@ void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( fieldDecl(hasType(PlatformSpecificFundamentalType)).bind("field_decl"), this); - // Match typedef declarations with platform-specific fundamental underlying types + // Match typedef declarations with platform-specific fundamental underlying + // types Finder->addMatcher( - typedefDecl(hasUnderlyingType(PlatformSpecificFundamentalType)).bind("typedef_decl"), + typedefDecl(hasUnderlyingType(PlatformSpecificFundamentalType)) + .bind("typedef_decl"), this); - // Match type alias declarations with platform-specific fundamental underlying types - Finder->addMatcher( - typeAliasDecl(hasType(PlatformSpecificFundamentalType)).bind("alias_decl"), - this); + // Match type alias declarations with platform-specific fundamental underlying + // types + Finder->addMatcher(typeAliasDecl(hasType(PlatformSpecificFundamentalType)) + .bind("alias_decl"), + this); } void AvoidPlatformSpecificFundamentalTypesCheck::check( const MatchFinder::MatchResult &Result) { SourceLocation Loc; QualType QT; - std::string DeclType; if (const auto *VD = Result.Nodes.getNodeAs("var_decl")) { Loc = VD->getLocation(); QT = VD->getType(); - DeclType = "variable"; } else if (const auto *FD = Result.Nodes.getNodeAs("func_decl")) { Loc = FD->getLocation(); QT = FD->getReturnType(); - DeclType = "function return type"; } else if (const auto *PD = Result.Nodes.getNodeAs("param_decl")) { Loc = PD->getLocation(); QT = PD->getType(); - DeclType = "function parameter"; } else if (const auto *FD = Result.Nodes.getNodeAs("field_decl")) { Loc = FD->getLocation(); QT = FD->getType(); - DeclType = "field"; } else if (const auto *TD = Result.Nodes.getNodeAs("typedef_decl")) { Loc = TD->getLocation(); QT = TD->getUnderlyingType(); - DeclType = "typedef"; } else if (const auto *AD = Result.Nodes.getNodeAs("alias_decl")) { Loc = AD->getLocation(); QT = AD->getUnderlyingType(); - DeclType = "type alias"; } else { return; } diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index 7c446328c8ea0..e0ae7c67fa310 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -36,10 +36,6 @@ class AvoidPlatformSpecificFundamentalTypesCheck : public ClangTidyCheck { std::optional getCheckTraversalKind() const override { return TK_IgnoreUnlessSpelledInSource; } - -private: - bool isFundamentalIntegerType(const Type *T) const; - bool isSemanticType(const Type *T) const; }; } // namespace clang::tidy::portability From 411d5987069dfba1861fc4ffc859b7324535db1d Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 3 Jul 2025 22:48:57 -0400 Subject: [PATCH 09/38] Fix doc --- .../portability/avoid-platform-specific-fundamental-types.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst index 3da0b19658343..2813b9ba385fd 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst @@ -1,7 +1,7 @@ .. title:: clang-tidy - portability-avoid-platform-specific-fundamental-types portability-avoid-platform-specific-fundamental-types -========================================== +===================================================== Finds fundamental types and recommends using typedefs or fixed-width types instead. From b427df738990651cc0b95a3faa34e45c68da18c1 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 5 Jul 2025 15:20:19 -0400 Subject: [PATCH 10/38] Fix issue on MSVC --- .../avoid-platform-specific-fundamental-types.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp index 3eb2b3b8a3074..337166cdf3699 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp @@ -8,8 +8,11 @@ typedef unsigned long long uint64_t; typedef long long int64_t; // Mock standard library semantic types -typedef unsigned long size_t; typedef long ptrdiff_t; +// MSVC defines size_t automatically +#ifndef _MSC_VER +typedef unsigned long size_t; +#endif // NOLINTEND(portability-avoid-platform-specific-fundamental-types) // Test fundamental integer types that should trigger warnings From 5dd5c722485d85022988f0948d955ed62680f2df Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 5 Jul 2025 15:21:33 -0400 Subject: [PATCH 11/38] Merge comment with previous line --- .../portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index e7efa2fde6564..286bbe420f260 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -1,5 +1,4 @@ -//===--- AvoidPlatformSpecificFundamentalTypesCheck.cpp - clang-tidy -//---------------===// +//===--- AvoidPlatformSpecificFundamentalTypesCheck.cpp - clang-tidy ------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. From 7c2031bc94538d283fd03efb514f8ff93ae7aada Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 5 Jul 2025 15:23:17 -0400 Subject: [PATCH 12/38] Add linter check to release notes --- clang-tools-extra/docs/ReleaseNotes.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 198efee7754de..0815b7f844c0b 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -148,6 +148,13 @@ New checks Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's alternative ``std::scoped_lock``. +- New :doc:`portability-avoid-platform-specific-fundamental-types + ` + check. + + Finds fundamental types (e.g. `int`, `float`) and recommends using typedefs + or fixed-width types instead to improve portability across different platforms. + - New :doc:`portability-avoid-pragma-once ` check. From 475f1b2bc2c817206222490e64e9e61560a9ed76 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 5 Jul 2025 15:46:45 -0400 Subject: [PATCH 13/38] Update documentation --- ...id-platform-specific-fundamental-types.rst | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst index 2813b9ba385fd..ef015f9c578fb 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst @@ -5,14 +5,15 @@ portability-avoid-platform-specific-fundamental-types Finds fundamental types and recommends using typedefs or fixed-width types instead. -This check detects fundamental integer types (``int``, ``short``, ``long``, ``long long``, and their -``unsigned`` variants) and warns against their use due to non-standard platform-dependent behavior. -For example, ``long`` is 64 bits on Linux but 32 bits on Windows. There is no standard rationale or +This check detects fundamental types (``int``, ``short``, ``long``, ``float``, +``char`` and their ``unsigned`` or ``signed`` variants) and warns against their +use due to non-standard platform-dependent behavior. For example, ``long`` is +64 bits on Linux but 32 bits on Windows. There is no standard rationale or intent for the sizes of these types. -Instead of fundamental types, use fixed-width types such as ``int32_t`` or implementation-defined -types with standard semantics, e.g. ``int_fast32_t`` for the fastest integer type greater than or -equal to 32 bits. +Instead of fundamental types, use fixed-width types such as ``int32_t`` or +implementation-defined types with standard semantics, e.g. ``int_fast32_t`` for +the fastest integer type greater than or equal to 32 bits. Examples -------- @@ -61,7 +62,8 @@ Examples int64_t member_int64; }; -The check will also warn about typedef declarations that use fundamental types as their underlying type: +The check will also warn about typedef declarations that use fundamental types +as their underlying type: .. code-block:: c++ @@ -78,34 +80,44 @@ The check will also warn about typedef declarations that use fundamental types a Rationale --------- -Fundamental integer types have platform-dependent sizes and behavior: +Fundamental types have platform-dependent sizes and behavior: -- ``int`` is typically 32 bits on modern platforms but is only guaranteed to be 16 bits by the spec +- ``int`` is typically 32 bits on modern platforms but is only guaranteed to be + 16 bits by the spec - ``long int`` is 32 bits on Windows but 64 bits on most Unix systems - -The C++ specification does not define these types beyond their minimum sizes. That means they can -communicate intent in non-standard ways and are often needlessly incompatible. For example, ``int`` -was traditionally the word size of a given processor in 16-bit and 32-bit computing and was a -reasonable default for performance. This is no longer true on modern 64-bit computers, but the size -of ``int`` remains fixed at 32 bits for backwards compatibility with code that relied on a 32-bit -implementation of ``int``. - -If code is explicitly relying on the size of an ``int`` being 32 bits, it is better to say so in -the typename with ``int32_t``. Otherwise, use an appropriate implementation-defined type that -communicates your intent. +- ``double`` is typically 64-bit IEEE754, but on some microcontrollers without + a 64-bit FPU (e.g. certain Arduinos) it can be 32 bits +- ``char`` is signed on ARM and unsigned on x86 + +The C++ specification does not define these types beyond their minimum sizes. +That means they can communicate intent in non-standard ways and are often +needlessly incompatible. For example, ``int``was traditionally the word size of +a given processor in 16-bit and 32-bit computing and was a reasonable default +for performance. This is no longer true on modern 64-bit computers, but the +size of ``int`` remains fixed at 32 bits for backwards compatibility with code +that relied on a 32-bit implementation of ``int``. + +If code is explicitly relying on the size of an ``int`` being 32 bits, it is +better to say so in the typename with ``int32_t``. Otherwise, use an +appropriate implementation-defined type such as ``fast_int32_t`` or +``least_int32_t`` that communicates the appropriate time/space tradeoff. + +Likewise, ``float`` and ``double`` should be replaced by ``float32_t`` and +``float64_t`` which are guaranteed to be standard IEEE754 floats for a given +size. + +``char`` should be replaced by ``char8_t`` when used in the representation of +Unicode text. When used to represent a byte on a given platform, ``std::byte`` +is an appropriate replacement. Types Not Flagged ----------------- The following types are intentionally not flagged: -- ``char``, ``signed char``, ``unsigned char`` (character types) - ``bool`` (boolean type) - Standard library typedefs like ``size_t``, ``ptrdiff_t``, or ``uint32_t``. - Already typedef'd types, though the check will flag the typedef itself -``char`` is excluded because it is implementation-defined to always be 1 byte, regardless of the -platform's definition of a byte. - ``bool`` is excluded because it can only be true or false, and is not vulnerable to overflow or narrowing issues that occur as a result of using implementation-defined types. From 20e43d842f37928898080af62f74558eb5008198 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 5 Jul 2025 15:46:51 -0400 Subject: [PATCH 14/38] Fix redundant check --- .../portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 286bbe420f260..a05d8b09ebd7c 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -106,9 +106,6 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( return; } - if (Loc.isInvalid() || QT.isNull()) - return; - // Get the type name for the diagnostic std::string TypeName = QT.getAsString(); From 20e9b32d647f6760e13d493fdf42865e93973730 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 5 Jul 2025 17:29:43 -0400 Subject: [PATCH 15/38] In progress work on float check --- ...dPlatformSpecificFundamentalTypesCheck.cpp | 179 +++++++++++++++--- ...oidPlatformSpecificFundamentalTypesCheck.h | 14 +- ...id-platform-specific-fundamental-types.rst | 34 ++++ ...form-specific-fundamental-types-floats.cpp | 100 ++++++++++ 4 files changed, 299 insertions(+), 28 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index a05d8b09ebd7c..f28507300e246 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -10,6 +10,7 @@ #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/TargetInfo.h" using namespace clang::ast_matchers; @@ -18,45 +19,121 @@ namespace clang::tidy::portability { AvoidPlatformSpecificFundamentalTypesCheck:: AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + : ClangTidyCheck(Name, Context), + WarnOnFloats(Options.get("WarnOnFloats", false)), + IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()) {} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + IncludeInserter.registerPreprocessor(PP); +} + +void AvoidPlatformSpecificFundamentalTypesCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "WarnOnFloats", WarnOnFloats); + Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); +} + +std::string AvoidPlatformSpecificFundamentalTypesCheck::getFloatReplacement( + const BuiltinType *BT, ASTContext &Context) const { + const TargetInfo &Target = Context.getTargetInfo(); + + auto GetReplacementType = [](unsigned Width) { + switch (Width) { + // This is ambiguous by default since it could be bfloat16 or float16 + case 16U: + return ""; + case 32U: + return "float32_t"; + case 64U: + return "float64_t"; + case 128U: + return "float128_t"; + default: + return ""; + } + }; + + switch (BT->getKind()) { + // Not an ambiguous type + case BuiltinType::BFloat16: + return "bfloat16_t"; + case BuiltinType::Half: + return GetReplacementType(Target.getHalfWidth()); + case BuiltinType::Float: + return GetReplacementType(Target.getFloatWidth()); + case BuiltinType::Double: + return GetReplacementType(Target.getDoubleWidth()); + default: + return ""; + } +} void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( MatchFinder *Finder) { - // Create a matcher for platform-specific fundamental integer types - // This should only match direct uses of builtin types, not typedefs + // Build the list of type strings to match + std::vector TypeStrings = {"short", + "short int", + "signed short", + "signed short int", + "unsigned short", + "unsigned short int", + "int", + "signed", + "signed int", + "unsigned", + "unsigned int", + "long", + "long int", + "signed long", + "signed long int", + "unsigned long", + "unsigned long int", + "long long", + "long long int", + "signed long long", + "signed long long int", + "unsigned long long", + "unsigned long long int"}; + + // Add float types if the option is enabled + if (WarnOnFloats) { + TypeStrings.push_back("half"); + TypeStrings.push_back("__bf16"); + TypeStrings.push_back("float"); + TypeStrings.push_back("double"); + TypeStrings.push_back("long double"); + } + + // Create the matcher dynamically + auto TypeMatcher = asString(TypeStrings[0]); + for (size_t i = 1; i < TypeStrings.size(); ++i) { + TypeMatcher = anyOf(TypeMatcher, asString(TypeStrings[i])); + } + auto PlatformSpecificFundamentalType = qualType(allOf( // Must be a builtin type directly (not through typedef) builtinType(), - // Only match the specific fundamental integer types we care about - anyOf(asString("short"), asString("short int"), asString("signed short"), - asString("signed short int"), asString("unsigned short"), - asString("unsigned short int"), asString("int"), asString("signed"), - asString("signed int"), asString("unsigned"), - asString("unsigned int"), asString("long"), asString("long int"), - asString("signed long"), asString("signed long int"), - asString("unsigned long"), asString("unsigned long int"), - asString("long long"), asString("long long int"), - asString("signed long long"), asString("signed long long int"), - asString("unsigned long long"), - asString("unsigned long long int")))); - - // Match variable declarations with platform-specific fundamental integer - // types + // Match the specific fundamental types we care about + TypeMatcher)); + + // Match variable declarations with platform-specific fundamental types Finder->addMatcher( varDecl(hasType(PlatformSpecificFundamentalType)).bind("var_decl"), this); - // Match function declarations with platform-specific fundamental integer - // return types + // Match function declarations with platform-specific fundamental return types Finder->addMatcher( functionDecl(returns(PlatformSpecificFundamentalType)).bind("func_decl"), this); - // Match function parameters with platform-specific fundamental integer types + // Match function parameters with platform-specific fundamental types Finder->addMatcher( parmVarDecl(hasType(PlatformSpecificFundamentalType)).bind("param_decl"), this); - // Match field declarations with platform-specific fundamental integer types + // Match field declarations with platform-specific fundamental types Finder->addMatcher( fieldDecl(hasType(PlatformSpecificFundamentalType)).bind("field_decl"), this); @@ -79,29 +156,48 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( const MatchFinder::MatchResult &Result) { SourceLocation Loc; QualType QT; + SourceRange TypeRange; if (const auto *VD = Result.Nodes.getNodeAs("var_decl")) { Loc = VD->getLocation(); QT = VD->getType(); + if (VD->getTypeSourceInfo()) { + TypeRange = VD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + } } else if (const auto *FD = Result.Nodes.getNodeAs("func_decl")) { Loc = FD->getLocation(); QT = FD->getReturnType(); + if (FD->getTypeSourceInfo()) { + TypeRange = FD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + } } else if (const auto *PD = Result.Nodes.getNodeAs("param_decl")) { Loc = PD->getLocation(); QT = PD->getType(); + if (PD->getTypeSourceInfo()) { + TypeRange = PD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + } } else if (const auto *FD = Result.Nodes.getNodeAs("field_decl")) { Loc = FD->getLocation(); QT = FD->getType(); + if (FD->getTypeSourceInfo()) { + TypeRange = FD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + } } else if (const auto *TD = Result.Nodes.getNodeAs("typedef_decl")) { Loc = TD->getLocation(); QT = TD->getUnderlyingType(); + if (TD->getTypeSourceInfo()) { + TypeRange = TD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + } } else if (const auto *AD = Result.Nodes.getNodeAs("alias_decl")) { Loc = AD->getLocation(); QT = AD->getUnderlyingType(); + if (AD->getTypeSourceInfo()) { + TypeRange = AD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + } } else { return; } @@ -109,9 +205,42 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( // Get the type name for the diagnostic std::string TypeName = QT.getAsString(); - diag(Loc, "avoid using platform-dependent fundamental integer type '%0'; " - "consider using a typedef or fixed-width type instead") - << TypeName; + // Check if this is a floating point type + const auto *BT = QT->getAs(); + bool IsFloatingPoint = BT && (BT->getKind() == BuiltinType::Half || + BT->getKind() == BuiltinType::BFloat16 || + BT->getKind() == BuiltinType::Float || + BT->getKind() == BuiltinType::Double || + BT->getKind() == BuiltinType::LongDouble); + + if (IsFloatingPoint) { + // Handle floating point types + std::string Replacement = getFloatReplacement(BT, *Result.Context); + if (!Replacement.empty()) { + auto Diag = + diag(Loc, "avoid using platform-dependent floating point type '%0'; " + "consider using '%1' instead") + << TypeName << Replacement; + + if (TypeRange.isValid()) { + Diag << FixItHint::CreateReplacement(TypeRange, Replacement); + } + + if (auto IncludeFixit = IncludeInserter.createIncludeInsertion( + Result.SourceManager->getFileID(Loc), "")) { + Diag << *IncludeFixit; + } + } else { + diag(Loc, "avoid using platform-dependent floating point type '%0'; " + "consider using a typedef or fixed-width type instead") + << TypeName; + } + } else { + // Handle integer types + diag(Loc, "avoid using platform-dependent fundamental integer type '%0'; " + "consider using a typedef or fixed-width type instead") + << TypeName; + } } } // namespace clang::tidy::portability diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index e0ae7c67fa310..4d59cae47c52b 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -1,16 +1,16 @@ -//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -------*- C++ -//-*-===// +//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -------*- 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 // -//===----------------------------------------------------------------------===// +//===-------------------------------------------------------------------------------===// #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H #include "../ClangTidyCheck.h" +#include "../utils/IncludeInserter.h" namespace clang::tidy::portability { @@ -28,14 +28,22 @@ class AvoidPlatformSpecificFundamentalTypesCheck : public ClangTidyCheck { public: AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, ClangTidyContext *Context); + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus11; } std::optional getCheckTraversalKind() const override { return TK_IgnoreUnlessSpelledInSource; } + +private: + const bool WarnOnFloats; + utils::IncludeInserter IncludeInserter; + std::string getFloatReplacement(const BuiltinType *BT, ASTContext &Context) const; }; } // namespace clang::tidy::portability diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst index ef015f9c578fb..54fba9dfaec25 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst @@ -121,3 +121,37 @@ The following types are intentionally not flagged: ``bool`` is excluded because it can only be true or false, and is not vulnerable to overflow or narrowing issues that occur as a result of using implementation-defined types. + +Options +------- + +.. option:: WarnOnFloats + + When `true`, the check will warn about floating point types (``float`` and ``double``). + When `false` (default), floating point types are not flagged. + + Floating point types can have platform-dependent behavior: + + - ``float`` is typically 32-bit IEEE754, but can vary on some platforms + - ``double`` is typically 64-bit IEEE754, but on some microcontrollers without + a 64-bit FPU it can be 32 bits + + When this option is enabled, the check will suggest using ``float32_t`` and ``float64_t`` + instead of ``float`` and ``double`` respectively, when the target platform supports + standard IEEE754 sizes. + + Example with ``WarnOnFloats`` enabled: + + .. code-block:: c++ + + // Bad: platform-dependent floating point types + float pi = 3.14f; + double e = 2.71828; + + .. code-block:: c++ + + // Good: use fixed-width floating point types + #include // C++23 + + float32_t pi = 3.14f; + float64_t e = 2.71828; diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp new file mode 100644 index 0000000000000..22b3629731b66 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp @@ -0,0 +1,100 @@ +// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: true}]}" -header-filter=.* -- -std=c++23 + +// Mock fixed-width float types +// In reality, these types are aliases to "extended floating point types", and +// are not typedefs. However, there isn't a good way to mock extended floats as +// they are not fundamental types. +// NOLINTBEGIN(portability-avoid-platform-specific-fundamental-types) +typedef float float32_t; +typedef double float64_t; +// NOLINTEND(portability-avoid-platform-specific-fundamental-types) + +// Test floating point types that should trigger warnings when WarnOnFloats is enabled +float global_float = 3.14f; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent floating point type 'float'; consider using 'float32_t' instead [portability-avoid-platform-specific-fundamental-types] +// CHECK-FIXES: float32_t global_float = 3.14f; + +double global_double = 3.14159; +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: avoid using platform-dependent floating point type 'double'; consider using 'float64_t' instead [portability-avoid-platform-specific-fundamental-types] +// CHECK-FIXES: float64_t global_double = 3.14159; + +// Test integer types that should still trigger warnings +int global_int = 42; +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] + +// Test function parameters with float types +void function_with_float_param(float param) { +// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: avoid using platform-dependent floating point type 'float'; consider using 'float32_t' instead [portability-avoid-platform-specific-fundamental-types] +} + +void function_with_double_param(double param) { +// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: avoid using platform-dependent floating point type 'double'; consider using 'float64_t' instead [portability-avoid-platform-specific-fundamental-types] +} + +// Test function return types with float types +float function_returning_float() { +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent floating point type 'float'; consider using 'float32_t' instead [portability-avoid-platform-specific-fundamental-types] + return 3.14f; +} + +double function_returning_double() { +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: avoid using platform-dependent floating point type 'double'; consider using 'float64_t' instead [portability-avoid-platform-specific-fundamental-types] + return 3.14159; +} + +// Test local variables with float types +void test_local_float_variables() { + float local_float = 2.71f; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent floating point type 'float'; consider using 'float32_t' instead [portability-avoid-platform-specific-fundamental-types] + + double local_double = 2.71828; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: avoid using platform-dependent floating point type 'double'; consider using 'float64_t' instead [portability-avoid-platform-specific-fundamental-types] + + // Fixed-width types should not trigger warnings + float32_t local_float32 = 3.14f; + float64_t local_float64 = 3.14159; +} + +// Test struct/class members with float types +struct TestFloatStruct { + float member_float; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent floating point type 'float'; consider using 'float32_t' instead [portability-avoid-platform-specific-fundamental-types] + + double member_double; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: avoid using platform-dependent floating point type 'double'; consider using 'float64_t' instead [portability-avoid-platform-specific-fundamental-types] + + // Fixed-width types should not trigger warnings + float32_t member_float32; + float64_t member_float64; +}; + +class TestFloatClass { +public: + float public_float_member; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid using platform-dependent floating point type 'float'; consider using 'float32_t' instead [portability-avoid-platform-specific-fundamental-types] + +private: + double private_double_member; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: avoid using platform-dependent floating point type 'double'; consider using 'float64_t' instead [portability-avoid-platform-specific-fundamental-types] +}; + +// Test typedefs and type aliases with float types +typedef float MyFloat; +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: avoid using platform-dependent floating point type 'float'; consider using 'float32_t' instead [portability-avoid-platform-specific-fundamental-types] + +using MyDouble = double; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent floating point type 'double'; consider using 'float64_t' instead [portability-avoid-platform-specific-fundamental-types] + +// Test template specializations with float types +template +void template_function(T param) {} + +template<> +void template_function(float param) { +// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: avoid using platform-dependent floating point type 'float'; consider using 'float32_t' instead [portability-avoid-platform-specific-fundamental-types] +} + +template<> +void template_function(double param) { +// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: avoid using platform-dependent floating point type 'double'; consider using 'float64_t' instead [portability-avoid-platform-specific-fundamental-types] +} From f49a289fde746f4e011209a87c44fc2f6d58c806 Mon Sep 17 00:00:00 2001 From: JJ Marr <168750718+jj-marr@users.noreply.github.com> Date: Sat, 5 Jul 2025 17:51:14 -0400 Subject: [PATCH 16/38] Declare const Co-authored-by: EugeneZelenko --- .../portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index f28507300e246..6ea84516def42 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -203,7 +203,7 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( } // Get the type name for the diagnostic - std::string TypeName = QT.getAsString(); + const std::string TypeName = QT.getAsString(); // Check if this is a floating point type const auto *BT = QT->getAs(); From 143fcadfeaf23b78b4661be5ed432baabb4d6c40 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 5 Jul 2025 18:36:37 -0400 Subject: [PATCH 17/38] Synchronize with release notes --- .../portability/avoid-platform-specific-fundamental-types.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst index 54fba9dfaec25..6f0835aba9c41 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst @@ -3,7 +3,8 @@ portability-avoid-platform-specific-fundamental-types ===================================================== -Finds fundamental types and recommends using typedefs or fixed-width types instead. +Finds fundamental types (e.g. `int`, `float`) and recommends using typedefs +or fixed-width types instead to improve portability across different platforms. This check detects fundamental types (``int``, ``short``, ``long``, ``float``, ``char`` and their ``unsigned`` or ``signed`` variants) and warns against their From 3c2ccd5fd336ebf007fcb22aab4f2f0c999b8f4f Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sat, 5 Jul 2025 18:44:55 -0400 Subject: [PATCH 18/38] Attempt to format --- .../AvoidPlatformSpecificFundamentalTypesCheck.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index 4d59cae47c52b..da9e73660bace 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -1,10 +1,12 @@ -//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -------*- C++ -*-===// +// clang-format off +//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -*- 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 // -//===-------------------------------------------------------------------------------===// +//===-------------------------------------------------------------------------===// +// clang-format on #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H @@ -43,7 +45,8 @@ class AvoidPlatformSpecificFundamentalTypesCheck : public ClangTidyCheck { private: const bool WarnOnFloats; utils::IncludeInserter IncludeInserter; - std::string getFloatReplacement(const BuiltinType *BT, ASTContext &Context) const; + std::string getFloatReplacement(const BuiltinType *BT, + ASTContext &Context) const; }; } // namespace clang::tidy::portability From 40b8be31da0db152ac0c7ee2aff3cae29dc062d2 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 01:10:01 -0400 Subject: [PATCH 19/38] Allow for int to not be warned --- ...dPlatformSpecificFundamentalTypesCheck.cpp | 70 +++++++++++-------- ...oidPlatformSpecificFundamentalTypesCheck.h | 1 + ...tform-specific-fundamental-types-ints.cpp} | 0 3 files changed, 43 insertions(+), 28 deletions(-) rename clang-tools-extra/test/clang-tidy/checkers/portability/{avoid-platform-specific-fundamental-types.cpp => avoid-platform-specific-fundamental-types-ints.cpp} (100%) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 6ea84516def42..c5f320c89dbb1 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -21,6 +21,7 @@ AvoidPlatformSpecificFundamentalTypesCheck:: ClangTidyContext *Context) : ClangTidyCheck(Name, Context), WarnOnFloats(Options.get("WarnOnFloats", false)), + WarnOnInts(Options.get("WarnOnInts", true)), IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", utils::IncludeSorter::IS_LLVM), areDiagsSelfContained()) {} @@ -33,6 +34,7 @@ void AvoidPlatformSpecificFundamentalTypesCheck::registerPPCallbacks( void AvoidPlatformSpecificFundamentalTypesCheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "WarnOnFloats", WarnOnFloats); + Options.store(Opts, "WarnOnInts", WarnOnInts); Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); } @@ -74,37 +76,49 @@ std::string AvoidPlatformSpecificFundamentalTypesCheck::getFloatReplacement( void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( MatchFinder *Finder) { // Build the list of type strings to match - std::vector TypeStrings = {"short", - "short int", - "signed short", - "signed short int", - "unsigned short", - "unsigned short int", - "int", - "signed", - "signed int", - "unsigned", - "unsigned int", - "long", - "long int", - "signed long", - "signed long int", - "unsigned long", - "unsigned long int", - "long long", - "long long int", - "signed long long", - "signed long long int", - "unsigned long long", - "unsigned long long int"}; + std::vector TypeStrings; + + // Add integer types if the option is enabled + if (WarnOnInts) { + TypeStrings.insert(TypeStrings.end(), { + "short", + "short int", + "signed short", + "signed short int", + "unsigned short", + "unsigned short int", + "int", + "signed", + "signed int", + "unsigned", + "unsigned int", + "long", + "long int", + "signed long", + "signed long int", + "unsigned long", + "unsigned long int", + "long long", + "long long int", + "signed long long", + "signed long long int", + "unsigned long long", + "unsigned long long int"}); + } // Add float types if the option is enabled if (WarnOnFloats) { - TypeStrings.push_back("half"); - TypeStrings.push_back("__bf16"); - TypeStrings.push_back("float"); - TypeStrings.push_back("double"); - TypeStrings.push_back("long double"); + TypeStrings.insert(TypeStrings.end(), { + "half", + "__bf16", + "float", + "double", + "long double"}); + } + + // If no types are enabled, return early + if (TypeStrings.empty()) { + return; } // Create the matcher dynamically diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index da9e73660bace..c15660a9cf1f8 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -44,6 +44,7 @@ class AvoidPlatformSpecificFundamentalTypesCheck : public ClangTidyCheck { private: const bool WarnOnFloats; + const bool WarnOnInts; utils::IncludeInserter IncludeInserter; std::string getFloatReplacement(const BuiltinType *BT, ASTContext &Context) const; diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp similarity index 100% rename from clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types.cpp rename to clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp From 93c8489cb193c786056cf12f11f7eadd109f9dcd Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 01:13:38 -0400 Subject: [PATCH 20/38] Reduce some duplication --- ...dPlatformSpecificFundamentalTypesCheck.cpp | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index c5f320c89dbb1..3b783ccc2e764 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -172,46 +172,40 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( QualType QT; SourceRange TypeRange; + auto SetTypeRange = [&TypeRange](auto Decl){ + if(Decl->getTypeSourceInfo()) { + TypeRange = Decl->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + } + }; + if (const auto *VD = Result.Nodes.getNodeAs("var_decl")) { Loc = VD->getLocation(); QT = VD->getType(); - if (VD->getTypeSourceInfo()) { - TypeRange = VD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); - } + SetTypeRange(VD); } else if (const auto *FD = Result.Nodes.getNodeAs("func_decl")) { Loc = FD->getLocation(); QT = FD->getReturnType(); - if (FD->getTypeSourceInfo()) { - TypeRange = FD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); - } + SetTypeRange(FD); } else if (const auto *PD = Result.Nodes.getNodeAs("param_decl")) { Loc = PD->getLocation(); QT = PD->getType(); - if (PD->getTypeSourceInfo()) { - TypeRange = PD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); - } + SetTypeRange(PD); } else if (const auto *FD = Result.Nodes.getNodeAs("field_decl")) { Loc = FD->getLocation(); QT = FD->getType(); - if (FD->getTypeSourceInfo()) { - TypeRange = FD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); - } + SetTypeRange(FD); } else if (const auto *TD = Result.Nodes.getNodeAs("typedef_decl")) { Loc = TD->getLocation(); QT = TD->getUnderlyingType(); - if (TD->getTypeSourceInfo()) { - TypeRange = TD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); - } + SetTypeRange(TD); } else if (const auto *AD = Result.Nodes.getNodeAs("alias_decl")) { Loc = AD->getLocation(); QT = AD->getUnderlyingType(); - if (AD->getTypeSourceInfo()) { - TypeRange = AD->getTypeSourceInfo()->getTypeLoc().getSourceRange(); - } + SetTypeRange(AD); } else { return; } From 91eb7655fa848b9b8a60f4ad44f444b3e78b4346 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 01:36:58 -0400 Subject: [PATCH 21/38] vibecoding: not even once --- .../AvoidPlatformSpecificFundamentalTypesCheck.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 3b783ccc2e764..b9ed6c6078e3b 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -215,13 +215,8 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( // Check if this is a floating point type const auto *BT = QT->getAs(); - bool IsFloatingPoint = BT && (BT->getKind() == BuiltinType::Half || - BT->getKind() == BuiltinType::BFloat16 || - BT->getKind() == BuiltinType::Float || - BT->getKind() == BuiltinType::Double || - BT->getKind() == BuiltinType::LongDouble); - if (IsFloatingPoint) { + if (BT->isFloatingPoint()) { // Handle floating point types std::string Replacement = getFloatReplacement(BT, *Result.Context); if (!Replacement.empty()) { From 723a76e716433cbc0675d675fb6e54aca70945d5 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 01:39:18 -0400 Subject: [PATCH 22/38] For each loop --- .../AvoidPlatformSpecificFundamentalTypesCheck.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index b9ed6c6078e3b..6621480b448ca 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -122,9 +122,9 @@ void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( } // Create the matcher dynamically - auto TypeMatcher = asString(TypeStrings[0]); - for (size_t i = 1; i < TypeStrings.size(); ++i) { - TypeMatcher = anyOf(TypeMatcher, asString(TypeStrings[i])); + auto TypeMatcher = asString(TypeStrings.front()); + for (const auto& TypeString : TypeStrings) { + TypeMatcher = anyOf(TypeMatcher, asString(TypeString)); } auto PlatformSpecificFundamentalType = qualType(allOf( From a30bedf1cec06544e6ba67bdb21e65ace08466ba Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 01:39:37 -0400 Subject: [PATCH 23/38] Format code --- .../AvoidPlatformSpecificFundamentalTypesCheck.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 6621480b448ca..bae2712134a53 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -123,7 +123,7 @@ void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( // Create the matcher dynamically auto TypeMatcher = asString(TypeStrings.front()); - for (const auto& TypeString : TypeStrings) { + for (const auto &TypeString : TypeStrings) { TypeMatcher = anyOf(TypeMatcher, asString(TypeString)); } @@ -172,8 +172,8 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( QualType QT; SourceRange TypeRange; - auto SetTypeRange = [&TypeRange](auto Decl){ - if(Decl->getTypeSourceInfo()) { + auto SetTypeRange = [&TypeRange](auto Decl) { + if (Decl->getTypeSourceInfo()) { TypeRange = Decl->getTypeSourceInfo()->getTypeLoc().getSourceRange(); } }; From 76125bb2832a7db4ef0cba4b4884f1253d79d6a4 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 01:54:30 -0400 Subject: [PATCH 24/38] Warn on chars --- ...dPlatformSpecificFundamentalTypesCheck.cpp | 20 +++++- ...oidPlatformSpecificFundamentalTypesCheck.h | 1 + ...id-platform-specific-fundamental-types.rst | 32 ++++++++++ ...tform-specific-fundamental-types-chars.cpp | 63 +++++++++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index bae2712134a53..87ca48cdee46e 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -22,6 +22,7 @@ AvoidPlatformSpecificFundamentalTypesCheck:: : ClangTidyCheck(Name, Context), WarnOnFloats(Options.get("WarnOnFloats", false)), WarnOnInts(Options.get("WarnOnInts", true)), + WarnOnChars(Options.get("WarnOnChars", false)), IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", utils::IncludeSorter::IS_LLVM), areDiagsSelfContained()) {} @@ -35,6 +36,7 @@ void AvoidPlatformSpecificFundamentalTypesCheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "WarnOnFloats", WarnOnFloats); Options.store(Opts, "WarnOnInts", WarnOnInts); + Options.store(Opts, "WarnOnChars", WarnOnChars); Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); } @@ -116,6 +118,14 @@ void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( "long double"}); } + // Add char types if the option is enabled + if (WarnOnChars) { + TypeStrings.insert(TypeStrings.end(), { + "char", + "signed char", + "unsigned char"}); + } + // If no types are enabled, return early if (TypeStrings.empty()) { return; @@ -213,7 +223,7 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( // Get the type name for the diagnostic const std::string TypeName = QT.getAsString(); - // Check if this is a floating point type + // Check the type category const auto *BT = QT->getAs(); if (BT->isFloatingPoint()) { @@ -238,6 +248,14 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( "consider using a typedef or fixed-width type instead") << TypeName; } + } else if (BT->getKind() == BuiltinType::Char_S || + BT->getKind() == BuiltinType::Char_U || + BT->getKind() == BuiltinType::SChar || + BT->getKind() == BuiltinType::UChar) { + // Handle char types + diag(Loc, "avoid using platform-dependent character type '%0'; " + "consider using char8_t for text or std::byte for bytes") + << TypeName; } else { // Handle integer types diag(Loc, "avoid using platform-dependent fundamental integer type '%0'; " diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index c15660a9cf1f8..f4bea1e631953 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -45,6 +45,7 @@ class AvoidPlatformSpecificFundamentalTypesCheck : public ClangTidyCheck { private: const bool WarnOnFloats; const bool WarnOnInts; + const bool WarnOnChars; utils::IncludeInserter IncludeInserter; std::string getFloatReplacement(const BuiltinType *BT, ASTContext &Context) const; diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst index 6f0835aba9c41..155006586f3bd 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst @@ -156,3 +156,35 @@ Options float32_t pi = 3.14f; float64_t e = 2.71828; + +.. option:: WarnOnChars + + When `true`, the check will warn about character types (``char``, ``signed char``, and ``unsigned char``). + When `false` (default), character types are not flagged. + + Character types can have platform-dependent behavior: + + - ``char`` can be either signed or unsigned depending on the platform (signed on ARM, unsigned on x86) + - The signedness of ``char`` affects comparisons and arithmetic operations + + When this option is enabled, the check will suggest using explicit signedness or typedefs + to make the intent clear and ensure consistent behavior across platforms. + + Example with ``WarnOnChars`` enabled: + + .. code-block:: c++ + + // Bad: platform-dependent character types + char buffer[256]; + signed char byte_value = -1; + unsigned char raw_byte = 255; + + .. code-block:: c++ + + // Good: use explicit types or typedefs + using byte_t = unsigned char; // For raw byte data + using text_char_t = char; // For text (when signedness doesn't matter) + + text_char_t buffer[256]; // For text storage + int8_t signed_byte = -1; // For signed 8-bit values + uint8_t raw_byte = 255; // For unsigned 8-bit values diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp new file mode 100644 index 0000000000000..e7307823dc22d --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp @@ -0,0 +1,63 @@ +// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: true}]}" -header-filter=.* -- -std=c++11 + +// Test character types that should trigger warnings when WarnOnChars is enabled +char global_char = 'a'; +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid using platform-dependent character type 'char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +signed char global_signed_char = 'b'; +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: avoid using platform-dependent character type 'signed char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +unsigned char global_unsigned_char = 'c'; +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: avoid using platform-dependent character type 'unsigned char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +// Function parameters +void func_with_char_param(char param) {} +// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: avoid using platform-dependent character type 'char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +void func_with_signed_char_param(signed char param) {} +// CHECK-MESSAGES: :[[@LINE-1]]:46: warning: avoid using platform-dependent character type 'signed char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +void func_with_unsigned_char_param(unsigned char param) {} +// CHECK-MESSAGES: :[[@LINE-1]]:50: warning: avoid using platform-dependent character type 'unsigned char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +// Function return types +char func_returning_char() { return 'a'; } +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid using platform-dependent character type 'char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +signed char func_returning_signed_char() { return 'b'; } +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: avoid using platform-dependent character type 'signed char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +unsigned char func_returning_unsigned_char() { return 'c'; } +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: avoid using platform-dependent character type 'unsigned char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +// Struct fields +struct TestStruct { + char field_char; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: avoid using platform-dependent character type 'char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + + signed char field_signed_char; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: avoid using platform-dependent character type 'signed char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + + unsigned char field_unsigned_char; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: avoid using platform-dependent character type 'unsigned char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] +}; + +// Typedefs +typedef char char_typedef; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: avoid using platform-dependent character type 'char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +typedef signed char signed_char_typedef; +// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: avoid using platform-dependent character type 'signed char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +typedef unsigned char unsigned_char_typedef; +// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: avoid using platform-dependent character type 'unsigned char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +// Type aliases (C++11) +using char_alias = char; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent character type 'char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +using signed_char_alias = signed char; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent character type 'signed char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +using unsigned_char_alias = unsigned char; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent character type 'unsigned char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] From 8258324cb681363aff02c6dcbec884400af8f27a Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 01:59:41 -0400 Subject: [PATCH 25/38] Fix header doc --- .../AvoidPlatformSpecificFundamentalTypesCheck.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index f4bea1e631953..dd7652c770d4c 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -16,13 +16,11 @@ namespace clang::tidy::portability { -/// Find fundamental integer types and recommend using typedefs or fixed-width -/// types. +/// Find fundamental platform-dependent types and recommend using typedefs or +/// fixed-width types. /// -/// Detects fundamental integer types (int, short, long, long long, and their -/// unsigned variants) and warns against their use due to platform-dependent -/// behavior. Excludes semantic types like char, bool, wchar_t, char16_t, -/// char32_t, size_t, and ptrdiff_t. +/// Detects fundamental types (int, short, long, long long, char, float, etc) +/// and warns against their use due to platform-dependent behavior. /// /// For the user-facing documentation see: /// http://clang.llvm.org/extra/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.html From 8dd606b33698a5595471051636fcf2da45b47e21 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 02:03:44 -0400 Subject: [PATCH 26/38] Forgot to format --- ...dPlatformSpecificFundamentalTypesCheck.cpp | 61 ++++++++----------- ...oidPlatformSpecificFundamentalTypesCheck.h | 4 +- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 87ca48cdee46e..e9d403540560f 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -82,48 +82,41 @@ void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( // Add integer types if the option is enabled if (WarnOnInts) { - TypeStrings.insert(TypeStrings.end(), { - "short", - "short int", - "signed short", - "signed short int", - "unsigned short", - "unsigned short int", - "int", - "signed", - "signed int", - "unsigned", - "unsigned int", - "long", - "long int", - "signed long", - "signed long int", - "unsigned long", - "unsigned long int", - "long long", - "long long int", - "signed long long", - "signed long long int", - "unsigned long long", - "unsigned long long int"}); + TypeStrings.insert(TypeStrings.end(), {"short", + "short int", + "signed short", + "signed short int", + "unsigned short", + "unsigned short int", + "int", + "signed", + "signed int", + "unsigned", + "unsigned int", + "long", + "long int", + "signed long", + "signed long int", + "unsigned long", + "unsigned long int", + "long long", + "long long int", + "signed long long", + "signed long long int", + "unsigned long long", + "unsigned long long int"}); } // Add float types if the option is enabled if (WarnOnFloats) { - TypeStrings.insert(TypeStrings.end(), { - "half", - "__bf16", - "float", - "double", - "long double"}); + TypeStrings.insert(TypeStrings.end(), + {"half", "__bf16", "float", "double", "long double"}); } // Add char types if the option is enabled if (WarnOnChars) { - TypeStrings.insert(TypeStrings.end(), { - "char", - "signed char", - "unsigned char"}); + TypeStrings.insert(TypeStrings.end(), + {"char", "signed char", "unsigned char"}); } // If no types are enabled, return early diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index dd7652c770d4c..d7b1582cf8f41 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -16,10 +16,10 @@ namespace clang::tidy::portability { -/// Find fundamental platform-dependent types and recommend using typedefs or +/// Find fundamental platform-dependent types and recommend using typedefs or /// fixed-width types. /// -/// Detects fundamental types (int, short, long, long long, char, float, etc) +/// Detects fundamental types (int, short, long, long long, char, float, etc) /// and warns against their use due to platform-dependent behavior. /// /// For the user-facing documentation see: From 90c98871c280500dac53ba1f0452359073a4027e Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 16:23:59 -0400 Subject: [PATCH 27/38] Fix typo --- .../avoid-platform-specific-fundamental-types.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst index 155006586f3bd..289f10e4fdce9 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst @@ -92,11 +92,11 @@ Fundamental types have platform-dependent sizes and behavior: The C++ specification does not define these types beyond their minimum sizes. That means they can communicate intent in non-standard ways and are often -needlessly incompatible. For example, ``int``was traditionally the word size of -a given processor in 16-bit and 32-bit computing and was a reasonable default -for performance. This is no longer true on modern 64-bit computers, but the -size of ``int`` remains fixed at 32 bits for backwards compatibility with code -that relied on a 32-bit implementation of ``int``. +needlessly incompatible. For example, ``int`` was traditionally the word size +of a given processor in 16-bit and 32-bit computing and was a reasonable +default for performance. This is no longer true on modern 64-bit computers, but +the size of ``int`` remains fixed at 32 bits for backwards compatibility with +code that relied on a 32-bit implementation of ``int``. If code is explicitly relying on the size of an ``int`` being 32 bits, it is better to say so in the typename with ``int32_t``. Otherwise, use an From c487bf3176bb58c200caf1c93247e530ce6367a6 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 16:25:36 -0400 Subject: [PATCH 28/38] Fix formatting --- .../AvoidPlatformSpecificFundamentalTypesCheck.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index d7b1582cf8f41..6b214a546002f 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -1,12 +1,10 @@ -// clang-format off -//===--- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -*- C++ -*-===// +//==-- AvoidPlatformSpecificFundamentalTypesCheck.h - clang-tidy -*- 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 // -//===-------------------------------------------------------------------------===// -// clang-format on +//==------------------------------------------------------------------------==// #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPLATFORMSPECIFICFUNDAMENTALTYPESCHECK_H From 09a762d881624871e54c84a6e9a2ec11a0338cf2 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 16:27:27 -0400 Subject: [PATCH 29/38] Declare as const --- .../portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index e9d403540560f..74256ba34d7d4 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -221,7 +221,7 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( if (BT->isFloatingPoint()) { // Handle floating point types - std::string Replacement = getFloatReplacement(BT, *Result.Context); + const std::string Replacement = getFloatReplacement(BT, *Result.Context); if (!Replacement.empty()) { auto Diag = diag(Loc, "avoid using platform-dependent floating point type '%0'; " From a53b5bcf50975d98aa4377bd805f1f1552f045a9 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Sun, 6 Jul 2025 16:35:14 -0400 Subject: [PATCH 30/38] Add WarnOnInts documentation --- ...id-platform-specific-fundamental-types.rst | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst index 289f10e4fdce9..3a74e7d9f6529 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst @@ -126,6 +126,43 @@ narrowing issues that occur as a result of using implementation-defined types. Options ------- +.. option:: WarnOnInts + + When `true` (default), the check will warn about fundamental integer types (``short``, ``int``, ``long``, ``long long`` and their ``signed`` and ``unsigned`` variants). + When `false`, integer types are not flagged. + + Example with ``WarnOnInts`` enabled (default): + + .. code-block:: c++ + + // Bad: platform-dependent integer types + #include + + int counter = 0; + long timestamp = 12345L; + unsigned short port = 8080; + + std::vector vec; + // If int is 32 bits and (vec.size > 2^31 - 1), this overflows + for(int i = 0; i + #include + + int32_t counter = 0; // When you need exactly 32 bits + int64_t timestamp = 12345L; // When you need exactly 64 bits + uint16_t port = 8080; // When you need exactly 16 unsigned bits + std::vector vec; + // A size_t is the maximum size of an object on a given platform + for(size_t i = 0U; i Date: Sun, 6 Jul 2025 16:39:27 -0400 Subject: [PATCH 31/38] Enable all checks by default --- ...AvoidPlatformSpecificFundamentalTypesCheck.cpp | 4 ++-- .../avoid-platform-specific-fundamental-types.rst | 8 ++++---- ...-platform-specific-fundamental-types-chars.cpp | 8 +++++++- ...platform-specific-fundamental-types-floats.cpp | 12 ++++++++---- ...d-platform-specific-fundamental-types-ints.cpp | 15 +++++++++------ 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 74256ba34d7d4..31cf10f3c2949 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -20,9 +20,9 @@ AvoidPlatformSpecificFundamentalTypesCheck:: AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), - WarnOnFloats(Options.get("WarnOnFloats", false)), + WarnOnFloats(Options.get("WarnOnFloats", true)), WarnOnInts(Options.get("WarnOnInts", true)), - WarnOnChars(Options.get("WarnOnChars", false)), + WarnOnChars(Options.get("WarnOnChars", true)), IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", utils::IncludeSorter::IS_LLVM), areDiagsSelfContained()) {} diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst index 3a74e7d9f6529..28b29544724fd 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-platform-specific-fundamental-types.rst @@ -165,8 +165,8 @@ Options .. option:: WarnOnFloats - When `true`, the check will warn about floating point types (``float`` and ``double``). - When `false` (default), floating point types are not flagged. + When `true` (default), the check will warn about floating point types (``float`` and ``double``). + When `false`, floating point types are not flagged. Floating point types can have platform-dependent behavior: @@ -196,8 +196,8 @@ Options .. option:: WarnOnChars - When `true`, the check will warn about character types (``char``, ``signed char``, and ``unsigned char``). - When `false` (default), character types are not flagged. + When `true` (default), the check will warn about character types (``char``, ``signed char``, and ``unsigned char``). + When `false`, character types are not flagged. Character types can have platform-dependent behavior: diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp index e7307823dc22d..59a0dbeefe840 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: true}]}" -header-filter=.* -- -std=c++11 +// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnInts, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: false}]}" -header-filter=.* -- -std=c++11 // Test character types that should trigger warnings when WarnOnChars is enabled char global_char = 'a'; @@ -61,3 +61,9 @@ using signed_char_alias = signed char; using unsigned_char_alias = unsigned char; // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: avoid using platform-dependent character type 'unsigned char'; consider using char8_t for text or std::byte for bytes [portability-avoid-platform-specific-fundamental-types] + +// Test that integer and float types are NOT flagged when their options are disabled +int should_not_warn_int = 42; +long should_not_warn_long = 100L; +float should_not_warn_float = 3.14f; +double should_not_warn_double = 2.71828; diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp index 22b3629731b66..4cea5fe84d4bb 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: true}]}" -header-filter=.* -- -std=c++23 +// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnInts, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: false}]}" -header-filter=.* -- -std=c++23 // Mock fixed-width float types // In reality, these types are aliases to "extended floating point types", and @@ -18,9 +18,6 @@ double global_double = 3.14159; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: avoid using platform-dependent floating point type 'double'; consider using 'float64_t' instead [portability-avoid-platform-specific-fundamental-types] // CHECK-FIXES: float64_t global_double = 3.14159; -// Test integer types that should still trigger warnings -int global_int = 42; -// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: avoid using platform-dependent fundamental integer type 'int'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] // Test function parameters with float types void function_with_float_param(float param) { @@ -98,3 +95,10 @@ template<> void template_function(double param) { // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: avoid using platform-dependent floating point type 'double'; consider using 'float64_t' instead [portability-avoid-platform-specific-fundamental-types] } + +// Test that integer and char types are NOT flagged when their options are disabled +int should_not_warn_int = 42; +long should_not_warn_long = 100L; +char should_not_warn_char = 'a'; +signed char should_not_warn_signed_char = 'b'; +unsigned char should_not_warn_unsigned_char = 'c'; diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp index 337166cdf3699..c072fb8a52590 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t +// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: false}]}" -header-filter=.* -- -std=c++11 // Mock fixed-width integer types // NOLINTBEGIN(portability-avoid-platform-specific-fundamental-types) @@ -40,12 +40,15 @@ unsigned long global_unsigned_long = 100UL; unsigned long long global_unsigned_long_long = 1000ULL; // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: avoid using platform-dependent fundamental integer type 'unsigned long long'; consider using a typedef or fixed-width type instead [portability-avoid-platform-specific-fundamental-types] -// Test semantic types that should NOT trigger warnings -char global_char = 'a'; -signed char global_signed_char = 'b'; -unsigned char global_unsigned_char = 'c'; +// Test integer that should NEVER trigger warnings bool global_bool = true; -wchar_t global_wchar = L'w'; + +// Test that char and float types are NOT flagged when their options are disabled +float should_not_warn_float = 3.14f; +double should_not_warn_double = 2.71828; +char should_not_warn_char = 'a'; +signed char should_not_warn_signed_char = 'b'; +unsigned char should_not_warn_unsigned_char = 'c'; // Test fixed-width types that should NOT trigger warnings uint32_t global_uint32 = 42U; From de662e86a7a61ee8c67e6cfc41f5ef2974a6389d Mon Sep 17 00:00:00 2001 From: JJ Marr <168750718+jj-marr@users.noreply.github.com> Date: Sun, 6 Jul 2025 22:49:24 -0400 Subject: [PATCH 32/38] Update clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp Co-authored-by: Baranov Victor --- .../portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 31cf10f3c2949..272c832be29ff 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "AvoidPlatformSpecificFundamentalTypesCheck.h" -#include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/TargetInfo.h" From d0012d364c4367eed28e1858249203517436dd43 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 10 Jul 2025 20:00:08 -0400 Subject: [PATCH 33/38] Fix formatting more --- .../AvoidPlatformSpecificFundamentalTypesCheck.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 272c832be29ff..abe8649b7593f 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -119,15 +119,13 @@ void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( } // If no types are enabled, return early - if (TypeStrings.empty()) { + if (TypeStrings.empty()) return; - } // Create the matcher dynamically auto TypeMatcher = asString(TypeStrings.front()); - for (const auto &TypeString : TypeStrings) { + for (const auto &TypeString : TypeStrings) TypeMatcher = anyOf(TypeMatcher, asString(TypeString)); - } auto PlatformSpecificFundamentalType = qualType(allOf( // Must be a builtin type directly (not through typedef) @@ -175,9 +173,8 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( SourceRange TypeRange; auto SetTypeRange = [&TypeRange](auto Decl) { - if (Decl->getTypeSourceInfo()) { + if (Decl->getTypeSourceInfo()) TypeRange = Decl->getTypeSourceInfo()->getTypeLoc().getSourceRange(); - } }; if (const auto *VD = Result.Nodes.getNodeAs("var_decl")) { @@ -227,9 +224,8 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( "consider using '%1' instead") << TypeName << Replacement; - if (TypeRange.isValid()) { + if (TypeRange.isValid()) Diag << FixItHint::CreateReplacement(TypeRange, Replacement); - } if (auto IncludeFixit = IncludeInserter.createIncludeInsertion( Result.SourceManager->getFileID(Loc), "")) { From 304b7b0d446bdeeeae697be4562d5ce85af84f3d Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 10 Jul 2025 20:10:30 -0400 Subject: [PATCH 34/38] Use or later standards --- .../avoid-platform-specific-fundamental-types-chars.cpp | 2 +- .../avoid-platform-specific-fundamental-types-floats.cpp | 2 +- .../avoid-platform-specific-fundamental-types-ints.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp index 59a0dbeefe840..d7cb01cf23b51 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnInts, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: false}]}" -header-filter=.* -- -std=c++11 +// RUN: %check_clang_tidy -std=c++11-or-later %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnInts, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: false}]}" -header-filter=.* // Test character types that should trigger warnings when WarnOnChars is enabled char global_char = 'a'; diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp index 4cea5fe84d4bb..31d8839b6398b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnInts, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: false}]}" -header-filter=.* -- -std=c++23 +// RUN: %check_clang_tidy -std=c++23-or-later %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnInts, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: false}]}" -header-filter=.* // Mock fixed-width float types // In reality, these types are aliases to "extended floating point types", and diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp index c072fb8a52590..cef758c9bc7ea 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: false}]}" -header-filter=.* -- -std=c++11 +// RUN: %check_clang_tidy -std=c++11-or-later %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: false}]}" -header-filter=.* // Mock fixed-width integer types // NOLINTBEGIN(portability-avoid-platform-specific-fundamental-types) From e66cf7bbedf1c63b8c807c5b8dd306306c0a6694 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 10 Jul 2025 20:10:59 -0400 Subject: [PATCH 35/38] Remove header filters --- .../avoid-platform-specific-fundamental-types-chars.cpp | 2 +- .../avoid-platform-specific-fundamental-types-floats.cpp | 2 +- .../avoid-platform-specific-fundamental-types-ints.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp index d7cb01cf23b51..9648a84bf64cb 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-chars.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy -std=c++11-or-later %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnInts, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: false}]}" -header-filter=.* +// RUN: %check_clang_tidy -std=c++11-or-later %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnInts, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: false}]}" // Test character types that should trigger warnings when WarnOnChars is enabled char global_char = 'a'; diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp index 31d8839b6398b..9e4605aacec67 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-floats.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy -std=c++23-or-later %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnInts, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: false}]}" -header-filter=.* +// RUN: %check_clang_tidy -std=c++23-or-later %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnInts, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: false}]}" // Mock fixed-width float types // In reality, these types are aliases to "extended floating point types", and diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp index cef758c9bc7ea..a4b40595245ce 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-platform-specific-fundamental-types-ints.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy -std=c++11-or-later %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: false}]}" -header-filter=.* +// RUN: %check_clang_tidy -std=c++11-or-later %s portability-avoid-platform-specific-fundamental-types %t -- -config="{CheckOptions: [{key: portability-avoid-platform-specific-fundamental-types.WarnOnChars, value: false}, {key: portability-avoid-platform-specific-fundamental-types.WarnOnFloats, value: false}]}" // Mock fixed-width integer types // NOLINTBEGIN(portability-avoid-platform-specific-fundamental-types) From c2f53d98e2f50a556cd598060db0695c961a4656 Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 10 Jul 2025 20:57:44 -0400 Subject: [PATCH 36/38] Replace string matching --- ...dPlatformSpecificFundamentalTypesCheck.cpp | 117 ++++++++++-------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index abe8649b7593f..5c6b0f6eb2a2d 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -7,12 +7,69 @@ //===----------------------------------------------------------------------===// #include "AvoidPlatformSpecificFundamentalTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/TargetInfo.h" using namespace clang::ast_matchers; +namespace { +AST_MATCHER(clang::QualType, isBuiltinInt) { + const auto *BT = Node->getAs(); + if (!BT) + return false; + + switch (BT->getKind()) { + case clang::BuiltinType::Short: + case clang::BuiltinType::UShort: + case clang::BuiltinType::Int: + case clang::BuiltinType::UInt: + case clang::BuiltinType::Long: + case clang::BuiltinType::ULong: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::ULongLong: + return true; + default: + return false; + } +} + +AST_MATCHER(clang::QualType, isBuiltinFloat) { + const auto *BT = Node->getAs(); + if (!BT) + return false; + + switch (BT->getKind()) { + case clang::BuiltinType::Half: + case clang::BuiltinType::BFloat16: + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + return true; + default: + return false; + } +} + +AST_MATCHER(clang::QualType, isBuiltinChar) { + const auto *BT = Node->getAs(); + if (!BT) + return false; + + switch (BT->getKind()) { + case clang::BuiltinType::Char_S: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::SChar: + case clang::BuiltinType::UChar: + return true; + default: + return false; + } +} +} // namespace + namespace clang::tidy::portability { AvoidPlatformSpecificFundamentalTypesCheck:: @@ -76,63 +133,17 @@ std::string AvoidPlatformSpecificFundamentalTypesCheck::getFloatReplacement( void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( MatchFinder *Finder) { - // Build the list of type strings to match - std::vector TypeStrings; - - // Add integer types if the option is enabled - if (WarnOnInts) { - TypeStrings.insert(TypeStrings.end(), {"short", - "short int", - "signed short", - "signed short int", - "unsigned short", - "unsigned short int", - "int", - "signed", - "signed int", - "unsigned", - "unsigned int", - "long", - "long int", - "signed long", - "signed long int", - "unsigned long", - "unsigned long int", - "long long", - "long long int", - "signed long long", - "signed long long int", - "unsigned long long", - "unsigned long long int"}); - } - - // Add float types if the option is enabled - if (WarnOnFloats) { - TypeStrings.insert(TypeStrings.end(), - {"half", "__bf16", "float", "double", "long double"}); - } - - // Add char types if the option is enabled - if (WarnOnChars) { - TypeStrings.insert(TypeStrings.end(), - {"char", "signed char", "unsigned char"}); - } + // Create the type matcher using the three separate matchers + auto PlatformSpecificFundamentalType = qualType( + allOf(builtinType(), + anyOf(WarnOnInts ? isBuiltinInt() : unless(anything()), + WarnOnFloats ? isBuiltinFloat() : unless(anything()), + WarnOnChars ? isBuiltinChar() : unless(anything())))); // If no types are enabled, return early - if (TypeStrings.empty()) + if (!WarnOnInts && !WarnOnFloats && !WarnOnChars) return; - // Create the matcher dynamically - auto TypeMatcher = asString(TypeStrings.front()); - for (const auto &TypeString : TypeStrings) - TypeMatcher = anyOf(TypeMatcher, asString(TypeString)); - - auto PlatformSpecificFundamentalType = qualType(allOf( - // Must be a builtin type directly (not through typedef) - builtinType(), - // Match the specific fundamental types we care about - TypeMatcher)); - // Match variable declarations with platform-specific fundamental types Finder->addMatcher( varDecl(hasType(PlatformSpecificFundamentalType)).bind("var_decl"), this); From 32343ae50742930f330ecb67ab1bf916723f8a9c Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 10 Jul 2025 20:59:13 -0400 Subject: [PATCH 37/38] Remove useless comments --- ...AvoidPlatformSpecificFundamentalTypesCheck.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 5c6b0f6eb2a2d..410654b274a46 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -133,45 +133,35 @@ std::string AvoidPlatformSpecificFundamentalTypesCheck::getFloatReplacement( void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( MatchFinder *Finder) { - // Create the type matcher using the three separate matchers auto PlatformSpecificFundamentalType = qualType( allOf(builtinType(), anyOf(WarnOnInts ? isBuiltinInt() : unless(anything()), WarnOnFloats ? isBuiltinFloat() : unless(anything()), WarnOnChars ? isBuiltinChar() : unless(anything())))); - // If no types are enabled, return early if (!WarnOnInts && !WarnOnFloats && !WarnOnChars) return; - // Match variable declarations with platform-specific fundamental types Finder->addMatcher( varDecl(hasType(PlatformSpecificFundamentalType)).bind("var_decl"), this); - // Match function declarations with platform-specific fundamental return types Finder->addMatcher( functionDecl(returns(PlatformSpecificFundamentalType)).bind("func_decl"), this); - // Match function parameters with platform-specific fundamental types Finder->addMatcher( parmVarDecl(hasType(PlatformSpecificFundamentalType)).bind("param_decl"), this); - // Match field declarations with platform-specific fundamental types Finder->addMatcher( fieldDecl(hasType(PlatformSpecificFundamentalType)).bind("field_decl"), this); - // Match typedef declarations with platform-specific fundamental underlying - // types Finder->addMatcher( typedefDecl(hasUnderlyingType(PlatformSpecificFundamentalType)) .bind("typedef_decl"), this); - // Match type alias declarations with platform-specific fundamental underlying - // types Finder->addMatcher(typeAliasDecl(hasType(PlatformSpecificFundamentalType)) .bind("alias_decl"), this); @@ -220,14 +210,11 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( return; } - // Get the type name for the diagnostic const std::string TypeName = QT.getAsString(); - // Check the type category const auto *BT = QT->getAs(); if (BT->isFloatingPoint()) { - // Handle floating point types const std::string Replacement = getFloatReplacement(BT, *Result.Context); if (!Replacement.empty()) { auto Diag = @@ -251,12 +238,10 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( BT->getKind() == BuiltinType::Char_U || BT->getKind() == BuiltinType::SChar || BT->getKind() == BuiltinType::UChar) { - // Handle char types diag(Loc, "avoid using platform-dependent character type '%0'; " "consider using char8_t for text or std::byte for bytes") << TypeName; } else { - // Handle integer types diag(Loc, "avoid using platform-dependent fundamental integer type '%0'; " "consider using a typedef or fixed-width type instead") << TypeName; From d37015e5f21708d7a64362c3e2e24a4c8a36361a Mon Sep 17 00:00:00 2001 From: JJ Marr Date: Thu, 10 Jul 2025 21:05:49 -0400 Subject: [PATCH 38/38] Add static helper functions --- ...dPlatformSpecificFundamentalTypesCheck.cpp | 33 ++++++++++--------- ...oidPlatformSpecificFundamentalTypesCheck.h | 2 -- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp index 410654b274a46..3543abb5604f1 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.cpp @@ -16,6 +16,20 @@ using namespace clang::ast_matchers; namespace { + +static bool isCharType(const clang::BuiltinType *BT) { + using clang::BuiltinType; + switch (BT->getKind()) { + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + return true; + default: + return false; + } +} + AST_MATCHER(clang::QualType, isBuiltinInt) { const auto *BT = Node->getAs(); if (!BT) @@ -58,15 +72,7 @@ AST_MATCHER(clang::QualType, isBuiltinChar) { if (!BT) return false; - switch (BT->getKind()) { - case clang::BuiltinType::Char_S: - case clang::BuiltinType::Char_U: - case clang::BuiltinType::SChar: - case clang::BuiltinType::UChar: - return true; - default: - return false; - } + return isCharType(BT); } } // namespace @@ -96,8 +102,8 @@ void AvoidPlatformSpecificFundamentalTypesCheck::storeOptions( Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); } -std::string AvoidPlatformSpecificFundamentalTypesCheck::getFloatReplacement( - const BuiltinType *BT, ASTContext &Context) const { +static std::string getFloatReplacement(const BuiltinType *BT, + ASTContext &Context) { const TargetInfo &Target = Context.getTargetInfo(); auto GetReplacementType = [](unsigned Width) { @@ -234,10 +240,7 @@ void AvoidPlatformSpecificFundamentalTypesCheck::check( "consider using a typedef or fixed-width type instead") << TypeName; } - } else if (BT->getKind() == BuiltinType::Char_S || - BT->getKind() == BuiltinType::Char_U || - BT->getKind() == BuiltinType::SChar || - BT->getKind() == BuiltinType::UChar) { + } else if (isCharType(BT)) { diag(Loc, "avoid using platform-dependent character type '%0'; " "consider using char8_t for text or std::byte for bytes") << TypeName; diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h index 6b214a546002f..95e62d983f65d 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h +++ b/clang-tools-extra/clang-tidy/portability/AvoidPlatformSpecificFundamentalTypesCheck.h @@ -43,8 +43,6 @@ class AvoidPlatformSpecificFundamentalTypesCheck : public ClangTidyCheck { const bool WarnOnInts; const bool WarnOnChars; utils::IncludeInserter IncludeInserter; - std::string getFloatReplacement(const BuiltinType *BT, - ASTContext &Context) const; }; } // namespace clang::tidy::portability