All files / src/rules strict_sql.ts

97.67% Statements 84/86
94.28% Branches 33/35
100% Functions 5/5
97.67% Lines 84/86

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 861x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 10057x 10057x 10057x 10057x 29996x 29996x 29996x 29996x 29996x 29996x 29996x 29996x 29996x 29996x 29996x 29996x 29996x 29996x 10057x 10057x 9555x 9555x 10057x 10057x 234x 234x 10057x 10057x 259x 259x 259x 259x 22x 22x 237x 237x 259x     237x 259x 1338x 1338x 15x 15x 15x 15x 15x 15x 15x 15x 3x 15x 6x 6x 6x 6x 6x 15x 2x 2x 6x 6x 6x 6x 6x 6x 1338x 237x 237x 237x 10057x
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 StrictSQLConf extends BasicRuleConfig {
}
 
export class StrictSQL extends ABAPRule {
  private conf = new StrictSQLConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "strict_sql",
      title: "Strict SQL",
      shortDescription: `Strict SQL`,
      extendedInformation: `https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abapinto_clause.htm
 
https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-us/abenopensql_strict_mode_750.htm
 
Also see separate rule sql_escape_host_variables
 
Activates from v750 and up`,
      tags: [RuleTag.Upport, RuleTag.Quickfix],
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: StrictSQLConf) {
    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.v750
        && this.reg.getConfig().getVersion() !== Version.Cloud) {
      return [];
    }
 
    for (const s of file.getStatements()) {
      if (s.get() instanceof Statements.Select
          || s.get() instanceof Statements.SelectLoop) {
 
        const expr = s.findDirectExpression(Expressions.Select);
        const where = expr?.findDirectExpression(Expressions.SQLCond);
        const order = expr?.findDirectExpression(Expressions.SQLOrderBy);
        const into = expr?.findDirectExpression(Expressions.SQLIntoStructure)
          || expr?.findDirectExpression(Expressions.SQLIntoList)
          || expr?.findDirectExpression(Expressions.SQLIntoTable);
        if (into === undefined || where === undefined) {
          continue;
        } else if (where.getFirstToken().getStart().isBefore(into.getFirstToken().getStart())) {
          continue;
        }
 
        const fix1 = EditHelper.deleteRange(file, into.getFirstToken().getStart(), into.getLastToken().getEnd());
        let last = where.getLastToken();
        if (order && order.getLastToken().getEnd().isAfter(last.getEnd())) {
          last = order.getLastToken();
        }
        const fix2 = EditHelper.insertAt(file, last.getEnd(), " " + into.concatTokens());
        const fix = EditHelper.merge(fix2, fix1);
        const message = "INTO/APPENDING must be last in strict SQL";
        const issue = Issue.atToken(file, s.getFirstToken(), message, this.getMetadata().key, this.conf.severity, fix);
        issues.push(issue);
      }
    }
 
    return issues;
  }
}