diff --git a/clang-tools-extra/clang-tidy/google/CMakeLists.txt b/clang-tools-extra/clang-tidy/google/CMakeLists.txt index 2470c089ef7ca..1d4229ebb7b09 100644 --- a/clang-tools-extra/clang-tidy/google/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/google/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(clangTidyGoogleModule STATIC DefaultArgumentsCheck.cpp ExplicitConstructorCheck.cpp ExplicitMakePairCheck.cpp + FloatTypesCheck.cpp FunctionNamingCheck.cpp GlobalNamesInHeadersCheck.cpp GlobalVariableDeclarationCheck.cpp diff --git a/clang-tools-extra/clang-tidy/google/FloatTypesCheck.cpp b/clang-tools-extra/clang-tidy/google/FloatTypesCheck.cpp new file mode 100644 index 0000000000000..3d5fb021db296 --- /dev/null +++ b/clang-tools-extra/clang-tidy/google/FloatTypesCheck.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// 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 "FloatTypesCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +namespace clang { + +using namespace ast_matchers; + +namespace { + +AST_POLYMORPHIC_MATCHER(isValidAndNotInMacro, + AST_POLYMORPHIC_SUPPORTED_TYPES(TypeLoc, + FloatingLiteral)) { + const SourceLocation Loc = Node.getBeginLoc(); + return Loc.isValid() && !Loc.isMacroID(); +} + +AST_MATCHER(TypeLoc, isLongDoubleType) { + TypeLoc TL = Node; + if (const auto QualLoc = Node.getAs()) + TL = QualLoc.getUnqualifiedLoc(); + + const auto BuiltinLoc = TL.getAs(); + if (!BuiltinLoc) + return false; + + if (const auto *BT = BuiltinLoc.getTypePtr()) + return BT->getKind() == BuiltinType::LongDouble; + return false; +} + +AST_MATCHER(FloatingLiteral, isLongDoubleLiteral) { + if (const auto *BT = + dyn_cast_if_present(Node.getType().getTypePtr())) + return BT->getKind() == BuiltinType::LongDouble; + return false; +} + +} // namespace + +namespace tidy::google::runtime { + +void RuntimeFloatCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(typeLoc(loc(realFloatingPointType()), + isValidAndNotInMacro(), isLongDoubleType()) + .bind("longDoubleTypeLoc"), + this); + Finder->addMatcher(floatLiteral(isValidAndNotInMacro(), isLongDoubleLiteral()) + .bind("longDoubleFloatLiteral"), + this); +} + +void RuntimeFloatCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *TL = Result.Nodes.getNodeAs("longDoubleTypeLoc")) { + diag(TL->getBeginLoc(), "%0 type is not portable and should not be used") + << TL->getType(); + } + + if (const auto *FL = + Result.Nodes.getNodeAs("longDoubleFloatLiteral")) { + diag(FL->getBeginLoc(), "%0 type from literal suffix 'L' is not portable " + "and should not be used") + << FL->getType(); + } +} + +} // namespace tidy::google::runtime + +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/google/FloatTypesCheck.h b/clang-tools-extra/clang-tidy/google/FloatTypesCheck.h new file mode 100644 index 0000000000000..b5534c046e68f --- /dev/null +++ b/clang-tools-extra/clang-tidy/google/FloatTypesCheck.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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_GOOGLE_FLOATTYPESCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_FLOATTYPESCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::google::runtime { + +/// Finds usages of `long double` and suggests against their use due to lack +/// of portability. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/google/runtime-float.html +class RuntimeFloatCheck : public ClangTidyCheck { +public: + RuntimeFloatCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus && !LangOpts.ObjC; + } +}; + +} // namespace clang::tidy::google::runtime + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_FLOATTYPESCHECK_H diff --git a/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp b/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp index 5343e2b3a5975..eb5666be62bcf 100644 --- a/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp @@ -19,6 +19,7 @@ #include "DefaultArgumentsCheck.h" #include "ExplicitConstructorCheck.h" #include "ExplicitMakePairCheck.h" +#include "FloatTypesCheck.h" #include "FunctionNamingCheck.h" #include "GlobalNamesInHeadersCheck.h" #include "GlobalVariableDeclarationCheck.h" @@ -57,6 +58,8 @@ class GoogleModule : public ClangTidyModule { "google-objc-function-naming"); CheckFactories.registerCheck( "google-objc-global-variable-declaration"); + CheckFactories.registerCheck( + "google-runtime-float"); CheckFactories.registerCheck( "google-runtime-int"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 28620a92e4205..23d757b5e6f2e 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -155,6 +155,12 @@ New checks Finds calls to ``operator[]`` in STL containers and suggests replacing them with safe alternatives. +- New :doc:`google-runtime-float + ` check. + + Finds uses of ``long double`` and suggests against their use due to lack of + portability. + - New :doc:`llvm-mlir-op-builder ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/google/runtime-float.rst b/clang-tools-extra/docs/clang-tidy/checks/google/runtime-float.rst new file mode 100644 index 0000000000000..4b853ad56021d --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/google/runtime-float.rst @@ -0,0 +1,10 @@ +.. title:: clang-tidy - google-runtime-float + +google-runtime-float +==================== + +Finds uses of ``long double`` and suggests against their use due to lack of +portability. + +The corresponding style guide rule: +https://google.github.io/styleguide/cppguide.html#Floating-Point_Types diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 89ad491935f7f..c490d2ece2e0a 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -238,6 +238,7 @@ Clang-Tidy Checks :doc:`google-readability-avoid-underscore-in-googletest-name `, :doc:`google-readability-casting `, :doc:`google-readability-todo `, + :doc:`google-runtime-float `, :doc:`google-runtime-int `, :doc:`google-runtime-operator `, :doc:`google-upgrade-googletest-case `, "Yes" diff --git a/clang-tools-extra/test/clang-tidy/checkers/google/runtime-float.cpp b/clang-tools-extra/test/clang-tidy/checkers/google/runtime-float.cpp new file mode 100644 index 0000000000000..5c9cc11dbef2a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/google/runtime-float.cpp @@ -0,0 +1,40 @@ +// RUN: %check_clang_tidy %s google-runtime-float %t + +long double foo; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: 'long double' type is not portable and should not be used [google-runtime-float] + +typedef long double MyLongDouble; +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: 'long double' type is not portable and should not be used [google-runtime-float] + +typedef long double MyOtherLongDouble; // NOLINT + +template +void tmpl() { T i; } + +long volatile double v = 10; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: 'volatile long double' type is not portable and should not be used [google-runtime-float] + +long double h(long const double aaa, long double bbb = 0.5L) { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: 'long double' type is not portable and should not be used [google-runtime-float] + // CHECK-MESSAGES: :[[@LINE-2]]:15: warning: 'const long double' type is not portable and should not be used [google-runtime-float] + // CHECK-MESSAGES: :[[@LINE-3]]:38: warning: 'long double' type is not portable and should not be used [google-runtime-float] + // CHECK-MESSAGES: :[[@LINE-4]]:56: warning: 'long double' type from literal suffix 'L' is not portable and should not be used [google-runtime-float] + double x = 0.1; + double y = 0.2L; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'long double' type from literal suffix 'L' is not portable and should not be used [google-runtime-float] +#define ldtype long double + ldtype z; + tmpl(); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'long double' type is not portable and should not be used [google-runtime-float] + return 0; +} + +struct S{}; +constexpr S operator"" _baz(unsigned long long) { + long double j; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'long double' type is not portable and should not be used [google-runtime-float] + MyOtherLongDouble x; + long int a = 1L; + return S{}; +} +