@@ -10,7 +10,10 @@ use crate::{
10
10
diag,
11
11
diagnostics:: { codes:: * , Diagnostic } ,
12
12
editions:: Flavor ,
13
- expansion:: ast:: { AttributeName_ , Fields , Friend , ModuleIdent , Value_ , Visibility } ,
13
+ expansion:: ast:: {
14
+ AttributeName_ , AttributeValue_ , Attribute_ , Attributes , Fields , Friend , ModuleAccess_ ,
15
+ ModuleIdent , ModuleIdent_ , Value_ , Visibility ,
16
+ } ,
14
17
naming:: ast:: { self as N , TParam , TParamID , Type , TypeName_ , Type_ } ,
15
18
parser:: ast:: { Ability_ , BinOp_ , ConstantName , Field , FunctionName , StructName , UnaryOp_ } ,
16
19
shared:: {
@@ -86,6 +89,10 @@ fn modules(
86
89
. expect ( "ICE compiler added duplicate friends to public(package) friend list" ) ;
87
90
}
88
91
92
+ for ( _, mident, mdef) in & typed_modules {
93
+ gen_unused_warnings ( context, mident, mdef) ;
94
+ }
95
+
89
96
typed_modules
90
97
}
91
98
@@ -95,8 +102,6 @@ fn module(
95
102
mdef : N :: ModuleDefinition ,
96
103
) -> ( T :: ModuleDefinition , BTreeSet < ( ModuleIdent , Loc ) > ) {
97
104
assert ! ( context. current_script_constants. is_none( ) ) ;
98
- assert ! ( context. called_fns. is_empty( ) ) ;
99
- assert ! ( context. new_friends. is_empty( ) ) ;
100
105
101
106
context. current_module = Some ( ident) ;
102
107
let N :: ModuleDefinition {
@@ -114,6 +119,7 @@ fn module(
114
119
structs
115
120
. iter_mut ( )
116
121
. for_each ( |( _, _, s) | struct_def ( context, s) ) ;
122
+ process_attributes ( context, & attributes) ;
117
123
let constants = nconstants. map ( |name, c| constant ( context, name, c) ) ;
118
124
let functions = nfunctions. map ( |name, f| function ( context, name, f, false ) ) ;
119
125
assert ! ( context. constraints. is_empty( ) ) ;
@@ -129,12 +135,8 @@ fn module(
129
135
constants,
130
136
functions,
131
137
} ;
132
- gen_unused_warnings ( context, & typed_module) ;
133
138
// get the list of new friends and reset the list.
134
139
let new_friends = std:: mem:: take ( & mut context. new_friends ) ;
135
- // reset called functions set so that it's ready to be be populated with values from
136
- // a single module only
137
- context. called_fns . clear ( ) ;
138
140
( typed_module, new_friends)
139
141
}
140
142
@@ -202,6 +204,7 @@ fn function(
202
204
assert ! ( context. constraints. is_empty( ) ) ;
203
205
context. reset_for_module_item ( ) ;
204
206
context. current_function = Some ( name) ;
207
+ process_attributes ( context, & attributes) ;
205
208
function_signature ( context, & signature) ;
206
209
if is_script {
207
210
let mk_msg = || {
@@ -301,6 +304,8 @@ fn constant(context: &mut Context, _name: ConstantName, nconstant: N::Constant)
301
304
} = nconstant;
302
305
context. env . add_warning_filter_scope ( warning_filter. clone ( ) ) ;
303
306
307
+ process_attributes ( context, & attributes) ;
308
+
304
309
// Don't need to add base type constraint, as it is checked in `check_valid_constant::signature`
305
310
let mut signature = core:: instantiate ( context, signature) ;
306
311
check_valid_constant:: signature (
@@ -1241,6 +1246,13 @@ fn exp_inner(context: &mut Context, sp!(eloc, ne_): N::Exp) -> T::Exp {
1241
1246
1242
1247
NE :: Constant ( m, c) => {
1243
1248
let ty = core:: make_constant_type ( context, eloc, & m, & c) ;
1249
+ if let Some ( mident) = m {
1250
+ context
1251
+ . used_module_members
1252
+ . entry ( mident. value )
1253
+ . or_insert_with ( BTreeSet :: new)
1254
+ . insert ( c. value ( ) ) ;
1255
+ }
1244
1256
( ty, TE :: Constant ( m, c) )
1245
1257
}
1246
1258
@@ -2102,9 +2114,11 @@ fn module_call(
2102
2114
parameter_types : params_ty_list,
2103
2115
acquires,
2104
2116
} ;
2105
- if context. is_current_module ( & m) {
2106
- context. called_fns . insert ( f. value ( ) ) ;
2107
- }
2117
+ context
2118
+ . used_module_members
2119
+ . entry ( m. value )
2120
+ . or_insert_with ( BTreeSet :: new)
2121
+ . insert ( f. value ( ) ) ;
2108
2122
( ret_ty, T :: UnannotatedExp_ :: ModuleCall ( Box :: new ( call) ) )
2109
2123
}
2110
2124
@@ -2318,12 +2332,38 @@ fn make_arg_types<S: std::fmt::Display, F: Fn() -> S>(
2318
2332
given
2319
2333
}
2320
2334
2335
+ //**************************************************************************************************
2336
+ // Utils
2337
+ //**************************************************************************************************
2338
+
2339
+ fn process_attributes ( context : & mut Context , all_attributes : & Attributes ) {
2340
+ for ( _, _, attr) in all_attributes {
2341
+ match & attr. value {
2342
+ Attribute_ :: Name ( _) => ( ) ,
2343
+ Attribute_ :: Parameterized ( _, attrs) => process_attributes ( context, attrs) ,
2344
+ Attribute_ :: Assigned ( _, val) => {
2345
+ let AttributeValue_ :: ModuleAccess ( mod_access) = & val. value else {
2346
+ continue ;
2347
+ } ;
2348
+ if let ModuleAccess_ :: ModuleAccess ( mident, name) = mod_access. value {
2349
+ // conservatively assume that each `ModuleAccess` refers to a constant name
2350
+ context
2351
+ . used_module_members
2352
+ . entry ( mident. value )
2353
+ . or_insert_with ( BTreeSet :: new)
2354
+ . insert ( name. value ) ;
2355
+ }
2356
+ }
2357
+ }
2358
+ }
2359
+ }
2360
+
2321
2361
//**************************************************************************************************
2322
2362
// Module-wide warnings
2323
2363
//**************************************************************************************************
2324
2364
2325
- /// Generates warnings for unused (private) functions.
2326
- fn gen_unused_warnings ( context : & mut Context , mdef : & T :: ModuleDefinition ) {
2365
+ /// Generates warnings for unused (private) functions and unused constants .
2366
+ fn gen_unused_warnings ( context : & mut Context , mident : & ModuleIdent_ , mdef : & T :: ModuleDefinition ) {
2327
2367
if !mdef. is_source_module {
2328
2368
// generate warnings only for modules compiled in this pass rather than for all modules
2329
2369
// including pre-compiled libraries for which we do not have source code available and
@@ -2336,6 +2376,22 @@ fn gen_unused_warnings(context: &mut Context, mdef: &T::ModuleDefinition) {
2336
2376
. env
2337
2377
. add_warning_filter_scope ( mdef. warning_filter . clone ( ) ) ;
2338
2378
2379
+ for ( loc, name, c) in & mdef. constants {
2380
+ context
2381
+ . env
2382
+ . add_warning_filter_scope ( c. warning_filter . clone ( ) ) ;
2383
+
2384
+ let members = context. used_module_members . get ( mident) ;
2385
+ if members. is_none ( ) || !members. unwrap ( ) . contains ( name) {
2386
+ let msg = format ! ( "The constant '{name}' is never used. Consider removing it." ) ;
2387
+ context
2388
+ . env
2389
+ . add_diag ( diag ! ( UnusedItem :: Constant , ( loc, msg) ) )
2390
+ }
2391
+
2392
+ context. env . pop_warning_filter_scope ( ) ;
2393
+ }
2394
+
2339
2395
for ( loc, name, fun) in & mdef. functions {
2340
2396
if fun. attributes . iter ( ) . any ( |( _, n, _) | {
2341
2397
n == & AttributeName_ :: Known ( KnownAttribute :: Testing ( TestingAttribute :: Test ) )
@@ -2350,9 +2406,11 @@ fn gen_unused_warnings(context: &mut Context, mdef: &T::ModuleDefinition) {
2350
2406
context
2351
2407
. env
2352
2408
. add_warning_filter_scope ( fun. warning_filter . clone ( ) ) ;
2353
- if !context. called_fns . contains ( name)
2354
- && fun. entry . is_none ( )
2409
+
2410
+ let members = context. used_module_members . get ( mident) ;
2411
+ if fun. entry . is_none ( )
2355
2412
&& matches ! ( fun. visibility, Visibility :: Internal )
2413
+ && ( members. is_none ( ) || !members. unwrap ( ) . contains ( name) )
2356
2414
{
2357
2415
// TODO: postponing handling of friend functions until we decide what to do with them
2358
2416
// vis-a-vis ideas around package-private
0 commit comments