blob: 82167f99ffe5928dc286d2494822623fa3538432 [file]
// 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_verification/pointer_nullability_diagnosis.h"
#include "nullability_verification/pointer_nullability.h"
#include "nullability_verification/pointer_nullability_matchers.h"
#include "clang/AST/Expr.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
namespace clang {
namespace tidy {
namespace nullability {
using ast_matchers::MatchFinder;
using dataflow::Environment;
namespace {
llvm::Optional<const Stmt*> diagnosePointerAccess(const Stmt* PointerAccessExpr,
const Expr* PointerExpr,
const Environment& Env) {
auto* PointerVal = getPointerValueFromExpr(PointerExpr, Env);
if (!PointerVal) return PointerAccessExpr;
auto [PointerKnown, PointerNotNull] = getPointerNullState(*PointerVal, Env);
auto& PointerNotKnownNull =
Env.makeNot(Env.makeAnd(PointerKnown, Env.makeNot(PointerNotNull)));
if (!Env.flowConditionImplies(PointerNotKnownNull)) {
return PointerAccessExpr;
}
return llvm::None;
}
llvm::Optional<const Stmt*> diagnoseDereference(const UnaryOperator* UnaryOp,
const MatchFinder::MatchResult&,
const Environment& Env) {
return diagnosePointerAccess(UnaryOp, UnaryOp->getSubExpr(), Env);
}
llvm::Optional<const Stmt*> diagnoseArrow(
const MemberExpr* MemberExpr, const MatchFinder::MatchResult& Result,
const Environment& Env) {
return diagnosePointerAccess(MemberExpr, MemberExpr->getBase(), Env);
}
auto buildDiagnoser() {
return dataflow::MatchSwitchBuilder<const Environment,
llvm::Optional<const Stmt*>>()
// (*)
.CaseOf<UnaryOperator>(isPointerDereference(), diagnoseDereference)
// (->)
.CaseOf<MemberExpr>(isPointerArrow(), diagnoseArrow)
.Build();
}
} // namespace
PointerNullabilityDiagnoser::PointerNullabilityDiagnoser()
: Diagnoser(buildDiagnoser()) {}
} // namespace nullability
} // namespace tidy
} // namespace clang