forge_lint/sol/low/
deprecated_oz_function.rs1use super::DeprecatedOzFunction;
2use crate::{
3 linter::{LateLintPass, LintContext},
4 sol::{
5 Severity, SolLint,
6 analysis::{OPENZEPPELIN_ROOTS, source_in_package},
7 },
8};
9use solar::sema::{
10 Gcx,
11 hir::{Expr, ExprKind, FunctionId},
12};
13
14declare_forge_lint!(
15 DEPRECATED_OZ_FUNCTION,
16 Severity::Low,
17 "deprecated-oz-function",
18 "this OpenZeppelin function is deprecated"
19);
20
21impl<'gcx> LateLintPass<'gcx> for DeprecatedOzFunction {
22 fn check_expr(&mut self, ctx: &LintContext, gcx: Gcx<'gcx>, expr: &'gcx Expr<'gcx>) {
23 if matches!(expr.kind, ExprKind::Ident(..) | ExprKind::Member(..))
27 && let Some(function_id) = gcx.resolved_function(expr)
28 && is_deprecated_oz(gcx, function_id)
29 {
30 ctx.emit(&DEPRECATED_OZ_FUNCTION, expr.span);
31 }
32 }
33}
34
35fn is_deprecated_oz(gcx: Gcx<'_>, function_id: FunctionId) -> bool {
41 let function = gcx.hir.function(function_id);
42 let (Some(name), Some(contract_id)) = (function.name, function.contract) else { return false };
43 if !source_in_package(&gcx.hir, function.source, OPENZEPPELIN_ROOTS) {
44 return false;
45 }
46 let contract = gcx.hir.contract(contract_id);
47 matches!(
48 (name.as_str(), contract.kind.is_library(), contract.name.as_str()),
49 ("safeApprove", true, "SafeERC20" | "SafeERC20Upgradeable")
50 | ("_setupRole", false, "AccessControl" | "AccessControlUpgradeable")
51 )
52}