llvm/clang/unittests/StaticAnalyzer/SValTest.cpp

//===- unittests/StaticAnalyzer/SvalTest.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 "CheckerRegistration.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
#include "clang/Testing/TestClangConfig.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"

namespace clang {

// getType() tests include whole bunch of type comparisons,
// so when something is wrong, it's good to have gtest telling us
// what are those types.
LLVM_ATTRIBUTE_UNUSED std::ostream &operator<<(std::ostream &OS,
                                               const QualType &T) {}

LLVM_ATTRIBUTE_UNUSED std::ostream &operator<<(std::ostream &OS,
                                               const CanQualType &T) {}

namespace ento {
namespace {

//===----------------------------------------------------------------------===//
//                       Testing framework implementation
//===----------------------------------------------------------------------===//

/// A simple map from variable names to symbolic values used to init them.
SVals;

/// SValCollector is the barebone of all tests.
///
/// It is implemented as a checker and reacts to binds, so we find
/// symbolic values of interest, and to end analysis, where we actually
/// can test whatever we gathered.
class SValCollector : public Checker<check::Bind, check::EndAnalysis> {};

static void expectSameSignAndBitWidth(QualType ExpectedTy, QualType ActualTy,
                                      const ASTContext &Context) {}

// Fixture class for parameterized SValTest
class SValTest : public testing::TestWithParam<TestClangConfig> {};

// SVAL_TEST is a combined way of providing a short code snippet and
// to test some programmatic predicates on symbolic values produced by the
// engine for the actual code.
//
// Each test has a NAME.  One can think of it as a name for normal gtests.
//
// Each test should provide a CODE snippet.  Code snippets might contain any
// valid C/C++, but have ONLY ONE defined function.  There are no requirements
// about function's name or parameters.  It can even be a class method.  The
// body of the function must contain a set of variable declarations.  Each
// variable declaration gets bound to a symbolic value, so for the following
// example:
//
//     int x = <expr>;
//
// `x` will be bound to whatever symbolic value the engine produced for <expr>.
// LIVENESS and REASSIGNMENTS don't affect this binding.
//
// During the test the actual values can be accessed via `getByName` function,
// and, for the `x`-bound value, one must use "x" as its name.
//
// Example:
// SVAL_TEST(SimpleSValTest, R"(
// void foo() {
//   int x = 42;
// })") {
//   SVal X = getByName("x");
//   EXPECT_TRUE(X.isConstant(42));
// }
#define SVAL_TEST(NAME, CODE)

//===----------------------------------------------------------------------===//
//                                 Actual tests
//===----------------------------------------------------------------------===//

SVAL_TEST(GetConstType, R"(
void foo() {
  int x = 42;
  int *y = nullptr;
  bool z = true;
})") {}

SVAL_TEST(GetLocAsIntType, R"(
void foo(int *x) {
  long int a = (long long int)x;
  unsigned b = (long long unsigned)&a;
  int c = (long long int)nullptr;
})") {}

SVAL_TEST(GetSymExprType, R"(
void foo(int a, int b) {
  int x = a;
  int y = a + b;
  long z = a;
})") {}

SVAL_TEST(GetPointerType, R"(
int *bar();
int &foobar();
struct Z {
  int a;
  int *b;
};
void foo(int x, int *y, Z z) {
  int &a = x;
  int &b = *y;
  int &c = *bar();
  int &d = foobar();
  int &e = z.a;
  int &f = *z.b;
})") {}

SVAL_TEST(GetCompoundType, R"(
struct TestStruct {
  int a, b;
};
union TestUnion {
  int a;
  float b;
  TestStruct c;
};
void foo(int x) {
  int a[] = {1, x, 2};
  TestStruct b = {x, 42};
  TestUnion c = {42};
  TestUnion d = {.c=b};
}
)") {}

SVAL_TEST(GetStringType, R"(
void foo() {
  const char *a = "Hello, world!";
}
)") {}

SVAL_TEST(GetThisType, R"(
class TestClass {
  void foo();
};
void TestClass::foo() {
  const auto *a = this;
}
)") {}

SVAL_TEST(GetFunctionPtrType, R"(
void bar();
void foo() {
  auto *a = &bar;
}
)") {}

SVAL_TEST(GetLabelType, R"(
void foo() {
  entry:
  void *a = &&entry;
  char *b = (char *)&&entry;
}
)") {}

std::vector<TestClangConfig> allTestClangConfigs() {}

INSTANTIATE_TEST_SUITE_P();

} // namespace
} // namespace ento
} // namespace clang