All files / src/lsp rename.ts

91.39% Statements 85/93
75% Branches 21/28
100% Functions 4/4
91.39% 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 9x 9x 1x 1x 10x 10x     10x 10x     10x 10x 10x 2x 2x 8x 8x 8x 10x 2x 10x 4x 6x     2x 2x 2x 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;
  }
 
}