All files / src/lsp inlay_hints.ts

90.47% Statements 76/84
66.66% Branches 8/12
100% Functions 3/3
90.47% Lines 76/84

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 841x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 13x 13x 1x 1x 13x 13x     13x 13x 13x     13x 13x 13x 13x 13x 13x 13x 29x 29x 29x 29x 29x     29x 29x     29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 13x 13x 13x 13x 1x 1x 54x 54x 54x 58x 58x 41x 58x 29x 29x 58x 54x 54x 41x 41x 54x 54x 54x 1x 1x
import * as LServer from "vscode-languageserver-types";
import {IRegistry} from "../_iregistry";
import {LSPUtils} from "./_lsp_utils";
import {SyntaxLogic} from "../abap/5_syntax/syntax";
import {ABAPObject} from "../objects/_abap_object";
import {ISpaghettiScopeNode} from "../abap/5_syntax/_spaghetti_scope";
import {ReferenceType, IReference} from "../abap/5_syntax/_reference";
import {TypedIdentifier} from "../abap/types/_typed_identifier";
import {ClassDefinition} from "../abap/types";
 
export type InlayHintsSettings = {
  inferredTypes: boolean,
};
 
export class InlayHints {
  private readonly reg: IRegistry;
 
  public constructor(reg: IRegistry) {
    this.reg = reg;
  }
 
  public list(textDocument: LServer.TextDocumentIdentifier, settings: InlayHintsSettings = {inferredTypes: true}): LServer.InlayHint[] {
    const file = LSPUtils.getABAPFile(this.reg, textDocument.uri);
    if (file === undefined) {
      return [];
    }
 
    const obj = this.reg.findObjectForFile(file);
    if (obj === undefined || !(obj instanceof ABAPObject)) {
      return [];
    }
    const top = new SyntaxLogic(this.reg, obj).run().spaghetti.getTop();
 
    const ret: LServer.InlayHint[] = [];
 
    if (settings.inferredTypes === true) {
      const implicit = this.findImplicitReferences(top);
      for (const i of implicit) {
 
        let label: string | undefined = undefined;
        if (i.resolved instanceof TypedIdentifier) {
          label = "TYPE " + i.resolved.getType().toABAP();
        } else if (i.resolved instanceof ClassDefinition) {
          label = "TYPE REF TO " + i.resolved.getName();
        }
 
        if (label === undefined) {
          continue;
        }
 
        ret.push({
          label: label,
          tooltip: "Inferred type",
          kind: LServer.InlayHintKind.Type,
          paddingLeft: true,
          paddingRight: true,
          position: LSPUtils.positionToLS(i.position.getEnd()),
        });
      }
    }
 
    return ret;
  }
 
  private findImplicitReferences(node: ISpaghettiScopeNode): IReference[] {
    const ret: IReference[] = [];
 
    for (const r of node.getData().references) {
      if (
        r.referenceType === ReferenceType.InferredType ||
        r.referenceType === ReferenceType.DataWriteReference
      ) {
        ret.push(r);
      }
    }
 
    for (const c of node.getChildren()) {
      ret.push(...this.findImplicitReferences(c));
    }
 
    return ret;
  }
 
}