10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/Lex/Lexer.h" 22 IgnoreDestructors(Options.get(
"IgnoreDestructors", false)),
23 AllowOverrideAndFinal(Options.get(
"AllowOverrideAndFinal", false)),
24 OverrideSpelling(Options.get(
"OverrideSpelling",
"override")),
25 FinalSpelling(Options.get(
"FinalSpelling",
"final")) {}
28 Options.
store(Opts,
"IgnoreDestructors", IgnoreDestructors);
29 Options.
store(Opts,
"AllowOverrideAndFinal", AllowOverrideAndFinal);
30 Options.
store(Opts,
"OverrideSpelling", OverrideSpelling);
39 if (IgnoreDestructors)
41 cxxMethodDecl(isOverride(), unless(cxxDestructorDecl())).bind(
"method"),
44 Finder->addMatcher(cxxMethodDecl(isOverride()).bind(
"method"),
this);
49 static SmallVector<Token, 16>
51 const SourceManager &Sources = *Result.SourceManager;
52 std::pair<FileID, unsigned> LocInfo =
53 Sources.getDecomposedLoc(Range.getBegin());
54 StringRef File = Sources.getBufferData(LocInfo.first);
55 const char *TokenBegin = File.data() + LocInfo.second;
56 Lexer RawLexer(Sources.getLocForStartOfFile(LocInfo.first),
57 Result.Context->getLangOpts(), File.begin(), TokenBegin,
59 SmallVector<Token, 16> Tokens;
62 while (!RawLexer.LexFromRawLexer(Tok)) {
63 if ((Tok.is(tok::semi) || Tok.is(tok::l_brace)) && NestedParens == 0)
65 if (Sources.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation()))
67 if (Tok.is(tok::l_paren))
69 else if (Tok.is(tok::r_paren))
71 if (Tok.is(tok::raw_identifier)) {
72 IdentifierInfo &
Info = Result.Context->Idents.get(StringRef(
73 Sources.getCharacterData(Tok.getLocation()), Tok.getLength()));
74 Tok.setIdentifierInfo(&Info);
75 Tok.setKind(Info.getTokenID());
77 Tokens.push_back(Tok);
82 static StringRef
GetText(
const Token &Tok,
const SourceManager &Sources) {
83 return StringRef(Sources.getCharacterData(Tok.getLocation()),
88 const auto *Method = Result.Nodes.getNodeAs<FunctionDecl>(
"method");
89 const SourceManager &Sources = *Result.SourceManager;
91 ASTContext &Context = *Result.Context;
93 assert(Method !=
nullptr);
94 if (Method->getInstantiatedFromMemberFunction() !=
nullptr)
95 Method = Method->getInstantiatedFromMemberFunction();
97 if (Method->isImplicit() || Method->getLocation().isMacroID() ||
98 Method->isOutOfLine())
101 bool HasVirtual = Method->isVirtualAsWritten();
102 bool HasOverride = Method->getAttr<OverrideAttr>();
103 bool HasFinal = Method->getAttr<FinalAttr>();
105 bool OnlyVirtualSpecified = HasVirtual && !HasOverride && !HasFinal;
106 unsigned KeywordCount = HasVirtual + HasOverride + HasFinal;
108 if ((!OnlyVirtualSpecified && KeywordCount == 1) ||
109 (!HasVirtual && HasOverride && HasFinal && AllowOverrideAndFinal))
113 if (OnlyVirtualSpecified) {
114 Message =
"prefer using '%0' or (rarely) '%1' instead of 'virtual'";
115 }
else if (KeywordCount == 0) {
116 Message =
"annotate this function with '%0' or (rarely) '%1'";
118 StringRef Redundant =
119 HasVirtual ? (HasOverride && HasFinal && !AllowOverrideAndFinal
120 ?
"'virtual' and '%0' are" 123 StringRef Correct = HasFinal ?
"'%1'" :
"'%0'";
125 Message = (llvm::Twine(Redundant) +
126 " redundant since the function is already declared " + Correct)
131 << OverrideSpelling << FinalSpelling;
133 CharSourceRange FileRange = Lexer::makeFileCharRange(
137 if (!FileRange.isValid())
143 SmallVector<Token, 16> Tokens =
ParseTokens(FileRange, Result);
146 if (!HasFinal && !HasOverride) {
147 SourceLocation InsertLoc;
148 std::string ReplacementText = OverrideSpelling +
" ";
149 SourceLocation MethodLoc = Method->getLocation();
151 for (Token T : Tokens) {
152 if (T.is(tok::kw___attribute) &&
153 !Sources.isBeforeInTranslationUnit(T.getLocation(), MethodLoc)) {
154 InsertLoc = T.getLocation();
159 if (Method->hasAttrs()) {
160 for (
const clang::Attr *A : Method->getAttrs()) {
161 if (!A->isImplicit() && !A->isInherited()) {
163 Sources.getExpansionLoc(A->getRange().getBegin());
164 if ((!InsertLoc.isValid() ||
165 Sources.isBeforeInTranslationUnit(Loc, InsertLoc)) &&
166 !Sources.isBeforeInTranslationUnit(Loc, MethodLoc))
172 if (InsertLoc.isInvalid() && Method->doesThisDeclarationHaveABody() &&
173 Method->getBody() && !Method->isDefaulted()) {
178 ReplacementText =
" " + OverrideSpelling;
179 auto LastTokenIter = std::prev(Tokens.end());
182 if (LastTokenIter->is(tok::kw_try))
183 LastTokenIter = std::prev(LastTokenIter);
184 InsertLoc = LastTokenIter->getEndLoc();
187 if (!InsertLoc.isValid()) {
191 if (Tokens.size() > 2 &&
192 (
GetText(Tokens.back(), Sources) ==
"0" ||
193 Tokens.back().is(tok::kw_default) ||
194 Tokens.back().is(tok::kw_delete)) &&
195 GetText(Tokens[Tokens.size() - 2], Sources) ==
"=") {
196 InsertLoc = Tokens[Tokens.size() - 2].getLocation();
198 if ((Tokens[Tokens.size() - 2].getFlags() & Token::LeadingSpace) == 0)
199 ReplacementText =
" " + OverrideSpelling +
" ";
200 }
else if (
GetText(Tokens.back(), Sources) ==
"ABSTRACT")
201 InsertLoc = Tokens.back().getLocation();
204 if (!InsertLoc.isValid()) {
205 InsertLoc = FileRange.getEnd();
206 ReplacementText =
" " + OverrideSpelling;
211 if (OverrideSpelling !=
"override" &&
212 !Context.Idents.get(OverrideSpelling).hasMacroDefinition())
215 Diag << FixItHint::CreateInsertion(InsertLoc, ReplacementText);
218 if (HasFinal && HasOverride && !AllowOverrideAndFinal) {
219 SourceLocation OverrideLoc = Method->getAttr<OverrideAttr>()->getLocation();
220 Diag << FixItHint::CreateRemoval(
225 for (Token Tok : Tokens) {
226 if (Tok.is(tok::kw_virtual)) {
228 Tok.getLocation(), Tok.getLocation()));
SourceLocation Loc
'#' location in the include directive
constexpr llvm::StringLiteral Message
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.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
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 StringRef GetText(const Token &Tok, const SourceManager &Sources)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
CharSourceRange Range
SourceRange for the file name.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
static SmallVector< Token, 16 > ParseTokens(CharSourceRange Range, const MatchFinder::MatchResult &Result)
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.