1 //===--- MtUnsafeCheck.cpp - clang-tidy -----------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "MtUnsafeCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 using namespace clang::ast_matchers
;
15 // Initial list was extracted from gcc documentation
16 static const clang::StringRef GlibcFunctions
[] = {
91 "::getwchar_unlocked",
124 "::__ppc_get_timebase_freq",
126 "::putchar_unlocked",
130 "::putwchar_unlocked",
133 "::register_printf_function",
176 static const clang::StringRef PosixFunctions
[] = {
200 "::getchar_unlocked",
213 "::getprotobynumber",
241 "::putchar_unlocked",
261 namespace clang::tidy
{
263 template <> struct OptionEnumMapping
<concurrency::MtUnsafeCheck::FunctionSet
> {
264 static llvm::ArrayRef
<
265 std::pair
<concurrency::MtUnsafeCheck::FunctionSet
, StringRef
>>
267 static constexpr std::pair
<concurrency::MtUnsafeCheck::FunctionSet
,
269 Mapping
[] = {{concurrency::MtUnsafeCheck::FunctionSet::Posix
, "posix"},
270 {concurrency::MtUnsafeCheck::FunctionSet::Glibc
, "glibc"},
271 {concurrency::MtUnsafeCheck::FunctionSet::Any
, "any"}};
272 return ArrayRef(Mapping
);
276 namespace concurrency
{
278 static ast_matchers::internal::Matcher
<clang::NamedDecl
>
279 hasAnyMtUnsafeNames(MtUnsafeCheck::FunctionSet Libc
) {
281 case MtUnsafeCheck::FunctionSet::Posix
:
282 return hasAnyName(PosixFunctions
);
283 case MtUnsafeCheck::FunctionSet::Glibc
:
284 return hasAnyName(GlibcFunctions
);
285 case MtUnsafeCheck::FunctionSet::Any
:
286 return anyOf(hasAnyName(PosixFunctions
), hasAnyName(GlibcFunctions
));
288 llvm_unreachable("invalid FunctionSet");
291 MtUnsafeCheck::MtUnsafeCheck(StringRef Name
, ClangTidyContext
*Context
)
292 : ClangTidyCheck(Name
, Context
),
293 FuncSet(Options
.get("FunctionSet", MtUnsafeCheck::FunctionSet::Any
)) {}
295 void MtUnsafeCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
296 Options
.store(Opts
, "FunctionSet", FuncSet
);
299 void MtUnsafeCheck::registerMatchers(MatchFinder
*Finder
) {
301 callExpr(callee(functionDecl(hasAnyMtUnsafeNames(FuncSet
))))
306 void MtUnsafeCheck::check(const MatchFinder::MatchResult
&Result
) {
307 const auto *Call
= Result
.Nodes
.getNodeAs
<CallExpr
>("mt-unsafe");
308 assert(Call
&& "Unhandled binding in the Matcher");
310 diag(Call
->getBeginLoc(), "function is not thread safe");
313 } // namespace concurrency
314 } // namespace clang::tidy