aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang-tidy/cert/CERTTidyModule.cpp10
-rw-r--r--clang-tidy/cert/CMakeLists.txt1
-rw-r--r--clang-tidy/hicpp/HICPPTidyModule.cpp3
-rw-r--r--clang-tidy/readability/CMakeLists.txt1
-rw-r--r--clang-tidy/readability/IdentifierNamingCheck.cpp21
-rw-r--r--clang-tidy/readability/ReadabilityTidyModule.cpp3
-rw-r--r--clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp236
-rw-r--r--clang-tidy/readability/UppercaseLiteralSuffixCheck.h44
-rw-r--r--clang-tidy/utils/ASTUtils.cpp26
-rw-r--r--clang-tidy/utils/ASTUtils.h12
-rw-r--r--docs/ReleaseNotes.rst18
-rw-r--r--docs/clang-tidy/checks/cert-dcl16-c.rst9
-rw-r--r--docs/clang-tidy/checks/hicpp-uppercase-literal-suffix.rst9
-rw-r--r--docs/clang-tidy/checks/list.rst3
-rw-r--r--docs/clang-tidy/checks/readability-uppercase-literal-suffix.rst42
-rw-r--r--test/clang-tidy/cert-uppercase-literal-suffix-integer.cpp159
-rw-r--r--test/clang-tidy/readability-uppercase-literal-suffix-floating-point-opencl-half.cpp30
-rw-r--r--test/clang-tidy/readability-uppercase-literal-suffix-floating-point.cpp198
-rw-r--r--test/clang-tidy/readability-uppercase-literal-suffix-hexadecimal-floating-point.cpp155
-rw-r--r--test/clang-tidy/readability-uppercase-literal-suffix-integer-custom-list.cpp130
-rw-r--r--test/clang-tidy/readability-uppercase-literal-suffix-integer-macro.cpp25
-rw-r--r--test/clang-tidy/readability-uppercase-literal-suffix-integer-ms.cpp77
-rw-r--r--test/clang-tidy/readability-uppercase-literal-suffix-integer.cpp245
-rw-r--r--test/clang-tidy/readability-uppercase-literal-suffix.h16
24 files changed, 1454 insertions, 19 deletions
diff --git a/clang-tidy/cert/CERTTidyModule.cpp b/clang-tidy/cert/CERTTidyModule.cpp
index da09932e..b6a0e7b6 100644
--- a/clang-tidy/cert/CERTTidyModule.cpp
+++ b/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 @@ public:
// C checkers
// DCL
CheckFactories.registerCheck<misc::StaticAssertCheck>("cert-dcl03-c");
+ CheckFactories.registerCheck<readability::UppercaseLiteralSuffixCheck>(
+ "cert-dcl16-c");
// ENV
CheckFactories.registerCheck<CommandProcessorCheck>("cert-env33-c");
// FLP
@@ -78,6 +81,13 @@ public:
CheckFactories.registerCheck<ProperlySeededRandomGeneratorCheck>(
"cert-msc32-c");
}
+
+ ClangTidyOptions getModuleOptions() override {
+ ClangTidyOptions Options;
+ ClangTidyOptions::OptionMap &Opts = Options.CheckOptions;
+ Opts["cert-dcl16-c.NewSuffixes"] = "L;LL;LU;LLU";
+ return Options;
+ }
};
} // namespace cert
diff --git a/clang-tidy/cert/CMakeLists.txt b/clang-tidy/cert/CMakeLists.txt
index edc93c8e..aa05cc47 100644
--- a/clang-tidy/cert/CMakeLists.txt
+++ b/clang-tidy/cert/CMakeLists.txt
@@ -24,5 +24,6 @@ add_clang_library(clangTidyCERTModule
clangTidyGoogleModule
clangTidyMiscModule
clangTidyPerformanceModule
+ clangTidyReadabilityModule
clangTidyUtils
)
diff --git a/clang-tidy/hicpp/HICPPTidyModule.cpp b/clang-tidy/hicpp/HICPPTidyModule.cpp
index d2b9fc6d..7b25cdaa 100644
--- a/clang-tidy/hicpp/HICPPTidyModule.cpp
+++ b/clang-tidy/hicpp/HICPPTidyModule.cpp
@@ -35,6 +35,7 @@
#include "../readability/BracesAroundStatementsCheck.h"
#include "../readability/FunctionSizeCheck.h"
#include "../readability/IdentifierNamingCheck.h"
+#include "../readability/UppercaseLiteralSuffixCheck.h"
#include "ExceptionBaseclassCheck.h"
#include "MultiwayPathsCoveredCheck.h"
#include "NoAssemblerCheck.h"
@@ -100,6 +101,8 @@ public:
"hicpp-use-nullptr");
CheckFactories.registerCheck<modernize::UseOverrideCheck>(
"hicpp-use-override");
+ CheckFactories.registerCheck<readability::UppercaseLiteralSuffixCheck>(
+ "hicpp-uppercase-literal-suffix");
CheckFactories.registerCheck<cppcoreguidelines::ProTypeVarargCheck>(
"hicpp-vararg");
}
diff --git a/clang-tidy/readability/CMakeLists.txt b/clang-tidy/readability/CMakeLists.txt
index da2320ea..bd010af9 100644
--- a/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tidy/readability/CMakeLists.txt
@@ -31,6 +31,7 @@ add_clang_library(clangTidyReadabilityModule
StaticDefinitionInAnonymousNamespaceCheck.cpp
StringCompareCheck.cpp
UniqueptrDeleteReleaseCheck.cpp
+ UppercaseLiteralSuffixCheck.cpp
LINK_LIBS
clangAST
diff --git a/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tidy/readability/IdentifierNamingCheck.cpp
index 1d116817..fb3c02e1 100644
--- a/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ b/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -9,6 +9,7 @@
#include "IdentifierNamingCheck.h"
+#include "../utils/ASTUtils.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/PPCallbacks.h"
@@ -681,25 +682,7 @@ static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures,
if (!Failure.ShouldFix)
return;
- // Check if the range is entirely contained within a macro argument.
- SourceLocation MacroArgExpansionStartForRangeBegin;
- SourceLocation MacroArgExpansionStartForRangeEnd;
- bool RangeIsEntirelyWithinMacroArgument =
- SourceMgr &&
- SourceMgr->isMacroArgExpansion(Range.getBegin(),
- &MacroArgExpansionStartForRangeBegin) &&
- SourceMgr->isMacroArgExpansion(Range.getEnd(),
- &MacroArgExpansionStartForRangeEnd) &&
- MacroArgExpansionStartForRangeBegin == MacroArgExpansionStartForRangeEnd;
-
- // Check if the range contains any locations from a macro expansion.
- bool RangeContainsMacroExpansion = RangeIsEntirelyWithinMacroArgument ||
- Range.getBegin().isMacroID() ||
- Range.getEnd().isMacroID();
-
- bool RangeCanBeFixed =
- RangeIsEntirelyWithinMacroArgument || !RangeContainsMacroExpansion;
- Failure.ShouldFix = RangeCanBeFixed;
+ Failure.ShouldFix = utils::rangeCanBeFixed(Range, SourceMgr);
}
/// Convenience method when the usage to be added is a NamedDecl
diff --git a/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tidy/readability/ReadabilityTidyModule.cpp
index a5b91544..ca49f6f1 100644
--- a/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/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 {
@@ -102,6 +103,8 @@ public:
"readability-simplify-boolean-expr");
CheckFactories.registerCheck<UniqueptrDeleteReleaseCheck>(
"readability-uniqueptr-delete-release");
+ CheckFactories.registerCheck<UppercaseLiteralSuffixCheck>(
+ "readability-uppercase-literal-suffix");
}
};
diff --git a/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp b/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp
new file mode 100644
index 00000000..3feeaf99
--- /dev/null
+++ b/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp
@@ -0,0 +1,236 @@
+//===--- 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 "../utils/OptionsUtils.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 IntegerLiteralCheck {
+ using type = 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("");
+ // Suffix can only consist of 'u' and 'l' chars, and can be a complex number
+ // ('i', 'j'). In MS compatibility mode, suffixes like i32 are supported.
+ static constexpr llvm::StringLiteral Suffixes =
+ llvm::StringLiteral("uUlLiIjJ");
+};
+constexpr llvm::StringLiteral IntegerLiteralCheck::Name;
+constexpr llvm::StringLiteral IntegerLiteralCheck::SkipFirst;
+constexpr llvm::StringLiteral IntegerLiteralCheck::Suffixes;
+
+struct FloatingLiteralCheck {
+ using type = clang::FloatingLiteral;
+ static constexpr llvm::StringLiteral Name =
+ llvm::StringLiteral("floating point");
+ // C++17 introduced hexadecimal floating-point literals, and 'f' is both a
+ // valid hexadecimal digit in a hex float literal and a valid floating-point
+ // literal suffix.
+ // So we can't just "skip to the chars that can be in the suffix".
+ // Since the exponent ('p'/'P') is mandatory for hexadecimal floating-point
+ // literals, we first skip everything before the exponent.
+ static constexpr llvm::StringLiteral SkipFirst = llvm::StringLiteral("pP");
+ // Suffix can only consist of 'f', 'l', "f16", 'h', 'q' chars,
+ // and can be a complex number ('i', 'j').
+ static constexpr llvm::StringLiteral Suffixes =
+ llvm::StringLiteral("fFlLhHqQiIjJ");
+};
+constexpr llvm::StringLiteral FloatingLiteralCheck::Name;
+constexpr llvm::StringLiteral FloatingLiteralCheck::SkipFirst;
+constexpr llvm::StringLiteral FloatingLiteralCheck::Suffixes;
+
+struct NewSuffix {
+ SourceLocation LiteralLocation;
+ StringRef OldSuffix;
+ llvm::Optional<FixItHint> FixIt;
+};
+
+llvm::Optional<SourceLocation> GetMacroAwareLocation(SourceLocation Loc,
+ const SourceManager &SM) {
+ // Do nothing if the provided location is invalid.
+ if (Loc.isInvalid())
+ return llvm::None;
+ // Look where the location was *actually* written.
+ SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
+ if (SpellingLoc.isInvalid())
+ return llvm::None;
+ return SpellingLoc;
+}
+
+llvm::Optional<SourceRange> GetMacroAwareSourceRange(SourceRange Loc,
+ const SourceManager &SM) {
+ llvm::Optional<SourceLocation> Begin =
+ GetMacroAwareLocation(Loc.getBegin(), SM);
+ llvm::Optional<SourceLocation> End = GetMacroAwareLocation(Loc.getEnd(), SM);
+ if (!Begin || !End)
+ return llvm::None;
+ return SourceRange(*Begin, *End);
+}
+
+llvm::Optional<std::string>
+getNewSuffix(llvm::StringRef OldSuffix,
+ const std::vector<std::string> &NewSuffixes) {
+ // If there is no config, just uppercase the entirety of the suffix.
+ if (NewSuffixes.empty())
+ return OldSuffix.upper();
+ // Else, find matching suffix, case-*insensitive*ly.
+ auto NewSuffix = llvm::find_if(
+ NewSuffixes, [OldSuffix](const std::string &PotentialNewSuffix) {
+ return OldSuffix.equals_lower(PotentialNewSuffix);
+ });
+ // Have a match, return it.
+ if (NewSuffix != NewSuffixes.end())
+ return *NewSuffix;
+ // Nope, I guess we have to keep it as-is.
+ return llvm::None;
+}
+
+template <typename LiteralType>
+llvm::Optional<NewSuffix>
+shouldReplaceLiteralSuffix(const Expr &Literal,
+ const std::vector<std::string> &NewSuffixes,
+ const SourceManager &SM, const LangOptions &LO) {
+ NewSuffix ReplacementDsc;
+
+ const auto &L = cast<typename LiteralType::type>(Literal);
+
+ // The naive location of the literal. Is always valid.
+ ReplacementDsc.LiteralLocation = L.getLocation();
+
+ // Was this literal fully spelled or is it a product of macro expansion?
+ bool RangeCanBeFixed =
+ utils::rangeCanBeFixed(ReplacementDsc.LiteralLocation, &SM);
+
+ // The literal may have macro expansion, we need the final expanded src range.
+ llvm::Optional<SourceRange> Range =
+ GetMacroAwareSourceRange(ReplacementDsc.LiteralLocation, SM);
+ if (!Range)
+ return llvm::None;
+
+ if (RangeCanBeFixed)
+ ReplacementDsc.LiteralLocation = Range->getBegin();
+ // Else keep the naive literal location!
+
+ // Get the whole literal from the source buffer.
+ bool Invalid;
+ const StringRef LiteralSourceText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(*Range), SM, LO, &Invalid);
+ assert(!Invalid && "Failed to retrieve the source text.");
+
+ 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);
+ // We could be in non-hexadecimal floating-point literal, with no exponent.
+ if (Skip == StringRef::npos)
+ 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);
+
+ // We can't check whether the *Literal has any suffix or not without actually
+ // looking for the suffix. So it is totally possible that there is no suffix.
+ if (Skip == StringRef::npos)
+ return llvm::None;
+
+ // Move the cursor in the source range to the beginning of the suffix.
+ Range->setBegin(Range->getBegin().getLocWithOffset(Skip));
+ // And in our textual representation too.
+ ReplacementDsc.OldSuffix = LiteralSourceText.drop_front(Skip);
+ assert(!ReplacementDsc.OldSuffix.empty() &&
+ "We still should have some chars left.");
+
+ // And get the replacement suffix.
+ llvm::Optional<std::string> NewSuffix =
+ getNewSuffix(ReplacementDsc.OldSuffix, NewSuffixes);
+ if (!NewSuffix || ReplacementDsc.OldSuffix == *NewSuffix)
+ return llvm::None; // The suffix was already the way it should be.
+
+ if (RangeCanBeFixed)
+ ReplacementDsc.FixIt = FixItHint::CreateReplacement(*Range, *NewSuffix);
+
+ return ReplacementDsc;
+}
+
+} // namespace
+
+UppercaseLiteralSuffixCheck::UppercaseLiteralSuffixCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ NewSuffixes(
+ utils::options::parseStringList(Options.get("NewSuffixes", ""))) {}
+
+void UppercaseLiteralSuffixCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "NewSuffixes",
+ utils::options::serializeStringList(NewSuffixes));
+}
+
+void UppercaseLiteralSuffixCheck::registerMatchers(MatchFinder *Finder) {
+ // Sadly, we can't check whether the literal has sufix or not.
+ // E.g. i32 suffix still results in 'BuiltinType::Kind::Int'.
+ // And such an info is not stored in the *Literal itself.
+ Finder->addMatcher(
+ stmt(allOf(eachOf(integerLiteral().bind(IntegerLiteralCheck::Name),
+ floatLiteral().bind(FloatingLiteralCheck::Name)),
+ unless(hasParent(userDefinedLiteral())))),
+ this);
+}
+
+template <typename LiteralType>
+bool UppercaseLiteralSuffixCheck::checkBoundMatch(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Literal =
+ Result.Nodes.getNodeAs<typename LiteralType::type>(LiteralType::Name);
+ if (!Literal)
+ return false;
+
+ // We won't *always* want to diagnose.
+ // We might have a suffix that is already uppercase.
+ if (auto Details = shouldReplaceLiteralSuffix<LiteralType>(
+ *Literal, NewSuffixes, *Result.SourceManager, getLangOpts())) {
+ auto Complaint = diag(Details->LiteralLocation,
+ "%0 literal has suffix '%1', which is not uppercase")
+ << LiteralType::Name << Details->OldSuffix;
+ if (Details->FixIt) // Similarly, a fix-it is not always possible.
+ Complaint << *(Details->FixIt);
+ }
+
+ return true;
+}
+
+void UppercaseLiteralSuffixCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (checkBoundMatch<IntegerLiteralCheck>(Result))
+ return; // If it *was* IntegerLiteral, don't check for FloatingLiteral.
+ checkBoundMatch<FloatingLiteralCheck>(Result);
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tidy/readability/UppercaseLiteralSuffixCheck.h b/clang-tidy/readability/UppercaseLiteralSuffixCheck.h
new file mode 100644
index 00000000..8d26e6c2
--- /dev/null
+++ b/clang-tidy/readability/UppercaseLiteralSuffixCheck.h
@@ -0,0 +1,44 @@
+//===--- 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"
+#include "../utils/OptionsUtils.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.
+/// Alternatively, a list of destination suffixes can be provided.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-uppercase-literal-suffix.html
+class UppercaseLiteralSuffixCheck : public ClangTidyCheck {
+public:
+ UppercaseLiteralSuffixCheck(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;
+
+private:
+ template <typename LiteralType>
+ bool checkBoundMatch(const ast_matchers::MatchFinder::MatchResult &Result);
+
+ const std::vector<std::string> NewSuffixes;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_UPPERCASELITERALSUFFIXCHECK_H
diff --git a/clang-tidy/utils/ASTUtils.cpp b/clang-tidy/utils/ASTUtils.cpp
index 5c6b9843..3c0427fd 100644
--- a/clang-tidy/utils/ASTUtils.cpp
+++ b/clang-tidy/utils/ASTUtils.cpp
@@ -67,6 +67,32 @@ bool exprHasBitFlagWithSpelling(const Expr *Flags, const SourceManager &SM,
return true;
}
+bool rangeIsEntirelyWithinMacroArgument(SourceRange Range,
+ const SourceManager *SM) {
+ // Check if the range is entirely contained within a macro argument.
+ SourceLocation MacroArgExpansionStartForRangeBegin;
+ SourceLocation MacroArgExpansionStartForRangeEnd;
+ bool RangeIsEntirelyWithinMacroArgument =
+ SM &&
+ SM->isMacroArgExpansion(Range.getBegin(),
+ &MacroArgExpansionStartForRangeBegin) &&
+ SM->isMacroArgExpansion(Range.getEnd(),
+ &MacroArgExpansionStartForRangeEnd) &&
+ MacroArgExpansionStartForRangeBegin == MacroArgExpansionStartForRangeEnd;
+
+ return RangeIsEntirelyWithinMacroArgument;
+}
+
+bool rangeContainsMacroExpansion(SourceRange Range, const SourceManager *SM) {
+ return rangeIsEntirelyWithinMacroArgument(Range, SM) ||
+ Range.getBegin().isMacroID() || Range.getEnd().isMacroID();
+}
+
+bool rangeCanBeFixed(SourceRange Range, const SourceManager *SM) {
+ return utils::rangeIsEntirelyWithinMacroArgument(Range, SM) ||
+ !utils::rangeContainsMacroExpansion(Range, SM);
+}
+
} // namespace utils
} // namespace tidy
} // namespace clang
diff --git a/clang-tidy/utils/ASTUtils.h b/clang-tidy/utils/ASTUtils.h
index ccff000a..4196eeb9 100644
--- a/clang-tidy/utils/ASTUtils.h
+++ b/clang-tidy/utils/ASTUtils.h
@@ -27,6 +27,18 @@ bool IsBinaryOrTernary(const Expr *E);
bool exprHasBitFlagWithSpelling(const Expr *Flags, const SourceManager &SM,
const LangOptions &LangOpts,
StringRef FlagName);
+
+// Check if the range is entirely contained within a macro argument.
+bool rangeIsEntirelyWithinMacroArgument(SourceRange Range,
+ const SourceManager *SM);
+
+// Check if the range contains any locations from a macro expansion.
+bool rangeContainsMacroExpansion(SourceRange Range, const SourceManager *SM);
+
+// Can a fix-it be issued for this whole Range?
+// FIXME: false-negative if the entire range is fully expanded from a macro.
+bool rangeCanBeFixed(SourceRange Range, const SourceManager *SM);
+
} // namespace utils
} // namespace tidy
} // namespace clang
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index 5adb4287..17be5cea 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -122,6 +122,24 @@ Improvements to clang-tidy
Detects usage of magic numbers, numbers that are used as literals instead of
introduced via constants or symbols.
+- New :doc:`readability-uppercase-literal-suffix
+ <clang-tidy/checks/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. The list of destination
+ suffixes can be optionally provided.
+
+- New alias :doc:`cert-dcl16-c
+ <clang-tidy/checks/cert-dcl16-c>` to :doc:`readability-uppercase-literal-suffix
+ <clang-tidy/checks/readability-uppercase-literal-suffix>`
+ added.
+
+- New alias :doc:`hicpp-uppercase-literal-suffix
+ <clang-tidy/checks/hicpp-uppercase-literal-suffix>` to
+ :doc:`readability-uppercase-literal-suffix
+ <clang-tidy/checks/readability-uppercase-literal-suffix>`
+ added.
+
Improvements to include-fixer
-----------------------------
diff --git a/docs/clang-tidy/checks/cert-dcl16-c.rst b/docs/clang-tidy/checks/cert-dcl16-c.rst
new file mode 100644
index 00000000..edfe5283
--- /dev/null
+++ b/docs/clang-tidy/checks/cert-dcl16-c.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - cert-dcl16-c
+.. meta::
+ :http-equiv=refresh: 5;URL=readability-uppercase-literal-suffix.html
+
+cert-dcl16-c
+============
+
+The cert-dcl16-c check is an alias, please see
+`readability-uppercase-literal-suffix <readability-uppercase-literal-suffix.html>`_ for more information.
diff --git a/docs/clang-tidy/checks/hicpp-uppercase-literal-suffix.rst b/docs/clang-tidy/checks/hicpp-uppercase-literal-suffix.rst
new file mode 100644
index 00000000..88fafd58
--- /dev/null
+++ b/docs/clang-tidy/checks/hicpp-uppercase-literal-suffix.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - hicpp-uppercase-literal-suffix
+.. meta::
+ :http-equiv=refresh: 5;URL=readability-uppercase-literal-suffix.html
+
+hicpp-uppercase-literal-suffix
+==============================
+
+The hicpp-uppercase-literal-suffix check is an alias, please see
+`readability-uppercase-literal-suffix <readability-uppercase-literal-suffix.html>`_ for more information.
diff --git a/docs/clang-tidy/checks/list.rst b/docs/clang-tidy/checks/list.rst
index cc966a9b..f5d4ac89 100644
--- a/docs/clang-tidy/checks/list.rst
+++ b/docs/clang-tidy/checks/list.rst
@@ -65,6 +65,7 @@ Clang-Tidy Checks
bugprone-use-after-move
bugprone-virtual-near-miss
cert-dcl03-c (redirects to misc-static-assert) <cert-dcl03-c>
+ cert-dcl16-c (redirects to readability-uppercase-literal-suffix) <cert-dcl16-c>
cert-dcl21-cpp
cert-dcl50-cpp
cert-dcl54-cpp (redirects to misc-new-delete-overloads) <cert-dcl54-cpp>
@@ -155,6 +156,7 @@ Clang-Tidy Checks
hicpp-use-nullptr (redirects to modernize-use-nullptr) <hicpp-use-nullptr>
hicpp-use-override (redirects to modernize-use-override) <hicpp-use-override>
hicpp-vararg (redirects to cppcoreguidelines-pro-type-vararg) <hicpp-vararg>
+ hicpp-uppercase-literal-suffix (redirects to readability-uppercase-literal-suffix) <hicpp-uppercase-literal-suffix>
llvm-header-guard
llvm-include-order
llvm-namespace-comment
@@ -245,4 +247,5 @@ Clang-Tidy Checks
readability-static-definition-in-anonymous-namespace
readability-string-compare
readability-uniqueptr-delete-release
+ readability-uppercase-literal-suffix
zircon-temporary-objects
diff --git a/docs/clang-tidy/checks/readability-uppercase-literal-suffix.rst b/docs/clang-tidy/checks/readability-uppercase-literal-suffix.rst
new file mode 100644
index 00000000..e869fbee
--- /dev/null
+++ b/docs/clang-tidy/checks/readability-uppercase-literal-suffix.rst
@@ -0,0 +1,42 @@
+.. title:: clang-tidy - readability-uppercase-literal-suffix
+
+readability-uppercase-literal-suffix
+====================================
+
+`cert-dcl16-c` redirects here as an alias for this check.
+By default, only the suffixes that begin with 'l' ("l", "ll", "lu", "llu",
+but not "u", "ul", "ull") are diagnosed by that alias.
+
+`hicpp-uppercase-literal-suffix` redirects here as an alias for this check.
+
+Detects when the integral literal or floating point (decimal or hexadecimal)
+literal has a non-uppercase suffix and provides a fix-it-hint
+with the uppercase suffix.
+
+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.
+
+ ...
+
+Optionally, a list of the destination suffixes can be provided.
+When the suffix is found, a case-insensitive lookup in that list is made,
+and if a replacement is found that is different from the current suffix,
+then the diagnostic is issued. This allows for fine-grained control of
+what suffixes to consider and what their replacements should be.
+
+For example, given a list ``L;uL``:
+* ``l`` -> ``L``
+* ``L`` will be kept as is.
+* ``ul`` -> ``uL``
+* ``Ul`` -> ``uL``
+* ``UL`` -> ``uL``
+* ``uL`` will be kept as is.
+* ``ull`` will be kept as is, since it is not in the list
+* and so on.
diff --git a/test/clang-tidy/cert-uppercase-literal-suffix-integer.cpp b/test/clang-tidy/cert-uppercase-literal-suffix-integer.cpp
new file mode 100644
index 00000000..c19aacdd
--- /dev/null
+++ b/test/clang-tidy/cert-uppercase-literal-suffix-integer.cpp
@@ -0,0 +1,159 @@
+// RUN: %check_clang_tidy %s cert-dcl16-c %t -- -- -I %S
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,cert-dcl16-c' -fix -- -I %S
+// RUN: clang-tidy %t.cpp -checks='-*,cert-dcl16-c' -warnings-as-errors='-*,cert-dcl16-c' -- -I %S
+
+#include "readability-uppercase-literal-suffix.h"
+
+void integer_suffix() {
+ static constexpr auto v0 = __LINE__; // synthetic
+ static_assert(v0 == 9 || v0 == 5, "");
+
+ static constexpr auto v1 = __cplusplus; // synthetic, long
+
+ static constexpr auto v2 = 1; // no literal
+ static_assert(is_same<decltype(v2), const int>::value, "");
+ static_assert(v2 == 1, "");
+
+ // Unsigned
+
+ static constexpr auto v3 = 1u;
+ static_assert(is_same<decltype(v3), const unsigned int>::value, "");
+ static_assert(v3 == 1, "");
+
+ static constexpr auto v4 = 1U; // OK.
+ static_assert(is_same<decltype(v4), const unsigned int>::value, "");
+ static_assert(v4 == 1, "");
+
+ // Long
+
+ static constexpr auto v5 = 1l;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'l', which is not uppercase
+ // 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<decltype(v5), const long>::value, "");
+ static_assert(v5 == 1, "");
+
+ static constexpr auto v6 = 1L; // OK.
+ static_assert(is_same<decltype(v6), const long>::value, "");
+ static_assert(v6 == 1, "");
+
+ // Long Long
+
+ static constexpr auto v7 = 1ll;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'll', which is not uppercase
+ // 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<decltype(v7), const long long>::value, "");
+ static_assert(v7 == 1, "");
+
+ static constexpr auto v8 = 1LL; // OK.
+ static_assert(is_same<decltype(v8), const long long>::value, "");
+ static_assert(v8 == 1, "");
+
+ // Unsigned Long
+
+ static constexpr auto v9 = 1ul;
+ static_assert(is_same<decltype(v9), const unsigned long>::value, "");
+ static_assert(v9 == 1, "");
+
+ static constexpr auto v10 = 1uL;
+ static_assert(is_same<decltype(v10), const unsigned long>::value, "");
+ static_assert(v10 == 1, "");
+
+ static constexpr auto v11 = 1Ul;
+ static_assert(is_same<decltype(v11), const unsigned long>::value, "");
+ static_assert(v11 == 1, "");
+
+ static constexpr auto v12 = 1UL; // OK.
+ static_assert(is_same<decltype(v12), const unsigned long>::value, "");
+ static_assert(v12 == 1, "");
+
+ // Long Unsigned
+
+ static constexpr auto v13 = 1lu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'lu', which is not uppercase
+ // 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<decltype(v13), const unsigned long>::value, "");
+ static_assert(v13 == 1, "");
+
+ static constexpr auto v14 = 1Lu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Lu', which is not uppercase
+ // 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<decltype(v14), const unsigned long>::value, "");
+ static_assert(v14 == 1, "");
+
+ static constexpr auto v15 = 1lU;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'lU', which is not uppercase
+ // 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<decltype(v15), const unsigned long>::value, "");
+ static_assert(v15 == 1, "");
+
+ static constexpr auto v16 = 1LU; // OK.
+ static_assert(is_same<decltype(v16), const unsigned long>::value, "");
+ static_assert(v16 == 1, "");
+
+ // Unsigned Long Long
+
+ static constexpr auto v17 = 1ull;
+ static_assert(is_same<decltype(v17), const unsigned long long>::value, "");
+ static_assert(v17 == 1, "");
+
+ static constexpr auto v18 = 1uLL;
+ static_assert(is_same<decltype(v18), const unsigned long long>::value, "");
+ static_assert(v18 == 1, "");
+
+ static constexpr auto v19 = 1Ull;
+ static_assert(is_same<decltype(v19), const unsigned long long>::value, "");
+ static_assert(v19 == 1, "");
+
+ static constexpr auto v20 = 1ULL; // OK.
+ static_assert(is_same<decltype(v20), const unsigned long long>::value, "");
+ static_assert(v20 == 1, "");
+
+ // Long Long Unsigned
+
+ static constexpr auto v21 = 1llu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'llu', which is not uppercase
+ // 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<decltype(v21), const unsigned long long>::value, "");
+ static_assert(v21 == 1, "");
+
+ static constexpr auto v22 = 1LLu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'LLu', which is not uppercase
+ // 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<decltype(v22), const unsigned long long>::value, "");
+ static_assert(v22 == 1, "");
+
+ static constexpr auto v23 = 1llU;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'llU', which is not uppercase
+ // 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<decltype(v23), const unsigned long long>::value, "");
+ static_assert(v23 == 1, "");
+
+ static constexpr auto v24 = 1LLU; // OK.
+ static_assert(is_same<decltype(v24), const unsigned long long>::value, "");
+ static_assert(v24 == 1, "");
+}
diff --git a/test/clang-tidy/readability-uppercase-literal-suffix-floating-point-opencl-half.cpp b/test/clang-tidy/readability-uppercase-literal-suffix-floating-point-opencl-half.cpp
new file mode 100644
index 00000000..8ae97fed
--- /dev/null
+++ b/test/clang-tidy/readability-uppercase-literal-suffix-floating-point-opencl-half.cpp
@@ -0,0 +1,30 @@
+// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -I %S -std=cl2.0 -x cl
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -- -I %S -std=cl2.0 -x cl
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -- -I %S -std=cl2.0 -x cl
+
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+
+void floating_point_half_suffix() {
+ static half v0 = 0x0p0; // no literal
+
+ // half
+
+ static half v2 = 1.h;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: floating point literal has suffix 'h', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static half v2 = 1.h;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}H{{$}}
+ // CHECK-HIXES: static half v2 = 1.H;
+
+ static half v3 = 1.e0h;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: floating point literal has suffix 'h', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static half v3 = 1.e0h;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}H{{$}}
+ // CHECK-HIXES: static half v3 = 1.e0H;
+
+ static half v4 = 1.H; // OK.
+
+ static half v5 = 1.e0H; // OK.
+}
diff --git a/test/clang-tidy/readability-uppercase-literal-suffix-floating-point.cpp b/test/clang-tidy/readability-uppercase-literal-suffix-floating-point.cpp
new file mode 100644
index 00000000..50ae4164
--- /dev/null
+++ b/test/clang-tidy/readability-uppercase-literal-suffix-floating-point.cpp
@@ -0,0 +1,198 @@
+// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -I %S
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -- -I %S
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -- -I %S
+
+#include "readability-uppercase-literal-suffix.h"
+
+void floating_point_suffix() {
+ static constexpr auto v0 = 1.; // no literal
+ static_assert(is_same<decltype(v0), const double>::value, "");
+ static_assert(v0 == 1., "");
+
+ static constexpr auto v1 = 1.e0; // no literal
+ static_assert(is_same<decltype(v1), const double>::value, "");
+ static_assert(v1 == 1., "");
+
+ // Float
+
+ static constexpr auto v2 = 1.f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
+ // 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<decltype(v2), const float>::value, "");
+ static_assert(v2 == 1.0F, "");
+
+ static constexpr auto v3 = 1.e0f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
+ // 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<decltype(v3), const float>::value, "");
+ static_assert(v3 == 1.0F, "");
+
+ static constexpr auto v4 = 1.F; // OK.
+ static_assert(is_same<decltype(v4), const float>::value, "");
+ static_assert(v4 == 1.0F, "");
+
+ static constexpr auto v5 = 1.e0F; // OK.
+ static_assert(is_same<decltype(v5), const float>::value, "");
+ static_assert(v5 == 1.0F, "");
+
+ // Long double
+
+ static constexpr auto v6 = 1.l;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'l', which is not uppercase
+ // 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<decltype(v6), const long double>::value, "");
+ static_assert(v6 == 1., "");
+
+ static constexpr auto v7 = 1.e0l;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'l', which is not uppercase
+ // 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<decltype(v7), const long double>::value, "");
+ static_assert(v7 == 1., "");
+
+ static constexpr auto v8 = 1.L; // OK.
+ static_assert(is_same<decltype(v8), const long double>::value, "");
+ static_assert(v8 == 1., "");
+
+ static constexpr auto v9 = 1.e0L; // OK.
+ static_assert(is_same<decltype(v9), const long double>::value, "");
+ static_assert(v9 == 1., "");
+
+ // __float128
+
+ static constexpr auto v10 = 1.q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'q', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v10 = 1.q;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}Q{{$}}
+ // CHECK-FIXES: static constexpr auto v10 = 1.Q;
+ static_assert(is_same<decltype(v10), const __float128>::value, "");
+ static_assert(v10 == 1., "");
+
+ static constexpr auto v11 = 1.e0q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'q', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v11 = 1.e0q;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}Q{{$}}
+ // CHECK-FIXES: static constexpr auto v11 = 1.e0Q;
+ static_assert(is_same<decltype(v11), const __float128>::value, "");
+ static_assert(v11 == 1., "");
+
+ static constexpr auto v12 = 1.Q; // OK.
+ static_assert(is_same<decltype(v12), const __float128>::value, "");
+ static_assert(v12 == 1., "");
+
+ static constexpr auto v13 = 1.e0Q; // OK.
+ static_assert(is_same<decltype(v13), const __float128>::value, "");
+ static_assert(v13 == 1., "");
+
+ // _Float16
+
+ static constexpr auto v14 = 1.f16;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f16', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v14 = 1.f16;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}F16{{$}}
+ // CHECK-FIXES: static constexpr auto v14 = 1.F16;
+ static_assert(is_same<decltype(v14), const _Float16>::value, "");
+ static_assert(v14 == 1.F16, "");
+
+ static constexpr auto v15 = 1.e0f16;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f16', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v15 = 1.e0f16;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}F16{{$}}
+ // CHECK-FIXES: static constexpr auto v15 = 1.e0F16;
+ static_assert(is_same<decltype(v15), const _Float16>::value, "");
+ static_assert(v15 == 1.F16, "");
+
+ static constexpr auto v16 = 1.F16; // OK.
+ static_assert(is_same<decltype(v16), const _Float16>::value, "");
+ static_assert(v16 == 1.F16, "");
+
+ static constexpr auto v17 = 1.e0F16; // OK.
+ static_assert(is_same<decltype(v17), const _Float16>::value, "");
+ static_assert(v17 == 1.F16, "");
+}
+
+void floating_point_complex_suffix() {
+ // _Complex, I
+
+ static constexpr auto v14 = 1.i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'i', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v14 = 1.i;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}I{{$}}
+ // CHECK-FIXES: static constexpr auto v14 = 1.I;
+ static_assert(is_same<decltype(v14), const _Complex double>::value, "");
+ static_assert(v14 == 1.I, "");
+
+ static constexpr auto v15 = 1.e0i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'i', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v15 = 1.e0i;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}I{{$}}
+ // CHECK-FIXES: static constexpr auto v15 = 1.e0I;
+ static_assert(is_same<decltype(v15), const _Complex double>::value, "");
+ static_assert(v15 == 1.I, "");
+
+ static constexpr auto v16 = 1.I; // OK.
+ static_assert(is_same<decltype(v16), const _Complex double>::value, "");
+ static_assert(v16 == 1.I, "");
+
+ static constexpr auto v17 = 1.e0I; // OK.
+ static_assert(is_same<decltype(v17), const _Complex double>::value, "");
+ static_assert(v17 == 1.I, "");
+
+ // _Complex, J
+
+ static constexpr auto v18 = 1.j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'j', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v18 = 1.j;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}J{{$}}
+ // CHECK-FIXES: static constexpr auto v18 = 1.J;
+ static_assert(is_same<decltype(v18), const _Complex double>::value, "");
+ static_assert(v18 == 1.J, "");
+
+ static constexpr auto v19 = 1.e0j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'j', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v19 = 1.e0j;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}J{{$}}
+ // CHECK-FIXES: static constexpr auto v19 = 1.e0J;
+ static_assert(is_same<decltype(v19), const _Complex double>::value, "");
+ static_assert(v19 == 1.J, "");
+
+ static constexpr auto v20 = 1.J; // OK.
+ static_assert(is_same<decltype(v20), const _Complex double>::value, "");
+ static_assert(v20 == 1.J, "");
+
+ static constexpr auto v21 = 1.e0J; // OK.
+ static_assert(is_same<decltype(v21), const _Complex double>::value, "");
+ static_assert(v21 == 1.J, "");
+}
+
+void macros() {
+#define PASSTHROUGH(X) X
+ static constexpr auto m0 = PASSTHROUGH(1.f);
+ // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: floating point literal has suffix 'f', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto m0 = PASSTHROUGH(1.f);
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}F{{$}}
+ // CHECK-FIXES: static constexpr auto m0 = PASSTHROUGH(1.F);
+ static_assert(is_same<decltype(m0), const float>::value, "");
+ static_assert(m0 == 1.0F, "");
+}
diff --git a/test/clang-tidy/readability-uppercase-literal-suffix-hexadecimal-floating-point.cpp b/test/clang-tidy/readability-uppercase-literal-suffix-hexadecimal-floating-point.cpp
new file mode 100644
index 00000000..4d662694
--- /dev/null
+++ b/test/clang-tidy/readability-uppercase-literal-suffix-hexadecimal-floating-point.cpp
@@ -0,0 +1,155 @@
+// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -I %S
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -- -I %S
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -- -I %S
+
+#include "readability-uppercase-literal-suffix.h"
+
+void floating_point_suffix() {
+ static constexpr auto v0 = 0x0p0; // no literal
+ static_assert(is_same<decltype(v0), const double>::value, "");
+ static_assert(v0 == 0, "");
+
+ // Float
+
+ static constexpr auto v1 = 0xfp0f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
+ // 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<decltype(v1), const float>::value, "");
+ static_assert(v1 == 15, "");
+
+ static constexpr auto v2 = 0xfp0F; // OK
+ static_assert(is_same<decltype(v2), const float>::value, "");
+ static_assert(v2 == 15, "");
+
+ static constexpr auto v3 = 0xfP0f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
+ // 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<decltype(v3), const float>::value, "");
+ static_assert(v3 == 15, "");
+
+ static constexpr auto v4 = 0xfP0F; // OK
+ static_assert(is_same<decltype(v4), const float>::value, "");
+ static_assert(v4 == 15, "");
+
+ static constexpr auto v5 = 0xFP0f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
+ // 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<decltype(v5), const float>::value, "");
+ static_assert(v5 == 15, "");
+
+ static constexpr auto v6 = 0xFP0F; // OK
+ static_assert(is_same<decltype(v6), const float>::value, "");
+ static_assert(v6 == 15, "");
+
+ static constexpr auto v7 = 0xFp0f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
+ // 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<decltype(v7), const float>::value, "");
+ static_assert(v7 == 15, "");
+
+ static constexpr auto v8 = 0xFp0F; // OK
+ static_assert(is_same<decltype(v8), const float>::value, "");
+ static_assert(v8 == 15, "");
+
+ // long double
+
+ static constexpr auto v9 = 0xfp0l;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'l', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v9 = 0xfp0l;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}L{{$}}
+ // CHECK-FIXES: static constexpr auto v9 = 0xfp0L;
+ static_assert(is_same<decltype(v9), const long double>::value, "");
+ static_assert(v9 == 0xfp0, "");
+
+ static constexpr auto v10 = 0xfp0L; // OK.
+ static_assert(is_same<decltype(v10), const long double>::value, "");
+ static_assert(v10 == 0xfp0, "");
+
+ // __float128
+
+ static constexpr auto v11 = 0xfp0q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'q', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v11 = 0xfp0q;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}Q{{$}}
+ // CHECK-FIXES: static constexpr auto v11 = 0xfp0Q;
+ static_assert(is_same<decltype(v11), const __float128>::value, "");
+ static_assert(v11 == 0xfp0, "");
+
+ static constexpr auto v12 = 0xfp0Q; // OK.
+ static_assert(is_same<decltype(v12), const __float128>::value, "");
+ static_assert(v12 == 0xfp0, "");
+
+ // _Float16
+
+ static constexpr auto v13 = 0xfp0f16;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'f16', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v13 = 0xfp0f16;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}F16{{$}}
+ // CHECK-FIXES: static constexpr auto v13 = 0xfp0F16;
+ static_assert(is_same<decltype(v13), const _Float16>::value, "");
+ static_assert(v13 == 0xfp0F16, "");
+
+ static constexpr auto v14 = 0xfp0F16; // OK.
+ static_assert(is_same<decltype(v14), const _Float16>::value, "");
+ static_assert(v14 == 0xfp0F16, "");
+}
+
+void floating_point_complex_suffix() {
+ // _Complex, I
+
+ static constexpr auto v14 = 0xfp0i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'i', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v14 = 0xfp0i;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}I{{$}}
+ // CHECK-FIXES: static constexpr auto v14 = 0xfp0I;
+ static_assert(is_same<decltype(v14), const _Complex double>::value, "");
+ static_assert(v14 == 0xfp0I, "");
+
+ static constexpr auto v16 = 0xfp0I; // OK.
+ static_assert(is_same<decltype(v16), const _Complex double>::value, "");
+ static_assert(v16 == 0xfp0I, "");
+
+ // _Complex, J
+
+ static constexpr auto v18 = 0xfp0j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: floating point literal has suffix 'j', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v18 = 0xfp0j;
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}J{{$}}
+ // CHECK-FIXES: static constexpr auto v18 = 0xfp0J;
+ static_assert(is_same<decltype(v18), const _Complex double>::value, "");
+ static_assert(v18 == 0xfp0J, "");
+
+ static constexpr auto v20 = 0xfp0J; // OK.
+ static_assert(is_same<decltype(v20), const _Complex double>::value, "");
+ static_assert(v20 == 0xfp0J, "");
+}
+
+void macros() {
+#define PASSTHROUGH(X) X
+ static constexpr auto m0 = PASSTHROUGH(0x0p0f);
+ // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: floating point literal has suffix 'f', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto m0 = PASSTHROUGH(0x0p0f);
+ // CHECK-MESSAGES-NEXT: ^ ~
+ // CHECK-MESSAGES-NEXT: {{^ *}}F{{$}}
+ // CHECK-FIXES: static constexpr auto m0 = PASSTHROUGH(0x0p0F);
+ static_assert(is_same<decltype(m0), const float>::value, "");
+ static_assert(m0 == 0x0p0F, "");
+}
diff --git a/test/clang-tidy/readability-uppercase-literal-suffix-integer-custom-list.cpp b/test/clang-tidy/readability-uppercase-literal-suffix-integer-custom-list.cpp
new file mode 100644
index 00000000..ff67a336
--- /dev/null
+++ b/test/clang-tidy/readability-uppercase-literal-suffix-integer-custom-list.cpp
@@ -0,0 +1,130 @@
+// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -config="{CheckOptions: [{key: readability-uppercase-literal-suffix.NewSuffixes, value: 'L;uL'}]}" -- -I %S
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -config="{CheckOptions: [{key: readability-uppercase-literal-suffix.NewSuffixes, value: 'L;uL'}]}" -- -I %S
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -config="{CheckOptions: [{key: readability-uppercase-literal-suffix.NewSuffixes, value: 'L;uL'}]}" -- -I %S
+
+#include "readability-uppercase-literal-suffix.h"
+
+void integer_suffix() {
+ // Unsigned
+
+ static constexpr auto v3 = 1u; // OK.
+ static_assert(is_same<decltype(v3), const unsigned int>::value, "");
+ static_assert(v3 == 1, "");
+
+ static constexpr auto v4 = 1U; // OK.
+ static_assert(is_same<decltype(v4), const unsigned int>::value, "");
+ static_assert(v4 == 1, "");
+
+ // Long
+
+ static constexpr auto v5 = 1l;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'l', which is not uppercase
+ // 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<decltype(v5), const long>::value, "");
+ static_assert(v5 == 1, "");
+
+ static constexpr auto v6 = 1L; // OK.
+ static_assert(is_same<decltype(v6), const long>::value, "");
+ static_assert(v6 == 1, "");
+
+ // Long Long
+
+ static constexpr auto v7 = 1ll; // OK.
+ static_assert(is_same<decltype(v7), const long long>::value, "");
+ static_assert(v7 == 1, "");
+
+ static constexpr auto v8 = 1LL; // OK.
+ static_assert(is_same<decltype(v8), const long long>::value, "");
+ static_assert(v8 == 1, "");
+
+ // Unsigned Long
+
+ static constexpr auto v9 = 1ul;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'ul', which is not uppercase
+ // 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<decltype(v9), const unsigned long>::value, "");
+ static_assert(v9 == 1, "");
+
+ static constexpr auto v10 = 1uL; // OK.
+ static_assert(is_same<decltype(v10), const unsigned long>::value, "");
+ static_assert(v10 == 1, "");
+
+ static constexpr auto v11 = 1Ul;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Ul', which is not uppercase
+ // 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<decltype(v11), const unsigned long>::value, "");
+ static_assert(v11 == 1, "");
+
+ static constexpr auto v12 = 1UL; // OK.
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'UL', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v12 = 1UL;
+ // CHECK-MESSAGES-NEXT: ^~~
+ // CHECK-MESSAGES-NEXT: {{^ *}}uL{{$}}
+ // CHECK-FIXES: static constexpr auto v12 = 1uL;
+ static_assert(is_same<decltype(v12), const unsigned long>::value, "");
+ static_assert(v12 == 1, "");
+
+ // Long Unsigned
+
+ static constexpr auto v13 = 1lu; // OK.
+ static_assert(is_same<decltype(v13), const unsigned long>::value, "");
+ static_assert(v13 == 1, "");
+
+ static constexpr auto v14 = 1Lu; // OK.
+ static_assert(is_same<decltype(v14), const unsigned long>::value, "");
+ static_assert(v14 == 1, "");
+
+ static constexpr auto v15 = 1lU; // OK.
+ static_assert(is_same<decltype(v15), const unsigned long>::value, "");
+ static_assert(v15 == 1, "");
+
+ static constexpr auto v16 = 1LU; // OK.
+ static_assert(is_same<decltype(v16), const unsigned long>::value, "");
+ static_assert(v16 == 1, "");
+
+ // Unsigned Long Long
+
+ static constexpr auto v17 = 1ull; // OK.
+ static_assert(is_same<decltype(v17), const unsigned long long>::value, "");
+ static_assert(v17 == 1, "");
+
+ static constexpr auto v18 = 1uLL; // OK.
+ static_assert(is_same<decltype(v18), const unsigned long long>::value, "");
+ static_assert(v18 == 1, "");
+
+ static constexpr auto v19 = 1Ull; // OK.
+ static_assert(is_same<decltype(v19), const unsigned long long>::value, "");
+ static_assert(v19 == 1, "");
+
+ static constexpr auto v20 = 1ULL; // OK.
+ static_assert(is_same<decltype(v20), const unsigned long long>::value, "");
+ static_assert(v20 == 1, "");
+
+ // Long Long Unsigned
+
+ static constexpr auto v21 = 1llu; // OK.
+ static_assert(is_same<decltype(v21), const unsigned long long>::value, "");
+ static_assert(v21 == 1, "");
+
+ static constexpr auto v22 = 1LLu; // OK.
+ static_assert(is_same<decltype(v22), const unsigned long long>::value, "");
+ static_assert(v22 == 1, "");
+
+ static constexpr auto v23 = 1llU; // OK.
+ static_assert(is_same<decltype(v23), const unsigned long long>::value, "");
+ static_assert(v23 == 1, "");
+
+ static constexpr auto v24 = 1LLU; // OK.
+ static_assert(is_same<decltype(v24), const unsigned long long>::value, "");
+ static_assert(v24 == 1, "");
+}
diff --git a/test/clang-tidy/readability-uppercase-literal-suffix-integer-macro.cpp b/test/clang-tidy/readability-uppercase-literal-suffix-integer-macro.cpp
new file mode 100644
index 00000000..9668a9ea
--- /dev/null
+++ b/test/clang-tidy/readability-uppercase-literal-suffix-integer-macro.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -I %S
+
+void macros() {
+#define INMACRO(X) 1.f
+ static constexpr auto m1 = INMACRO();
+ // CHECK-NOTES: :[[@LINE-1]]:30: warning: floating point literal has suffix 'f', which is not uppercase
+ // CHECK-NOTES: :[[@LINE-3]]:20: note: expanded from macro 'INMACRO'
+ // CHECK-FIXES: #define INMACRO(X) 1.f
+ // CHECK-FIXES: static constexpr auto m1 = INMACRO();
+ // ^ so no fix-its here.
+}
+
+void horrible_macros() {
+#define MAKE_UNSIGNED(x) x##u
+#define ONE MAKE_UNSIGNED(1)
+ static constexpr auto hm0 = ONE;
+ // CHECK-NOTES: :[[@LINE-1]]:31: warning: integer literal has suffix 'u', which is not uppercase
+ // CHECK-NOTES: :[[@LINE-3]]:13: note: expanded from macro 'ONE'
+ // CHECK-NOTES: :[[@LINE-5]]:26: note: expanded from macro 'MAKE_UNSIGNED'
+ // CHECK-NOTES: note: expanded from here
+ // CHECK-FIXES: #define MAKE_UNSIGNED(x) x##u
+ // CHECK-FIXES: #define ONE MAKE_UNSIGNED(1)
+ // CHECK-FIXES: static constexpr auto hm0 = ONE;
+ // Certainly no fix-its.
+}
diff --git a/test/clang-tidy/readability-uppercase-literal-suffix-integer-ms.cpp b/test/clang-tidy/readability-uppercase-literal-suffix-integer-ms.cpp
new file mode 100644
index 00000000..f0d87088
--- /dev/null
+++ b/test/clang-tidy/readability-uppercase-literal-suffix-integer-ms.cpp
@@ -0,0 +1,77 @@
+// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -I %S -fms-extensions
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -- -I %S -fms-extensions
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -- -I %S -fms-extensions
+
+#include "readability-uppercase-literal-suffix.h"
+
+void integer_suffix() {
+ static constexpr auto v0 = __LINE__; // synthetic
+ static_assert(v0 == 9 || v0 == 5, "");
+
+ static constexpr auto v1 = __cplusplus; // synthetic, long
+
+ static constexpr auto v2 = 1; // no literal
+ static_assert(is_same<decltype(v2), const int>::value, "");
+ static_assert(v2 == 1, "");
+
+ // i32
+
+ static constexpr auto v3 = 1i32;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'i32', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v3 = 1i32;
+ // CHECK-MESSAGES-NEXT: ^~
+ // CHECK-MESSAGES-NEXT: {{^ *}}I32{{$}}
+ // CHECK-FIXES: static constexpr auto v3 = 1I32;
+ static_assert(is_same<decltype(v3), const int>::value, "");
+ static_assert(v3 == 1I32, "");
+
+ static constexpr auto v4 = 1I32; // OK.
+ static_assert(is_same<decltype(v4), const int>::value, "");
+ static_assert(v4 == 1I32, "");
+
+ // i64
+
+ static constexpr auto v5 = 1i64;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'i64', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v5 = 1i64;
+ // CHECK-MESSAGES-NEXT: ^~
+ // CHECK-MESSAGES-NEXT: {{^ *}}I64{{$}}
+ // CHECK-FIXES: static constexpr auto v5 = 1I64;
+ static_assert(is_same<decltype(v5), const long int>::value, "");
+ static_assert(v5 == 1I64, "");
+
+ static constexpr auto v6 = 1I64; // OK.
+ static_assert(is_same<decltype(v6), const long int>::value, "");
+ static_assert(v6 == 1I64, "");
+
+ // i16
+
+ static constexpr auto v7 = 1i16;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'i16', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v7 = 1i16;
+ // CHECK-MESSAGES-NEXT: ^~
+ // CHECK-MESSAGES-NEXT: {{^ *}}I16{{$}}
+ // CHECK-FIXES: static constexpr auto v7 = 1I16;
+ static_assert(is_same<decltype(v7), const short>::value, "");
+ static_assert(v7 == 1I16, "");
+
+ static constexpr auto v8 = 1I16; // OK.
+ static_assert(is_same<decltype(v8), const short>::value, "");
+ static_assert(v8 == 1I16, "");
+
+ // i8
+
+ static constexpr auto v9 = 1i8;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'i8', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v9 = 1i8;
+ // CHECK-MESSAGES-NEXT: ^~
+ // CHECK-MESSAGES-NEXT: {{^ *}}I8{{$}}
+ // CHECK-FIXES: static constexpr auto v9 = 1I8;
+ static_assert(is_same<decltype(v9), const char>::value, "");
+ static_assert(v9 == 1I8, "");
+
+ static constexpr auto v10 = 1I8; // OK.
+ static_assert(is_same<decltype(v10), const char>::value, "");
+ static_assert(v10 == 1I8, "");
+}
diff --git a/test/clang-tidy/readability-uppercase-literal-suffix-integer.cpp b/test/clang-tidy/readability-uppercase-literal-suffix-integer.cpp
new file mode 100644
index 00000000..f41cf7ff
--- /dev/null
+++ b/test/clang-tidy/readability-uppercase-literal-suffix-integer.cpp
@@ -0,0 +1,245 @@
+// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix %t -- -- -I %S
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -fix -- -I %S
+// RUN: clang-tidy %t.cpp -checks='-*,readability-uppercase-literal-suffix' -warnings-as-errors='-*,readability-uppercase-literal-suffix' -- -I %S
+
+#include "readability-uppercase-literal-suffix.h"
+
+void integer_suffix() {
+ static constexpr auto v0 = __LINE__; // synthetic
+ static_assert(v0 == 9 || v0 == 5, "");
+
+ static constexpr auto v1 = __cplusplus; // synthetic, long
+
+ static constexpr auto v2 = 1; // no literal
+ static_assert(is_same<decltype(v2), const int>::value, "");
+ static_assert(v2 == 1, "");
+
+ // Unsigned
+
+ static constexpr auto v3 = 1u;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'u', which is not uppercase
+ // 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<decltype(v3), const unsigned int>::value, "");
+ static_assert(v3 == 1, "");
+
+ static constexpr auto v4 = 1U; // OK.
+ static_assert(is_same<decltype(v4), const unsigned int>::value, "");
+ static_assert(v4 == 1, "");
+
+ // Long
+
+ static constexpr auto v5 = 1l;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'l', which is not uppercase
+ // 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<decltype(v5), const long>::value, "");
+ static_assert(v5 == 1, "");
+
+ static constexpr auto v6 = 1L; // OK.
+ static_assert(is_same<decltype(v6), const long>::value, "");
+ static_assert(v6 == 1, "");
+
+ // Long Long
+
+ static constexpr auto v7 = 1ll;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'll', which is not uppercase
+ // 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<decltype(v7), const long long>::value, "");
+ static_assert(v7 == 1, "");
+
+ static constexpr auto v8 = 1LL; // OK.
+ static_assert(is_same<decltype(v8), const long long>::value, "");
+ static_assert(v8 == 1, "");
+
+ // Unsigned Long
+
+ static constexpr auto v9 = 1ul;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'ul', which is not uppercase
+ // 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<decltype(v9), const unsigned long>::value, "");
+ static_assert(v9 == 1, "");
+
+ static constexpr auto v10 = 1uL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'uL', which is not uppercase
+ // 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<decltype(v10), const unsigned long>::value, "");
+ static_assert(v10 == 1, "");
+
+ static constexpr auto v11 = 1Ul;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Ul', which is not uppercase
+ // 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<decltype(v11), const unsigned long>::value, "");
+ static_assert(v11 == 1, "");
+
+ static constexpr auto v12 = 1UL; // OK.
+ static_assert(is_same<decltype(v12), const unsigned long>::value, "");
+ static_assert(v12 == 1, "");
+
+ // Long Unsigned
+
+ static constexpr auto v13 = 1lu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'lu', which is not uppercase
+ // 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<decltype(v13), const unsigned long>::value, "");
+ static_assert(v13 == 1, "");
+
+ static constexpr auto v14 = 1Lu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Lu', which is not uppercase
+ // 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<decltype(v14), const unsigned long>::value, "");
+ static_assert(v14 == 1, "");
+
+ static constexpr auto v15 = 1lU;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'lU', which is not uppercase
+ // 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<decltype(v15), const unsigned long>::value, "");
+ static_assert(v15 == 1, "");
+
+ static constexpr auto v16 = 1LU; // OK.
+ static_assert(is_same<decltype(v16), const unsigned long>::value, "");
+ static_assert(v16 == 1, "");
+
+ // Unsigned Long Long
+
+ static constexpr auto v17 = 1ull;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'ull', which is not uppercase
+ // 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<decltype(v17), const unsigned long long>::value, "");
+ static_assert(v17 == 1, "");
+
+ static constexpr auto v18 = 1uLL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'uLL', which is not uppercase
+ // 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<decltype(v18), const unsigned long long>::value, "");
+ static_assert(v18 == 1, "");
+
+ static constexpr auto v19 = 1Ull;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Ull', which is not uppercase
+ // 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<decltype(v19), const unsigned long long>::value, "");
+ static_assert(v19 == 1, "");
+
+ static constexpr auto v20 = 1ULL; // OK.
+ static_assert(is_same<decltype(v20), const unsigned long long>::value, "");
+ static_assert(v20 == 1, "");
+
+ // Long Long Unsigned
+
+ static constexpr auto v21 = 1llu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'llu', which is not uppercase
+ // 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<decltype(v21), const unsigned long long>::value, "");
+ static_assert(v21 == 1, "");
+
+ static constexpr auto v22 = 1LLu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'LLu', which is not uppercase
+ // 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<decltype(v22), const unsigned long long>::value, "");
+ static_assert(v22 == 1, "");
+
+ static constexpr auto v23 = 1llU;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'llU', which is not uppercase
+ // 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<decltype(v23), const unsigned long long>::value, "");
+ static_assert(v23 == 1, "");
+
+ static constexpr auto v24 = 1LLU; // OK.
+ static_assert(is_same<decltype(v24), const unsigned long long>::value, "");
+ static_assert(v24 == 1, "");
+}
+
+void integer_complex_suffix() {
+ // _Complex, I
+
+ static constexpr auto v25 = 1i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'i', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v25 = 1i;
+ // CHECK-MESSAGES-NEXT: ^~
+ // CHECK-MESSAGES-NEXT: {{^ *}}I{{$}}
+ // CHECK-FIXES: static constexpr auto v25 = 1I;
+ static_assert(is_same<decltype(v25), const _Complex int>::value, "");
+ static_assert(v25 == 1I, "");
+
+ static constexpr auto v26 = 1I; // OK.
+ static_assert(is_same<decltype(v26), const _Complex int>::value, "");
+ static_assert(v26 == 1I, "");
+
+ // _Complex, J
+
+ static constexpr auto v27 = 1j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'j', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v27 = 1j;
+ // CHECK-MESSAGES-NEXT: ^~
+ // CHECK-MESSAGES-NEXT: {{^ *}}J{{$}}
+ // CHECK-FIXES: static constexpr auto v27 = 1J;
+ static_assert(is_same<decltype(v27), const _Complex int>::value, "");
+ static_assert(v27 == 1J, "");
+
+ static constexpr auto v28 = 1J; // OK.
+ static_assert(is_same<decltype(v28), const _Complex int>::value, "");
+ static_assert(v28 == 1J, "");
+}
+
+void macros() {
+#define PASSTHROUGH(X) X
+ static constexpr auto m0 = PASSTHROUGH(1u);
+ // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: integer literal has suffix 'u', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto m0 = PASSTHROUGH(1u);
+ // CHECK-MESSAGES-NEXT: ^~
+ // CHECK-MESSAGES-NEXT: {{^ *}}U{{$}}
+ // CHECK-FIXES: static constexpr auto m0 = PASSTHROUGH(1U);
+ static_assert(is_same<decltype(m0), const unsigned int>::value, "");
+ static_assert(m0 == 1, "");
+}
+
+// Check that user-defined literals do not cause any diags.
+
+unsigned long long int operator"" _ull(unsigned long long int);
+void user_defined_literals() {
+ 1_ull;
+}
diff --git a/test/clang-tidy/readability-uppercase-literal-suffix.h b/test/clang-tidy/readability-uppercase-literal-suffix.h
new file mode 100644
index 00000000..680321e7
--- /dev/null
+++ b/test/clang-tidy/readability-uppercase-literal-suffix.h
@@ -0,0 +1,16 @@
+template <class T, T v>
+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<bool, false>;
+using true_type = integral_constant<bool, true>;
+
+template <class T, class U>
+struct is_same : false_type {};
+
+template <class T>
+struct is_same<T, T> : true_type {};