All files / src/rules sql_escape_host_variables.ts

97.95% Statements 96/98
80% Branches 28/35
100% Functions 5/5
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 1x 1x 1x 1x 11306x 11306x 11306x 11306x 33771x 33771x 33771x 33771x 33771x 33771x 33771x 33771x 33771x 33771x 11306x 11306x 10810x 10810x 11306x 11306x 232x 232x 11306x 11306x 268x 268x 268x 268x 23x 23x 245x 245x 268x     245x 268x 1316x 1316x 1316x 1316x 1316x 1316x 1316x 25x 25x 13x 13x 13x 8x 8x 8x 1x 1x 1x 7x 7x 7x 8x 8x 8x 8x 8x 13x 25x 25x 15x 15x 10x 10x 5x 5x 5x 15x 15x 15x 15x 15x 25x 1316x 245x 245x 245x 11306x
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()) {
      const get = s.get();
      if (get instanceof Statements.UpdateDatabase
          || get instanceof Statements.ModifyDatabase
          || get instanceof Statements.Select
          || get instanceof Statements.SelectLoop
          || get instanceof Statements.InsertDatabase
          || 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)) {
 
            if (get instanceof Statements.ModifyDatabase
                && first.getFirstToken().getStr().toUpperCase().startsWith("LS_")) {
              // heuristic, might not be correct in all cases
              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, 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;
  }
}