10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/RecursiveASTVisitor.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Frontend/CompilerInstance.h"
15 #include "clang/Lex/Lexer.h"
16 #include "clang/Lex/Preprocessor.h"
41 for (
const CXXConstructorDecl *Ctor : Node.ctors()) {
42 if (Ctor->isMoveConstructor() && !Ctor->isDeleted())
50 return lValueReferenceType(
51 pointee(unless(templateSpecializationType()), isConstQualified()));
55 return qualType(unless(anyOf(referenceType(), isConstQualified())));
62 const ParmVarDecl *ParamDecl) {
67 class ExactlyOneUsageVisitor
68 :
public RecursiveASTVisitor<ExactlyOneUsageVisitor> {
69 friend class RecursiveASTVisitor<ExactlyOneUsageVisitor>;
72 ExactlyOneUsageVisitor(
const ParmVarDecl *ParamDecl)
73 : ParamDecl(ParamDecl) {}
78 bool hasExactlyOneUsageIn(
const CXXConstructorDecl *Ctor) {
80 TraverseDecl(
const_cast<CXXConstructorDecl *
>(Ctor));
88 bool VisitDeclRefExpr(DeclRefExpr *
D) {
89 if (
const ParmVarDecl *To = dyn_cast<ParmVarDecl>(
D->getDecl())) {
90 if (To == ParamDecl) {
101 const ParmVarDecl *ParamDecl;
105 return ExactlyOneUsageVisitor(ParamDecl).hasExactlyOneUsageIn(Ctor);
132 const ParmVarDecl *Param) {
133 if (!Param->getType().getCanonicalType()->isLValueReferenceType()) {
137 const int ParamIdx = Param->getFunctionScopeIndex();
138 const CXXRecordDecl *
Record = Ctor->getParent();
142 const auto IsRValueOverload = [&Ctor, ParamIdx](
const CXXConstructorDecl *
C) {
143 if (
C == Ctor ||
C->isDeleted() ||
144 C->getNumParams() != Ctor->getNumParams())
146 for (
int I = 0,
E =
C->getNumParams(); I <
E; ++I) {
147 const clang::QualType CandidateParamType =
148 C->parameters()[I]->getType().getCanonicalType();
149 const clang::QualType CtorParamType =
150 Ctor->parameters()[I]->getType().getCanonicalType();
151 const bool IsLValueRValuePair =
152 CtorParamType->isLValueReferenceType() &&
153 CandidateParamType->isRValueReferenceType() &&
154 CandidateParamType->getPointeeType()->getUnqualifiedDesugaredType() ==
155 CtorParamType->getPointeeType()->getUnqualifiedDesugaredType();
158 if (!IsLValueRValuePair)
162 if (!(CandidateParamType == CtorParamType || IsLValueRValuePair))
179 static SmallVector<const ParmVarDecl *, 2>
181 const ParmVarDecl *ParamDecl) {
182 SmallVector<const ParmVarDecl *, 2>
Results;
183 unsigned ParamIdx = ParamDecl->getFunctionScopeIndex();
185 for (
const FunctionDecl *Redecl : Ctor->redecls())
186 Results.push_back(Redecl->getParamDecl(ParamIdx));
192 Inserter(Options.getLocalOrGlobal(
"IncludeStyle",
193 utils::IncludeSorter::IS_LLVM),
194 areDiagsSelfContained()),
195 ValuesOnly(Options.get(
"ValuesOnly", false)) {}
207 forEachConstructorInitializer(
209 unless(isBaseInitializer()),
215 withInitializer(cxxConstructExpr(
216 has(ignoringParenImpCasts(declRefExpr(to(
228 hasDeclaration(cxxConstructorDecl(
229 isCopyConstructor(), unless(isDeleted()),
231 cxxRecordDecl(isMoveConstructible())))))))
232 .bind(
"Initializer")))
239 Preprocessor *ModuleExpanderPP) {
244 const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>(
"Ctor");
245 const auto *ParamDecl = Result.Nodes.getNodeAs<ParmVarDecl>(
"Param");
246 const auto *Initializer =
247 Result.Nodes.getNodeAs<CXXCtorInitializer>(
"Initializer");
248 SourceManager &SM = *Result.SourceManager;
257 if (ParamDecl->getType().getNonReferenceType().isTriviallyCopyableType(
265 auto Diag =
diag(ParamDecl->getBeginLoc(),
"pass by value and use std::move");
269 if (ParamDecl->getType()->isLValueReferenceType()) {
272 TypeLoc ParamTL = ParmDecl->getTypeSourceInfo()->getTypeLoc();
273 ReferenceTypeLoc RefTL = ParamTL.getAs<ReferenceTypeLoc>();
274 if (RefTL.isNull()) {
282 TypeLoc ParamTL = ParmDecl->getTypeSourceInfo()->getTypeLoc();
283 ReferenceTypeLoc RefTL = ParamTL.getAs<ReferenceTypeLoc>();
285 TypeLoc ValueTL = RefTL.getPointeeLoc();
286 CharSourceRange TypeRange = CharSourceRange::getTokenRange(
287 ParmDecl->getBeginLoc(), ParamTL.getEndLoc());
288 std::string ValueStr =
290 CharSourceRange::getTokenRange(ValueTL.getSourceRange()), SM,
294 Diag << FixItHint::CreateReplacement(TypeRange, ValueStr);
299 Diag << FixItHint::CreateInsertion(Initializer->getRParenLoc(),
")")
300 << FixItHint::CreateInsertion(
301 Initializer->getLParenLoc().getLocWithOffset(1),
"std::move(")
303 Result.SourceManager->getFileID(Initializer->getSourceLocation()),