xref: /llvm-project/clang/unittests/StaticAnalyzer/IsCLibraryFunctionTest.cpp (revision 80ab8234ac309418637488b97e0a62d8377b2ecf)
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"
8 
9 #include <memory>
10 
11 using namespace clang;
12 using namespace ento;
13 using namespace ast_matchers;
14 
15 testing::AssertionResult extractFunctionDecl(StringRef Code,
16                                              const FunctionDecl *&Result) {
17   auto ASTUnit = tooling::buildASTFromCode(Code);
18   if (!ASTUnit)
19     return testing::AssertionFailure() << "AST construction failed";
20 
21   ASTContext &Context = ASTUnit->getASTContext();
22   if (Context.getDiagnostics().hasErrorOccurred())
23     return testing::AssertionFailure() << "Compilation error";
24 
25   auto Matches = ast_matchers::match(functionDecl().bind("fn"), Context);
26   if (Matches.empty())
27     return testing::AssertionFailure() << "No function declaration found";
28 
29   if (Matches.size() > 1)
30     return testing::AssertionFailure()
31            << "Multiple function declarations found";
32 
33   Result = Matches[0].getNodeAs<FunctionDecl>("fn");
34   return testing::AssertionSuccess();
35 }
36 
37 TEST(IsCLibraryFunctionTest, AcceptsGlobal) {
38   const FunctionDecl *Result;
39   ASSERT_TRUE(extractFunctionDecl(R"cpp(void fun();)cpp", Result));
40   EXPECT_TRUE(CheckerContext::isCLibraryFunction(Result));
41 }
42 
43 TEST(IsCLibraryFunctionTest, AcceptsExternCGlobal) {
44   const FunctionDecl *Result;
45   ASSERT_TRUE(
46       extractFunctionDecl(R"cpp(extern "C" { void fun(); })cpp", Result));
47   EXPECT_TRUE(CheckerContext::isCLibraryFunction(Result));
48 }
49 
50 TEST(IsCLibraryFunctionTest, RejectsNoInlineNoExternalLinkage) {
51   // Functions that are neither inlined nor externally visible cannot be C library functions.
52   const FunctionDecl *Result;
53   ASSERT_TRUE(extractFunctionDecl(R"cpp(static void fun();)cpp", Result));
54   EXPECT_FALSE(CheckerContext::isCLibraryFunction(Result));
55 }
56 
57 TEST(IsCLibraryFunctionTest, RejectsAnonymousNamespace) {
58   const FunctionDecl *Result;
59   ASSERT_TRUE(
60       extractFunctionDecl(R"cpp(namespace { void fun(); })cpp", Result));
61   EXPECT_FALSE(CheckerContext::isCLibraryFunction(Result));
62 }
63 
64 TEST(IsCLibraryFunctionTest, AcceptsStdNamespace) {
65   const FunctionDecl *Result;
66   ASSERT_TRUE(
67       extractFunctionDecl(R"cpp(namespace std { void fun(); })cpp", Result));
68   EXPECT_TRUE(CheckerContext::isCLibraryFunction(Result));
69 }
70 
71 TEST(IsCLibraryFunctionTest, RejectsOtherNamespaces) {
72   const FunctionDecl *Result;
73   ASSERT_TRUE(
74       extractFunctionDecl(R"cpp(namespace stdx { void fun(); })cpp", Result));
75   EXPECT_FALSE(CheckerContext::isCLibraryFunction(Result));
76 }
77 
78 TEST(IsCLibraryFunctionTest, RejectsClassStatic) {
79   const FunctionDecl *Result;
80   ASSERT_TRUE(
81       extractFunctionDecl(R"cpp(class A { static void fun(); };)cpp", Result));
82   EXPECT_FALSE(CheckerContext::isCLibraryFunction(Result));
83 }
84 
85 TEST(IsCLibraryFunctionTest, RejectsClassMember) {
86   const FunctionDecl *Result;
87   ASSERT_TRUE(extractFunctionDecl(R"cpp(class A { void fun(); };)cpp", Result));
88   EXPECT_FALSE(CheckerContext::isCLibraryFunction(Result));
89 }
90