1 //===--- SmartPtrArrayMismatchCheck.cpp - clang-tidy ----------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "SmartPtrArrayMismatchCheck.h"
10 #include "../utils/ASTUtils.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Lex/Lexer.h"
14 using namespace clang::ast_matchers
;
16 namespace clang::tidy::bugprone
{
20 constexpr char ConstructExprN
[] = "found_construct_expr";
21 constexpr char NewExprN
[] = "found_new_expr";
22 constexpr char ConstructorN
[] = "found_constructor";
24 bool isInSingleDeclStmt(const DeclaratorDecl
*D
) {
25 const DynTypedNodeList Parents
=
26 D
->getASTContext().getParentMapContext().getParents(*D
);
27 for (const DynTypedNode
&PNode
: Parents
)
28 if (const auto *PDecl
= PNode
.get
<DeclStmt
>())
29 return PDecl
->isSingleDecl();
33 const DeclaratorDecl
*getConstructedVarOrField(const Expr
*FoundConstructExpr
,
35 const DynTypedNodeList ConstructParents
=
36 Ctx
.getParentMapContext().getParents(*FoundConstructExpr
);
37 if (ConstructParents
.size() != 1)
39 const auto *ParentDecl
= ConstructParents
.begin()->get
<DeclaratorDecl
>();
40 if (isa_and_nonnull
<VarDecl
, FieldDecl
>(ParentDecl
))
48 const char SmartPtrArrayMismatchCheck::PointerTypeN
[] = "pointer_type";
50 SmartPtrArrayMismatchCheck::SmartPtrArrayMismatchCheck(
51 StringRef Name
, ClangTidyContext
*Context
, StringRef SmartPointerName
)
52 : ClangTidyCheck(Name
, Context
), SmartPointerName(SmartPointerName
) {}
54 void SmartPtrArrayMismatchCheck::storeOptions(
55 ClangTidyOptions::OptionMap
&Opts
) {}
57 void SmartPtrArrayMismatchCheck::registerMatchers(MatchFinder
*Finder
) {
58 // For both shared and unique pointers, we need to find constructor with
59 // exactly one parameter that has the pointer type. Other constructors are
60 // not applicable for this check.
61 auto FindConstructor
=
62 cxxConstructorDecl(ofClass(getSmartPointerClassMatcher()),
63 parameterCountIs(1), isExplicit())
65 auto FindConstructExpr
=
67 hasDeclaration(FindConstructor
), argumentCountIs(1),
70 hasType(hasCanonicalType(pointerType(
71 pointee(equalsBoundNode(PointerTypeN
))))))
73 .bind(ConstructExprN
);
74 Finder
->addMatcher(FindConstructExpr
, this);
77 void SmartPtrArrayMismatchCheck::check(const MatchFinder::MatchResult
&Result
) {
78 const auto *FoundNewExpr
= Result
.Nodes
.getNodeAs
<CXXNewExpr
>(NewExprN
);
79 const auto *FoundConstructExpr
=
80 Result
.Nodes
.getNodeAs
<CXXConstructExpr
>(ConstructExprN
);
81 const auto *FoundConstructorDecl
=
82 Result
.Nodes
.getNodeAs
<CXXConstructorDecl
>(ConstructorN
);
84 ASTContext
&Ctx
= FoundConstructorDecl
->getASTContext();
85 const DeclaratorDecl
*VarOrField
=
86 getConstructedVarOrField(FoundConstructExpr
, Ctx
);
88 auto D
= diag(FoundNewExpr
->getBeginLoc(),
89 "%0 pointer to non-array is initialized with array")
91 D
<< FoundNewExpr
->getSourceRange();
94 auto TSTypeLoc
= VarOrField
->getTypeSourceInfo()
96 .getAsAdjusted
<clang::TemplateSpecializationTypeLoc
>();
97 assert(TSTypeLoc
.getNumArgs() >= 1 &&
98 "Matched type should have at least 1 template argument.");
100 SourceRange TemplateArgumentRange
= TSTypeLoc
.getArgLoc(0)
104 D
<< TemplateArgumentRange
;
106 if (isInSingleDeclStmt(VarOrField
)) {
107 const SourceManager
&SM
= Ctx
.getSourceManager();
108 if (!utils::rangeCanBeFixed(TemplateArgumentRange
, &SM
))
111 SourceLocation InsertLoc
= Lexer::getLocForEndOfToken(
112 TemplateArgumentRange
.getEnd(), 0, SM
, Ctx
.getLangOpts());
113 D
<< FixItHint::CreateInsertion(InsertLoc
, "[]");
118 } // namespace clang::tidy::bugprone