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);
35 if (IgnoreDestructors)
37 cxxMethodDecl(isOverride(), unless(cxxDestructorDecl())).bind(
"method"),
40 Finder->addMatcher(cxxMethodDecl(isOverride()).bind(
"method"),
this);
45 static SmallVector<Token, 16>
47 const SourceManager &Sources = *Result.SourceManager;
48 std::pair<FileID, unsigned> LocInfo =
49 Sources.getDecomposedLoc(
Range.getBegin());
50 StringRef File = Sources.getBufferData(LocInfo.first);
51 const char *TokenBegin = File.data() + LocInfo.second;
52 Lexer RawLexer(Sources.getLocForStartOfFile(LocInfo.first),
53 Result.Context->getLangOpts(), File.begin(), TokenBegin,
55 SmallVector<Token, 16> Tokens;
58 while (!RawLexer.LexFromRawLexer(Tok)) {
59 if ((Tok.is(tok::semi) || Tok.is(tok::l_brace)) && NestedParens == 0)
61 if (Sources.isBeforeInTranslationUnit(
Range.getEnd(), Tok.getLocation()))
63 if (Tok.is(tok::l_paren))
65 else if (Tok.is(tok::r_paren))
67 if (Tok.is(tok::raw_identifier)) {
68 IdentifierInfo &
Info = Result.Context->Idents.get(StringRef(
69 Sources.getCharacterData(Tok.getLocation()), Tok.getLength()));
70 Tok.setIdentifierInfo(&
Info);
71 Tok.setKind(
Info.getTokenID());
73 Tokens.push_back(Tok);
78 static StringRef
GetText(
const Token &Tok,
const SourceManager &Sources) {
79 return StringRef(Sources.getCharacterData(Tok.getLocation()),
84 const auto *Method = Result.Nodes.getNodeAs<FunctionDecl>(
"method");
85 const SourceManager &Sources = *Result.SourceManager;
87 ASTContext &Context = *Result.Context;
89 assert(Method !=
nullptr);
90 if (Method->getInstantiatedFromMemberFunction() !=
nullptr)
91 Method = Method->getInstantiatedFromMemberFunction();
93 if (Method->isImplicit() || Method->getLocation().isMacroID() ||
94 Method->isOutOfLine())
97 bool HasVirtual = Method->isVirtualAsWritten();
98 bool HasOverride = Method->getAttr<OverrideAttr>();
99 bool HasFinal = Method->getAttr<FinalAttr>();
101 bool OnlyVirtualSpecified = HasVirtual && !HasOverride && !HasFinal;
102 unsigned KeywordCount = HasVirtual + HasOverride + HasFinal;
104 if ((!OnlyVirtualSpecified && KeywordCount == 1) ||
105 (!HasVirtual && HasOverride && HasFinal && AllowOverrideAndFinal))
109 if (OnlyVirtualSpecified) {
110 Message =
"prefer using '%0' or (rarely) '%1' instead of 'virtual'";
111 }
else if (KeywordCount == 0) {
112 Message =
"annotate this function with '%0' or (rarely) '%1'";
114 StringRef Redundant =
115 HasVirtual ? (HasOverride && HasFinal && !AllowOverrideAndFinal
116 ?
"'virtual' and '%0' are"
119 StringRef Correct = HasFinal ?
"'%1'" :
"'%0'";
121 Message = (llvm::Twine(Redundant) +
122 " redundant since the function is already declared " + Correct)
127 << OverrideSpelling << FinalSpelling;
129 CharSourceRange FileRange = Lexer::makeFileCharRange(
130 CharSourceRange::getTokenRange(Method->getSourceRange()), Sources,
133 if (!FileRange.isValid())
139 SmallVector<Token, 16> Tokens =
ParseTokens(FileRange, Result);
142 if (!HasFinal && !HasOverride) {
143 SourceLocation InsertLoc;
144 std::string ReplacementText = OverrideSpelling +
" ";
145 SourceLocation MethodLoc = Method->getLocation();
147 for (Token T : Tokens) {
148 if (T.is(tok::kw___attribute) &&
149 !Sources.isBeforeInTranslationUnit(T.getLocation(), MethodLoc)) {
150 InsertLoc = T.getLocation();
155 if (Method->hasAttrs()) {
156 for (
const clang::Attr *A : Method->getAttrs()) {
157 if (!A->isImplicit() && !A->isInherited()) {
159 Sources.getExpansionLoc(A->getRange().getBegin());
160 if ((!InsertLoc.isValid() ||
161 Sources.isBeforeInTranslationUnit(
Loc, InsertLoc)) &&
162 !Sources.isBeforeInTranslationUnit(
Loc, MethodLoc))
168 if (InsertLoc.isInvalid() && Method->doesThisDeclarationHaveABody() &&
169 Method->getBody() && !Method->isDefaulted()) {
174 ReplacementText =
" " + OverrideSpelling;
175 auto LastTokenIter = std::prev(Tokens.end());
178 if (LastTokenIter->is(tok::kw_try))
179 LastTokenIter = std::prev(LastTokenIter);
180 InsertLoc = LastTokenIter->getEndLoc();
183 if (!InsertLoc.isValid()) {
187 if (Tokens.size() > 2 &&
188 (
GetText(Tokens.back(), Sources) ==
"0" ||
189 Tokens.back().is(tok::kw_default) ||
190 Tokens.back().is(tok::kw_delete)) &&
191 GetText(Tokens[Tokens.size() - 2], Sources) ==
"=") {
192 InsertLoc = Tokens[Tokens.size() - 2].getLocation();
194 if ((Tokens[Tokens.size() - 2].getFlags() & Token::LeadingSpace) == 0)
195 ReplacementText =
" " + OverrideSpelling +
" ";
196 }
else if (
GetText(Tokens.back(), Sources) ==
"ABSTRACT")
197 InsertLoc = Tokens.back().getLocation();
200 if (!InsertLoc.isValid()) {
201 InsertLoc = FileRange.getEnd();
202 ReplacementText =
" " + OverrideSpelling;
207 if (OverrideSpelling !=
"override" &&
208 !Context.Idents.get(OverrideSpelling).hasMacroDefinition())
211 Diag << FixItHint::CreateInsertion(InsertLoc, ReplacementText);
214 if (HasFinal && HasOverride && !AllowOverrideAndFinal) {
215 SourceLocation OverrideLoc = Method->getAttr<OverrideAttr>()->getLocation();
216 Diag << FixItHint::CreateRemoval(
217 CharSourceRange::getTokenRange(OverrideLoc, OverrideLoc));
221 for (Token Tok : Tokens) {
222 if (Tok.is(tok::kw_virtual)) {
223 Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
224 Tok.getLocation(), Tok.getLocation()));