All files / src/rules prefer_is_not.ts

100% Statements 50/50
100% Branches 24/24
100% Functions 6/6
100% Lines 50/50

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 1101x 1x 1x 1x 1x 1x   1x     1x     1x   7266x     21678x                                     7008x       114x       164x   164x 793x 47x 28x 19x 1x     18x   18x 18x       164x           18x 4x 4x 4x   14x 2x 2x 2x   12x 6x   6x 1x   5x 1x   4x 1x   3x 1x   2x 1x     1x     17x 17x 17x 17x   17x        
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import * as Expressions from "../abap/2_statements/expressions";
import {BasicRuleConfig} from "./_basic_rule_config";
import {EditHelper, IEdit} from "../edit_helper";
import {IRuleMetadata, RuleTag} from "./_irule";
import {ABAPFile} from "../abap/abap_file";
import {Position} from "../position";
import {ExpressionNode} from "../abap/nodes";
 
export class PreferIsNotConf extends BasicRuleConfig {
}
 
export class PreferIsNot extends ABAPRule {
 
  private conf = new PreferIsNotConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "prefer_is_not",
      title: "Prefer IS NOT to NOT IS",
      shortDescription: `Prefer IS NOT to NOT IS`,
      extendedInformation: `
https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-is-not-to-not-is
 
"if not is_valid( )." examples are skipped`,
      tags: [RuleTag.Styleguide, RuleTag.Quickfix, RuleTag.SingleFile],
      goodExample: `IF variable IS NOT INITIAL.
IF variable NP 'TODO*'.
IF variable <> 42.`,
      badExample: `IF NOT variable IS INITIAL.
IF NOT variable CP 'TODO*'.
IF NOT variable = 42.`,
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: PreferIsNotConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile): Issue[] {
    const issues: Issue[] = [];
 
    for (const s of file.getStatements()) {
      for (const c of s.findAllExpressions(Expressions.Compare)) {
        if (c.concatTokens().toUpperCase().startsWith("NOT ") === false) {
          continue;
        } else if (c.getChildren().length === 2 && c.getChildren()[1].get() instanceof Expressions.MethodCallChain) {
          continue;
        }
 
        const message = "Prefer IS NOT to NOT IS";
 
        const fix = this.getFix(file, c);
        issues.push(Issue.atToken(file, c.getFirstToken(), message, this.getMetadata().key, this.conf.severity, fix));
      }
    }
 
    return issues;
  }
 
  private getFix(file: ABAPFile, c: ExpressionNode): IEdit|undefined {
    let insertFix: IEdit;
 
    if (c.getChildren()[2].getFirstToken().getStr().toUpperCase() === "IS") {
      const tokenPositionBeforeDelete = c.getChildren()[2].getLastToken().getEnd();
      const tokenPosition = new Position(tokenPositionBeforeDelete.getRow(), tokenPositionBeforeDelete.getCol() + 1);
      insertFix = EditHelper.insertAt(file, tokenPosition, "NOT ");
    }
    else if(c.getChildren()[2].getFirstToken().getStr().toUpperCase() === "IN" || c.getChildren()[2].getFirstToken().getStr().toUpperCase() === "BETWEEN") {
      const tokenPositionBeforeDelete = c.getChildren()[1].getLastToken().getEnd();
      const tokenPosition = new Position(tokenPositionBeforeDelete.getRow(), tokenPositionBeforeDelete.getCol() + 1);
      insertFix = EditHelper.insertAt(file, tokenPosition, "NOT ");
    }
    else if(c.getChildren()[2].getFirstToken().getStr() === "=") {
      insertFix = EditHelper.replaceToken(file, c.getChildren()[2].getLastToken(), "<>");
    }
    else if(c.getChildren()[2].getFirstToken().getStr() === "<>") {
      insertFix = EditHelper.replaceToken(file, c.getChildren()[2].getLastToken(), "=");
    }
    else if(c.getChildren()[2].getFirstToken().getStr() === "<") {
      insertFix = EditHelper.replaceToken(file, c.getChildren()[2].getLastToken(), ">");
    }
    else if(c.getChildren()[2].getFirstToken().getStr() === ">") {
      insertFix = EditHelper.replaceToken(file, c.getChildren()[2].getLastToken(), "<");
    }
    else if(c.getChildren()[2].getFirstToken().getStr() === "<=") {
      insertFix = EditHelper.replaceToken(file, c.getChildren()[2].getLastToken(), ">=");
    }
    else if(c.getChildren()[2].getFirstToken().getStr() === ">=") {
      insertFix = EditHelper.replaceToken(file, c.getChildren()[2].getLastToken(), "<=");
    }
    else {
      return;
    }
 
    const endCol = c.getChildren()[0].getFirstToken().getEnd().getCol() + 1;
    const endPosition = new Position(c.getChildren()[0].getFirstToken().getEnd().getRow(), endCol);
    const deleteFix = EditHelper.deleteRange(file, c.getChildren()[0].getFirstToken().getStart(), endPosition);
    const finalFix = EditHelper.merge(insertFix, deleteFix);
 
    return finalFix;
  }
 
}