115 lines · cpp
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-exception6//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 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 46SmartPtrArrayMismatchCheck::SmartPtrArrayMismatchCheck(47 StringRef Name, ClangTidyContext *Context, StringRef SmartPointerName)48 : ClangTidyCheck(Name, Context), SmartPointerName(SmartPointerName) {}49 50void SmartPtrArrayMismatchCheck::storeOptions(51 ClangTidyOptions::OptionMap &Opts) {}52 53void SmartPtrArrayMismatchCheck::registerMatchers(MatchFinder *Finder) {54 // For both shared and unique pointers, we need to find constructor with55 // exactly one parameter that has the pointer type. Other constructors are56 // 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::bugprone115