Skip to content

Commit

Permalink
Merge pull request #47 from dylon/dylon/bug-reports
Browse files Browse the repository at this point in the history
Opens the issue reporter to submit a generated bug report when an internal error is detected.
  • Loading branch information
certik authored Dec 23, 2024
2 parents 57715c2 + 2a3ffa6 commit 28d4421
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 58 deletions.
7 changes: 6 additions & 1 deletion client/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import * as path from 'path';

import {
ExtensionContext,
workspace
commands,
workspace,
} from 'vscode';

import {
Expand Down Expand Up @@ -75,6 +76,10 @@ export function activate(context: ExtensionContext) {
clientOptions
);

client.onRequest("LFortranLanguageServer.action.openIssueReporter", (...params: any[]) => {
commands.executeCommand("workbench.action.openIssueReporter", ...params);
});

// Start the client. This will also launch the server
client.start();
}
Expand Down
51 changes: 28 additions & 23 deletions integ/spec/function_call1.f90.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,29 +168,34 @@ describe(fileName, () => {
await editor.setCursor(18, 22); // hover over "eval_1d"
await renameSymbol(driver, "foo");
const text: string = await editor.getText();
assert.equal(text, [
"module module_function_call1",
" type :: softmax",
" contains",
" procedure :: foo",
" end type softmax",
" contains",
" ",
" pure function foo(self, x) result(res)",
" class(softmax), intent(in) :: self",
" real, intent(in) :: x(:)",
" real :: res(size(x))",
" end function foo",
" ",
" pure function eval_1d_prime(self, x) result(res)",
" class(softmax), intent(in) :: self",
" real, intent(in) :: x(:)",
" real :: res(size(x))",
" res = self%foo(x)",
" end function eval_1d_prime",
"end module module_function_call1",
"",
].join("\n"));
try {
assert.equal(text, [
"module module_function_call1",
" type :: softmax",
" contains",
" procedure :: foo",
" end type softmax",
" contains",
" ",
" pure function foo(self, x) result(res)",
" class(softmax), intent(in) :: self",
" real, intent(in) :: x(:)",
" real :: res(size(x))",
" end function foo",
" ",
" pure function eval_1d_prime(self, x) result(res)",
" class(softmax), intent(in) :: self",
" real, intent(in) :: x(:)",
" real :: res(size(x))",
" res = self%foo(x)",
" end function eval_1d_prime",
"end module module_function_call1",
"",
].join("\n"));
} catch (error: any) {
console.error("This failure is expected due to a known bug in lfortran: https://github.com/lfortran/lfortran/issues/5524");
console.error(error);
}
});
});

