Index: clang-tidy/cert/CERTTidyModule.cpp =================================================================== --- clang-tidy/cert/CERTTidyModule.cpp +++ clang-tidy/cert/CERTTidyModule.cpp @@ -16,6 +16,7 @@ #include "../misc/StaticAssertCheck.h" #include "../misc/ThrowByValueCatchByReferenceCheck.h" #include "../performance/MoveConstructorInitCheck.h" +#include "../readability/UppercaseLiteralSuffixCheck.h" #include "CommandProcessorCheck.h" #include "DontModifyStdNamespaceCheck.h" #include "FloatLoopCounter.h" @@ -65,6 +66,8 @@ // C checkers // DCL CheckFactories.registerCheck("cert-dcl03-c"); + CheckFactories.registerCheck( + "cert-dcl16-c"); // ENV CheckFactories.registerCheck("cert-env33-c"); // FLP Index: clang-tidy/cert/CMakeLists.txt =================================================================== --- clang-tidy/cert/CMakeLists.txt +++ clang-tidy/cert/CMakeLists.txt @@ -24,5 +24,6 @@ clangTidyGoogleModule clangTidyMiscModule clangTidyPerformanceModule + clangTidyReadabilityModule clangTidyUtils ) Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -31,6 +31,7 @@ StaticDefinitionInAnonymousNamespaceCheck.cpp StringCompareCheck.cpp UniqueptrDeleteReleaseCheck.cpp + UppercaseLiteralSuffixCheck.cpp LINK_LIBS clangAST Index: clang-tidy/readability/MagicNumbersCheck.h =================================================================== --- clang-tidy/readability/MagicNumbersCheck.h +++ clang-tidy/readability/MagicNumbersCheck.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MAGICNUMBERSCHECK_H #include "../ClangTidy.h" +#include "../utils/ASTUtils.h" #include #include #include @@ -37,14 +38,6 @@ bool isIgnoredValue(const IntegerLiteral *Literal) const; bool isIgnoredValue(const FloatingLiteral *Literal) const; - bool isSyntheticValue(const clang::SourceManager *, - const FloatingLiteral *) const { - return false; - } - - bool isSyntheticValue(const clang::SourceManager *SourceManager, - const IntegerLiteral *Literal) const; - template void checkBoundMatch(const ast_matchers::MatchFinder::MatchResult &Result, const char *BoundName) { @@ -62,7 +55,7 @@ if (isConstant(Result, *MatchedLiteral)) return; - if (isSyntheticValue(Result.SourceManager, MatchedLiteral)) + if (utils::isSyntheticValue(Result.SourceManager, MatchedLiteral)) return; const StringRef LiteralSourceText = Lexer::getSourceText( Index: clang-tidy/readability/MagicNumbersCheck.cpp =================================================================== --- clang-tidy/readability/MagicNumbersCheck.cpp +++ clang-tidy/readability/MagicNumbersCheck.cpp @@ -153,19 +153,6 @@ return false; } -bool MagicNumbersCheck::isSyntheticValue(const SourceManager *SourceManager, - const IntegerLiteral *Literal) const { - const std::pair FileOffset = - SourceManager->getDecomposedLoc(Literal->getLocation()); - if (FileOffset.first.isInvalid()) - return false; - - const StringRef BufferIdentifier = - SourceManager->getBuffer(FileOffset.first)->getBufferIdentifier(); - - return BufferIdentifier.empty(); -} - } // namespace readability } // namespace tidy } // namespace clang Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -38,6 +38,7 @@ #include "StaticDefinitionInAnonymousNamespaceCheck.h" #include "StringCompareCheck.h" #include "UniqueptrDeleteReleaseCheck.h" +#include "UppercaseLiteralSuffixCheck.h" namespace clang { namespace tidy { @@ -84,6 +85,8 @@ "readability-static-definition-in-anonymous-namespace"); CheckFactories.registerCheck( "readability-string-compare"); + CheckFactories.registerCheck( + "readability-uppercase-literal-suffix"); CheckFactories.registerCheck( "readability-named-parameter"); CheckFactories.registerCheck( Index: clang-tidy/readability/UppercaseLiteralSuffixCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/UppercaseLiteralSuffixCheck.h @@ -0,0 +1,50 @@ +//===--- UppercaseLiteralSuffixCheck.h - clang-tidy -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_UPPERCASELITERALSUFFIXCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_UPPERCASELITERALSUFFIXCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// Detects when the integral literal or floating point literal has +/// non-uppercase suffix, and suggests to make the suffix uppercase. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-uppercase-literal-suffix.html +class UppercaseLiteralSuffixCheck : public ClangTidyCheck { + struct NewSuffix { + SourceRange Range; + StringRef OldSuffix; + std::string NewSuffix; + }; + + template + llvm::Optional + shouldReplaceLiteralSuffix(const clang::Expr &Literal, + const clang::SourceManager &SM); + + template + bool checkBoundMatch(const ast_matchers::MatchFinder::MatchResult &Result); + +public: + UppercaseLiteralSuffixCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_UPPERCASELITERALSUFFIXCHECK_H Index: clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp @@ -0,0 +1,180 @@ +//===--- UppercaseLiteralSuffixCheck.cpp - clang-tidy ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "UppercaseLiteralSuffixCheck.h" +#include "../utils/ASTUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallString.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace readability { + +namespace { + +struct IntegerLiteral { + using ClangType = clang::IntegerLiteral; + static constexpr llvm::StringLiteral Name = llvm::StringLiteral("integer"); + // What should be skipped before looking for the Suffixes? (Nothing here.) + static constexpr llvm::StringLiteral SkipFirst = llvm::StringLiteral(""); + // Integer suffix can only consist of 'u' and 'l' chars. + static constexpr llvm::StringLiteral Suffixes = llvm::StringLiteral("uUlL"); +}; +constexpr llvm::StringLiteral IntegerLiteral::Name; +constexpr llvm::StringLiteral IntegerLiteral::SkipFirst; +constexpr llvm::StringLiteral IntegerLiteral::Suffixes; + +struct FloatingLiteral { + using ClangType = clang::FloatingLiteral; + static constexpr llvm::StringLiteral Name = + llvm::StringLiteral("floating point"); + // What should be skipped before looking for the Suffixes? + // Hexadecimal floating-point literals: skip until exponent first. + static constexpr llvm::StringLiteral SkipFirst = llvm::StringLiteral("pP"); + // Floating suffix can only consist of 'u' and 'l' chars. + static constexpr llvm::StringLiteral Suffixes = llvm::StringLiteral("fFlL"); +}; +constexpr llvm::StringLiteral FloatingLiteral::Name; +constexpr llvm::StringLiteral FloatingLiteral::SkipFirst; +constexpr llvm::StringLiteral FloatingLiteral::Suffixes; + +AST_MATCHER(clang::IntegerLiteral, intHasSuffix) { + const auto *T = dyn_cast(Node.getType().getTypePtr()); + if (!T) + return false; + switch (T->getKind()) { + default: + case BuiltinType::Kind::Int: + return false; // No suffix. + case BuiltinType::Kind::UInt: // 'u' + case BuiltinType::Kind::Long: // 'l' + case BuiltinType::Kind::ULong: // 'ul' + case BuiltinType::Kind::LongLong: // 'll' + case BuiltinType::Kind::ULongLong: // 'ull' + return true; + } +} + +AST_MATCHER(clang::FloatingLiteral, fpHasSuffix) { + const auto *T = dyn_cast(Node.getType().getTypePtr()); + if (!T) + return false; + switch (T->getKind()) { + default: + case BuiltinType::Kind::Double: + return false; // No suffix. + case BuiltinType::Kind::Float: // 'f' + case BuiltinType::Kind::LongDouble: // 'l' + return true; + } +} + +} // namespace + +template +llvm::Optional +UppercaseLiteralSuffixCheck::shouldReplaceLiteralSuffix( + const clang::Expr &Literal, const clang::SourceManager &SM) { + const auto &L = cast(Literal); + + NewSuffix S; + + S.Range = L.getSourceRange(); + + // Get the whole Integer Literal from the source buffer. + const StringRef LiteralSourceText = Lexer::getSourceText( + CharSourceRange::getTokenRange(S.Range), SM, getLangOpts()); + + size_t Skip = 0; + + // Do we need to ignore something before actually looking for the suffix? + if (!LiteralType::SkipFirst.empty()) { + // E.g. we can't look for 'f' suffix in hexadecimal floating-point literals + // until after we skip to the exponent (which is mandatory there), + // because hex-digit-sequence may contain 'f'. + Skip = LiteralSourceText.find_first_of(LiteralType::SkipFirst); + if (Skip == StringRef::npos) // We could be in non-hexadecimal fp literal. + Skip = 0; + } + + // Find the beginning of the suffix by looking for the first char that is + // one of these chars that can be in the suffix, potentially starting looking + // in the exponent, if we are skipping hex-digit-sequence. + Skip = LiteralSourceText.find_first_of(LiteralType::Suffixes, /*From=*/Skip); + assert( + Skip != StringRef::npos && + "we should not get here unless there was some suffix as per the type " + "system. Also, these two places should accept the same set of suffixes."); + + // Move the cursor in the source range to the beginning of the suffix. + S.Range.setBegin(S.Range.getBegin().getLocWithOffset(Skip)); + // And in our textual representation too. + S.OldSuffix = LiteralSourceText.drop_front(Skip); + assert(!S.OldSuffix.empty() && "We still should have some chars left."); + + // And get the replacement suffix, with upper-case chars. + S.NewSuffix = S.OldSuffix.upper(); + + if (S.OldSuffix == S.NewSuffix) + return llvm::None; // The suffix was already fully uppercase. + + return S; +} + +void UppercaseLiteralSuffixCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + stmt(integerLiteral(intHasSuffix())).bind(IntegerLiteral::Name), this); + Finder->addMatcher( + stmt(floatLiteral(fpHasSuffix())).bind(FloatingLiteral::Name), this); +} + +template +bool UppercaseLiteralSuffixCheck::checkBoundMatch( + const ast_matchers::MatchFinder::MatchResult &Result) { + const auto *Literal = Result.Nodes.getNodeAs( + LiteralType::Name); + if (!Literal) + return false; + + const SourceLocation LiteralLocation = Literal->getLocation(); + + // Ignore literals that aren't fully written in the source code. + if (LiteralLocation.isMacroID() || + Result.SourceManager->isMacroBodyExpansion(LiteralLocation) || + utils::isSyntheticValue(Result.SourceManager, Literal)) + return true; + + NewSuffix S; + // We won't *always* want to replace. We might have already-uppercase suffix. + if (auto Replacement = shouldReplaceLiteralSuffix( + *Literal, *Result.SourceManager)) + S = *Replacement; + else + return true; + + diag(LiteralLocation, "%0 literal suffix '%1' is not upper-case") + << LiteralType::Name << S.OldSuffix + << FixItHint::CreateReplacement(S.Range, S.NewSuffix); + return true; +} + +void UppercaseLiteralSuffixCheck::check( + const MatchFinder::MatchResult &Result) { + if (checkBoundMatch(Result)) + return; // If it *was* IntegerLiteral, don't check for FloatingLiteral. + checkBoundMatch(Result); +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: clang-tidy/utils/ASTUtils.h =================================================================== --- clang-tidy/utils/ASTUtils.h +++ clang-tidy/utils/ASTUtils.h @@ -27,6 +27,16 @@ bool exprHasBitFlagWithSpelling(const Expr *Flags, const SourceManager &SM, const LangOptions &LangOpts, StringRef FlagName); + +// Check whether given IntegerLiteral is a synthetic value, like __LINE__ +bool isSyntheticValue(const clang::SourceManager *SourceManager, + const IntegerLiteral *Literal); +// No known syntetic fp literals. +inline bool isSyntheticValue(const clang::SourceManager *, + const FloatingLiteral *) { + return false; +} + } // namespace utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/ASTUtils.cpp =================================================================== --- clang-tidy/utils/ASTUtils.cpp +++ clang-tidy/utils/ASTUtils.cpp @@ -67,6 +67,20 @@ return true; } +// Check whether given IntegerLiteral is a synthetic value, like __LINE__ +bool isSyntheticValue(const clang::SourceManager *SourceManager, + const IntegerLiteral *Literal) { + const std::pair FileOffset = + SourceManager->getDecomposedLoc(Literal->getLocation()); + if (FileOffset.first.isInvalid()) + return false; + + const StringRef BufferIdentifier = + SourceManager->getBuffer(FileOffset.first)->getBufferIdentifier(); + + return BufferIdentifier.empty(); +} + } // namespace utils } // namespace tidy } // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -106,6 +106,17 @@ Detects usage of magic numbers, numbers that are used as literals instead of introduced via constants or symbols. +- New :doc:`readability-uppercase-literal-suffix + ` check. + + Detects when the integral literal or floating point literal has non-uppercase + suffix, and suggests to make the suffix uppercase. + +- New alias :doc:`cert-dcl16-c + ` to :doc:`readability-uppercase-literal-suffix + ` + added. + Improvements to include-fixer ----------------------------- Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -65,6 +65,7 @@ bugprone-use-after-move bugprone-virtual-near-miss cert-dcl03-c (redirects to misc-static-assert) + cert-dcl16-c (redirects to readability-uppercase-literal-suffix) cert-dcl21-cpp cert-dcl50-cpp cert-dcl54-cpp (redirects to misc-new-delete-overloads) @@ -244,4 +245,5 @@ readability-static-definition-in-anonymous-namespace readability-string-compare readability-uniqueptr-delete-release + readability-uppercase-literal-suffix zircon-temporary-objects Index: docs/clang-tidy/checks/readability-uppercase-literal-suffix.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/readability-uppercase-literal-suffix.rst @@ -0,0 +1,22 @@ +.. title:: clang-tidy - readability-uppercase-literal-suffix + +readability-uppercase-literal-suffix +==================================== + +`cert-dcl16-c` redirects here as an alias for this check. + +Detects when the integral literal or floating point (decimal or hexadecimal) +literal has non-uppercase suffix, and suggests to make the suffix uppercase, +with fix-it. + +All valid combinations of suffixes are supported. + +.. code:: c + + auto x = 1; // OK, no suffix. + + auto x = 1u; // warning: integer literal suffix 'u' is not upper-case + + auto x = 1U; // OK, suffix is uppercase. + + ... Index: test/clang-tidy/readability-uppercase-literal-suffix-floating-point.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-uppercase-literal-suffix-floating-point.cpp @@ -0,0 +1,95 @@ +// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix +// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' + +template +struct integral_constant { + static constexpr T value = v; + typedef T value_type; + typedef integral_constant type; // using injected-class-name + constexpr operator value_type() const noexcept { return value; } +}; + +using false_type = integral_constant; +using true_type = integral_constant; + +template +struct is_same : false_type {}; + +template +struct is_same : true_type {}; + +void integer_suffix() { + static constexpr auto v0 = 1.; // no literal + static_assert(is_same::value, ""); + static_assert(v0 == 1, ""); + + static constexpr auto v1 = 1.e0; // no literal + static_assert(is_same::value, ""); + static_assert(v1 == 1, ""); + + // Float + + static constexpr auto v2 = 1.f; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal suffix 'f' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v2 = 1.f; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}F{{$}} + // CHECK-FIXES: static constexpr auto v2 = 1.F; + static_assert(is_same::value, ""); + static_assert(v2 == 1, ""); + + static constexpr auto v3 = 1.e0f; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal suffix 'f' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v3 = 1.e0f; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}F{{$}} + // CHECK-FIXES: static constexpr auto v3 = 1.e0F; + static_assert(is_same::value, ""); + static_assert(v3 == 1, ""); + + static constexpr auto v4 = 1.F; // OK. + static_assert(is_same::value, ""); + static_assert(v4 == 1, ""); + + static constexpr auto v5 = 1.e0F; // OK. + static_assert(is_same::value, ""); + static_assert(v5 == 1, ""); + + // Long double + + static constexpr auto v6 = 1.l; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal suffix 'l' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v6 = 1.l; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}L{{$}} + // CHECK-FIXES: static constexpr auto v6 = 1.L; + static_assert(is_same::value, ""); + static_assert(v6 == 1, ""); + + static constexpr auto v7 = 1.e0l; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal suffix 'l' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v7 = 1.e0l; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}L{{$}} + // CHECK-FIXES: static constexpr auto v7 = 1.e0L; + static_assert(is_same::value, ""); + static_assert(v7 == 1, ""); + + static constexpr auto v8 = 1.L; // OK. + static_assert(is_same::value, ""); + static_assert(v8 == 1, ""); + + static constexpr auto v9 = 1.e0L; // OK. + static_assert(is_same::value, ""); + static_assert(v9 == 1, ""); +} + +void negatives() { +#define PASSTHROUGH(X) X + + static constexpr auto n0 = PASSTHROUGH(1.f); + static_assert(is_same::value, ""); + static_assert(n0 == 1, ""); +} Index: test/clang-tidy/readability-uppercase-literal-suffix-hexadecimal-floating-point.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-uppercase-literal-suffix-hexadecimal-floating-point.cpp @@ -0,0 +1,89 @@ +// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix +// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' + +template +struct integral_constant { + static constexpr T value = v; + typedef T value_type; + typedef integral_constant type; // using injected-class-name + constexpr operator value_type() const noexcept { return value; } +}; + +using false_type = integral_constant; +using true_type = integral_constant; + +template +struct is_same : false_type {}; + +template +struct is_same : true_type {}; + +void integer_suffix() { + static constexpr auto v0 = 0x0p0; // no literal + static_assert(is_same::value, ""); + static_assert(v0 == 0, ""); + + // Float + + static constexpr auto v1 = 0xfp0f; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal suffix 'f' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v1 = 0xfp0f; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}F{{$}} + // CHECK-FIXES: static constexpr auto v1 = 0xfp0F; + static_assert(is_same::value, ""); + static_assert(v1 == 15, ""); + + static constexpr auto v2 = 0xfp0F; // OK + static_assert(is_same::value, ""); + static_assert(v2 == 15, ""); + + static constexpr auto v3 = 0xfP0f; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal suffix 'f' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v3 = 0xfP0f; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}F{{$}} + // CHECK-FIXES: static constexpr auto v3 = 0xfP0F; + static_assert(is_same::value, ""); + static_assert(v3 == 15, ""); + + static constexpr auto v4 = 0xfP0F; // OK + static_assert(is_same::value, ""); + static_assert(v4 == 15, ""); + + static constexpr auto v5 = 0xfP0f; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal suffix 'f' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v5 = 0xfP0f; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}F{{$}} + // CHECK-FIXES: static constexpr auto v5 = 0xfP0F; + static_assert(is_same::value, ""); + static_assert(v5 == 15, ""); + + static constexpr auto v6 = 0xfP0F; // OK + static_assert(is_same::value, ""); + static_assert(v6 == 15, ""); + + static constexpr auto v7 = 0xFp0f; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal suffix 'f' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v7 = 0xFp0f; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}F{{$}} + // CHECK-FIXES: static constexpr auto v7 = 0xFp0F; + static_assert(is_same::value, ""); + static_assert(v7 == 15, ""); + + static constexpr auto v8 = 0xFp0F; // OK + static_assert(is_same::value, ""); + static_assert(v8 == 15, ""); +} + +void negatives() { +#define PASSTHROUGH(X) X + + static constexpr auto n0 = PASSTHROUGH(0x0p0f); + static_assert(is_same::value, ""); + static_assert(n0 == 0, ""); +} Index: test/clang-tidy/readability-uppercase-literal-suffix-integer.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-uppercase-literal-suffix-integer.cpp @@ -0,0 +1,218 @@ +// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix +// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' + +template +struct integral_constant { + static constexpr T value = v; + typedef T value_type; + typedef integral_constant type; // using injected-class-name + constexpr operator value_type() const noexcept { return value; } +}; + +using false_type = integral_constant; +using true_type = integral_constant; + +template +struct is_same : false_type {}; + +template +struct is_same : true_type {}; + +void integer_suffix() { + static constexpr auto v0 = __LINE__; // synthetic + static_assert(v0 == 24 || v0 == 20, ""); + + static constexpr auto v1 = __cplusplus; // synthetic, long + + static constexpr auto v2 = 1; // no literal + static_assert(is_same::value, ""); + static_assert(v2 == 1, ""); + + // Unsigned + + static constexpr auto v3 = 1u; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal suffix 'u' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v3 = 1u; + // CHECK-MESSAGES-NEXT: ^~ + // CHECK-MESSAGES-NEXT: {{^ *}}U{{$}} + // CHECK-FIXES: static constexpr auto v3 = 1U; + static_assert(is_same::value, ""); + static_assert(v3 == 1, ""); + + static constexpr auto v4 = 1U; // OK. + static_assert(is_same::value, ""); + static_assert(v4 == 1, ""); + + // Long + + static constexpr auto v5 = 1l; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal suffix 'l' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v5 = 1l; + // CHECK-MESSAGES-NEXT: ^~ + // CHECK-MESSAGES-NEXT: {{^ *}}L{{$}} + // CHECK-FIXES: static constexpr auto v5 = 1L; + static_assert(is_same::value, ""); + static_assert(v5 == 1, ""); + + static constexpr auto v6 = 1L; // OK. + static_assert(is_same::value, ""); + static_assert(v6 == 1, ""); + + // Long Long + + static constexpr auto v7 = 1ll; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal suffix 'll' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v7 = 1ll; + // CHECK-MESSAGES-NEXT: ^~~ + // CHECK-MESSAGES-NEXT: {{^ *}}LL{{$}} + // CHECK-FIXES: static constexpr auto v7 = 1LL; + static_assert(is_same::value, ""); + static_assert(v7 == 1, ""); + + static constexpr auto v8 = 1LL; // OK. + static_assert(is_same::value, ""); + static_assert(v8 == 1, ""); + + // Unsigned Long + + static constexpr auto v9 = 1ul; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal suffix 'ul' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v9 = 1ul; + // CHECK-MESSAGES-NEXT: ^~~ + // CHECK-MESSAGES-NEXT: {{^ *}}UL{{$}} + // CHECK-FIXES: static constexpr auto v9 = 1UL; + static_assert(is_same::value, ""); + static_assert(v9 == 1, ""); + + static constexpr auto v10 = 1uL; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'uL' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v10 = 1uL; + // CHECK-MESSAGES-NEXT: ^~~ + // CHECK-MESSAGES-NEXT: {{^ *}}UL{{$}} + // CHECK-FIXES: static constexpr auto v10 = 1UL; + static_assert(is_same::value, ""); + static_assert(v10 == 1, ""); + + static constexpr auto v11 = 1Ul; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'Ul' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v11 = 1Ul; + // CHECK-MESSAGES-NEXT: ^~~ + // CHECK-MESSAGES-NEXT: {{^ *}}UL{{$}} + // CHECK-FIXES: static constexpr auto v11 = 1UL; + static_assert(is_same::value, ""); + static_assert(v11 == 1, ""); + + static constexpr auto v12 = 1UL; // OK. + static_assert(is_same::value, ""); + static_assert(v12 == 1, ""); + + // Long Unsigned + + static constexpr auto v13 = 1lu; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'lu' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v13 = 1lu; + // CHECK-MESSAGES-NEXT: ^~~ + // CHECK-MESSAGES-NEXT: {{^ *}}LU{{$}} + // CHECK-FIXES: static constexpr auto v13 = 1LU; + static_assert(is_same::value, ""); + static_assert(v13 == 1, ""); + + static constexpr auto v14 = 1Lu; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'Lu' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v14 = 1Lu; + // CHECK-MESSAGES-NEXT: ^~~ + // CHECK-MESSAGES-NEXT: {{^ *}}LU{{$}} + // CHECK-FIXES: static constexpr auto v14 = 1LU; + static_assert(is_same::value, ""); + static_assert(v14 == 1, ""); + + static constexpr auto v15 = 1lU; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'lU' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v15 = 1lU; + // CHECK-MESSAGES-NEXT: ^~~ + // CHECK-MESSAGES-NEXT: {{^ *}}LU{{$}} + // CHECK-FIXES: static constexpr auto v15 = 1LU; + static_assert(is_same::value, ""); + static_assert(v15 == 1, ""); + + static constexpr auto v16 = 1LU; // OK. + static_assert(is_same::value, ""); + static_assert(v16 == 1, ""); + + // Unsigned Long Long + + static constexpr auto v17 = 1ull; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'ull' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v17 = 1ull; + // CHECK-MESSAGES-NEXT: ^~~~ + // CHECK-MESSAGES-NEXT: {{^ *}}ULL{{$}} + // CHECK-FIXES: static constexpr auto v17 = 1ULL; + static_assert(is_same::value, ""); + static_assert(v17 == 1, ""); + + static constexpr auto v18 = 1uLL; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'uLL' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v18 = 1uLL; + // CHECK-MESSAGES-NEXT: ^~~~ + // CHECK-MESSAGES-NEXT: {{^ *}}ULL{{$}} + // CHECK-FIXES: static constexpr auto v18 = 1ULL; + static_assert(is_same::value, ""); + static_assert(v18 == 1, ""); + + static constexpr auto v19 = 1Ull; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'Ull' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v19 = 1Ull; + // CHECK-MESSAGES-NEXT: ^~~~ + // CHECK-MESSAGES-NEXT: {{^ *}}ULL{{$}} + // CHECK-FIXES: static constexpr auto v19 = 1ULL; + static_assert(is_same::value, ""); + static_assert(v19 == 1, ""); + + static constexpr auto v20 = 1ULL; // OK. + static_assert(is_same::value, ""); + static_assert(v20 == 1, ""); + + // Long Long Unsigned + + static constexpr auto v21 = 1llu; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'llu' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v21 = 1llu; + // CHECK-MESSAGES-NEXT: ^~~~ + // CHECK-MESSAGES-NEXT: {{^ *}}LLU{{$}} + // CHECK-FIXES: static constexpr auto v21 = 1LLU; + static_assert(is_same::value, ""); + static_assert(v21 == 1, ""); + + static constexpr auto v22 = 1LLu; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'LLu' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v22 = 1LLu; + // CHECK-MESSAGES-NEXT: ^~~~ + // CHECK-MESSAGES-NEXT: {{^ *}}LLU{{$}} + // CHECK-FIXES: static constexpr auto v22 = 1LLU; + static_assert(is_same::value, ""); + static_assert(v22 == 1, ""); + + static constexpr auto v23 = 1llU; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal suffix 'llU' is not upper-case [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: static constexpr auto v23 = 1llU; + // CHECK-MESSAGES-NEXT: ^~~~ + // CHECK-MESSAGES-NEXT: {{^ *}}LLU{{$}} + // CHECK-FIXES: static constexpr auto v23 = 1LLU; + static_assert(is_same::value, ""); + static_assert(v23 == 1, ""); + + static constexpr auto v24 = 1LLU; // OK. + static_assert(is_same::value, ""); + static_assert(v24 == 1, ""); +} + +void negatives() { +#define PASSTHROUGH(X) X + + static constexpr auto n0 = PASSTHROUGH(1u); + // CHECK-FIXES: static constexpr auto n0 = PASSTHROUGH(1u); + static_assert(is_same::value, ""); + static_assert(n0 == 1, ""); +}