'change language level' functionality moved to JavaProjectModelModificationService, test on IncreaseLanguageLevelFix added

This commit is contained in:
nik
2015-09-17 10:00:23 +03:00
parent 9a4a6568ea
commit 6a479aeef7
9 changed files with 138 additions and 36 deletions
@@ -22,18 +22,13 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JdkVersionUtil;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
import com.intellij.openapi.roots.JavaProjectModelModificationService;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiFile;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author cdr
@@ -59,24 +54,13 @@ public class IncreaseLanguageLevelFix implements IntentionAction {
return CodeInsightBundle.message("set.language.level");
}
private static boolean isJdkSupportsLevel(@Nullable final Sdk jdk, @NotNull LanguageLevel level) {
if (jdk == null) return true;
String versionString = jdk.getVersionString();
JavaSdkVersion version = versionString == null ? null : JdkVersionUtil.getVersion(versionString);
return version != null && version.getMaxLanguageLevel().isAtLeast(level);
}
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) return false;
final Module module = ModuleUtilCore.findModuleForFile(virtualFile, project);
if (module == null) return false;
return isLanguageLevelAcceptable(project, module, myLevel);
}
private static boolean isLanguageLevelAcceptable(@NotNull Project project, @NotNull Module module, @NotNull LanguageLevel level) {
return isJdkSupportsLevel(getRelevantJdk(project, module), level);
return JavaSdkUtil.isLanguageLevelAcceptable(project, module, myLevel);
}
@Override
@@ -86,23 +70,7 @@ public class IncreaseLanguageLevelFix implements IntentionAction {
final Module module = ModuleUtilCore.findModuleForFile(virtualFile, project);
if (module == null) return;
final LanguageLevel moduleLevel = LanguageLevelModuleExtensionImpl.getInstance(module).getLanguageLevel();
if (moduleLevel != null && isLanguageLevelAcceptable(project, module, myLevel)) {
final ModifiableRootModel rootModel = ModuleRootManager.getInstance(module).getModifiableModel();
rootModel.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(myLevel);
rootModel.commit();
}
else {
LanguageLevelProjectExtension.getInstance(project).setLanguageLevel(myLevel);
ProjectRootManagerEx.getInstanceEx(project).makeRootsChange(EmptyRunnable.INSTANCE, false, true);
}
}
@Nullable
private static Sdk getRelevantJdk(@NotNull Project project, @NotNull Module module) {
Sdk projectJdk = ProjectRootManager.getInstance(project).getProjectSdk();
Sdk moduleJdk = ModuleRootManager.getInstance(module).getSdk();
return moduleJdk == null ? projectJdk : moduleJdk;
JavaProjectModelModificationService.getInstance(project).changeLanguageLevel(module, myLevel);
}
@Override
@@ -15,12 +15,21 @@
*/
package com.intellij.openapi.projectRoots.ex;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JdkVersionUtil;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.rt.compiler.JavacRunner;
import com.intellij.util.PathUtil;
import com.intellij.util.PathsList;
import com.intellij.util.ReflectionUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
@@ -56,4 +65,22 @@ public class JavaSdkUtil {
return Arrays.asList(getJunit4JarPath(),
PathUtil.getJarPathForClass(ReflectionUtil.forName("org.hamcrest.Matcher")));
}
public static boolean isLanguageLevelAcceptable(@NotNull Project project, @NotNull Module module, @NotNull LanguageLevel level) {
return isJdkSupportsLevel(getRelevantJdk(project, module), level);
}
private static boolean isJdkSupportsLevel(@Nullable final Sdk jdk, @NotNull LanguageLevel level) {
if (jdk == null) return true;
String versionString = jdk.getVersionString();
JavaSdkVersion version = versionString == null ? null : JdkVersionUtil.getVersion(versionString);
return version != null && version.getMaxLanguageLevel().isAtLeast(level);
}
@Nullable
private static Sdk getRelevantJdk(@NotNull Project project, @NotNull Module module) {
Sdk projectJdk = ProjectRootManager.getInstance(project).getProjectSdk();
Sdk moduleJdk = ModuleRootManager.getInstance(module).getSdk();
return moduleJdk == null ? projectJdk : moduleJdk;
}
}
@@ -19,6 +19,7 @@ import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.pom.java.LanguageLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.Promise;
@@ -58,4 +59,6 @@ public abstract class JavaProjectModelModificationService {
@NotNull DependencyScope scope);
public abstract Promise<Void> addDependency(@NotNull Module from, @NotNull Library library, @NotNull DependencyScope scope);
public abstract Promise<Void> changeLanguageLevel(@NotNull Module module, @NotNull LanguageLevel languageLevel);
}
@@ -18,6 +18,7 @@ package com.intellij.openapi.roots;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.pom.java.LanguageLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.concurrency.Promise;
@@ -72,4 +73,15 @@ public abstract class JavaProjectModelModifier {
*/
@Nullable
public abstract Promise<Void> addLibraryDependency(@NotNull Module from, @NotNull Library library, @NotNull DependencyScope scope);
/**
* Implementation of this method should set language level for module {@code module} to the specified value accordingly
* to this dependencies management system. If it takes some time to propagate changes in the external project configuration to IDEA's
* project model the method may schedule this work for asynchronous execution and return {@link Promise} instance which will be fulfilled
* when the work is done.
*
* @return {@link Promise} instance if language level can be set by this dependencies management system or {@code null} otherwise
*/
@Nullable
public abstract Promise<Void> changeLanguageLevel(@NotNull Module module, @NotNull LanguageLevel level);
}
@@ -22,10 +22,14 @@ import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.roots.libraries.LibraryUtil;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.Promise;
@@ -91,4 +95,19 @@ public class IdeaProjectModelModifier extends JavaProjectModelModifier {
OrderEntryUtil.addLibraryToRoots(from, library);
return Promise.DONE;
}
@Override
public Promise<Void> changeLanguageLevel(@NotNull Module module, @NotNull LanguageLevel level) {
final LanguageLevel moduleLevel = LanguageLevelModuleExtensionImpl.getInstance(module).getLanguageLevel();
if (moduleLevel != null && JavaSdkUtil.isLanguageLevelAcceptable(myProject, module, level)) {
final ModifiableRootModel rootModel = ModuleRootManager.getInstance(module).getModifiableModel();
rootModel.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(level);
rootModel.commit();
}
else {
LanguageLevelProjectExtension.getInstance(myProject).setLanguageLevel(level);
ProjectRootManagerEx.getInstanceEx(myProject).makeRootsChange(EmptyRunnable.INSTANCE, false, true);
}
return Promise.DONE;
}
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.roots.ExternalLibraryDescriptor;
import com.intellij.openapi.roots.JavaProjectModelModificationService;
import com.intellij.openapi.roots.JavaProjectModelModifier;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.pom.java.LanguageLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.Promise;
@@ -70,6 +71,17 @@ public class JavaProjectModelModificationServiceImpl extends JavaProjectModelMod
return Promise.REJECTED;
}
@Override
public Promise<Void> changeLanguageLevel(@NotNull Module module, @NotNull LanguageLevel languageLevel) {
for (JavaProjectModelModifier modifier : getModelModifiers()) {
Promise<Void> promise = modifier.changeLanguageLevel(module, languageLevel);
if (promise != null) {
return promise;
}
}
return Promise.REJECTED;
}
@NotNull
private JavaProjectModelModifier[] getModelModifiers() {
return JavaProjectModelModifier.EP_NAME.getExtensions(myProject);
@@ -0,0 +1,7 @@
public class Lambda {
void m() {
Runnable r = <caret>() -> x();
}
void x() {}
}
@@ -0,0 +1,48 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.daemon.quickFix;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.util.PsiUtil;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
/**
* @author nik
*/
public class IncreaseLanguageLevelFixTest extends JavaCodeInsightFixtureTestCase {
@Override
protected String getTestDataPath() {
return JavaTestUtil.getJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/quickFix/increaseLanguageLevel/";
}
@Override
protected void tuneFixture(JavaModuleFixtureBuilder moduleBuilder) throws Exception {
moduleBuilder.setLanguageLevel(LanguageLevel.JDK_1_6);
moduleBuilder.addJdk(IdeaTestUtil.getMockJdk18Path().getPath());
}
public void testLambda() throws Exception {
myFixture.configureByFile("Lambda.java");
assertEquals(LanguageLevel.JDK_1_6, PsiUtil.getLanguageLevel(myFixture.getFile()));
IntentionAction fix = myFixture.findSingleIntention("Set language level");
myFixture.launchAction(fix);
assertEquals(LanguageLevel.JDK_1_8, PsiUtil.getLanguageLevel(myFixture.getFile()));
}
}
@@ -26,6 +26,7 @@ import com.intellij.openapi.roots.ExternalLibraryDescriptor;
import com.intellij.openapi.roots.JavaProjectModelModifier;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.psi.xml.XmlFile;
@@ -152,6 +153,11 @@ public class MavenProjectModelModifier extends JavaProjectModelModifier {
return null;
}
@Override
public Promise<Void> changeLanguageLevel(@NotNull Module module, @NotNull LanguageLevel level) {
return null;
}
@Nullable
private static String getMavenScope(DependencyScope scope) {
switch (scope) {