Alexander_Droste updated this revision to Diff 62640.
Alexander_Droste added a comment.

- fix comments


http://reviews.llvm.org/D21962

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MpiTypeMismatchCheck.cpp
  clang-tidy/misc/MpiTypeMismatchCheck.h
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-mpi-type-mismatch.rst
  test/clang-tidy/misc-mpi-type-mismatch.cpp

Index: test/clang-tidy/misc-mpi-type-mismatch.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/misc-mpi-type-mismatch.cpp
@@ -0,0 +1,249 @@
+// RUN: %check_clang_tidy %s misc-mpi-type-mismatch %t
+
+// #include "clang/../../test/Analysis/MPIMock.h"
+#include "/Users/lx/Documents/Text/Code/Open_Source/llvm_trunk_git/repo/tools/clang/test/Analysis/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'. [misc-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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+}
+
+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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+}
+
+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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+}
+
+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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+}
+
+void complex_c_long_double_complex_tNegativeTest() {
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+}
+
+void complex_cxx_float_complex_tNegativeTest() {
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+  
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+
+  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'. [misc-mpi-type-mismatch]
+}
+
+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);
+}
Index: docs/clang-tidy/checks/misc-mpi-type-mismatch.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/misc-mpi-type-mismatch.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - misc-mpi-type-mismatch
+
+misc-mpi-type-mismatch
+======================
+
+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.
+
+Example:
+// buffer type matches MPI datatype
+char buf;
+MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+// buffer type does not match MPI datatype
+int buf;
+MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -66,6 +66,7 @@
    misc-misplaced-widening-cast
    misc-move-const-arg
    misc-move-constructor-init
+   misc-mpi-type-mismatch
    misc-multiple-statement-macro
    misc-new-delete-overloads
    misc-noexcept-move-constructor
