forge_lint/sol/info/
incorrect_using_for.rs1use super::IncorrectUsingFor;
2use crate::{
3 linter::{LateLintPass, LintContext},
4 sol::{Severity, SolLint},
5};
6use solar::{
7 ast::DataLocation,
8 sema::{
9 Gcx,
10 hir::{self, UsingDirective, UsingEntryKind},
11 },
12};
13
14declare_forge_lint!(
15 INCORRECT_USING_FOR,
16 Severity::Info,
17 "incorrect-using-for",
18 "`using ... for` names a library with no function applicable to the type, so the directive attaches nothing"
19);
20
21impl<'gcx> LateLintPass<'gcx> for IncorrectUsingFor {
22 fn check_nested_source(&mut self, ctx: &LintContext, gcx: Gcx<'gcx>, id: hir::SourceId) {
23 for directive in gcx.hir.source(id).usings {
24 check_directive(ctx, gcx, directive);
25 }
26 }
27
28 fn check_nested_contract(&mut self, ctx: &LintContext, gcx: Gcx<'gcx>, id: hir::ContractId) {
29 for directive in gcx.hir.contract(id).usings {
30 check_directive(ctx, gcx, directive);
31 }
32 }
33}
34
35fn check_directive<'gcx>(ctx: &LintContext, gcx: Gcx<'gcx>, directive: &'gcx UsingDirective<'gcx>) {
39 let Some(hir_ty) = &directive.ty else { return };
41 let base_ty = gcx.type_of_hir_ty(hir_ty);
46 let tys = [DataLocation::Storage, DataLocation::Memory, DataLocation::Calldata]
47 .map(|loc| base_ty.with_loc_if_ref(gcx, loc));
48 for entry in directive.entries {
49 let UsingEntryKind::Library(library_id) = entry.kind else { continue };
52 let attaches = tys
56 .iter()
57 .flat_map(|ty| gcx.members_of(*ty, directive.source, directive.contract))
58 .filter(|member| member.attached)
59 .filter_map(|member| member.ty.function_id())
60 .any(|function_id| {
61 let function = gcx.hir.function(function_id);
62 function.contract == Some(library_id)
63 && function.visibility != hir::Visibility::Private
64 });
65 if !attaches {
66 ctx.emit(&INCORRECT_USING_FOR, entry.span);
67 }
68 }
69}