123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- //===--- 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
|