1 //===--- ReplaceAutoPtrCheck.cpp - clang-tidy------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ReplaceAutoPtrCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/Frontend/CompilerInstance.h" 13 #include "clang/Lex/Lexer.h" 14 #include "clang/Lex/Preprocessor.h" 15 16 using namespace clang; 17 using namespace clang::ast_matchers; 18 19 namespace clang { 20 namespace tidy { 21 namespace modernize { 22 23 namespace { 24 static const char AutoPtrTokenId[] = "AutoPrTokenId"; 25 static const char AutoPtrOwnershipTransferId[] = "AutoPtrOwnershipTransferId"; 26 27 /// Matches expressions that are lvalues. 28 /// 29 /// In the following example, a[0] matches expr(isLValue()): 30 /// \code 31 /// std::string a[2]; 32 /// std::string b; 33 /// b = a[0]; 34 /// b = "this string won't match"; 35 /// \endcode 36 AST_MATCHER(Expr, isLValue) { return Node.getValueKind() == VK_LValue; } 37 38 } // namespace 39 40 ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name, 41 ClangTidyContext *Context) 42 : ClangTidyCheck(Name, Context), 43 Inserter(Options.getLocalOrGlobal("IncludeStyle", 44 utils::IncludeSorter::IS_LLVM)) {} 45 46 void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { 47 Options.store(Opts, "IncludeStyle", Inserter.getStyle()); 48 } 49 50 void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) { 51 auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isInStdNamespace()); 52 auto AutoPtrType = qualType(hasDeclaration(AutoPtrDecl)); 53 54 // std::auto_ptr<int> a; 55 // ^~~~~~~~~~~~~ 56 // 57 // typedef std::auto_ptr<int> int_ptr_t; 58 // ^~~~~~~~~~~~~ 59 // 60 // std::auto_ptr<int> fn(std::auto_ptr<int>); 61 // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~ 62 Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType, 63 // Skip elaboratedType() as the named 64 // type will match soon thereafter. 65 unless(elaboratedType())))) 66 .bind(AutoPtrTokenId), 67 this); 68 69 // using std::auto_ptr; 70 // ^~~~~~~~~~~~~~~~~~~ 71 Finder->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(namedDecl( 72 hasName("auto_ptr"), isInStdNamespace())))) 73 .bind(AutoPtrTokenId), 74 this); 75 76 // Find ownership transfers via copy construction and assignment. 77 // AutoPtrOwnershipTransferId is bound to the part that has to be wrapped 78 // into std::move(). 79 // std::auto_ptr<int> i, j; 80 // i = j; 81 // ~~~~^ 82 auto MovableArgumentMatcher = 83 expr(isLValue(), hasType(AutoPtrType)).bind(AutoPtrOwnershipTransferId); 84 85 Finder->addMatcher( 86 cxxOperatorCallExpr(hasOverloadedOperatorName("="), 87 callee(cxxMethodDecl(ofClass(AutoPtrDecl))), 88 hasArgument(1, MovableArgumentMatcher)), 89 this); 90 Finder->addMatcher( 91 traverse(ast_type_traits::TK_AsIs, 92 cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1), 93 hasArgument(0, MovableArgumentMatcher))), 94 this); 95 } 96 97 void ReplaceAutoPtrCheck::registerPPCallbacks(const SourceManager &SM, 98 Preprocessor *PP, 99 Preprocessor *ModuleExpanderPP) { 100 Inserter.registerPreprocessor(PP); 101 } 102 103 void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) { 104 SourceManager &SM = *Result.SourceManager; 105 if (const auto *E = 106 Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) { 107 CharSourceRange Range = Lexer::makeFileCharRange( 108 CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions()); 109 110 if (Range.isInvalid()) 111 return; 112 113 auto Diag = diag(Range.getBegin(), "use std::move to transfer ownership") 114 << FixItHint::CreateInsertion(Range.getBegin(), "std::move(") 115 << FixItHint::CreateInsertion(Range.getEnd(), ")") 116 << Inserter.createMainFileIncludeInsertion("<utility>"); 117 118 return; 119 } 120 121 SourceLocation AutoPtrLoc; 122 if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) { 123 // std::auto_ptr<int> i; 124 // ^ 125 if (auto Loc = TL->getAs<TemplateSpecializationTypeLoc>()) 126 AutoPtrLoc = Loc.getTemplateNameLoc(); 127 } else if (const auto *D = 128 Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) { 129 // using std::auto_ptr; 130 // ^ 131 AutoPtrLoc = D->getNameInfo().getBeginLoc(); 132 } else { 133 llvm_unreachable("Bad Callback. No node provided."); 134 } 135 136 if (AutoPtrLoc.isMacroID()) 137 AutoPtrLoc = SM.getSpellingLoc(AutoPtrLoc); 138 139 // Ensure that only the 'auto_ptr' token is replaced and not the template 140 // aliases. 141 if (StringRef(SM.getCharacterData(AutoPtrLoc), strlen("auto_ptr")) != 142 "auto_ptr") 143 return; 144 145 SourceLocation EndLoc = 146 AutoPtrLoc.getLocWithOffset(strlen("auto_ptr") - 1); 147 diag(AutoPtrLoc, "auto_ptr is deprecated, use unique_ptr instead") 148 << FixItHint::CreateReplacement(SourceRange(AutoPtrLoc, EndLoc), 149 "unique_ptr"); 150 } 151 152 } // namespace modernize 153 } // namespace tidy 154 } // namespace clang 155