brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.4 KiB · af478b1 Raw
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