blob: b0ee71768108f51a2b5ce6c55ba450871d14e7d5 [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// This header defines functions available in nullability_tests.
//
// A test is a C++ source file that contains code to be analyzed.
// Any functions marked with TEST are analysis targets.
// These can include calls to assertion functions like nullable() defined here.
// Such calls assert details of analysis results (nullability of expressions).
//
// The nullability_test tool parses the code, runs the analysis, checks the
// assertions, and reports results.
//
// Example:
// #include "nullability_test.h"
// TEST void controlFlow(Nullable<int*> x) {
// if (x) {
// nonnull(x);
// } else {
// nullable(x);
// }
// }
#ifndef CRUBIT_NULLABILITY_TEST_NULLABILITY_TEST_H_
#define CRUBIT_NULLABILITY_TEST_NULLABILITY_TEST_H_
#include "nullability_annotations.h" // IWYU pragma: export
namespace preamble_detail {
template <typename, typename>
struct require_same;
template <typename T>
struct require_same<T, T> {
using type = T;
};
} // namespace preamble_detail
// Attribute applied to tests to be analyzed.
// For now, only functions are supported (including constructors).
// If TEST is applied to an unsupported construct, the test will fail.
#define TEST [[clang::annotate("test")]]
////////////// Assertion functions interpreted by the test driver /////////////
// Non-flow-sensitive analysis assertions.
// (These check the nullability vector of an expression's type).
// Asserts the exact static type and nullability of an expression.
// e.g. type<Nonnull<int*>(&i);
//
// Types written inside type<...> do not respect nullability pragmas!
template <
typename Expected, typename Actual,
// Statically verify that the canonical types are the same.
typename = typename preamble_detail::require_same<Expected, Actual>::type>
void type(Actual) {}
// Assertions for the full (flow-sensitive) analysis results.
// (These check whether from_nullable and is_null are implied by the flow
// condition. In addition, we provide general-purpose assertions for booleans.)
// Asserts that its argument is considered nullable.
template <typename T>
void nullable(const T &) {}
// Asserts that its argument is considered non-null.
template <typename T>
void nonnull(const T &) {}
// Asserts that its argument is neither considered nullable nor non-null.
template <typename T>
void unknown(const T &) {}
// Asserts that the analysis can prove `b` must be true at this point.
inline void provable(bool b) {}
// Asserts that the analysis can show `b` may be true at this point.
inline void possible(bool b) {}
///////////////// Helpers to make writing tests more convenient ////////////////
// Marker annotations for pointer types whose nullability is symbolic.
// This means we track it as a variable: without assuming a specific value.
//
// Example:
// void target(symbolic::X<int *> p) {
// type<Nonnull<symbolic::X<int *> *>(&p);
// }
//
// When this appears:
// - in a declaration (e.g. a function param): the decl's nullability is bound
// to a variable
// - in a type<...>() assertion: asserts that the nullability of the
// expression matches that variable.
//
// (For now we only provide two symbolic variables, this can be extended).
namespace symbolic {
template <typename T>
using X [[clang::annotate("symbolic_nullability:X")]] = T;
template <typename T>
using Y [[clang::annotate("symbolic_nullability:Y")]] = T;
} // namespace symbolic
// Generic factory for generating values of arbitrary types and nullability.
//
// `make<Nullable<int*>>()` is a value whose type in the AST is `int*` (no
// nullability sugar) and whose static nullability is [Nullable].
template <typename T>
static T make()
// suppresses 'undefined' error when instantiated with no-linkage type.
__attribute__((weakref("")));
// Tests tend to contain unused expressions like *x, so don't warn on them.
#pragma clang diagnostic ignored "-Wunused-value"
// Tests define functions that are not declared in any header.
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#endif // CRUBIT_NULLABILITY_TEST_NULLABILITY_TEST_H_