MPI-Checker patch for Clang Static Analyzer

Alexander Droste via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 9 05:34:25 PDT 2015


Hi,

this is a patch to add static analysis functionality for MPI code
written in C, in form of a checker to Clang's Static Analyzer. In comparison
to the code currently published on GitHub https://github.com/0ax1/MPI-Checker
I excluded the

unmatched point-to-point call check,
unreachable call check &
collective call in rank branch check

as I do not consider them to be solid enough, to be included
in the patch. These will be rewritten. I'm aware that the
invalid argument type, checking for expressions that evaluate to
a non-integer type, in some way is redundant to the compiler warning
produced by -Wfloat-conversion. My thought about this is that
it might be nice to get informed about this in context of other
MPI related bugs. Further, the -Wfloat-conversion flag seems a little bit
hidden as it is neither included in -Wall nor in -Wextra which is
why some users might not have enabled it by default.

The patch consists of three parts: The actual code for static analysis
contained in tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/,
unit tests in tools/clang/unittests/StaticAnalyzer/MPI-Checker/
and the integration tests I put into tools/clang/test/Analysis/MPIChecker.c.

Best regards,
Alex



-------------- next part --------------
Index: tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt	(revision 247122)
+++ tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt	(working copy)
@@ -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
Index: tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td	(revision 247122)
+++ tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td	(working copy)
@@ -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/MPI-Checker/Container.hpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Container.hpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Container.hpp	(working copy)
@@ -0,0 +1,166 @@
+//===-- Container.hpp - 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
+/// Convenience templates for C++ container classes.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef CONTAINER_HPP_XM1FDRVJ
+#define CONTAINER_HPP_XM1FDRVJ
+
+#include <algorithm>
+
+namespace cont {
+
+/// \brief Check if given element is contained.
+///
+/// \param container
+/// \param elementToCheck
+///
+/// \returns true if element contained
+template <typename T, typename E>
+bool isContained(const T &container, const E &elementToCheck) {
+  return std::find(container.begin(), container.end(), elementToCheck) !=
+         container.end();
+}
+
+/// \brief Check if given element is contained.
+///
+/// \param container
+/// \param elementToCheck
+///
+/// \returns true if element that matched predicate is contained
+template <typename T, typename P>
+bool isContainedPred(const T &container, P predicate) {
+  return std::find_if(container.begin(), container.end(), predicate) !=
+         container.end();
+}
+
+/// \brief Deletes first appearance of given element.
+///
+/// \param container
+/// \param elementToErase
+template <typename T, typename E> void erase(T &container, E &elementToErase) {
+  auto it = std::find(container.begin(), container.end(), elementToErase);
+  if (it != container.end())
+    container.erase(it);
+}
+
+/// \brief Deletes all appearances of given element.
+///
+/// \param container
+/// \param elementToErase
+template <typename T, typename E>
+void eraseAll(T &container, E &elementToErase) {
+  container.erase(
+      std::remove(container.begin(), container.end(), elementToErase),
+      container.end());
+}
+
+/// \brief Deletes first appearance of given pointer.
+///
+/// \param container
+/// \param elementToErase
+template <typename T, typename E>
+void erasePtr(T &container, E elementToErase) {
+  auto it = std::find(container.begin(), container.end(), elementToErase);
+  if (it != container.end())
+    container.erase(it);
+}
+
+/// \brief Deletes first element that matches the predicate.
+///
+/// \param container
+/// \param predicate
+template <typename T, typename P> void erasePred(T &container, P predicate) {
+  auto it = std::find_if(container.begin(), container.end(), predicate);
+  if (it != container.end())
+    container.erase(it);
+}
+
+/// \brief Deletes element at given index.
+///
+/// \param container
+/// \param index
+template <typename T> void eraseIndex(T &container, size_t idx) {
+  container.erase(container.begin() + idx);
+}
+
+/// \brief Sort with default criterion.
+///
+/// \param container
+template <typename T> void sort(T &container) {
+  std::sort(container.begin(), container.end());
+}
+
+/// \brief Sort with given predicate.
+///
+/// \param container
+/// \param predicate
+template <typename T, typename P> void sortPred(T &container, P predicate) {
+  std::sort(container.begin(), container.end(), predicate);
+}
+
+/// \brief Get index for element in container.
+///
+/// \param container
+/// \param element
+/// \returns index of first found element
+template <typename T, typename E>
+size_t index(const T &container, const E &element) {
+  return std::find(container.begin(), container.end(), element) -
+         container.begin();
+}
+
+/// \brief Get index for predicate.
+///
+/// \param container
+/// \param predicate
+/// \returns index of first found element
+template <typename T, typename P>
+size_t indexPred(const T &container, P predicate) {
+  return std::find_if(container.begin(), container.end(), predicate) -
+         container.begin();
+}
+
+/// \brief Copy elements from one container to another.
+///
+/// \param source
+/// \param dest
+template <typename T, typename T2> void copy(const T &source, T2 &dest) {
+  std::copy(source.begin(), source.end(), std::back_inserter(dest));
+}
+
+/// \brief Find an element by predicate. Return an iterator.
+///
+/// \param container
+/// \param predicate
+/// \returns iterator to found element
+template <typename T, typename P>
+typename T::iterator findPred(T &cont, P pred) {
+  return std::find_if(cont.begin(), cont.end(), pred);
+}
+
+/// \brief Checks if two containers are permutations of each other.
+///
+/// \tparam T1 type of container 1
+/// \tparam T2 type of container 2
+/// \param first container
+/// \param second container
+///
+/// \returns isPermutation
+template <typename T1, typename T2>
+bool isPermutation(const T1 &first, const T2 &second) {
+  return std::is_permutation(first.begin(), first.end(), second.begin());
+}
+
+} // end of namespace: cont
+
+#endif // end of include guard: CONTAINER_HPP_XM1FDRVJ
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp	(working copy)
@@ -0,0 +1,185 @@
+//===-- 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
+/// Used to emit bug reports for violated invariants detected by AST-based and
+/// path-sensitive analysis.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "MPIBugReporter.hpp"
+#include "Utility.hpp"
+
+using namespace clang;
+using namespace ento;
+
+namespace mpi {
+
+const std::string MPIError{"MPI Error"};
+const std::string MPIWarning{"MPI Warning"};
+
+std::string
+MPIBugReporter::lineNumber(const CallEventRef<> callEventRef) const {
+  std::string lineNo = callEventRef->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 *callExpr, const std::pair<size_t, size_t> &idxPair,
+    clang::QualType bufferType, std::string mpiType) const {
+  auto adc = analysisManager_.getAnalysisDeclContext(currentFunctionDecl_);
+  PathDiagnosticLocation location = PathDiagnosticLocation::createBegin(
+      callExpr, bugReporter_.getSourceManager(), adc);
+
+  // deref buffer type
+  while (bufferType->isPointerType()) {
+    bufferType = bufferType->getPointeeType();
+  }
+  // remove qualifiers
+  bufferType = bufferType.getUnqualifiedType();
+
+  SourceRange callRange = callExpr->getCallee()->getSourceRange();
+  std::string bugType{"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(callRange);
+  sourceRanges.push_back(callExpr->getArg(idxPair.first)->getSourceRange());
+  sourceRanges.push_back(callExpr->getArg(idxPair.second)->getSourceRange());
+
+  bugReporter_.EmitBasicReport(adc->getDecl(), &checkerBase_, bugType, MPIError,
+                               errorText, location, sourceRanges);
+}
+
+void MPIBugReporter::reportIncorrectBufferReferencing(
+    const CallExpr *callExpr, const std::pair<size_t, size_t> &idxPair,
+    clang::QualType bufferType, size_t pointerCount) const {
+  auto adc = analysisManager_.getAnalysisDeclContext(currentFunctionDecl_);
+  PathDiagnosticLocation location = PathDiagnosticLocation::createBegin(
+      callExpr, bugReporter_.getSourceManager(), adc);
+
+  SourceRange callRange = callExpr->getCallee()->getSourceRange();
+  std::string bugType{"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(callRange);
+  sourceRanges.push_back(callExpr->getArg(idxPair.first)->getSourceRange());
+
+  bugReporter_.EmitBasicReport(adc->getDecl(), &checkerBase_, bugType, MPIError,
+                               errorText, location, sourceRanges);
+}
+
+void MPIBugReporter::reportInvalidArgumentType(const CallExpr *const callExpr,
+                                               const size_t idx) const {
+  auto d = analysisManager_.getAnalysisDeclContext(currentFunctionDecl_);
+  PathDiagnosticLocation location = PathDiagnosticLocation::createBegin(
+      callExpr, bugReporter_.getSourceManager(), d);
+
+  std::string indexAsString{std::to_string(idx)};
+  SourceRange callExprRange = callExpr->getCallee()->getSourceRange();
+  std::string bugType{"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(callExprRange);
+  sourceRanges.push_back(callExpr->getArg(idx)->getSourceRange());
+  bugReporter_.EmitBasicReport(d->getDecl(), &checkerBase_, bugType, MPIError,
+                               errorText, location, sourceRanges);
+}
+
+// path sensitive reports –––––––––––––––––––––––––––––––––––––––––––––––––
+void MPIBugReporter::reportDoubleNonblocking(
+    const CallEvent &observedCall, const Request &request,
+    const ExplodedNode *const node) const {
+  std::string lineNo{lineNumber(request.lastUser_)};
+
+  std::string lastUser = request.lastUser_->getCalleeIdentifier()->getName();
+
+  std::string errorText{"Request '" + request.variableName() +
+                        "' is already in use by nonblocking call '" + lastUser +
+                        "' in line " + lineNo + ". "};
+
+  auto bugReport =
+      llvm::make_unique<BugReport>(*doubleNonblockingBugType_, errorText, node);
+  bugReport->addRange(observedCall.getSourceRange());
+  bugReport->addRange(request.lastUser_->getSourceRange());
+  SourceRange r = util::sourceRange(request.memRegion_);
+  if (r.isValid())
+    bugReport->addRange(r);
+  bugReporter_.emitReport(std::move(bugReport));
+}
+
+void MPIBugReporter::reportDoubleWait(const CallEvent &observedCall,
+                                      const Request &request,
+                                      const ExplodedNode *const node) const {
+  std::string lineNo{lineNumber(request.lastUser_)};
+  std::string lastUser = request.lastUser_->getCalleeIdentifier()->getName();
+  std::string errorText{"Request '" + request.variableName() +
+                        "' is already waited upon by '" + lastUser +
+                        "' in line " + lineNo + ". "};
+
+  auto bugReport =
+      llvm::make_unique<BugReport>(*doubleWaitBugType_, errorText, node);
+  bugReport->addRange(observedCall.getSourceRange());
+  bugReport->addRange(request.lastUser_->getSourceRange());
+  SourceRange r = util::sourceRange(request.memRegion_);
+  if (r.isValid())
+    bugReport->addRange(r);
+  bugReporter_.emitReport(std::move(bugReport));
+}
+
+void MPIBugReporter::reportMissingWait(const Request &request,
+                                       const ExplodedNode *const node) const {
+  std::string lineNo{lineNumber(request.lastUser_)};
+  std::string lastUser = request.lastUser_->getCalleeIdentifier()->getName();
+
+  std::string errorText{
+      "'" + lastUser + "' in line " + lineNo + ", using request '" +
+      request.variableName() +
+      "', has no matching wait in the scope of this function. "};
+
+  auto bugReport =
+      llvm::make_unique<BugReport>(*missingWaitBugType_, errorText, node);
+  bugReport->addRange(request.lastUser_->getSourceRange());
+  SourceRange r = util::sourceRange(request.memRegion_);
+  if (r.isValid())
+    bugReport->addRange(r);
+  bugReporter_.emitReport(std::move(bugReport));
+}
+
+void MPIBugReporter::reportUnmatchedWait(
+    const CallEvent &callEvent, const clang::ento::MemRegion *requestRegion,
+    const ExplodedNode *const node) const {
+  std::string errorText{"Request '" + util::variableName(requestRegion) +
+                        "' has no matching nonblocking call. "};
+
+  auto bugReport =
+      llvm::make_unique<BugReport>(*unmatchedWaitBugType_, errorText, node);
+  bugReport->addRange(callEvent.getSourceRange());
+  SourceRange r = util::sourceRange(requestRegion);
+  if (r.isValid())
+    bugReport->addRange(r);
+  bugReporter_.emitReport(std::move(bugReport));
+}
+
+} // end of namespace: mpi
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.hpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.hpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.hpp	(working copy)
@@ -0,0 +1,123 @@
+//===-- MPIBugReporter.hpp - 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
+/// Emits bug reports for errors detected by AST-based and path-sensitive
+/// analysis.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef MPIBUGREPORTER_HPP_57XZJI4L
+#define MPIBUGREPORTER_HPP_57XZJI4L
+
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "MPITypes.hpp"
+
+namespace mpi {
+
+class MPIBugReporter {
+public:
+  MPIBugReporter(clang::ento::BugReporter &bugReporter,
+                 const clang::ento::CheckerBase &checkerBase,
+                 clang::ento::AnalysisManager &analysisManager)
+      : bugReporter_{bugReporter}, checkerBase_{checkerBase},
+        analysisManager_{analysisManager} {
+    doubleWaitBugType_.reset(
+        new clang::ento::BugType(&checkerBase, "double wait", "MPI Error"));
+    unmatchedWaitBugType_.reset(
+        new clang::ento::BugType(&checkerBase, "unmatched wait", "MPI Error"));
+    doubleNonblockingBugType_.reset(new clang::ento::BugType(
+        &checkerBase, "double nonblocking", "MPI Error"));
+    missingWaitBugType_.reset(
+        new clang::ento::BugType(&checkerBase, "missing wait", "MPI Error"));
+  }
+
+  // ast reports ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
+
+  /// \brief Reports mismatch between buffer type and MPI datatype.
+  /// \param call expression to report mismatch for
+  /// \param argument indices
+  /// \param buffer type
+  /// \param MPI type
+  void reportTypeMismatch(const clang::CallExpr *const,
+                          const std::pair<size_t, size_t> &, clang::QualType,
+                          std::string) const;
+
+  /// \brief Report if a buffer is not passed as a single pointer.
+  void reportIncorrectBufferReferencing(const clang::CallExpr *,
+                                        const std::pair<size_t, size_t> &,
+                                        clang::QualType,
+                                        size_t pointerCount) const;
+
+  /// \brief Report non-integer value usage at indices where not allowed.
+  /// (e.g. count, rank)
+  ///
+  /// \param callExpr
+  /// \param idx
+  /// \param type
+  void reportInvalidArgumentType(const clang::CallExpr *const,
+                                 const size_t) const;
+
+  // path sensitive reports –––––––––––––––––––––––––––––––––––––––––––––––
+
+  /// \brief Report a missing wait for a nonblocking call.
+  ///
+  /// \param request
+  /// \param node
+  void reportMissingWait(const Request &,
+                         const clang::ento::ExplodedNode *const) const;
+
+  /// \brief Report there's no matching nonblocking call for request used by
+  /// wait.
+  ///
+  /// \param callExpr
+  /// \param request
+  /// \param node
+  void reportUnmatchedWait(const clang::ento::CallEvent &,
+                           const clang::ento::MemRegion *,
+                           const clang::ento::ExplodedNode *const) const;
+
+  /// \brief Report duplicate request use by waits.
+  ///
+  /// \param observedCall
+  /// \param request
+  /// \param node
+  void reportDoubleWait(const clang::ento::CallEvent &, const Request &,
+                        const clang::ento::ExplodedNode *const) const;
+
+  /// \brief Report duplicate request use by nonblocking calls.
+  ///
+  /// \param observedCall
+  /// \param request
+  /// \param node
+  void reportDoubleNonblocking(const clang::ento::CallEvent &,
+                               const mpi::Request &,
+                               const clang::ento::ExplodedNode *const) const;
+
+  const clang::Decl *currentFunctionDecl_{nullptr};
+
+private:
+  /// \brief Get line number for call event ref
+  /// \param call event reference
+  /// \returns line number as string
+  std::string lineNumber(const clang::ento::CallEventRef<>) 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 &checkerBase_;
+  clang::ento::AnalysisManager &analysisManager_;
+};
+
+} // end of namespace: mpi
+#endif // end of include guard: MPIBUGREPORTER_HPP_57XZJI4L
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp	(working copy)
@@ -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
+/// Main class which serves as an entry point for this checker.
+/// It is created once for every translation unit.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "TranslationUnitVisitor.hpp"
+#include "MPICheckerPathSensitive.hpp"
+
+using namespace clang;
+using namespace ento;
+
+namespace mpi {
+class MPIChecker : public Checker<check::ASTDecl<TranslationUnitDecl>,
+                                  check::PreCall, check::EndFunction> {
+public:
+  // ast callback–––––––––––––––––––––––––––––––––––––––––––––––––––––––
+  void checkASTDecl(const TranslationUnitDecl *tuDecl,
+                    AnalysisManager &analysisManager,
+                    BugReporter &bugReporter) const {
+
+    // traverse translation unit
+    TranslationUnitVisitor tuVisitor{bugReporter, *this, analysisManager};
+    tuVisitor.TraverseTranslationUnitDecl(
+        const_cast<TranslationUnitDecl *>(tuDecl));
+  }
+
+  // path sensitive callbacks––––––––––––––––––––––––––––––––––––––––––––
+  void checkPreCall(const CallEvent &callEvent, CheckerContext &ctx) const {
+    dynamicInit(ctx);
+    checkerSens_->checkWaitUsage(callEvent, ctx);
+    checkerSens_->checkDoubleNonblocking(callEvent, 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
+
+// registers the checker for static analysis.
+void ento::registerMPIChecker(CheckerManager &mgr) {
+  mgr.registerChecker<mpi::MPIChecker>();
+}
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.cpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.cpp	(working copy)
@@ -0,0 +1,352 @@
+//===-- 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
+/// AST-based checks to verify correct usage of the MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MPICheckerAST.hpp"
+
+using namespace clang;
+using namespace ento;
+
+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 mpiCall) const {
+  // one pair consists of {bufferIdx, mpiDatatypeIdx}
+  IndexPairs indexPairs = bufferDataTypeIndices(mpiCall);
+
+  // for every buffer mpi-data pair in function
+  // check if their types match
+  for (const auto &idxPair : indexPairs) {
+    auto bufferType =
+        mpiCall->getArg(idxPair.first)->IgnoreImpCasts()->getType();
+
+    // collect buffer type information
+    const mpi::TypeVisitor typeVisitor{bufferType};
+
+    // get MPI datatype as string
+    StringRef mpiDatatypeString{util::sourceRangeAsStringRef(
+        mpiCall->getArg(idxPair.second)->getSourceRange(), analysisManager_)};
+
+    // check if buffer is correctly referenced
+    if (typeVisitor.pointerCount() != 1) {
+      bugReporter_.reportIncorrectBufferReferencing(
+          mpiCall, idxPair, bufferType, typeVisitor.pointerCount());
+    }
+
+    // MPI_BYTE needs no matching
+    if (mpiDatatypeString == "MPI_BYTE")
+      return;
+
+    // if MPI type not known
+    if (!cont::isContained(mpiTypes_, mpiDatatypeString))
+      return;
+
+    selectTypeMatcher(typeVisitor, mpiCall, mpiDatatypeString, idxPair);
+  }
+}
+
+MPICheckerAST::IndexPairs MPICheckerAST::bufferDataTypeIndices(
+    const clang::CallExpr *const mpiCall) const {
+  IndexPairs indexPairs;
+
+  const IdentifierInfo *const ident = util::getIdentInfo(mpiCall);
+
+  if (funcClassifier_.isPointToPointType(ident)) {
+    indexPairs.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(mpiCall->getArg(0)->getSourceRange(),
+                                       analysisManager_) != "MPI_IN_PLACE") {
+        indexPairs.push_back({0, 3});
+      }
+      indexPairs.push_back({1, 3});
+    } else if (funcClassifier_.isScatterType(ident) ||
+               funcClassifier_.isGatherType(ident) ||
+               funcClassifier_.isAlltoallType(ident)) {
+      indexPairs.push_back({0, 2});
+      indexPairs.push_back({3, 5});
+    } else if (funcClassifier_.isBcastType(ident)) {
+      indexPairs.push_back({0, 2});
+    }
+  }
+  return indexPairs;
+}
+
+void MPICheckerAST::selectTypeMatcher(
+    const mpi::TypeVisitor &typeVisitor, const clang::CallExpr *const mpiCall,
+    const StringRef mpiDatatypeString,
+    const std::pair<size_t, size_t> &idxPair) const {
+  const clang::BuiltinType *builtinType = typeVisitor.builtinType();
+  bool isTypeMatching{true};
+
+  // check for exact width types (e.g. int16_t, uint32_t)
+  if (typeVisitor.isTypedefType()) {
+    isTypeMatching = matchExactWidthType(typeVisitor, mpiDatatypeString);
+  }
+  // check for complex-floating types (e.g. float _Complex)
+  else if (typeVisitor.isComplexType()) {
+    isTypeMatching = matchComplexType(typeVisitor, mpiDatatypeString);
+  }
+  // check for basic builtin types (e.g. int, char)
+  else if (!builtinType) {
+    return; // if no builtin type cancel checking
+  } else if (builtinType->isBooleanType()) {
+    isTypeMatching = matchBoolType(typeVisitor, mpiDatatypeString);
+  } else if (builtinType->isAnyCharacterType()) {
+    isTypeMatching = matchCharType(typeVisitor, mpiDatatypeString);
+  } else if (builtinType->isSignedInteger()) {
+    isTypeMatching = matchSignedType(typeVisitor, mpiDatatypeString);
+  } else if (builtinType->isUnsignedIntegerType()) {
+    isTypeMatching = matchUnsignedType(typeVisitor, mpiDatatypeString);
+  } else if (builtinType->isFloatingType()) {
+    isTypeMatching = matchFloatType(typeVisitor, mpiDatatypeString);
+  }
+
+  if (!isTypeMatching)
+    bugReporter_.reportTypeMismatch(mpiCall, idxPair, typeVisitor.qualType_,
+                                    mpiDatatypeString);
+}
+
+bool MPICheckerAST::matchBoolType(const mpi::TypeVisitor &visitor,
+                                  const llvm::StringRef mpiDatatype) const {
+  return (mpiDatatype == "MPI_C_BOOL");
+}
+
+bool MPICheckerAST::matchCharType(const mpi::TypeVisitor &visitor,
+                                  const llvm::StringRef mpiDatatype) const {
+  bool isTypeMatching;
+  switch (visitor.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 &visitor,
+                                    const llvm::StringRef mpiDatatype) const {
+  bool isTypeMatching;
+
+  switch (visitor.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 &visitor,
+                                      const llvm::StringRef mpiDatatype) const {
+  bool isTypeMatching;
+
+  switch (visitor.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 &visitor,
+                                   const llvm::StringRef mpiDatatype) const {
+  bool isTypeMatching;
+
+  switch (visitor.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 &visitor,
+                                     const llvm::StringRef mpiDatatype) const {
+  bool isTypeMatching;
+
+  switch (visitor.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 &visitor, const llvm::StringRef mpiDatatype) const {
+  // check typedef type match
+  // no break needs to be specified for string switch
+  bool isTypeMatching = llvm::StringSwitch<bool>(visitor.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 mpiCall) const {
+  llvm::SmallVector<size_t, 1> indicesToCheck{integerIndices(mpiCall)};
+  if (!indicesToCheck.size())
+    return;
+
+  // iterate indices which should not have integer arguments
+  for (const size_t idx : indicesToCheck) {
+    if (!mpiCall->getArg(idx)->IgnoreImpCasts()->getType()->isIntegerType()) {
+      bugReporter_.reportInvalidArgumentType(mpiCall, idx);
+    }
+  }
+}
+
+llvm::SmallVector<size_t, 1>
+MPICheckerAST::integerIndices(const clang::CallExpr *const mpiCall) const {
+  llvm::SmallVector<size_t, 1> intIndices;
+
+  const IdentifierInfo *const ident = util::getIdentInfo(mpiCall);
+
+  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 functionDecl) {
+  bugReporter_.currentFunctionDecl_ = functionDecl;
+}
+
+} // end of namespace: mpi
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.hpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.hpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerAST.hpp	(working copy)
@@ -0,0 +1,108 @@
+//===-- MPICheckerAST.hpp - 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
+/// AST-based checks to verify correct usage of the MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef MPICHECKERAST_HPP_O1KSUWZO
+#define MPICHECKERAST_HPP_O1KSUWZO
+
+#include "../ClangSACheckers.h"
+#include "MPIFunctionClassifier.hpp"
+#include "MPIBugReporter.hpp"
+#include "Container.hpp"
+#include "Utility.hpp"
+#include "TypeVisitor.hpp"
+
+namespace mpi {
+
+class MPICheckerAST : public clang::RecursiveASTVisitor<MPICheckerAST> {
+public:
+  MPICheckerAST(clang::ento::BugReporter &bugReporter,
+                const clang::ento::CheckerBase &checkerBase,
+                clang::ento::AnalysisManager &analysisManager)
+      : funcClassifier_{analysisManager},
+        bugReporter_{bugReporter, checkerBase, analysisManager},
+        analysisManager_{analysisManager} {
+    initMPITypeContainer();
+  }
+
+  using IndexPairs = llvm::SmallVector<std::pair<size_t, size_t>, 2>;
+
+  /// \brief Check if invalid argument types are used in a MPI call.
+  ///
+  /// Checks if expressions evaluate to non-integer type at indices where only
+  /// integer values are valid (count, rank, tag).
+  ///
+  /// \param mpiCall to check the arguments for
+  void checkForInvalidArgs(const clang::CallExpr *const) const;
+
+  /// \brief Checks if buffer type and specified MPI datatype matches.
+  /// \param mpiCall call to check type correspondence for
+  void checkBufferTypeMatch(const clang::CallExpr *const) const;
+
+  /// \brief Set function currently visited to pass to bug reporter
+  /// in case of invariant violation.
+  ///
+  /// \param functionDecl current function
+  void setCurrentlyVisitedFunction(const clang::FunctionDecl *const);
+
+  /// \brief Obtain function classifier instance used by MPICheckerAST
+  /// \returns function classifier
+  const MPIFunctionClassifier &funcClassifier() { return funcClassifier_; }
+
+private:
+  /// \brief Init MPI type container to recognize all type tags defined by the
+  /// MPI standard.
+  void initMPITypeContainer();
+
+  /// \brief Returns index pairs for each buffer, datatype pair.
+  ///
+  /// \param mpiCall
+  /// \returns index pairs
+  IndexPairs bufferDataTypeIndices(const clang::CallExpr *const) const;
+
+  /// \brief Return an array of indices that must be integer values for a given
+  /// call.
+  ///
+  /// \param mpiCall
+  ///
+  /// \returns int indices
+  llvm::SmallVector<size_t, 1>
+  integerIndices(const clang::CallExpr *const) const;
+
+  /// \brief Select apprioriate function to match the buffer type against
+  /// the specified MPI datatype.
+  ///
+  /// \param typeVisitor contains information about the buffer
+  /// \param mpiCall call whose arguments are observed
+  /// \param mpiDatatypeString
+  /// \param idxPair (bufferIdx, mpiDatatypeIdx)
+  void selectTypeMatcher(const TypeVisitor &, const clang::CallExpr *const,
+                         const clang::StringRef,
+                         const std::pair<size_t, size_t> &) const;
+  bool matchBoolType(const TypeVisitor &, const llvm::StringRef) const;
+  bool matchCharType(const TypeVisitor &, const llvm::StringRef) const;
+  bool matchSignedType(const TypeVisitor &, const llvm::StringRef) const;
+  bool matchUnsignedType(const TypeVisitor &, const llvm::StringRef) const;
+  bool matchFloatType(const TypeVisitor &, const llvm::StringRef) const;
+  bool matchComplexType(const TypeVisitor &, const llvm::StringRef) const;
+  bool matchExactWidthType(const TypeVisitor &, const llvm::StringRef) const;
+
+  MPIFunctionClassifier funcClassifier_;
+  llvm::SmallVector<std::string, 32> mpiTypes_;
+  MPIBugReporter bugReporter_;
+  clang::ento::AnalysisManager &analysisManager_;
+};
+
+} // end of namespace: mpi
+
+#endif // end of include guard: MPICHECKERAST_HPP_O1KSUWZO
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp	(working copy)
@@ -0,0 +1,166 @@
+//===-- 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
+/// Path-sensitive checks to verify correct usage of the MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MPICheckerPathSensitive.hpp"
+#include "Utility.hpp"
+
+namespace mpi {
+
+using namespace clang;
+using namespace ento;
+
+void MPICheckerPathSensitive::checkDoubleNonblocking(
+    const clang::ento::CallEvent &callEvent, CheckerContext &ctx) const {
+  if (!funcClassifier_.isNonBlockingType(callEvent.getCalleeIdentifier())) {
+    return;
+  }
+  const MemRegion *memRegion =
+      callEvent.getArgSVal(callEvent.getNumArgs() - 1).getAsRegion();
+
+  // no way to reason about symbolic region
+  if (memRegion->getBaseRegion()->getAs<SymbolicRegion>())
+    return;
+
+  ProgramStateRef state = ctx.getState();
+  CallEventRef<> callEventRef = callEvent.cloneWithState(state);
+
+  const Request *request = state->get<RequestMap>(memRegion);
+  const ExplodedNode *const node = ctx.addTransition();
+
+  if (request) {
+    if (funcClassifier_.isNonBlockingType(
+            request->lastUser_->getCalleeIdentifier())) {
+      bugReporter_.reportDoubleNonblocking(callEvent, *request, node);
+    }
+  }
+
+  state =
+      state->set<RequestMap>(memRegion, mpi::Request{memRegion, callEventRef});
+  ctx.addTransition(state);
+}
+
+const MemRegion *MPICheckerPathSensitive::memRegionUsedInWait(
+    const clang::ento::CallEvent &callEvent) const {
+  if (funcClassifier_.isMPI_Wait(callEvent.getCalleeIdentifier())) {
+    return callEvent.getArgSVal(0).getAsRegion();
+  } else if (funcClassifier_.isMPI_Waitall(callEvent.getCalleeIdentifier())) {
+    return callEvent.getArgSVal(1).getAsRegion();
+  } else {
+    return (const MemRegion *)nullptr;
+  }
+}
+
+void MPICheckerPathSensitive::collectUsedMemRegions(
+    llvm::SmallVector<const MemRegion *, 2> &requestRegions,
+    const MemRegion *memRegion, const clang::ento::CallEvent &callEvent,
+    CheckerContext &ctx) const {
+  ProgramStateRef state = ctx.getState();
+  MemRegionManager *regionManager = memRegion->getMemRegionManager();
+
+  if (funcClassifier_.isMPI_Waitall(callEvent.getCalleeIdentifier())) {
+    const MemRegion *superRegion{nullptr};
+    if (const ElementRegion *er = memRegion->getAs<ElementRegion>()) {
+      superRegion = er->getSuperRegion();
+    }
+
+    // single request passed to waitall
+    if (!superRegion) {
+      requestRegions.push_back(memRegion);
+      return;
+    }
+
+    auto size = ctx.getStoreManager().getSizeInElements(
+        state, superRegion,
+        callEvent.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 *elementRegion = regionManager->getElementRegion(
+          callEvent.getArgExpr(1)->getType()->getPointeeType(), idx,
+          superRegion, ctx.getASTContext());
+
+      requestRegions.push_back(elementRegion->getAs<MemRegion>());
+    }
+  } else if (funcClassifier_.isMPI_Wait(callEvent.getCalleeIdentifier())) {
+    requestRegions.push_back(memRegion);
+  }
+}
+
+void MPICheckerPathSensitive::checkWaitUsage(
+    const clang::ento::CallEvent &callEvent, CheckerContext &ctx) const {
+  if (!funcClassifier_.isWaitType(callEvent.getCalleeIdentifier()))
+    return;
+  const MemRegion *memRegion = memRegionUsedInWait(callEvent);
+  if (!memRegion)
+    return;
+
+  // no way to reason about symbolic region
+  if (memRegion->getBaseRegion()->getAs<SymbolicRegion>())
+    return;
+
+  ProgramStateRef state = ctx.getState();
+  CallEventRef<> callEventRef = callEvent.cloneWithState(state);
+  const ExplodedNode *const node = ctx.addTransition();
+  llvm::SmallVector<const MemRegion *, 2> requestRegions;
+  collectUsedMemRegions(requestRegions, memRegion, callEvent, ctx);
+
+  // check all requestRegions used in wait function
+  for (const auto requestRegion : requestRegions) {
+    const Request *request = state->get<RequestMap>(requestRegion);
+    state =
+        state->set<RequestMap>(requestRegion, {requestRegion, callEventRef});
+    if (request) {
+      // check for double wait
+      if (funcClassifier_.isWaitType(
+              request->lastUser_->getCalleeIdentifier())) {
+        bugReporter_.reportDoubleWait(callEvent, *request, node);
+      }
+    }
+    // no matching nonblocking call
+    else {
+      bugReporter_.reportUnmatchedWait(callEvent, requestRegion, node);
+    }
+  }
+
+  ctx.addTransition(state);
+}
+
+void MPICheckerPathSensitive::checkMissingWaits(CheckerContext &ctx) {
+  ProgramStateRef state = ctx.getState();
+  auto requests = state->get<RequestMap>();
+  ExplodedNode *node = ctx.addTransition();
+  // at the end of a function immediate calls should be matched with wait
+  for (auto &request : requests) {
+    if (request.second.lastUser_ &&
+        funcClassifier_.isNonBlockingType(
+            request.second.lastUser_->getCalleeIdentifier())) {
+      bugReporter_.reportMissingWait(request.second, node);
+    }
+  }
+}
+
+void MPICheckerPathSensitive::clearRequests(CheckerContext &ctx) const {
+  ProgramStateRef state = ctx.getState();
+  auto requests = state->get<RequestMap>();
+  // clear rank container
+  for (auto &request : requests) {
+    state = state->remove<RequestMap>(request.first);
+  }
+  ctx.addTransition(state);
+}
+
+} // end of namespace: mpi
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.hpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.hpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.hpp	(working copy)
@@ -0,0 +1,87 @@
+//===-- MPICheckerPathSensitive.hpp - 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
+/// Path-sensitive checks to verify correct usage of the MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef MPICHECKERPATHSENSITIVE_HPP_BKYOQUPL
+#define MPICHECKERPATHSENSITIVE_HPP_BKYOQUPL
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "MPIFunctionClassifier.hpp"
+#include "MPITypes.hpp"
+#include "MPIBugReporter.hpp"
+
+namespace mpi {
+
+class MPICheckerPathSensitive {
+public:
+  MPICheckerPathSensitive(clang::ento::AnalysisManager &analysisManager,
+                          const clang::ento::CheckerBase *checkerBase,
+                          clang::ento::BugReporter &bugReporter)
+      : funcClassifier_{analysisManager},
+        bugReporter_{bugReporter, *checkerBase, analysisManager} {}
+
+  /// \brief Checks if a request is used by nonblocking calls multiple times
+  /// before intermediate wait.
+  ///
+  /// \param callExpr
+  /// \param ctx
+  void checkDoubleNonblocking(const clang::ento::CallEvent &,
+                              clang::ento::CheckerContext &) const;
+  /// \brief Checks if a request is used by wait multiple times without
+  /// intermediate nonblocking call.
+  ///
+  /// \param callExpr
+  /// \param ctx
+  void checkWaitUsage(const clang::ento::CallEvent &,
+                      clang::ento::CheckerContext &) const;
+  /// \brief Check if a nonblocking call has no matching wait.
+  ///
+  /// \param ctx
+  void checkMissingWaits(clang::ento::CheckerContext &);
+
+  /// \brief Erase all request vars from the path sensitive map.
+  //
+  /// \param ctx
+  void clearRequests(clang::ento::CheckerContext &) const;
+
+private:
+  /// \brief Returns the memory region used in a wait function.
+  ///
+  /// \param callEvent wait function
+  /// \returns memory region
+  const clang::ento::MemRegion *
+  memRegionUsedInWait(const clang::ento::CallEvent &) const;
+
+  /// \brief Collects all memory regions used in 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 collected
+  ///
+  /// \param requestRegions vector the regions get pushed into
+  /// \param memRegion top most region to iterate
+  /// \param callEvent function using the region/s
+  /// \param ctx checker context
+  void
+  collectUsedMemRegions(llvm::SmallVector<const clang::ento::MemRegion *, 2> &,
+                        const clang::ento::MemRegion *,
+                        const clang::ento::CallEvent &,
+                        clang::ento::CheckerContext &) const;
+
+  MPIFunctionClassifier funcClassifier_;
+  MPIBugReporter bugReporter_;
+};
+} // end of namespace: mpi
+
+#endif // end of include guard: MPICHECKERPATHSENSITIVE_HPP_BKYOQUPL
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp	(working copy)
@@ -0,0 +1,362 @@
+//===-- 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
+/// Identify and classify MPI functions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MPIFunctionClassifier.hpp"
+#include "Utility.hpp"
+#include "Container.hpp"
+
+using namespace clang;
+using namespace ento;
+
+namespace mpi {
+
+void MPIFunctionClassifier::identifierInit(
+    clang::ento::AnalysisManager &analysisManager) {
+  // init function identifiers
+  initPointToPointIdentifiers(analysisManager);
+  initCollectiveIdentifiers(analysisManager);
+  initAdditionalIdentifiers(analysisManager);
+}
+
+void MPIFunctionClassifier::initPointToPointIdentifiers(
+    clang::ento::AnalysisManager &analysisManager) {
+  ASTContext &context = analysisManager.getASTContext();
+
+  // copy identifiers into the correct classification containers
+  identInfo_MPI_Send_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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 &analysisManager) {
+  ASTContext &context = analysisManager.getASTContext();
+
+  // copy identifiers into the correct classification containers
+  identInfo_MPI_Scatter_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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_ = &context.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 &analysisManager) {
+  ASTContext &context = analysisManager.getASTContext();
+
+  identInfo_MPI_Comm_rank_ = &context.Idents.get("MPI_Comm_rank");
+  mpiType_.push_back(identInfo_MPI_Comm_rank_);
+  assert(identInfo_MPI_Comm_rank_);
+
+  identInfo_MPI_Comm_size_ = &context.Idents.get("MPI_Comm_size");
+  mpiType_.push_back(identInfo_MPI_Comm_size_);
+  assert(identInfo_MPI_Comm_size_);
+
+  identInfo_MPI_Wait_ = &context.Idents.get("MPI_Wait");
+  mpiType_.push_back(identInfo_MPI_Wait_);
+  assert(identInfo_MPI_Wait_);
+
+  identInfo_MPI_Waitall_ = &context.Idents.get("MPI_Waitall");
+  mpiType_.push_back(identInfo_MPI_Waitall_);
+  assert(identInfo_MPI_Waitall_);
+
+  identInfo_MPI_Waitany_ = &context.Idents.get("MPI_Waitany");
+  mpiType_.push_back(identInfo_MPI_Waitany_);
+  assert(identInfo_MPI_Waitany_);
+
+  identInfo_MPI_Waitsome_ = &context.Idents.get("MPI_Waitsome");
+  mpiType_.push_back(identInfo_MPI_Waitsome_);
+  assert(identInfo_MPI_Waitsome_);
+
+  identInfo_MPI_Barrier_ = &context.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::isContained(mpiType_, identInfo);
+}
+
+bool MPIFunctionClassifier::isBlockingType(
+    const IdentifierInfo *identInfo) const {
+  return cont::isContained(mpiBlockingTypes_, identInfo);
+}
+
+bool MPIFunctionClassifier::isNonBlockingType(
+    const IdentifierInfo *identInfo) const {
+  return cont::isContained(mpiNonBlockingTypes_, identInfo);
+}
+
+// point to point identifiers––––––––––––––––––––––––––––––––––––––––––
+bool MPIFunctionClassifier::isPointToPointType(
+    const IdentifierInfo *identInfo) const {
+  return cont::isContained(mpiPointToPointTypes_, identInfo);
+}
+
+bool MPIFunctionClassifier::isSendType(const IdentifierInfo *identInfo) const {
+  return cont::isContained(mpiSendTypes_, identInfo);
+}
+
+bool MPIFunctionClassifier::isRecvType(const IdentifierInfo *identInfo) const {
+  return cont::isContained(mpiRecvTypes_, identInfo);
+}
+
+// collective identifiers––––––––––––––––––––––––––––––––––––––––––––––
+bool MPIFunctionClassifier::isCollectiveType(
+    const IdentifierInfo *identInfo) const {
+  return cont::isContained(mpiCollectiveTypes_, identInfo);
+}
+
+bool MPIFunctionClassifier::isCollToColl(
+    const IdentifierInfo *identInfo) const {
+  return cont::isContained(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
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.hpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.hpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.hpp	(working copy)
@@ -0,0 +1,113 @@
+//===-- MPIFunctionClassifier.hpp - 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
+/// Identify and classify MPI functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef MPIFUNCTIONCLASSIFIER_HPP_Q3AOUNFC
+#define MPIFUNCTIONCLASSIFIER_HPP_Q3AOUNFC
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+namespace mpi {
+
+class MPIFunctionClassifier {
+public:
+  MPIFunctionClassifier(clang::ento::AnalysisManager &analysisManager) {
+    identifierInit(analysisManager);
+  }
+
+  // general identifiers–––––––––––––––––––––––––––––––––––––––––––––––––
+  bool isMPIType(const clang::IdentifierInfo *const) const;
+  bool isBlockingType(const clang::IdentifierInfo *const) const;
+  bool isNonBlockingType(const clang::IdentifierInfo *const) const;
+
+  // point to point identifiers––––––––––––––––––––––––––––––––––––––––––
+  bool isPointToPointType(const clang::IdentifierInfo *const) const;
+  bool isSendType(const clang::IdentifierInfo *const) const;
+  bool isRecvType(const clang::IdentifierInfo *const) const;
+
+  // collective identifiers––––––––––––––––––––––––––––––––––––––––––––––
+  bool isCollectiveType(const clang::IdentifierInfo *const) const;
+  bool isCollToColl(const clang::IdentifierInfo *const) const;
+  bool isScatterType(const clang::IdentifierInfo *const) const;
+  bool isGatherType(const clang::IdentifierInfo *const) const;
+  bool isAllgatherType(const clang::IdentifierInfo *const) const;
+  bool isAlltoallType(const clang::IdentifierInfo *const) const;
+  bool isReduceType(const clang::IdentifierInfo *const) const;
+  bool isBcastType(const clang::IdentifierInfo *const) const;
+
+  // additional identifiers ––––––––––––––––––––––––––––––––––––––––––––––
+  bool isMPI_Comm_rank(const clang::IdentifierInfo *const) const;
+  bool isMPI_Comm_size(const clang::IdentifierInfo *const) const;
+  bool isMPI_Wait(const clang::IdentifierInfo *const) const;
+  bool isMPI_Waitall(const clang::IdentifierInfo *const) const;
+  bool isMPI_Waitany(const clang::IdentifierInfo *const) const;
+  bool isMPI_Waitsome(const clang::IdentifierInfo *const) const;
+  bool isWaitType(const clang::IdentifierInfo *const) const;
+
+private:
+  /// \brief Initializes function identifiers.
+  ///
+  /// Initializes function identifiers. Instead of using strings,
+  /// indentifier-pointers are initially captured
+  /// to recognize functions during analysis by comparison later.
+  //
+  /// \param analysis manager
+  void identifierInit(clang::ento::AnalysisManager &);
+  void initPointToPointIdentifiers(clang::ento::AnalysisManager &);
+  void initCollectiveIdentifiers(clang::ento::AnalysisManager &);
+  void initAdditionalIdentifiers(clang::ento::AnalysisManager &);
+
+  // 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
+
+#endif // end of include guard: MPIFUNCTIONCLASSIFIER_HPP_Q3AOUNFC
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.hpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.hpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.hpp	(working copy)
@@ -0,0 +1,66 @@
+//===-- 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
+/// Definitions to model MPI point-to-point schema, MPI request.
+///
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef MPITYPES_HPP_IC7XR2MI
+#define MPITYPES_HPP_IC7XR2MI
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "llvm/ADT/SmallSet.h"
+#include "MPIFunctionClassifier.hpp"
+#include "Utility.hpp"
+#include "Container.hpp"
+
+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 memRegion,
+          const clang::ento::CallEventRef<> callEvent)
+      : memRegion_{memRegion}, lastUser_{callEvent} {
+    variableName_ = util::variableName(memRegion);
+  }
+
+  void Profile(llvm::FoldingSetNodeID &id) const {
+    id.AddPointer(memRegion_);
+    id.AddPointer(lastUser_->getOriginExpr());
+  }
+
+  bool operator==(const Request &toCompare) const {
+    return toCompare.memRegion_ == memRegion_;
+  }
+
+  const clang::ento::MemRegion *const memRegion_;
+  const clang::ento::CallEventRef<> lastUser_;
+
+  std::string variableName() const { return variableName_; }
+
+private:
+  std::string variableName_;
+};
+} // end of namespace: mpi
+
+// register data structure for path sensitive analysis
+REGISTER_MAP_WITH_PROGRAMSTATE(RequestMap, const clang::ento::MemRegion *,
+                               mpi::Request)
+
+#endif // end of include guard: MPITYPES_HPP_IC7XR2MI
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.cpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.cpp	(working copy)
@@ -0,0 +1,42 @@
+//===-- 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
+/// AST-based checks are invoked on an MPICheckerAST instance during traversal
+/// by the TranslationUnitVisitor.
+///
+//===----------------------------------------------------------------------===//
+
+#include "TranslationUnitVisitor.hpp"
+#include "MPICheckerPathSensitive.hpp"
+
+using namespace clang;
+using namespace ento;
+
+namespace mpi {
+
+bool TranslationUnitVisitor::VisitFunctionDecl(FunctionDecl *functionDecl) {
+  // to keep track which function implementation is currently analysed
+  if (functionDecl->clang::Decl::hasBody() && !functionDecl->isInlined()) {
+    // to make display of function in diagnostics available
+    checkerAST_.setCurrentlyVisitedFunction(functionDecl);
+  }
+  return true;
+}
+
+bool TranslationUnitVisitor::VisitCallExpr(clang::CallExpr *mpiCall) {
+  if (checkerAST_.funcClassifier().isMPIType(util::getIdentInfo(mpiCall))) {
+    checkerAST_.checkBufferTypeMatch(mpiCall);
+    checkerAST_.checkForInvalidArgs(mpiCall);
+  }
+
+  return true;
+}
+
+} // end of namespace: mpi
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.hpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.hpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TranslationUnitVisitor.hpp	(working copy)
@@ -0,0 +1,52 @@
+//===-- TranslationUnitVisitor.hpp - 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
+/// AST-based checks are invoked on an MPICheckerAST instance during traversal
+/// by the TranslationUnitVisitor.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef MPISCHEMACHECKERAST_HPP_NKN9I06D
+#define MPISCHEMACHECKERAST_HPP_NKN9I06D
+
+#include "MPICheckerAST.hpp"
+
+namespace mpi {
+
+class TranslationUnitVisitor
+    : public clang::RecursiveASTVisitor<TranslationUnitVisitor> {
+public:
+  TranslationUnitVisitor(clang::ento::BugReporter &bugReporter,
+                         const clang::ento::CheckerBase &checkerBase,
+                         clang::ento::AnalysisManager &analysisManager)
+      : checkerAST_{bugReporter, checkerBase, analysisManager} {}
+
+  // visitor callbacks----------------------------
+
+  /// \brief Visited for each function declaration.
+  ///
+  /// \param functionDecl
+  ///
+  /// \returns continue visiting
+  bool VisitFunctionDecl(clang::FunctionDecl *);
+
+  /// \brief Visited for each function call.
+  ///
+  /// \param callExpr
+  ///
+  /// \returns continue visiting
+  bool VisitCallExpr(clang::CallExpr *);
+
+  MPICheckerAST checkerAST_;
+};
+
+} // end of namespace: mpi
+
+#endif // end of include guard: MPISCHEMACHECKERAST_HPP_NKN9I06D
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TypeVisitor.hpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TypeVisitor.hpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/TypeVisitor.hpp	(working copy)
@@ -0,0 +1,75 @@
+//===-- 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
+/// Traverses qualified type to collect information about it.
+/// Detects if a QualType is a typedef, complex, builtin type.
+/// For matches the type information is stored.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef TYPEVISITOR_HPP_KOZYUVZH
+#define TYPEVISITOR_HPP_KOZYUVZH
+
+#include "clang/AST/RecursiveASTVisitor.h"
+
+namespace mpi {
+
+class TypeVisitor : public clang::RecursiveASTVisitor<TypeVisitor> {
+public:
+  TypeVisitor(clang::QualType qualType) : qualType_{qualType} {
+    TraverseType(qualType);
+  }
+
+  bool VisitTypedefType(clang::TypedefType *tdt) {
+    typedefTypeName_ = tdt->getDecl()->getQualifiedNameAsString();
+    isTypedefType_ = true;
+    return true;
+  }
+
+  bool VisitBuiltinType(clang::BuiltinType *builtinType) {
+    builtinType_ = builtinType;
+    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 qualType_;
+
+  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
+#endif // end of include guard: TYPEVISITOR_HPP_KOZYUVZH
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp	(working copy)
@@ -0,0 +1,113 @@
+//===-- 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
+/// Utility functions for MPI-Checker.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Lexer.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "Utility.hpp"
+#include <sstream>
+#include <vector>
+
+namespace util {
+
+/// \brief Split string by delimiter helper function.
+static std::vector<std::string> &split(const std::string &s, char delim,
+                                       std::vector<std::string> &elems) {
+  std::stringstream ss(s);
+  std::string item;
+  while (std::getline(ss, item, delim)) {
+    elems.push_back(item);
+  }
+  return elems;
+}
+
+std::vector<std::string> split(const std::string &s, char delim) {
+  std::vector<std::string> elems;
+  split(s, delim, elems);
+  return elems;
+}
+
+clang::StringRef
+sourceRangeAsStringRef(const clang::SourceRange &sourceRange,
+                       clang::ento::AnalysisManager &analysisManager) {
+  auto charSourceRange = clang::CharSourceRange::getTokenRange(sourceRange);
+  return clang::Lexer::getSourceText(charSourceRange,
+                                     analysisManager.getSourceManager(),
+                                     clang::LangOptions());
+}
+
+clang::SourceRange sourceRange(const clang::ento::MemRegion *memRegion) {
+  const clang::ento::VarRegion *varRegion =
+      clang::dyn_cast<clang::ento::VarRegion>(memRegion->getBaseRegion());
+
+  const clang::ento::FieldRegion *fieldRegion =
+      clang::dyn_cast<clang::ento::FieldRegion>(memRegion);
+
+  if (fieldRegion) {
+    return fieldRegion->getDecl()->getSourceRange();
+  } else if (varRegion) {
+    return varRegion->getDecl()->getSourceRange();
+  } else {
+    // non valid source range (can be checked by client)
+    return clang::SourceRange{};
+  }
+}
+
+std::string variableName(const clang::ento::MemRegion *memRegion) {
+  const clang::ento::VarRegion *varRegion =
+      clang::dyn_cast<clang::ento::VarRegion>(memRegion->getBaseRegion());
+
+  const clang::ento::FieldRegion *fieldRegion =
+      clang::dyn_cast<clang::ento::FieldRegion>(memRegion);
+
+  const clang::ento::ElementRegion *elementRegion =
+      memRegion->getAs<clang::ento::ElementRegion>();
+
+  std::string varName{""};
+
+  // members, fields
+  if (fieldRegion) {
+    varName = varRegion->getDecl()->getNameAsString() + "." +
+              fieldRegion->getDecl()->getNameAsString();
+  }
+  // variable
+  else if (varRegion) {
+    varName = varRegion->getDecl()->getNameAsString();
+  } else {
+    // get var-decl-name for symbolic region
+  }
+
+  if (elementRegion) {
+    llvm::APSInt indexInArray;
+    indexInArray = elementRegion->getIndex()
+                       .getAs<clang::ento::nonloc::ConcreteInt>()
+                       ->getValue();
+
+    llvm::SmallVector<char, 2> intValAsString;
+    indexInArray.toString(intValAsString);
+    std::string idx{intValAsString.begin(), intValAsString.end()};
+    return varName + "[" + idx + "]";
+  } else {
+    return varName;
+  }
+}
+
+const clang::IdentifierInfo *getIdentInfo(const clang::CallExpr *callExpr) {
+  if (callExpr->getDirectCallee()) {
+    return callExpr->getDirectCallee()->getIdentifier();
+  } else {
+    return nullptr;
+  }
+}
+
+} // end of namespace: util
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.hpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.hpp	(revision 0)
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.hpp	(working copy)
@@ -0,0 +1,53 @@
+//===-- Utility.hpp - 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
+/// Utility functions for MPI-Checker.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef UTILITY_HPP_SVQZWTL8
+#define UTILITY_HPP_SVQZWTL8
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+namespace util {
+
+/// \brief Returns part of the code specified by range unmodified as string ref.
+///
+/// \param source range
+/// \param analysis manager
+///
+/// \return code part as string ref
+clang::StringRef sourceRangeAsStringRef(const clang::SourceRange &,
+                                        clang::ento::AnalysisManager &);
+
+/// \brief Split string by delimiter.
+///
+/// \param string to split
+/// \param delimiter
+///
+/// \return string array split by delimiter
+std::vector<std::string> split(const std::string &, char);
+
+/// \brief Retrieve identifier info for a call expression.
+///
+/// Returns nullptr if there's no direct callee.
+///
+/// \param callExpr to retrieve ident info for
+///
+/// \return identifier info for passed call expression
+const clang::IdentifierInfo *getIdentInfo(const clang::CallExpr *);
+
+std::string variableName(const clang::ento::MemRegion *);
+clang::SourceRange sourceRange(const clang::ento::MemRegion *);
+
+} // end of namespace: util
+
+#endif // end of include guard: UTILITY_HPP_SVQZWTL8
Index: tools/clang/test/Analysis/MPIChecker.c
===================================================================
--- tools/clang/test/Analysis/MPIChecker.c	(revision 0)
+++ tools/clang/test/Analysis/MPIChecker.c	(working copy)
@@ -0,0 +1,462 @@
+// RUN: %clang_cc1 -I/usr/include/ -I/usr/local/include/ -analyze -analyzer-checker=mpi.MPI-Checker -verify %s
+
+#include <mpi.h>
+#include <complex.h>
+#include <stdint.h>
+
+/// Point-to-point calls of different test functions should not be matched
+/// -> set tags.
+
+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, 1, MPI_COMM_WORLD, &req[0]);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 1, 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 21.}}
+  }
+}
+
+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, 2, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 2, 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 36.}}
+  }
+}
+
+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 51.}}
+}
+
+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, 3, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 3, MPI_COMM_WORLD, &recvReq1);
+    MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+  }
+} // expected-warning{{'MPI_Isend' in line 63, 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, 21, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 21, 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, 22, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 22, 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, 23, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 23, 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, 4, MPI_COMM_WORLD, &sendReq1);
+    MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 4, MPI_COMM_WORLD, &sendReq1); // expected-warning{{Request 'sendReq1' is already in use by nonblocking call 'MPI_Isend' in line 122.}}
+    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, 5, MPI_COMM_WORLD, &req);
+  MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 5, MPI_COMM_WORLD, &req); // expected-warning{{Request 'req' is already in use by nonblocking call 'MPI_Ireduce' in line 134.}}
+  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 147.}}
+  MPI_Wait(&rs.req, MPI_STATUS_IGNORE);
+}
+
+void missingNonBlocking() {
+  int rank = 0;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  if (rank == 1) {
+    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);
+}
+
+// same tag is used for all type matching functions
+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, 0, 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, 0, 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, 0, MPI_COMM_WORLD);
+  } else {
+    MPI_Recv(bufP, 1, MPI_DOUBLE, rank - 1, 0, 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, 0, 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, 0, 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, 0, MPI_COMM_WORLD);
+  } else {
+    MPI_Recv(&buf, 1, MPI_LONG_DOUBLE, rank - 1, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, MPI_COMM_WORLD);
+  } else {
+    MPI_Recv(&buf, 1, MPI_UINT8_T, rank - 1, 0, 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 = 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 = 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 = 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 = 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 = 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, 17, 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, 17, 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, 18, 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, 18, 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, 18, 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, 18, 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(), 18, 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(), 18, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // expected-warning{{The type, argument at index 3 evaluates to, is not an integer type.}}
+  }
+}
Index: tools/clang/unittests/StaticAnalyzer/CMakeLists.txt
===================================================================
--- tools/clang/unittests/StaticAnalyzer/CMakeLists.txt	(revision 247122)
+++ tools/clang/unittests/StaticAnalyzer/CMakeLists.txt	(working copy)
@@ -6,8 +6,10 @@
   AnalyzerOptionsTest.cpp
   )
 
