blob: dc47af2ef282d77bfec72f10eaaa17f2e3c5b8d5 [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
#ifndef CRUBIT_NULLABILITY_VERIFICATION_POINTER_NULLABILITY_H_
#define CRUBIT_NULLABILITY_VERIFICATION_POINTER_NULLABILITY_H_
#include <utility>
#include "nullability_verification/pointer_nullability_lattice.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDumper.h"
#include "clang/AST/Expr.h"
#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "clang/Basic/Specifiers.h"
namespace clang {
namespace tidy {
namespace nullability {
using dataflow::TransferState;
/// Returns the `NullabilityKind` corresponding to the nullability annotation on
/// `Type` if present. Otherwise, returns `NullabilityKind::Unspecified`.
NullabilityKind getNullabilityKind(QualType Type, ASTContext& Ctx);
/// Returns the `PointerValue` allocated to `PointerExpr` if available.
/// Otherwise, returns nullptr.
dataflow::PointerValue* getPointerValueFromExpr(
const Expr* PointerExpr, const dataflow::Environment& Env);
/// Returns the properties representing the nullness information of a pointer.
///
/// The first boolean indicates if the pointer's nullability is known.
/// The second boolean indicates if the pointer's value is null.
std::pair<dataflow::AtomicBoolValue&, dataflow::AtomicBoolValue&>
getPointerNullState(const dataflow::PointerValue& PointerVal,
const dataflow::Environment& Env);
/// Sets the nullness properties on `PointerVal` if not already initialised.
///
/// The boolean properties may be constrained by specifying `KnownConstraint`
/// and `NullConstraint`. Otherwise, the properties are set to freshly
/// created atomic booleans.
void initPointerNullState(dataflow::PointerValue& PointerVal,
dataflow::Environment& Env,
dataflow::BoolValue* KnownConstraint = nullptr,
dataflow::BoolValue* NullConstraint = nullptr);
/// Sets the nullness properties on `PointerVal` representing a nullptr if not
/// already initialised.
///
/// `Known` is constrained to true, `Null` is constrained to true.
inline void initNullPointer(dataflow::PointerValue& PointerVal,
dataflow::Environment& Env) {
initPointerNullState(PointerVal, Env,
/*KnownConstraint=*/&Env.getBoolLiteralValue(true),
/*NullConstraint=*/&Env.getBoolLiteralValue(true));
}
/// Sets the nullness properties on `PointerVal` representing a pointer that is
/// not null if not already initialised.
///
/// `Known` is constrained to true, `Null` is constrained to false.
inline void initNotNullPointer(dataflow::PointerValue& PointerVal,
dataflow::Environment& Env) {
initPointerNullState(PointerVal, Env,
/*KnownConstraint=*/&Env.getBoolLiteralValue(true),
/*NullConstraint=*/&Env.getBoolLiteralValue(false));
}
/// Sets the nullness properties on `PointerVal` representing a pointer that is
/// nullable if not already initialised.
///
/// `Known` is constrained to true, `Null` is unconstrained.
inline void initNullablePointer(dataflow::PointerValue& PointerVal,
dataflow::Environment& Env) {
initPointerNullState(PointerVal, Env,
/*KnownConstraint=*/&Env.getBoolLiteralValue(true));
}
/// Sets the nullness properties on `PointerVal` representing a pointer with
/// unknown nullability if not already initialised.
///
/// `Known` is constrained to false, `Null` is unconstrained.
inline void initUnknownPointer(dataflow::PointerValue& PointerVal,
dataflow::Environment& Env) {
initPointerNullState(PointerVal, Env,
/*KnownConstraint=*/&Env.getBoolLiteralValue(false));
}
/// Returns true if there is evidence that `PointerVal` may hold a nullptr.
bool isNullable(const dataflow::PointerValue& PointerVal,
const dataflow::Environment& Env);
/// Returns a human-readable debug representation of a nullability vector.
std::string nullabilityToString(ArrayRef<NullabilityKind> Nullability);
/// A function that may provide enhanced nullability information for a
/// substituted template parameter (which has no sugar of its own).
using GetTypeParamNullability = std::optional<std::vector<NullabilityKind>>(
const SubstTemplateTypeParmType* ST);
/// Traverse over a type to get its nullability. For example, if T is the type
/// Struct3Arg<int * _Nonnull, int, pair<int * _Nullable, int *>> * _Nonnull,
/// the resulting nullability annotations will be {_Nonnull, _Nonnull,
/// _Nullable, _Unknown}. Note that non-pointer elements (e.g., the second
/// argument of Struct3Arg) do not get a nullability annotation.
std::vector<NullabilityKind> getNullabilityAnnotationsFromType(
QualType T,
llvm::function_ref<GetTypeParamNullability> SubstituteTypeParam = nullptr);
/// Computes the number of pointer slots within a type.
/// Each of these could conceptually be nullable, so this is the length of
/// the nullability vector computed by getNullabilityAnnotationsFromType().
unsigned countPointersInType(QualType T);
unsigned countPointersInType(const Expr* E);
unsigned countPointersInType(TemplateArgument TA);
QualType exprType(const Expr* E);
std::vector<NullabilityKind> unspecifiedNullability(const Expr* E);
// Work around the lack of Expr.dump() etc with an ostream but no ASTContext.
template <typename T>
void dump(const T& Node, llvm::raw_ostream& OS) {
clang::ASTDumper(OS, /*ShowColors=*/false).Visit(Node);
}
// Returns the computed nullability for a subexpr of the current expression.
// This is always available as we compute bottom-up.
ArrayRef<NullabilityKind> getNullabilityForChild(
const Expr* E, TransferState<PointerNullabilityLattice>& State);
} // namespace nullability
} // namespace tidy
} // namespace clang
#endif // CRUBIT_NULLABILITY_VERIFICATION_POINTER_NULLABILITY_H_