Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support quickfix for gradle jpms projects #2304

Merged
merged 3 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.buildship.core.internal.util.gradle.GradleVersion;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.ls.core.internal.commands.BuildPathCommand;
Expand All @@ -33,7 +34,6 @@
import org.eclipse.jdt.ls.core.internal.handlers.FormatterHandler;
import org.eclipse.jdt.ls.core.internal.handlers.ResolveSourceMappingHandler;
import org.eclipse.jdt.ls.core.internal.managers.GradleProjectImporter;
import org.eclipse.jdt.ls.core.internal.managers.GradleUtils;
import org.eclipse.lsp4j.ResolveTypeHierarchyItemParams;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.TextDocumentPositionParams;
Expand Down Expand Up @@ -126,7 +126,7 @@ public Object executeCommand(String commandId, List<Object> arguments, IProgress
String projectUri = (String) arguments.get(0);
String gradleVersion = arguments.size() > 1 ? (String) arguments.get(1) : null;
if (gradleVersion == null) {
gradleVersion = GradleUtils.CURRENT_GRADLE;
gradleVersion = GradleVersion.current().getVersion();
}
return GradleProjectImporter.upgradeGradleVersion(projectUri, gradleVersion, monitor);
case "java.project.resolveWorkspaceSymbol":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ private CorrectionMessages() {
public static String NewCUCompletionUsingWizardProposal_tooltip_enclosingtype;
public static String NewCUCompletionUsingWizardProposal_tooltip_package;

public static String NotAccessibleType_upgrade_Gradle_label;

public static String JavaCorrectionProcessor_addquote_description;
public static String JavaCorrectionProcessor_error_quickfix_message;
public static String JavaCorrectionProcessor_error_status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,8 @@ NewCUCompletionUsingWizardProposal_dialogtitle=New
NewCUCompletionUsingWizardProposal_tooltip_enclosingtype=Enclosing Type:
NewCUCompletionUsingWizardProposal_tooltip_package=Package:

NotAccessibleType_upgrade_Gradle_label=Upgrade Gradle version to 7.0.1

JavaCorrectionProcessor_addquote_description=Insert missing quote
JavaCorrectionProcessor_error_quickfix_message=An error occurred while computing quick fixes. Check log for details.
JavaCorrectionProcessor_error_status=Exception while processing quick fixes or quick assists
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.eclipse.jdt.ls.core.internal.corrections.proposals.CUCorrectionProposal;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.ChangeCorrectionProposal;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.GetterSetterCorrectionSubProcessor;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.GradleCompatibilityProcessor;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.IProposalRelevance;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.JavadocTagsSubProcessor;
import org.eclipse.jdt.ls.core.internal.corrections.proposals.LocalCorrectionsSubProcessor;
Expand All @@ -53,6 +54,7 @@
import org.eclipse.jdt.ls.core.internal.handlers.OrganizeImportsHandler;
import org.eclipse.jdt.ls.core.internal.text.correction.ModifierCorrectionSubProcessor;
import org.eclipse.lsp4j.CodeActionKind;
import org.eclipse.lsp4j.CodeActionParams;

/**
*/
Expand All @@ -73,7 +75,7 @@ private static int moveBack(int offset, int start, String ignoreCharacters, ICom
return start;
}

public List<ChangeCorrectionProposal> getCorrections(IInvocationContext context, IProblemLocationCore[] locations) throws CoreException {
public List<ChangeCorrectionProposal> getCorrections(CodeActionParams params, IInvocationContext context, IProblemLocationCore[] locations) throws CoreException {
if (locations == null || locations.length == 0) {
return Collections.emptyList();
}
Expand All @@ -82,7 +84,7 @@ public List<ChangeCorrectionProposal> getCorrections(IInvocationContext context,
for (int i = 0; i < locations.length; i++) {
IProblemLocationCore curr = locations[i];
if (handledProblems(curr, locations, handledProblems)) {
process(context, curr, resultingCollections);
process(params, context, curr, resultingCollections);
}
}
return resultingCollections;
Expand All @@ -105,7 +107,7 @@ private static boolean handledProblems(IProblemLocationCore location, IProblemLo
return handledProblems.add(problemId);
}

private void process(IInvocationContext context, IProblemLocationCore problem, Collection<ChangeCorrectionProposal> proposals) throws CoreException {
private void process(CodeActionParams params, IInvocationContext context, IProblemLocationCore problem, Collection<ChangeCorrectionProposal> proposals) throws CoreException {
int id = problem.getProblemId();
if (id == 0) { // no proposals for none-problem locations
return;
Expand Down Expand Up @@ -551,6 +553,9 @@ private void process(IInvocationContext context, IProblemLocationCore problem, C
case IProblem.PotentiallyUnclosedCloseable:
LocalCorrectionsSubProcessor.getTryWithResourceProposals(context, problem, proposals);
break;
case IProblem.NotAccessibleType:
GradleCompatibilityProcessor.getGradleCompatibilityProposals(context, problem, proposals);
break;
// case IProblem.MissingSynchronizedModifierInInheritedMethod:
// ModifierCorrectionSubProcessor.addSynchronizedMethodProposal(context,
// problem, proposals);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*******************************************************************************
* Copyright (c) 2022 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.corrections.proposals;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;

import org.eclipse.buildship.core.internal.CorePlugin;
import org.eclipse.buildship.core.internal.preferences.PersistentModel;
import org.eclipse.buildship.core.internal.util.gradle.GradleVersion;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IModuleDescription;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
import org.eclipse.jdt.internal.ui.text.correction.IProblemLocationCore;
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
import org.eclipse.jdt.ls.core.internal.commands.ProjectCommand;
import org.eclipse.jdt.ls.core.internal.commands.ProjectCommand.ClasspathResult;
import org.eclipse.jdt.ls.core.internal.corrections.CorrectionMessages;
import org.eclipse.jdt.ls.core.internal.corrections.IInvocationContext;
import org.eclipse.jdt.ls.core.internal.managers.GradleUtils;
import org.eclipse.jdt.ls.core.internal.text.correction.CUCorrectionCommandProposal;
import org.eclipse.lsp4j.CodeActionKind;

public class GradleCompatibilityProcessor {
public static void getGradleCompatibilityProposals(IInvocationContext context, IProblemLocationCore problem, Collection<ChangeCorrectionProposal> proposals) {
jdneo marked this conversation as resolved.
Show resolved Hide resolved
IJavaProject javaProject = context.getCompilationUnit().getJavaProject();
CsCherrYY marked this conversation as resolved.
Show resolved Hide resolved
if (javaProject == null) {
return;
}
IProject project = javaProject.getProject();
if (!ProjectUtils.isGradleProject(project)) {
return;
}
PersistentModel model = CorePlugin.modelPersistence().loadModel(project);
if (!model.isPresent()) {
return;
}
GradleVersion gradleVersion = model.getGradleVersion();
if (gradleVersion != null && gradleVersion.compareTo(GradleVersion.version(GradleUtils.JPMS_SUPPORTED_VERSION)) < 0) {
IResource resource = javaProject.getResource();
if (resource == null) {
return;
}
URI uri = resource.getLocationURI();
if (uri == null) {
return;
}
try {
ClasspathResult result = ProjectCommand.getClasspathsFromJavaProject(javaProject, new ProjectCommand.ClasspathOptions());
IModuleDescription moduleDescription = javaProject.getModuleDescription();
if (moduleDescription == null) {
Copy link
Contributor

@jdneo jdneo Dec 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest extracting the code in if-else blocks to methods separately - for better readiness.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in daf2a76

addProposalForNonModulerProject(result, context, uri, proposals);
} else {
addProposalForModulerProject(javaProject, result, context, uri, proposals);
}
} catch (CoreException | URISyntaxException e) {
return;
}
}
}

/**
* Add proposal for a non-modular project. For a project doesn't have a module
* description file (module-info.java), there should be nothing in the module
* path. See: https://github.com/gradle/gradle/issues/16922
*
* @param result
* the classpath result
* @param context
* the invocation context
* @param uri
* the project uri
* @param proposals
* the current proposals
*/
private static void addProposalForNonModulerProject(ClasspathResult result, IInvocationContext context, URI uri, Collection<ChangeCorrectionProposal> proposals) {
if (result.modulepaths.length > 0) {
addProposal(context, uri, proposals);
}
}

/**
* Add proposal for a modular project. For a project has a module description
* file (module-info.java), we should check that all the dependencies in
* classpath don't contain module description (either description or automatic
* description, the supported inferred modules in Gradle) See:
* https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_modular)
*
* @param javaProject
* the java project
* @param result
* the classpath result
* @param context
* the invocation context
* @param uri
* the project uri
* @param proposals
* the current proposals
*/
private static void addProposalForModulerProject(IJavaProject javaProject, ClasspathResult result, IInvocationContext context, URI uri, Collection<ChangeCorrectionProposal> proposals) {
for (String classpath : result.classpaths) {
try {
IPackageFragmentRoot packageFragmentRoot = javaProject.findPackageFragmentRoot(new Path(classpath));
if (packageFragmentRoot instanceof JarPackageFragmentRoot) {
// try to get module description
IModuleDescription jarModuleDescription = ((JarPackageFragmentRoot) packageFragmentRoot).getModuleDescription();
if (jarModuleDescription == null) {
// fall back to get automatic module description
jarModuleDescription = ((JarPackageFragmentRoot) packageFragmentRoot).getAutomaticModuleDescription();
}
if (jarModuleDescription != null) {
addProposal(context, uri, proposals);
break;
}
}
} catch (CoreException e) {
continue;
}
}
}

private static void addProposal(IInvocationContext context, URI uri, Collection<ChangeCorrectionProposal> proposals) {
proposals.add(new CUCorrectionCommandProposal(CorrectionMessages.NotAccessibleType_upgrade_Gradle_label, CodeActionKind.QuickFix, context.getCompilationUnit(), IProposalRelevance.CONFIGURE_BUILD_PATH, "java.project.upgradeGradle",
Arrays.asList(uri.toString(), GradleUtils.JPMS_SUPPORTED_VERSION)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public List<Either<Command, CodeAction>> getCodeActionCommands(CodeActionParams
if (containsKind(codeActionKinds, CodeActionKind.QuickFix)) {
try {
codeActions.addAll(nonProjectFixProcessor.getCorrections(params, context, locations));
List<ChangeCorrectionProposal> quickfixProposals = this.quickFixProcessor.getCorrections(context, locations);
List<ChangeCorrectionProposal> quickfixProposals = this.quickFixProcessor.getCorrections(params, context, locations);
this.quickFixProcessor.addAddAllMissingImportsProposal(context, quickfixProposals);
Set<ChangeCorrectionProposal> quickSet = new TreeSet<>(comparator);
quickSet.addAll(quickfixProposals);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.eclipse.buildship.core.SynchronizationResult;
import org.eclipse.buildship.core.WrapperGradleDistribution;
import org.eclipse.buildship.core.internal.CorePlugin;
import org.eclipse.buildship.core.internal.DefaultGradleBuild;
import org.eclipse.buildship.core.internal.preferences.PersistentModel;
import org.eclipse.buildship.core.internal.util.gradle.GradleVersion;
import org.eclipse.core.resources.IFile;
Expand Down Expand Up @@ -247,7 +248,7 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException {
}
}
if (JavaLanguageServerPlugin.getProjectsManager() != null && JavaLanguageServerPlugin.getProjectsManager().getConnection() != null) {
GradleCompatibilityInfo info = new GradleCompatibilityInfo(gradleStatus.getProjectUri(), gradleStatus.getMessage(), gradleStatus.getHighestJavaVersion(), GradleUtils.CURRENT_GRADLE);
GradleCompatibilityInfo info = new GradleCompatibilityInfo(gradleStatus.getProjectUri(), gradleStatus.getMessage(), gradleStatus.getHighestJavaVersion(), GradleVersion.current().getVersion());
EventNotification notification = new EventNotification().withType(EventType.IncompatibleGradleJdkIssue).withData(info);
JavaLanguageServerPlugin.getProjectsManager().getConnection().sendEventNotification(notification);
}
Expand All @@ -271,7 +272,7 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException {
IMarker marker = ResourceUtils.createWarningMarker(GRADLE_UPGRADE_WRAPPER_MARKER_ID, wrapperProperties, GRADLE_INVALID_TYPE_CODE_MESSAGE, INVALID_TYPE_CODE_ID, reader.getLineNumber());
marker.setAttribute(GRADLE_MARKER_COLUMN_START, 0);
marker.setAttribute(GRADLE_MARKER_COLUMN_END, line.length());
UpgradeGradleWrapperInfo info = new UpgradeGradleWrapperInfo(gradleStatus.getProjectUri(), GRADLE_INVALID_TYPE_CODE_MESSAGE, GradleUtils.CURRENT_GRADLE);
UpgradeGradleWrapperInfo info = new UpgradeGradleWrapperInfo(gradleStatus.getProjectUri(), GRADLE_INVALID_TYPE_CODE_MESSAGE, GradleVersion.current().getVersion());
EventNotification notification = new EventNotification().withType(EventType.UpgradeGradleWrapper).withData(info);
JavaLanguageServerPlugin.getProjectsManager().getConnection().sendEventNotification(notification);
break;
Expand Down Expand Up @@ -531,17 +532,34 @@ public boolean accept(File dir, String name) {
return shouldSynchronize;
}

public static boolean upgradeGradleVersion(String projectUri, String gradleVersion, IProgressMonitor monitor) {
/**
* update the gradle wrapper to the given version
* @param projectUri uri of the project
* @param gradleVersion the target gradle version
* @param monitor the progress monitor
* @return the path to the new gradle-wrapper.properties file
*/
public static String upgradeGradleVersion(String projectUri, String gradleVersion, IProgressMonitor monitor) {
String newDistributionUrl = String.format("https://services.gradle.org/distributions/gradle-%s-bin.zip", gradleVersion);
Path projectFolder = Paths.get(URI.create(projectUri));
// try to get root project directory
IProject project = ProjectUtils.getProjectFromUri(projectUri);
Optional<GradleBuild> build = GradleCore.getWorkspace().getBuild(project);
if (build.isEmpty()) {
return null;
}
GradleBuild gradleBuild = build.get();
if (gradleBuild instanceof DefaultGradleBuild) {
projectFolder = ((DefaultGradleBuild) gradleBuild).getBuildConfig().getRootProjectDirectory().toPath();
}
File propertiesFile = projectFolder.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties").toFile();
Properties properties = new Properties();
if (propertiesFile.exists()) {
try (FileInputStream stream = new FileInputStream(propertiesFile)) {
properties.load(stream);
properties.setProperty("distributionUrl", newDistributionUrl);
} catch (IOException e) {
return false;
return null;
}
} else {
properties.setProperty("distributionBase", "GRADLE_USER_HOME");
Expand All @@ -553,10 +571,8 @@ public static boolean upgradeGradleVersion(String projectUri, String gradleVersi
try {
properties.store(new FileOutputStream(propertiesFile), null);
} catch (Exception e) {
return false;
return null;
}
BuildConfiguration build = getBuildConfiguration(projectFolder);
GradleBuild gradleBuild = GradleCore.getWorkspace().createBuild(build);
try {
gradleBuild.withConnection(connection -> {
connection.newBuild().forTasks("wrapper").run();
Expand All @@ -565,7 +581,7 @@ public static boolean upgradeGradleVersion(String projectUri, String gradleVersi
} catch (Exception e) {
// Do nothing
}
return true;
return propertiesFile.getAbsolutePath();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@
public class GradleUtils {

public static String MAX_SUPPORTED_JAVA = JavaCore.VERSION_17;
public static String CURRENT_GRADLE = "7.3.1";
// see https://github.com/gradle/gradle/pull/17397
public static String INVALID_TYPE_FIXED_VERSION = "7.2";
// see https://github.com/gradle/gradle/issues/890
// see https://github.com/gradle/gradle/issues/16922
public static String JPMS_SUPPORTED_VERSION = "7.0.1";

private static final String MESSAGE_DIGEST_ALGORITHM = "SHA-256";

Expand Down