All files / src/rules message_exists.ts

95.83% Statements 46/48
85% Branches 17/20
100% Functions 5/5
95.83% Lines 46/48

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 901x 1x 1x 1x   1x     1x     1x 7273x     21661x               7008x       114x       137x   137x 137x 12x     125x   125x 7x 3x 3x 3x   1x 1x 1x         125x 7x 4x 4x       4x 4x 4x 4x 1x 1x 1x 1x   1x   3x 3x     3x 3x 3x 1x 1x 1x             125x    
import * as Expressions from "../abap/2_statements/expressions";
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import {MessageClass} from "../objects";
import {DDIC} from "../ddic";
import {ABAPFile} from "../abap/abap_file";
 
export class MessageExistsConf extends BasicRuleConfig {
}
 
export class MessageExistsRule extends ABAPRule {
  private conf = new MessageExistsConf();
 
  public getMetadata() {
    return {
      key: "message_exists",
      title: "Check MESSAGE exists",
      shortDescription: `In message statements, check that the message class + id exist`,
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: MessageExistsConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile) {
    const issues: Issue[] = [];
 
    const struc = file.getStructure();
    if (struc === undefined) {
      return [];
    }
 
    const expressions = struc.findAllExpressionsMulti([Expressions.MessageClass, Expressions.MessageSource]);
 
    for (const node of expressions) {
      if (node.get() instanceof Expressions.MessageClass) {
        const token = node.getFirstToken();
        const name = token.getStr();
        if (this.reg.getObject("MSAG", name) === undefined
            && new DDIC(this.reg).inErrorNamespace(name) === true) {
          const message = "Message class \"" + name + "\" not found";
          const issue = Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity);
          issues.push(issue);
        }
      }
    }
 
    for (const node of expressions) {
      if (node.get() instanceof Expressions.MessageSource) {
        const clas = node.findFirstExpression(Expressions.MessageClass);
        Iif (clas === undefined) {
// todo, handle case where message class is defined on header level instead of in the statement
          continue;
        }
        const token = clas.getFirstToken();
        const name = token.getStr();
        const msag = this.reg.getObject("MSAG", name) as MessageClass | undefined;
        if (msag === undefined) {
          Eif (new DDIC(this.reg).inErrorNamespace(name) === true) {
            const message = "Message class \"" + token.getStr() + "\" not found";
            const issue = Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity);
            issues.push(issue);
          }
          continue;
        }
        const typeNumber = node.findFirstExpression(Expressions.MessageTypeAndNumber);
        Iif (typeNumber === undefined) {
          continue;
        }
        const numberToken = typeNumber.getFirstToken();
        const num = numberToken.getStr().substr(1);
        if (msag.getByNumber(num) === undefined) {
          const message = "Message number \"" + num + "\" not found in class \"" + name + "\"";
          const issue = Issue.atToken(file, numberToken, message, this.getMetadata().key, this.conf.severity);
          issues.push(issue);
        }
      }
    }
 
// todo, check number of placeholders in message vs code matches
 
    return issues;
  }
}