11 #include "../utils/ASTUtils.h" 12 #include "../utils/OptionsUtils.h" 13 #include "clang/AST/ASTContext.h" 14 #include "clang/ASTMatchers/ASTMatchFinder.h" 15 #include "llvm/ADT/Optional.h" 16 #include "llvm/ADT/SmallString.h" 22 namespace readability {
26 struct IntegerLiteralCheck {
27 using type = clang::IntegerLiteral;
28 static constexpr llvm::StringLiteral
Name = llvm::StringLiteral(
"integer");
30 static constexpr llvm::StringLiteral
SkipFirst = llvm::StringLiteral(
"");
33 static constexpr llvm::StringLiteral
Suffixes =
34 llvm::StringLiteral(
"uUlLiIjJ");
40 struct FloatingLiteralCheck {
41 using type = clang::FloatingLiteral;
42 static constexpr llvm::StringLiteral
Name =
43 llvm::StringLiteral(
"floating point");
50 static constexpr llvm::StringLiteral
SkipFirst = llvm::StringLiteral(
"pP");
53 static constexpr llvm::StringLiteral
Suffixes =
54 llvm::StringLiteral(
"fFlLhHqQiIjJ");
63 llvm::Optional<FixItHint>
FixIt;
66 llvm::Optional<SourceLocation> GetMacroAwareLocation(SourceLocation
Loc,
67 const SourceManager &SM) {
72 SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
73 if (SpellingLoc.isInvalid())
78 llvm::Optional<SourceRange> GetMacroAwareSourceRange(SourceRange
Loc,
79 const SourceManager &SM) {
80 llvm::Optional<SourceLocation> Begin =
81 GetMacroAwareLocation(Loc.getBegin(), SM);
82 llvm::Optional<SourceLocation> End = GetMacroAwareLocation(Loc.getEnd(), SM);
85 return SourceRange(*Begin, *End);
88 llvm::Optional<std::string>
90 const std::vector<std::string> &NewSuffixes) {
92 if (NewSuffixes.empty())
93 return OldSuffix.upper();
95 auto NewSuffix = llvm::find_if(
96 NewSuffixes, [OldSuffix](
const std::string &PotentialNewSuffix) {
97 return OldSuffix.equals_lower(PotentialNewSuffix);
100 if (NewSuffix != NewSuffixes.end())
106 template <
typename LiteralType>
107 llvm::Optional<NewSuffix>
108 shouldReplaceLiteralSuffix(
const Expr &Literal,
109 const std::vector<std::string> &NewSuffixes,
110 const SourceManager &SM,
const LangOptions &LO) {
111 NewSuffix ReplacementDsc;
113 const auto &L = cast<typename LiteralType::type>(Literal);
116 ReplacementDsc.LiteralLocation = L.getSourceRange();
119 bool RangeCanBeFixed =
123 llvm::Optional<SourceRange>
Range =
124 GetMacroAwareSourceRange(ReplacementDsc.LiteralLocation, SM);
129 ReplacementDsc.LiteralLocation = *
Range;
134 const StringRef LiteralSourceText = Lexer::getSourceText(
135 CharSourceRange::getTokenRange(*Range), SM, LO, &Invalid);
136 assert(!Invalid &&
"Failed to retrieve the source text.");
147 if (Skip == StringRef::npos)
158 if (Skip == StringRef::npos)
162 Range->setBegin(Range->getBegin().getLocWithOffset(Skip));
164 ReplacementDsc.OldSuffix = LiteralSourceText.drop_front(Skip);
165 assert(!ReplacementDsc.OldSuffix.empty() &&
166 "We still should have some chars left.");
169 llvm::Optional<std::string> NewSuffix =
170 getNewSuffix(ReplacementDsc.OldSuffix, NewSuffixes);
171 if (!NewSuffix || ReplacementDsc.OldSuffix == *NewSuffix)
175 ReplacementDsc.FixIt = FixItHint::CreateReplacement(*Range, *NewSuffix);
177 return ReplacementDsc;
182 UppercaseLiteralSuffixCheck::UppercaseLiteralSuffixCheck(
187 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", 1) != 0) {}
203 unless(anyOf(hasParent(userDefinedLiteral()),
204 hasAncestor(isImplicit()),
205 hasAncestor(substNonTypeTemplateParmExpr())))),
209 template <
typename LiteralType>
210 bool UppercaseLiteralSuffixCheck::checkBoundMatch(
211 const MatchFinder::MatchResult &
Result) {
212 const auto *Literal =
219 if (
auto Details = shouldReplaceLiteralSuffix<LiteralType>(
220 *Literal, NewSuffixes, *Result.SourceManager,
getLangOpts())) {
221 if (Details->LiteralLocation.getBegin().isMacroID() && IgnoreMacros)
223 auto Complaint =
diag(Details->LiteralLocation.getBegin(),
224 "%0 literal has suffix '%1', which is not uppercase")
227 Complaint << *(Details->FixIt);
234 const MatchFinder::MatchResult &
Result) {
235 if (checkBoundMatch<IntegerLiteralCheck>(Result))
237 checkBoundMatch<FloatingLiteralCheck>(
Result);
SourceLocation Loc
'#' location in the include directive
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
std::string serializeStringList(ArrayRef< std::string > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
LangOptions getLangOpts() const
Returns the language options from the context.
Base class for all clang-tidy checks.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
SourceRange LiteralLocation
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
static constexpr llvm::StringLiteral SkipFirst
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
CharSourceRange Range
SourceRange for the file name.
bool rangeCanBeFixed(SourceRange Range, const SourceManager *SM)
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::Optional< FixItHint > FixIt
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
static constexpr llvm::StringLiteral Suffixes