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