From 45bfad69ed23f9d6cca3bdf12b35da87cac59e81 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 19 Aug 2016 13:59:42 +0300 Subject: [PATCH] prohibit modifications of mock jdk to avoid corrupting it by unrelated tests --- .../projectRoots/impl/MockJdkWrapper.java | 3 +- .../projectRoots/impl/JavaSdkImpl.java | 134 +++++++++++++++++- .../NullableStuffInspectionAncientTest.java | 27 ++-- .../BytecodeAnalysisIntegrationTest.java | 12 +- .../roots/ModuleRootManagerTestCase.java | 10 +- .../com/intellij/roots/RootsChangedTest.java | 37 +++-- .../intellij/testFramework/IdeaTestUtil.java | 53 ++++--- .../projectRoots/impl/ProjectJdkImpl.java | 27 ++-- .../intellij/testFramework/PsiTestUtil.java | 20 ++- 9 files changed, 255 insertions(+), 68 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/openapi/projectRoots/impl/MockJdkWrapper.java b/java/compiler/impl/src/com/intellij/openapi/projectRoots/impl/MockJdkWrapper.java index 5120843b4e8b..ce75b72629a7 100644 --- a/java/compiler/impl/src/com/intellij/openapi/projectRoots/impl/MockJdkWrapper.java +++ b/java/compiler/impl/src/com/intellij/openapi/projectRoots/impl/MockJdkWrapper.java @@ -81,7 +81,8 @@ public final class MockJdkWrapper implements Sdk { @NotNull public Object clone() throws CloneNotSupportedException { - throw new CloneNotSupportedException(); + Sdk delegateClone = (Sdk)myDelegate.clone(); + return new MockJdkWrapper(myHomePath, delegateClone); } public SdkAdditionalData getSdkAdditionalData() { diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java index ae66bb316975..b04ea71d9d6f 100644 --- a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java +++ b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java @@ -19,6 +19,7 @@ import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.util.ExecUtil; import com.intellij.icons.AllIcons; import com.intellij.lang.LangBundle; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; @@ -30,16 +31,19 @@ import com.intellij.openapi.projectRoots.*; import com.intellij.openapi.roots.AnnotationOrderRootType; import com.intellij.openapi.roots.JavadocOrderRootType; import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.RootProvider; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.impl.jrt.JrtFileSystem; +import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import org.jetbrains.jps.model.java.impl.JavaSdkUtil; import javax.swing.*; @@ -527,12 +531,136 @@ public class JavaSdkImpl extends JavaSdk { return jdk; } + @NotNull + @TestOnly + public Sdk createMockJdk(@NotNull String jdkName, @NotNull String home, boolean isJre) { + String homePath = home.replace(File.separatorChar, '/'); + File jdkHomeFile = new File(homePath); + List classes = findClasses(jdkHomeFile, isJre); + VirtualFile sources = findSources(jdkHomeFile); + VirtualFile docs = findDocs(jdkHomeFile, "docs/api"); + ProjectRootContainerImpl rootContainer = new ProjectRootContainerImpl(true); + rootContainer.startChange(); + for (VirtualFile aClass : classes) { + rootContainer.addRoot(aClass, OrderRootType.CLASSES); + } + if (sources != null) { + rootContainer.addRoot(sources, OrderRootType.SOURCES); + } + if (docs != null) { + rootContainer.addRoot(docs, OrderRootType.DOCUMENTATION); + } + rootContainer.finishChange(); + + ProjectJdkImpl jdk = new ProjectJdkImpl(jdkName, this, homePath, jdkName) { + @Override + public void setName(@NotNull String name) { + throwReadOnly(); + } + + @Override + public void readExternal(@NotNull Element element) { + throwReadOnly(); + } + + @Override + public void readExternal(@NotNull Element element, @Nullable ProjectJdkTable projectJdkTable) { + throwReadOnly(); + } + + @NotNull + @Override + public SdkModificator getSdkModificator() { + throwReadOnly(); + return null; + } + + @Override + public void setSdkAdditionalData(SdkAdditionalData data) { + throwReadOnly(); + } + + @Override + public void addRoot(VirtualFile root, OrderRootType rootType) { + throwReadOnly(); + } + + @Override + public void removeRoot(VirtualFile root, OrderRootType rootType) { + throwReadOnly(); + } + + @Override + public void removeRoots(OrderRootType rootType) { + throwReadOnly(); + } + + @Override + public void removeAllRoots() { + throwReadOnly(); + } + + @Override + public boolean isWritable() { + return false; + } + + @Override + public void update() { + throwReadOnly(); + } + + @Override + public VirtualFile[] getRoots(OrderRootType rootType) { + return rootContainer.getRootFiles(rootType); + } + + @NotNull + @Override + public RootProvider getRootProvider() { + return new RootProvider() { + @NotNull + @Override + public String[] getUrls(@NotNull OrderRootType rootType) { + return ContainerUtil.map2Array(getFiles(rootType), String.class, VirtualFile::getUrl); + } + + @NotNull + @Override + public VirtualFile[] getFiles(@NotNull OrderRootType rootType) { + return getRoots(rootType); + } + + @Override + public void addRootSetChangedListener(@NotNull RootSetChangedListener listener) { + } + + @Override + public void addRootSetChangedListener(@NotNull RootSetChangedListener listener, @NotNull Disposable parentDisposable) { + } + + @Override + public void removeRootSetChangedListener(@NotNull RootSetChangedListener listener) { + } + }; + } + }; + + ProjectJdkImpl.copyRoots(rootContainer, jdk); + return jdk; + } + + private static void throwReadOnly() { + throw new IncorrectOperationException("Can't modify, MockJDK is read-only, consider calling .clone() first"); + } + private static void addClasses(File file, SdkModificator sdkModificator, boolean isJre) { for (VirtualFile virtualFile : findClasses(file, isJre)) { sdkModificator.addRoot(virtualFile, OrderRootType.CLASSES); } } + @NotNull private static List findClasses(File file, boolean isJre) { List result = ContainerUtil.newArrayList(); VirtualFileManager fileManager = VirtualFileManager.getInstance(); @@ -555,7 +683,7 @@ public class JavaSdkImpl extends JavaSdk { return result; } - private static void addSources(File file, SdkModificator sdkModificator) { + private static void addSources(@NotNull File file, @NotNull SdkModificator sdkModificator) { VirtualFile vFile = findSources(file); if (vFile != null) { sdkModificator.addRoot(vFile, OrderRootType.SOURCES); @@ -571,7 +699,6 @@ public class JavaSdkImpl extends JavaSdk { @Nullable @SuppressWarnings("HardCodedStringLiteral") private static VirtualFile findSources(File file, final String srcName) { - File srcDir = new File(file, "src"); File jarFile = new File(file, srcName + ".jar"); if (!jarFile.exists()) { jarFile = new File(file, srcName + ".zip"); @@ -585,6 +712,7 @@ public class JavaSdkImpl extends JavaSdk { return vFile; } else { + File srcDir = new File(file, "src"); if (!srcDir.exists() || !srcDir.isDirectory()) return null; String path = srcDir.getAbsolutePath().replace(File.separatorChar, '/'); return LocalFileSystem.getInstance().findFileByPath(path); @@ -608,7 +736,7 @@ public class JavaSdkImpl extends JavaSdk { } @Nullable - private static VirtualFile findDocs(File file, final String relativePath) { + private static VirtualFile findDocs(@NotNull File file, @NotNull String relativePath) { file = new File(file.getAbsolutePath() + File.separator + relativePath.replace('/', File.separatorChar)); if (!file.exists() || !file.isDirectory()) return null; String path = file.getAbsolutePath().replace(File.separatorChar, '/'); diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionAncientTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionAncientTest.java index 79c36144385b..f0a9522562c1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionAncientTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionAncientTest.java @@ -28,8 +28,8 @@ import com.intellij.codeInspection.nullable.NullableStuffInspection; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModificator; -import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.InspectionTestCase; import com.intellij.testFramework.PsiTestUtil; @@ -55,18 +55,26 @@ public class NullableStuffInspectionAncientTest extends InspectionTestCase { } @Override - protected void setupRootModel(@NotNull String testDir, @NotNull VirtualFile[] sourceDir, String sdkName) { - super.setupRootModel(testDir, sourceDir, sdkName); - Sdk sdk = ModuleRootManager.getInstance(myModule).getSdk(); - removeAnnotationsJar(sdk); + protected Sdk getTestProjectSdk() { + Sdk sdk = super.getTestProjectSdk(); + sdk = removeAnnotationsJar(sdk); if ("testJdkAnnotationsWithoutJetBrainsAnnotations".equals(getName())) { - PsiTestUtil.addJdkAnnotations(sdk); + sdk = PsiTestUtil.addJdkAnnotations(sdk); } + return sdk; } - private static void removeAnnotationsJar(final Sdk sdk) { - ApplicationManager.getApplication().runWriteAction(() -> { - final SdkModificator sdkMod = sdk.getSdkModificator(); + @NotNull + private static Sdk removeAnnotationsJar(@NotNull Sdk sdk) { + return ApplicationManager.getApplication().runWriteAction((Computable)() -> { + Sdk clone; + try { + clone = (Sdk)sdk.clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + final SdkModificator sdkMod = clone.getSdkModificator(); for (VirtualFile file : sdkMod.getRoots(OrderRootType.CLASSES)) { if ("annotations.jar".equals(file.getName())) { sdkMod.removeRoot(file, OrderRootType.CLASSES); @@ -74,6 +82,7 @@ public class NullableStuffInspectionAncientTest extends InspectionTestCase { } } sdkMod.commitChanges(); + return clone; }); } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java index 6ccfb6ff4957..8c64dc6b4e3f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java @@ -57,7 +57,7 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC private static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName(); private MessageDigest myMessageDigest; - private List myDiffs = new ArrayList<>(); + private final List myDiffs = new ArrayList<>(); private boolean myNullableMethodRegistryValue; @Override @@ -104,9 +104,17 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC } Sdk sdk = modifiableRootModel.getSdk(); if (sdk != null) { - SdkModificator sdkModificator = sdk.getSdkModificator(); + Sdk clone; + try { + clone = (Sdk)sdk.clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + SdkModificator sdkModificator = clone.getSdkModificator(); sdkModificator.addRoot(annotationsDir, AnnotationOrderRootType.getInstance()); sdkModificator.commitChanges(); + modifiableRootModel.setSdk(clone); } } }); diff --git a/java/java-tests/testSrc/com/intellij/roots/ModuleRootManagerTestCase.java b/java/java-tests/testSrc/com/intellij/roots/ModuleRootManagerTestCase.java index ee18c631b9b4..1826e04305d5 100644 --- a/java/java-tests/testSrc/com/intellij/roots/ModuleRootManagerTestCase.java +++ b/java/java-tests/testSrc/com/intellij/roots/ModuleRootManagerTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -30,6 +30,7 @@ import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.ModuleTestCase; import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.PathsList; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -58,7 +59,14 @@ public abstract class ModuleRootManagerTestCase extends ModuleTestCase { } @NotNull + @Contract(pure = true) private static Sdk retainRtJarOnlyAndSetVersion(Sdk jdk) { + try { + jdk = (Sdk)jdk.clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } final SdkModificator modificator = jdk.getSdkModificator(); VirtualFile rtJar = null; for (VirtualFile root : modificator.getRoots(OrderRootType.CLASSES)) { diff --git a/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java b/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java index 1648e6b42eb4..e639e0a4180f 100644 --- a/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java +++ b/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java @@ -126,7 +126,13 @@ public class RootsChangedTest extends ModuleTestCase { Module a = loadModule(PathManagerEx.getHomePath(getClass()) + "/java/java-tests/testData/moduleRootManager/rootsChanged/emptyModule/a.iml"); assertEventsCount(1); - final Sdk jdk = IdeaTestUtil.getMockJdk17(); + final Sdk jdk; + try { + jdk = (Sdk)IdeaTestUtil.getMockJdk17().clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } ProjectJdkTable.getInstance().addJdk(jdk); assertEventsCount(0); @@ -148,7 +154,13 @@ public class RootsChangedTest extends ModuleTestCase { final Module moduleB = createModule("b.iml"); assertEventsCount(2); - final Sdk jdk = IdeaTestUtil.getMockJdk17(); + final Sdk jdk; + try { + jdk = (Sdk)IdeaTestUtil.getMockJdk17().clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } ProjectJdkTable.getInstance().addJdk(jdk); assertEventsCount(0); @@ -156,7 +168,7 @@ public class RootsChangedTest extends ModuleTestCase { final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel(); rootModelA.setSdk(jdk); rootModelB.setSdk(jdk); - ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB}; + ModifiableRootModel[] rootModels = {rootModelA, rootModelB}; ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel()); assertEventsCount(1); @@ -177,11 +189,18 @@ public class RootsChangedTest extends ModuleTestCase { final Module moduleB = createModule("b.iml"); assertEventsCount(2); - final Sdk jdk = IdeaTestUtil.getMockJdk17("AAA"); - ProjectJdkTable.getInstance().addJdk(jdk); - assertEventsCount(0); + final Sdk jdk; + final Sdk jdkBBB; + try { + jdk = (Sdk)IdeaTestUtil.getMockJdk17("AAA").clone(); + ProjectJdkTable.getInstance().addJdk(jdk); + assertEventsCount(0); - final Sdk jdkBBB = IdeaTestUtil.getMockJdk17("BBB"); + jdkBBB = (Sdk)IdeaTestUtil.getMockJdk17("BBB").clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } ProjectJdkTable.getInstance().addJdk(jdk); assertEventsCount(0); @@ -192,7 +211,7 @@ public class RootsChangedTest extends ModuleTestCase { final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel(); rootModelA.inheritSdk(); rootModelB.inheritSdk(); - ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB}; + ModifiableRootModel[] rootModels = {rootModelA, rootModelB}; if (rootModels.length > 0) { ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel()); } @@ -211,7 +230,7 @@ public class RootsChangedTest extends ModuleTestCase { }); } - private void verifyLibraryTableEditing(final LibraryTable libraryTable) throws IOException { + private void verifyLibraryTableEditing(final LibraryTable libraryTable) { final Module moduleA = createModule("a.iml"); final Module moduleB = createModule("b.iml"); assertEventsCount(2); diff --git a/java/testFramework/src/com/intellij/testFramework/IdeaTestUtil.java b/java/testFramework/src/com/intellij/testFramework/IdeaTestUtil.java index f6ad08c80230..3e33201489aa 100644 --- a/java/testFramework/src/com/intellij/testFramework/IdeaTestUtil.java +++ b/java/testFramework/src/com/intellij/testFramework/IdeaTestUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -19,6 +19,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.projectRoots.*; +import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; import com.intellij.openapi.roots.LanguageLevelModuleExtensionImpl; import com.intellij.openapi.roots.LanguageLevelProjectExtension; @@ -27,28 +28,23 @@ import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.JarFileSystem; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.util.PathUtil; import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; +import org.junit.Assume; import java.io.File; import java.util.List; -import static org.junit.Assume.assumeTrue; - public class IdeaTestUtil extends PlatformTestUtil { private static final String MOCK_JDK_DIR_NAME_PREFIX = "mockJDK-"; - public static void main(String[] args) { - printDetectedPerformanceTimings(); - } - - @SuppressWarnings({"UseOfSystemOutOrSystemErr"}) + @SuppressWarnings("UseOfSystemOutOrSystemErr") public static void printDetectedPerformanceTimings() { System.out.println(Timings.getStatistics()); } @@ -76,20 +72,30 @@ public class IdeaTestUtil extends PlatformTestUtil { modifiable.commit(); } + @TestOnly public static Sdk getMockJdk17() { return getMockJdk17("java 1.7"); } + @NotNull + @TestOnly + private static Sdk createMockJdk(@NotNull String name, String path) { + return ((JavaSdkImpl)JavaSdk.getInstance()).createMockJdk(name, path, false); + } + + @TestOnly public static Sdk getMockJdk17(@NotNull String name) { - return JavaSdk.getInstance().createJdk(name, getMockJdk17Path().getPath(), false); + return createMockJdk(name, getMockJdk17Path().getPath()); } + @TestOnly public static Sdk getMockJdk18() { - return JavaSdk.getInstance().createJdk("java 1.8", getMockJdk18Path().getPath(), false); + return createMockJdk("java 1.8", getMockJdk18Path().getPath()); } + @TestOnly public static Sdk getMockJdk14() { - return JavaSdk.getInstance().createJdk("java 1.4", getMockJdk14Path().getPath(), false); + return createMockJdk("java 1.4", getMockJdk14Path().getPath()); } public static File getMockJdk14Path() { @@ -117,17 +123,27 @@ public class IdeaTestUtil extends PlatformTestUtil { return mockJdkCEPath.exists() ? mockJdkCEPath : new File(PathManager.getHomePath(), "community/java/" + name); } + @TestOnly public static Sdk getWebMockJdk17() { Sdk jdk = getMockJdk17(); - addWebJarsTo(jdk); + jdk=addWebJarsTo(jdk); return jdk; } - public static void addWebJarsTo(@NotNull Sdk jdk) { + @NotNull + @Contract(pure=true) + public static Sdk addWebJarsTo(@NotNull Sdk jdk) { + try { + jdk = (Sdk)jdk.clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } SdkModificator sdkModificator = jdk.getSdkModificator(); sdkModificator.addRoot(findJar("lib/jsp-api.jar"), OrderRootType.CLASSES); sdkModificator.addRoot(findJar("lib/servlet-api.jar"), OrderRootType.CLASSES); sdkModificator.commitChanges(); + return jdk; } private static VirtualFile findJar(String name) { @@ -145,12 +161,7 @@ public class IdeaTestUtil extends PlatformTestUtil { final String oldVersionString = sdk.getVersionString(); ((ProjectJdkImpl)sdk).setVersionString(testVersion.getDescription()); assert JavaSdk.getInstance().getVersion(sdk) == testVersion; - Disposer.register(parentDisposable, new Disposable() { - @Override - public void dispose() { - ((ProjectJdkImpl)sdk).setVersionString(oldVersionString); - } - }); + Disposer.register(parentDisposable, () -> ((ProjectJdkImpl)sdk).setVersionString(oldVersionString)); } @@ -164,7 +175,7 @@ public class IdeaTestUtil extends PlatformTestUtil { return path; } } - assumeTrue("Cannot find JDK, checked paths: " + paths, false); + Assume.assumeTrue("Cannot find JDK, checked paths: " + paths, false); return null; } } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java index 5eae3f971e9a..10150486455b 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkImpl.java @@ -20,7 +20,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.projectRoots.*; import com.intellij.openapi.projectRoots.ex.ProjectRoot; -import com.intellij.openapi.projectRoots.ex.ProjectRootContainer; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.RootProvider; import com.intellij.openapi.roots.impl.RootProviderBaseImpl; @@ -42,7 +41,7 @@ import java.util.List; public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModificator { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.ProjectJdkImpl"); - private final ProjectRootContainerImpl myRootContainer; + final ProjectRootContainerImpl myRootContainer; private String myName; private String myVersionString; private boolean myVersionDefined; @@ -248,28 +247,24 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi final String name = getName(); dest.setName(name); dest.setHomePath(getHomePath()); - if (myVersionDefined) { - dest.setVersionString(getVersionString()); - } - else { - dest.resetVersionString(); - } + dest.myVersionDefined = myVersionDefined; + dest.myVersionString = myVersionString; dest.setSdkAdditionalData(getSdkAdditionalData()); + copyRoots(myRootContainer, dest); + } + + static void copyRoots(@NotNull ProjectRootContainerImpl rootContainer, @NotNull ProjectJdkImpl dest) { dest.myRootContainer.startChange(); dest.myRootContainer.removeAllRoots(); for (OrderRootType rootType : OrderRootType.getAllTypes()) { - copyRoots(myRootContainer, dest.myRootContainer, rootType); + final ProjectRoot[] newRoots = rootContainer.getRoots(rootType); + for (ProjectRoot newRoot : newRoots) { + dest.myRootContainer.addRoot(newRoot, rootType); + } } dest.myRootContainer.finishChange(); } - private static void copyRoots(ProjectRootContainer srcContainer, ProjectRootContainer destContainer, OrderRootType type) { - final ProjectRoot[] newRoots = srcContainer.getRoots(type); - for (ProjectRoot newRoot : newRoots) { - destContainer.addRoot(newRoot, type); - } - } - private class MyRootProvider extends RootProviderBaseImpl implements ProjectRootListener { @Override @NotNull diff --git a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java index 459521380692..76567ea0195c 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java @@ -39,6 +39,7 @@ import com.intellij.psi.PsiFileFactory; import com.intellij.psi.impl.DebugUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.JpsElement; @@ -371,14 +372,21 @@ public class PsiTestUtil { ModuleRootModificationUtil.updateModel(module, model -> model.getModuleExtension(JavaModuleExternalPaths.class).setJavadocUrls(urls)); } - public static Sdk addJdkAnnotations(Sdk sdk) { + @NotNull + @Contract(pure=true) + public static Sdk addJdkAnnotations(@NotNull Sdk sdk) { String path = FileUtil.toSystemIndependentName(PlatformTestUtil.getCommunityPath()) + "/java/jdkAnnotations"; VirtualFile root = LocalFileSystem.getInstance().findFileByPath(path); - if (root != null) { - SdkModificator sdkModificator = sdk.getSdkModificator(); - sdkModificator.addRoot(root, AnnotationOrderRootType.getInstance()); - sdkModificator.commitChanges(); + Sdk clone; + try { + clone = (Sdk)sdk.clone(); } - return sdk; + catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + SdkModificator sdkModificator = clone.getSdkModificator(); + sdkModificator.addRoot(root, AnnotationOrderRootType.getInstance()); + sdkModificator.commitChanges(); + return clone; } } \ No newline at end of file