10 #include "../utils/ASTUtils.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/SmallString.h"
21 namespace readability {
25 struct IntegerLiteralCheck {
26 using type = clang::IntegerLiteral;
27 static constexpr llvm::StringLiteral
Name = llvm::StringLiteral(
"integer");
29 static constexpr llvm::StringLiteral
SkipFirst = llvm::StringLiteral(
"");
32 static constexpr llvm::StringLiteral
Suffixes =
33 llvm::StringLiteral(
"uUlLiIjJ");
39 struct FloatingLiteralCheck {
40 using type = clang::FloatingLiteral;
41 static constexpr llvm::StringLiteral
Name =
42 llvm::StringLiteral(
"floating point");
49 static constexpr llvm::StringLiteral
SkipFirst = llvm::StringLiteral(
"pP");
52 static constexpr llvm::StringLiteral
Suffixes =
53 llvm::StringLiteral(
"fFlLhHqQiIjJ");
62 llvm::Optional<FixItHint>
FixIt;
65 llvm::Optional<SourceLocation> GetMacroAwareLocation(SourceLocation
Loc,
66 const SourceManager &SM) {
71 SourceLocation SpellingLoc = SM.getSpellingLoc(
Loc);
72 if (SpellingLoc.isInvalid())
77 llvm::Optional<SourceRange> GetMacroAwareSourceRange(SourceRange
Loc,
78 const SourceManager &SM) {
79 llvm::Optional<SourceLocation> Begin =
80 GetMacroAwareLocation(
Loc.getBegin(), SM);
81 llvm::Optional<SourceLocation> End = GetMacroAwareLocation(
Loc.getEnd(), SM);
84 return SourceRange(*Begin, *End);
87 llvm::Optional<std::string>
89 const std::vector<std::string> &NewSuffixes) {
91 if (NewSuffixes.empty())
94 auto NewSuffix = llvm::find_if(
95 NewSuffixes, [
OldSuffix](
const std::string &PotentialNewSuffix) {
96 return OldSuffix.equals_lower(PotentialNewSuffix);
99 if (NewSuffix != NewSuffixes.end())
105 template <
typename LiteralType>
106 llvm::Optional<NewSuffix>
107 shouldReplaceLiteralSuffix(
const Expr &Literal,
108 const std::vector<std::string> &NewSuffixes,
109 const SourceManager &SM,
const LangOptions &LO) {
110 NewSuffix ReplacementDsc;
112 const auto &L = cast<typename LiteralType::type>(Literal);
115 ReplacementDsc.LiteralLocation = L.getSourceRange();
118 bool RangeCanBeFixed =
122 llvm::Optional<SourceRange>
Range =
123 GetMacroAwareSourceRange(ReplacementDsc.LiteralLocation, SM);
128 ReplacementDsc.LiteralLocation = *
Range;
133 const StringRef LiteralSourceText = Lexer::getSourceText(
134 CharSourceRange::getTokenRange(*
Range), SM, LO, &Invalid);
135 assert(!Invalid &&
"Failed to retrieve the source text.");
146 if (Skip == StringRef::npos)
157 if (Skip == StringRef::npos)
161 Range->setBegin(
Range->getBegin().getLocWithOffset(Skip));
163 ReplacementDsc.OldSuffix = LiteralSourceText.drop_front(Skip);
164 assert(!ReplacementDsc.OldSuffix.empty() &&
165 "We still should have some chars left.");
168 llvm::Optional<std::string> NewSuffix =
169 getNewSuffix(ReplacementDsc.OldSuffix, NewSuffixes);
170 if (!NewSuffix || ReplacementDsc.OldSuffix == *NewSuffix)
174 ReplacementDsc.FixIt = FixItHint::CreateReplacement(*
Range, *NewSuffix);
176 return ReplacementDsc;
181 UppercaseLiteralSuffixCheck::UppercaseLiteralSuffixCheck(
186 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true)) {}
199 Finder->addMatcher(traverse(TK_AsIs,
202 unless(anyOf(hasParent(userDefinedLiteral()),
203 hasAncestor(isImplicit()),
204 hasAncestor(substNonTypeTemplateParmExpr()))))),
208 template <
typename LiteralType>
209 bool UppercaseLiteralSuffixCheck::checkBoundMatch(
210 const MatchFinder::MatchResult &Result) {
211 const auto *Literal =
218 if (
auto Details = shouldReplaceLiteralSuffix<LiteralType>(
219 *Literal, NewSuffixes, *Result.SourceManager,
getLangOpts())) {
220 if (Details->LiteralLocation.getBegin().isMacroID() && IgnoreMacros)
222 auto Complaint =
diag(Details->LiteralLocation.getBegin(),
223 "%0 literal has suffix '%1', which is not uppercase")
226 Complaint << *(Details->FixIt);
233 const MatchFinder::MatchResult &Result) {
234 if (checkBoundMatch<IntegerLiteralCheck>(Result))
236 checkBoundMatch<FloatingLiteralCheck>(Result);