151 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//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 16using namespace clang;17using namespace clang::ast_matchers;18 19namespace clang::tidy::modernize {20 21namespace {22static const char AutoPtrTokenId[] = "AutoPrTokenId";23static const char AutoPtrOwnershipTransferId[] = "AutoPtrOwnershipTransferId";24 25/// Matches expressions that are lvalues.26///27/// In the following example, a[0] matches expr(isLValue()):28/// \code29/// std::string a[2];30/// std::string b;31/// b = a[0];32/// b = "this string won't match";33/// \endcode34AST_MATCHER(Expr, isLValue) { return Node.getValueKind() == VK_LValue; }35 36} // namespace37 38ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name,39 ClangTidyContext *Context)40 : ClangTidyCheck(Name, Context),41 Inserter(Options.getLocalOrGlobal("IncludeStyle",42 utils::IncludeSorter::IS_LLVM),43 areDiagsSelfContained()) {}44 45void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {46 Options.store(Opts, "IncludeStyle", Inserter.getStyle());47}48 49void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {50 auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isInStdNamespace());51 auto AutoPtrType = hasCanonicalType(recordType(hasDeclaration(AutoPtrDecl)));52 53 // std::auto_ptr<int> a;54 // ^~~~~~~~~~~~~55 //56 // typedef std::auto_ptr<int> int_ptr_t;57 // ^~~~~~~~~~~~~58 //59 // std::auto_ptr<int> fn(std::auto_ptr<int>);60 // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~61 Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType))).bind(AutoPtrTokenId),62 this);63 64 // using std::auto_ptr;65 // ^~~~~~~~~~~~~~~~~~~66 Finder->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(namedDecl(67 hasName("auto_ptr"), isInStdNamespace()))))68 .bind(AutoPtrTokenId),69 this);70 71 // Find ownership transfers via copy construction and assignment.72 // AutoPtrOwnershipTransferId is bound to the part that has to be wrapped73 // into std::move().74 // std::auto_ptr<int> i, j;75 // i = j;76 // ~~~~^77 auto MovableArgumentMatcher =78 expr(isLValue(), hasType(AutoPtrType)).bind(AutoPtrOwnershipTransferId);79 80 Finder->addMatcher(81 cxxOperatorCallExpr(hasOverloadedOperatorName("="),82 callee(cxxMethodDecl(ofClass(AutoPtrDecl))),83 hasArgument(1, MovableArgumentMatcher)),84 this);85 Finder->addMatcher(86 traverse(TK_AsIs,87 cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1),88 hasArgument(0, MovableArgumentMatcher))),89 this);90}91 92void ReplaceAutoPtrCheck::registerPPCallbacks(const SourceManager &SM,93 Preprocessor *PP,94 Preprocessor *ModuleExpanderPP) {95 Inserter.registerPreprocessor(PP);96}97 98void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {99 const SourceManager &SM = *Result.SourceManager;100 if (const auto *E =101 Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) {102 const CharSourceRange Range = Lexer::makeFileCharRange(103 CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions());104 105 if (Range.isInvalid())106 return;107 108 auto Diag = diag(Range.getBegin(), "use std::move to transfer ownership")109 << FixItHint::CreateInsertion(Range.getBegin(), "std::move(")110 << FixItHint::CreateInsertion(Range.getEnd(), ")")111 << Inserter.createMainFileIncludeInsertion("<utility>");112 113 return;114 }115 116 SourceLocation AutoPtrLoc;117 if (const auto *PTL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {118 auto TL = *PTL;119 if (auto QTL = TL.getAs<QualifiedTypeLoc>())120 TL = QTL.getUnqualifiedLoc();121 // std::auto_ptr<int> i;122 // ^123 if (auto Loc = TL.getAs<TemplateSpecializationTypeLoc>())124 AutoPtrLoc = Loc.getTemplateNameLoc();125 } else if (const auto *D =126 Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {127 // using std::auto_ptr;128 // ^129 AutoPtrLoc = D->getNameInfo().getBeginLoc();130 } else {131 llvm_unreachable("Bad Callback. No node provided.");132 }133 134 if (AutoPtrLoc.isMacroID())135 AutoPtrLoc = SM.getSpellingLoc(AutoPtrLoc);136 137 // Ensure that only the 'auto_ptr' token is replaced and not the template138 // aliases.139 if (StringRef(SM.getCharacterData(AutoPtrLoc), strlen("auto_ptr")) !=140 "auto_ptr")141 return;142 143 const SourceLocation EndLoc =144 AutoPtrLoc.getLocWithOffset(strlen("auto_ptr") - 1);145 diag(AutoPtrLoc, "auto_ptr is deprecated, use unique_ptr instead")146 << FixItHint::CreateReplacement(SourceRange(AutoPtrLoc, EndLoc),147 "unique_ptr");148}149 150} // namespace clang::tidy::modernize151