11use std:: convert:: TryInto ;
22
3- use crate :: analysis:: parsing:: { statement:: { self , CompoundContent , SwitchCase } ,
3+ use crate :: analysis:: parsing:: { statement:: { self , CompoundContent , ForContent ,
4+ SwitchCase , WhileContent } ,
45 structure:: ObjectStatementsContent ,
56 types:: { LayoutContent , StructTypeContent } } ;
67use crate :: span:: { Range , ZeroIndexed , Row , Column } ;
@@ -32,6 +33,9 @@ pub fn setup_indentation_size(cfg: &mut LintCfg) {
3233 if let Some ( in9) = & mut cfg. in9 {
3334 in9. indentation_spaces = indentation_spaces;
3435 }
36+ if let Some ( in10) = & mut cfg. in10 {
37+ in10. indentation_spaces = indentation_spaces;
38+ }
3539}
3640#[ derive( Clone , Debug , Serialize , Deserialize , PartialEq ) ]
3741pub struct LongLineOptions {
@@ -417,3 +421,98 @@ impl Rule for IN9Rule {
417421 RuleType :: IN9
418422 }
419423}
424+
425+ // IN10: Indentation in empty loop
426+ pub struct IN10Rule {
427+ pub enabled : bool ,
428+ indentation_spaces : u32
429+ }
430+
431+ #[ derive( Clone , Debug , Serialize , Deserialize , PartialEq ) ]
432+ pub struct IN10Options {
433+ #[ serde( default = "default_indentation_spaces" ) ]
434+ pub indentation_spaces : u32 ,
435+ }
436+
437+ pub struct IN10Args < ' a > {
438+ loop_keyword_range : ZeroRange ,
439+ semicolon_range : ZeroRange ,
440+ expected_depth : & ' a mut u32 ,
441+ }
442+
443+ impl IN10Args < ' _ > {
444+ pub fn from_for_content < ' a > ( node : & ForContent , depth : & ' a mut u32 ) -> Option < IN10Args < ' a > > {
445+ if let Content :: Some ( statement:: StatementContent :: Empty ( semicolon) ) = node. statement . content . as_ref ( ) {
446+ * depth += 1 ;
447+ return Some ( IN10Args {
448+ loop_keyword_range : node. fortok . range ( ) ,
449+ semicolon_range : semicolon. range ( ) ,
450+ expected_depth : depth
451+ } ) ;
452+
453+ }
454+ return None ;
455+ }
456+
457+ pub fn from_while_content < ' a > ( node : & WhileContent , depth : & ' a mut u32 ) -> Option < IN10Args < ' a > > {
458+ if let Content :: Some ( statement:: StatementContent :: Empty ( semicolon) ) = node. statement . content . as_ref ( ) {
459+ * depth += 1 ;
460+ return Some ( IN10Args {
461+ loop_keyword_range : node. whiletok . range ( ) ,
462+ semicolon_range : semicolon. range ( ) ,
463+ expected_depth : depth
464+ } ) ;
465+
466+ }
467+ return None ;
468+ }
469+ }
470+
471+ impl IN10Rule {
472+ pub fn from_options ( options : & Option < IN10Options > ) -> IN10Rule {
473+ match options {
474+ Some ( options) => IN10Rule {
475+ enabled : true ,
476+ indentation_spaces : options. indentation_spaces
477+ } ,
478+ None => IN10Rule {
479+ enabled : false ,
480+ indentation_spaces : 0
481+ }
482+ }
483+ }
484+ pub fn check < ' a > ( & self , acc : & mut Vec < DMLStyleError > ,
485+ args : Option < IN10Args < ' a > > )
486+ {
487+ if !self . enabled { return ; }
488+ let Some ( args) = args else { return ; } ;
489+ if self . indentation_is_not_aligned ( args. semicolon_range , * args. expected_depth ) ||
490+ args. loop_keyword_range . row_start == args. semicolon_range . row_start {
491+ let dmlerror = DMLStyleError {
492+ error : LocalDMLError {
493+ range : Range :: combine ( args. loop_keyword_range , args. semicolon_range ) ,
494+ description : Self :: description ( ) . to_string ( ) ,
495+ } ,
496+ rule_type : Self :: get_rule_type ( ) ,
497+ } ;
498+ acc. push ( dmlerror) ;
499+ }
500+ }
501+ fn indentation_is_not_aligned ( & self , member_range : ZeroRange , depth : u32 ) -> bool {
502+ let expected_column = self . indentation_spaces * depth;
503+ member_range. col_start . 0 != expected_column
504+ }
505+ }
506+
507+ impl Rule for IN10Rule {
508+ fn name ( ) -> & ' static str {
509+ "IN10_INDENTATION_EMPTY_LOOP"
510+ }
511+ fn description ( ) -> & ' static str {
512+ "When the body of a while or for loop is left empty, \
513+ indent the semicolon to the appropriate statement level"
514+ }
515+ fn get_rule_type ( ) -> RuleType {
516+ RuleType :: IN10
517+ }
518+ }
0 commit comments