MPITypeMismatchCheck for Clang-Tidy
authorAlexander Kornienko <alexfh@google.com>
Mon, 25 Jul 2016 15:43:14 +0000 (15:43 +0000)
committerAlexander Kornienko <alexfh@google.com>
Mon, 25 Jul 2016 15:43:14 +0000 (15:43 +0000)
Summary:
This check verifies if buffer type and MPI (Message Passing Interface)
datatype pairs match. All MPI datatypes defined by the MPI standard (3.1)
are verified by this check. User defined typedefs, custom MPI datatypes and
null pointer constants are skipped, in the course of verification.

Instructions on how to apply the check can be found at: https://github.com/0ax1/MPI-Checker/tree/master/examples

Reviewers: alexfh

Subscribers: cfe-commits

Projects: #clang-tools-extra

Patch by Alexander Droste!

Differential Revision: https://reviews.llvm.org/D21962

llvm-svn: 276640

12 files changed:
clang-tools-extra/clang-tidy/CMakeLists.txt
clang-tools-extra/clang-tidy/mpi/CMakeLists.txt [new file with mode: 0644]
clang-tools-extra/clang-tidy/mpi/MPITidyModule.cpp [new file with mode: 0644]
clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp [new file with mode: 0644]
clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.h [new file with mode: 0644]
clang-tools-extra/clang-tidy/plugin/CMakeLists.txt
clang-tools-extra/clang-tidy/tool/CMakeLists.txt
clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
clang-tools-extra/docs/clang-tidy/checks/list.rst
clang-tools-extra/docs/clang-tidy/checks/mpi-type-mismatch.rst [new file with mode: 0644]
clang-tools-extra/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h [new file with mode: 0644]
clang-tools-extra/test/clang-tidy/mpi-type-mismatch.cpp [new file with mode: 0644]

index 8ac6124..5e946f4 100644 (file)
@@ -34,6 +34,7 @@ add_subdirectory(cppcoreguidelines)
 add_subdirectory(google)
 add_subdirectory(misc)
 add_subdirectory(modernize)
+add_subdirectory(mpi)
 add_subdirectory(performance)
 add_subdirectory(readability)
 add_subdirectory(utils)
