All files / src/rules no_public_attributes.ts

98.11% Statements 104/106
92.3% Branches 24/26
100% Functions 11/11
98.11% Lines 104/106

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 1071x 1x 1x 1x 1x 1x 1x 1x 1x 1x 29365x 29365x 29365x 29365x 29365x 29365x 1x 14683x 14683x 14683x 14683x 14683x 14683x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 72204x 14683x 14683x 55x 55x 14683x 14683x 14120x 14120x 14683x 14683x 265x 265x 14683x 14683x 304x 304x 304x 304x 14683x 14683x 304x 304x 304x 304x 304x 14683x 14683x 304x 304x 304x 145x 3x 3x 142x 142x 304x 304x 14683x 14683x 304x 304x 57x 57x 304x 304x 14683x 14683x 304x 304x 69x 4x 69x 10x 65x 55x     55x 55x 55x 304x 304x 14683x 14683x 14683x  
import {Issue} from "../issue";
import {BasicRuleConfig} from "./_basic_rule_config";
import {ABAPRule} from "./_abap_rule";
import {Visibility} from "../abap/4_file_information/visibility";
import {InfoAttribute, AttributeLevel} from "../abap/4_file_information/_abap_file_information";
import {ABAPObject} from "../objects/_abap_object";
import {DDIC} from "../ddic";
import {IRuleMetadata, RuleTag} from "./_irule";
import {ABAPFile} from "../abap/abap_file";
 
export class NoPublicAttributesConf extends BasicRuleConfig {
  /** Allows public attributes, if they are declared as READ-ONLY. */
  public allowReadOnly: boolean = false;
  /** Option to ignore test classes for this check. */
  public ignoreTestClasses: boolean = false;
}
 
export class NoPublicAttributes extends ABAPRule {
  private conf = new NoPublicAttributesConf();
 
  private file: ABAPFile;
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "no_public_attributes",
      title: "No public attributes",
      shortDescription: `Checks that classes and interfaces don't contain any public attributes.
Exceptions are excluded from this rule.`,
      extendedInformation:
        `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#members-private-by-default-protected-only-if-needed`,
      tags: [RuleTag.Styleguide, RuleTag.SingleFile],
      badExample: `CLASS zcl_foo DEFINITION PUBLIC.
  PUBLIC SECTION.
    DATA counter TYPE i.
ENDCLASS.`,
      goodExample: `CLASS zcl_foo DEFINITION PUBLIC.
  PRIVATE SECTION.
    DATA counter TYPE i.
ENDCLASS.`,
    };
  }
 
  private getDescription(name: string): string {
    return "Public attributes are not allowed, attribute \"" + name + "\"";
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: NoPublicAttributesConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile, obj: ABAPObject) {
    this.file = file;
    const attributes = this.getAllPublicAttributes(obj);
    return this.findAllIssues(attributes);
  }
 
  private getAllPublicAttributes(obj: ABAPObject): InfoAttribute[] {
    let attributes: InfoAttribute[] = [];
    attributes = attributes.concat(this.getAllPublicClassAttributes(obj));
    attributes = attributes.concat(this.getAllPublicInterfaceAttributes());
    return attributes;
  }
 
  private getAllPublicClassAttributes(obj: ABAPObject): InfoAttribute[] {
    let attributes: InfoAttribute[] = [];
    const ddic = new DDIC(this.reg);
    for (const classDef of this.file.getInfo().listClassDefinitions()) {
      if (ddic.isException(classDef, obj)) {
        continue;
      }
      attributes = attributes.concat(classDef.attributes.filter(a => a.visibility === Visibility.Public));
    }
    return attributes;
  }
 
  private getAllPublicInterfaceAttributes(): InfoAttribute[] {
    let attributes: InfoAttribute[] = [];
    for (const interfaceDef of this.file.getInfo().listInterfaceDefinitions()) {
      attributes = attributes.concat(interfaceDef.attributes.filter(a => a.visibility === Visibility.Public));
    }
    return attributes;
  }
 
  private findAllIssues(attributes: InfoAttribute[]): Issue[] {
    const issues: Issue[] = [];
    for (const attr of attributes) {
      if (this.conf.allowReadOnly === true && attr.readOnly) {
        continue;
      } else if (attr.level === AttributeLevel.Constant) {
        continue;
      } else if ((this.conf.ignoreTestClasses === true)
        && this.file.getFilename().includes(".testclasses.")) {
        continue;
      }
      const issue = Issue.atIdentifier(attr.identifier, this.getDescription(attr.name), this.getMetadata().key, this.conf.severity);
      issues.push(issue);
    }
    return issues;
  }
 
 
}