https://github.com/jj-marr updated https://github.com/llvm/llvm-project/pull/146970
>From 3ef4feb748551806c863529306fefb2bd914e5be Mon Sep 17 00:00:00 2001 From: JJ Marr <jjm...@gmail.com> Date: Thu, 3 Jul 2025 17:17:06 -0400 Subject: [PATCH 01/14] 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<clang::Type>, + 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<BuiltinType>(); + 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<BuiltinType>(); + 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<VarDecl>("var_decl")) { + Loc = VD->getLocation(); + QT = VD->getType(); + DeclType = "variable"; + } else if (const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func_decl")) { + Loc = FD->getLocation(); + QT = FD->getReturnType(); + DeclType = "function return type"; + } else if (const auto *PD = Result.Nodes.getNodeAs<ParmVarDecl>("param_decl")) { + Loc = PD->getLocation(); + QT = PD->getType(); + DeclType = "function parameter"; + } else if (const auto *FD = Result.Nodes.getNodeAs<FieldDecl>("field_decl")) { + Loc = FD->getLocation(); + QT = FD->getType(); + DeclType = "field"; + } else if (const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>("typedef_decl")) { + Loc = TD->getLocation(); + QT = TD->getUnderlyingType(); + DeclType = "typedef"; + } else if (const auto *AD = Result.Nodes.getNodeAs<TypeAliasDecl>("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<TraversalKind> 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<AvoidBindCheck>("modernize-avoid-bind"); CheckFactories.registerCheck<AvoidCArraysCheck>("modernize-avoid-c-arrays"); + CheckFactories.registerCheck<AvoidFundamentalIntegerTypesCheck>( + "modernize-avoid-fundamental-integer-types"); CheckFactories.registerCheck<ConcatNestedNamespacesCheck>( "modernize-concat-nested-namespaces"); CheckFactories.registerCheck<DeprecatedHeadersCheck>( 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<typename T> +void template_function(T param) {} + +template<> +void template_function<int>(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 <jjm...@gmail.com> Date: Thu, 3 Jul 2025 17:33:54 -0400 Subject: [PATCH 02/14] 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<TypedefType>()) { + 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<typename T> void template_function(T param) {} @@ -105,4 +138,4 @@ void template_function(T param) {} template<> void template_function<int>(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 <jjm...@gmail.com> Date: Thu, 3 Jul 2025 18:26:31 -0400 Subject: [PATCH 03/14] 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 <misc/use-internal-linkage>`, "Yes" :doc:`modernize-avoid-bind <modernize/avoid-bind>`, "Yes" :doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`, + :doc:`modernize-avoid-fundamental-integer-types <modernize/avoid-fundamental-integer-types>`, :doc:`modernize-concat-nested-namespaces <modernize/concat-nested-namespaces>`, "Yes" :doc:`modernize-deprecated-headers <modernize/deprecated-headers>`, "Yes" :doc:`modernize-deprecated-ios-base-aliases <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 <cstdint> + + 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 <jjm...@gmail.com> Date: Thu, 3 Jul 2025 21:50:01 -0400 Subject: [PATCH 04/14] 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 <jjm...@gmail.com> Date: Thu, 3 Jul 2025 22:27:08 -0400 Subject: [PATCH 05/14] 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<AvoidBindCheck>("modernize-avoid-bind"); CheckFactories.registerCheck<AvoidCArraysCheck>("modernize-avoid-c-arrays"); - CheckFactories.registerCheck<AvoidFundamentalIntegerTypesCheck>( - "modernize-avoid-fundamental-integer-types"); CheckFactories.registerCheck<ConcatNestedNamespacesCheck>( "modernize-concat-nested-namespaces"); CheckFactories.registerCheck<DeprecatedHeadersCheck>( 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<AvoidPlatformSpecificFundamentalTypesCheck>( + "portability-avoid-platform-specific-fundamental-types"); CheckFactories.registerCheck<AvoidPragmaOnceCheck>( "portability-avoid-pragma-once"); CheckFactories.registerCheck<RestrictSystemIncludesCheck>( 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 <misc/use-internal-linkage>`, "Yes" :doc:`modernize-avoid-bind <modernize/avoid-bind>`, "Yes" :doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`, - :doc:`modernize-avoid-fundamental-integer-types <modernize/avoid-fundamental-integer-types>`, :doc:`modernize-concat-nested-namespaces <modernize/concat-nested-namespaces>`, "Yes" :doc:`modernize-deprecated-headers <modernize/deprecated-headers>`, "Yes" :doc:`modernize-deprecated-ios-base-aliases <modernize/deprecated-ios-base-aliases>`, "Yes" @@ -354,6 +353,7 @@ Clang-Tidy Checks :doc:`performance-type-promotion-in-math-fn <performance/type-promotion-in-math-fn>`, "Yes" :doc:`performance-unnecessary-copy-initialization <performance/unnecessary-copy-initialization>`, "Yes" :doc:`performance-unnecessary-value-param <performance/unnecessary-value-param>`, "Yes" + :doc:`portability-avoid-platform-specific-fundamental-types <portability/avoid-platform-specific-fundamental-types>`, :doc:`portability-avoid-pragma-once <portability/avoid-pragma-once>`, :doc:`portability-restrict-system-includes <portability/restrict-system-includes>`, "Yes" :doc:`portability-simd-intrinsics <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<typename T> @@ -137,5 +137,5 @@ void template_function(T param) {} template<> void template_function<int>(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 <jjm...@gmail.com> Date: Thu, 3 Jul 2025 22:29:08 -0400 Subject: [PATCH 06/14] 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<FunctionDecl>("func_decl")) { + } else if (const auto *FD = + Result.Nodes.getNodeAs<FunctionDecl>("func_decl")) { Loc = FD->getLocation(); QT = FD->getReturnType(); DeclType = "function return type"; - } else if (const auto *PD = Result.Nodes.getNodeAs<ParmVarDecl>("param_decl")) { + } else if (const auto *PD = + Result.Nodes.getNodeAs<ParmVarDecl>("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<TypedefDecl>("typedef_decl")) { + } else if (const auto *TD = + Result.Nodes.getNodeAs<TypedefDecl>("typedef_decl")) { Loc = TD->getLocation(); QT = TD->getUnderlyingType(); DeclType = "typedef"; - } else if (const auto *AD = Result.Nodes.getNodeAs<TypeAliasDecl>("alias_decl")) { + } else if (const auto *AD = + Result.Nodes.getNodeAs<TypeAliasDecl>("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 <jjm...@gmail.com> Date: Thu, 3 Jul 2025 22:40:12 -0400 Subject: [PATCH 07/14] 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<clang::Type>, - 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<TypedefType>()) { - 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 <jjm...@gmail.com> Date: Thu, 3 Jul 2025 22:45:33 -0400 Subject: [PATCH 08/14] 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<BuiltinType>(); - 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<BuiltinType>(); - 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<VarDecl>("var_decl")) { Loc = VD->getLocation(); QT = VD->getType(); - DeclType = "variable"; } else if (const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func_decl")) { Loc = FD->getLocation(); QT = FD->getReturnType(); - DeclType = "function return type"; } else if (const auto *PD = Result.Nodes.getNodeAs<ParmVarDecl>("param_decl")) { Loc = PD->getLocation(); QT = PD->getType(); - DeclType = "function parameter"; } else if (const auto *FD = Result.Nodes.getNodeAs<FieldDecl>("field_decl")) { Loc = FD->getLocation(); QT = FD->getType(); - DeclType = "field"; } else if (const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>("typedef_decl")) { Loc = TD->getLocation(); QT = TD->getUnderlyingType(); - DeclType = "typedef"; } else if (const auto *AD = Result.Nodes.getNodeAs<TypeAliasDecl>("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<TraversalKind> 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 <jjm...@gmail.com> Date: Thu, 3 Jul 2025 22:48:57 -0400 Subject: [PATCH 09/14] 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 <jjm...@gmail.com> Date: Sat, 5 Jul 2025 15:20:19 -0400 Subject: [PATCH 10/14] 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 <jjm...@gmail.com> Date: Sat, 5 Jul 2025 15:21:33 -0400 Subject: [PATCH 11/14] 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 <jjm...@gmail.com> Date: Sat, 5 Jul 2025 15:23:17 -0400 Subject: [PATCH 12/14] 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 + <clang-tidy/checks/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 <clang-tidy/checks/portability/avoid-pragma-once>` check. >From 475f1b2bc2c817206222490e64e9e61560a9ed76 Mon Sep 17 00:00:00 2001 From: JJ Marr <jjm...@gmail.com> Date: Sat, 5 Jul 2025 15:46:45 -0400 Subject: [PATCH 13/14] 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 <jjm...@gmail.com> Date: Sat, 5 Jul 2025 15:46:51 -0400 Subject: [PATCH 14/14] 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(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits