1 #include "clang/ASTMatchers/ASTMatchFinder.h"
2 #include "clang/ASTMatchers/ASTMatchers.h"
3 #include "clang/Analysis/AnalysisDeclContext.h"
4 #include "clang/Frontend/ASTUnit.h"
5 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
6 #include "clang/Tooling/Tooling.h"
7 #include "gtest/gtest.h"
11 using namespace clang
;
13 using namespace ast_matchers
;
15 class IsCLibraryFunctionTest
: public testing::Test
{
16 std::unique_ptr
<ASTUnit
> ASTUnitP
;
17 const FunctionDecl
*Result
= nullptr;
20 const FunctionDecl
*getFunctionDecl() const { return Result
; }
22 testing::AssertionResult
buildAST(StringRef Code
) {
23 ASTUnitP
= tooling::buildASTFromCode(Code
);
25 return testing::AssertionFailure() << "AST construction failed";
27 ASTContext
&Context
= ASTUnitP
->getASTContext();
28 if (Context
.getDiagnostics().hasErrorOccurred())
29 return testing::AssertionFailure() << "Compilation error";
31 auto Matches
= ast_matchers::match(functionDecl().bind("fn"), Context
);
33 return testing::AssertionFailure() << "No function declaration found";
35 if (Matches
.size() > 1)
36 return testing::AssertionFailure()
37 << "Multiple function declarations found";
39 Result
= Matches
[0].getNodeAs
<FunctionDecl
>("fn");
40 return testing::AssertionSuccess();
44 TEST_F(IsCLibraryFunctionTest
, AcceptsGlobal
) {
45 ASSERT_TRUE(buildAST(R
"cpp(void fun();)cpp"));
46 EXPECT_TRUE(CheckerContext::isCLibraryFunction(getFunctionDecl()));
49 TEST_F(IsCLibraryFunctionTest
, AcceptsExternCGlobal
) {
50 ASSERT_TRUE(buildAST(R
"cpp(extern "C
" { void fun(); })cpp"));
51 EXPECT_TRUE(CheckerContext::isCLibraryFunction(getFunctionDecl()));
54 TEST_F(IsCLibraryFunctionTest
, RejectsNoInlineNoExternalLinkage
) {
55 // Functions that are neither inlined nor externally visible cannot be C
57 ASSERT_TRUE(buildAST(R
"cpp(static void fun();)cpp"));
58 EXPECT_FALSE(CheckerContext::isCLibraryFunction(getFunctionDecl()));
61 TEST_F(IsCLibraryFunctionTest
, RejectsAnonymousNamespace
) {
62 ASSERT_TRUE(buildAST(R
"cpp(namespace { void fun(); })cpp"));
63 EXPECT_FALSE(CheckerContext::isCLibraryFunction(getFunctionDecl()));
66 TEST_F(IsCLibraryFunctionTest
, AcceptsStdNamespace
) {
67 ASSERT_TRUE(buildAST(R
"cpp(namespace std { void fun(); })cpp"));
68 EXPECT_TRUE(CheckerContext::isCLibraryFunction(getFunctionDecl()));
71 TEST_F(IsCLibraryFunctionTest
, RejectsOtherNamespaces
) {
72 ASSERT_TRUE(buildAST(R
"cpp(namespace stdx { void fun(); })cpp"));
73 EXPECT_FALSE(CheckerContext::isCLibraryFunction(getFunctionDecl()));
76 TEST_F(IsCLibraryFunctionTest
, RejectsClassStatic
) {
77 ASSERT_TRUE(buildAST(R
"cpp(class A { static void fun(); };)cpp"));
78 EXPECT_FALSE(CheckerContext::isCLibraryFunction(getFunctionDecl()));
81 TEST_F(IsCLibraryFunctionTest
, RejectsClassMember
) {
82 ASSERT_TRUE(buildAST(R
"cpp(class A { void fun(); };)cpp"));
83 EXPECT_FALSE(CheckerContext::isCLibraryFunction(getFunctionDecl()));