brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.6 KiB · 00082c7 Raw
130 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 "BufferDerefCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "clang/Tooling/FixIt.h"13 14using namespace clang::ast_matchers;15 16namespace clang::tidy::mpi {17 18void BufferDerefCheck::registerMatchers(MatchFinder *Finder) {19  Finder->addMatcher(callExpr().bind("CE"), this);20}21 22void BufferDerefCheck::check(const MatchFinder::MatchResult &Result) {23  const auto *CE = Result.Nodes.getNodeAs<CallExpr>("CE");24  if (!CE->getDirectCallee())25    return;26 27  if (!FuncClassifier)28    FuncClassifier.emplace(*Result.Context);29 30  const IdentifierInfo *Identifier = CE->getDirectCallee()->getIdentifier();31  if (!Identifier || !FuncClassifier->isMPIType(Identifier))32    return;33 34  // These containers are used, to capture the type and expression of a buffer.35  SmallVector<const Type *, 1> BufferTypes;36  SmallVector<const Expr *, 1> BufferExprs;37 38  // Adds the type and expression of a buffer that is used in the MPI call39  // expression to the captured containers.40  auto AddBuffer = [&CE, &Result, &BufferTypes,41                    &BufferExprs](const size_t BufferIdx) {42    // Skip null pointer constants and in place 'operators'.43    if (CE->getArg(BufferIdx)->isNullPointerConstant(44            *Result.Context, Expr::NPC_ValueDependentIsNull) ||45        tooling::fixit::getText(*CE->getArg(BufferIdx), *Result.Context) ==46            "MPI_IN_PLACE")47      return;48 49    const Expr *ArgExpr = CE->getArg(BufferIdx);50    if (!ArgExpr)51      return;52    const Type *ArgType = ArgExpr->IgnoreImpCasts()->getType().getTypePtr();53    if (!ArgType)54      return;55    BufferExprs.push_back(ArgExpr);56    BufferTypes.push_back(ArgType);57  };58 59  // Collect buffer types and argument expressions for all buffers used in the60  // MPI call expression. The number passed to the lambda corresponds to the61  // argument index of the currently verified MPI function call.62  if (FuncClassifier->isPointToPointType(Identifier)) {63    AddBuffer(0);64  } else if (FuncClassifier->isCollectiveType(Identifier)) {65    if (FuncClassifier->isReduceType(Identifier)) {66      AddBuffer(0);67      AddBuffer(1);68    } else if (FuncClassifier->isScatterType(Identifier) ||69               FuncClassifier->isGatherType(Identifier) ||70               FuncClassifier->isAlltoallType(Identifier)) {71      AddBuffer(0);72      AddBuffer(3);73    } else if (FuncClassifier->isBcastType(Identifier)) {74      AddBuffer(0);75    }76  }77 78  checkBuffers(BufferTypes, BufferExprs);79}80 81void BufferDerefCheck::checkBuffers(ArrayRef<const Type *> BufferTypes,82                                    ArrayRef<const Expr *> BufferExprs) {83  for (size_t I = 0; I < BufferTypes.size(); ++I) {84    unsigned IndirectionCount = 0;85    const Type *BufferType = BufferTypes[I];86    llvm::SmallVector<IndirectionType, 1> Indirections;87 88    // Capture the depth and types of indirections for the passed buffer.89    while (true) {90      if (BufferType->isPointerType()) {91        BufferType = BufferType->getPointeeType().getTypePtr();92        Indirections.push_back(IndirectionType::Pointer);93      } else if (BufferType->isArrayType()) {94        BufferType = BufferType->getArrayElementTypeNoTypeQual();95        Indirections.push_back(IndirectionType::Array);96      } else {97        break;98      }99      ++IndirectionCount;100    }101 102    if (IndirectionCount > 1) {103      // Referencing an array with '&' is valid, as this also points to the104      // beginning of the array.105      if (IndirectionCount == 2 &&106          Indirections[0] == IndirectionType::Pointer &&107          Indirections[1] == IndirectionType::Array)108        return;109 110      // Build the indirection description in reverse order of discovery.111      std::string IndirectionDesc;112      for (auto It = Indirections.rbegin(); It != Indirections.rend(); ++It) {113        if (!IndirectionDesc.empty())114          IndirectionDesc += "->";115        if (*It == IndirectionType::Pointer) {116          IndirectionDesc += "pointer";117        } else {118          IndirectionDesc += "array";119        }120      }121 122      const auto Loc = BufferExprs[I]->getSourceRange().getBegin();123      diag(Loc, "buffer is insufficiently dereferenced: %0") << IndirectionDesc;124    }125  }126}127 128void BufferDerefCheck::onEndOfTranslationUnit() { FuncClassifier.reset(); }129} // namespace clang::tidy::mpi130