9 #include "../utils/TypeTraits.h"
11 #include "clang/Frontend/CompilerInstance.h"
12 #include "clang/Lex/Lexer.h"
13 #include "clang/Lex/Preprocessor.h"
23 constexpr
char ConstructorCall[] =
"constructorCall";
24 constexpr
char ResetCall[] =
"resetCall";
25 constexpr
char NewExpression[] =
"newExpression";
27 std::string getNewExprName(
const CXXNewExpr *NewExpr,
const SourceManager &SM,
28 const LangOptions &Lang) {
30 CharSourceRange::getTokenRange(
31 NewExpr->getAllocatedTypeSourceInfo()->getTypeLoc().getSourceRange()),
33 if (NewExpr->isArray()) {
34 return (WrittenName +
"[]").str();
36 return WrittenName.str();
41 const char MakeSmartPtrCheck::PointerType[] =
"pointerType";
44 StringRef MakeSmartPtrFunctionName)
46 Inserter(Options.getLocalOrGlobal(
"IncludeStyle",
47 utils::IncludeSorter::IS_LLVM),
48 areDiagsSelfContained()),
49 MakeSmartPtrFunctionHeader(
50 Options.get(
"MakeSmartPtrFunctionHeader",
"<memory>")),
51 MakeSmartPtrFunctionName(
52 Options.get(
"MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
53 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true)),
54 IgnoreDefaultInitialization(
55 Options.get(
"IgnoreDefaultInitialization", true)) {}
59 Options.
store(Opts,
"MakeSmartPtrFunctionHeader", MakeSmartPtrFunctionHeader);
60 Options.
store(Opts,
"MakeSmartPtrFunction", MakeSmartPtrFunctionName);
63 IgnoreDefaultInitialization);
73 Preprocessor *ModuleExpanderPP) {
80 auto CanCallCtor = unless(has(ignoringImpCasts(
81 cxxConstructExpr(hasDeclaration(decl(unless(
isPublic())))))));
83 auto IsPlacement = hasAnyPlacementArg(anything());
88 cxxBindTemporaryExpr(has(ignoringParenImpCasts(
92 0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
94 CanCallCtor, unless(IsPlacement))
95 .bind(NewExpression)),
96 unless(isInTemplateInstantiation()))
97 .bind(ConstructorCall))))),
104 callee(cxxMethodDecl(hasName(
"reset"))),
105 hasArgument(0, cxxNewExpr(CanCallCtor, unless(IsPlacement))
106 .bind(NewExpression)),
107 unless(isInTemplateInstantiation()))
117 SourceManager &SM = *Result.SourceManager;
118 const auto *Construct =
119 Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall);
120 const auto *Reset = Result.Nodes.getNodeAs<CXXMemberCallExpr>(ResetCall);
122 const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression);
125 if (New->getType()->getPointeeType()->getContainedAutoType())
136 bool Initializes = New->hasInitializer() ||
138 New->getAllocatedType(), *Result.Context);
139 if (!Initializes && IgnoreDefaultInitialization)
142 checkConstruct(SM, Result.Context, Construct,
Type, New);
144 checkReset(SM, Result.Context, Reset, New);
147 void MakeSmartPtrCheck::checkConstruct(SourceManager &SM, ASTContext *
Ctx,
148 const CXXConstructExpr *Construct,
149 const QualType *Type,
150 const CXXNewExpr *New) {
151 SourceLocation ConstructCallStart = Construct->getExprLoc();
152 bool InMacro = ConstructCallStart.isMacroID();
154 if (InMacro && IgnoreMacros) {
158 bool Invalid =
false;
160 CharSourceRange::getCharRange(
161 ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
166 auto Diag =
diag(ConstructCallStart,
"use %0 instead")
167 << MakeSmartPtrFunctionName;
174 if (!replaceNew(Diag, New, SM,
Ctx)) {
179 size_t LAngle = ExprStr.find(
'<');
180 SourceLocation ConstructCallEnd;
181 if (LAngle == StringRef::npos) {
184 ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
185 Diag << FixItHint::CreateInsertion(
186 ConstructCallEnd,
"<" + getNewExprName(New, SM,
getLangOpts()) +
">");
188 ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
191 Diag << FixItHint::CreateReplacement(
192 CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
193 MakeSmartPtrFunctionName);
197 if (Construct->isListInitialization()) {
198 SourceRange BraceRange = Construct->getParenOrBraceRange();
199 Diag << FixItHint::CreateReplacement(
200 CharSourceRange::getCharRange(
201 BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)),
203 Diag << FixItHint::CreateReplacement(
204 CharSourceRange::getCharRange(BraceRange.getEnd(),
205 BraceRange.getEnd().getLocWithOffset(1)),
209 insertHeader(Diag, SM.getFileID(ConstructCallStart));
212 void MakeSmartPtrCheck::checkReset(SourceManager &SM, ASTContext *
Ctx,
213 const CXXMemberCallExpr *Reset,
214 const CXXNewExpr *New) {
215 const auto *Expr = cast<MemberExpr>(Reset->getCallee());
216 SourceLocation OperatorLoc = Expr->getOperatorLoc();
217 SourceLocation ResetCallStart = Reset->getExprLoc();
218 SourceLocation ExprStart = Expr->getBeginLoc();
219 SourceLocation ExprEnd =
220 Lexer::getLocForEndOfToken(Expr->getEndLoc(), 0, SM,
getLangOpts());
222 bool InMacro = ExprStart.isMacroID();
224 if (InMacro && IgnoreMacros) {
231 if (OperatorLoc.isInvalid()) {
235 auto Diag =
diag(ResetCallStart,
"use %0 instead")
236 << MakeSmartPtrFunctionName;
243 if (!replaceNew(Diag, New, SM,
Ctx)) {
247 Diag << FixItHint::CreateReplacement(
248 CharSourceRange::getCharRange(OperatorLoc, ExprEnd),
249 (llvm::Twine(
" = ") + MakeSmartPtrFunctionName +
"<" +
254 Diag << FixItHint::CreateInsertion(ExprStart,
"*");
256 insertHeader(Diag, SM.getFileID(OperatorLoc));
259 bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
260 const CXXNewExpr *New, SourceManager &SM,
262 auto SkipParensParents = [&](
const Expr *
E) {
263 TraversalKindScope RAII(*
Ctx, TK_AsIs);
265 for (
const Expr *OldE =
nullptr;
E != OldE;) {
267 for (
const auto &Node :
Ctx->getParents(*
E)) {
268 if (
const Expr *
Parent = Node.get<ParenExpr>()) {
277 SourceRange NewRange = SkipParensParents(New)->getSourceRange();
278 SourceLocation NewStart = NewRange.getBegin();
279 SourceLocation NewEnd = NewRange.getEnd();
282 if (NewStart.isInvalid() || NewEnd.isInvalid())
285 std::string ArraySizeExpr;
286 if (
const auto *ArraySize = New->getArraySize().value_or(
nullptr)) {
288 ArraySize->getSourceRange()),
298 auto HasListIntializedArgument = [](
const CXXConstructExpr *
CE) {
299 for (
const auto *Arg :
CE->arguments()) {
300 Arg = Arg->IgnoreImplicit();
302 if (isa<CXXStdInitializerListExpr>(Arg) || isa<InitListExpr>(Arg))
306 if (
const auto *CEArg = dyn_cast<CXXConstructExpr>(Arg)) {
310 if (CEArg->isElidable()) {
311 if (
const auto *TempExp = CEArg->getArg(0)) {
312 if (
const auto *UnwrappedCE =
313 dyn_cast<CXXConstructExpr>(TempExp->IgnoreImplicit()))
317 if (CEArg->isStdInitListInitialization())
323 switch (New->getInitializationStyle()) {
324 case CXXNewExpr::NoInit: {
325 if (ArraySizeExpr.empty()) {
326 Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
330 Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
335 case CXXNewExpr::CallInit: {
353 if (
const auto *
CE = New->getConstructExpr()) {
354 if (HasListIntializedArgument(
CE))
357 if (ArraySizeExpr.empty()) {
358 SourceRange InitRange = New->getDirectInitRange();
359 Diag << FixItHint::CreateRemoval(
360 SourceRange(NewStart, InitRange.getBegin()));
361 Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
367 Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
372 case CXXNewExpr::ListInit: {
374 SourceRange InitRange;
375 if (
const auto *NewConstruct = New->getConstructExpr()) {
376 if (NewConstruct->isStdInitListInitialization() ||
377 HasListIntializedArgument(NewConstruct)) {
400 InitRange = SourceRange(
401 NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1),
402 NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1));
413 if (
const CXXRecordDecl *RD = New->getType()->getPointeeCXXRecordDecl()) {
414 if (llvm::find_if(RD->ctors(), [](
const CXXConstructorDecl *Ctor) {
415 return Ctor->isCopyOrMoveConstructor() &&
416 (Ctor->isDeleted() || Ctor->getAccess() == AS_private);
417 }) != RD->ctor_end()) {
421 InitRange = SourceRange(
422 New->getAllocatedTypeSourceInfo()->getTypeLoc().getBeginLoc(),
423 New->getInitializer()->getSourceRange().getEnd());
425 Diag << FixItHint::CreateRemoval(
426 CharSourceRange::getCharRange(NewStart, InitRange.getBegin()));
427 Diag << FixItHint::CreateRemoval(
428 SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
435 void MakeSmartPtrCheck::insertHeader(DiagnosticBuilder &Diag, FileID FD) {
436 if (MakeSmartPtrFunctionHeader.empty()) {