Clang Project

clang_source_code/unittests/Analysis/CFGTest.cpp
1//===- unittests/Analysis/CFGTest.cpp - CFG tests -------------------------===//
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 "clang/ASTMatchers/ASTMatchFinder.h"
10#include "clang/Analysis/CFG.h"
11#include "clang/Tooling/Tooling.h"
12#include "gtest/gtest.h"
13#include <string>
14#include <vector>
15
16namespace clang {
17namespace analysis {
18namespace {
19
20enum BuildResult {
21  ToolFailed,
22  ToolRan,
23  SawFunctionBody,
24  BuiltCFG,
25};
26
27class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
28public:
29  BuildResult TheBuildResult = ToolRan;
30
31  void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
32    const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
33    Stmt *Body = Func->getBody();
34    if (!Body)
35      return;
36    TheBuildResult = SawFunctionBody;
37    CFG::BuildOptions Options;
38    Options.AddImplicitDtors = true;
39    if (CFG::buildCFG(nullptrBodyResult.ContextOptions))
40        TheBuildResult = BuiltCFG;
41  }
42};
43
44BuildResult BuildCFG(const char *Code) {
45  CFGCallback Callback;
46
47  ast_matchers::MatchFinder Finder;
48  Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
49  std::unique_ptr<tooling::FrontendActionFactory> Factory(
50      tooling::newFrontendActionFactory(&Finder));
51  std::vector<std::string> Args = {"-std=c++11""-fno-delayed-template-parsing"};
52  if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args))
53    return ToolFailed;
54  return Callback.TheBuildResult;
55}
56
57// Constructing a CFG for a range-based for over a dependent type fails (but
58// should not crash).
59TEST(CFG, RangeBasedForOverDependentType) {
60  const char *Code = "class Foo;\n"
61                     "template <typename T>\n"
62                     "void f(const T &Range) {\n"
63                     "  for (const Foo *TheFoo : Range) {\n"
64                     "  }\n"
65                     "}\n";
66  EXPECT_EQ(SawFunctionBodyBuildCFG(Code));
67}
68
69// Constructing a CFG containing a delete expression on a dependent type should
70// not crash.
71TEST(CFG, DeleteExpressionOnDependentType) {
72  const char *Code = "template<class T>\n"
73                     "void f(T t) {\n"
74                     "  delete t;\n"
75                     "}\n";
76  EXPECT_EQ(BuiltCFGBuildCFG(Code));
77}
78
79// Constructing a CFG on a function template with a variable of incomplete type
80// should not crash.
81TEST(CFG, VariableOfIncompleteType) {
82  const char *Code = "template<class T> void f() {\n"
83                     "  class Undefined;\n"
84                     "  Undefined u;\n"
85                     "}\n";
86  EXPECT_EQ(BuiltCFGBuildCFG(Code));
87}
88
89// namespace
90// namespace analysis
91// namespace clang
92