All files / src/rules sql_escape_host_variables.ts

97.77% Statements 88/90
77.41% Branches 24/31
100% Functions 5/5
97.77% Lines 88/90

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 901x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 10486x 10486x 10486x 10486x 31287x 31287x 31287x 31287x 31287x 31287x 31287x 31287x 31287x 31287x 10486x 10486x 9952x 9952x 10486x 10486x 251x 251x 10486x 10486x 287x 287x 287x 287x 23x 23x 264x 264x 287x     264x 287x 1431x 1431x 1431x 1431x 1431x 1431x 25x 25x 12x 12x 12x 7x 7x 7x 7x 7x 7x 7x 12x 25x 25x 16x 16x 10x 10x 6x 6x 6x 16x 16x 16x 16x 16x 25x 1431x 264x 264x 264x 10486x
import * as Statements from "../abap/2_statements/statements";
import * as Expressions from "../abap/2_statements/expressions";
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import {Version} from "../version";
import {RuleTag, IRuleMetadata} from "./_irule";
import {ABAPFile} from "../abap/abap_file";
import {ABAPObject} from "../objects/_abap_object";
import {EditHelper} from "../edit_helper";
 
export class SQLEscapeHostVariablesConf extends BasicRuleConfig {
}
 
export class SQLEscapeHostVariables extends ABAPRule {
  private conf = new SQLEscapeHostVariablesConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "sql_escape_host_variables",
      title: "Escape SQL host variables",
      shortDescription: `Escape SQL host variables, from 740sp05`,
      extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#avoid-obsolete-language-elements`,
      tags: [RuleTag.Upport, RuleTag.Styleguide, RuleTag.Quickfix, RuleTag.Syntax],
      badExample: `SELECT * FROM tab INTO TABLE res WHERE field = val.`,
      goodExample: `SELECT * FROM tab INTO TABLE @res WHERE field = @val.`,
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: SQLEscapeHostVariablesConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile, obj: ABAPObject) {
    const issues: Issue[] = [];
 
    const type = obj.getType();
    if (type === "INTF" || type === "TYPE") {
      return [];
    }
 
    if (this.reg.getConfig().getVersion() < Version.v740sp02
        && this.reg.getConfig().getVersion() !== Version.Cloud) {
      return [];
    }
 
    for (const s of file.getStatements()) {
      if (s.get() instanceof Statements.UpdateDatabase
          || s.get() instanceof Statements.ModifyDatabase
          || s.get() instanceof Statements.Select
          || s.get() instanceof Statements.SelectLoop
          || s.get() instanceof Statements.InsertDatabase
          || s.get() instanceof Statements.DeleteDatabase) {
 
        for (const o of s.findAllExpressionsMulti([Expressions.SQLSource, Expressions.SQLSourceSimple])) {
          const first = o.getFirstChild();
          if ((first?.get() instanceof Expressions.Source && first.getChildren()[0].get() instanceof Expressions.FieldChain)
              || (first?.get() instanceof Expressions.SimpleSource3 && first.getChildren()[0].get() instanceof Expressions.FieldChain)) {
            const message = "Escape SQL host variables";
            const firstToken = o.getFirstChild()!.getFirstToken();
            const fix = EditHelper.replaceToken(file, firstToken, "@" + firstToken?.getStr());
            const issue = Issue.atToken(file, first.getFirstToken(), message, this.getMetadata().key, this.conf.severity, fix);
            issues.push(issue);
            break;
          }
        }
 
        for (const o of s.findAllExpressions(Expressions.SQLTarget)) {
          const escaped = o.findDirectTokenByText("@");
          if (escaped !== undefined) {
            continue;
          }
 
          const message = "Escape SQL host variables";
          const firstToken = o.getFirstChild()!.getFirstToken();
          const fix = EditHelper.replaceToken(file, firstToken, "@" + firstToken?.getStr());
          const issue = Issue.atToken(file, o.getFirstToken(), message, this.getMetadata().key, this.conf.severity, fix);
          issues.push(issue);
          break;
        }
      }
    }
 
    return issues;
  }
}