@abaplint/core
Version:
abaplint - Core API
372 lines • 16.9 kB
JavaScript
"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