Alexander_Droste created this revision.
Alexander_Droste added a reviewer: alexfh.
Alexander_Droste added a subscriber: cfe-commits.

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.


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 typedef, 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
@@ -60,12 +60,14 @@
    misc-inaccurate-erase
    misc-incorrect-roundings
    misc-inefficient-algorithm
+   misc-m-p-i-type-mismatch
    misc-macro-parentheses
    misc-macro-repeated-side-effects
    misc-misplaced-const
    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,158 @@
+//===--- 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 typedef, 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
+   *
+   * @return 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
+   *
+   * @return 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
+   *
+   * @return 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
+   *
+   * @return 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
+   *
+   * @return 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
+   *
+   * @return 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