10#include "clang/Lex/Lexer.h"
11#include "clang/Tooling/FixIt.h"
12#include "llvm/ADT/StringSet.h"
28 const BuiltinType::Kind Kind, StringRef MPIDatatype) {
29 auto ItPair = MultiMap.equal_range(
Kind);
30 while (ItPair.first != ItPair.second) {
31 if (ItPair.first->second == MPIDatatype)
44 static llvm::StringSet<> AllTypes = {
"MPI_C_BOOL",
57 "MPI_UNSIGNED_LONG_LONG",
62 "MPI_C_FLOAT_COMPLEX",
63 "MPI_C_DOUBLE_COMPLEX",
64 "MPI_C_LONG_DOUBLE_COMPLEX",
74 "MPI_CXX_FLOAT_COMPLEX",
75 "MPI_CXX_DOUBLE_COMPLEX",
76 "MPI_CXX_LONG_DOUBLE_COMPLEX"};
78 return AllTypes.contains(MPIDatatype);
90 std::string &BufferTypeName,
91 StringRef MPIDatatype,
92 const LangOptions &LO) {
93 static std::multimap<BuiltinType::Kind, StringRef> BuiltinMatches = {
96 {BuiltinType::SChar,
"MPI_CHAR"},
97 {BuiltinType::SChar,
"MPI_SIGNED_CHAR"},
98 {BuiltinType::SChar,
"MPI_UNSIGNED_CHAR"},
99 {BuiltinType::Char_S,
"MPI_CHAR"},
100 {BuiltinType::Char_S,
"MPI_SIGNED_CHAR"},
101 {BuiltinType::Char_S,
"MPI_UNSIGNED_CHAR"},
102 {BuiltinType::UChar,
"MPI_CHAR"},
103 {BuiltinType::UChar,
"MPI_SIGNED_CHAR"},
104 {BuiltinType::UChar,
"MPI_UNSIGNED_CHAR"},
105 {BuiltinType::Char_U,
"MPI_CHAR"},
106 {BuiltinType::Char_U,
"MPI_SIGNED_CHAR"},
107 {BuiltinType::Char_U,
"MPI_UNSIGNED_CHAR"},
108 {BuiltinType::WChar_S,
"MPI_WCHAR"},
109 {BuiltinType::WChar_U,
"MPI_WCHAR"},
110 {BuiltinType::Bool,
"MPI_C_BOOL"},
111 {BuiltinType::Bool,
"MPI_CXX_BOOL"},
112 {BuiltinType::Short,
"MPI_SHORT"},
113 {BuiltinType::Int,
"MPI_INT"},
114 {BuiltinType::Long,
"MPI_LONG"},
115 {BuiltinType::LongLong,
"MPI_LONG_LONG"},
116 {BuiltinType::LongLong,
"MPI_LONG_LONG_INT"},
117 {BuiltinType::UShort,
"MPI_UNSIGNED_SHORT"},
118 {BuiltinType::UInt,
"MPI_UNSIGNED"},
119 {BuiltinType::ULong,
"MPI_UNSIGNED_LONG"},
120 {BuiltinType::ULongLong,
"MPI_UNSIGNED_LONG_LONG"},
121 {BuiltinType::Float,
"MPI_FLOAT"},
122 {BuiltinType::Double,
"MPI_DOUBLE"},
123 {BuiltinType::LongDouble,
"MPI_LONG_DOUBLE"}};
126 BufferTypeName = std::string(Builtin->getName(LO));
143 std::string &BufferTypeName,
144 StringRef MPIDatatype,
145 const LangOptions &LO) {
146 static std::multimap<BuiltinType::Kind, StringRef> ComplexCMatches = {
147 {BuiltinType::Float,
"MPI_C_COMPLEX"},
148 {BuiltinType::Float,
"MPI_C_FLOAT_COMPLEX"},
149 {BuiltinType::Double,
"MPI_C_DOUBLE_COMPLEX"},
150 {BuiltinType::LongDouble,
"MPI_C_LONG_DOUBLE_COMPLEX"}};
152 const auto *Builtin =
153 Complex->getElementType().getTypePtr()->getAs<BuiltinType>();
157 BufferTypeName = (llvm::Twine(Builtin->getName(LO)) +
" _Complex").str();
174 std::string &BufferTypeName, StringRef MPIDatatype,
175 const LangOptions &LO) {
176 static std::multimap<BuiltinType::Kind, StringRef> ComplexCXXMatches = {
177 {BuiltinType::Float,
"MPI_CXX_FLOAT_COMPLEX"},
178 {BuiltinType::Double,
"MPI_CXX_DOUBLE_COMPLEX"},
179 {BuiltinType::LongDouble,
"MPI_CXX_LONG_DOUBLE_COMPLEX"}};
181 if (Template->getAsCXXRecordDecl()->getName() !=
"complex")
184 const auto *Builtin = Template->template_arguments()[0]
187 ->getAs<BuiltinType>();
192 (llvm::Twine(
"complex<") + Builtin->getName(LO) +
">").str();
207 std::string &BufferTypeName,
208 StringRef MPIDatatype) {
209 static llvm::StringMap<StringRef> FixedWidthMatches = {
210 {
"int8_t",
"MPI_INT8_T"}, {
"int16_t",
"MPI_INT16_T"},
211 {
"int32_t",
"MPI_INT32_T"}, {
"int64_t",
"MPI_INT64_T"},
212 {
"uint8_t",
"MPI_UINT8_T"}, {
"uint16_t",
"MPI_UINT16_T"},
213 {
"uint32_t",
"MPI_UINT32_T"}, {
"uint64_t",
"MPI_UINT64_T"}};
215 const auto It = FixedWidthMatches.find(Typedef->getDecl()->getName());
217 if (It != FixedWidthMatches.end() && It->getValue() != MPIDatatype) {
218 BufferTypeName = std::string(Typedef->getDecl()->getName());
231 const QualType QT =
CE->getArg(Idx)->IgnoreImpCasts()->getType();
232 return QT.getTypePtr()->getPointeeOrArrayElementType();
236 Finder->addMatcher(callExpr().bind(
"CE"),
this);
240 const auto *
const CE = Result.Nodes.getNodeAs<CallExpr>(
"CE");
241 if (!
CE->getDirectCallee())
245 FuncClassifier.emplace(*Result.Context);
247 const IdentifierInfo *Identifier =
CE->getDirectCallee()->getIdentifier();
248 if (!Identifier || !FuncClassifier->isMPIType(Identifier))
252 SmallVector<const Type *, 1> BufferTypes;
253 SmallVector<const Expr *, 1> BufferExprs;
254 SmallVector<StringRef, 1> MPIDatatypes;
258 auto AddPair = [&
CE, &Result, &BufferTypes, &BufferExprs, &MPIDatatypes](
259 const size_t BufferIdx,
const size_t DatatypeIdx) {
261 if (
CE->getArg(BufferIdx)->isNullPointerConstant(
262 *Result.Context, Expr::NPC_ValueDependentIsNull) ||
263 tooling::fixit::getText(*
CE->getArg(BufferIdx), *Result.Context) ==
267 StringRef MPIDatatype =
268 tooling::fixit::getText(*
CE->getArg(DatatypeIdx), *Result.Context);
275 BufferTypes.push_back(ArgType);
276 BufferExprs.push_back(
CE->getArg(BufferIdx));
277 MPIDatatypes.push_back(MPIDatatype);
281 if (FuncClassifier->isPointToPointType(Identifier)) {
283 }
else if (FuncClassifier->isCollectiveType(Identifier)) {
284 if (FuncClassifier->isReduceType(Identifier)) {
287 }
else if (FuncClassifier->isScatterType(Identifier) ||
288 FuncClassifier->isGatherType(Identifier) ||
289 FuncClassifier->isAlltoallType(Identifier)) {
292 }
else if (FuncClassifier->isBcastType(Identifier)) {
296 checkArguments(BufferTypes, BufferExprs, MPIDatatypes,
getLangOpts());
299void TypeMismatchCheck::checkArguments(ArrayRef<const Type *> BufferTypes,
300 ArrayRef<const Expr *> BufferExprs,
301 ArrayRef<StringRef> MPIDatatypes,
302 const LangOptions &LO) {
303 std::string BufferTypeName;
305 for (
size_t I = 0; I < MPIDatatypes.size(); ++I) {
306 const Type *
const BT = BufferTypes[I];
309 if (
const auto *Typedef = BT->getAs<TypedefType>()) {
311 }
else if (
const auto *Complex = BT->getAs<ComplexType>()) {
314 }
else if (
const auto *Template = BT->getAs<TemplateSpecializationType>()) {
316 MPIDatatypes[I], LO);
317 }
else if (
const auto *Builtin = BT->getAs<BuiltinType>()) {
323 const auto Loc = BufferExprs[I]->getSourceRange().getBegin();
324 diag(
Loc,
"buffer type '%0' does not match the MPI datatype '%1'")
325 << BufferTypeName << MPIDatatypes[I];
static constexpr llvm::SourceMgr::DiagKind Error
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
const LangOptions & getLangOpts() const
Returns the language options from the context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void onEndOfTranslationUnit() override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
static bool isTypedefTypeMatching(const TypedefType *const Typedef, std::string &BufferTypeName, StringRef MPIDatatype)
Check if a fixed size width buffer type matches the MPI datatype.
static bool isCComplexTypeMatching(const ComplexType *const Complex, std::string &BufferTypeName, StringRef MPIDatatype, const LangOptions &LO)
Check if a complex float/double/long double buffer type matches the MPI datatype.
static bool isBuiltinTypeMatching(const BuiltinType *Builtin, std::string &BufferTypeName, StringRef MPIDatatype, const LangOptions &LO)
Check if a BuiltinType matches the MPI datatype.
static bool isCXXComplexTypeMatching(const TemplateSpecializationType *const Template, std::string &BufferTypeName, StringRef MPIDatatype, const LangOptions &LO)
Check if a complex<float/double/long double> templated buffer type matches the MPI datatype.
static const Type * argumentType(const CallExpr *const CE, const size_t Idx)
Get the unqualified, dereferenced type of an argument.
static bool isMPITypeMatching(const std::multimap< BuiltinType::Kind, StringRef > &MultiMap, const BuiltinType::Kind Kind, StringRef MPIDatatype)
Check if a BuiltinType::Kind matches the MPI datatype.
static bool isStandardMPIDatatype(StringRef MPIDatatype)
Check if the MPI datatype is a standard type.