diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/misc')
| -rw-r--r-- | clang-tools-extra/clang-tidy/misc/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp | 4 | ||||
| -rw-r--r-- | clang-tools-extra/clang-tidy/misc/UseOverride.cpp | 131 | ||||
| -rw-r--r-- | clang-tools-extra/clang-tidy/misc/UseOverride.h | 29 |
4 files changed, 165 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index 3dd97bf0b4f..796dc15062d 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_library(clangTidyMiscModule ArgumentCommentCheck.cpp MiscTidyModule.cpp RedundantSmartptrGet.cpp + UseOverride.cpp LINK_LIBS clangAST diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp index b89e2dcad48..28a2f0be788 100644 --- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -12,6 +12,7 @@ #include "../ClangTidyModuleRegistry.h" #include "ArgumentCommentCheck.h" #include "RedundantSmartptrGet.h" +#include "UseOverride.h" namespace clang { namespace tidy { @@ -25,6 +26,9 @@ public: CheckFactories.addCheckFactory( "misc-redundant-smartptr-get", new ClangTidyCheckFactory<RedundantSmartptrGet>()); + CheckFactories.addCheckFactory( + "misc-use-override", + new ClangTidyCheckFactory<UseOverride>()); } }; diff --git a/clang-tools-extra/clang-tidy/misc/UseOverride.cpp b/clang-tools-extra/clang-tidy/misc/UseOverride.cpp new file mode 100644 index 00000000000..3d2411ec56a --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/UseOverride.cpp @@ -0,0 +1,131 @@ +//===--- UseOverride.cpp - clang-tidy -------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "UseOverride.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { + +void UseOverride::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(methodDecl(isOverride()).bind("method"), this); +} + +// Re-lex the tokens to get precise locations to insert 'override' and remove +// 'virtual'. +static SmallVector<Token, 16> ParseTokens(CharSourceRange Range, + const SourceManager &Sources, + LangOptions LangOpts) { + std::pair<FileID, unsigned> LocInfo = + Sources.getDecomposedLoc(Range.getBegin()); + StringRef File = Sources.getBufferData(LocInfo.first); + const char *TokenBegin = File.data() + LocInfo.second; + Lexer RawLexer(Sources.getLocForStartOfFile(LocInfo.first), LangOpts, + File.begin(), TokenBegin, File.end()); + SmallVector<Token, 16> Tokens; + Token Tok; + while (!RawLexer.LexFromRawLexer(Tok)) { + if (Tok.is(tok::semi) || Tok.is(tok::l_brace)) + break; + if (Sources.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation())) + break; + Tokens.push_back(Tok); + } + return Tokens; +} + +static StringRef GetText(const Token& Tok, const SourceManager &Sources) { + return {Sources.getCharacterData(Tok.getLocation()), Tok.getLength()}; +} + +void UseOverride::check(const MatchFinder::MatchResult &Result) { + const FunctionDecl *Method = Result.Nodes.getStmtAs<FunctionDecl>("method"); + const SourceManager &Sources = *Result.SourceManager; + + assert(Method != nullptr); + if (Method->getInstantiatedFromMemberFunction() != nullptr) + Method = Method->getInstantiatedFromMemberFunction(); + + if (Method->isImplicit() || Method->getLocation().isMacroID() || + Method->isOutOfLine()) + return; + + if (Method->getAttr<clang::OverrideAttr>() != nullptr && + !Method->isVirtualAsWritten()) + return; // Nothing to do. + + DiagnosticBuilder Diag = diag(Method->getLocation(), + "Prefer using 'override' instead of 'virtual'"); + + CharSourceRange FileRange = + Lexer::makeFileCharRange(CharSourceRange::getTokenRange( + Method->getLocStart(), Method->getLocEnd()), + Sources, Result.Context->getLangOpts()); + + if (!FileRange.isValid()) + return; + + // FIXME: Instead of re-lexing and looking for specific macros such as + // 'ABSTRACT', properly store the location of 'virtual' and '= 0' in each + // FunctionDecl. + SmallVector<Token, 16> Tokens = ParseTokens(FileRange, Sources, + Result.Context->getLangOpts()); + + // Add 'override' on inline declarations that don't already have it. + if (Method->getAttr<clang::OverrideAttr>() == nullptr) { + SourceLocation InsertLoc; + StringRef ReplacementText = "override "; + + if (Method->hasAttrs()) { + for (const clang::Attr *attr : Method->getAttrs()) { + if (!attr->isImplicit()) { + InsertLoc = Sources.getExpansionLoc(attr->getLocation()); + break; + } + } + } + + if (InsertLoc.isInvalid() && Method->doesThisDeclarationHaveABody()) { + InsertLoc = Method->getBody()->getLocStart(); + } + + if (!InsertLoc.isValid()) { + if (Tokens.size() > 2 && GetText(Tokens.back(), Sources) == "0" && + GetText(Tokens[Tokens.size() - 2], Sources) == "=") { + InsertLoc = Tokens[Tokens.size() - 2].getLocation(); + } else if (GetText(Tokens.back(), Sources) == "ABSTRACT") { + InsertLoc = Tokens.back().getLocation(); + } + } + + if (!InsertLoc.isValid()) { + InsertLoc = FileRange.getEnd(); + ReplacementText = " override"; + } + Diag << FixItHint::CreateInsertion(InsertLoc, ReplacementText); + } + + if (Method->isVirtualAsWritten()) { + for (unsigned i = 0, e = Tokens.size(); i != e; ++i) { + if (Tokens[i].is(tok::raw_identifier) && + GetText(Tokens[i], Sources) == "virtual") { + Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange( + Tokens[i].getLocation(), Tokens[i].getLocation())); + break; + } + } + } +} + +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/UseOverride.h b/clang-tools-extra/clang-tidy/misc/UseOverride.h new file mode 100644 index 00000000000..0f911771daa --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/UseOverride.h @@ -0,0 +1,29 @@ +//===--- UseOverride.h - clang-tidy -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USE_OVERRIDE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USE_OVERRIDE_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { + +/// \brief Use C++11's 'override' and remove 'virtual' where applicable. +class UseOverride : public ClangTidyCheck { +public: + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USE_OVERRIDE_H + |

