All files / src/rules indentation.ts

95.12% Statements 117/123
85.71% Branches 36/42
100% Functions 6/6
95.12% Lines 117/123

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 1231x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 15336x 15336x 15336x 15336x 15336x 15336x 15336x 15336x 15336x 15336x 15336x 1x 7683x 7683x 7683x 7683x 22945x 22945x 22945x 22945x 22945x 22945x 22945x 7683x 7683x 7346x 7346x 7683x 7683x 140x 140x 7683x 7683x 208x 208x 208x 208x 20x 20x 188x 208x 32x 32x 32x 1x 32x 1x 1x 32x 186x 186x 208x 208x 208x 208x 208x 208x 208x 208x 208x 987x 987x 9x 9x 978x 978x 978x 987x 11x 11x 1x 1x 11x 1x 1x 10x 3x 3x 11x 973x 987x 6x 6x 1x 1x 6x     5x     6x 972x 987x 103x 103x 103x 103x 103x 103x     103x 987x 186x 186x 186x 7683x
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {IObject} from "../objects/_iobject";
import {Class} from "../objects";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IIndentationOptions} from "../pretty_printer/indentation_options";
import {Indent} from "../pretty_printer/indent";
import * as Statements from "../abap/2_statements/statements";
import * as Expressions from "../abap/2_statements/expressions";
import {IRuleMetadata, RuleTag} from "./_irule";
import {DDIC} from "../ddic";
import {Position, VirtualPosition} from "../position";
import {EditHelper} from "../edit_helper";
import {ABAPFile} from "../abap/abap_file";
 
export class IndentationConf extends BasicRuleConfig {
  /** Ignore global exception classes */
  public ignoreExceptions: boolean = true;
  /** Align TRY CATCH, TRY and CATCH should have the same indentation */
  public alignTryCatch: boolean = false;
  /** Add indentation for SELECTION SCREEN BLOCK, standard pretty printer indents this from 754 */
  public selectionScreenBlockIndentation: boolean = false;
  public globalClassSkipFirst: boolean = false;
  public ignoreGlobalClassDefinition: boolean = false;
  public ignoreGlobalInterface: boolean = false;
}
 
export class Indentation extends ABAPRule {
  private conf = new IndentationConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "indentation",
      title: "Indentation",
      shortDescription: `Checks indentation`,
      tags: [RuleTag.Whitespace, RuleTag.Quickfix, RuleTag.SingleFile],
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: IndentationConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile, obj: IObject) {
    const MAX_ISSUES = 100;
    let skip = false;
 
    if (file.getStructure() === undefined) {
      return []; // syntax error in file
    }
 
    if (obj instanceof Class) {
      const definition = obj.getClassDefinition();
      const ddic = new DDIC(this.reg);
      if (definition === undefined) {
        return [];
      } else if (this.conf.ignoreExceptions && ddic.isException(definition, obj)) {
        return [];
      }
    }
 
    const indentOpts: IIndentationOptions = {
      selectionScreenBlockIndentation: this.conf?.selectionScreenBlockIndentation,
      alignTryCatch: this.conf?.alignTryCatch,
      globalClassSkipFirst: this.conf.globalClassSkipFirst,
    };
 
    const expected = new Indent(indentOpts).getExpectedIndents(file);
    const ret: Issue[] = [];
 
    for (const statement of file.getStatements()) {
      const position = statement.getFirstToken().getStart();
      if (position instanceof VirtualPosition) {
        continue;
      }
 
      const indent = expected.shift();
 
      if (this.conf.ignoreGlobalClassDefinition) {
        if (statement.get() instanceof Statements.ClassDefinition
          && statement.findFirstExpression(Expressions.ClassGlobal)) {
          skip = true;
          continue;
        } else if (skip === true && statement.get() instanceof Statements.EndClass) {
          skip = false;
          continue;
        } else if (skip === true) {
          continue;
        }
      }
 
      if (this.conf.ignoreGlobalInterface) {
        if (statement.get() instanceof Statements.Interface
          && statement.findFirstExpression(Expressions.ClassGlobal)) {
          skip = true;
          continue;
        } else if (skip === true && statement.get() instanceof Statements.EndInterface) {
          skip = false;
          continue;
        } else if (skip === true) {
          continue;
        }
      }
 
      if (indent && indent > 0 && indent !== position.getCol()) {
        const expected = indent - 1;
        const fix = EditHelper.replaceRange(file, new Position(position.getRow(), 1), position, " ".repeat(expected));
        const message = "Indentation problem, expected " + expected + " spaces";
        const issue = Issue.atPosition(file, position, message, this.getMetadata().key, this.conf.severity, fix);
        ret.push(issue);
        if (ret.length >= MAX_ISSUES) {
          break;
        }
      }
    }
 
    return ret;
  }
}