1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "CheckerRegistration.h" |
10 | #include "clang/StaticAnalyzer/Core/Checker.h" |
11 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" |
12 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
13 | #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" |
14 | #include "gtest/gtest.h" |
15 | |
16 | using namespace clang; |
17 | using namespace ento; |
18 | |
19 | namespace { |
20 | class EvalCallBase : public Checker<eval::Call> { |
21 | const CallDescription Foo = {{"foo" }, 0}; |
22 | |
23 | public: |
24 | bool evalCall(const CallEvent &Call, CheckerContext &C) const { |
25 | return Foo.matches(Call); |
26 | } |
27 | }; |
28 | |
29 | class EvalCallFoo1 : public EvalCallBase {}; |
30 | class EvalCallFoo2 : public EvalCallBase {}; |
31 | void addEvalFooCheckers(AnalysisASTConsumer &AnalysisConsumer, |
32 | AnalyzerOptions &AnOpts) { |
33 | AnOpts.CheckersAndPackages = {{"test.EvalFoo1" , true}, |
34 | {"test.EvalFoo2" , true}}; |
35 | AnalysisConsumer.AddCheckerRegistrationFn(Fn: [](CheckerRegistry &Registry) { |
36 | Registry.addChecker<EvalCallFoo1>(FullName: "test.EvalFoo1" , Desc: "EmptyDescription" , |
37 | DocsUri: "EmptyDocsUri" ); |
38 | Registry.addChecker<EvalCallFoo2>(FullName: "test.EvalFoo2" , Desc: "EmptyDescription" , |
39 | DocsUri: "EmptyDocsUri" ); |
40 | }); |
41 | } |
42 | } // namespace |
43 | |
44 | TEST(EvalCall, DetectConflictingEvalCalls) { |
45 | #ifdef NDEBUG |
46 | GTEST_SKIP() << "This test is only available for debug builds." ; |
47 | #endif |
48 | const std::string Code = R"code( |
49 | void foo(); |
50 | void top() { |
51 | foo(); // crash |
52 | } |
53 | )code" ; |
54 | constexpr auto Regex = |
55 | "The 'foo\\(\\)' call has been already evaluated by the test\\.EvalFoo1 " |
56 | "checker, while the test\\.EvalFoo2 checker also tried to evaluate the " |
57 | "same call\\. At most one checker supposed to evaluate a call\\." ; |
58 | ASSERT_DEATH(runCheckerOnCode<addEvalFooCheckers>(Code), Regex); |
59 | } |
60 | |