10 #include "../utils/ASTUtils.h" 11 #include "../utils/OptionsUtils.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.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())
92 return OldSuffix.upper();
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(
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", 1) != 0) {}
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);
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.
std::string serializeStringList(ArrayRef< std::string > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
Base class for all clang-tidy checks.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
const LangOptions & getLangOpts() const
Returns the language options from the context.
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
SourceRange LiteralLocation
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.
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
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