clang-tools 22.0.0git
SmartPtrArrayMismatchCheck.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8
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
18static constexpr char ConstructExprN[] = "found_construct_expr";
19static constexpr char NewExprN[] = "found_new_expr";
20static constexpr char ConstructorN[] = "found_constructor";
21
22static bool isInSingleDeclStmt(const DeclaratorDecl *D) {
23 const DynTypedNodeList Parents =
24 D->getASTContext().getParentMapContext().getParents(*D);
25 for (const DynTypedNode &PNode : Parents)
26 if (const auto *PDecl = PNode.get<DeclStmt>())
27 return PDecl->isSingleDecl();
28 return false;
29}
30
31static const DeclaratorDecl *
32getConstructedVarOrField(const Expr *FoundConstructExpr, ASTContext &Ctx) {
33 const DynTypedNodeList ConstructParents =
34 Ctx.getParentMapContext().getParents(*FoundConstructExpr);
35 if (ConstructParents.size() != 1)
36 return nullptr;
37 const auto *ParentDecl = ConstructParents.begin()->get<DeclaratorDecl>();
38 if (isa_and_nonnull<VarDecl, FieldDecl>(ParentDecl))
39 return ParentDecl;
40
41 return nullptr;
42}
43
44const char SmartPtrArrayMismatchCheck::PointerTypeN[] = "pointer_type";
45
47 StringRef Name, ClangTidyContext *Context, StringRef SmartPointerName)
48 : ClangTidyCheck(Name, Context), SmartPointerName(SmartPointerName) {}
49
52
54 // For both shared and unique pointers, we need to find constructor with
55 // exactly one parameter that has the pointer type. Other constructors are
56 // not applicable for this check.
57 auto FindConstructor =
58 cxxConstructorDecl(ofClass(getSmartPointerClassMatcher()),
59 parameterCountIs(1), isExplicit())
60 .bind(ConstructorN);
61 auto FindConstructExpr =
62 cxxConstructExpr(
63 hasDeclaration(FindConstructor), argumentCountIs(1),
64 hasArgument(0,
65 cxxNewExpr(isArray(),
66 hasType(hasCanonicalType(pointerType(
67 pointee(equalsBoundNode(PointerTypeN))))))
68 .bind(NewExprN)))
69 .bind(ConstructExprN);
70 Finder->addMatcher(FindConstructExpr, this);
71}
72
73void SmartPtrArrayMismatchCheck::check(const MatchFinder::MatchResult &Result) {
74 const auto *FoundNewExpr = Result.Nodes.getNodeAs<CXXNewExpr>(NewExprN);
75 const auto *FoundConstructExpr =
76 Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructExprN);
77 const auto *FoundConstructorDecl =
78 Result.Nodes.getNodeAs<CXXConstructorDecl>(ConstructorN);
79
80 ASTContext &Ctx = FoundConstructorDecl->getASTContext();
81 const DeclaratorDecl *VarOrField =
82 getConstructedVarOrField(FoundConstructExpr, Ctx);
83
84 auto D = diag(FoundNewExpr->getBeginLoc(),
85 "%0 pointer to non-array is initialized with array")
86 << SmartPointerName;
87 D << FoundNewExpr->getSourceRange();
88
89 if (VarOrField) {
90 auto TSTypeLoc = VarOrField->getTypeSourceInfo()
91 ->getTypeLoc()
92 .getAsAdjusted<clang::TemplateSpecializationTypeLoc>();
93 assert(TSTypeLoc.getNumArgs() >= 1 &&
94 "Matched type should have at least 1 template argument.");
95
96 const SourceRange TemplateArgumentRange = TSTypeLoc.getArgLoc(0)
97 .getTypeSourceInfo()
98 ->getTypeLoc()
99 .getSourceRange();
100 D << TemplateArgumentRange;
101
102 if (isInSingleDeclStmt(VarOrField)) {
103 const SourceManager &SM = Ctx.getSourceManager();
104 if (!utils::rangeCanBeFixed(TemplateArgumentRange, &SM))
105 return;
106
107 const SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
108 TemplateArgumentRange.getEnd(), 0, SM, Ctx.getLangOpts());
109 D << FixItHint::CreateInsertion(InsertLoc, "[]");
110 }
111 }
112}
113
114} // namespace clang::tidy::bugprone
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
virtual SmartPtrClassMatcher getSmartPointerClassMatcher() const =0
Returns matcher that match with different smart pointer classes.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
SmartPtrArrayMismatchCheck(StringRef Name, ClangTidyContext *Context, StringRef SmartPointerName)
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
static bool isInSingleDeclStmt(const DeclaratorDecl *D)
static constexpr char ConstructExprN[]
static constexpr char NewExprN[]
static const DeclaratorDecl * getConstructedVarOrField(const Expr *FoundConstructExpr, ASTContext &Ctx)
static constexpr char ConstructorN[]
bool rangeCanBeFixed(SourceRange Range, const SourceManager *SM)
Definition ASTUtils.cpp:86
llvm::StringMap< ClangTidyValue > OptionMap