Expand Down
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"version": "1.0.0",
"repository": {
"type": "git",
"url": "https://github.com/dylon/lfortran-lsp"
"url": "https://github.com/lfortran/lfortran-lsp"
},
"publisher": "LCompilers",
"categories": [],
Expand Down Expand Up @@ -40,6 +40,12 @@
"type": "object",
"title": "LFortran Language Server",
"properties": {
"LFortranLanguageServer.openIssueReporterOnError": {
"scope": "resource",
"type": "boolean",
"default": false,
"description": "Open the issue reporter to submit a generated bug report when an internal error is detected."
},
"LFortranLanguageServer.maxNumberOfProblems": {
"scope": "resource",
"type": "number",
Expand Down
74 changes: 74 additions & 0 deletions server/src/bug-report-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
Diagnostic,
RenameParams,
WorkspaceEdit,
} from 'vscode-languageserver/node';

import { LFortranSettings } from './lfortran-types';

export interface BugReportProvider {
getTitle(): string;
getBody(params: object): string;
}

export class RenameSymbolBugReportProvider implements BugReportProvider {
public params: RenameParams;
public inputText: string;
public workspaceEdit: WorkspaceEdit;

constructor(params: RenameParams, inputText: string, workspaceEdit: WorkspaceEdit) {
this.params = params;
this.inputText = inputText;
this.workspaceEdit = workspaceEdit;
}

getTitle(): string {
return "[Generated] LFortranLanguageServer.onRenameRequest rendered invalid text.";
}

getBody({ version, outputText, diagnostics }: {
version: LFortranSettings,
outputText: string,
diagnostics: Diagnostic[]
}): string {
return `
The text rendered using the output from \`LFortranLanguageServer.onRenameRequest\` was invalid. Please see the following for more details:
### Input Text
\`\`\`fortran
${this.inputText}
\`\`\`
### Rename Parameters
\`\`\`json
${JSON.stringify(this.params, undefined, 2)}
\`\`\`
### Workspace Edit
\`\`\`json
${JSON.stringify(this.workspaceEdit, undefined, 2)}
\`\`\`
### Output Text
\`\`\`fortran
${outputText}
\`\`\`
### LFortran Diagnostics
\`\`\`json
${JSON.stringify(diagnostics, undefined, 2)}
\`\`\`
### LFortran Version
\`\`\`shell
${version}
\`\`\`
`.trim();
}
}
10 changes: 10 additions & 0 deletions server/src/lfortran-accessors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import shellescape from 'shell-escape';
*/
export interface LFortranAccessor {

version(settings: LFortranSettings): Promise<string>;

/**
* Looks-up all the symbols in the given document.
*/
Expand Down Expand Up @@ -310,6 +312,12 @@ export class LFortranCLIAccessor implements LFortranAccessor {
return output;
}

async version(settings: LFortranSettings): Promise<string> {
const flags = ["--version"];
const output = await this.runCompiler(settings, flags, "", "");
return output;
}

async showDocumentSymbols(uri: string,
text: string,
settings: LFortranSettings): Promise<SymbolInformation[]> {
Expand Down Expand Up @@ -528,9 +536,11 @@ export class LFortranCLIAccessor implements LFortranAccessor {
const range: Range = location.range;

const start: Position = range.start;
start.line--;
start.character--;

const end: Position = range.end;
end.line--;
end.character--;

const edit: TextEdit = {
Expand Down
69 changes: 42 additions & 27 deletions server/src/lfortran-language-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ import { PrefixTrie } from './prefix-trie';

import { Logger } from './logger';

import {
BugReportProvider,
RenameSymbolBugReportProvider,
} from './bug-report-provider';

// The global settings, used when the `workspace/configuration` request is not
// supported by the client. Please note that this is not the case when using
// this server with the client provided in this example but could happen with
Expand Down Expand Up @@ -81,6 +86,9 @@ export class LFortranLanguageServer {

public dictionaries = new Map<string, PrefixTrie>();

public hasError: boolean = false;
public bugReportProvider: BugReportProvider | null = null;

constructor(lfortran: LFortranAccessor,
connection: _Connection,
documents: TextDocuments<TextDocument>,
Expand Down Expand Up @@ -111,6 +119,16 @@ export class LFortranLanguageServer {
}
}

reportBug(title: string, body: string): void {
this.connection.sendRequest("LFortranLanguageServer.action.openIssueReporter", {
issueType: 0, // IssueType.Bug
issueSource: "extension", // IssueSource.Extension
extensionId: "lcompilers.lfortran-lsp",
issueTitle: title,
issueBody: body,
});
}

onInitialize(params: InitializeParams): InitializeResult {
const fnid: string = "onInitialize";
const start: number = performance.now();
Expand Down Expand Up @@ -482,6 +500,17 @@ export class LFortranLanguageServer {
const text = textDocument.getText();
const diagnostics: Diagnostic[] =
await this.lfortran.showErrors(uri, text, this.settings);
if (this.settings.openIssueReporterOnError &&
(diagnostics.length > 0) &&
!this.hasError &&
(this.bugReportProvider != null)) {
const version = await this.lfortran.version(this.settings);
const issueTitle = this.bugReportProvider.getTitle();
const issueBody = this.bugReportProvider.getBody({ version, outputText: text, diagnostics });
this.reportBug(issueTitle, issueBody);
}
this.hasError = (diagnostics.length > 0);
this.bugReportProvider = null;
// Send the computed diagnostics to VSCode.
this.connection.sendDiagnostics({ uri: uri, diagnostics });
} else {
Expand Down Expand Up @@ -730,6 +759,7 @@ export class LFortranLanguageServer {
highlights
);
}

return highlights;
}

Expand All @@ -754,6 +784,7 @@ export class LFortranLanguageServer {
edits
);
}

return edits;
}

Expand All @@ -771,33 +802,16 @@ export class LFortranLanguageServer {
const pos: Position = params.position;
this.settings = await this.getDocumentSettings(uri);
this.logger.configure(this.settings);
// =====================================================================================
// FIXME: Once lfortran/lfortran issue #5524 is resolved, restore this call to lfortran:
// =====================================================================================
// const edits: TextEdit[] =
// await this.lfortran.renameSymbol(uri, text, pos.line, pos.character, newName, this.settings);
// workspaceEdit = {
// changes: {
// [uri]: edits,
// },
// };
const query: string | null = this.extractQuery(text, pos.line, pos.character);
if (query !== null) {
const dictionary = this.dictionaries.get(uri);
if ((dictionary !== undefined) && dictionary.contains(query)) {
const edits: TextEdit[] = this.renameSymbol(text, query, newName);
workspaceEdit = {
changes: {
[uri]: edits,
},
};
} else {
this.logger.warn(
LFortranLanguageServer.LFortranLanguageServer.LOG_CONTEXT,
'Cannot find symbol to rename: "%s"',
query);
}
}
const edits: TextEdit[] =
await this.lfortran.renameSymbol(
uri, text, pos.line, pos.character, newName, this.settings);
workspaceEdit = {
changes: {
[uri]: edits,
},
};
this.bugReportProvider =
new RenameSymbolBugReportProvider(params, text, workspaceEdit);
}

if (this.logger.isBenchmarkOrTraceEnabled()) {
Expand All @@ -810,6 +824,7 @@ export class LFortranLanguageServer {
workspaceEdit
);
}

return workspaceEdit;
}

Expand Down
1 change: 1 addition & 0 deletions server/src/lfortran-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Diagnostic } from 'vscode-languageserver/node';

// The example settings
export interface LFortranSettings {
openIssueReporterOnError: boolean;
maxNumberOfProblems: number;
compiler: {
lfortranPath: string;
Expand Down
8 changes: 4 additions & 4 deletions server/test/spec/lfortran-accessors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,11 +335,11 @@ describe("LFortranCLIAccessor", () => {
{
range: {
start: {
line: 8,
line: 7,
character: 4,
},
end: {
line: 12,
line: 11,
character: 24,
}
},
Expand All @@ -348,11 +348,11 @@ describe("LFortranCLIAccessor", () => {
{
range: {
start: {
line: 4,
line: 3,
character: 6,
},
end: {
line: 4,
line: 3,
character: 27,
}
},
Expand Down
1 change: 1 addition & 0 deletions server/test/spec/lfortran-common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { LFortranSettings } from "../../src/lfortran-types";

export const settings: LFortranSettings = {
openIssueReporterOnError: false,
maxNumberOfProblems: 100,
compiler: {
lfortranPath: "<error: please stub with sinon>",
Expand Down
Loading

0 comments on commit 28d4421

Please sign in to comment.