+add_subdirectory(MPI-Checker)
+
 target_link_libraries(StaticAnalysisTests
   clangBasic
   clangAnalysis
-  clangStaticAnalyzerCore 
+  clangStaticAnalyzerCore
   )
Index: tools/clang/unittests/StaticAnalyzer/MPI-Checker/CMakeLists.txt
===================================================================
--- tools/clang/unittests/StaticAnalyzer/MPI-Checker/CMakeLists.txt	(revision 0)
+++ tools/clang/unittests/StaticAnalyzer/MPI-Checker/CMakeLists.txt	(working copy)
@@ -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/MPI-Checker/ContainerTest.cpp
===================================================================
--- tools/clang/unittests/StaticAnalyzer/MPI-Checker/ContainerTest.cpp	(revision 0)
+++ tools/clang/unittests/StaticAnalyzer/MPI-Checker/ContainerTest.cpp	(working copy)
@@ -0,0 +1,105 @@
+#include "gtest/gtest.h"
+#include <vector>
+#include "Container.hpp"
+
+TEST(Container, isContained) {
+  std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 8, 9};
+  EXPECT_TRUE(cont::isContained(v, 0));
+  EXPECT_TRUE(cont::isContained(v, 3));
+  EXPECT_TRUE(cont::isContained(v, 9));
+}
+
+TEST(Container, isNotContained) {
+  std::vector<int> v{1, 2, 4, 5, 6, 8};
+  EXPECT_FALSE(cont::isContained(v, 0));
+  EXPECT_FALSE(cont::isContained(v, 3));
+  EXPECT_FALSE(cont::isContained(v, 9));
+}
+
+TEST(Container, isContainedPred) {
+  std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 8, 9};
+  EXPECT_TRUE(cont::isContainedPred(v, [](int x) { return x == 0; }));
+  EXPECT_TRUE(cont::isContainedPred(v, [](int x) { return x == 3; }));
+  EXPECT_TRUE(cont::isContainedPred(v, [](int x) { return x == 9; }));
+}
+
+TEST(Container, isNotContainedPred) {
+  std::vector<int> v{1, 2, 4, 5, 6, 8};
+  EXPECT_FALSE(cont::isContainedPred(v, [](int x) { return x == 0; }));
+  EXPECT_FALSE(cont::isContainedPred(v, [](int x) { return x == 3; }));
+  EXPECT_FALSE(cont::isContainedPred(v, [](int x) { return x == 9; }));
+}
+
+TEST(Container, erase) {
+  std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 8, 9};
+  int x = 0, y = 3, z = 9;
+
+  cont::erase(v, x);
+  std::vector<int> comp{1, 2, 3, 4, 5, 6, 8, 9};
+  EXPECT_EQ(v, comp);
+
+  cont::erase(v, y);
+  comp = {1, 2, 4, 5, 6, 8, 9};
+  EXPECT_EQ(v, comp);
+
+  cont::erase(v, z);
+  comp = {1, 2, 4, 5, 6, 8};
+  EXPECT_EQ(v, comp);
+
+  std::vector<int> v2{0, 1, 1, 3, 4, 5, 6, 8, 9};
+  std::vector<int> comp2{0, 1, 3, 4, 5, 6, 8, 9};
+  int x2 = 1;
+  cont::erase(v2, x2);
+  EXPECT_EQ(v2, comp2);
+}
+
+TEST(Container, eraseAll) {
+  std::vector<int> v{1, 1, 2, 3, 1, 5, 6, 8, 9};
+  int x = 1;
+  cont::eraseAll(v, x);
+
+  EXPECT_FALSE(cont::isContained(v, x));
+
+  std::vector<int> comp{2, 3, 5, 6, 8, 9};
+  EXPECT_EQ(v, comp);
+}
+
+TEST(Container, erasePred) {
+  std::vector<int> v{1, 1, 2, 3, 1, 5, 6, 8, 9};
+  cont::erasePred(v, [](int x) { return x == 1; });
+  std::vector<int> comp{1, 2, 3, 1, 5, 6, 8, 9};
+  EXPECT_EQ(v, comp);
+
+  cont::erasePred(v, [](int x) { return x == 1; });
+  comp = {2, 3, 1, 5, 6, 8, 9};
+  EXPECT_EQ(v, comp);
+
+  cont::erasePred(v, [](int x) { return x == 9; });
+  comp = {2, 3, 1, 5, 6, 8};
+  EXPECT_EQ(v, comp);
+}
+
+TEST(Container, eraseIndex) {
+  std::vector<int> v{0, 1, 2, 3};
+  cont::eraseIndex(v, 1);
+  std::vector<int> comp{0, 2, 3};
+  EXPECT_EQ(v, comp);
+}
+
+TEST(Container, copy) {
+  std::vector<int> v{0, 1};
+  std::vector<int> v2{2, 3};
+  std::vector<int> comp{0, 1, 2, 3};
+  cont::copy(v2, v);
+  EXPECT_EQ(v, comp);
+}
+
+TEST(Container, isPermutation) {
+  std::vector<int> v1{0, 1, 2, 3};
+  std::vector<int> v2{1, 0, 3, 2};
+
+  EXPECT_TRUE(cont::isPermutation(v1, v2));
+
+  std::vector<int> v3{1, 0, 4, 2};
+  EXPECT_FALSE(cont::isPermutation(v1, v3));
+}
Index: tools/clang/unittests/StaticAnalyzer/MPI-Checker/UtilityTest.cpp
===================================================================
--- tools/clang/unittests/StaticAnalyzer/MPI-Checker/UtilityTest.cpp	(revision 0)
+++ tools/clang/unittests/StaticAnalyzer/MPI-Checker/UtilityTest.cpp	(working copy)
@@ -0,0 +1,12 @@
+#include "gtest/gtest.h"
+#include "Utility.hpp"
+
+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");
+}


More information about the cfe-commits mailing list