All files / src/rules unknown_types.ts

98.33% Statements 59/60
92.86% Branches 26/28
100% Functions 9/9
98.33% Lines 59/60

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 123 124 125  1x 1x   1x 1x 1x 1x     1x     1x   1x     1x   7270x     21683x                 122x 122x       7013x       114x       140x 8x     132x   132x           562x   562x 490x 490x 3531x 3531x 3531x 7x 7x       490x 490x 438x 438x 438x 1x 1x         562x 27x 27x 1x 1x       562x 430x     562x       27x 6x 5x 5x 1x       26x       48935x 9x 48926x 560x 44947x 44947x       48366x 14x   48912x      
import {IRegistry} from "../_iregistry";
import {SyntaxLogic} from "../abap/5_syntax/syntax";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IObject} from "../objects/_iobject";
import {ABAPObject} from "../objects/_abap_object";
import {Issue} from "../issue";
import * as BasicTypes from "../abap/types/basic";
import {IRuleMetadata, RuleTag, IRule} from "./_irule";
import {ISpaghettiScopeNode} from "../abap/5_syntax/_spaghetti_scope";
import {AbstractType} from "../abap/types/basic/_abstract_type";
import {TypedIdentifier} from "../abap/types/_typed_identifier";
import {IInterfaceDefinition} from "../abap/types/_interface_definition";
import {Identifier} from "../abap/4_file_information/_identifier";
import {ScopeType} from "../abap/5_syntax/_scope_type";
 
export class UnknownTypesConf extends BasicRuleConfig {
}
 
export class UnknownTypes implements IRule {
  private reg: IRegistry;
  private conf = new UnknownTypesConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "unknown_types",
      title: "Unknown types",
      shortDescription: `Enables check for unknown data types, respects errorNamespace`,
      tags: [RuleTag.Syntax],
    };
  }
 
  public initialize(reg: IRegistry) {
    this.reg = reg;
    return this;
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: UnknownTypesConf) {
    this.conf = conf;
  }
 
  public run(obj: IObject): Issue[] {
    if (!(obj instanceof ABAPObject)) {
      return [];
    }
 
    const spaghetti = new SyntaxLogic(this.reg, obj).run().spaghetti;
 
    return this.traverse(spaghetti.getTop());
  }
 
/////////////////////
 
  private traverse(node: ISpaghettiScopeNode): Issue[] {
    const ret: Issue[] = [];
 
    if (node.getIdentifier().stype !== ScopeType.ClassImplementation) {
      const vars = node.getData().vars;
      for (const name in vars) {
        const identifier = vars[name];
        const found = this.containsUnknown(identifier.getType());
        if (found) {
          const message = "Variable \"" + name + "\" contains unknown: " + found;
          ret.push(Issue.atIdentifier(identifier, message, this.getMetadata().key, this.conf.severity));
        }
      }
 
      const types = node.getData().types;
      for (const name in types) {
        const identifier = types[name];
        const found = this.containsUnknown(identifier.getType());
        if (found) {
          const message = "Type \"" + name + "\" contains unknown: " + found;
          ret.push(Issue.atIdentifier(identifier, message, this.getMetadata().key, this.conf.severity));
        }
      }
    }
 
    for (const v of node.getData().idefs) {
      const found = this.checkInterface(v);
      if (found) {
        const message = "Contains unknown, " + found.found;
        ret.push(Issue.atIdentifier(found.id, message, this.getMetadata().key, this.conf.severity));
      }
    }
 
    for (const n of node.getChildren()) {
      ret.push(...this.traverse(n));
    }
 
    return ret;
  }
 
  private checkInterface(idef: IInterfaceDefinition): {id: Identifier, found: string} | undefined {
    for (const m of idef.getMethodDefinitions()?.getAll() || []) {
      for (const p of m.getParameters().getAll()) {
        const found = this.containsUnknown(p.getType());
        if (found) {
          return {id: p, found};
        }
      }
    }
    return undefined;
  }
 
  private containsUnknown(type: AbstractType): string | undefined {
    if (type instanceof BasicTypes.UnknownType) {
      return type.getError();
    } else if (type instanceof BasicTypes.StructureType) {
      for (const c of type.getComponents()) {
        const found = this.containsUnknown(c.type instanceof TypedIdentifier ? c.type.getType() : c.type);
        Iif (found) {
          return found;
        }
      }
    } else if (type instanceof BasicTypes.TableType) {
      return this.containsUnknown(type.getRowType());
    }
    return undefined;
  }
 
}