Skip to content
Merged
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/google/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ add_clang_library(clangTidyGoogleModule STATIC
DefaultArgumentsCheck.cpp
ExplicitConstructorCheck.cpp
ExplicitMakePairCheck.cpp
FloatTypesCheck.cpp
FunctionNamingCheck.cpp
GlobalNamesInHeadersCheck.cpp
GlobalVariableDeclarationCheck.cpp
Expand Down
77 changes: 77 additions & 0 deletions clang-tools-extra/clang-tidy/google/FloatTypesCheck.cpp
Original file line number Diff line number Diff line change
@@ -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<QualifiedTypeLoc>())
TL = QualLoc.getUnqualifiedLoc();

const auto BuiltinLoc = TL.getAs<BuiltinTypeLoc>();
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<BuiltinType>(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<TypeLoc>("longDoubleTypeLoc")) {
diag(TL->getBeginLoc(), "%0 type is not portable and should not be used")
<< TL->getType();
}

if (const auto *FL =
Result.Nodes.getNodeAs<FloatingLiteral>("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
34 changes: 34 additions & 0 deletions clang-tools-extra/clang-tidy/google/FloatTypesCheck.h
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -57,6 +58,8 @@ class GoogleModule : public ClangTidyModule {
"google-objc-function-naming");
CheckFactories.registerCheck<objc::GlobalVariableDeclarationCheck>(
"google-objc-global-variable-declaration");
CheckFactories.registerCheck<runtime::RuntimeFloatCheck>(
"google-runtime-float");
CheckFactories.registerCheck<runtime::IntegerTypesCheck>(
"google-runtime-int");
CheckFactories.registerCheck<runtime::OverloadedUnaryAndCheck>(
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
<clang-tidy/checks/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
<clang-tidy/checks/llvm/use-new-mlir-op-builder>` check.

Expand Down
10 changes: 10 additions & 0 deletions clang-tools-extra/docs/clang-tidy/checks/google/runtime-float.rst
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ Clang-Tidy Checks
:doc:`google-readability-avoid-underscore-in-googletest-name <google/readability-avoid-underscore-in-googletest-name>`,
:doc:`google-readability-casting <google/readability-casting>`,
:doc:`google-readability-todo <google/readability-todo>`,
:doc:`google-runtime-float <google/runtime-float>`,
:doc:`google-runtime-int <google/runtime-int>`,
:doc:`google-runtime-operator <google/runtime-operator>`,
:doc:`google-upgrade-googletest-case <google/upgrade-googletest-case>`, "Yes"
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <typename T>
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<long double>();
// 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{};
}