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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x 3x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 1x 1x 1x 1x 1x 1x 1x 3x 3x 3x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x 3x 3x 3x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 12x 12x 12x 6x 3x 1x 1x 3x 6x 12x 12x 9x 9x 12x 12x 12x 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 {MessageClass} from "../objects"; import {ISpaghettiScopeNode} from "../abap/5_syntax/_spaghetti_scope"; import {IReference, ReferenceType} from "../abap/5_syntax/_reference"; import {MethodDefinition} from "../abap/types"; import {ABAPFile} from "../abap/abap_file"; export type CodeLensSettings = { messageText: boolean, dynamicExceptions: boolean, }; export class CodeLens { private readonly reg: IRegistry; public constructor(reg: IRegistry) { this.reg = reg; } public list(textDocument: LServer.TextDocumentIdentifier, settings: CodeLensSettings = {messageText: true, dynamicExceptions: true}): LServer.CodeLens[] { 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.CodeLens[] = []; if (settings.messageText === true) { const list = this.reg.getMSAGReferences().listByFilename(file.getFilename()); for (const l of list) { const msag = this.reg.getObject("MSAG", l.messageClass) as MessageClass | undefined; if (msag === undefined) { continue; } const text = msag.getByNumber(l.number)?.getMessage(); if (text === undefined) { continue; } ret.push({ range: LSPUtils.tokenToRange(l.token), command: LServer.Command.create(text, "")}); } } if (settings.dynamicExceptions === true) { for (const ref of this.findMethodReferences(top, file)) { if (!(ref.resolved instanceof MethodDefinition)) { continue; } let text = ""; for (const e of ref.resolved.getRaising()) { if (this.isDynamicException(e, top)) { if (text === "") { text = "Dynamic Exceptions: "; } else { text += " & "; } text += e.toUpperCase(); } } if (text !== "") { ret.push({ range: LSPUtils.tokenToRange(ref.position.getToken()), command: LServer.Command.create(text, "")}); } } } return ret; } private isDynamicException(name: string, top: ISpaghettiScopeNode) { // todo: this method only works with global exceptions? let current: string | undefined = name; while (current !== undefined) { if (current.toUpperCase() === "CX_DYNAMIC_CHECK") { return true; } current = top.findClassDefinition(current)?.getSuperClass(); } return false; } private findMethodReferences(node: ISpaghettiScopeNode, file: ABAPFile): IReference[] { const ret: IReference[] = []; if (node.getIdentifier().filename === file.getFilename()) { for (const r of node.getData().references) { if (r.referenceType === ReferenceType.MethodReference) { ret.push(r); } } } for (const c of node.getChildren()) { ret.push(...this.findMethodReferences(c, file)); } return ret; } } |