-
Notifications
You must be signed in to change notification settings - Fork 752
/
goLint.ts
160 lines (144 loc) · 5.08 KB
/
goLint.ts
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------*/
import path = require('path');
import vscode = require('vscode');
import { CommandFactory } from './commands';
import { getGoConfig, getGoplsConfig } from './config';
import { toolExecutionEnvironment } from './goEnv';
import { diagnosticsStatusBarItem, outputChannel } from './goStatus';
import { goplsStaticcheckEnabled } from './goTools';
import { getWorkspaceFolderPath, handleDiagnosticErrors, ICheckResult, resolvePath, runTool } from './util';
/**
* Runs linter on the current file, package or workspace.
*/
export function lintCode(scope?: string): CommandFactory {
return (ctx, goCtx) => () => {
const editor = vscode.window.activeTextEditor;
if (scope !== 'workspace') {
if (!editor) {
vscode.window.showInformationMessage('No editor is active, cannot find current package to lint');
return;
}
if (editor.document.languageId !== 'go') {
vscode.window.showInformationMessage(
'File in the active editor is not a Go file, cannot find current package to lint'
);
return;
}
}
const documentUri = editor ? editor.document.uri : undefined;
const goConfig = getGoConfig(documentUri);
const goplsConfig = getGoplsConfig(documentUri);
outputChannel.clear(); // Ensures stale output from lint on save is cleared
diagnosticsStatusBarItem.show();
diagnosticsStatusBarItem.text = 'Linting...';
goLint(documentUri, goConfig, goplsConfig, scope)
.then((warnings) => {
handleDiagnosticErrors(
goCtx,
editor ? editor.document : undefined,
warnings,
goCtx.lintDiagnosticCollection
);
diagnosticsStatusBarItem.hide();
})
.catch((err) => {
vscode.window.showInformationMessage('Error: ' + err);
diagnosticsStatusBarItem.text = 'Linting Failed';
});
};
}
/**
* Runs linter and presents the output in the 'Go' channel and in the diagnostic collections.
*
* @param fileUri Document uri.
* @param goConfig Configuration for the Go extension.
* @param scope Scope in which to run the linter.
*/
export function goLint(
fileUri: vscode.Uri | undefined,
goConfig: vscode.WorkspaceConfiguration,
goplsConfig: vscode.WorkspaceConfiguration,
scope?: string
): Promise<ICheckResult[]> {
const lintTool = goConfig['lintTool'] || 'staticcheck';
if (lintTool === 'staticcheck' && goplsStaticcheckEnabled(goConfig, goplsConfig)) {
return Promise.resolve([]);
}
epoch++;
const closureEpoch = epoch;
if (tokenSource) {
if (running) {
tokenSource.cancel();
}
tokenSource.dispose();
}
tokenSource = new vscode.CancellationTokenSource();
const currentWorkspace = getWorkspaceFolderPath(fileUri);
const cwd = scope === 'workspace' && currentWorkspace ? currentWorkspace : path.dirname(fileUri?.fsPath ?? '');
if (!path.isAbsolute(cwd)) {
return Promise.resolve([]);
}
const lintFlags: string[] = goConfig['lintFlags'] || [];
const lintEnv = toolExecutionEnvironment();
const args: string[] = [];
lintFlags.forEach((flag) => {
// --json is not a valid flag for golint and in gometalinter, it is used to print output in json which we dont want
if (flag === '--json') {
return;
}
if (flag.startsWith('--config=') || flag.startsWith('-config=')) {
let configFilePath = flag.substr(flag.indexOf('=') + 1).trim();
if (!configFilePath) {
return;
}
configFilePath = resolvePath(configFilePath);
args.push(`${flag.substr(0, flag.indexOf('=') + 1)}${configFilePath}`);
return;
}
args.push(flag);
});
if (lintTool === 'golangci-lint') {
if (args.indexOf('run') === -1) {
args.unshift('run');
}
if (args.indexOf('--print-issued-lines=false') === -1) {
// print only file:number:column
args.push('--print-issued-lines=false');
}
if (args.indexOf('--out-format=colored-line-number') === -1) {
// print file:number:column.
// Explicit override in case .golangci.yml calls for a format we don't understand
args.push('--out-format=colored-line-number');
}
if (args.indexOf('--issues-exit-code=') === -1) {
// adds an explicit no-error-code return argument, to avoid npm error
// message detection logic. See golang/vscode-go/issues/411
args.push('--issues-exit-code=0');
}
}
if (scope === 'workspace' && currentWorkspace) {
args.push('./...');
outputChannel.appendLine(`Starting linting the current workspace at ${currentWorkspace}`);
} else if (scope === 'file') {
args.push(fileUri?.fsPath ?? '');
outputChannel.appendLine(`Starting linting the current file at ${fileUri?.fsPath}`);
} else {
outputChannel.appendLine(`Starting linting the current package at ${cwd}`);
}
running = true;
const lintPromise = runTool(args, cwd, 'warning', false, lintTool, lintEnv, false, tokenSource.token).then(
(result) => {
if (closureEpoch === epoch) {
running = false;
}
return result;
}
);
return lintPromise;
}
let epoch = 0;
let tokenSource: vscode.CancellationTokenSource;
let running = false;