All files / src/rules bdef_check_syntax.ts

92.92% Statements 92/99
85.71% Branches 18/21
100% Functions 9/9
92.92% Lines 92/99

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 1001x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 14687x 14687x 14687x 14687x 14687x 43910x 43910x 43910x 43910x 43910x 43910x 43910x 43910x 43910x 43910x 14687x 14687x 14120x 14120x 14687x 14687x 264x 264x 14687x 14687x 270x 270x 270x 14687x 14687x 367x 359x 359x 8x 8x 8x 367x 1x 1x 7x 7x 7x 7x 7x 7x 14687x 14687x 7x 7x 7x     7x 7x 2x 2x 2x 7x 7x 14687x 14687x 7x 7x 7x       7x 7x     7x 7x 7x 7x 1x 1x 1x 7x 7x 14687x 14687x 14x 14x 14687x  
import {ExpressionNode} from "../abap/nodes";
import {BDEFDefineBehavior, BDEFImplementationIn, BDEFName} from "../bdef/expressions";
import {DDIC} from "../ddic";
import {IFile} from "../files/_ifile";
import {Issue} from "../issue";
import {BehaviorDefinition} from "../objects";
import {IObject} from "../objects/_iobject";
import {IRegistry} from "../_iregistry";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IRule, IRuleMetadata, RuleTag} from "./_irule";
 
export class BDEFCheckSyntaxConf extends BasicRuleConfig {
}
 
export class BDEFCheckSyntax implements IRule {
  private reg: IRegistry;
  private conf = new BDEFCheckSyntaxConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "bdef_check_syntax",
      title: "BDEF Check Syntax",
      shortDescription: "Checks behavior definition references to entities and implementation classes",
      extendedInformation: `Performs semantic checks which require other objects to be available.
 
Missing objects are only reported when their names match the configured errorNamespace.`,
      tags: [RuleTag.Syntax],
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: BDEFCheckSyntaxConf) {
    this.conf = conf;
  }
 
  public initialize(reg: IRegistry): IRule {
    this.reg = reg;
    return this;
  }
 
  public run(object: IObject): Issue[] {
    if (!(object instanceof BehaviorDefinition)) {
      return [];
    }
 
    const tree = object.getTree();
    const file = object.findSourceFile();
    if (tree === undefined || file === undefined) {
      return [];
    }
 
    const issues: Issue[] = [];
    this.checkImplementationClasses(tree, issues, file);
    this.checkEntities(tree, issues, file);
    return issues;
  }
 
  private checkImplementationClasses(tree: ExpressionNode, issues: Issue[], file: IFile) {
    for (const implementation of tree.findAllExpressions(BDEFImplementationIn)) {
      const nameNode = implementation.findDirectExpression(BDEFName);
      if (nameNode === undefined) {
        continue;
      }
      const name = this.name(nameNode);
      if (this.reg.getObject("CLAS", name) === undefined && this.reg.inErrorNamespace(name)) {
        issues.push(Issue.atToken(file, nameNode.getFirstToken(), `Implementation class "${name}" not found`,
                                  this.getMetadata().key, this.conf.severity));
      }
    }
  }
 
  private checkEntities(tree: ExpressionNode, issues: Issue[], file: IFile) {
    const ddic = new DDIC(this.reg);
    for (const define of tree.findDirectExpressions(BDEFDefineBehavior)) {
      if (define.getFirstToken().getStr().toUpperCase() !== "DEFINE") {
        // "extend behavior for" refers to entities of the extended BDEF
        continue;
      }
      const nameNode = define.findDirectExpression(BDEFName);
      if (nameNode === undefined) {
        continue;
      }
      const name = this.name(nameNode);
      if (this.reg.inErrorNamespace(name)
          && this.reg.getObject("DDLS", name) === undefined
          && ddic.lookupDDLS(name) === undefined) {
        issues.push(Issue.atToken(file, nameNode.getFirstToken(), `Entity "${name}" not found`,
                                  this.getMetadata().key, this.conf.severity));
      }
    }
  }
 
  private name(node: ExpressionNode): string {
    return node.concatTokens().replace(/ /g, "");
  }
}