|  | //===--- SmartPtrArrayMismatchCheck.cpp - clang-tidy ----------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "SmartPtrArrayMismatchCheck.h" | 
|  | #include "../utils/ASTUtils.h" | 
|  | #include "clang/ASTMatchers/ASTMatchFinder.h" | 
|  | #include "clang/Lex/Lexer.h" | 
|  |  | 
|  | using namespace clang::ast_matchers; | 
|  |  | 
|  | namespace clang::tidy::bugprone { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | constexpr char ConstructExprN[] = "found_construct_expr"; | 
|  | constexpr char NewExprN[] = "found_new_expr"; | 
|  | constexpr char ConstructorN[] = "found_constructor"; | 
|  |  | 
|  | bool isInSingleDeclStmt(const DeclaratorDecl *D) { | 
|  | const DynTypedNodeList Parents = | 
|  | D->getASTContext().getParentMapContext().getParents(*D); | 
|  | for (const DynTypedNode &PNode : Parents) | 
|  | if (const auto *PDecl = PNode.get<DeclStmt>()) | 
|  | return PDecl->isSingleDecl(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const DeclaratorDecl *getConstructedVarOrField(const Expr *FoundConstructExpr, | 
|  | ASTContext &Ctx) { | 
|  | const DynTypedNodeList ConstructParents = | 
|  | Ctx.getParentMapContext().getParents(*FoundConstructExpr); | 
|  | if (ConstructParents.size() != 1) | 
|  | return nullptr; | 
|  | const auto *ParentDecl = ConstructParents.begin()->get<DeclaratorDecl>(); | 
|  | if (isa_and_nonnull<VarDecl, FieldDecl>(ParentDecl)) | 
|  | return ParentDecl; | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | const char SmartPtrArrayMismatchCheck::PointerTypeN[] = "pointer_type"; | 
|  |  | 
|  | SmartPtrArrayMismatchCheck::SmartPtrArrayMismatchCheck( | 
|  | StringRef Name, ClangTidyContext *Context, StringRef SmartPointerName) | 
|  | : ClangTidyCheck(Name, Context), SmartPointerName(SmartPointerName) {} | 
|  |  | 
|  | void SmartPtrArrayMismatchCheck::storeOptions( | 
|  | ClangTidyOptions::OptionMap &Opts) {} | 
|  |  | 
|  | void SmartPtrArrayMismatchCheck::registerMatchers(MatchFinder *Finder) { | 
|  | // For both shared and unique pointers, we need to find constructor with | 
|  | // exactly one parameter that has the pointer type. Other constructors are | 
|  | // not applicable for this check. | 
|  | auto FindConstructor = | 
|  | cxxConstructorDecl(ofClass(getSmartPointerClassMatcher()), | 
|  | parameterCountIs(1), isExplicit()) | 
|  | .bind(ConstructorN); | 
|  | auto FindConstructExpr = | 
|  | cxxConstructExpr( | 
|  | hasDeclaration(FindConstructor), argumentCountIs(1), | 
|  | hasArgument(0, | 
|  | cxxNewExpr(isArray(), | 
|  | hasType(hasCanonicalType(pointerType( | 
|  | pointee(equalsBoundNode(PointerTypeN)))))) | 
|  | .bind(NewExprN))) | 
|  | .bind(ConstructExprN); | 
|  | Finder->addMatcher(FindConstructExpr, this); | 
|  | } | 
|  |  | 
|  | void SmartPtrArrayMismatchCheck::check(const MatchFinder::MatchResult &Result) { | 
|  | const auto *FoundNewExpr = Result.Nodes.getNodeAs<CXXNewExpr>(NewExprN); | 
|  | const auto *FoundConstructExpr = | 
|  | Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructExprN); | 
|  | const auto *FoundConstructorDecl = | 
|  | Result.Nodes.getNodeAs<CXXConstructorDecl>(ConstructorN); | 
|  |  | 
|  | ASTContext &Ctx = FoundConstructorDecl->getASTContext(); | 
|  | const DeclaratorDecl *VarOrField = | 
|  | getConstructedVarOrField(FoundConstructExpr, Ctx); | 
|  |  | 
|  | auto D = diag(FoundNewExpr->getBeginLoc(), | 
|  | "%0 pointer to non-array is initialized with array") | 
|  | << SmartPointerName; | 
|  | D << FoundNewExpr->getSourceRange(); | 
|  |  | 
|  | if (VarOrField) { | 
|  | auto TSTypeLoc = VarOrField->getTypeSourceInfo() | 
|  | ->getTypeLoc() | 
|  | .getAsAdjusted<clang::TemplateSpecializationTypeLoc>(); | 
|  | assert(TSTypeLoc.getNumArgs() >= 1 && | 
|  | "Matched type should have at least 1 template argument."); | 
|  |  | 
|  | SourceRange TemplateArgumentRange = TSTypeLoc.getArgLoc(0) | 
|  | .getTypeSourceInfo() | 
|  | ->getTypeLoc() | 
|  | .getSourceRange(); | 
|  | D << TemplateArgumentRange; | 
|  |  | 
|  | if (isInSingleDeclStmt(VarOrField)) { | 
|  | const SourceManager &SM = Ctx.getSourceManager(); | 
|  | if (!utils::rangeCanBeFixed(TemplateArgumentRange, &SM)) | 
|  | return; | 
|  |  | 
|  | SourceLocation InsertLoc = Lexer::getLocForEndOfToken( | 
|  | TemplateArgumentRange.getEnd(), 0, SM, Ctx.getLangOpts()); | 
|  | D << FixItHint::CreateInsertion(InsertLoc, "[]"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | } // namespace clang::tidy::bugprone |