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