summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:31:31 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:31:31 +0000
commite5dd70708596ae51455a0ffa086a00c5b29f8583 (patch)
tree5d676f27b570bacf71e786c3b5cff3e6f6679b59 /gnu/llvm/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.tar.xz
wireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp')
-rw-r--r--gnu/llvm/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp162
1 files changed, 162 insertions, 0 deletions
diff --git a/gnu/llvm/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp b/gnu/llvm/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
new file mode 100644
index 00000000000..2ebaa46b0f7
--- /dev/null
+++ b/gnu/llvm/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
@@ -0,0 +1,162 @@
+//===- unittests/StaticAnalyzer/CallDescriptionTest.cpp -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Reusables.h"
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ento {
+namespace {
+
+// A wrapper around CallDescriptionMap<bool> that allows verifying that
+// all functions have been found. This is needed because CallDescriptionMap
+// isn't supposed to support iteration.
+class ResultMap {
+ size_t Found, Total;
+ CallDescriptionMap<bool> Impl;
+
+public:
+ ResultMap(std::initializer_list<std::pair<CallDescription, bool>> Data)
+ : Found(0),
+ Total(std::count_if(Data.begin(), Data.end(),
+ [](const std::pair<CallDescription, bool> &Pair) {
+ return Pair.second == true;
+ })),
+ Impl(std::move(Data)) {}
+
+ const bool *lookup(const CallEvent &Call) {
+ const bool *Result = Impl.lookup(Call);
+ // If it's a function we expected to find, remember that we've found it.
+ if (Result && *Result)
+ ++Found;
+ return Result;
+ }
+
+ // Fail the test if we haven't found all the true-calls we were looking for.
+ ~ResultMap() { EXPECT_EQ(Found, Total); }
+};
+
+// Scan the code body for call expressions and see if we find all calls that
+// we were supposed to find ("true" in the provided ResultMap) and that we
+// don't find the ones that we weren't supposed to find
+// ("false" in the ResultMap).
+class CallDescriptionConsumer : public ExprEngineConsumer {
+ ResultMap &RM;
+ void performTest(const Decl *D) {
+ using namespace ast_matchers;
+
+ if (!D->hasBody())
+ return;
+
+ const CallExpr *CE = findNode<CallExpr>(D, callExpr());
+ const StackFrameContext *SFC =
+ Eng.getAnalysisDeclContextManager().getStackFrame(D);
+ ProgramStateRef State = Eng.getInitialState(SFC);
+ CallEventRef<> Call =
+ Eng.getStateManager().getCallEventManager().getCall(CE, State, SFC);
+
+ const bool *LookupResult = RM.lookup(*Call);
+ // Check that we've found the function in the map
+ // with the correct description.
+ EXPECT_TRUE(LookupResult && *LookupResult);
+
+ // ResultMap is responsible for making sure that we've found *all* calls.
+ }
+
+public:
+ CallDescriptionConsumer(CompilerInstance &C,
+ ResultMap &RM)
+ : ExprEngineConsumer(C), RM(RM) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ for (const auto *D : DG)
+ performTest(D);
+ return true;
+ }
+};
+
+class CallDescriptionAction : public ASTFrontendAction {
+ ResultMap RM;
+
+public:
+ CallDescriptionAction(
+ std::initializer_list<std::pair<CallDescription, bool>> Data)
+ : RM(Data) {}
+
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ return std::make_unique<CallDescriptionConsumer>(Compiler, RM);
+ }
+};
+
+TEST(CallEvent, CallDescription) {
+ // Test simple name matching.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ std::unique_ptr<CallDescriptionAction>(new CallDescriptionAction({
+ {{"bar"}, false}, // false: there's no call to 'bar' in this code.
+ {{"foo"}, true}, // true: there's a call to 'foo' in this code.
+ })), "void foo(); void bar() { foo(); }"));
+
+ // Test arguments check.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ std::unique_ptr<CallDescriptionAction>(new CallDescriptionAction({
+ {{"foo", 1}, true},
+ {{"foo", 2}, false},
+ })), "void foo(int); void foo(int, int); void bar() { foo(1); }"));
+
+ // Test lack of arguments check.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ std::unique_ptr<CallDescriptionAction>(new CallDescriptionAction({
+ {{"foo", None}, true},
+ {{"foo", 2}, false},
+ })), "void foo(int); void foo(int, int); void bar() { foo(1); }"));
+
+ // Test qualified names.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ std::unique_ptr<CallDescriptionAction>(new CallDescriptionAction({
+ {{{"std", "basic_string", "c_str"}}, true},
+ })),
+ "namespace std { inline namespace __1 {"
+ " template<typename T> class basic_string {"
+ " public:"
+ " T *c_str();"
+ " };"
+ "}}"
+ "void foo() {"
+ " using namespace std;"
+ " basic_string<char> s;"
+ " s.c_str();"
+ "}"));
+
+ // A negative test for qualified names.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ std::unique_ptr<CallDescriptionAction>(new CallDescriptionAction({
+ {{{"foo", "bar"}}, false},
+ {{{"bar", "foo"}}, false},
+ {{"foo"}, true},
+ })), "void foo(); struct bar { void foo(); }; void test() { foo(); }"));
+
+ // Test CDF_MaybeBuiltin - a flag that allows matching weird builtins.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ std::unique_ptr<CallDescriptionAction>(new CallDescriptionAction({
+ {{"memset", 3}, false},
+ {{CDF_MaybeBuiltin, "memset", 3}, true}
+ })),
+ "void foo() {"
+ " int x;"
+ " __builtin___memset_chk(&x, 0, sizeof(x),"
+ " __builtin_object_size(&x, 0));"
+ "}"));
+}
+
+} // namespace
+} // namespace ento
+} // namespace clang