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