diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy')
4 files changed, 326 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index 56ef66008ba..1d575af525c 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_library(clangTidyModernizeModule LoopConvertUtils.cpp ModernizeTidyModule.cpp PassByValueCheck.cpp + ReplaceAutoPtrCheck.cpp UseAutoCheck.cpp UseNullptrCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index 9f482b171b7..71c6221d257 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -12,6 +12,7 @@ #include "../ClangTidyModuleRegistry.h" #include "LoopConvertCheck.h" #include "PassByValueCheck.h" +#include "ReplaceAutoPtrCheck.h" #include "UseAutoCheck.h" #include "UseNullptrCheck.h" @@ -26,6 +27,8 @@ public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck<LoopConvertCheck>("modernize-loop-convert"); CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value"); + CheckFactories.registerCheck<ReplaceAutoPtrCheck>( + "modernize-replace-auto-ptr"); CheckFactories.registerCheck<UseAutoCheck>("modernize-use-auto"); CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr"); } @@ -35,6 +38,7 @@ public: auto &Opts = Options.CheckOptions; Opts["modernize-loop-convert.MinConfidence"] = "reasonable"; Opts["modernize-pass-by-value.IncludeStyle"] = "llvm"; // Also: "google". + Opts["modernize-replace-auto-ptr.IncludeStyle"] = "llvm"; // Also: "google". // Comma-separated list of macros that behave like NULL. Opts["modernize-use-nullptr.NullMacros"] = "NULL"; diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp new file mode 100644 index 00000000000..83f12824afe --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp @@ -0,0 +1,262 @@ +//===--- ReplaceAutoPtrCheck.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 "ReplaceAutoPtrCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang; +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace modernize { + +const char AutoPtrTokenId[] = "AutoPrTokenId"; +const char AutoPtrOwnershipTransferId[] = "AutoPtrOwnershipTransferId"; + +/// \brief Matches expressions that are lvalues. +/// +/// In the following example, a[0] matches expr(isLValue()): +/// \code +/// std::string a[2]; +/// std::string b; +/// b = a[0]; +/// b = "this string won't match"; +/// \endcode +AST_MATCHER(Expr, isLValue) { return Node.getValueKind() == VK_LValue; } + +/// Matches declarations whose declaration context is the C++ standard library +/// namespace std. +/// +/// Note that inline namespaces are silently ignored during the lookup since +/// both libstdc++ and libc++ are known to use them for versioning purposes. +/// +/// Given: +/// \code +/// namespace ns { +/// struct my_type {}; +/// using namespace std; +/// } +/// +/// using std::vector; +/// using ns:my_type; +/// using ns::list; +/// \code +/// +/// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(isFromStdNamespace()))) +/// matches "using std::vector" and "using ns::list". +AST_MATCHER(Decl, isFromStdNamespace) { + const DeclContext *D = Node.getDeclContext(); + + while (D->isInlineNamespace()) + D = D->getParent(); + + if (!D->isNamespace() || !D->getParent()->isTranslationUnit()) + return false; + + const IdentifierInfo *Info = cast<NamespaceDecl>(D)->getIdentifier(); + + return (Info && Info->isStr("std")); +} + +/// \brief Matcher that finds auto_ptr declarations. +static DeclarationMatcher AutoPtrDecl = + recordDecl(hasName("auto_ptr"), isFromStdNamespace()); + +/// \brief Matches types declared as auto_ptr. +static TypeMatcher AutoPtrType = qualType(hasDeclaration(AutoPtrDecl)); + +/// \brief Matcher that finds expressions that are candidates to be wrapped with +/// 'std::move'. +/// +/// Binds the id \c AutoPtrOwnershipTransferId to the expression. +static StatementMatcher MovableArgumentMatcher = + expr(allOf(isLValue(), hasType(AutoPtrType))) + .bind(AutoPtrOwnershipTransferId); + +/// \brief Creates a matcher that finds the locations of types referring to the +/// \c std::auto_ptr() type. +/// +/// \code +/// std::auto_ptr<int> a; +/// ^~~~~~~~~~~~~ +/// +/// typedef std::auto_ptr<int> int_ptr_t; +/// ^~~~~~~~~~~~~ +/// +/// std::auto_ptr<int> fn(std::auto_ptr<int>); +/// ^~~~~~~~~~~~~ ^~~~~~~~~~~~~ +/// +/// <etc...> +/// \endcode +TypeLocMatcher makeAutoPtrTypeLocMatcher() { + // Skip elaboratedType() as the named type will match soon thereafter. + return typeLoc(loc(qualType(AutoPtrType, unless(elaboratedType())))) + .bind(AutoPtrTokenId); +} + +/// \brief Creates a matcher that finds the using declarations referring to +/// \c std::auto_ptr. +/// +/// \code +/// using std::auto_ptr; +/// ^~~~~~~~~~~~~~~~~~~ +/// \endcode +DeclarationMatcher makeAutoPtrUsingDeclMatcher() { + return usingDecl(hasAnyUsingShadowDecl(hasTargetDecl( + allOf(hasName("auto_ptr"), isFromStdNamespace())))) + .bind(AutoPtrTokenId); +} + +/// \brief Creates a matcher that finds the \c std::auto_ptr copy-ctor and +/// assign-operator expressions. +/// +/// \c AutoPtrOwnershipTransferId is assigned to the argument of the expression, +/// this is the part that has to be wrapped by \c std::move(). +/// +/// \code +/// std::auto_ptr<int> i, j; +/// i = j; +/// ~~~~^ +/// \endcode +StatementMatcher makeTransferOwnershipExprMatcher() { + return anyOf(operatorCallExpr(allOf(hasOverloadedOperatorName("="), + callee(methodDecl(ofClass(AutoPtrDecl))), + hasArgument(1, MovableArgumentMatcher))), + constructExpr(allOf(hasType(AutoPtrType), argumentCountIs(1), + hasArgument(0, MovableArgumentMatcher)))); +} + +/// \brief Locates the \c auto_ptr token when it is referred by a \c TypeLoc. +/// +/// \code +/// std::auto_ptr<int> i; +/// ^~~~~~~~~~~~~ +/// \endcode +/// +/// The caret represents the location returned and the tildes cover the +/// parameter \p AutoPtrTypeLoc. +/// +/// \return An invalid \c SourceLocation if not found, otherwise the location +/// of the beginning of the \c auto_ptr token. +static SourceLocation locateFromTypeLoc(const TypeLoc *AutoPtrTypeLoc, + const SourceManager &SM) { + auto TL = AutoPtrTypeLoc->getAs<TemplateSpecializationTypeLoc>(); + if (TL.isNull()) + return SourceLocation(); + + return TL.getTemplateNameLoc(); +} + +/// \brief Locates the \c auto_ptr token in using declarations. +/// +/// \code +/// using std::auto_ptr; +/// ^ +/// \endcode +/// +/// The caret represents the location returned. +/// +/// \return An invalid \c SourceLocation if not found, otherwise the location +/// of the beginning of the \c auto_ptr token. +static SourceLocation locateFromUsingDecl(const UsingDecl *UsingAutoPtrDecl, + const SourceManager &SM) { + return UsingAutoPtrDecl->getNameInfo().getBeginLoc(); +} + +/// \brief Verifies that the token at \p TokenStart is 'auto_ptr'. +static bool checkTokenIsAutoPtr(SourceLocation TokenStart, + const SourceManager &SM, + const LangOptions &LO) { + SmallVector<char, 8> Buffer; + bool Invalid = false; + StringRef Res = Lexer::getSpelling(TokenStart, Buffer, SM, LO, &Invalid); + + return (!Invalid && Res == "auto_ptr"); +} + +ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IncludeStyle(Options.get("IncludeStyle", "llvm") == "llvm" + ? IncludeSorter::IS_LLVM + : IncludeSorter::IS_Google) {} + +void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IncludeStyle", + IncludeStyle == IncludeSorter::IS_LLVM ? "llvm" : "google"); +} + +void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(makeAutoPtrTypeLocMatcher(), this); + Finder->addMatcher(makeAutoPtrUsingDeclMatcher(), this); + Finder->addMatcher(makeTransferOwnershipExprMatcher(), this); +} + +void ReplaceAutoPtrCheck::registerPPCallbacks(CompilerInstance &Compiler) { + Inserter.reset(new IncludeInserter(Compiler.getSourceManager(), + Compiler.getLangOpts(), IncludeStyle)); + Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks()); +} + +void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) { + SourceManager &SM = *Result.SourceManager; + if (const auto *E = + Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) { + CharSourceRange Range = Lexer::makeFileCharRange( + CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions()); + + if (Range.isInvalid()) + return; + + auto Diag = diag(Range.getBegin(), "use std::move to transfer ownership") + << FixItHint::CreateInsertion(Range.getBegin(), "std::move(") + << FixItHint::CreateInsertion(Range.getEnd(), ")"); + + auto Insertion = + Inserter->CreateIncludeInsertion(SM.getMainFileID(), "utility", + /*IsAngled=*/true); + if (Insertion.hasValue()) + Diag << Insertion.getValue(); + + return; + } + + SourceLocation IdentifierLoc; + if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) { + IdentifierLoc = locateFromTypeLoc(TL, SM); + } else if (const auto *D = + Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) { + IdentifierLoc = locateFromUsingDecl(D, SM); + } else { + llvm_unreachable("Bad Callback. No node provided."); + } + + if (IdentifierLoc.isMacroID()) + IdentifierLoc = SM.getSpellingLoc(IdentifierLoc); + + // Ensure that only the 'auto_ptr' token is replaced and not the template + // aliases. + if (!checkTokenIsAutoPtr(IdentifierLoc, SM, LangOptions())) + return; + + SourceLocation EndLoc = + IdentifierLoc.getLocWithOffset(strlen("auto_ptr") - 1); + diag(IdentifierLoc, "auto_ptr is deprecated, use unique_ptr instead") + << FixItHint::CreateReplacement(SourceRange(IdentifierLoc, EndLoc), + "unique_ptr"); +} + +} // namespace modernize +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h new file mode 100644 index 00000000000..4aad852c8b0 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h @@ -0,0 +1,59 @@ +//===--- ReplaceAutoPtrCheck.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_MODERNIZE_REPLACE_AUTO_PTR_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_AUTO_PTR_H + +#include "../ClangTidy.h" +#include "../utils/IncludeInserter.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// \brief Transforms the deprecated \c std::auto_ptr into the C++11 \c +/// std::unique_ptr. +/// +/// Note that both the \c std::auto_ptr type and the transfer of ownership are +/// transformed. \c std::auto_ptr provides two ways to transfer the ownership, +/// the copy-constructor and the assignment operator. Unlike most classes these +/// operations do not 'copy' the resource but they 'steal' it. +/// \c std::unique_ptr uses move semantics instead, which makes the intent of +/// transferring the resource explicit. This difference between the two smart +/// pointers requeres to wrap the copy-ctor and assign-operator with +/// \c std::move(). +/// +/// For example, given: +/// \code +/// std::auto_ptr<int> i, j; +/// i = j; +/// \endcode +/// This code is transformed to: +/// \code +/// std::unique_ptr<in> i, j; +/// i = std::move(j); +/// \endcode +class ReplaceAutoPtrCheck : public ClangTidyCheck { +public: + ReplaceAutoPtrCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void registerPPCallbacks(CompilerInstance &Compiler) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + std::unique_ptr<IncludeInserter> Inserter; + const IncludeSorter::IncludeStyle IncludeStyle; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_AUTO_PTR_H |

