All files / src/lsp rename.ts

91.4% Statements 85/93
75% Branches 21/28
100% Functions 4/4
91.4% Lines 85/93

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 931x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 1x 1x 8x 8x     8x 8x     8x 8x 8x 2x 2x 6x 6x 6x 8x 1x 8x 4x 5x     1x 1x 1x 1x 1x 5x 5x 1x 1x 4x 4x 5x 3x 5x   5x 1x 5x   5x 5x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 1x 1x 1x 1x
import * as LServer from "vscode-languageserver-types";
import {ITextDocumentPositionParams, IRenameParams} from "./_interfaces";
import {LSPUtils} from "./_lsp_utils";
import {IRegistry} from "../_iregistry";
import {ABAPObject} from "../objects/_abap_object";
import {LSPLookup} from "./_lookup";
import {TypedIdentifier} from "../abap/types/_typed_identifier";
import {ClassDefinition, InterfaceDefinition} from "../abap/types";
import {References} from "./references";
import {IFile} from "../files/_ifile";
import {Renamer} from "../objects/rename/renamer";
 
 
export enum RenameType {
  GlobalClass = 1,
  Variable = 2,
  GlobalInterface = 3,
}
 
export interface IPrepareResult {
  range: LServer.Range,
  placeholder: string,
  type: RenameType,
  file: IFile,
}
 
export class Rename {
  private readonly reg: IRegistry;
 
  public constructor(reg: IRegistry) {
    this.reg = reg;
  }
 
  public prepareRename(params: ITextDocumentPositionParams): IPrepareResult | undefined {
    const file = LSPUtils.getABAPFile(this.reg, params.textDocument.uri);
    if (file === undefined) {
      return undefined;
    }
    const obj = this.reg.getObject(file.getObjectType(), file.getObjectName());
    if (!(obj instanceof ABAPObject)) {
      return undefined;
    }
 
    const cursor = LSPUtils.findCursor(this.reg, params);
    if (cursor === undefined) {
      return undefined;
    }
 
    const range = LSPUtils.tokenToRange(cursor.token);
    const lookup = LSPLookup.lookup(cursor, this.reg, obj);
    if (lookup?.definitionId instanceof TypedIdentifier) {
      return {range, placeholder: cursor.token.getStr(), type: RenameType.Variable, file};
    } else if (lookup?.definitionId instanceof ClassDefinition) {
      return {range, placeholder: cursor.token.getStr(), type: RenameType.GlobalClass, file};
    } else if (lookup?.definitionId instanceof InterfaceDefinition) {
      return {range, placeholder: cursor.token.getStr(), type: RenameType.GlobalInterface, file};
    }
 
    return undefined;
  }
 
  public rename(params: IRenameParams): LServer.WorkspaceEdit | undefined {
    const prepare = this.prepareRename(params);
    if (prepare === undefined) {
      return undefined;
    }
 
    switch (prepare.type) {
      case RenameType.GlobalClass:
        return new Renamer(this.reg).buildEdits("CLAS", prepare.placeholder, params.newName);
      case RenameType.GlobalInterface:
        return new Renamer(this.reg).buildEdits("INTF", prepare.placeholder, params.newName);
      case RenameType.Variable:
        return this.renameVariable(params);
      default:
        return undefined;
    }
  }
 
////
 
  private renameVariable(params: IRenameParams): LServer.WorkspaceEdit | undefined {
    const workspace: LServer.WorkspaceEdit = {documentChanges: []};
    const refs = new References(this.reg).references(params);
    for (const r of refs) {
      const doc: LServer.VersionedTextDocumentIdentifier = {uri: r.uri, version: 1};
      const edit = LServer.TextDocumentEdit.create(doc, [LServer.TextEdit.replace(r.range, params.newName)]);
      workspace.documentChanges?.push(edit);
    }
    return workspace;
  }
 
}