Alexander_Droste updated this revision to Diff 34647.
Alexander_Droste marked 2 inline comments as done.
Alexander_Droste added a comment.

- fixed integration test file: tools/clang/test/Analysis/MPIChecker.c
- mocked types, constants, functions from mpi.h
- mocked types from stdint.h
- dropped -I/usr/... from first line


http://reviews.llvm.org/D12761

Files:
  tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
  tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Container.h
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.cpp
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.h
  
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.h
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.h
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.h
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.cpp
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.h
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TypeVisitor.h
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp
  tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.h
  tools/clang/test/Analysis/MPIChecker.c
  tools/clang/unittests/StaticAnalyzer/CMakeLists.txt
  tools/clang/unittests/StaticAnalyzer/MPI-Checker/CMakeLists.txt
  tools/clang/unittests/StaticAnalyzer/MPI-Checker/ContainerTest.cpp
  tools/clang/unittests/StaticAnalyzer/MPI-Checker/UtilityTest.cpp

Index: tools/clang/unittests/StaticAnalyzer/MPI-Checker/UtilityTest.cpp
===================================================================
--- tools/clang/unittests/StaticAnalyzer/MPI-Checker/UtilityTest.cpp
+++ tools/clang/unittests/StaticAnalyzer/MPI-Checker/UtilityTest.cpp
@@ -0,0 +1,12 @@
+#include "gtest/gtest.h"
+#include "Utility.h"
+
+TEST(Utility, split) {
+  auto s = util::split("aaa:bbb", ':');
+  EXPECT_EQ(s[0], "aaa");
+  EXPECT_EQ(s[1], "bbb");
+
+  auto s2 = util::split("aaa,bbb", ',');
+  EXPECT_EQ(s2[0], "aaa");
+  EXPECT_EQ(s2[1], "bbb");
+}
Index: tools/clang/unittests/StaticAnalyzer/MPI-Checker/ContainerTest.cpp
===================================================================
--- tools/clang/unittests/StaticAnalyzer/MPI-Checker/ContainerTest.cpp
+++ tools/clang/unittests/StaticAnalyzer/MPI-Checker/ContainerTest.cpp
@@ -0,0 +1,10 @@
+#include "gtest/gtest.h"
+#include <vector>
+#include "Container.h"
+
+TEST(Container, contains) {
+  std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 8, 9};
+  EXPECT_TRUE(cont::contains(v, 0));
+  EXPECT_TRUE(cont::contains(v, 3));
+  EXPECT_TRUE(cont::contains(v, 9));
+}
Index: tools/clang/unittests/StaticAnalyzer/MPI-Checker/CMakeLists.txt
===================================================================
--- tools/clang/unittests/StaticAnalyzer/MPI-Checker/CMakeLists.txt
+++ tools/clang/unittests/StaticAnalyzer/MPI-Checker/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS Support)
+
+include_directories(
+    ../../../lib/StaticAnalyzer/Checkers/MPI-Checker
+    )
+
+add_clang_unittest(MPI-Checker
+    UtilityTest.cpp
+    ContainerTest.cpp
+    )
+
+target_link_libraries(MPI-Checker
+  clangAST
+  clangBasic
+  clangLex
+  clangParse
+  clangSema
+  clangStaticAnalyzerCheckers)
Index: tools/clang/unittests/StaticAnalyzer/CMakeLists.txt
===================================================================
--- tools/clang/unittests/StaticAnalyzer/CMakeLists.txt
+++ tools/clang/unittests/StaticAnalyzer/CMakeLists.txt
@@ -6,8 +6,10 @@
   AnalyzerOptionsTest.cpp
   )
 
+add_subdirectory(MPI-Checker)
+
 target_link_libraries(StaticAnalysisTests
   clangBasic
   clangAnalysis
-  clangStaticAnalyzerCore 
+  clangStaticAnalyzerCore
   )
