Skip to content

Commit 39cacc1

Browse files
authored
Support Gradle invalid type code error check (#2442)
* support gradle invalid type code error check Signed-off-by: Shi Chen <chenshi@microsoft.com>
1 parent 34d7bcf commit 39cacc1

File tree

4 files changed

+119
-29
lines changed

4 files changed

+119
-29
lines changed

src/commands.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,5 +257,7 @@ export namespace Commands {
257257

258258
export const RESOLVE_WORKSPACE_SYMBOL = 'java.project.resolveWorkspaceSymbol';
259259

260-
export const GET_WORKSPACE_PATH = '_java.workspace.path';
260+
export const GET_WORKSPACE_PATH = '_java.workspace.path';
261+
262+
export const UPGRADE_GRADLE_WRAPPER = '_java.gradle.upgradeWrapper';
261263
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use strict';
2+
3+
import * as fse from "fs-extra";
4+
import * as path from "path";
5+
import { CancellationToken, CodeAction, CodeActionContext, CodeActionKind, CodeActionProvider, CodeActionProviderMetadata, Command, commands, Diagnostic, DiagnosticRelatedInformation, ExtensionContext, ProviderResult, Range, Selection, TextDocument, Uri } from "vscode";
6+
import { Commands } from "../commands";
7+
import { upgradeGradle } from "../standardLanguageClient";
8+
9+
export class GradleCodeActionProvider implements CodeActionProvider<CodeAction> {
10+
11+
private static UPGRADE_GRADLE_WRAPPER_TITLE = "Upgrade Gradle Wrapper";
12+
private static WRAPPER_PROPERTIES_DESCRIPTOR = "gradle/wrapper/gradle-wrapper.properties";
13+
private static GRADLE_PROBLEM_ID = 0x00080000;
14+
private static GRADLE_INVALID_TYPE_CODE_ID = GradleCodeActionProvider.GRADLE_PROBLEM_ID + 1;
15+
16+
constructor(context: ExtensionContext) {
17+
context.subscriptions.push(commands.registerCommand(Commands.UPGRADE_GRADLE_WRAPPER, (projectUri: string) => {
18+
upgradeGradle(projectUri);
19+
}));
20+
}
21+
22+
public provideCodeActions(document: TextDocument, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult<(CodeAction | Command)[]> {
23+
if (context?.diagnostics?.length && context.diagnostics[0].source === "Java") {
24+
return this.provideGradleCodeActions(document, context.diagnostics);
25+
}
26+
return [];
27+
}
28+
29+
private async provideGradleCodeActions(document: TextDocument, diagnostics: readonly Diagnostic[]): Promise<CodeAction[]> {
30+
const codeActions = [];
31+
for (const diagnostic of diagnostics) {
32+
const documentUri = document.uri.toString();
33+
if (documentUri.endsWith(GradleCodeActionProvider.WRAPPER_PROPERTIES_DESCRIPTOR) && diagnostic.code === GradleCodeActionProvider.GRADLE_INVALID_TYPE_CODE_ID.toString()) {
34+
const projectPath = path.resolve(Uri.parse(documentUri).fsPath, "..", "..", "..").normalize();
35+
if (await fse.pathExists(projectPath)) {
36+
const projectUri = Uri.file(projectPath).toString();
37+
const upgradeWrapperCommand: Command = {
38+
title: GradleCodeActionProvider.UPGRADE_GRADLE_WRAPPER_TITLE,
39+
command: Commands.UPGRADE_GRADLE_WRAPPER,
40+
arguments: [projectUri]
41+
};
42+
const codeAction = new CodeAction(GradleCodeActionProvider.UPGRADE_GRADLE_WRAPPER_TITLE, CodeActionKind.QuickFix.append("gradle"));
43+
codeAction.command = upgradeWrapperCommand;
44+
codeActions.push(codeAction);
45+
}
46+
}
47+
}
48+
return codeActions;
49+
}
50+
}
51+
52+
export const gradleCodeActionMetadata: CodeActionProviderMetadata = {
53+
providedCodeActionKinds: [
54+
CodeActionKind.QuickFix.append("gradle")
55+
]
56+
};

src/protocol.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export enum EventType {
5959
ClasspathUpdated = 100,
6060
ProjectsImported = 200,
6161
IncompatibleGradleJdkIssue = 300,
62+
UpgradeGradleWrapper = 400,
6263
}
6364

6465
export enum CompileWorkspaceStatus {
@@ -425,3 +426,9 @@ export interface GradleCompatibilityInfo {
425426
highestJavaVersion: string;
426427
recommendedGradleVersion: string;
427428
}
429+
430+
export interface UpgradeGradleWrapperInfo {
431+
projectUri: string;
432+
message: string;
433+
recommendedGradleVersion: string;
434+
}

src/standardLanguageClient.ts

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { prepareExecutable, awaitServerConnection } from "./javaServerStarter";
77
import { getJavaConfig, applyWorkspaceEdit } from "./extension";
88
import { LanguageClientOptions, Position as LSPosition, Location as LSLocation, MessageType, TextDocumentPositionParams, ConfigurationRequest, ConfigurationParams } from "vscode-languageclient";
99
import { LanguageClient, StreamInfo } from "vscode-languageclient/node";
10-
import { CompileWorkspaceRequest, CompileWorkspaceStatus, SourceAttachmentRequest, SourceAttachmentResult, SourceAttachmentAttribute, ProjectConfigurationUpdateRequest, FeatureStatus, StatusNotification, ProgressReportNotification, ActionableNotification, ExecuteClientCommandRequest, ServerNotification, EventNotification, EventType, LinkLocation, FindLinks, GradleCompatibilityInfo } from "./protocol";
10+
import { CompileWorkspaceRequest, CompileWorkspaceStatus, SourceAttachmentRequest, SourceAttachmentResult, SourceAttachmentAttribute, ProjectConfigurationUpdateRequest, FeatureStatus, StatusNotification, ProgressReportNotification, ActionableNotification, ExecuteClientCommandRequest, ServerNotification, EventNotification, EventType, LinkLocation, FindLinks, GradleCompatibilityInfo, UpgradeGradleWrapperInfo } from "./protocol";
1111
import { setGradleWrapperChecksum, excludeProjectSettingsFiles, ServerMode } from "./settings";
1212
import { onExtensionChange, collectBuildFilePattern } from "./plugin";
1313
import { activationProgressNotification, serverTaskPresenter } from "./serverTaskPresenter";
@@ -35,6 +35,7 @@ import { pomCodeActionMetadata, PomCodeActionProvider } from "./pom/pomCodeActio
3535
import { findRuntimes, IJavaRuntime } from "jdk-utils";
3636
import { snippetCompletionProvider } from "./snippetCompletionProvider";
3737
import { JavaInlayHintsProvider } from "./inlayHintsProvider";
38+
import { gradleCodeActionMetadata, GradleCodeActionProvider } from "./gradle/gradleCodeActionProvider";
3839

3940
const extensionName = 'Language Support for Java';
4041
const GRADLE_CHECKSUM = "gradle/checksum/prompt";
@@ -184,7 +185,22 @@ export class StandardLanguageClient {
184185
} else {
185186
options.push(USE_JAVA + runtimes[0].version.major + AS_GRADLE_JVM);
186187
}
187-
this.showGradleCompatibilityIssueNotification(info.message, options, info.projectUri, runtimes[0]?.homedir);
188+
this.showGradleCompatibilityIssueNotification(info.message, options, info.projectUri, info.recommendedGradleVersion, runtimes[0]?.homedir);
189+
break;
190+
case EventType.UpgradeGradleWrapper:
191+
const neverShow: boolean | undefined = context.globalState.get<boolean>("java.neverShowUpgradeWrapperNotification");
192+
if (!neverShow) {
193+
const upgradeInfo = notification.data as UpgradeGradleWrapperInfo;
194+
const option = `Upgrade to ${upgradeInfo.recommendedGradleVersion}`;
195+
window.showWarningMessage(upgradeInfo.message, option, "Don't show again").then(async (choice) => {
196+
if (choice === option) {
197+
await upgradeGradle(upgradeInfo.projectUri, upgradeInfo.recommendedGradleVersion);
198+
} else if (choice === "Don't show again") {
199+
context.globalState.update("java.neverShowUpgradeWrapperNotification", true);
200+
}
201+
});
202+
}
203+
break;
188204
default:
189205
break;
190206
}
@@ -258,7 +274,7 @@ export class StandardLanguageClient {
258274
this.status = ClientStatus.Initialized;
259275
}
260276

261-
private showGradleCompatibilityIssueNotification(message: string, options: string[], projectUri: string, newJavaHome: string) {
277+
private showGradleCompatibilityIssueNotification(message: string, options: string[], projectUri: string, gradleVersion: string, newJavaHome: string) {
262278
window.showErrorMessage(message + " [Learn More](https://docs.gradle.org/current/userguide/compatibility.html)", ...options).then(async (choice) => {
263279
if (choice === GET_JDK) {
264280
commands.executeCommand(Commands.OPEN_BROWSER, Uri.parse(getJdkUrl()));
@@ -267,31 +283,7 @@ export class StandardLanguageClient {
267283
commands.executeCommand("workbench.action.openSettings", GRADLE_IMPORT_JVM);
268284
commands.executeCommand(Commands.IMPORT_PROJECTS_CMD);
269285
} else if (choice.startsWith(UPGRADE_GRADLE)) {
270-
const useWrapper = workspace.getConfiguration().get<boolean>("java.import.gradle.wrapper.enabled");
271-
if (!useWrapper) {
272-
await workspace.getConfiguration().update("java.import.gradle.wrapper.enabled", true, ConfigurationTarget.Workspace);
273-
}
274-
const result = await window.withProgress({
275-
location: ProgressLocation.Notification,
276-
title: "Upgrading Gradle wrapper...",
277-
cancellable: true,
278-
}, (_progress, token) => {
279-
return commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, "java.project.upgradeGradle", projectUri, token);
280-
});
281-
if (result) {
282-
const propertiesFile = path.join(Uri.parse(projectUri).fsPath, "gradle", "wrapper", "gradle-wrapper.properties");
283-
if (fse.pathExists(propertiesFile)) {
284-
const content = await fse.readFile(propertiesFile);
285-
const offset = content.toString().indexOf("distributionUrl");
286-
if (offset >= 0) {
287-
const document = await workspace.openTextDocument(propertiesFile);
288-
const position = document.positionAt(offset);
289-
const distributionUrlRange = document.getWordRangeAtPosition(position);
290-
window.showTextDocument(document, {selection: new Range(distributionUrlRange.start, new Position(distributionUrlRange.start.line + 1, 0))});
291-
}
292-
}
293-
commands.executeCommand(Commands.IMPORT_PROJECTS_CMD);
294-
}
286+
await upgradeGradle(projectUri, gradleVersion);
295287
}
296288
});
297289
}
@@ -504,6 +496,11 @@ export class StandardLanguageClient {
504496
pattern: "**/pom.xml"
505497
}, new PomCodeActionProvider(context), pomCodeActionMetadata);
506498

499+
languages.registerCodeActionsProvider({
500+
scheme: "file",
501+
pattern: "**/gradle/wrapper/gradle-wrapper.properties"
502+
}, new GradleCodeActionProvider(context), gradleCodeActionMetadata);
503+
507504
if (languages.registerInlayHintsProvider) {
508505
context.subscriptions.push(languages.registerInlayHintsProvider([
509506
{ scheme: "file", language: "java", pattern: "**/*.java" },
@@ -634,3 +631,31 @@ export function showNoLocationFound(message: string): void {
634631
message
635632
);
636633
}
634+
635+
export async function upgradeGradle(projectUri: string, version?: string): Promise<void> {
636+
const useWrapper = workspace.getConfiguration().get<boolean>("java.import.gradle.wrapper.enabled");
637+
if (!useWrapper) {
638+
await workspace.getConfiguration().update("java.import.gradle.wrapper.enabled", true, ConfigurationTarget.Workspace);
639+
}
640+
const result = await window.withProgress({
641+
location: ProgressLocation.Notification,
642+
title: "Upgrading Gradle wrapper...",
643+
cancellable: true,
644+
}, (_progress, token) => {
645+
return commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, "java.project.upgradeGradle", projectUri, version, token);
646+
});
647+
if (result) {
648+
const propertiesFile = path.join(Uri.parse(projectUri).fsPath, "gradle", "wrapper", "gradle-wrapper.properties");
649+
if (fse.pathExists(propertiesFile)) {
650+
const content = await fse.readFile(propertiesFile);
651+
const offset = content.toString().indexOf("distributionUrl");
652+
if (offset >= 0) {
653+
const document = await workspace.openTextDocument(propertiesFile);
654+
const position = document.positionAt(offset);
655+
const distributionUrlRange = document.getWordRangeAtPosition(position);
656+
window.showTextDocument(document, {selection: new Range(distributionUrlRange.start, new Position(distributionUrlRange.start.line + 1, 0))});
657+
}
658+
}
659+
commands.executeCommand(Commands.IMPORT_PROJECTS_CMD);
660+
}
661+
}

0 commit comments

Comments
 (0)