blob: b19e9fcc65672af62cf46fee779d86b51f679f92 [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
#include "nullability/inference/resolve_constraints.h"
#include "nullability/inference/inference.proto.h"
#include "nullability/pointer_nullability.h"
#include "clang/Analysis/FlowSensitive/Solver.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
#include "llvm/ADT/DenseSet.h"
namespace clang::tidy::nullability {
namespace {
bool isSatisfiable(
const llvm::DenseSet<clang::dataflow::BoolValue *> &ConstraintSet) {
clang::dataflow::WatchedLiteralsSolver Solver;
std::vector<const clang::dataflow::Formula *> Vec;
for (const auto *Constraint : ConstraintSet)
Vec.push_back(&Constraint->formula());
return Solver.solve(Vec).getStatus() ==
clang::dataflow::Solver::Result::Status::Satisfiable;
}
bool isUnsatisfiable(
const llvm::DenseSet<clang::dataflow::BoolValue *> &ConstraintSet) {
clang::dataflow::WatchedLiteralsSolver Solver;
std::vector<const clang::dataflow::Formula *> Vec;
for (const auto *Constraint : ConstraintSet)
Vec.push_back(&Constraint->formula());
return Solver.solve(Vec).getStatus() ==
clang::dataflow::Solver::Result::Status::Unsatisfiable;
}
} // namespace
NullabilityConstraint resolveConstraints(
const llvm::DenseSet<clang::dataflow::BoolValue *> &SafetyConstraints,
const clang::dataflow::PointerValue &Pointer) {
// If the safety constraints are satisfiable, then we can potentially
// add annotations that are necessary for them to be satisfied. If they
// are not all satisfiable together, we need to prune conditions in a
// targeted way to do the best we can with the code we have.
// TODO(b/268440048) Handle unsatisfiable safety constraints
if (!isSatisfiable(SafetyConstraints)) return {};
clang::dataflow::AtomicBoolValue &IsNull =
getPointerNullState(Pointer).second;
auto SafetyConstraintsAndIsNull = SafetyConstraints;
SafetyConstraintsAndIsNull.insert(&IsNull);
// If the safety constraints are satisfiable, but the conjunction of
// the safety constraints and this pointer being null is not
// satisfiable, then the safety constraints imply that the pointer
// must be Nonnull.
//
// Example code behaviors that could create safety conditions implying
// Nonnull:
// - For return values, a Nonnull variable assigned to the return
// value of the function under analysis.
// - For a parameter, an unconditional dereference.
// TODO(b/268440048) implement safety constraints that imply Nonnull.
// The examples above are not implemented.
NullabilityConstraint NullabilityConstraint;
NullabilityConstraint.set_must_be_nonnull(
isUnsatisfiable(SafetyConstraintsAndIsNull));
return NullabilityConstraint;
}
} // namespace clang::tidy::nullability