All files / src/lsp inlay_hints.ts

92.59% Statements 75/81
72.72% Branches 8/11
100% Functions 3/3
92.59% Lines 75/81

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 811x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 8x 8x 1x 1x 8x 8x     8x 8x 8x     8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 7x 8x 1x 1x 8x 8x     8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 1x 1x 29x 29x 29x 30x 8x 8x 30x 29x 29x 21x 21x 29x 29x 29x 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) {
        ret.push(r);
      }
    }
 
    for (const c of node.getChildren()) {
      ret.push(...this.findImplicitReferences(c));
    }
 
    return ret;
  }
 
}