All files / src/rules no_public_attributes.ts

97.95% Statements 96/98
92.3% Branches 24/26
100% Functions 11/11
97.95% Lines 96/98

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 981x 1x 1x 1x 1x 1x 1x 1x 1x 1x 17845x 17845x 17845x 17845x 17845x 17845x 1x 8923x 8923x 8923x 8923x 8923x 8923x 35134x 35134x 35134x 35134x 35134x 35134x 35134x 35134x 35134x 35134x 8923x 8923x 40x 40x 8923x 8923x 8485x 8485x 8923x 8923x 203x 203x 8923x 8923x 224x 224x 224x 224x 8923x 8923x 224x 224x 224x 224x 224x 8923x 8923x 224x 224x 224x 108x 3x 3x 105x 105x 224x 224x 8923x 8923x 224x 224x 40x 40x 224x 224x 8923x 8923x 224x 224x 51x 3x 51x 8x 48x 40x     40x 40x 40x 224x 224x 8923x 8923x 8923x
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],
    };
  }
 
  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;
  }
 
 
}