40 auto IgnoreDestructorMatcher =
41 IgnoreDestructors ? cxxMethodDecl(unless(cxxDestructorDecl()))
43 auto IgnoreTemplateInstantiationsMatcher =
44 IgnoreTemplateInstantiations
45 ? cxxMethodDecl(unless(ast_matchers::isTemplateInstantiation()))
47 Finder->addMatcher(cxxMethodDecl(isOverride(),
48 IgnoreTemplateInstantiationsMatcher,
49 IgnoreDestructorMatcher)
57parseTokens(CharSourceRange Range,
const MatchFinder::MatchResult &Result) {
58 const SourceManager &Sources = *Result.SourceManager;
59 const std::pair<FileID, unsigned> LocInfo =
60 Sources.getDecomposedLoc(Range.getBegin());
61 const StringRef File = Sources.getBufferData(LocInfo.first);
62 const char *TokenBegin = File.data() + LocInfo.second;
63 Lexer RawLexer(Sources.getLocForStartOfFile(LocInfo.first),
64 Result.Context->getLangOpts(), File.begin(), TokenBegin,
69 while (!RawLexer.LexFromRawLexer(Tok)) {
70 if ((Tok.is(tok::semi) || Tok.is(tok::l_brace)) && NestedParens == 0)
72 if (Sources.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation()))
74 if (Tok.is(tok::l_paren))
76 else if (Tok.is(tok::r_paren))
78 if (Tok.is(tok::raw_identifier)) {
79 IdentifierInfo &Info = Result.Context->Idents.get(StringRef(
80 Sources.getCharacterData(Tok.getLocation()), Tok.getLength()));
81 Tok.setIdentifierInfo(&Info);
82 Tok.setKind(Info.getTokenID());
84 Tokens.push_back(Tok);
90 const auto *Method = Result.Nodes.getNodeAs<FunctionDecl>(
"method");
91 const SourceManager &Sources = *Result.SourceManager;
93 ASTContext &Context = *Result.Context;
95 assert(Method !=
nullptr);
96 if (Method->getInstantiatedFromMemberFunction() !=
nullptr)
97 Method = Method->getInstantiatedFromMemberFunction();
99 if (Method->isImplicit() || Method->getLocation().isMacroID() ||
100 Method->isOutOfLine())
103 const bool HasVirtual = Method->isVirtualAsWritten();
104 const bool HasOverride = Method->getAttr<OverrideAttr>();
105 const bool HasFinal = Method->getAttr<FinalAttr>();
107 const bool OnlyVirtualSpecified = HasVirtual && !HasOverride && !HasFinal;
108 const unsigned KeywordCount = HasVirtual + HasOverride + HasFinal;
110 const bool AcceptsOverrideAndFinal =
111 !HasVirtual && HasOverride && HasFinal && AllowOverrideAndFinal;
112 const bool AcceptsVirtualAndOverride = HasVirtual && HasOverride &&
113 AllowVirtualAndOverride &&
114 (!HasFinal || AllowOverrideAndFinal);
116 if ((!OnlyVirtualSpecified && KeywordCount == 1) || AcceptsOverrideAndFinal ||
117 AcceptsVirtualAndOverride)
121 if (OnlyVirtualSpecified) {
122 Message =
"prefer using '%0' or (rarely) '%1' instead of 'virtual'";
123 }
else if (KeywordCount == 0) {
124 Message =
"annotate this function with '%0' or (rarely) '%1'";
126 const StringRef Redundant =
127 HasVirtual ? (HasOverride && HasFinal && !AllowOverrideAndFinal
128 ?
"'virtual' and '%0' are"
131 const StringRef Correct = HasFinal ?
"'%1'" :
"'%0'";
133 Message = (llvm::Twine(Redundant) +
134 " redundant since the function is already declared " + Correct)
138 auto Diag = diag(Method->getLocation(),
Message)
139 << OverrideSpelling << FinalSpelling;
141 const CharSourceRange FileRange = Lexer::makeFileCharRange(
142 CharSourceRange::getTokenRange(Method->getSourceRange()), Sources,
145 if (!FileRange.isValid())
153 if (!HasFinal && !HasOverride) {
156 if (OverrideSpelling !=
"override" &&
157 !Context.Idents.get(OverrideSpelling).hasMacroDefinition())
160 Diag << FixItHint::CreateInsertion(
161 Lexer::getLocForEndOfToken(
162 Method->getTypeSourceInfo()->getTypeLoc().getEndLoc(), 0, Sources,
164 (
" " + OverrideSpelling).str());
167 if (HasFinal && HasOverride && !AllowOverrideAndFinal)
168 Diag << FixItHint::CreateRemoval(
169 Method->getAttr<OverrideAttr>()->getLocation());
172 for (
const Token Tok : Tokens) {
173 if (Tok.is(tok::kw_virtual)) {
174 std::optional<Token> NextToken =
176 Tok.getEndLoc(), Sources, getLangOpts());
177 if (NextToken.has_value()) {
178 Diag << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
179 Tok.getLocation(), NextToken->getLocation()));
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.