Index: tools/clang/test/Analysis/MPIChecker.c
===================================================================
--- tools/clang/test/Analysis/MPIChecker.c
+++ tools/clang/test/Analysis/MPIChecker.c
@@ -0,0 +1,507 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=mpi.MPI-Checker -verify %s
+
+
+// MPI-Checker makes no assumptions about details of an MPI implementation.
+// Typedefs and constants are compared as strings.
+
+#define NULL ((void *)0)
+
+// mock types
+typedef int MPI_Datatype;
+typedef int MPI_Comm;
+typedef int MPI_Request;
+typedef int MPI_Status;
+typedef int MPI_Op;
+
+typedef int int8_t;
+typedef int uint8_t;
+typedef int uint16_t;
+typedef int int64_t;
+
+// mock constants
+#define MPI_COMM_WORLD 0
+#define MPI_CHAR 0
+#define MPI_BYTE 0
+#define MPI_INT 0
+#define MPI_LONG 0
+#define MPI_LONG_DOUBLE 0
+#define MPI_UNSIGNED 0
+#define MPI_INT8_T 0
+#define MPI_UINT8_T 0
+#define MPI_UINT16_T 0
+#define MPI_C_LONG_DOUBLE_COMPLEX 0
+#define MPI_FLOAT 0
+#define MPI_DOUBLE 0
+#define MPI_IN_PLACE 0
+#define MPI_STATUS_IGNORE 0
+#define MPI_STATUSES_IGNORE 0
+#define MPI_SUM 0
+
+// mock functions
+int MPI_Comm_size(MPI_Comm, int *);
+int MPI_Comm_rank(MPI_Comm, int *);
+int MPI_Send(const void *, int, MPI_Datatype, int, int, MPI_Comm);
+int MPI_Recv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Status *);
+int MPI_Isend(const void *, int, MPI_Datatype, int, int, MPI_Comm,
+    MPI_Request *);
+int MPI_Irecv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *);
+int MPI_Wait(MPI_Request *, MPI_Status *);
+int MPI_Waitall(int, MPI_Request[], MPI_Status[]);
+int MPI_Reduce(const void *, void *, int, MPI_Datatype, MPI_Op, int, MPI_Comm);
+int MPI_Ireduce(const void *, void *, int, MPI_Datatype, MPI_Op, int, MPI_Comm,
+    MPI_Request *);
+int MPI_Bcast(void *, int count, MPI_Datatype, int, MPI_Comm);
+
+//integration tests-------------------------------------------------------
+
+void doubleWait() {
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  if (rank > 0) {
+    MPI_Request req[2];
+
+    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 0, MPI_COMM_WORLD, &req[0]);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 0, MPI_COMM_WORLD, &req[1]);
+
+    MPI_Wait(&req[0], MPI_STATUS_IGNORE);
+    MPI_Waitall(2, req, MPI_STATUS_IGNORE); // expected-warning{{Request 'req[0]' is already waited upon by 'MPI_Wait' in line 68.}}
+  }
+}
+
+void doubleWait2() {
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank != 0) {
+    MPI_Request sendReq1, recvReq1;
+
+    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 1, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 1, MPI_COMM_WORLD, &recvReq1);
+    MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+    MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+    MPI_Wait(&recvReq1, MPI_STATUS_IGNORE); // expected-warning{{Request 'recvReq1' is already waited upon by 'MPI_Wait' in line 83.}}
+  }
+}
+
+void doubleWait3() {
+  typedef struct { MPI_Request req; } ReqStruct;
+
+  ReqStruct rs;
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+              &rs.req);
+  MPI_Wait(&rs.req, MPI_STATUS_IGNORE);
+  MPI_Wait(&rs.req, MPI_STATUS_IGNORE); // expected-warning{{Request 'rs.req' is already waited upon by 'MPI_Wait' in line 98.}}
+}
+
+void missingWait() {
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank == 0) {
+  } else {
+    MPI_Request sendReq1, recvReq1;
+
+    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 2, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 2, MPI_COMM_WORLD, &recvReq1);
+    MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+  }
+} // expected-warning{{'MPI_Isend' in line 110, using request 'sendReq1', has no matching wait in the scope of this function.}}
+
+void matchedWait1() {
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank >= 0) {
+    MPI_Request sendReq1, recvReq1;
+    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 3, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 3, MPI_COMM_WORLD, &recvReq1);
+
+    MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+    MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+  }
+} // no error
+
+void matchedWait2() {
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank >= 0) {
+    MPI_Request sendReq1, recvReq1;
+    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 4, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 4, MPI_COMM_WORLD, &recvReq1);
+    MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+    MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+  }
+} // no error
+
+void matchedWait3() {
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank >= 0) {
+    MPI_Request sendReq1, recvReq1;
+    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 5, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 5, MPI_COMM_WORLD, &recvReq1);
+
+    if (rank > 1000) {
+      MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+      MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+    } else {
+      MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+      MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+    }
+  }
+} // no error
+
+void doubleNonblocking() {
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank == 1) {
+  } else {
+    MPI_Request sendReq1;
+
+    MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 6, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 6, MPI_COMM_WORLD, &sendReq1); // expected-warning{{Request 'sendReq1' is already in use by nonblocking call 'MPI_Isend' in line 170.}}
+    MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+  }
+}
+
+void doubleNonblocking2() {
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  MPI_Request req;
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &req);
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &req); // expected-warning{{Request 'req' is already in use by nonblocking call 'MPI_Ireduce' in line 182.}}
+  MPI_Wait(&req, MPI_STATUS_IGNORE);
+}
+
+void doubleNonblocking3() {
+  typedef struct { MPI_Request req; } ReqStruct;
+
+  ReqStruct rs;
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &rs.req);
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &rs.req); // expected-warning{{Request 'rs.req' is already in use by nonblocking call 'MPI_Ireduce' in line 195.}}
+  MPI_Wait(&rs.req, MPI_STATUS_IGNORE);
+}
+
+void missingNonBlocking() {
+  int rank = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  MPI_Request sendReq1;
+  MPI_Wait(&sendReq1, MPI_STATUS_IGNORE); // expected-warning{{Request 'sendReq1' has no matching nonblocking call.}}
+}
+
+void noDoubleRequestUsage() {
+  typedef struct {
+    MPI_Request req;
+    MPI_Request req2;
+  } ReqStruct;
+
+  ReqStruct rs;
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+              &rs.req);
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+              &rs.req2);
+  MPI_Wait(&rs.req, MPI_STATUS_IGNORE);
+  MPI_Wait(&rs.req2, MPI_STATUS_IGNORE);
+}
+
+void noDoubleRequestUsage2() {
+  typedef struct {
+    MPI_Request req[2];
+    MPI_Request req2;
+  } ReqStruct;
+
+  ReqStruct rs;
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+              &rs.req[0]);
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+              &rs.req[1]);
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+              &rs.req2);
+  MPI_Wait(&rs.req[0], MPI_STATUS_IGNORE);
+  MPI_Wait(&rs.req[1], MPI_STATUS_IGNORE);
+  MPI_Wait(&rs.req2, MPI_STATUS_IGNORE);
+}
+
+void nestedRequest() {
+  typedef struct {
+    MPI_Request req[2];
+    MPI_Request req2;
+  } ReqStruct;
+
+  ReqStruct rs;
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+              &rs.req[0]);
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+              &rs.req[1]);
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+              &rs.req2);
+  MPI_Waitall(2, rs.req, MPI_STATUSES_IGNORE);
+  MPI_Wait(&rs.req2, MPI_STATUS_IGNORE);
+}
+
+void singleRequestInWaitall() {
+  MPI_Request r;
+  int rank = 0;
+  double buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+              &r);
+  MPI_Waitall(1, &r, MPI_STATUSES_IGNORE);
+}
+
+void typeMatching1() {
+  double buf = 0;
+  double *bufP = &buf;
+  int rank = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  if (rank == 0) {
+    MPI_Send(&buf, 1, MPI_FLOAT, rank + 1, 7, MPI_COMM_WORLD); // expected-warning{{Buffer type 'double' and specified MPI type 'MPI_FLOAT' do not match.}}
+  } else {
+    MPI_Recv(bufP, 1, MPI_FLOAT, rank - 1, 7, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // expected-warning{{Buffer type 'double' and specified MPI type 'MPI_FLOAT' do not match.}}
+  }
+
+  if (rank == 0) {
+    MPI_Send(&buf, 1, MPI_DOUBLE, rank + 1, 7, MPI_COMM_WORLD);
+  } else {
+    MPI_Recv(bufP, 1, MPI_DOUBLE, rank - 1, 7, MPI_COMM_WORLD,
+             MPI_STATUS_IGNORE);
+  }
+}
+
+void typeMatching2() {
+  int buf = 0;
+  int *bufP = &buf;
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_CHAR, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer type 'int' and specified MPI type 'MPI_CHAR' do not match.}}
+  MPI_Reduce(MPI_IN_PLACE, bufP, 1, MPI_CHAR, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer type 'int' and specified MPI type 'MPI_CHAR' do not match.}}
+
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
+  MPI_Reduce(MPI_IN_PLACE, bufP, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
+}
+
+void typeMatching3() {
+  long double buf = 11;
+  const long double *const bufP = &buf;
+  int rank = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank == 0) {
+    MPI_Send(bufP, 1, MPI_DOUBLE, rank + 1, 8, MPI_COMM_WORLD); // expected-warning{{Buffer type 'long double' and specified MPI type 'MPI_DOUBLE' do not match.}}
+  } else {
+    MPI_Recv(&buf, 1, MPI_DOUBLE, rank - 1, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // expected-warning{{Buffer type 'long double' and specified MPI type 'MPI_DOUBLE' do not match.}}
+  }
+
+  if (rank == 0) {
+    MPI_Send(bufP, 1, MPI_LONG_DOUBLE, rank + 1, 8, MPI_COMM_WORLD);
+  } else {
+    MPI_Recv(&buf, 1, MPI_LONG_DOUBLE, rank - 1, 8, MPI_COMM_WORLD,
+             MPI_STATUS_IGNORE);
+  }
+}
+
+void typeMatching4() {
+  long double _Complex buf = 11;
+  long double _Complex *bufP = &buf;
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer type '_Complex long double' and specified MPI type 'MPI_DOUBLE' do not match.}}
+  MPI_Reduce(MPI_IN_PLACE, bufP, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer type '_Complex long double' and specified MPI type 'MPI_DOUBLE' do not match.}}
+
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_C_LONG_DOUBLE_COMPLEX, MPI_SUM, 0,
+             MPI_COMM_WORLD);
+  MPI_Reduce(MPI_IN_PLACE, bufP, 1, MPI_C_LONG_DOUBLE_COMPLEX, MPI_SUM, 0,
+             MPI_COMM_WORLD);
+}
+
+void typeMatching5() {
+  int64_t buf = 11;
+  const int64_t *const bufP = &buf;
+  int rank = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank == 0) {
+    MPI_Send(bufP, 1, MPI_INT, rank + 1, 9, MPI_COMM_WORLD); // expected-warning{{Buffer type 'int64_t' and specified MPI type 'MPI_INT' do not match.}}
+  } else {
+    MPI_Recv(&buf, 1, MPI_INT, rank - 1, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // expected-warning{{Buffer type 'int64_t' and specified MPI type 'MPI_INT' do not match.}}
+  }
+}
+
+void typeMatching6() {
+  uint8_t buf = 11;
+  uint8_t *bufP = &buf;
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_UNSIGNED, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer type 'uint8_t' and specified MPI type 'MPI_UNSIGNED' do not match.}}
+  MPI_Reduce(MPI_IN_PLACE, bufP, 1, MPI_UNSIGNED, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer type 'uint8_t' and specified MPI type 'MPI_UNSIGNED' do not match.}}
+
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_UINT8_T, MPI_SUM, 0, MPI_COMM_WORLD);
+  MPI_Reduce(MPI_IN_PLACE, bufP, 1, MPI_UINT8_T, MPI_SUM, 0, MPI_COMM_WORLD);
+}
+
+void typeMatching7() {
+  uint8_t buf = 11;
+  const uint8_t *const bufP = &buf;
+
+  int rank = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  if (rank == 0) {
+    MPI_Send(bufP, 1, MPI_UINT16_T, rank + 1, 10, MPI_COMM_WORLD); // expected-warning{{Buffer type 'uint8_t' and specified MPI type 'MPI_UINT16_T' do not match.}}
+  } else {
+    MPI_Recv(&buf, 1, MPI_UINT16_T, rank - 1, 10, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // expected-warning{{Buffer type 'uint8_t' and specified MPI type 'MPI_UINT16_T' do not match.}}
+  }
+
+  if (rank == 0) {
+    MPI_Send(bufP, 1, MPI_UINT8_T, rank + 1, 10, MPI_COMM_WORLD);
+  } else {
+    MPI_Recv(&buf, 1, MPI_UINT8_T, rank - 1, 10, MPI_COMM_WORLD,
+             MPI_STATUS_IGNORE);
+  }
+}
+
+void typeMatching8() {
+  uint8_t buf = 11;
+  uint8_t *bufP = &buf;
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_INT8_T, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer type 'uint8_t' and specified MPI type 'MPI_INT8_T' do not match.}}
+  MPI_Reduce(MPI_IN_PLACE, bufP, 1, MPI_INT8_T, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer type 'uint8_t' and specified MPI type 'MPI_INT8_T' do not match.}}
+
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_UINT8_T, MPI_SUM, 0, MPI_COMM_WORLD);
+  MPI_Reduce(MPI_IN_PLACE, bufP, 1, MPI_UINT8_T, MPI_SUM, 0, MPI_COMM_WORLD);
+}
+
+void typeMatching9() {
+  char buf = 'a';
+  char *bufP = &buf;
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer type 'char' and specified MPI type 'MPI_INT' do not match.}}
+  MPI_Reduce(MPI_IN_PLACE, bufP, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer type 'char' and specified MPI type 'MPI_INT' do not match.}}
+
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_CHAR, MPI_SUM, 0, MPI_COMM_WORLD);
+  MPI_Reduce(MPI_IN_PLACE, bufP, 1, MPI_CHAR, MPI_SUM, 0, MPI_COMM_WORLD);
+}
+
+void typeMatching10() {
+  struct a {
+    int x;
+  } buf;
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
+} // no error, checker does not verify structs
+
+void typeMatching11() {
+  float ***buf = (float ***)NULL;
+  MPI_Reduce(MPI_IN_PLACE, **buf, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD);
+} // no error
+
+void typeMatching12() {
+  typedef int Int;
+  Int buf = 1;
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_CHAR, MPI_SUM, 0, MPI_COMM_WORLD);
+} // no error, checker makes no assumptions about typedefs
+
+void typeMatching13() {
+  long buf = 0;
+  MPI_Reduce(MPI_IN_PLACE, &buf, 8, MPI_BYTE, MPI_SUM, 0, MPI_COMM_WORLD);
+} // no error, checker does not verify MPI_BYTE
+
+void typeMatching14() {
+  float ***buf = (float ***)NULL;
+  MPI_Reduce(MPI_IN_PLACE, buf, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer is not correctly dereferenced. It is passed as a *** pointer.}}
+} // buffer type not correctly dereferenced
+
+void typeMatching15() {
+  float *buf = (float *)NULL;
+  MPI_Reduce(MPI_IN_PLACE, &buf, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer is not correctly dereferenced. It is passed as a ** pointer.}}
+} // buffer type is float **
+
+void typeMatching16() {
+  float ***buf = (float ***)NULL;
+  MPI_Reduce(MPI_IN_PLACE, *buf, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer is not correctly dereferenced. It is passed as a ** pointer.}}
+} // buffer type not correctly dereferenced
+
+void typeMatching17() {
+  float buf[2];
+  MPI_Reduce(MPI_IN_PLACE, buf, 2, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD);
+}
+
+void typeMatching18() {
+  float *buf[2];
+  MPI_Reduce(MPI_IN_PLACE, buf, 2, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer is not correctly dereferenced. It is passed as a ** pointer.}}
+}
+
+void typeMatching19() {
+  float *buf[2];
+  MPI_Reduce(MPI_IN_PLACE, buf, 2, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD); // expected-warning{{Buffer is not correctly dereferenced. It is passed as a ** pointer.}}
+}
+
+void typeMatching20() {
+  float *buf = (float *)NULL;
+  MPI_Reduce(MPI_IN_PLACE, &buf[0], 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD);
+  MPI_Bcast(&buf[0], 21, MPI_FLOAT, 0, MPI_COMM_WORLD);
+}
+
+void invalidArgType() {
+  int rank = 0;
+  int buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank == 0) {
+    MPI_Send(&buf, 1, MPI_INT, rank + 1.1, 11, MPI_COMM_WORLD); // expected-warning{{The type, argument at index 3 evaluates to, is not an integer type.}}
+  } else if (rank == 1) {
+    MPI_Recv(&buf, 1, MPI_INT, rank - 1.1, 11, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // expected-warning{{The type, argument at index 3 evaluates to, is not an integer type.}}
+  }
+}
+
+void invalidArgType2() {
+  int rank = 0;
+  int buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank == 0) {
+    MPI_Send(&buf, 1 + 1.1, MPI_INT, rank + 1, 12, MPI_COMM_WORLD); // expected-warning{{The type, argument at index 1 evaluates to, is not an integer type.}}
+  } else if (rank == 1) {
+    MPI_Recv(&buf, 1 + 1.1, MPI_INT, rank - 1, 12, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // expected-warning{{The type, argument at index 1 evaluates to, is not an integer type.}}
+  }
+}
+
+void invalidArgType3() {
+  int rank = 0;
+  int buf = 0;
+  double x = 1.1;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank == 0) {
+    MPI_Send(&buf, 1 + x, MPI_INT, rank + 1, 13, MPI_COMM_WORLD); // expected-warning{{The type, argument at index 1 evaluates to, is not an integer type.}}
+  } else if (rank == 1) {
+    MPI_Recv(&buf, 1 + x, MPI_INT, rank - 1, 13, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // expected-warning{{The type, argument at index 1 evaluates to, is not an integer type.}}
+  }
+}
+
+double d() { return 1.1; }
+void invalidArgType4() {
+  int rank = 0;
+  int buf = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank == 0) {
+    MPI_Send(&buf, 1, MPI_INT, rank + d(), 14, MPI_COMM_WORLD); // expected-warning{{The type, argument at index 3 evaluates to, is not an integer type.}}
+  } else if (rank == 1) {
+    MPI_Recv(&buf, 1, MPI_INT, rank - d(), 14, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // expected-warning{{The type, argument at index 3 evaluates to, is not an integer type.}}
+  }
+}
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.h
@@ -0,0 +1,61 @@
+//===-- Utility.h - utility functions ---------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines utility helper functions for MPI-Checker.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_UTILITY_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_UTILITY_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+namespace util {
+
+/// Retrieve source range from memory region. The range retrieval
+/// is based on the decl obtained from the memory region.
+/// For a VarRegion the range of the base region is returned.
+/// For a FieldRegion the range of the field is returned.
+/// If no declaration is found, an empty source range is returned.
+/// The client is responsible for checking if the returned range is valid.
+///
+/// \param MR memory region to retrieve the source range for
+///
+/// \returns source range for declaration retrieved from memory region
+clang::SourceRange sourceRange(const clang::ento::MemRegion *MR);
+
+/// Returns the source range \p Range as a StringRef.
+clang::StringRef sourceRangeAsStringRef(const clang::SourceRange &Range,
+                                        clang::ento::AnalysisManager &AM);
+
+/// Returns an array of strings for \p String split by \p Delimiter.
+std::vector<std::string> split(const std::string &String, char Delimiter);
+
+/// Retrieve identifier info for a call expression.
+/// Returns nullptr if there's no direct callee.
+///
+/// \param CE call expression to retrieve ident info for
+///
+/// \returns identifier info for passed call expression
+const clang::IdentifierInfo *getIdentInfo(const clang::CallExpr *CE);
+
+/// Get variable name for memory region. The name is obtained from
+/// the variable/field declaration retrieved from the memory region.
+/// Regions that point to an array are returned as: "arr[0]".
+/// Regions that point to a struct are returned as: "st.var".
+///
+/// \param MR memory region to get the variable name for
+///
+/// \returns variable name for memory region
+std::string variableName(const clang::ento::MemRegion *MR);
+
+} // end of namespace: util
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp
@@ -0,0 +1,103 @@
+//===-- Utility.cpp - utility functions -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines utility helper functions for MPI-Checker.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Lexer.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "Utility.h"
+#include <sstream>
+#include <vector>
+
+namespace util {
+
+clang::SourceRange sourceRange(const clang::ento::MemRegion *MR) {
+  const clang::ento::VarRegion *VR =
+      clang::dyn_cast<clang::ento::VarRegion>(MR->getBaseRegion());
+
+  const clang::ento::FieldRegion *FR =
+      clang::dyn_cast<clang::ento::FieldRegion>(MR);
+
+  if (FR) {
+    return FR->getDecl()->getSourceRange();
+  } else if (VR) {
+    return VR->getDecl()->getSourceRange();
+  } else {
+    // non valid source range (can be checked by client)
+    return clang::SourceRange{};
+  }
+}
+
+clang::StringRef sourceRangeAsStringRef(const clang::SourceRange &Range,
+                                        clang::ento::AnalysisManager &AM) {
+  auto CharRange = clang::CharSourceRange::getTokenRange(Range);
+  return clang::Lexer::getSourceText(CharRange, AM.getSourceManager(),
+                                     clang::LangOptions());
+}
+
+std::vector<std::string> split(const std::string &String, char Delimiter) {
+  std::vector<std::string> Elements;
+  std::stringstream StringStream(String);
+  std::string Item;
+  while (std::getline(StringStream, Item, Delimiter)) {
+    Elements.push_back(Item);
+  }
+  return Elements;
+}
+
+std::string variableName(const clang::ento::MemRegion *MR) {
+  const clang::ento::VarRegion *VR =
+      clang::dyn_cast<clang::ento::VarRegion>(MR->getBaseRegion());
+
+  const clang::ento::FieldRegion *FR =
+      clang::dyn_cast<clang::ento::FieldRegion>(MR);
+
+  const clang::ento::ElementRegion *ER =
+      MR->getAs<clang::ento::ElementRegion>();
+
+  std::string VariableName{""};
+
+  // members, fields
+  if (FR) {
+    VariableName = VR->getDecl()->getNameAsString() + "." +
+                   FR->getDecl()->getNameAsString();
+  }
+  // variable
+  else if (VR) {
+    VariableName = VR->getDecl()->getNameAsString();
+  } else {
+    // get var-decl-name for symbolic region
+  }
+
+  if (ER) {
+    llvm::APSInt IndexInArray;
+    IndexInArray =
+        ER->getIndex().getAs<clang::ento::nonloc::ConcreteInt>()->getValue();
+
+    llvm::SmallVector<char, 2> intValAsString;
+    IndexInArray.toString(intValAsString);
+    std::string idx{intValAsString.begin(), intValAsString.end()};
+    return VariableName + "[" + idx + "]";
+  } else {
+    return VariableName;
+  }
+}
+
+const clang::IdentifierInfo *getIdentInfo(const clang::CallExpr *CE) {
+  if (CE->getDirectCallee()) {
+    return CE->getDirectCallee()->getIdentifier();
+  } else {
+    return nullptr;
+  }
+}
+
+} // end of namespace: util
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TypeVisitor.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TypeVisitor.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TypeVisitor.h
@@ -0,0 +1,78 @@
+//===-- TypeVisitor - traverse qual type ------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines a type visitor class which collects information about the
+//  QualType instance passed to its ctor. It detects if the QualType is a
+/// typedef, complex type, builtin type and the pointer count.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_TYPEVISITOR_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_TYPEVISITOR_H
+
+#include "clang/AST/RecursiveASTVisitor.h"
+
+namespace clang {
+namespace mpi {
+
+class TypeVisitor : public clang::RecursiveASTVisitor<TypeVisitor> {
+public:
+  TypeVisitor(clang::QualType TypeToInspect) : InspectedType{TypeToInspect} {
+    TraverseType(TypeToInspect);
+  }
+
+  bool VisitTypedefType(clang::TypedefType *TDT) {
+    TypedefTypeName = TDT->getDecl()->getQualifiedNameAsString();
+    IsTypedefType = true;
+    return true;
+  }
+
+  bool VisitBuiltinType(clang::BuiltinType *BuiltinT) {
+    BuiltinType = BuiltinT;
+    return true;
+  }
+
+  bool VisitComplexType(clang::ComplexType *) {
+    IsComplexType = true;
+    return true;
+  }
+
+  bool VisitPointerType(clang::PointerType *) {
+    ++PointerCount;
+    return true;
+  }
+
+  bool VisitArrayType(clang::ArrayType *) {
+    ++PointerCount;
+    return true;
+  }
+
+  // passed qual type
+  const clang::QualType InspectedType;
+
+  bool isTypedefType() const { return IsTypedefType; }
+  bool isComplexType() const { return IsComplexType; }
+  const std::string typedefTypeName() const & { return TypedefTypeName; }
+  const clang::BuiltinType *builtinType() const { return BuiltinType; }
+  size_t pointerCount() const { return PointerCount; }
+
+private:
+  bool IsTypedefType{false};
+  bool IsComplexType{false};
+  std::string TypedefTypeName;
+  size_t PointerCount{0};
+
+  clang::BuiltinType *BuiltinType = nullptr;
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.h
@@ -0,0 +1,44 @@
+//===-- TranslationUnitVisitor.h - traverses tu --*---------------- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines a translation unit visitor class that invokes
+/// AST-based checks on an MPICheckerAST instance during traversal.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_TRANSLATIONUNITVISITOR_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_TRANSLATIONUNITVISITOR_H
+
+#include "MPICheckerAST.h"
+
+namespace clang {
+namespace mpi {
+
+class TranslationUnitVisitor
+    : public clang::RecursiveASTVisitor<TranslationUnitVisitor> {
+public:
+  TranslationUnitVisitor(clang::ento::BugReporter &BR,
+                         const clang::ento::CheckerBase &CB,
+                         clang::ento::AnalysisManager &AM)
+      : CheckerAST{BR, CB, AM} {}
+
+  /// Visited for each function declaration.
+  bool VisitFunctionDecl(clang::FunctionDecl *FuncDecl);
+
+  /// Visited for each call expression.
+  bool VisitCallExpr(clang::CallExpr *CE);
+
+  MPICheckerAST CheckerAST;
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.cpp
@@ -0,0 +1,41 @@
+//===-- TranslationUnitVisitor.cpp - traverses tu --*-------------- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines a translation unit visitor class that invokes
+/// AST-based checks on an MPICheckerAST instance during traversal.
+///
+//===----------------------------------------------------------------------===//
+
+#include "TranslationUnitVisitor.h"
+#include "MPICheckerPathSensitive.h"
+
+namespace clang {
+namespace mpi {
+
+bool TranslationUnitVisitor::VisitFunctionDecl(FunctionDecl *FuncDecl) {
+  // to keep track which function implementation is currently analysed
+  if (FuncDecl->clang::Decl::hasBody() && !FuncDecl->isInlined()) {
+    // to make display of function in diagnostics available
+    CheckerAST.setCurrentlyVisitedFunction(FuncDecl);
+  }
+  return true;
+}
+
+bool TranslationUnitVisitor::VisitCallExpr(clang::CallExpr *CE) {
+  if (CheckerAST.funcClassifier().isMPIType(util::getIdentInfo(CE))) {
+    CheckerAST.checkBufferTypeMatch(CE);
+    CheckerAST.checkForInvalidArgs(CE);
+  }
+
+  return true;
+}
+
+} // end of namespace: mpi
+} // end of namespace: clang
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.h
@@ -0,0 +1,67 @@
+//===-- MPITypes.h - Functionality to model MPI concepts --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides definitions, to model the schema of MPI point-to-point
+/// functions and MPI requests. The mpi::Request class defines a wrapper
+/// class, in order to make MPI requests trackable for path-sensitive analysis.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPITYPES_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPITYPES_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "llvm/ADT/SmallSet.h"
+#include "MPIFunctionClassifier.h"
+#include "Utility.h"
+#include "Container.h"
+
+namespace clang {
+namespace mpi {
+// argument schema enums –––––––––––––––––––––––––––––––––––––––––––––––
+// scope enums, but keep weak typing to make values usable as indices
+namespace MPIPointToPoint {
+// valid for all point to point functions
+enum { Buf, Count, Datatype, Rank, Tag, Comm, Request };
+}
+
+// for path sensitive analysis–––––––––––––––––––––––––––––––––––––––––––––––
+class Request {
+public:
+  Request(const clang::ento::MemRegion *const MR,
+          const clang::ento::CallEventRef<> MPICallEvent)
+      : MR{MR}, LastUser{MPICallEvent} {
+    VariableName = util::variableName(MR);
+  }
+
+  void Profile(llvm::FoldingSetNodeID &Id) const {
+    Id.AddPointer(MR);
+    Id.AddPointer(LastUser->getOriginExpr());
+  }
+
+  bool operator==(const Request &toCompare) const { return toCompare.MR == MR; }
+
+  const clang::ento::MemRegion *const MR;
+  const clang::ento::CallEventRef<> LastUser;
+
+  std::string variableName() const { return VariableName; }
+
+private:
+  std::string VariableName;
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+// register data structure for path-sensitive analysis
+REGISTER_MAP_WITH_PROGRAMSTATE(RequestMap, const clang::ento::MemRegion *,
+                               clang::mpi::Request)
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.h
@@ -0,0 +1,109 @@
+//===-- MPIFunctionClassifier.h - classifies MPI functions ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines functionality to identify and classify MPI functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIFUNCTIONCLASSIFIER_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIFUNCTIONCLASSIFIER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+namespace clang {
+namespace mpi {
+
+class MPIFunctionClassifier {
+public:
+  MPIFunctionClassifier(clang::ento::AnalysisManager &AM) {
+    identifierInit(AM);
+  }
+
+  // general identifiers–––––––––––––––––––––––––––––––––––––––––––––––––
+  bool isMPIType(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isBlockingType(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isNonBlockingType(const clang::IdentifierInfo *const IdentInfo) const;
+
+  // point to point identifiers––––––––––––––––––––––––––––––––––––––––––
+  bool isPointToPointType(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isSendType(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isRecvType(const clang::IdentifierInfo *const IdentInfo) const;
+
+  // collective identifiers––––––––––––––––––––––––––––––––––––––––––––––
+  bool isCollectiveType(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isCollToColl(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isScatterType(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isGatherType(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isAllgatherType(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isAlltoallType(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isReduceType(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isBcastType(const clang::IdentifierInfo *const IdentInfo) const;
+
+  // additional identifiers ––––––––––––––––––––––––––––––––––––––––––––––
+  bool isMPI_Comm_rank(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isMPI_Comm_size(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isMPI_Wait(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isMPI_Waitall(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isMPI_Waitany(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isMPI_Waitsome(const clang::IdentifierInfo *const IdentInfo) const;
+  bool isWaitType(const clang::IdentifierInfo *const IdentInfo) const;
+
+private:
+  /// Initializes function identifiers to recognize them during analysis.
+  void identifierInit(clang::ento::AnalysisManager &AM);
+  void initPointToPointIdentifiers(clang::ento::AnalysisManager &AM);
+  void initCollectiveIdentifiers(clang::ento::AnalysisManager &AM);
+  void initAdditionalIdentifiers(clang::ento::AnalysisManager &AM);
+
+  // to enable classification of mpi-functions during analysis
+  llvm::SmallVector<clang::IdentifierInfo *, 8> MPISendTypes;
+  llvm::SmallVector<clang::IdentifierInfo *, 2> MPIRecvTypes;
+
+  llvm::SmallVector<clang::IdentifierInfo *, 12> MPIBlockingTypes;
+  llvm::SmallVector<clang::IdentifierInfo *, 12> MPINonBlockingTypes;
+
+  llvm::SmallVector<clang::IdentifierInfo *, 10> MPIPointToPointTypes;
+  llvm::SmallVector<clang::IdentifierInfo *, 16> MPICollectiveTypes;
+
+  llvm::SmallVector<clang::IdentifierInfo *, 4> MPIPointToCollTypes;
+  llvm::SmallVector<clang::IdentifierInfo *, 4> MPICollToPointTypes;
+  llvm::SmallVector<clang::IdentifierInfo *, 6> MPICollToCollTypes;
+
+  llvm::SmallVector<clang::IdentifierInfo *, 32> MPIType;
+
+  // point to point functions
+  clang::IdentifierInfo *IdentInfo_MPI_Send{nullptr},
+      *IdentInfo_MPI_Isend{nullptr}, *IdentInfo_MPI_Ssend{nullptr},
+      *IdentInfo_MPI_Issend{nullptr}, *IdentInfo_MPI_Bsend{nullptr},
+      *IdentInfo_MPI_Ibsend{nullptr}, *IdentInfo_MPI_Rsend{nullptr},
+      *IdentInfo_MPI_Irsend{nullptr}, *IdentInfo_MPI_Recv{nullptr},
+      *IdentInfo_MPI_Irecv{nullptr};
+
+  // collective functions
+  clang::IdentifierInfo *IdentInfo_MPI_Scatter{nullptr},
+      *IdentInfo_MPI_Iscatter{nullptr}, *IdentInfo_MPI_Gather{nullptr},
+      *IdentInfo_MPI_Igather{nullptr}, *IdentInfo_MPI_Allgather{nullptr},
+      *IdentInfo_MPI_Iallgather{nullptr}, *IdentInfo_MPI_Bcast{nullptr},
+      *IdentInfo_MPI_Ibcast{nullptr}, *IdentInfo_MPI_Reduce{nullptr},
+      *IdentInfo_MPI_Ireduce{nullptr}, *IdentInfo_MPI_Allreduce{nullptr},
+      *IdentInfo_MPI_Iallreduce{nullptr}, *IdentInfo_MPI_Alltoall{nullptr},
+      *IdentInfo_MPI_Ialltoall{nullptr}, *IdentInfo_MPI_Barrier{nullptr};
+
+  // additional functions
+  clang::IdentifierInfo *IdentInfo_MPI_Comm_rank{nullptr},
+      *IdentInfo_MPI_Comm_size{nullptr}, *IdentInfo_MPI_Wait{nullptr},
+      *IdentInfo_MPI_Waitall{nullptr}, *IdentInfo_MPI_Waitany{nullptr},
+      *IdentInfo_MPI_Waitsome{nullptr};
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp
@@ -0,0 +1,359 @@
+//===-- MPIFunctionClassifier.cpp - classifies MPI functions ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines functionality to identify and classify MPI functions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MPIFunctionClassifier.h"
+#include "Utility.h"
+#include "Container.h"
+
+namespace clang {
+namespace mpi {
+
+void MPIFunctionClassifier::identifierInit(clang::ento::AnalysisManager &AM) {
+  // init function identifiers
+  initPointToPointIdentifiers(AM);
+  initCollectiveIdentifiers(AM);
+  initAdditionalIdentifiers(AM);
+}
+
+void MPIFunctionClassifier::initPointToPointIdentifiers(
+    clang::ento::AnalysisManager &AM) {
+  ASTContext &ASTCtx = AM.getASTContext();
+
+  // copy identifiers into the correct classification containers
+  IdentInfo_MPI_Send = &ASTCtx.Idents.get("MPI_Send");
+  MPISendTypes.push_back(IdentInfo_MPI_Send);
+  MPIPointToPointTypes.push_back(IdentInfo_MPI_Send);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Send);
+  MPIType.push_back(IdentInfo_MPI_Send);
+  assert(IdentInfo_MPI_Send);
+
+  IdentInfo_MPI_Isend = &ASTCtx.Idents.get("MPI_Isend");
+  MPISendTypes.push_back(IdentInfo_MPI_Isend);
+  MPIPointToPointTypes.push_back(IdentInfo_MPI_Isend);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Isend);
+  MPIType.push_back(IdentInfo_MPI_Isend);
+  assert(IdentInfo_MPI_Isend);
+
+  IdentInfo_MPI_Ssend = &ASTCtx.Idents.get("MPI_Ssend");
+  MPISendTypes.push_back(IdentInfo_MPI_Ssend);
+  MPIPointToPointTypes.push_back(IdentInfo_MPI_Ssend);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Ssend);
+  MPIType.push_back(IdentInfo_MPI_Ssend);
+  assert(IdentInfo_MPI_Ssend);
+
+  IdentInfo_MPI_Issend = &ASTCtx.Idents.get("MPI_Issend");
+  MPISendTypes.push_back(IdentInfo_MPI_Issend);
+  MPIPointToPointTypes.push_back(IdentInfo_MPI_Issend);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Issend);
+  MPIType.push_back(IdentInfo_MPI_Issend);
+  assert(IdentInfo_MPI_Issend);
+
+  IdentInfo_MPI_Bsend = &ASTCtx.Idents.get("MPI_Bsend");
+  MPISendTypes.push_back(IdentInfo_MPI_Bsend);
+  MPIPointToPointTypes.push_back(IdentInfo_MPI_Bsend);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Bsend);
+  MPIType.push_back(IdentInfo_MPI_Bsend);
+  assert(IdentInfo_MPI_Bsend);
+
+  IdentInfo_MPI_Ibsend = &ASTCtx.Idents.get("MPI_Ibsend");
+  MPISendTypes.push_back(IdentInfo_MPI_Ibsend);
+  MPIPointToPointTypes.push_back(IdentInfo_MPI_Ibsend);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Ibsend);
+  MPIType.push_back(IdentInfo_MPI_Ibsend);
+  assert(IdentInfo_MPI_Ibsend);
+
+  IdentInfo_MPI_Rsend = &ASTCtx.Idents.get("MPI_Rsend");
+  MPISendTypes.push_back(IdentInfo_MPI_Rsend);
+  MPIPointToPointTypes.push_back(IdentInfo_MPI_Rsend);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Rsend);
+  MPIType.push_back(IdentInfo_MPI_Rsend);
+  assert(IdentInfo_MPI_Rsend);
+
+  IdentInfo_MPI_Irsend = &ASTCtx.Idents.get("MPI_Irsend");
+  MPISendTypes.push_back(IdentInfo_MPI_Irsend);
+  MPIPointToPointTypes.push_back(IdentInfo_MPI_Irsend);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Irsend);
+  MPIType.push_back(IdentInfo_MPI_Irsend);
+  assert(IdentInfo_MPI_Irsend);
+
+  IdentInfo_MPI_Recv = &ASTCtx.Idents.get("MPI_Recv");
+  MPIRecvTypes.push_back(IdentInfo_MPI_Recv);
+  MPIPointToPointTypes.push_back(IdentInfo_MPI_Recv);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Recv);
+  MPIType.push_back(IdentInfo_MPI_Recv);
+  assert(IdentInfo_MPI_Recv);
+
+  IdentInfo_MPI_Irecv = &ASTCtx.Idents.get("MPI_Irecv");
+  MPIRecvTypes.push_back(IdentInfo_MPI_Irecv);
+  MPIPointToPointTypes.push_back(IdentInfo_MPI_Irecv);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Irecv);
+  MPIType.push_back(IdentInfo_MPI_Irecv);
+  assert(IdentInfo_MPI_Irecv);
+}
+
+void MPIFunctionClassifier::initCollectiveIdentifiers(
+    clang::ento::AnalysisManager &AM) {
+  ASTContext &ASTCtx = AM.getASTContext();
+
+  // copy identifiers into the correct classification containers
+  IdentInfo_MPI_Scatter = &ASTCtx.Idents.get("MPI_Scatter");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Scatter);
+  MPIPointToCollTypes.push_back(IdentInfo_MPI_Scatter);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Scatter);
+  MPIType.push_back(IdentInfo_MPI_Scatter);
+  assert(IdentInfo_MPI_Scatter);
+
+  IdentInfo_MPI_Iscatter = &ASTCtx.Idents.get("MPI_Iscatter");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Iscatter);
+  MPIPointToCollTypes.push_back(IdentInfo_MPI_Iscatter);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Iscatter);
+  MPIType.push_back(IdentInfo_MPI_Iscatter);
+  assert(IdentInfo_MPI_Iscatter);
+
+  IdentInfo_MPI_Gather = &ASTCtx.Idents.get("MPI_Gather");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Gather);
+  MPICollToPointTypes.push_back(IdentInfo_MPI_Gather);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Gather);
+  MPIType.push_back(IdentInfo_MPI_Gather);
+  assert(IdentInfo_MPI_Gather);
+
+  IdentInfo_MPI_Igather = &ASTCtx.Idents.get("MPI_Igather");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Igather);
+  MPICollToPointTypes.push_back(IdentInfo_MPI_Igather);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Igather);
+  MPIType.push_back(IdentInfo_MPI_Igather);
+  assert(IdentInfo_MPI_Igather);
+
+  IdentInfo_MPI_Allgather = &ASTCtx.Idents.get("MPI_Allgather");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Allgather);
+  MPICollToCollTypes.push_back(IdentInfo_MPI_Allgather);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Allgather);
+  MPIType.push_back(IdentInfo_MPI_Allgather);
+  assert(IdentInfo_MPI_Allgather);
+
+  IdentInfo_MPI_Iallgather = &ASTCtx.Idents.get("MPI_Iallgather");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Iallgather);
+  MPICollToCollTypes.push_back(IdentInfo_MPI_Iallgather);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Iallgather);
+  MPIType.push_back(IdentInfo_MPI_Iallgather);
+  assert(IdentInfo_MPI_Iallgather);
+
+  IdentInfo_MPI_Bcast = &ASTCtx.Idents.get("MPI_Bcast");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Bcast);
+  MPIPointToCollTypes.push_back(IdentInfo_MPI_Bcast);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Bcast);
+  MPIType.push_back(IdentInfo_MPI_Bcast);
+  assert(IdentInfo_MPI_Bcast);
+
+  IdentInfo_MPI_Ibcast = &ASTCtx.Idents.get("MPI_Ibcast");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Ibcast);
+  MPIPointToCollTypes.push_back(IdentInfo_MPI_Ibcast);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Ibcast);
+  MPIType.push_back(IdentInfo_MPI_Ibcast);
+  assert(IdentInfo_MPI_Ibcast);
+
+  IdentInfo_MPI_Reduce = &ASTCtx.Idents.get("MPI_Reduce");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Reduce);
+  MPICollToPointTypes.push_back(IdentInfo_MPI_Reduce);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Reduce);
+  MPIType.push_back(IdentInfo_MPI_Reduce);
+  assert(IdentInfo_MPI_Reduce);
+
+  IdentInfo_MPI_Ireduce = &ASTCtx.Idents.get("MPI_Ireduce");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Ireduce);
+  MPICollToPointTypes.push_back(IdentInfo_MPI_Ireduce);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Ireduce);
+  MPIType.push_back(IdentInfo_MPI_Ireduce);
+  assert(IdentInfo_MPI_Ireduce);
+
+  IdentInfo_MPI_Allreduce = &ASTCtx.Idents.get("MPI_Allreduce");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Allreduce);
+  MPICollToCollTypes.push_back(IdentInfo_MPI_Allreduce);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Allreduce);
+  MPIType.push_back(IdentInfo_MPI_Allreduce);
+  assert(IdentInfo_MPI_Allreduce);
+
+  IdentInfo_MPI_Iallreduce = &ASTCtx.Idents.get("MPI_Iallreduce");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Iallreduce);
+  MPICollToCollTypes.push_back(IdentInfo_MPI_Iallreduce);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Iallreduce);
+  MPIType.push_back(IdentInfo_MPI_Iallreduce);
+  assert(IdentInfo_MPI_Iallreduce);
+
+  IdentInfo_MPI_Alltoall = &ASTCtx.Idents.get("MPI_Alltoall");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Alltoall);
+  MPICollToCollTypes.push_back(IdentInfo_MPI_Alltoall);
+  MPIBlockingTypes.push_back(IdentInfo_MPI_Alltoall);
+  MPIType.push_back(IdentInfo_MPI_Alltoall);
+  assert(IdentInfo_MPI_Alltoall);
+
+  IdentInfo_MPI_Ialltoall = &ASTCtx.Idents.get("MPI_Ialltoall");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Ialltoall);
+  MPICollToCollTypes.push_back(IdentInfo_MPI_Ialltoall);
+  MPINonBlockingTypes.push_back(IdentInfo_MPI_Ialltoall);
+  MPIType.push_back(IdentInfo_MPI_Ialltoall);
+  assert(IdentInfo_MPI_Ialltoall);
+}
+
+void MPIFunctionClassifier::initAdditionalIdentifiers(
+    clang::ento::AnalysisManager &AM) {
+  ASTContext &ASTCtx = AM.getASTContext();
+
+  IdentInfo_MPI_Comm_rank = &ASTCtx.Idents.get("MPI_Comm_rank");
+  MPIType.push_back(IdentInfo_MPI_Comm_rank);
+  assert(IdentInfo_MPI_Comm_rank);
+
+  IdentInfo_MPI_Comm_size = &ASTCtx.Idents.get("MPI_Comm_size");
+  MPIType.push_back(IdentInfo_MPI_Comm_size);
+  assert(IdentInfo_MPI_Comm_size);
+
+  IdentInfo_MPI_Wait = &ASTCtx.Idents.get("MPI_Wait");
+  MPIType.push_back(IdentInfo_MPI_Wait);
+  assert(IdentInfo_MPI_Wait);
+
+  IdentInfo_MPI_Waitall = &ASTCtx.Idents.get("MPI_Waitall");
+  MPIType.push_back(IdentInfo_MPI_Waitall);
+  assert(IdentInfo_MPI_Waitall);
+
+  IdentInfo_MPI_Waitany = &ASTCtx.Idents.get("MPI_Waitany");
+  MPIType.push_back(IdentInfo_MPI_Waitany);
+  assert(IdentInfo_MPI_Waitany);
+
+  IdentInfo_MPI_Waitsome = &ASTCtx.Idents.get("MPI_Waitsome");
+  MPIType.push_back(IdentInfo_MPI_Waitsome);
+  assert(IdentInfo_MPI_Waitsome);
+
+  IdentInfo_MPI_Barrier = &ASTCtx.Idents.get("MPI_Barrier");
+  MPICollectiveTypes.push_back(IdentInfo_MPI_Barrier);
+  MPIType.push_back(IdentInfo_MPI_Barrier);
+  assert(IdentInfo_MPI_Barrier);
+}
+
+// general identifiers–––––––––––––––––––––––––––––––––––––––––––––––––
+bool MPIFunctionClassifier::isMPIType(const IdentifierInfo *IdentInfo) const {
+  return cont::contains(MPIType, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isBlockingType(
+    const IdentifierInfo *IdentInfo) const {
+  return cont::contains(MPIBlockingTypes, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isNonBlockingType(
+    const IdentifierInfo *IdentInfo) const {
+  return cont::contains(MPINonBlockingTypes, IdentInfo);
+}
+
+// point to point identifiers––––––––––––––––––––––––––––––––––––––––––
+bool MPIFunctionClassifier::isPointToPointType(
+    const IdentifierInfo *IdentInfo) const {
+  return cont::contains(MPIPointToPointTypes, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isSendType(const IdentifierInfo *IdentInfo) const {
+  return cont::contains(MPISendTypes, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isRecvType(const IdentifierInfo *IdentInfo) const {
+  return cont::contains(MPIRecvTypes, IdentInfo);
+}
+
+// collective identifiers––––––––––––––––––––––––––––––––––––––––––––––
+bool MPIFunctionClassifier::isCollectiveType(
+    const IdentifierInfo *IdentInfo) const {
+  return cont::contains(MPICollectiveTypes, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isCollToColl(
+    const IdentifierInfo *IdentInfo) const {
+  return cont::contains(MPICollToCollTypes, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isScatterType(
+    const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Scatter ||
+         IdentInfo == IdentInfo_MPI_Iscatter;
+}
+
+bool MPIFunctionClassifier::isGatherType(
+    const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Gather ||
+         IdentInfo == IdentInfo_MPI_Igather ||
+         IdentInfo == IdentInfo_MPI_Allgather ||
+         IdentInfo == IdentInfo_MPI_Iallgather;
+}
+
+bool MPIFunctionClassifier::isAllgatherType(
+    const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Allgather ||
+         IdentInfo == IdentInfo_MPI_Iallgather;
+}
+
+bool MPIFunctionClassifier::isAlltoallType(
+    const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Alltoall ||
+         IdentInfo == IdentInfo_MPI_Ialltoall;
+}
+
+bool MPIFunctionClassifier::isBcastType(const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Bcast || IdentInfo == IdentInfo_MPI_Ibcast;
+}
+
+bool MPIFunctionClassifier::isReduceType(
+    const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Reduce ||
+         IdentInfo == IdentInfo_MPI_Ireduce ||
+         IdentInfo == IdentInfo_MPI_Allreduce ||
+         IdentInfo == IdentInfo_MPI_Iallreduce;
+}
+
+// additional identifiers ––––––––––––––––––––––––––––––––––––––––––––––
+bool MPIFunctionClassifier::isMPI_Comm_rank(
+    const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Comm_rank;
+}
+
+bool MPIFunctionClassifier::isMPI_Comm_size(
+    const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Comm_size;
+}
+
+bool MPIFunctionClassifier::isMPI_Wait(const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Wait;
+}
+
+bool MPIFunctionClassifier::isMPI_Waitall(
+    const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Waitall;
+}
+
+bool MPIFunctionClassifier::isMPI_Waitany(
+    const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Waitany;
+}
+
+bool MPIFunctionClassifier::isMPI_Waitsome(
+    const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Waitsome;
+}
+
+bool MPIFunctionClassifier::isWaitType(const IdentifierInfo *IdentInfo) const {
+  return IdentInfo == IdentInfo_MPI_Wait ||
+         IdentInfo == IdentInfo_MPI_Waitall ||
+         IdentInfo == IdentInfo_MPI_Waitany ||
+         IdentInfo == IdentInfo_MPI_Waitsome;
+}
+
+} // end of namespace: mpi
+} // end of namespace: clang
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.h
@@ -0,0 +1,88 @@
+//===-- MPICheckerPathSensitive.h - path-sensitive checks -------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines path-sensitive checks, to verify correct usage of the
+/// MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPICHECKERPATHSENSITIVE_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPICHECKERPATHSENSITIVE_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "MPIFunctionClassifier.h"
+#include "MPITypes.h"
+#include "MPIBugReporter.h"
+
+namespace clang {
+namespace mpi {
+
+class MPICheckerPathSensitive {
+public:
+  MPICheckerPathSensitive(clang::ento::AnalysisManager &AM,
+                          const clang::ento::CheckerBase *CB,
+                          clang::ento::BugReporter &BR)
+      : FuncClassifier{AM}, BugReporter{BR, *CB, AM} {}
+
+  /// Checks if a request is used by nonblocking calls multiple times
+  /// in sequence without intermediate wait. The check contains a guard,
+  /// in order to only inspect nonblocking functions.
+  ///
+  /// \CE MPI call to check for if it is causing a double nonblocking
+  void checkDoubleNonblocking(const clang::ento::CallEvent &CE,
+                              clang::ento::CheckerContext &Ctx) const;
+
+  /// Checks if a request is used by a wait multiple times in sequence without
+  /// intermediate nonblocking call or if the request used by the wait
+  /// function was not used at all before. The check contains a guard,
+  /// in order to only inspect wait functions.
+  ///
+  /// \CE MPI call to check for if it is causing a double wait
+  void checkWaitUsage(const clang::ento::CallEvent &CE,
+                      clang::ento::CheckerContext &Ctx) const;
+
+  /// Check if a nonblocking call has no matching wait.
+  /// When this function is invoked, any requests whose last user
+  /// is a nonblocking call are rated as missings waits.
+  void checkMissingWaits(clang::ento::CheckerContext &Ctx);
+
+  /// Erase all requests from the path-sensitive map.
+  void clearRequests(clang::ento::CheckerContext &Ctx) const;
+
+private:
+  /// Returns the memory region used by wait function.
+  /// Distinguishes between MPI_Wait and MPI_Waitall.
+  ///
+  /// \CE MPI wait call
+  const clang::ento::MemRegion *
+  memRegionUsedInWait(const clang::ento::CallEvent &CE) const;
+
+  /// Collects all memory regions of a request(array) used by a wait
+  /// function. If the wait function uses a single request, this is a single
+  /// region. For wait functions using multiple requests, multiple regions
+  /// representing elements in the array are pushed into the vector.
+  ///
+  /// \param ReqRegions vector the regions get pushed into
+  /// \param MR top most region to iterate
+  /// \param CE MPI wait call using the request(s)
+  void collectUsedMemRegions(
+      llvm::SmallVector<const clang::ento::MemRegion *, 2> &ReqRegions,
+      const clang::ento::MemRegion *MR, const clang::ento::CallEvent &CE,
+      clang::ento::CheckerContext &Ctx) const;
+
+  MPIFunctionClassifier FuncClassifier;
+  MPIBugReporter BugReporter;
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp
@@ -0,0 +1,162 @@
+//===-- MPICheckerPathSensitive.cpp - path-sensitive checks -----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines path-sensitive checks, to verify correct usage of the
+/// MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MPICheckerPathSensitive.h"
+#include "Utility.h"
+
+namespace clang {
+namespace mpi {
+
+using namespace clang::ento;
+
+void MPICheckerPathSensitive::checkDoubleNonblocking(
+    const clang::ento::CallEvent &CE, CheckerContext &Ctx) const {
+  if (!FuncClassifier.isNonBlockingType(CE.getCalleeIdentifier())) {
+    return;
+  }
+  const MemRegion *MR = CE.getArgSVal(CE.getNumArgs() - 1).getAsRegion();
+
+  // no way to reason about symbolic region
+  if (MR->getBaseRegion()->getAs<SymbolicRegion>())
+    return;
+
+  ProgramStateRef State = Ctx.getState();
+  CallEventRef<> CERef = CE.cloneWithState(State);
+
+  const Request *Req = State->get<RequestMap>(MR);
+  const ExplodedNode *const ExplNode = Ctx.addTransition();
+
+  if (Req) {
+    if (FuncClassifier.isNonBlockingType(
+            Req->LastUser->getCalleeIdentifier())) {
+      BugReporter.reportDoubleNonblocking(CE, *Req, ExplNode);
+    }
+  }
+
+  State = State->set<RequestMap>(MR, mpi::Request{MR, CERef});
+  Ctx.addTransition(State);
+}
+
+void MPICheckerPathSensitive::checkWaitUsage(const clang::ento::CallEvent &CE,
+                                             CheckerContext &Ctx) const {
+  if (!FuncClassifier.isWaitType(CE.getCalleeIdentifier()))
+    return;
+  const MemRegion *MR = memRegionUsedInWait(CE);
+  if (!MR)
+    return;
+
+  // no way to reason about symbolic region
+  if (MR->getBaseRegion()->getAs<SymbolicRegion>())
+    return;
+
+  ProgramStateRef State = Ctx.getState();
+  CallEventRef<> CERef = CE.cloneWithState(State);
+  const ExplodedNode *const ExplNode = Ctx.addTransition();
+  llvm::SmallVector<const MemRegion *, 2> ReqRegions;
+  collectUsedMemRegions(ReqRegions, MR, CE, Ctx);
+
+  // check all requestRegions used in wait function
+  for (const auto ReqRegion : ReqRegions) {
+    const Request *Req = State->get<RequestMap>(ReqRegion);
+    State = State->set<RequestMap>(ReqRegion, {ReqRegion, CERef});
+    if (Req) {
+      // check for double wait
+      if (FuncClassifier.isWaitType(Req->LastUser->getCalleeIdentifier())) {
+        BugReporter.reportDoubleWait(CE, *Req, ExplNode);
+      }
+    }
+    // no matching nonblocking call
+    else {
+      BugReporter.reportUnmatchedWait(CE, ReqRegion, ExplNode);
+    }
+  }
+
+  Ctx.addTransition(State);
+}
+
+void MPICheckerPathSensitive::checkMissingWaits(CheckerContext &Ctx) {
+  ProgramStateRef State = Ctx.getState();
+  auto Requests = State->get<RequestMap>();
+  ExplodedNode *ExplNode = Ctx.addTransition();
+  // at the end of a function immediate calls should be matched with wait
+  for (auto &Req : Requests) {
+    if (Req.second.LastUser &&
+        FuncClassifier.isNonBlockingType(
+            Req.second.LastUser->getCalleeIdentifier())) {
+      BugReporter.reportMissingWait(Req.second, ExplNode);
+    }
+  }
+}
+
+void MPICheckerPathSensitive::clearRequests(CheckerContext &Ctx) const {
+  ProgramStateRef State = Ctx.getState();
+  auto Requests = State->get<RequestMap>();
+  // clear rank container
+  for (auto &Req : Requests) {
+    State = State->remove<RequestMap>(Req.first);
+  }
+  Ctx.addTransition(State);
+}
+
+const MemRegion *MPICheckerPathSensitive::memRegionUsedInWait(
+    const clang::ento::CallEvent &CE) const {
+  if (FuncClassifier.isMPI_Wait(CE.getCalleeIdentifier())) {
+    return CE.getArgSVal(0).getAsRegion();
+  } else if (FuncClassifier.isMPI_Waitall(CE.getCalleeIdentifier())) {
+    return CE.getArgSVal(1).getAsRegion();
+  } else {
+    return (const MemRegion *)nullptr;
+  }
+}
+
+void MPICheckerPathSensitive::collectUsedMemRegions(
+    llvm::SmallVector<const MemRegion *, 2> &ReqRegions, const MemRegion *MR,
+    const clang::ento::CallEvent &CE, CheckerContext &Ctx) const {
+  ProgramStateRef State = Ctx.getState();
+  MemRegionManager *RegionManager = MR->getMemRegionManager();
+
+  if (FuncClassifier.isMPI_Waitall(CE.getCalleeIdentifier())) {
+    const MemRegion *SuperRegion{nullptr};
+    if (const ElementRegion *ER = MR->getAs<ElementRegion>()) {
+      SuperRegion = ER->getSuperRegion();
+    }
+
+    // single request passed to waitall
+    if (!SuperRegion) {
+      ReqRegions.push_back(MR);
+      return;
+    }
+
+    auto size = Ctx.getStoreManager().getSizeInElements(
+        State, SuperRegion, CE.getArgExpr(1)->getType()->getPointeeType());
+
+    const llvm::APSInt &arrSize = size.getAs<nonloc::ConcreteInt>()->getValue();
+
+    for (size_t i = 0; i < arrSize; ++i) {
+      NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i);
+
+      const ElementRegion *ER = RegionManager->getElementRegion(
+          CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion,
+          Ctx.getASTContext());
+
+      ReqRegions.push_back(ER->getAs<MemRegion>());
+    }
+  } else if (FuncClassifier.isMPI_Wait(CE.getCalleeIdentifier())) {
+    ReqRegions.push_back(MR);
+  }
+}
+
+} // end of namespace: mpi
+} // end of namespace: clang
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.h
@@ -0,0 +1,110 @@
+//===-- MPICheckerAST.h - AST-based checks for MPI --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines AST-based checks, to verify correct usage of the MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPICHECKERAST_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPICHECKERAST_H
+
+#include "MPIFunctionClassifier.h"
+#include "MPIBugReporter.h"
+#include "Container.h"
+#include "Utility.h"
+#include "TypeVisitor.h"
+
+namespace clang {
+namespace mpi {
+
+class MPICheckerAST {
+public:
+  MPICheckerAST(clang::ento::BugReporter &BR,
+                const clang::ento::CheckerBase &CB,
+                clang::ento::AnalysisManager &AM)
+      : FuncClassifier{AM}, BugReporter{BR, CB, AM}, AnalysisManager{AM} {
+    initMPITypeContainer();
+  }
+
+  using IndexPairs = llvm::SmallVector<std::pair<size_t, size_t>, 2>;
+
+  /// Checks if expressions evaluate to non-integer type at indices where only
+  /// integer values are valid (count, rank, tag).
+  ///
+  /// \param MPICallExpr call to check the arguments for
+  void checkForInvalidArgs(const clang::CallExpr *const MPICallExpr) const;
+
+  /// Checks if buffer type and specified MPI datatype matches.
+  /// \param MPICallExpr call to check type correspondence for
+  void checkBufferTypeMatch(const clang::CallExpr *const MPICallExpr) const;
+
+  /// Set function currently visited to pass the information to the bug
+  /// reporter, in case of a found bug.
+  ///
+  /// \param FuncDecl current function visited
+  void setCurrentlyVisitedFunction(const clang::FunctionDecl *const FuncDecl);
+
+  /// Obtain function classifier instance used by MPICheckerAST.
+  /// \returns function classifier
+  const MPIFunctionClassifier &funcClassifier() { return FuncClassifier; }
+
+private:
+  /// Init MPI type container to recognize all MPI type defined by the standard.
+  void initMPITypeContainer();
+
+  /// Returns index pairs for each buffer, datatype pair.
+  ///
+  /// \param MPICallExpr MPI call to get the buffer, MPI datatypetype pairs for
+  IndexPairs
+  bufferDataTypeIndices(const clang::CallExpr *const MPICallExpr) const;
+
+  /// Return an array of indices that must be of integer type for a given
+  /// call.
+  ///
+  /// \param MPICallExpr MPI call to get the indices for
+  llvm::SmallVector<size_t, 1>
+  integerIndices(const clang::CallExpr *const) const;
+
+  /// Selects an appropriate function to match the buffer type against the
+  /// specified MPI datatype.
+  ///
+  /// \param TypeVis contains information about the buffer type
+  /// \param MPICallExpr buffer index pair is observed
+  /// \param MPIDatatypeString MPI datatype as string
+  /// \param IdxPair buffer, MPI datatype index pair
+  void selectTypeMatcher(const mpi::TypeVisitor &TypeVis,
+                         const clang::CallExpr *const MPICallExpr,
+                         const llvm::StringRef MPIDatatypeString,
+                         const std::pair<size_t, size_t> &IdxPair) const;
+  bool matchBoolType(const mpi::TypeVisitor &TypeVis,
+                     const llvm::StringRef MPIDatatype) const;
+  bool matchCharType(const mpi::TypeVisitor &TypeVis,
+                     const llvm::StringRef MPIDatatype) const;
+  bool matchSignedType(const mpi::TypeVisitor &TypeVis,
+                       const llvm::StringRef MPIDatatype) const;
+  bool matchUnsignedType(const mpi::TypeVisitor &TypeVis,
+                         const llvm::StringRef MPIDatatype) const;
+  bool matchFloatType(const mpi::TypeVisitor &TypeVis,
+                      const llvm::StringRef MPIDatatype) const;
+  bool matchComplexType(const mpi::TypeVisitor &TypeVis,
+                        const llvm::StringRef MPIDatatype) const;
+  bool matchExactWidthType(const mpi::TypeVisitor &TypeVis,
+                           const llvm::StringRef MPIDatatype) const;
+
+  MPIFunctionClassifier FuncClassifier;
+  llvm::SmallVector<std::string, 32> MPITypes;
+  MPIBugReporter BugReporter;
+  clang::ento::AnalysisManager &AnalysisManager;
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.cpp
@@ -0,0 +1,355 @@
+//===-- MPICheckerAST.cpp - AST-based checks for MPI ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines AST-based checks, to verify correct usage of the MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MPICheckerAST.h"
+
+namespace clang {
+namespace mpi {
+
+void MPICheckerAST::initMPITypeContainer() {
+  MPITypes = {"MPI_BYTE",
+              "MPI_C_BOOL",
+              "MPI_CHAR",
+              "MPI_SIGNED_CHAR",
+              "MPI_UNSIGNED_CHAR",
+              "MPI_WCHAR",
+              "MPI_INT",
+              "MPI_LONG",
+              "MPI_SHORT",
+              "MPI_LONG_LONG",
+              "MPI_LONG_LONG_INT",
+              "MPI_UNSIGNED",
+              "MPI_UNSIGNED_SHORT",
+              "MPI_UNSIGNED_LONG",
+              "MPI_UNSIGNED_LONG_LONG",
+              "MPI_FLOAT",
+              "MPI_DOUBLE",
+              "MPI_LONG_DOUBLE",
+              "MPI_C_COMPLEX",
+              "MPI_C_FLOAT_COMPLEX",
+              "MPI_C_DOUBLE_COMPLEX",
+              "MPI_C_LONG_DOUBLE_COMPLEX",
+              "MPI_INT8_T",
+              "MPI_INT16_T",
+              "MPI_INT32_T",
+              "MPI_INT64_T",
+              "MPI_UINT8_T",
+              "MPI_UINT16_T",
+              "MPI_UINT32_T",
+              "MPI_UINT64_T"};
+}
+
+void MPICheckerAST::checkBufferTypeMatch(
+    const clang::CallExpr *const MPICallExpr) const {
+  // one pair consists of {bufferIdx, MPIDatatypeIdx}
+  IndexPairs IdxPairs = bufferDataTypeIndices(MPICallExpr);
+
+  // for every buffer mpi-data pair in function
+  // check if their types match
+  for (const auto &IdxPair : IdxPairs) {
+    auto BufferType =
+        MPICallExpr->getArg(IdxPair.first)->IgnoreImpCasts()->getType();
+
+    // collect buffer type information
+    const mpi::TypeVisitor TypeVis{BufferType};
+
+    // get MPI datatype as string
+    StringRef MPIDatatypeString{util::sourceRangeAsStringRef(
+        MPICallExpr->getArg(IdxPair.second)->getSourceRange(),
+        AnalysisManager)};
+
+    // check if buffer is correctly referenced
+    if (TypeVis.pointerCount() != 1) {
+      BugReporter.reportIncorrectBufferReferencing(MPICallExpr, IdxPair.first,
+                                                   TypeVis.pointerCount());
+    }
+
+    // MPI_BYTE needs no matching
+    if (MPIDatatypeString == "MPI_BYTE")
+      return;
+
+    // if MPI type not known
+    if (!cont::contains(MPITypes, MPIDatatypeString))
+      return;
+
+    selectTypeMatcher(TypeVis, MPICallExpr, MPIDatatypeString, IdxPair);
+  }
+}
+
+MPICheckerAST::IndexPairs MPICheckerAST::bufferDataTypeIndices(
+    const clang::CallExpr *const MPICallExpr) const {
+  IndexPairs IdxPairs;
+
+  const IdentifierInfo *const Ident = util::getIdentInfo(MPICallExpr);
+
+  if (FuncClassifier.isPointToPointType(Ident)) {
+    IdxPairs.push_back({MPIPointToPoint::Buf, MPIPointToPoint::Datatype});
+  } else if (FuncClassifier.isCollectiveType(Ident)) {
+    if (FuncClassifier.isReduceType(Ident)) {
+      // only check buffer type if not inplace
+      if (util::sourceRangeAsStringRef(MPICallExpr->getArg(0)->getSourceRange(),
+                                       AnalysisManager) != "MPI_IN_PLACE") {
+        IdxPairs.push_back({0, 3});
+      }
+      IdxPairs.push_back({1, 3});
+    } else if (FuncClassifier.isScatterType(Ident) ||
+               FuncClassifier.isGatherType(Ident) ||
+               FuncClassifier.isAlltoallType(Ident)) {
+      IdxPairs.push_back({0, 2});
+      IdxPairs.push_back({3, 5});
+    } else if (FuncClassifier.isBcastType(Ident)) {
+      IdxPairs.push_back({0, 2});
+    }
+  }
+  return IdxPairs;
+}
+
+void MPICheckerAST::selectTypeMatcher(
+    const mpi::TypeVisitor &TypeVis, const clang::CallExpr *const MPICallExpr,
+    const StringRef MPIDatatypeString,
+    const std::pair<size_t, size_t> &IdxPair) const {
+  const clang::BuiltinType *BuiltinTy = TypeVis.builtinType();
+  bool IsTypeMatching{true};
+
+  // check for exact width types (e.g. int16_t, uint32_t)
+  if (TypeVis.isTypedefType()) {
+    IsTypeMatching = matchExactWidthType(TypeVis, MPIDatatypeString);
+  }
+  // check for complex-floating types (e.g. float _Complex)
+  else if (TypeVis.isComplexType()) {
+    IsTypeMatching = matchComplexType(TypeVis, MPIDatatypeString);
+  }
+  // check for basic builtin types (e.g. int, char)
+  else if (!BuiltinTy) {
+    return; // if no builtin type cancel checking
+  } else if (BuiltinTy->isBooleanType()) {
+    IsTypeMatching = matchBoolType(TypeVis, MPIDatatypeString);
+  } else if (BuiltinTy->isAnyCharacterType()) {
+    IsTypeMatching = matchCharType(TypeVis, MPIDatatypeString);
+  } else if (BuiltinTy->isSignedInteger()) {
+    IsTypeMatching = matchSignedType(TypeVis, MPIDatatypeString);
+  } else if (BuiltinTy->isUnsignedIntegerType()) {
+    IsTypeMatching = matchUnsignedType(TypeVis, MPIDatatypeString);
+  } else if (BuiltinTy->isFloatingType()) {
+    IsTypeMatching = matchFloatType(TypeVis, MPIDatatypeString);
+  }
+
+  if (!IsTypeMatching)
+    BugReporter.reportTypeMismatch(MPICallExpr, IdxPair, TypeVis.InspectedType,
+                                   MPIDatatypeString);
+}
+
+bool MPICheckerAST::matchBoolType(const mpi::TypeVisitor &TypeVis,
+                                  const llvm::StringRef MPIDatatype) const {
+  return (MPIDatatype == "MPI_C_BOOL");
+}
+
+bool MPICheckerAST::matchCharType(const mpi::TypeVisitor &TypeVis,
+                                  const llvm::StringRef MPIDatatype) const {
+  bool IsTypeMatching;
+  switch (TypeVis.builtinType()->getKind()) {
+  case BuiltinType::SChar:
+    IsTypeMatching =
+        (MPIDatatype == "MPI_CHAR" || MPIDatatype == "MPI_SIGNED_CHAR");
+    break;
+  case BuiltinType::Char_S:
+    IsTypeMatching =
+        (MPIDatatype == "MPI_CHAR" || MPIDatatype == "MPI_SIGNED_CHAR");
+    break;
+  case BuiltinType::UChar:
+    IsTypeMatching = (MPIDatatype == "MPI_UNSIGNED_CHAR");
+    break;
+  case BuiltinType::Char_U:
+    IsTypeMatching = (MPIDatatype == "MPI_UNSIGNED_CHAR");
+    break;
+  case BuiltinType::WChar_S:
+    IsTypeMatching = (MPIDatatype == "MPI_WCHAR");
+    break;
+  case BuiltinType::WChar_U:
+    IsTypeMatching = (MPIDatatype == "MPI_WCHAR");
+    break;
+
+  default:
+    IsTypeMatching = true;
+  }
+
+  return IsTypeMatching;
+}
+
+bool MPICheckerAST::matchSignedType(const mpi::TypeVisitor &TypeVis,
+                                    const llvm::StringRef MPIDatatype) const {
+  bool IsTypeMatching;
+
+  switch (TypeVis.builtinType()->getKind()) {
+  case BuiltinType::Int:
+    IsTypeMatching = (MPIDatatype == "MPI_INT");
+    break;
+  case BuiltinType::Long:
+    IsTypeMatching = (MPIDatatype == "MPI_LONG");
+    break;
+  case BuiltinType::Short:
+    IsTypeMatching = (MPIDatatype == "MPI_SHORT");
+    break;
+  case BuiltinType::LongLong:
+    IsTypeMatching =
+        (MPIDatatype == "MPI_LONG_LONG" || MPIDatatype == "MPI_LONG_LONG_INT");
+    break;
+  default:
+    IsTypeMatching = true;
+  }
+
+  return IsTypeMatching;
+}
+
+bool MPICheckerAST::matchUnsignedType(const mpi::TypeVisitor &TypeVis,
+                                      const llvm::StringRef MPIDatatype) const {
+  bool IsTypeMatching;
+
+  switch (TypeVis.builtinType()->getKind()) {
+  case BuiltinType::UInt:
+    IsTypeMatching = (MPIDatatype == "MPI_UNSIGNED");
+    break;
+  case BuiltinType::UShort:
+    IsTypeMatching = (MPIDatatype == "MPI_UNSIGNED_SHORT");
+    break;
+  case BuiltinType::ULong:
+    IsTypeMatching = (MPIDatatype == "MPI_UNSIGNED_LONG");
+    break;
+  case BuiltinType::ULongLong:
+    IsTypeMatching = (MPIDatatype == "MPI_UNSIGNED_LONG_LONG");
+    break;
+
+  default:
+    IsTypeMatching = true;
+  }
+  return IsTypeMatching;
+}
+
+bool MPICheckerAST::matchFloatType(const mpi::TypeVisitor &TypeVis,
+                                   const llvm::StringRef MPIDatatype) const {
+  bool IsTypeMatching;
+
+  switch (TypeVis.builtinType()->getKind()) {
+  case BuiltinType::Float:
+    IsTypeMatching = (MPIDatatype == "MPI_FLOAT");
+    break;
+  case BuiltinType::Double:
+    IsTypeMatching = (MPIDatatype == "MPI_DOUBLE");
+    break;
+  case BuiltinType::LongDouble:
+    IsTypeMatching = (MPIDatatype == "MPI_LONG_DOUBLE");
+    break;
+  default:
+    IsTypeMatching = true;
+  }
+  return IsTypeMatching;
+}
+
+bool MPICheckerAST::matchComplexType(const mpi::TypeVisitor &TypeVis,
+                                     const llvm::StringRef MPIDatatype) const {
+  bool IsTypeMatching;
+
+  switch (TypeVis.builtinType()->getKind()) {
+  case BuiltinType::Float:
+    IsTypeMatching = (MPIDatatype == "MPI_C_COMPLEX" ||
+                      MPIDatatype == "MPI_C_FLOAT_COMPLEX");
+    break;
+  case BuiltinType::Double:
+    IsTypeMatching = (MPIDatatype == "MPI_C_DOUBLE_COMPLEX");
+    break;
+  case BuiltinType::LongDouble:
+    IsTypeMatching = (MPIDatatype == "MPI_C_LONG_DOUBLE_COMPLEX");
+    break;
+  default:
+    IsTypeMatching = true;
+  }
+
+  return IsTypeMatching;
+}
+
+bool MPICheckerAST::matchExactWidthType(
+    const mpi::TypeVisitor &TypeVis, const llvm::StringRef MPIDatatype) const {
+  // check typedef type match
+  // no break needs to be specified for string switch
+  bool IsTypeMatching = llvm::StringSwitch<bool>(TypeVis.typedefTypeName())
+                            .Case("int8_t", (MPIDatatype == "MPI_INT8_T"))
+                            .Case("int16_t", (MPIDatatype == "MPI_INT16_T"))
+                            .Case("int32_t", (MPIDatatype == "MPI_INT32_T"))
+                            .Case("int64_t", (MPIDatatype == "MPI_INT64_T"))
+
+                            .Case("uint8_t", (MPIDatatype == "MPI_UINT8_T"))
+                            .Case("uint16_t", (MPIDatatype == "MPI_UINT16_T"))
+                            .Case("uint32_t", (MPIDatatype == "MPI_UINT32_T"))
+                            .Case("uint64_t", (MPIDatatype == "MPI_UINT64_T"))
+                            // unknown typedefs are rated as correct
+                            .Default(true);
+
+  return IsTypeMatching;
+}
+
+void MPICheckerAST::checkForInvalidArgs(
+    const clang::CallExpr *const MPICallExpr) const {
+  llvm::SmallVector<size_t, 1> IndicesToCheck{integerIndices(MPICallExpr)};
+  if (!IndicesToCheck.size())
+    return;
+
+  // iterate indices which should not have integer arguments
+  for (const size_t Idx : IndicesToCheck) {
+    if (!MPICallExpr->getArg(Idx)
+             ->IgnoreImpCasts()
+             ->getType()
+             ->isIntegerType()) {
+      BugReporter.reportInvalidArgumentType(MPICallExpr, Idx);
+    }
+  }
+}
+
+llvm::SmallVector<size_t, 1>
+MPICheckerAST::integerIndices(const clang::CallExpr *const MPICallExpr) const {
+  llvm::SmallVector<size_t, 1> IntIndices;
+
+  const IdentifierInfo *const Ident = util::getIdentInfo(MPICallExpr);
+
+  if (FuncClassifier.isPointToPointType(Ident)) {
+    IntIndices = {MPIPointToPoint::Count, MPIPointToPoint::Rank,
+                  MPIPointToPoint::Tag};
+  } else if (FuncClassifier.isScatterType(Ident) ||
+             FuncClassifier.isGatherType(Ident)) {
+    if (FuncClassifier.isAllgatherType(Ident)) {
+      IntIndices = {1, 4};
+    } else {
+      IntIndices = {1, 4, 6};
+    }
+  } else if (FuncClassifier.isAlltoallType(Ident)) {
+    IntIndices = {1, 4};
+  } else if (FuncClassifier.isReduceType(Ident)) {
+    if (FuncClassifier.isCollToColl(Ident)) {
+      IntIndices = {2};
+    } else {
+      IntIndices = {2, 5};
+    }
+  } else if (FuncClassifier.isBcastType(Ident)) {
+    IntIndices = {1, 3};
+  }
+
+  return IntIndices;
+}
+
+void MPICheckerAST::setCurrentlyVisitedFunction(
+    const clang::FunctionDecl *const FuncDecl) {
+  BugReporter.CurrentFunctionDecl = FuncDecl;
+}
+
+} // end of namespace: mpi
+} // end of namespace: clang
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
@@ -0,0 +1,71 @@
+//===-- MPIChecker.cpp - Checker Entry Point Class --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines the main class of MPI-Checker which serves as an entry
+/// point. It is created once for each translation unit analysed.
+///
+//===----------------------------------------------------------------------===//
+
+#include "../ClangSACheckers.h"
+#include "TranslationUnitVisitor.h"
+#include "MPICheckerPathSensitive.h"
+
+using namespace clang::ento;
+
+namespace clang {
+namespace mpi {
+class MPIChecker : public Checker<check::ASTDecl<TranslationUnitDecl>,
+                                  check::PreCall, check::EndFunction> {
+public:
+  // ast callback–––––––––––––––––––––––––––––––––––––––––––––––––––––––
+  void checkASTDecl(const TranslationUnitDecl *TuDecl, AnalysisManager &AM,
+                    BugReporter &BR) const {
+
+    // traverse translation unit
+    TranslationUnitVisitor TuVisitor{BR, *this, AM};
+    TuVisitor.TraverseTranslationUnitDecl(
+        const_cast<TranslationUnitDecl *>(TuDecl));
+  }
+
+  // path-sensitive callbacks––––––––––––––––––––––––––––––––––––––––––––
+  void checkPreCall(const CallEvent &CE, CheckerContext &Ctx) const {
+    dynamicInit(Ctx);
+    CheckerSens->checkWaitUsage(CE, Ctx);
+    CheckerSens->checkDoubleNonblocking(CE, Ctx);
+  }
+
+  void checkEndFunction(CheckerContext &Ctx) const {
+    // true if the current LocationContext has no caller context
+    if (Ctx.inTopFrame()) {
+      dynamicInit(Ctx);
+      CheckerSens->checkMissingWaits(Ctx);
+      CheckerSens->clearRequests(Ctx);
+    }
+  }
+
+private:
+  const std::unique_ptr<MPICheckerPathSensitive> CheckerSens;
+
+  void dynamicInit(CheckerContext &Ctx) const {
+    if (!CheckerSens) {
+      const_cast<std::unique_ptr<MPICheckerPathSensitive> &>(CheckerSens)
+          .reset(new MPICheckerPathSensitive(Ctx.getAnalysisManager(), this,
+                                             Ctx.getBugReporter()));
+    }
+  }
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+// registers the checker for static analysis.
+void clang::ento::registerMPIChecker(CheckerManager &MGR) {
+  MGR.registerChecker<clang::mpi::MPIChecker>();
+}
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
@@ -0,0 +1,132 @@
+//===-- MPIBugReporter.h - bug reporter -----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines prefabricated reports which are emitted in
+/// case of MPI related bugs, detected by AST-based and path-sensitive analysis.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIBUGREPORTER_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIBUGREPORTER_H
+
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "MPITypes.h"
+
+namespace clang {
+namespace mpi {
+
+class MPIBugReporter {
+public:
+  MPIBugReporter(clang::ento::BugReporter &BR,
+                 const clang::ento::CheckerBase &CB,
+                 clang::ento::AnalysisManager &AM)
+      : BugReporter{BR}, CkrBase{CB}, AnalysisManager{AM} {
+    DoubleWaitBugType.reset(
+        new clang::ento::BugType(&CB, "double wait", "MPI Error"));
+    UnmatchedWaitBugType.reset(
+        new clang::ento::BugType(&CB, "unmatched wait", "MPI Error"));
+    DoubleNonblockingBugType.reset(
+        new clang::ento::BugType(&CB, "double nonblocking", "MPI Error"));
+    MissingWaitBugType.reset(
+        new clang::ento::BugType(&CB, "missing wait", "MPI Error"));
+  }
+
+  // ast reports ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
+
+  /// Reports mismatch between buffer type and MPI datatype.
+  ///
+  /// \param MPICallExpr MPI call to report the mismatch for
+  /// \param IdxPair buffer type, MPI type index pair of the mismatch
+  /// \param BufferType buffer type
+  /// \param MPIType MPI datatype as string
+  void reportTypeMismatch(const clang::CallExpr *MPICallExpr,
+                          const std::pair<size_t, size_t> &IdxPair,
+                          clang::QualType BufferType,
+                          std::string MPIType) const;
+
+  /// Report if a buffer is not passed as a single pointer.
+  ///
+  /// \param MPICallExpr MPI call to report incorrect buffer referencing for
+  /// \param Idx index of incorrectly referenced buffer
+  /// \param PointerCount pointer count
+  void reportIncorrectBufferReferencing(const clang::CallExpr *MPICallExpr,
+                                        size_t Idx, size_t PointerCount) const;
+
+  /// Report non-integer value usage at indices where not allowed. (e.g. rank)
+  ///
+  /// \param MPICallExpr MPI call to report the invalid argument type for
+  /// \param Idx argument index of invalid argument type
+  void reportInvalidArgumentType(const clang::CallExpr *const MPICallExpr,
+                                 const size_t Idx) const;
+
+  // path sensitive reports –––––––––––––––––––––––––––––––––––––––––––––––
+
+  /// Report duplicate request use by waits in sequence without intermediate
+  /// nonblocking call.
+  ///
+  /// \param MPICallExpr MPI call that caused the double wait
+  /// \param Req request that was used by two waits in sequence
+  /// \param ExplNode node in the graph the bug appeared at
+  void reportDoubleWait(const clang::ento::CallEvent &MPICallExpr,
+                        const Request &Req,
+                        const clang::ento::ExplodedNode *const ExplNode) const;
+
+  /// Report duplicate request use by nonblocking calls without intermediate
+  /// wait.
+  ///
+  /// \param MPICallExpr MPI call that caused the double nonblocking
+  /// \param Req request that was used by two nonblocking calls in sequence
+  /// \param ExplNode node in the graph the bug appeared at
+  void reportDoubleNonblocking(
+      const clang::ento::CallEvent &MPICallExpr, const Request &Req,
+      const clang::ento::ExplodedNode *const ExplNode) const;
+
+  /// Report a missing wait for a nonblocking call. A missing wait report
+  /// is emitted if a nonblocking call is matched in the scope of a function.
+  ///
+  /// \param Req request that is not matched by a wait
+  /// \param ExplNode node in the graph the bug appeared at
+  void reportMissingWait(const Request &Req,
+                         const clang::ento::ExplodedNode *const ExplNode) const;
+
+  /// Report a wait on a request that has not been used at all before.
+  ///
+  /// \param CE wait call that uses the request
+  /// \param ReqRegion memory region of the request
+  /// \param ExplNode node in the graph the bug appeared at
+  void
+  reportUnmatchedWait(const clang::ento::CallEvent &CE,
+                      const clang::ento::MemRegion *const ReqRegion,
+                      const clang::ento::ExplodedNode *const ExplNode) const;
+
+  const clang::Decl *CurrentFunctionDecl = nullptr;
+
+private:
+  /// Get line number for call event reference.
+  ///
+  /// \param CEREf call event reference
+  /// \returns line number as string
+  std::string lineNumber(const clang::ento::CallEventRef<> CERef) const;
+
+  // path-sensitive bug types
+  std::unique_ptr<clang::ento::BugType> UnmatchedWaitBugType;
+  std::unique_ptr<clang::ento::BugType> MissingWaitBugType;
+  std::unique_ptr<clang::ento::BugType> DoubleWaitBugType;
+  std::unique_ptr<clang::ento::BugType> DoubleNonblockingBugType;
+
+  clang::ento::BugReporter &BugReporter;
+  const clang::ento::CheckerBase &CkrBase;
+  clang::ento::AnalysisManager &AnalysisManager;
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
@@ -0,0 +1,184 @@
+//===-- MPIBugReporter.cpp - bug reporter -----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines prefabricated reports which are emitted in
+/// case of MPI related bugs, detected by AST-based and path-sensitive analysis.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "MPIBugReporter.h"
+#include "Utility.h"
+
+using namespace clang::ento;
+
+namespace clang {
+namespace mpi {
+
+const std::string MPIError{"MPI Error"};
+const std::string MPIWarning{"MPI Warning"};
+
+std::string MPIBugReporter::lineNumber(const CallEventRef<> CERef) const {
+  std::string LineNo = CERef->getSourceRange().getBegin().printToString(
+      BugReporter.getSourceManager());
+
+  // split written string into parts
+  std::vector<std::string> Strs = util::split(LineNo, ':');
+  return util::split(LineNo, ':').at(Strs.size() - 2);
+}
+
+// bug reports ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
+
+// ast reports ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
+void MPIBugReporter::reportTypeMismatch(
+    const CallExpr *MPICallExpr, const std::pair<size_t, size_t> &IdxPair,
+    clang::QualType BufferType, std::string MPIType) const {
+  auto ADC = AnalysisManager.getAnalysisDeclContext(CurrentFunctionDecl);
+  PathDiagnosticLocation Location = PathDiagnosticLocation::createBegin(
+      MPICallExpr, BugReporter.getSourceManager(), ADC);
+
+  // deref buffer type
+  while (BufferType->isPointerType()) {
+    BufferType = BufferType->getPointeeType();
+  }
+  // remove qualifiers
+  BufferType = BufferType.getUnqualifiedType();
+
+  SourceRange MPICallExprRange = MPICallExpr->getCallee()->getSourceRange();
+  std::string BT{"type mismatch"};
+  std::string ErrorText{"Buffer type '" + BufferType.getAsString() +
+                        +"' and specified MPI type '" + MPIType +
+                        "' do not match. "};
+
+  llvm::SmallVector<SourceRange, 3> SourceRanges;
+  SourceRanges.push_back(MPICallExprRange);
+  SourceRanges.push_back(MPICallExpr->getArg(IdxPair.first)->getSourceRange());
+  SourceRanges.push_back(MPICallExpr->getArg(IdxPair.second)->getSourceRange());
+
+  BugReporter.EmitBasicReport(ADC->getDecl(), &CkrBase, BT, MPIError, ErrorText,
+                              Location, SourceRanges);
+}
+
+void MPIBugReporter::reportIncorrectBufferReferencing(
+    const CallExpr *MPICallExpr, size_t Idx, size_t PointerCount) const {
+  auto ADC = AnalysisManager.getAnalysisDeclContext(CurrentFunctionDecl);
+  PathDiagnosticLocation Location = PathDiagnosticLocation::createBegin(
+      MPICallExpr, BugReporter.getSourceManager(), ADC);
+
+  SourceRange MPICallExprRange = MPICallExpr->getCallee()->getSourceRange();
+  std::string BT{"incorrect buffer referencing"};
+  std::string ErrorText{
+      "Buffer is not correctly dereferenced. It is passed as a " +
+      std::string(PointerCount, '*') + " pointer. "};
+
+  llvm::SmallVector<SourceRange, 2> SourceRanges;
+  SourceRanges.push_back(MPICallExprRange);
+  SourceRanges.push_back(MPICallExpr->getArg(Idx)->getSourceRange());
+
+  BugReporter.EmitBasicReport(ADC->getDecl(), &CkrBase, BT, MPIError, ErrorText,
+                              Location, SourceRanges);
+}
+
+void MPIBugReporter::reportInvalidArgumentType(
+    const CallExpr *const MPICallExpr, const size_t Idx) const {
+  auto ADC = AnalysisManager.getAnalysisDeclContext(CurrentFunctionDecl);
+  PathDiagnosticLocation Location = PathDiagnosticLocation::createBegin(
+      MPICallExpr, BugReporter.getSourceManager(), ADC);
+
+  std::string IndexAsString{std::to_string(Idx)};
+  SourceRange MPICallExprRange = MPICallExpr->getCallee()->getSourceRange();
+  std::string BT{"invalid argument type"};
+  std::string ErrorText{"The type, argument at index " + IndexAsString +
+                        " evaluates to, is not an integer type. "};
+
+  SmallVector<SourceRange, 3> SourceRanges;
+  SourceRanges.push_back(MPICallExprRange);
+  SourceRanges.push_back(MPICallExpr->getArg(Idx)->getSourceRange());
+  BugReporter.EmitBasicReport(ADC->getDecl(), &CkrBase, BT, MPIError, ErrorText,
+                              Location, SourceRanges);
+}
+
+// path sensitive reports –––––––––––––––––––––––––––––––––––––––––––––––––
+void MPIBugReporter::reportDoubleWait(
+    const CallEvent &MPICallExpr, const Request &Req,
+    const ExplodedNode *const ExplNode) const {
+  std::string LineNo{lineNumber(Req.LastUser)};
+  std::string LastUser = Req.LastUser->getCalleeIdentifier()->getName();
+  std::string ErrorText{"Request '" + Req.variableName() +
+                        "' is already waited upon by '" + LastUser +
+                        "' in line " + LineNo + ". "};
+
+  auto Report =
+      llvm::make_unique<BugReport>(*DoubleWaitBugType, ErrorText, ExplNode);
+  Report->addRange(MPICallExpr.getSourceRange());
+  Report->addRange(Req.LastUser->getSourceRange());
+  SourceRange Range = util::sourceRange(Req.MR);
+  if (Range.isValid())
+    Report->addRange(Range);
+  BugReporter.emitReport(std::move(Report));
+}
+
+void MPIBugReporter::reportDoubleNonblocking(
+    const CallEvent &MPICallExpr, const Request &Req,
+    const ExplodedNode *const ExplNode) const {
+  std::string LineNo{lineNumber(Req.LastUser)};
+
+  std::string LastUser = Req.LastUser->getCalleeIdentifier()->getName();
+
+  std::string ErrorText{"Request '" + Req.variableName() +
+                        "' is already in use by nonblocking call '" + LastUser +
+                        "' in line " + LineNo + ". "};
+
+  auto Report = llvm::make_unique<BugReport>(*DoubleNonblockingBugType,
+                                             ErrorText, ExplNode);
+  Report->addRange(MPICallExpr.getSourceRange());
+  Report->addRange(Req.LastUser->getSourceRange());
+  SourceRange Range = util::sourceRange(Req.MR);
+  if (Range.isValid())
+    Report->addRange(Range);
+  BugReporter.emitReport(std::move(Report));
+}
+
+void MPIBugReporter::reportMissingWait(
+    const Request &Req, const ExplodedNode *const ExplNode) const {
+  std::string LineNo{lineNumber(Req.LastUser)};
+  std::string LastUser = Req.LastUser->getCalleeIdentifier()->getName();
+
+  std::string ErrorText{
+      "'" + LastUser + "' in line " + LineNo + ", using request '" +
+      Req.variableName() +
+      "', has no matching wait in the scope of this function. "};
+
+  auto Report =
+      llvm::make_unique<BugReport>(*MissingWaitBugType, ErrorText, ExplNode);
+  Report->addRange(Req.LastUser->getSourceRange());
+  SourceRange Range = util::sourceRange(Req.MR);
+  if (Range.isValid())
+    Report->addRange(Range);
+  BugReporter.emitReport(std::move(Report));
+}
+
+void MPIBugReporter::reportUnmatchedWait(
+    const CallEvent &CE, const clang::ento::MemRegion *const ReqRegion,
+    const ExplodedNode *const ExplNode) const {
+  std::string ErrorText{"Request '" + util::variableName(ReqRegion) +
+                        "' has no matching nonblocking call. "};
+
+  auto Report =
+      llvm::make_unique<BugReport>(*UnmatchedWaitBugType, ErrorText, ExplNode);
+  Report->addRange(CE.getSourceRange());
+  SourceRange Range = util::sourceRange(ReqRegion);
+  if (Range.isValid())
+    Report->addRange(Range);
+  BugReporter.emitReport(std::move(Report));
+}
+
+} // end of namespace: mpi
+} // end of namespace: clang
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Container.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Container.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Container.h
@@ -0,0 +1,31 @@
+//===-- Container.h - convenience templates for containers ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines convenience templates for C++ container class usage.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_CONTAINER_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_CONTAINER_H
+
+#include <algorithm>
+
+namespace cont {
+
+/// Returns true if \p Container contains \p Element.
+template <typename T, typename E>
+bool contains(const T &Container, const E &Element) {
+  return std::find(Container.begin(), Container.end(), Element) !=
+         Container.end();
+}
+
+} // end of namespace: cont
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
+++ tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -27,6 +27,8 @@
 def DeadCode : Package<"deadcode">;
 def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden;
 
+def MPI : Package<"mpi">;
+
 def Security : Package <"security">;
 def InsecureAPI : Package<"insecureAPI">, InPackage<Security>;
 def SecurityAlpha : Package<"security">, InPackage<Alpha>, Hidden;
@@ -516,6 +518,13 @@
   DescFile<"ObjCContainersChecker.cpp">;
 
 }
+
+let ParentPackage = MPI in {
+def MPIChecker : Checker<"MPI-Checker">,
+  HelpText<"Checks MPI code written in C">,
+  DescFile<"MPIChecker.cpp">;
+} // end "MPI"
+
 //===----------------------------------------------------------------------===//
 // Checkers for LLVM development.
 //===----------------------------------------------------------------------===//
Index: tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -45,6 +45,13 @@
   MallocChecker.cpp
   MallocOverflowSecurityChecker.cpp
   MallocSizeofChecker.cpp
+  MPI-Checker/MPIBugReporter.cpp
+  MPI-Checker/MPIChecker.cpp
+  MPI-Checker/MPICheckerAST.cpp
+  MPI-Checker/MPICheckerPathSensitive.cpp
+  MPI-Checker/MPIFunctionClassifier.cpp
+  MPI-Checker/TranslationUnitVisitor.cpp
+  MPI-Checker/Utility.cpp
   NSAutoreleasePoolChecker.cpp
   NSErrorChecker.cpp
   NoReturnFunctionChecker.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to