Index: clang-tidy/misc/MpiTypeMismatchCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/misc/MpiTypeMismatchCheck.h
@@ -0,0 +1,142 @@
+//===--- MpiTypeMismatchCheck.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_MISC_MPI_TYPE_MISMATCH_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MPI_TYPE_MISMATCH_H
+
+#include "../ClangTidy.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <map>
+#include <unordered_set>
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// 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/misc-mpi-type-mismatch.html
+class MpiTypeMismatchCheck : public ClangTidyCheck {
+public:
+  MpiTypeMismatchCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {
+    initContainers();
+  }
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  void initContainers();
+  void initTypedefMap();
+  void initBuiltinMap();
+  void initComplexCMap();
+  void initComplexCXXMap();
+  void initAlltypesSet();
+
+  /// Get the passed argument as a StringRef. This function is used, to obtain
+  /// MPI datatype (tags) by their name.
+  ///
+  /// \param CE call expression
+  /// \param idx argument index
+  /// \param Result
+  ///
+  /// \returns the argument as a string ref
+  StringRef argumentAsStringRef(
+      const CallExpr *const CE, const size_t idx,
+      const clang::ast_matchers::MatchFinder::MatchResult &Result) const;
+
+  /// Get the unqualified, dereferenced type of an argument.
+  ///
+  /// \param CE call expression
+  /// \param idx argument index
+  ///
+  /// \returns type of the argument
+  const Type *argumentType(const CallExpr *const CE, const size_t idx) const;
+
+  /// Check if the buffer type MPI datatype pairs match.
+  ///
+  /// \param BufferTypes buffer types
+  /// \param MPIDatatypes MPI datatype
+  /// \param ArgumentExpressions buffer arguments as expressions
+  void checkArguments(const SmallVector<const Type *, 1> &BufferTypes,
+                      const SmallVector<StringRef, 1> &MPIDatatypes,
+                      const SmallVector<const Expr *, 1> &ArgumentExpressions);
+
+  /// 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
+  bool isMPITypeMatching(
+      const std::multimap<clang::BuiltinType::Kind, std::string> &MultiMap,
+      const clang::BuiltinType::Kind Kind,
+      const std::string &MPIDatatype) const;
+
+  /// 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
+  ///
+  /// \returns true if the type matches or the buffer type is unknown
+  bool isCComplexTypeMatching(const clang::ComplexType *const Complex,
+                              std::string &BufferTypeName,
+                              const std::string &MPIDatatype) const;
+
+  /// 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
+  ///
+  /// \returns true if the type matches or the buffer type is unknown
+  bool isCXXComplexTypeMatching(
+      const clang::TemplateSpecializationType *const Template,
+      std::string &BufferTypeName, const std::string &MPIDatatype) const;
+
+  /// 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
+  bool isTypedefTypeMatching(const clang::TypedefType *const Typedef,
+                             std::string &BufferTypeName,
+                             const std::string &MPIDatatype) const;
+
+  /// Emit a warning in case of an error.
+  ///
+  /// \param ArgumentExpression buffer argument expression
+  /// \param BufferTypeName buffer type name
+  /// \param MPIDatatype MPI datatype name
+  void logError(const Expr *const ArgumentExpression, StringRef BufferTypeName,
+                StringRef MPIDatatype);
+
+  llvm::SmallVector<std::string, 32> MPITypes;
+  std::multimap<clang::BuiltinType::Kind, std::string> BuiltinMatches;
+  std::multimap<clang::BuiltinType::Kind, std::string> ComplexCMatches;
+  std::multimap<clang::BuiltinType::Kind, std::string> ComplexCXXMatches;
+  std::map<std::string, std::string> FixedWidthMatches;
+  std::unordered_set<std::string> AllTypes;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MPI_TYPE_MISMATCH_H
Index: clang-tidy/misc/MpiTypeMismatchCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/misc/MpiTypeMismatchCheck.cpp
@@ -0,0 +1,302 @@
+//===--- MpiTypeMismatchCheck.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 "MpiTypeMismatchCheck.h"
+#include "clang/../../lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void MpiTypeMismatchCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(callExpr().bind("CE"), this);
+}
+
+void MpiTypeMismatchCheck::initContainers() {
+  initTypedefMap();
+  initBuiltinMap();
+  initComplexCMap();
+  initComplexCXXMap();
+  initAlltypesSet();
+}
+
+void MpiTypeMismatchCheck::initTypedefMap() {
+  FixedWidthMatches["int8_t"] = "MPI_INT8_T";
+  FixedWidthMatches["int16_t"] = "MPI_INT16_T";
+  FixedWidthMatches["int32_t"] = "MPI_INT32_T";
+  FixedWidthMatches["int64_t"] = "MPI_INT64_T";
+  FixedWidthMatches["uint8_t"] = "MPI_UINT8_T";
+  FixedWidthMatches["uint16_t"] = "MPI_UINT16_T";
+  FixedWidthMatches["uint32_t"] = "MPI_UINT32_T";
+  FixedWidthMatches["uint64_t"] = "MPI_UINT64_T";
+}
+
+void MpiTypeMismatchCheck::initBuiltinMap() {
+  BuiltinMatches.insert({BuiltinType::SChar, "MPI_CHAR"});
+  BuiltinMatches.insert({BuiltinType::SChar, "MPI_SIGNED_CHAR"});
+  BuiltinMatches.insert({BuiltinType::Char_S, "MPI_CHAR"});
+  BuiltinMatches.insert({BuiltinType::Char_S, "MPI_SIGNED_CHAR"});
+  BuiltinMatches.insert({BuiltinType::UChar, "MPI_UNSIGNED_CHAR"});
+  BuiltinMatches.insert({BuiltinType::Char_U, "MPI_UNSIGNED_CHAR"});
+  BuiltinMatches.insert({BuiltinType::WChar_S, "MPI_WCHAR"});
+  BuiltinMatches.insert({BuiltinType::WChar_U, "MPI_WCHAR"});
+
+  BuiltinMatches.insert({BuiltinType::Bool, "MPI_C_BOOL"});
+  BuiltinMatches.insert({BuiltinType::Bool, "MPI_CXX_BOOL"});
+  BuiltinMatches.insert({BuiltinType::Short, "MPI_SHORT"});
+  BuiltinMatches.insert({BuiltinType::Int, "MPI_INT"});
+  BuiltinMatches.insert({BuiltinType::Long, "MPI_LONG"});
+  BuiltinMatches.insert({BuiltinType::LongLong, "MPI_LONG_LONG"});
+  BuiltinMatches.insert({BuiltinType::LongLong, "MPI_LONG_LONG_INT"});
+
+  BuiltinMatches.insert({BuiltinType::UShort, "MPI_UNSIGNED_SHORT"});
+  BuiltinMatches.insert({BuiltinType::UInt, "MPI_UNSIGNED"});
+  BuiltinMatches.insert({BuiltinType::ULong, "MPI_UNSIGNED_LONG"});
+  BuiltinMatches.insert({BuiltinType::ULongLong, "MPI_UNSIGNED_LONG_LONG"});
+
+  BuiltinMatches.insert({BuiltinType::Float, "MPI_FLOAT"});
+  BuiltinMatches.insert({BuiltinType::Double, "MPI_DOUBLE"});
+  BuiltinMatches.insert({BuiltinType::LongDouble, "MPI_LONG_DOUBLE"});
+}
+
+void MpiTypeMismatchCheck::initComplexCMap() {
+  ComplexCMatches.insert({BuiltinType::Float, "MPI_C_COMPLEX"});
+  ComplexCMatches.insert({BuiltinType::Float, "MPI_C_FLOAT_COMPLEX"});
+  ComplexCMatches.insert({BuiltinType::Double, "MPI_C_DOUBLE_COMPLEX"});
+  ComplexCMatches.insert(
+      {BuiltinType::LongDouble, "MPI_C_LONG_DOUBLE_COMPLEX"});
+}
+
+void MpiTypeMismatchCheck::initComplexCXXMap() {
+  ComplexCXXMatches.insert({BuiltinType::Float, "MPI_CXX_FLOAT_COMPLEX"});
+  ComplexCXXMatches.insert({BuiltinType::Double, "MPI_CXX_DOUBLE_COMPLEX"});
+  ComplexCXXMatches.insert(
+      {BuiltinType::LongDouble, "MPI_CXX_LONG_DOUBLE_COMPLEX"});
+}
+
+void MpiTypeMismatchCheck::initAlltypesSet() {
+  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"};
+}
+
+bool MpiTypeMismatchCheck::isMPITypeMatching(
+    const std::multimap<clang::BuiltinType::Kind, std::string> &MultiMap,
+    const clang::BuiltinType::Kind Kind, const std::string &MPIDatatype) const {
+
+  bool Matches{false};
+  auto ItPair = MultiMap.equal_range(Kind);
+  if (ItPair.first != ItPair.second) {
+    while (ItPair.first != ItPair.second) {
+      if (ItPair.first->second == MPIDatatype) {
+        Matches = true;
+        break;
+      }
+      ++ItPair.first;
+    }
+  }
+  return Matches;
+}
+
+StringRef MpiTypeMismatchCheck::argumentAsStringRef(
+    const CallExpr *const CE, const size_t idx,
+    const MatchFinder::MatchResult &Result) const {
+  return Lexer::getSourceText(
+      CharSourceRange::getTokenRange(CE->getArg(idx)->getSourceRange()),
+      *Result.SourceManager, LangOptions());
+}
+
+const Type *MpiTypeMismatchCheck::argumentType(const CallExpr *const CE,
+                                               const size_t idx) const {
+  const clang::QualType QT = CE->getArg(idx)->IgnoreImpCasts()->getType();
+  if (QT.getTypePtr()->isArrayType()) {
+    return QT.getTypePtr()->getArrayElementTypeNoTypeQual();
+  } else if (QT.getTypePtr()->isPointerType()) {
+    return QT.getTypePtr()->getPointeeType()->getBaseElementTypeUnsafe();
+  } else {
+    return (const Type *)nullptr;
+  }
+}
+
+void MpiTypeMismatchCheck::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;
+
+  SmallVector<const Type *, 1> BufferTypes;
+  SmallVector<StringRef, 1> MPIDatatypes;
+  SmallVector<const Expr *, 1> ArgumentExpr;
+
+  auto addPair = [&](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) ||
+        argumentAsStringRef(CE, BufferIdx, Result) == "MPI_IN_PLACE")
+      return;
+    // Skip unknown MPI datatypes and void pointer.
+    StringRef MPIDatatype = argumentAsStringRef(CE, DatatypeIdx, Result);
+    const Type *ArgType = argumentType(CE, BufferIdx);
+    if (AllTypes.find(MPIDatatype) == AllTypes.end() || ArgType->isVoidType())
+      return;
+
+    ArgumentExpr.push_back(CE->getArg(BufferIdx));
+    BufferTypes.push_back(ArgType);
+    MPIDatatypes.push_back(MPIDatatype);
+  };
+
+  // Collect pairs.
+  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, MPIDatatypes, ArgumentExpr);
+}
+
+bool MpiTypeMismatchCheck::isCComplexTypeMatching(
+    const clang::ComplexType *const Complex, std::string &BufferTypeName,
+    const std::string &MPIDatatype) const {
+
+  const clang::BuiltinType *const Builtin =
+      Complex->getElementType().getTypePtr()->getAs<BuiltinType>();
+  if (Builtin) {
+    BufferTypeName =
+        (llvm::Twine(Builtin->getName(LangOptions())) + " _Complex").str();
+    return isMPITypeMatching(ComplexCMatches, Builtin->getKind(), MPIDatatype);
+  }
+  return true;
+}
+
+bool MpiTypeMismatchCheck::isCXXComplexTypeMatching(
+    const clang::TemplateSpecializationType *const Template,
+    std::string &BufferTypeName, const std::string &MPIDatatype) const {
+
+  if (Template->getAsCXXRecordDecl()->getNameAsString() != "complex")
+    return true;
+
+  const clang::BuiltinType *const Builtin =
+      Template->getArg(0).getAsType().getTypePtr()->getAs<BuiltinType>();
+  if (Builtin) {
+    BufferTypeName =
+        (llvm::Twine("complex<") + Builtin->getName(LangOptions()) + ">").str();
+    return isMPITypeMatching(ComplexCXXMatches, Builtin->getKind(),
+                             MPIDatatype);
+  }
+  return true;
+}
+
+bool MpiTypeMismatchCheck::isTypedefTypeMatching(
+    const clang::TypedefType *const Typedef, std::string &BufferTypeName,
+    const std::string &MPIDatatype) const {
+
+  StringRef TypedefName = Typedef->getDecl()->getQualifiedNameAsString();
+  BufferTypeName = TypedefName;
+  // Check if the typedef is known.
+  if (FixedWidthMatches.find(TypedefName) != FixedWidthMatches.end()) {
+    return FixedWidthMatches.at(TypedefName) == MPIDatatype;
+  }
+  return true;
+}
+
+void MpiTypeMismatchCheck::logError(const Expr *const ArgumentExpression,
+                                    StringRef BufferTypeName,
+                                    StringRef MPIDatatype) {
+  auto Loc = ArgumentExpression->getSourceRange().getBegin();
+  diag(Loc, (llvm::Twine("Buffer type '") + BufferTypeName +
+             "' does not match the MPI datatype '" + MPIDatatype + "'.")
+                .str());
+}
+
+void MpiTypeMismatchCheck::checkArguments(
+    const SmallVector<const Type *, 1> &BufferTypes,
+    const SmallVector<StringRef, 1> &MPIDatatypes,
+    const SmallVector<const Expr *, 1> &ArgumentExpressions) {
+
+  for (size_t i = 0; i < MPIDatatypes.size(); ++i) {
+    const Type *BT = BufferTypes[i];
+    bool Error{false};
+    std::string BufferTypeName;
+
+    // typedef
+    if (const clang::TypedefType *Typedef = BT->getAs<TypedefType>()) {
+      Error = !isTypedefTypeMatching(Typedef, BufferTypeName, MPIDatatypes[i]);
+    }
+    // complex c type
+    else if (const clang::ComplexType *Complex = BT->getAs<ComplexType>()) {
+      Error = !isCComplexTypeMatching(Complex, BufferTypeName, MPIDatatypes[i]);
+    }
+    // template type
+    else if (const clang::TemplateSpecializationType *Template =
+                 BT->getAs<TemplateSpecializationType>()) {
+      Error =
+          !isCXXComplexTypeMatching(Template, BufferTypeName, MPIDatatypes[i]);
+    }
+    // builtin type
+    else if (const clang::BuiltinType *Builtin = BT->getAs<BuiltinType>()) {
+      BufferTypeName = Builtin->getName(LangOptions());
+      Error = !isMPITypeMatching(BuiltinMatches, Builtin->getKind(),
+                                 MPIDatatypes[i]);
+    }
+
+    if (Error)
+      logError(ArgumentExpressions[i], BufferTypeName, MPIDatatypes[i]);
+  }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/misc/MiscTidyModule.cpp
===================================================================
--- clang-tidy/misc/MiscTidyModule.cpp
+++ clang-tidy/misc/MiscTidyModule.cpp
@@ -13,6 +13,7 @@
 #include "ArgumentCommentCheck.h"
 #include "AssertSideEffectCheck.h"
 #include "MisplacedConstCheck.h"
+#include "MpiTypeMismatchCheck.h"
 #include "UnconventionalAssignOperatorCheck.h"
 #include "BoolPointerImplicitConversionCheck.h"
 #include "DanglingHandleCheck.h"
@@ -64,6 +65,8 @@
         "misc-assert-side-effect");
     CheckFactories.registerCheck<MisplacedConstCheck>(
         "misc-misplaced-const");
+    CheckFactories.registerCheck<MpiTypeMismatchCheck>(
+        "misc-mpi-type-mismatch");
     CheckFactories.registerCheck<UnconventionalAssignOperatorCheck>(
         "misc-unconventional-assign-operator");
     CheckFactories.registerCheck<BoolPointerImplicitConversionCheck>(
Index: clang-tidy/misc/CMakeLists.txt
===================================================================
--- clang-tidy/misc/CMakeLists.txt
+++ clang-tidy/misc/CMakeLists.txt
@@ -4,6 +4,7 @@
   ArgumentCommentCheck.cpp
   AssertSideEffectCheck.cpp
   MisplacedConstCheck.cpp
+  MpiTypeMismatchCheck.cpp
   UnconventionalAssignOperatorCheck.cpp
   BoolPointerImplicitConversionCheck.cpp
   DanglingHandleCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to