All files / src/rules no_public_attributes.ts

100% Statements 44/44
100% Branches 8/8
100% Functions 13/13
100% Lines 42/42

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 931x 1x 1x 1x 1x   1x 1x     1x   14531x     1x 7266x         21690x                       30x       7008x       115x       139x 139x 139x       139x 139x 139x 139x       139x 139x 139x 83x 3x   80x   139x       139x 139x 27x   139x       139x 139x 36x 3x 33x 3x   30x 30x   139x        
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;
}
 
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],
    };
  }
 
  public 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;
      }
      const issue = Issue.atIdentifier(attr.identifier, this.getDescription(attr.name), this.getMetadata().key, this.conf.severity);
      issues.push(issue);
    }
    return issues;
  }
 
 
}