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