|
1 | 1 | use std::convert::TryInto; |
2 | 2 |
|
3 | 3 | use crate::analysis::parsing::{statement::{self, CompoundContent, ForContent, |
4 | | - SwitchCase, WhileContent}, |
| 4 | + SwitchCase, WhileContent, SwitchContent}, |
5 | 5 | structure::ObjectStatementsContent, |
6 | 6 | types::{BitfieldsContent, LayoutContent, StructTypeContent}}; |
7 | 7 | use crate::span::{Range, ZeroIndexed}; |
@@ -248,6 +248,137 @@ impl Rule for IN3Rule { |
248 | 248 | } |
249 | 249 | } |
250 | 250 |
|
| 251 | +pub struct IN4Rule { |
| 252 | + pub enabled: bool, |
| 253 | + pub indentation_spaces: u32, |
| 254 | +} |
| 255 | + |
| 256 | +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] |
| 257 | +pub struct IN4Options { |
| 258 | + #[serde(default = "default_indentation_spaces")] |
| 259 | + pub indentation_spaces: u32, |
| 260 | +} |
| 261 | + |
| 262 | +impl Rule for IN4Rule { |
| 263 | + fn name() -> &'static str { |
| 264 | + "IN4" |
| 265 | + } |
| 266 | + fn description() -> &'static str { |
| 267 | + "Closing braces at the beginning of a line should be aligned to the corresponding \ |
| 268 | + indentation level of the statement that started the code block. A closing brace should \ |
| 269 | + only ever appear on the same line as the opening brace, or first on a line." |
| 270 | + } |
| 271 | + fn get_rule_type() -> RuleType { |
| 272 | + RuleType::IN4 |
| 273 | + } |
| 274 | +} |
| 275 | + |
| 276 | +pub struct IN4Args { |
| 277 | + expected_depth: u32, |
| 278 | + lbrace: ZeroRange, |
| 279 | + last_member: ZeroRange, |
| 280 | + rbrace: ZeroRange, |
| 281 | +} |
| 282 | + |
| 283 | +impl IN4Args { |
| 284 | + pub fn from_compound_content(node: &CompoundContent, depth: u32) -> Option<IN4Args> { |
| 285 | + Some(IN4Args { |
| 286 | + expected_depth: depth.saturating_sub(1), |
| 287 | + lbrace: node.lbrace.range(), |
| 288 | + last_member: node.statements.last()?.range(), |
| 289 | + rbrace: node.rbrace.range(), |
| 290 | + }) |
| 291 | + } |
| 292 | + |
| 293 | + pub fn from_obj_stmts_content(node: &ObjectStatementsContent, depth: u32) -> Option<IN4Args> { |
| 294 | + if let ObjectStatementsContent::List(lbrace, stmnts, rbrace) = node { |
| 295 | + Some(IN4Args { |
| 296 | + expected_depth: depth.saturating_sub(1), |
| 297 | + lbrace: lbrace.range(), |
| 298 | + last_member: stmnts.last()?.range(), |
| 299 | + rbrace: rbrace.range(), |
| 300 | + }) |
| 301 | + } else { |
| 302 | + None |
| 303 | + } |
| 304 | + } |
| 305 | + |
| 306 | + pub fn from_switch_content(node: &SwitchContent, depth: u32) -> Option<IN4Args> { |
| 307 | + Some(IN4Args { |
| 308 | + // Switch content does not increase indentation level before this call |
| 309 | + // so there is no need to reduce it |
| 310 | + expected_depth: depth, |
| 311 | + lbrace: node.lbrace.range(), |
| 312 | + last_member: node.cases.last()?.range(), |
| 313 | + rbrace: node.rbrace.range(), |
| 314 | + }) |
| 315 | + } |
| 316 | + |
| 317 | + pub fn from_struct_type_content(node: &StructTypeContent, depth: u32) -> Option<IN4Args> { |
| 318 | + Some(IN4Args { |
| 319 | + expected_depth: depth.saturating_sub(1), |
| 320 | + lbrace: node.lbrace.range(), |
| 321 | + last_member: node.members.last()?.range(), |
| 322 | + rbrace: node.rbrace.range(), |
| 323 | + }) |
| 324 | + } |
| 325 | + |
| 326 | + pub fn from_layout_content(node: &LayoutContent, depth: u32) -> Option<IN4Args> { |
| 327 | + Some(IN4Args { |
| 328 | + expected_depth: depth.saturating_sub(1), |
| 329 | + lbrace: node.lbrace.range(), |
| 330 | + last_member: node.fields.last()?.range(), |
| 331 | + rbrace: node.rbrace.range(), |
| 332 | + }) |
| 333 | + } |
| 334 | + |
| 335 | + pub fn from_bitfields_content(node: &BitfieldsContent, depth: u32) -> Option<IN4Args> { |
| 336 | + Some(IN4Args { |
| 337 | + expected_depth: depth.saturating_sub(1), |
| 338 | + lbrace: node.lbrace.range(), |
| 339 | + last_member: node.fields.last()?.range(), |
| 340 | + rbrace: node.rbrace.range(), |
| 341 | + }) |
| 342 | + } |
| 343 | + |
| 344 | +} |
| 345 | + |
| 346 | +impl IN4Rule { |
| 347 | + pub fn from_options(options: &Option<IN4Options>) -> IN4Rule { |
| 348 | + match options { |
| 349 | + Some(options) => IN4Rule { |
| 350 | + enabled: true, |
| 351 | + indentation_spaces: options.indentation_spaces, |
| 352 | + }, |
| 353 | + None => IN4Rule { |
| 354 | + enabled: false, |
| 355 | + indentation_spaces: 0, |
| 356 | + }, |
| 357 | + } |
| 358 | + } |
| 359 | + |
| 360 | + pub fn check(&self, acc: &mut Vec<DMLStyleError>, args: Option<IN4Args>) { |
| 361 | + if !self.enabled { return; } |
| 362 | + let Some(args) = args else { return; }; |
| 363 | + |
| 364 | + let lbrace_on_same_row_than_rbrace:bool = args.lbrace.row_start |
| 365 | + == args.rbrace.row_start; |
| 366 | + if lbrace_on_same_row_than_rbrace { return; } |
| 367 | + |
| 368 | + let last_member_on_same_row_than_rbrace:bool = args.last_member.row_end |
| 369 | + == args.rbrace.row_start; |
| 370 | + if last_member_on_same_row_than_rbrace { |
| 371 | + return self.push_err(acc, args.rbrace); |
| 372 | + } |
| 373 | + |
| 374 | + let rbrace_on_same_ind_level_than_switchtok:bool = args.rbrace.col_start.0 |
| 375 | + == args.expected_depth * self.indentation_spaces; |
| 376 | + if !rbrace_on_same_ind_level_than_switchtok { |
| 377 | + return self.push_err(acc, args.rbrace); |
| 378 | + } |
| 379 | + } |
| 380 | +} |
| 381 | + |
251 | 382 | pub struct IN9Rule { |
252 | 383 | pub enabled: bool, |
253 | 384 | indentation_spaces: u32 |
|
0 commit comments