1
+ use std:: collections:: HashSet ;
2
+
1
3
use crate :: {
2
4
compiler:: {
3
5
db:: { build_scarb_root_database, ScarbDatabase } ,
4
6
CompilationUnit , CompilationUnitAttributes ,
5
7
} ,
6
- core:: TargetKind ,
8
+ core:: { PackageId , TargetKind } ,
7
9
ops,
8
10
} ;
9
11
use anyhow:: Result ;
@@ -19,13 +21,14 @@ use cairo_lint_core::{
19
21
diagnostics:: format_diagnostic,
20
22
plugin:: { cairo_lint_plugin_suite, diagnostic_kind_from_message, CairoLintKind } ,
21
23
} ;
24
+ use itertools:: Itertools ;
22
25
use scarb_ui:: components:: Status ;
23
26
use serde:: Deserialize ;
24
27
use smol_str:: SmolStr ;
25
28
26
29
use crate :: core:: { Package , Workspace } ;
27
30
28
- use super :: { CompilationUnitsOpts , FeaturesOpts , FeaturesSelector } ;
31
+ use super :: { compile_unit , CompilationUnitsOpts , FeaturesOpts , FeaturesSelector } ;
29
32
30
33
pub struct LintOptions {
31
34
pub packages : Vec < Package > ,
@@ -53,6 +56,19 @@ pub fn lint(opts: LintOptions, ws: &Workspace<'_>) -> Result<()> {
53
56
} ,
54
57
) ?;
55
58
59
+ // Select proc macro units that need to be compiled for Cairo compilation units.
60
+ let required_plugins = compilation_units
61
+ . iter ( )
62
+ . flat_map ( |unit| match unit {
63
+ CompilationUnit :: Cairo ( unit) => unit
64
+ . cairo_plugins
65
+ . iter ( )
66
+ . map ( |p| p. package . id )
67
+ . collect_vec ( ) ,
68
+ _ => Vec :: new ( ) ,
69
+ } )
70
+ . collect :: < HashSet < PackageId > > ( ) ;
71
+
56
72
for package in opts. packages {
57
73
let package_compilation_units = if opts. test {
58
74
compilation_units
@@ -78,13 +94,24 @@ pub fn lint(opts: LintOptions, ws: &Workspace<'_>) -> Result<()> {
78
94
. unwrap( ) ]
79
95
} ;
80
96
81
- for compilation_unit in package_compilation_units {
97
+ // We guarantee that proc-macro units are always processed first,
98
+ // so that all required plugins are compiled before we start checking Cairo units.
99
+ let units = package_compilation_units. into_iter ( ) . sorted_by_key ( |unit| {
100
+ if matches ! ( unit, CompilationUnit :: ProcMacro ( _) ) {
101
+ 0
102
+ } else {
103
+ 1
104
+ }
105
+ } ) ;
106
+
107
+ for compilation_unit in units {
82
108
match compilation_unit {
83
- // We skip proc macros as we don't want to check anything related to rust code.
84
- CompilationUnit :: ProcMacro ( _) => ws
85
- . config ( )
86
- . ui ( )
87
- . print ( Status :: new ( "Skipping proc macro" , & compilation_unit. name ( ) ) ) ,
109
+ CompilationUnit :: ProcMacro ( _) => {
110
+ // We process all proc-macro units that are required by Cairo compilation units.
111
+ if required_plugins. contains ( & compilation_unit. main_package_id ( ) ) {
112
+ compile_unit ( compilation_unit. clone ( ) , ws) ?;
113
+ }
114
+ }
88
115
CompilationUnit :: Cairo ( compilation_unit) => {
89
116
ws. config ( )
90
117
. ui ( )
0 commit comments