UNPKG

@abaplint/core

Version:
372 lines • 16.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LSPLookup = void 0; /* eslint-disable max-len */ const LServer = require("vscode-languageserver-types"); const Statements = require("../abap/2_statements/statements"); const Expressions = require("../abap/2_statements/expressions"); const syntax_1 = require("../abap/5_syntax/syntax"); const _lsp_utils_1 = require("./_lsp_utils"); const _typed_identifier_1 = require("../abap/types/_typed_identifier"); const _reference_1 = require("../abap/5_syntax/_reference"); const _builtin_1 = require("../abap/5_syntax/_builtin"); const _scope_type_1 = require("../abap/5_syntax/_scope_type"); const objects_1 = require("../objects"); const types_1 = require("../abap/types"); const _statement_1 = require("../abap/2_statements/statements/_statement"); const include_graph_1 = require("../utils/include_graph"); class LSPLookup { static lookup(cursor, reg, obj) { var _a, _b; const inc = this.findInclude(cursor, reg); if (inc) { const found = this.ABAPFileResult(inc); return { hover: "Include", definition: found, implementation: found }; } const fm = this.findFunctionModule(cursor); if (fm) { return { hover: "Function Module " + fm }; } let main = obj; if (obj instanceof objects_1.Program && obj.isInclude()) { // todo: this is slow const ig = new include_graph_1.IncludeGraph(reg); const mains = ig.listMainForInclude(cursor.identifier.getFilename()); if (mains.length === 1) { // yea, well, or it has to be a popup main = reg.findObjectForFile(reg.getFileByName(mains[0])) || obj; } } const bottomScope = new syntax_1.SyntaxLogic(reg, main).run().spaghetti.lookupPosition(cursor.identifier.getStart(), cursor.identifier.getFilename()); if (bottomScope === undefined) { return undefined; } const clas = bottomScope.findClassDefinition(cursor.token.getStr()); if (clas && clas.getStart().equals(cursor.token.getStart())) { const found = _lsp_utils_1.LSPUtils.identiferToLocation(clas); return { hover: "Class Definition, " + cursor.token.getStr(), definition: found, definitionId: clas, implementation: undefined, scope: bottomScope, }; } const intf = bottomScope.findInterfaceDefinition(cursor.token.getStr()); if (intf && intf.getStart().equals(cursor.token.getStart())) { const found = _lsp_utils_1.LSPUtils.identiferToLocation(intf); return { hover: "Interface Definition, " + cursor.token.getStr(), definition: found, definitionId: intf, implementation: undefined, scope: bottomScope, }; } const type = bottomScope.findType(cursor.token.getStr()); if (type !== undefined && type.getStart().equals(cursor.token.getStart())) { const found = _lsp_utils_1.LSPUtils.identiferToLocation(type); const hover = "Type Definition, " + cursor.token.getStr() + "\n\n" + this.dumpType(type); return { hover, definition: found, definitionId: type, scope: bottomScope }; } const method = this.findMethodDefinition(cursor, bottomScope.getParent()); if (method !== undefined && method.getStart().equals(cursor.token.getStart())) { const found = _lsp_utils_1.LSPUtils.identiferToLocation(method); const hover = "Method Definition \"" + method.getName() + "\""; return { hover, definition: found, definitionId: method, scope: bottomScope }; } let hoverValue = ""; const ddicRefs = reg.getDDICReferences().listByFilename(cursor.identifier.getFilename(), cursor.identifier.getStart().getRow()); for (const d of ddicRefs) { if (d.object && d.token && d.token.getStart().equals(cursor.identifier.getStart())) { hoverValue += `DDIC: ${d.object.getType()} ${d.object.getName()}`; } } const variable = bottomScope.findVariable(cursor.token.getStr()); if (variable !== undefined && variable.getStart().equals(cursor.token.getStart())) { const hover = "Variable Definition\n\n" + this.dumpType(variable); if (hoverValue !== "") { hoverValue = hover + "\n_________________\n" + hoverValue; } else { hoverValue = hover; } let location = undefined; if (variable.getMeta().includes("built-in" /* IdentifierMeta.BuiltIn */) === false) { location = _lsp_utils_1.LSPUtils.identiferToLocation(variable); } return { hover: hoverValue, definition: location, implementation: location, definitionId: variable, scope: bottomScope }; } // TODO: this can be optimized, no need to loop through all the defintions, the scope knows the name of the object? for (const c of [...bottomScope.listClassDefinitions(), ...bottomScope.listInterfaceDefinitions()]) { for (const m of ((_a = c.getMethodDefinitions()) === null || _a === void 0 ? void 0 : _a.getAll()) || []) { for (const p of ((_b = m.getParameters()) === null || _b === void 0 ? void 0 : _b.getAll()) || []) { if (p.getStart().equals(cursor.token.getStart())) { const found = _lsp_utils_1.LSPUtils.identiferToLocation(p); return { hover: "Method Parameter: " + cursor.token.getStr().replace("!", ""), definition: found, definitionId: p, implementation: undefined, scope: bottomScope, }; } } } } const refs = this.searchReferences(bottomScope, cursor.token); if (refs.length > 0) { for (const ref of refs) { if (hoverValue !== "") { hoverValue += "\n_________________\n"; } hoverValue += this.referenceHover(ref, bottomScope, reg); } let definition = undefined; let implementation = undefined; if (refs[0].resolved) { definition = _lsp_utils_1.LSPUtils.identiferToLocation(refs[0].resolved); if (definition.uri === _builtin_1.BuiltIn.filename) { definition = undefined; } if (refs[0].resolved instanceof types_1.FormDefinition) { implementation = definition; } } return { hover: hoverValue, definition: definition, implementation: implementation, definitionId: refs[0].resolved, scope: bottomScope, }; } if (cursor.snode.get() instanceof _statement_1.MacroCall) { const macroDefinition = reg.getMacroReferences().findDefinitionByUsage(cursor.identifier.getFilename(), cursor.snode.getFirstToken()); if (macroDefinition) { return { hover: "Macro Call", definition: { uri: macroDefinition === null || macroDefinition === void 0 ? void 0 : macroDefinition.filename, range: _lsp_utils_1.LSPUtils.tokenToRange(macroDefinition.token), }, }; } } if (hoverValue !== "") { return { hover: hoverValue, scope: bottomScope }; } return undefined; } //////////////////////////////////////////// static dumpType(variable) { let value = variable.toText() + "\n\nType: " + variable.getType().toText(0); if (variable.getValue()) { value += "\n\nValue: ```" + variable.getValue() + "```"; } if (variable.getMeta().length > 0) { value += "\n\nMeta: " + variable.getMeta().join(", "); } if (variable.getType().containsVoid() === true) { value += "\n\nContains Void types"; } if (variable.getType().getQualifiedName()) { value += "\n\nQualified Type Name: ```" + variable.getType().getQualifiedName() + "```"; } if (variable.getType().getRTTIName()) { value += "\n\nRTTI Name: ```" + variable.getType().getRTTIName() + "```"; } if (variable.getType().isGeneric() === true) { value += "\n\nIs Generic Type"; } if (variable.getType().getConversionExit() !== undefined) { value += "\n\nConversion Exit: ```" + variable.getType().getConversionExit() + "```"; } if (variable.getType().getDDICName() !== undefined) { value += "\n\nDDIC Name: ```" + variable.getType().getDDICName() + "```"; } if (variable.getType().getDescription() !== undefined) { value += "\n\nDescription: " + variable.getType().getDescription(); } return value; } static referenceHover(ref, scope, reg) { var _a, _b, _c, _d, _e; let name = ""; if (ref.resolved) { name = "```" + ref.resolved.getName() + "```"; } let ret = `${ref.referenceType} ${name}`; if (ref.referenceType === _reference_1.ReferenceType.MethodReference && ((_a = ref.extra) === null || _a === void 0 ? void 0 : _a.ooName)) { let cdef = scope.findClassDefinition(ref.extra.ooName); if (cdef === undefined) { cdef = scope.findInterfaceDefinition(ref.extra.ooName); } if (cdef === undefined) { cdef = (_b = reg.getObject("CLAS", ref.extra.ooName)) === null || _b === void 0 ? void 0 : _b.getDefinition(); } if (cdef === undefined) { cdef = (_c = reg.getObject("INTF", ref.extra.ooName)) === null || _c === void 0 ? void 0 : _c.getDefinition(); } ret += "\n\n" + this.hoverMethod(ref.position.getName(), cdef); } else if (ref.resolved instanceof _typed_identifier_1.TypedIdentifier) { ret += "\n\n" + this.dumpType(ref.resolved); } else if (ref.referenceType === _reference_1.ReferenceType.BuiltinMethodReference) { const builtinDef = _builtin_1.BuiltIn.searchBuiltin((_e = (_d = ref.resolved) === null || _d === void 0 ? void 0 : _d.getName()) === null || _e === void 0 ? void 0 : _e.toUpperCase()); if (builtinDef === undefined) { return "Error: builtin method signature not found"; } ret += "\n\n" + this.methodParameters(builtinDef); } if (ref.resolved) { ret += "\n\n(Resolved)"; } if (ref.extra !== undefined && Object.keys(ref.extra).length > 0) { ret += "\n\nExtra: " + JSON.stringify(ref.extra); } return ret; } static hoverMethod(method, classDef) { if (classDef === undefined) { return "class not found"; } const methodDef = classDef.getMethodDefinitions().getByName(method); if (methodDef === undefined) { return "method not found in definition"; } return this.methodParameters(methodDef); } static methodParameters(methodDef) { let ret = ""; const parameters = methodDef.getParameters(); const importing = parameters.getImporting(); if (importing.length > 0) { ret += "IMPORTING\n"; for (const p of importing) { ret += this.singleParameter(p); } } const exporting = parameters.getExporting(); if (exporting.length > 0) { ret += "EXPORTING\n"; for (const p of exporting) { ret += this.singleParameter(p); } } const changing = parameters.getChanging(); if (changing.length > 0) { ret += "CHANGING\n"; for (const p of changing) { ret += this.singleParameter(p); } } const r = parameters.getReturning(); if (r) { ret += "RETURNING\n" + this.singleParameter(r); } if (methodDef.getRaising().length > 0) { ret += "RAISING\n"; for (const p of methodDef.getRaising()) { ret += "* " + p + "\n"; } } return ret; } static singleParameter(p) { let extra = p.getMeta().join(", "); if (extra !== "") { extra = "(Meta: " + extra + ")"; } return "* " + p.getName() + extra + " TYPE " + p.getType().toText(1) + "\n\n"; } static searchReferences(scope, token) { const ret = []; for (const r of scope.getData().references) { if (r.position.getStart().equals(token.getStart())) { ret.push(r); } } const parent = scope.getParent(); if (parent) { ret.push(...this.searchReferences(parent, token)); } return ret; } static ABAPFileResult(abap) { return { uri: abap.getFilename(), range: LServer.Range.create(0, 0, 0, 0), }; } static findMethodDefinition(found, scope) { var _a, _b, _c, _d, _e, _f, _g; if (scope === undefined) { return undefined; } if ((scope.getIdentifier().stype !== _scope_type_1.ScopeType.ClassDefinition && scope.getIdentifier().stype !== _scope_type_1.ScopeType.Interface) || !(found.snode.get() instanceof Statements.MethodDef)) { return undefined; } const nameToken = (_a = found.snode.findFirstExpression(Expressions.MethodName)) === null || _a === void 0 ? void 0 : _a.getFirstToken(); if (nameToken === undefined) { return undefined; } if (found.snode.findFirstExpression(Expressions.Redefinition)) { return undefined; } // check the cursor is at the right token if (nameToken.getStart().getCol() !== found.token.getStart().getCol() || nameToken.getStart().getRow() !== found.token.getStart().getRow()) { return undefined; } if (scope.getIdentifier().stype === _scope_type_1.ScopeType.ClassDefinition) { const def = (_d = (_c = (_b = scope.getParent()) === null || _b === void 0 ? void 0 : _b.findClassDefinition(scope.getIdentifier().sname)) === null || _c === void 0 ? void 0 : _c.getMethodDefinitions()) === null || _d === void 0 ? void 0 : _d.getByName(nameToken.getStr()); return def; } else { const def = (_g = (_f = (_e = scope.getParent()) === null || _e === void 0 ? void 0 : _e.findInterfaceDefinition(scope.getIdentifier().sname)) === null || _f === void 0 ? void 0 : _f.getMethodDefinitions()) === null || _g === void 0 ? void 0 : _g.getByName(nameToken.getStr()); return def; } } static findFunctionModule(found) { if (!(found.snode.get() instanceof Statements.CallFunction)) { return undefined; } const name = found.snode.findFirstExpression(Expressions.FunctionName); if (name === undefined) { return undefined; } // check the cursor is at the right token const token = name.getFirstToken(); if (token.getStart().getCol() !== found.token.getStart().getCol() || token.getStart().getRow() !== found.token.getStart().getRow()) { return undefined; } return token.getStr(); } static findInclude(found, reg) { if (!(found.snode.get() instanceof Statements.Include)) { return; } const name = found.snode.findFirstExpression(Expressions.IncludeName); if (name === undefined) { return undefined; } // check the cursor is at the right token const token = name.getFirstToken(); if (token.getStart().getCol() !== found.token.getStart().getCol() || token.getStart().getRow() !== found.token.getStart().getRow()) { return undefined; } const obj = reg.getObject("PROG", token.getStr()); if (obj) { return obj.getABAPFiles()[0]; } return undefined; } } exports.LSPLookup = LSPLookup; //# sourceMappingURL=_lookup.js.map