diff --git a/clang-tools-extra/clang-tidy/mpi/CMakeLists.txt b/clang-tools-extra/clang-tidy/mpi/CMakeLists.txt
new file mode 100644 (file)
index 0000000..77a52d0
--- /dev/null
@@ -0,0 +1,15 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyMPIModule
+  MPITidyModule.cpp
+  TypeMismatchCheck.cpp
+
+  LINK_LIBS
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangLex
+  clangTidy
+  clangTidyUtils
+  clangTooling
+  )
diff --git a/clang-tools-extra/clang-tidy/mpi/MPITidyModule.cpp b/clang-tools-extra/clang-tidy/mpi/MPITidyModule.cpp
new file mode 100644 (file)
index 0000000..babf7b6
--- /dev/null
@@ -0,0 +1,37 @@
+//===--- MPITidyModule.cpp - clang-tidy -----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "TypeMismatchCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace mpi {
+
+class MPIModule : public ClangTidyModule {
+public:
+  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    CheckFactories.registerCheck<TypeMismatchCheck>("mpi-type-mismatch");
+  }
+};
+
+} // namespace mpi
+
+// Register the MPITidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<mpi::MPIModule>
+    X("mpi-module", "Adds MPI clang-tidy checks.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the MPIModule.
+volatile int MPIModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
new file mode 100644 (file)
index 0000000..adb2d7a
--- /dev/null
@@ -0,0 +1,328 @@
+//===--- TypeMismatchCheck.cpp - clang-tidy--------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypeMismatchCheck.h"
+#include "clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/FixIt.h"
+#include <map>
+#include <unordered_set>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace mpi {
+
+/// Check if a BuiltinType::Kind matches the MPI datatype.
+///
+/// \param MultiMap datatype group
+/// \param Kind buffer type kind
+/// \param MPIDatatype name of the MPI datatype
+///
+/// \returns true if the pair matches
+static bool
+isMPITypeMatching(const std::multimap<BuiltinType::Kind, std::string> &MultiMap,
+                  const BuiltinType::Kind Kind,
+                  const std::string &MPIDatatype) {
+  auto ItPair = MultiMap.equal_range(Kind);
+  while (ItPair.first != ItPair.second) {
+    if (ItPair.first->second == MPIDatatype)
+      return true;
+    ++ItPair.first;
+  }
+  return false;
+}
+
+/// Check if the MPI datatype is a standard type.
+///
+/// \param MPIDatatype name of the MPI datatype
+///
+/// \returns true if the type is a standard type
+static bool isStandardMPIDatatype(const std::string &MPIDatatype) {
+  static std::unordered_set<std::string> AllTypes = {
+      "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",
+      "MPI_CXX_BOOL",
+      "MPI_CXX_FLOAT_COMPLEX",
+      "MPI_CXX_DOUBLE_COMPLEX",
+      "MPI_CXX_LONG_DOUBLE_COMPLEX"};
+
+  return AllTypes.find(MPIDatatype) != AllTypes.end();
+}
+
+/// Check if a BuiltinType matches the MPI datatype.
+///
+/// \param Builtin the builtin type
+/// \param BufferTypeName buffer type name, gets assigned
+/// \param MPIDatatype name of the MPI datatype
+/// \param LO language options
+///
+/// \returns true if the type matches
+static bool isBuiltinTypeMatching(const BuiltinType *Builtin,
+                                  std::string &BufferTypeName,
+                                  const std::string &MPIDatatype,
+                                  const LangOptions &LO) {
+  static std::multimap<BuiltinType::Kind, std::string> BuiltinMatches = {
+      {BuiltinType::SChar, "MPI_CHAR"},
+      {BuiltinType::SChar, "MPI_SIGNED_CHAR"},
+      {BuiltinType::Char_S, "MPI_CHAR"},
+      {BuiltinType::Char_S, "MPI_SIGNED_CHAR"},
+      {BuiltinType::UChar, "MPI_UNSIGNED_CHAR"},
+      {BuiltinType::Char_U, "MPI_UNSIGNED_CHAR"},
+      {BuiltinType::WChar_S, "MPI_WCHAR"},
+      {BuiltinType::WChar_U, "MPI_WCHAR"},
+      {BuiltinType::Bool, "MPI_C_BOOL"},
+      {BuiltinType::Bool, "MPI_CXX_BOOL"},
+      {BuiltinType::Short, "MPI_SHORT"},
+      {BuiltinType::Int, "MPI_INT"},
+      {BuiltinType::Long, "MPI_LONG"},
+      {BuiltinType::LongLong, "MPI_LONG_LONG"},
+      {BuiltinType::LongLong, "MPI_LONG_LONG_INT"},
+      {BuiltinType::UShort, "MPI_UNSIGNED_SHORT"},
+      {BuiltinType::UInt, "MPI_UNSIGNED"},
+      {BuiltinType::ULong, "MPI_UNSIGNED_LONG"},
+      {BuiltinType::ULongLong, "MPI_UNSIGNED_LONG_LONG"},
+      {BuiltinType::Float, "MPI_FLOAT"},
+      {BuiltinType::Double, "MPI_DOUBLE"},
+      {BuiltinType::LongDouble, "MPI_LONG_DOUBLE"}};
+
+  if (!isMPITypeMatching(BuiltinMatches, Builtin->getKind(), MPIDatatype)) {
+    BufferTypeName = Builtin->getName(LO);
+    return false;
+  }
+
+  return true;
+}
+
+/// Check if a complex float/double/long double buffer type matches
+/// the MPI datatype.
+///
+/// \param Complex buffer type
+/// \param BufferTypeName buffer type name, gets assigned
+/// \param MPIDatatype name of the MPI datatype
+/// \param LO language options
+///
+/// \returns true if the type matches or the buffer type is unknown
+static bool isCComplexTypeMatching(const ComplexType *const Complex,
+                                   std::string &BufferTypeName,
+                                   const std::string &MPIDatatype,
+                                   const LangOptions &LO) {
+  static std::multimap<BuiltinType::Kind, std::string> ComplexCMatches = {
+      {BuiltinType::Float, "MPI_C_COMPLEX"},
+      {BuiltinType::Float, "MPI_C_FLOAT_COMPLEX"},
+      {BuiltinType::Double, "MPI_C_DOUBLE_COMPLEX"},
+      {BuiltinType::LongDouble, "MPI_C_LONG_DOUBLE_COMPLEX"}};
+
+  const auto *Builtin =
+      Complex->getElementType().getTypePtr()->getAs<BuiltinType>();
+
+  if (Builtin &&
+      !isMPITypeMatching(ComplexCMatches, Builtin->getKind(), MPIDatatype)) {
+    BufferTypeName = (llvm::Twine(Builtin->getName(LO)) + " _Complex").str();
+    return false;
+  }
+  return true;
+}
+
+/// Check if a complex<float/double/long double> templated buffer type matches
+/// the MPI datatype.
+///
+/// \param Complex buffer type
+/// \param BufferTypeName buffer type name, gets assigned
+/// \param MPIDatatype name of the MPI datatype
+/// \param LO language options
+///
+/// \returns true if the type matches or the buffer type is unknown
+static bool
+isCXXComplexTypeMatching(const TemplateSpecializationType *const Template,
+                         std::string &BufferTypeName,
+                         const std::string &MPIDatatype,
+                         const LangOptions &LO) {
+  static std::multimap<BuiltinType::Kind, std::string> ComplexCXXMatches = {
+      {BuiltinType::Float, "MPI_CXX_FLOAT_COMPLEX"},
+      {BuiltinType::Double, "MPI_CXX_DOUBLE_COMPLEX"},
+      {BuiltinType::LongDouble, "MPI_CXX_LONG_DOUBLE_COMPLEX"}};
+
+  if (Template->getAsCXXRecordDecl()->getName() != "complex")
+    return true;
+
+  const auto *Builtin =
+      Template->getArg(0).getAsType().getTypePtr()->getAs<BuiltinType>();
+
+  if (Builtin &&
+      !isMPITypeMatching(ComplexCXXMatches, Builtin->getKind(), MPIDatatype)) {
+    BufferTypeName =
+        (llvm::Twine("complex<") + Builtin->getName(LO) + ">").str();
+    return false;
+  }
+
+  return true;
+}
+
+/// Check if a fixed size width buffer type matches the MPI datatype.
+///
+/// \param Complex buffer type
+/// \param BufferTypeName buffer type name, gets assigned
+/// \param MPIDatatype name of the MPI datatype
+///
+/// \returns true if the type matches or the buffer type is unknown
+static bool isTypedefTypeMatching(const TypedefType *const Typedef,
+                                  std::string &BufferTypeName,
+                                  const std::string &MPIDatatype) {
+  static llvm::StringMap<std::string> FixedWidthMatches = {
+      {"int8_t", "MPI_INT8_T"},     {"int16_t", "MPI_INT16_T"},
+      {"int32_t", "MPI_INT32_T"},   {"int64_t", "MPI_INT64_T"},
+      {"uint8_t", "MPI_UINT8_T"},   {"uint16_t", "MPI_UINT16_T"},
+      {"uint32_t", "MPI_UINT32_T"}, {"uint64_t", "MPI_UINT64_T"}};
+
+  const auto it = FixedWidthMatches.find(Typedef->getDecl()->getName());
+  // Check if the typedef is known and not matching the MPI datatype.
+  if (it != FixedWidthMatches.end() && it->getValue() != MPIDatatype) {
+    BufferTypeName = Typedef->getDecl()->getName();
+    return false;
+  }
+  return true;
+}
+
+/// Get the unqualified, dereferenced type of an argument.
+///
+/// \param CE call expression
+/// \param idx argument index
+///
+/// \returns type of the argument
+static const Type *argumentType(const CallExpr *const CE, const size_t idx) {
+  const QualType QT = CE->getArg(idx)->IgnoreImpCasts()->getType();
+  return QT.getTypePtr()->getPointeeOrArrayElementType();
+}
+
+void TypeMismatchCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(callExpr().bind("CE"), this);
+}
+
+void TypeMismatchCheck::check(const MatchFinder::MatchResult &Result) {
+  static ento::mpi::MPIFunctionClassifier FuncClassifier(*Result.Context);
+  const CallExpr *const CE = Result.Nodes.getNodeAs<CallExpr>("CE");
+  if (!CE->getDirectCallee())
+    return;
+
+  const IdentifierInfo *Identifier = CE->getDirectCallee()->getIdentifier();
+  if (!Identifier || !FuncClassifier.isMPIType(Identifier))
+    return;
+
+  // These containers are used, to capture buffer, MPI datatype pairs.
+  SmallVector<const Type *, 1> BufferTypes;
+  SmallVector<const Expr *, 1> BufferExprs;
+  SmallVector<StringRef, 1> MPIDatatypes;
+
+  // Adds a buffer, MPI datatype pair of an MPI call expression to the
+  // containers. For buffers, the type and expression is captured.
+  auto addPair = [&CE, &Result, &BufferTypes, &BufferExprs, &MPIDatatypes](
+      const size_t BufferIdx, const size_t DatatypeIdx) {
+    // Skip null pointer constants and in place 'operators'.
+    if (CE->getArg(BufferIdx)->isNullPointerConstant(
+            *Result.Context, Expr::NPC_ValueDependentIsNull) ||
+        tooling::fixit::getText(*CE->getArg(BufferIdx), *Result.Context) ==
+            "MPI_IN_PLACE")
+      return;
+
+    StringRef MPIDatatype =
+        tooling::fixit::getText(*CE->getArg(DatatypeIdx), *Result.Context);
+
+    const Type *ArgType = argumentType(CE, BufferIdx);
+    // Skip unknown MPI datatypes and void pointers.
+    if (!isStandardMPIDatatype(MPIDatatype) || ArgType->isVoidType())
+      return;
+
+    BufferTypes.push_back(ArgType);
+    BufferExprs.push_back(CE->getArg(BufferIdx));
+    MPIDatatypes.push_back(MPIDatatype);
+  };
+
+  // Collect all buffer, MPI datatype pairs for the inspected call expression.
+  if (FuncClassifier.isPointToPointType(Identifier)) {
+    addPair(0, 2);
+  } else if (FuncClassifier.isCollectiveType(Identifier)) {
+    if (FuncClassifier.isReduceType(Identifier)) {
+      addPair(0, 3);
+      addPair(1, 3);
+    } else if (FuncClassifier.isScatterType(Identifier) ||
+               FuncClassifier.isGatherType(Identifier) ||
+               FuncClassifier.isAlltoallType(Identifier)) {
+      addPair(0, 2);
+      addPair(3, 5);
+    } else if (FuncClassifier.isBcastType(Identifier)) {
+      addPair(0, 2);
+    }
+  }
+  checkArguments(BufferTypes, BufferExprs, MPIDatatypes,
+                 Result.Context->getLangOpts());
+}
+
+void TypeMismatchCheck::checkArguments(ArrayRef<const Type *> BufferTypes,
+                                       ArrayRef<const Expr *> BufferExprs,
+                                       ArrayRef<StringRef> MPIDatatypes,
+                                       const LangOptions &LO) {
+  std::string BufferTypeName;
+
+  for (size_t i = 0; i < MPIDatatypes.size(); ++i) {
+    const Type *const BT = BufferTypes[i];
+    bool Error = false;
+
+    if (const auto *Typedef = BT->getAs<TypedefType>()) {
+      Error = !isTypedefTypeMatching(Typedef, BufferTypeName, MPIDatatypes[i]);
+    } else if (const auto *Complex = BT->getAs<ComplexType>()) {
+      Error =
+          !isCComplexTypeMatching(Complex, BufferTypeName, MPIDatatypes[i], LO);
+    } else if (const auto *Template = BT->getAs<TemplateSpecializationType>()) {
+      Error = !isCXXComplexTypeMatching(Template, BufferTypeName,
+                                        MPIDatatypes[i], LO);
+    } else if (const auto *Builtin = BT->getAs<BuiltinType>()) {
+      Error =
+          !isBuiltinTypeMatching(Builtin, BufferTypeName, MPIDatatypes[i], LO);
+    }
+
+    if (Error) {
+      const auto Loc = BufferExprs[i]->getSourceRange().getBegin();
+      diag(Loc, "buffer type '%0' does not match the MPI datatype '%1'")
+          << BufferTypeName << MPIDatatypes[i];
+    }
+  }
+}
+
+} // namespace mpi
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.h b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.h
new file mode 100644 (file)
index 0000000..699110a
--- /dev/null
@@ -0,0 +1,52 @@
+//===--- TypeMismatchCheck.h - clang-tidy------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_TYPE_MISMATCH_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_TYPE_MISMATCH_H
+
+#include "../ClangTidy.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+namespace clang {
+namespace tidy {
+namespace mpi {
+
+/// This check verifies if buffer type and MPI (Message Passing Interface)
+/// datatype pairs match. All MPI datatypes defined by the MPI standard (3.1)
+/// are verified by this check. User defined typedefs, custom MPI datatypes and
+/// null pointer constants are skipped, in the course of verification.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/mpi-type-mismatch.html
+class TypeMismatchCheck : public ClangTidyCheck {
+public:
+  TypeMismatchCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  /// Check if the buffer type MPI datatype pairs match.
+  ///
+  /// \param BufferTypes buffer types
+  /// \param BufferExprs buffer arguments as expressions
+  /// \param MPIDatatypes MPI datatype
+  /// \param LO language options
+  void checkArguments(ArrayRef<const Type *> BufferTypes,
+                      ArrayRef<const Expr *> BufferExprs,
+                      ArrayRef<StringRef> MPIDatatypes,
+                      const LangOptions &LO);
+};
+
+} // namespace mpi
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_TYPE_MISMATCH_H
index 212c7aa..5106d3f 100644 (file)
@@ -15,6 +15,7 @@ add_clang_library(clangTidyPlugin
   clangTidyLLVMModule
   clangTidyMiscModule
   clangTidyModernizeModule
+  clangTidyMPIModule
   clangTidyPerformanceModule
   clangTidyReadabilityModule
   clangTooling
index 45ec798..682d5eb 100644 (file)
@@ -20,6 +20,7 @@ target_link_libraries(clang-tidy
   clangTidyLLVMModule
   clangTidyMiscModule
   clangTidyModernizeModule
+  clangTidyMPIModule
   clangTidyPerformanceModule
   clangTidyReadabilityModule
   clangTooling
index eed7d31..d887b8e 100644 (file)
@@ -454,6 +454,11 @@ extern volatile int ModernizeModuleAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED ModernizeModuleAnchorDestination =
     ModernizeModuleAnchorSource;
 
+// This anchor is used to force the linker to link the MPIModule.
+extern volatile int MPIModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED MPIModuleAnchorDestination =
+          MPIModuleAnchorSource;
+
 // This anchor is used to force the linker to link the PerformanceModule.
 extern volatile int PerformanceModuleAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED PerformanceModuleAnchorDestination =
index f2cf6a2..340cafc 100644 (file)
@@ -108,6 +108,7 @@ Clang-Tidy Checks
    modernize-use-nullptr
    modernize-use-override
    modernize-use-using
+   mpi-type-mismatch
    performance-faster-string-find
    performance-for-range-copy
    performance-implicit-cast-in-loop
diff --git a/clang-tools-extra/docs/clang-tidy/checks/mpi-type-mismatch.rst b/clang-tools-extra/docs/clang-tidy/checks/mpi-type-mismatch.rst
new file mode 100644 (file)
index 0000000..9ca6b7a
--- /dev/null
@@ -0,0 +1,19 @@
+.. title:: clang-tidy - mpi-type-mismatch
+
+mpi-type-mismatch
+=================
+
+This check verifies if buffer type and MPI (Message Passing Interface) datatype
+pairs match for used MPI functions. All MPI datatypes defined by the MPI
+standard (3.1) are verified by this check. User defined typedefs, custom MPI
+datatypes and null pointer constants are skipped, in the course of verification.
+
+Example:
+.. code:: c++
+  // In this case, the buffer type matches MPI datatype.
+  char buf;
+  MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+  // In the following case, the buffer type does not match MPI datatype.
+  int buf;
+  MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
diff --git a/clang-tools-extra/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h b/clang-tools-extra/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h
new file mode 100644 (file)
index 0000000..9697b60
--- /dev/null
@@ -0,0 +1,62 @@
+// This Message Passing Interface mock header is used, to mock typedefs,
+// constants and functions, required for integration tests being part of
+// clang-tidy MPI checks.
+
+#ifndef MPIMOCK_H
+#define MPIMOCK_H
+
+#define NULL 0
+
+// These typedefs are used to mock MPI types, fixed width integer types and the
+// templated C++ complex number type.
+typedef int MPI_Datatype;
+typedef int MPI_Comm;
+typedef int MPI_Request;
+typedef int MPI_Status;
+typedef int MPI_Op;
+typedef int int8_t;
+typedef int uint8_t;
+typedef int uint16_t;
+typedef int int64_t;
+namespace std { template<class T> struct complex { T real; T imag; }; }
+
+// These defines are used to mock MPI constants.
+#define MPI_DATATYPE_NULL 0
+#define MPI_CHAR 0
+#define MPI_BYTE 0
+#define MPI_INT 0
+#define MPI_LONG 0
+#define MPI_LONG_DOUBLE 0
+#define MPI_UNSIGNED 0
+#define MPI_INT8_T 0
+#define MPI_UINT8_T 0
+#define MPI_UINT16_T 0
+#define MPI_C_LONG_DOUBLE_COMPLEX 0
+#define MPI_FLOAT 0
+#define MPI_DOUBLE 0
+#define MPI_CXX_BOOL 0
+#define MPI_CXX_FLOAT_COMPLEX 0
+#define MPI_CXX_DOUBLE_COMPLEX 0
+#define MPI_CXX_LONG_DOUBLE_COMPLEX 0
+#define MPI_IN_PLACE 0
+#define MPI_COMM_WORLD 0
+#define MPI_STATUS_IGNORE 0
+#define MPI_STATUSES_IGNORE 0
+#define MPI_SUM 0
+
+// These declarations are used to mock MPI functions.
+int MPI_Comm_size(MPI_Comm, int *);
+int MPI_Comm_rank(MPI_Comm, int *);
+int MPI_Send(const void *, int, MPI_Datatype, int, int, MPI_Comm);
+int MPI_Recv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Status *);
+int MPI_Isend(const void *, int, MPI_Datatype, int, int, MPI_Comm,
+    MPI_Request *);
+int MPI_Irecv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *);
+int MPI_Wait(MPI_Request *, MPI_Status *);
+int MPI_Waitall(int, MPI_Request[], MPI_Status[]);
+int MPI_Reduce(const void *, void *, int, MPI_Datatype, MPI_Op, int, MPI_Comm);
+int MPI_Ireduce(const void *, void *, int, MPI_Datatype, MPI_Op, int, MPI_Comm,
+    MPI_Request *);
+int MPI_Bcast(void *, int count, MPI_Datatype, int, MPI_Comm);
+
+#endif  // end of include guard: MPIMOCK_H
diff --git a/clang-tools-extra/test/clang-tidy/mpi-type-mismatch.cpp b/clang-tools-extra/test/clang-tidy/mpi-type-mismatch.cpp
new file mode 100644 (file)
index 0000000..8920bc4
--- /dev/null
@@ -0,0 +1,254 @@
+// RUN: %check_clang_tidy %s mpi-type-mismatch %t -- -- -I %S/Inputs/mpi-type-mismatch
+
+#include "mpimock.h"
+
+void charNegativeTest() {
+  unsigned char buf;
+  MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned char' does not match the MPI datatype 'MPI_CHAR' [mpi-type-mismatch]
+  
+  int buf2;
+  MPI_Send(&buf2, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'int' does not match the MPI datatype 'MPI_CHAR'
+  
+  short buf3;
+  MPI_Send(&buf3, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'short' does not match the MPI datatype 'MPI_CHAR'
+
+  long buf4;
+  MPI_Send(&buf4, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long' does not match the MPI datatype 'MPI_CHAR'
+  
+  int8_t buf5;
+  MPI_Send(&buf5, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'int8_t' does not match the MPI datatype 'MPI_CHAR'
+
+  uint16_t buf6;
+  MPI_Send(&buf6, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_CHAR'
+
+  long double _Complex buf7;
+  MPI_Send(&buf7, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long double _Complex' does not match the MPI datatype 'MPI_CHAR'
+
+  std::complex<float> buf8;
+  MPI_Send(&buf8, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<float>' does not match the MPI datatype 'MPI_CHAR'
+}
+
+void intNegativeTest() {
+  unsigned char buf;
+  MPI_Send(&buf, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned char' does not match the MPI datatype 'MPI_INT'
+  
+  unsigned buf2;
+  MPI_Send(&buf2, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned int' does not match the MPI datatype 'MPI_INT'
+  
+  short buf3;
+  MPI_Send(&buf3, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'short' does not match the MPI datatype 'MPI_INT'
+
+  long buf4;
+  MPI_Send(&buf4, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long' does not match the MPI datatype 'MPI_INT'
+  
+  int8_t buf5;
+  MPI_Send(&buf5, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'int8_t' does not match the MPI datatype 'MPI_INT'
+
+  uint16_t buf6;
+  MPI_Send(&buf6, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_INT'
+
+  long double _Complex buf7;
+  MPI_Send(&buf7, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long double _Complex' does not match the MPI datatype 'MPI_INT'
+
+  std::complex<float> buf8;
+  MPI_Send(&buf8, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<float>' does not match the MPI datatype 'MPI_INT'
+}
+
+void longNegativeTest() {
+  char buf;
+  MPI_Send(&buf, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'char' does not match the MPI datatype 'MPI_LONG'
+  
+  unsigned buf2;
+  MPI_Send(&buf2, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned int' does not match the MPI datatype 'MPI_LONG'
+  
+  unsigned short buf3;
+  MPI_Send(&buf3, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned short' does not match the MPI datatype 'MPI_LONG'
+
+  unsigned long buf4;
+  MPI_Send(&buf4, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned long' does not match the MPI datatype 'MPI_LONG'
+  
+  int8_t buf5;
+  MPI_Send(&buf5, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'int8_t' does not match the MPI datatype 'MPI_LONG'
+
+  uint16_t buf6;
+  MPI_Send(&buf6, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_LONG'
+
+  long double _Complex buf7;
+  MPI_Send(&buf7, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long double _Complex' does not match the MPI datatype 'MPI_LONG'
+
+  std::complex<float> buf8;
+  MPI_Send(&buf8, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<float>' does not match the MPI datatype 'MPI_LONG'
+}
+
+void int8_tNegativeTest() {
+  char buf;
+  MPI_Send(&buf, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'char' does not match the MPI datatype 'MPI_INT8_T'
+  
+  unsigned buf2;
+  MPI_Send(&buf2, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned int' does not match the MPI datatype 'MPI_INT8_T'
+  
+  short buf3;
+  MPI_Send(&buf3, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'short' does not match the MPI datatype 'MPI_INT8_T'
+
+  unsigned long buf4;
+  MPI_Send(&buf4, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned long' does not match the MPI datatype 'MPI_INT8_T'
+  
+  uint8_t buf5;
+  MPI_Send(&buf5, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint8_t' does not match the MPI datatype 'MPI_INT8_T'
+
+  uint16_t buf6;
+  MPI_Send(&buf6, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_INT8_T'
+
+  long double _Complex buf7;
+  MPI_Send(&buf7, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long double _Complex' does not match the MPI datatype 'MPI_INT8_T'
+
+  std::complex<float> buf8;
+  MPI_Send(&buf8, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<float>' does not match the MPI datatype 'MPI_INT8_T'
+}
+
+void complex_c_long_double_complexNegativeTest() {
+  char buf;
+  MPI_Send(&buf, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'char' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+  
+  unsigned buf2;
+  MPI_Send(&buf2, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned int' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+  
+  short buf3;
+  MPI_Send(&buf3, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'short' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+  unsigned long buf4;
+  MPI_Send(&buf4, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned long' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+  
+  uint8_t buf5;
+  MPI_Send(&buf5, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint8_t' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+  uint16_t buf6;
+  MPI_Send(&buf6, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+  double _Complex buf7;
+  MPI_Send(&buf7, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'double _Complex' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+  std::complex<float> buf8;
+  MPI_Send(&buf8, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<float>' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+}
+
+void complex_cxx_float_complexNegativeTest() {
+  char buf;
+  MPI_Send(&buf, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'char' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+  
+  unsigned buf2;
+  MPI_Send(&buf2, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned int' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+  
+  short buf3;
+  MPI_Send(&buf3, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'short' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+  unsigned long buf4;
+  MPI_Send(&buf4, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned long' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+  
+  uint8_t buf5;
+  MPI_Send(&buf5, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint8_t' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+  uint16_t buf6;
+  MPI_Send(&buf6, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+  double _Complex buf7;
+  MPI_Send(&buf7, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'double _Complex' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+  std::complex<double> buf8;
+  MPI_Send(&buf8, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<double>' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+}
+
+void skippedTypesTests() {
+  // typedefs, user defined MPI and nullptr types are skipped
+  typedef char CHAR;
+  CHAR buf;
+  MPI_Send(&buf, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  
+  typedef unsigned UNSIGNED;
+  UNSIGNED buf2;
+  MPI_Send(&buf2, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  
+#define _MPI_LONG MPI_LONG
+  int buf3;
+  MPI_Send(&buf3, 1, _MPI_LONG, 0, 0, MPI_COMM_WORLD);
+  
+#define _MPI_CXX_FLOAT_COMPLEX MPI_CXX_FLOAT_COMPLEX
+  short buf4;
+  MPI_Send(&buf4, 1, _MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+  MPI_Send(NULL, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+}
+
+void positiveTests() {
+  char buf;
+  MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+  int buf2;
+  MPI_Send(&buf2, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+
+  long buf3;
+  MPI_Send(&buf3, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+
+  int8_t buf4;
+  MPI_Send(&buf4, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+
+  long double _Complex buf5;
+  MPI_Send(&buf5, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+  std::complex<float> buf6;
+  MPI_Send(&buf6, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+  uint8_t buf7;
+  MPI_Send(&buf7, 1, MPI_UINT8_T, 0, 0, MPI_COMM_WORLD);
+
+  uint16_t buf8;
+  MPI_Send(&buf8, 1, MPI_UINT16_T, 0, 0, MPI_COMM_WORLD);
+}