1//===--- SmartPtrArrayMismatchCheck.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 "SmartPtrArrayMismatchCheck.h"
10#include "../utils/ASTUtils.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Lex/Lexer.h"
13
14using namespace clang::ast_matchers;
15
16namespace clang::tidy::bugprone {
17
18namespace {
19
20constexpr char ConstructExprN[] = "found_construct_expr";
21constexpr char NewExprN[] = "found_new_expr";
22constexpr char ConstructorN[] = "found_constructor";
23
24bool 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();
30 return false;
31}
32
33const DeclaratorDecl *getConstructedVarOrField(const Expr *FoundConstructExpr,
34 ASTContext &Ctx) {
35 const DynTypedNodeList ConstructParents =
36 Ctx.getParentMapContext().getParents(Node: *FoundConstructExpr);
37 if (ConstructParents.size() != 1)
38 return nullptr;
39 const auto *ParentDecl = ConstructParents.begin()->get<DeclaratorDecl>();
40 if (isa_and_nonnull<VarDecl, FieldDecl>(Val: ParentDecl))
41 return ParentDecl;
42
43 return nullptr;
44}
45
46} // namespace
47
48const char SmartPtrArrayMismatchCheck::PointerTypeN[] = "pointer_type";
49
50SmartPtrArrayMismatchCheck::SmartPtrArrayMismatchCheck(
51 StringRef Name, ClangTidyContext *Context, StringRef SmartPointerName)
52 : ClangTidyCheck(Name, Context), SmartPointerName(SmartPointerName) {}
53
54void SmartPtrArrayMismatchCheck::storeOptions(
55 ClangTidyOptions::OptionMap &Opts) {}
56
57void 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(InnerMatcher: getSmartPointerClassMatcher()),
63 parameterCountIs(N: 1), isExplicit())
64 .bind(ID: ConstructorN);
65 auto FindConstructExpr =
66 cxxConstructExpr(
67 hasDeclaration(InnerMatcher: FindConstructor), argumentCountIs(N: 1),
68 hasArgument(N: 0,
69 InnerMatcher: cxxNewExpr(isArray(),
70 hasType(InnerMatcher: hasCanonicalType(InnerMatcher: pointerType(
71 pointee(equalsBoundNode(ID: PointerTypeN))))))
72 .bind(ID: NewExprN)))
73 .bind(ID: ConstructExprN);
74 Finder->addMatcher(NodeMatch: FindConstructExpr, Action: this);
75}
76
77void SmartPtrArrayMismatchCheck::check(const MatchFinder::MatchResult &Result) {
78 const auto *FoundNewExpr = Result.Nodes.getNodeAs<CXXNewExpr>(ID: NewExprN);
79 const auto *FoundConstructExpr =
80 Result.Nodes.getNodeAs<CXXConstructExpr>(ID: ConstructExprN);
81 const auto *FoundConstructorDecl =
82 Result.Nodes.getNodeAs<CXXConstructorDecl>(ID: ConstructorN);
83
84 ASTContext &Ctx = FoundConstructorDecl->getASTContext();
85 const DeclaratorDecl *VarOrField =
86 getConstructedVarOrField(FoundConstructExpr, Ctx);
87
88 auto D = diag(Loc: FoundNewExpr->getBeginLoc(),
89 Description: "%0 pointer to non-array is initialized with array")
90 << SmartPointerName;
91 D << FoundNewExpr->getSourceRange();
92
93 if (VarOrField) {
94 auto TSTypeLoc = VarOrField->getTypeSourceInfo()
95 ->getTypeLoc()
96 .getAsAdjusted<clang::TemplateSpecializationTypeLoc>();
97 assert(TSTypeLoc.getNumArgs() >= 1 &&
98 "Matched type should have at least 1 template argument.");
99
100 SourceRange TemplateArgumentRange = TSTypeLoc.getArgLoc(0)
101 .getTypeSourceInfo()
102 ->getTypeLoc()
103 .getSourceRange();
104 D << TemplateArgumentRange;
105
106 if (isInSingleDeclStmt(D: VarOrField)) {
107 const SourceManager &SM = Ctx.getSourceManager();
108 if (!utils::rangeCanBeFixed(Range: TemplateArgumentRange, SM: &SM))
109 return;
110
111 SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
112 Loc: TemplateArgumentRange.getEnd(), Offset: 0, SM, LangOpts: Ctx.getLangOpts());
113 D << FixItHint::CreateInsertion(InsertionLoc: InsertLoc, Code: "[]");
114 }
115 }
116}
117
118} // namespace clang::tidy::bugprone
119

source code of clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.cpp