11 #include "clang/Lex/Lexer.h" 12 #include "clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h" 13 #include "clang/Tooling/FixIt.h" 15 #include <unordered_set> 33 const std::string &MPIDatatype) {
34 auto ItPair = MultiMap.equal_range(Kind);
35 while (ItPair.first != ItPair.second) {
36 if (ItPair.first->second == MPIDatatype)
49 static std::unordered_set<std::string> AllTypes = {
63 "MPI_UNSIGNED_LONG_LONG",
68 "MPI_C_FLOAT_COMPLEX",
69 "MPI_C_DOUBLE_COMPLEX",
70 "MPI_C_LONG_DOUBLE_COMPLEX",
80 "MPI_CXX_FLOAT_COMPLEX",
81 "MPI_CXX_DOUBLE_COMPLEX",
82 "MPI_CXX_LONG_DOUBLE_COMPLEX"};
84 return AllTypes.find(MPIDatatype) != AllTypes.end();
96 std::string &BufferTypeName,
97 const std::string &MPIDatatype,
98 const LangOptions &LO) {
99 static std::multimap<BuiltinType::Kind, std::string> BuiltinMatches = {
102 {BuiltinType::SChar,
"MPI_CHAR"},
103 {BuiltinType::SChar,
"MPI_SIGNED_CHAR"},
104 {BuiltinType::SChar,
"MPI_UNSIGNED_CHAR"},
105 {BuiltinType::Char_S,
"MPI_CHAR"},
106 {BuiltinType::Char_S,
"MPI_SIGNED_CHAR"},
107 {BuiltinType::Char_S,
"MPI_UNSIGNED_CHAR"},
108 {BuiltinType::UChar,
"MPI_CHAR"},
109 {BuiltinType::UChar,
"MPI_SIGNED_CHAR"},
110 {BuiltinType::UChar,
"MPI_UNSIGNED_CHAR"},
111 {BuiltinType::Char_U,
"MPI_CHAR"},
112 {BuiltinType::Char_U,
"MPI_SIGNED_CHAR"},
113 {BuiltinType::Char_U,
"MPI_UNSIGNED_CHAR"},
114 {BuiltinType::WChar_S,
"MPI_WCHAR"},
115 {BuiltinType::WChar_U,
"MPI_WCHAR"},
116 {BuiltinType::Bool,
"MPI_C_BOOL"},
117 {BuiltinType::Bool,
"MPI_CXX_BOOL"},
118 {BuiltinType::Short,
"MPI_SHORT"},
119 {BuiltinType::Int,
"MPI_INT"},
120 {BuiltinType::Long,
"MPI_LONG"},
121 {BuiltinType::LongLong,
"MPI_LONG_LONG"},
122 {BuiltinType::LongLong,
"MPI_LONG_LONG_INT"},
123 {BuiltinType::UShort,
"MPI_UNSIGNED_SHORT"},
124 {BuiltinType::UInt,
"MPI_UNSIGNED"},
125 {BuiltinType::ULong,
"MPI_UNSIGNED_LONG"},
126 {BuiltinType::ULongLong,
"MPI_UNSIGNED_LONG_LONG"},
127 {BuiltinType::Float,
"MPI_FLOAT"},
128 {BuiltinType::Double,
"MPI_DOUBLE"},
129 {BuiltinType::LongDouble,
"MPI_LONG_DOUBLE"}};
132 BufferTypeName = Builtin->getName(LO);
149 std::string &BufferTypeName,
150 const std::string &MPIDatatype,
151 const LangOptions &LO) {
152 static std::multimap<BuiltinType::Kind, std::string> ComplexCMatches = {
153 {BuiltinType::Float,
"MPI_C_COMPLEX"},
154 {BuiltinType::Float,
"MPI_C_FLOAT_COMPLEX"},
155 {BuiltinType::Double,
"MPI_C_DOUBLE_COMPLEX"},
156 {BuiltinType::LongDouble,
"MPI_C_LONG_DOUBLE_COMPLEX"}};
158 const auto *Builtin =
159 Complex->getElementType().getTypePtr()->getAs<BuiltinType>();
163 BufferTypeName = (llvm::Twine(Builtin->getName(LO)) +
" _Complex").str();
180 std::string &BufferTypeName,
181 const std::string &MPIDatatype,
182 const LangOptions &LO) {
183 static std::multimap<BuiltinType::Kind, std::string> ComplexCXXMatches = {
184 {BuiltinType::Float,
"MPI_CXX_FLOAT_COMPLEX"},
185 {BuiltinType::Double,
"MPI_CXX_DOUBLE_COMPLEX"},
186 {BuiltinType::LongDouble,
"MPI_CXX_LONG_DOUBLE_COMPLEX"}};
188 if (Template->getAsCXXRecordDecl()->getName() !=
"complex")
191 const auto *Builtin =
192 Template->getArg(0).getAsType().getTypePtr()->getAs<BuiltinType>();
197 (llvm::Twine(
"complex<") + Builtin->getName(LO) +
">").str();
212 std::string &BufferTypeName,
213 const std::string &MPIDatatype) {
214 static llvm::StringMap<std::string> FixedWidthMatches = {
215 {
"int8_t",
"MPI_INT8_T"}, {
"int16_t",
"MPI_INT16_T"},
216 {
"int32_t",
"MPI_INT32_T"}, {
"int64_t",
"MPI_INT64_T"},
217 {
"uint8_t",
"MPI_UINT8_T"}, {
"uint16_t",
"MPI_UINT16_T"},
218 {
"uint32_t",
"MPI_UINT32_T"}, {
"uint64_t",
"MPI_UINT64_T"}};
220 const auto it = FixedWidthMatches.find(Typedef->getDecl()->getName());
222 if (it != FixedWidthMatches.end() && it->getValue() != MPIDatatype) {
223 BufferTypeName = Typedef->getDecl()->getName();
235 static const Type *
argumentType(
const CallExpr *
const CE,
const size_t idx) {
236 const QualType QT = CE->getArg(idx)->IgnoreImpCasts()->getType();
237 return QT.getTypePtr()->getPointeeOrArrayElementType();
240 void TypeMismatchCheck::registerMatchers(MatchFinder *Finder) {
241 Finder->addMatcher(callExpr().bind(
"CE"),
this);
244 void TypeMismatchCheck::check(
const MatchFinder::MatchResult &Result) {
245 static ento::mpi::MPIFunctionClassifier FuncClassifier(*Result.Context);
246 const auto *
const CE = Result.Nodes.getNodeAs<CallExpr>(
"CE");
247 if (!CE->getDirectCallee())
250 const IdentifierInfo *Identifier = CE->getDirectCallee()->getIdentifier();
251 if (!Identifier || !FuncClassifier.isMPIType(Identifier))
255 SmallVector<const Type *, 1> BufferTypes;
256 SmallVector<const Expr *, 1> BufferExprs;
257 SmallVector<StringRef, 1> MPIDatatypes;
261 auto addPair = [&CE, &Result, &BufferTypes, &BufferExprs, &MPIDatatypes](
262 const size_t BufferIdx,
const size_t DatatypeIdx) {
264 if (CE->getArg(BufferIdx)->isNullPointerConstant(
265 *Result.Context, Expr::NPC_ValueDependentIsNull) ||
266 tooling::fixit::getText(*CE->getArg(BufferIdx), *Result.Context) ==
270 StringRef MPIDatatype =
271 tooling::fixit::getText(*CE->getArg(DatatypeIdx), *Result.Context);
278 BufferTypes.push_back(ArgType);
279 BufferExprs.push_back(CE->getArg(BufferIdx));
280 MPIDatatypes.push_back(MPIDatatype);
284 if (FuncClassifier.isPointToPointType(Identifier)) {
286 }
else if (FuncClassifier.isCollectiveType(Identifier)) {
287 if (FuncClassifier.isReduceType(Identifier)) {
290 }
else if (FuncClassifier.isScatterType(Identifier) ||
291 FuncClassifier.isGatherType(Identifier) ||
292 FuncClassifier.isAlltoallType(Identifier)) {
295 }
else if (FuncClassifier.isBcastType(Identifier)) {
299 checkArguments(BufferTypes, BufferExprs, MPIDatatypes, getLangOpts());
302 void TypeMismatchCheck::checkArguments(ArrayRef<const Type *> BufferTypes,
303 ArrayRef<const Expr *> BufferExprs,
304 ArrayRef<StringRef> MPIDatatypes,
305 const LangOptions &LO) {
306 std::string BufferTypeName;
308 for (
size_t i = 0; i < MPIDatatypes.size(); ++i) {
309 const Type *
const BT = BufferTypes[i];
312 if (
const auto *Typedef = BT->getAs<TypedefType>()) {
314 }
else if (
const auto *Complex = BT->getAs<ComplexType>()) {
317 }
else if (
const auto *Template = BT->getAs<TemplateSpecializationType>()) {
319 MPIDatatypes[i], LO);
320 }
else if (
const auto *Builtin = BT->getAs<BuiltinType>()) {
326 const auto Loc = BufferExprs[i]->getSourceRange().getBegin();
327 diag(
Loc,
"buffer type '%0' does not match the MPI datatype '%1'")
328 << BufferTypeName << MPIDatatypes[i];
SourceLocation Loc
'#' location in the include directive
static bool isTypedefTypeMatching(const TypedefType *const Typedef, std::string &BufferTypeName, const std::string &MPIDatatype)
Check if a fixed size width buffer type matches the MPI datatype.
static bool isMPITypeMatching(const std::multimap< BuiltinType::Kind, std::string > &MultiMap, const BuiltinType::Kind Kind, const std::string &MPIDatatype)
Check if a BuiltinType::Kind matches the MPI datatype.
static bool isStandardMPIDatatype(const std::string &MPIDatatype)
Check if the MPI datatype is a standard type.
static bool isCComplexTypeMatching(const ComplexType *const Complex, std::string &BufferTypeName, const std::string &MPIDatatype, const LangOptions &LO)
Check if a complex float/double/long double 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 isBuiltinTypeMatching(const BuiltinType *Builtin, std::string &BufferTypeName, const std::string &MPIDatatype, const LangOptions &LO)
Check if a BuiltinType matches the MPI datatype.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static bool isCXXComplexTypeMatching(const TemplateSpecializationType *const Template, std::string &BufferTypeName, const std::string &MPIDatatype, const LangOptions &LO)
Check if a complex<float/double/long double> templated buffer type matches the MPI datatype...