diff --git a/.idea/libraries/cucumber_java.xml b/.idea/libraries/cucumber_java.xml index 197af837c7b4..da3ae40aa4a5 100644 --- a/.idea/libraries/cucumber_java.xml +++ b/.idea/libraries/cucumber_java.xml @@ -1,9 +1,9 @@ - - - + + + diff --git a/.idea/libraries/cucumber_jvm.xml b/.idea/libraries/cucumber_jvm.xml index f31f0aa6f76b..ce5f19c44c58 100644 --- a/.idea/libraries/cucumber_jvm.xml +++ b/.idea/libraries/cucumber_jvm.xml @@ -1,7 +1,7 @@ - + diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index b3d8926fca1f..eb3dad7719fc 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -1409,6 +1409,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb } } + @NotNull public SuspendManager getSuspendManager() { return mySuspendManager; } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStaticGroup.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStaticGroup.java index 0f0d52691a57..5fceee2661c1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStaticGroup.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStaticGroup.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -21,6 +21,7 @@ import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.impl.watch.*; import com.intellij.debugger.ui.tree.render.ClassRenderer; import com.intellij.icons.AllIcons; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.xdebugger.frame.*; import com.sun.jdi.Field; import com.sun.jdi.ReferenceType; @@ -50,8 +51,17 @@ public class JavaStaticGroup extends XValueGroup implements NodeDescriptorProvid @Nullable @Override public String getComment() { - final ClassRenderer classRenderer = NodeRendererSettings.getInstance().getClassRenderer(); - return classRenderer.renderTypeName(myStaticDescriptor.getType().name()); + String res = NodeRendererSettings.getInstance().getClassRenderer().renderTypeName(myStaticDescriptor.getType().name()); + if (!StringUtil.isEmpty(res)) { + return " members of " + res; + } + return res; + } + + @NotNull + @Override + public String getSeparator() { + return ""; } @Nullable diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java index fec95e704364..34f3ab2436a0 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java @@ -111,10 +111,6 @@ public class DebuggerSession implements AbstractDebuggerSession { mySteppingThroughThread.set(threadProxy); } - void unsetSteppingThrough(ThreadReferenceProxyImpl threadProxy) { - mySteppingThroughThread.compareAndSet(threadProxy, null); - } - void clearSteppingThrough() { mySteppingThroughThread.set(null); } @@ -346,12 +342,7 @@ public class DebuggerSession implements AbstractDebuggerSession { public void resume() { final SuspendContextImpl suspendContext = getSuspendContext(); if(suspendContext != null) { - if (suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_ALL) { - clearSteppingThrough(); - } - else { - unsetSteppingThrough(suspendContext.getThread()); - } + clearSteppingThrough(); resetIgnoreStepFiltersFlag(); resumeAction(myDebugProcess.createResumeCommand(suspendContext), Event.RESUME); } @@ -519,7 +510,7 @@ public class DebuggerSession implements AbstractDebuggerSession { return; } - clearSteppingThrough(); + setSteppingThrough(suspendContext.getThread()); ThreadReferenceProxyImpl currentThread = suspendContext.getThread(); final StackFrameContext positionContext; @@ -647,7 +638,7 @@ public class DebuggerSession implements AbstractDebuggerSession { } final SuspendContextImpl currentSuspendContext = getContextManager().getContext().getSuspendContext(); if (currentSuspendContext == null) { - return true; + return mySteppingThroughThread.get() == null; } if (enableBreakpointsDuringEvaluation()) { final ThreadReferenceProxyImpl currentThread = currentSuspendContext.getThread(); @@ -658,10 +649,13 @@ public class DebuggerSession implements AbstractDebuggerSession { @Override - public void resumed(final SuspendContextImpl suspendContext) { + public void resumed(SuspendContextImpl suspendContext) { SuspendManager suspendManager = getProcess().getSuspendManager(); SuspendContextImpl context = suspendManager.getPausedContext(); - if (context != null && suspendContext != null && isSteppingThrough(suspendContext.getThread())) { + // single thread stepping + if (suspendContext != null + && suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD + && isSteppingThrough(suspendContext.getThread())) { context = suspendManager.pushSuspendContext(suspendContext.getSuspendPolicy(), 0); context.setThread(suspendContext.getThread().getThreadReference()); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LibrariesAlphaComparator.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LibrariesAlphaComparator.java deleted file mode 100644 index 1463e17daab7..000000000000 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LibrariesAlphaComparator.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2000-2009 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.openapi.roots.ui.configuration; - -import com.intellij.openapi.roots.OrderRootType; -import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.vfs.VirtualFile; - -import java.util.Comparator; - -/** - * @author Eugene Zhuravlev - * Date: Jan 14, 2004 - */ -public class LibrariesAlphaComparator implements Comparator { - public static LibrariesAlphaComparator INSTANCE = new LibrariesAlphaComparator(); - - @Override - public int compare(Library library1, Library library2) { - String name1 = library1.getName(); - if (name1 != null && name1.length() == 0) { - name1 = null; - } - String name2 = library2.getName(); - if (name2 != null && name2.length() == 0) { - name2 = null; - } - if (name1 == null && name2 == null) { - final VirtualFile[] files1 = library1.getFiles(OrderRootType.CLASSES); - final VirtualFile[] files2 = library2.getFiles(OrderRootType.CLASSES); - name1 = files1.length > 0? files1[0].getName() : null; - name2 = files2.length > 0? files2[0].getName() : null; - } - return compareNames(name1, name2); - } - - public int compareNames(String name1, String name2) { - if (name1 == null && name2 == null) { - return 0; - } - else if (name1 == null) { - return -1; - } - else if (name2 == null) { - return +1; - } - else { - return name1.compareToIgnoreCase(name2); - } - } -} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java index ae8ec6d2bd76..75c90c41d95d 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java @@ -286,51 +286,47 @@ public class ModulesConfigurator implements ModulesProvider, ModuleEditor.Change } final Ref exceptionRef = Ref.create(); - DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - try { - for (final ModuleEditor moduleEditor : myModuleEditors.values()) { - final ModifiableRootModel model = moduleEditor.apply(); - if (model != null) { - if (!model.isSdkInherited()) { - // make sure the sdk is set to original SDK stored in the JDK Table - final Sdk modelSdk = model.getSdk(); - if (modelSdk != null) { - final Sdk original = modifiedToOriginalMap.get(modelSdk); - if (original != null) { - model.setSdk(original); - } - } + try { + for (final ModuleEditor moduleEditor : myModuleEditors.values()) { + final ModifiableRootModel model = moduleEditor.apply(); + if (model != null) { + if (!model.isSdkInherited()) { + // make sure the sdk is set to original SDK stored in the JDK Table + final Sdk modelSdk = model.getSdk(); + if (modelSdk != null) { + final Sdk original = modifiedToOriginalMap.get(modelSdk); + if (original != null) { + model.setSdk(original); } - models.add(model); } } - myFacetsConfigurator.applyEditors(); - } - catch (ConfigurationException e) { - exceptionRef.set(e); - return; - } - - try { - final ModifiableRootModel[] rootModels = models.toArray(new ModifiableRootModel[models.size()]); - ModifiableModelCommitter.multiCommit(rootModels, myModuleModel); - myModuleModelCommitted = true; - myFacetsConfigurator.commitFacets(); - - } - finally { - ModuleStructureConfigurable.getInstance(myProject).getFacetEditorFacade().clearMaps(false); - - myFacetsConfigurator = createFacetsConfigurator(); - myModuleModel = ModuleManager.getInstance(myProject).getModifiableModel(); - myModuleModelCommitted = false; + models.add(model); } } - }); + myFacetsConfigurator.applyEditors(); + } + catch (ConfigurationException e) { + exceptionRef.set(e); + return; + } + + try { + final ModifiableRootModel[] rootModels = models.toArray(new ModifiableRootModel[models.size()]); + ModifiableModelCommitter.multiCommit(rootModels, myModuleModel); + myModuleModelCommitted = true; + myFacetsConfigurator.commitFacets(); + + } + finally { + ModuleStructureConfigurable.getInstance(myProject).getFacetEditorFacade().clearMaps(false); + + myFacetsConfigurator = createFacetsConfigurator(); + myModuleModel = ModuleManager.getInstance(myProject).getModifiableModel(); + myModuleModelCommitted = false; + } } }); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java index 8b0e89daec94..fc268c7cff5d 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java @@ -25,8 +25,6 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.fileChooser.FileChooserFactory; import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.project.DumbModePermission; -import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.project.ex.ProjectEx; @@ -226,39 +224,35 @@ public class ProjectConfigurable extends ProjectStructureElementConfigurable 0) { - try { - canonicalPath = FileUtil.resolveShortWindowsName(canonicalPath); - } - catch (IOException e) { - //file doesn't exist yet - } - canonicalPath = FileUtil.toSystemIndependentName(canonicalPath); - compilerProjectExtension.setCompilerOutputUrl(VfsUtilCore.pathToUrl(canonicalPath)); - } - else { - compilerProjectExtension.setCompilerOutputPointer(null); - } - - LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(myProject); - extension.setLanguageLevel(myLanguageLevelCombo.getSelectedLevel()); - extension.setDefault(myLanguageLevelCombo.isDefault()); - myProjectJdkConfigurable.apply(); - - if (myProjectName != null) { - ((ProjectEx)myProject).setProjectName(myProjectName.getText().trim()); - if (myDetailsComponent != null) myDetailsComponent.setText(getBannerSlogan()); - } + // set the output path first so that handlers of RootsChanged event sent after JDK is set + // would see the updated path + String canonicalPath = myProjectCompilerOutput.getText(); + if (canonicalPath != null && canonicalPath.length() > 0) { + try { + canonicalPath = FileUtil.resolveShortWindowsName(canonicalPath); } - }); + catch (IOException e) { + //file doesn't exist yet + } + canonicalPath = FileUtil.toSystemIndependentName(canonicalPath); + compilerProjectExtension.setCompilerOutputUrl(VfsUtilCore.pathToUrl(canonicalPath)); + } + else { + compilerProjectExtension.setCompilerOutputPointer(null); + } + + LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(myProject); + extension.setLanguageLevel(myLanguageLevelCombo.getSelectedLevel()); + extension.setDefault(myLanguageLevelCombo.isDefault()); + myProjectJdkConfigurable.apply(); + + if (myProjectName != null) { + ((ProjectEx)myProject).setProjectName(myProjectName.getText().trim()); + if (myDetailsComponent != null) myDetailsComponent.setText(getBannerSlogan()); + } } }); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java index acc6d5455c59..ed7466564d68 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurable.java @@ -155,12 +155,7 @@ public class ProjectJdkConfigurable implements UnnamedConfigurable { @Override public void apply() { - DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { - @Override - public void run() { - ProjectRootManager.getInstance(myProject).setProjectSdk(getSelectedProjectJdk()); - } - }); + ProjectRootManager.getInstance(myProject).setProjectSdk(getSelectedProjectJdk()); } @Override diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java index a717cadac336..c03abc08f361 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java @@ -25,8 +25,6 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.project.DumbModePermission; -import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; @@ -119,29 +117,25 @@ public class ProjectJdksConfigurable extends MasterDetailsComponent { @Override public void apply() throws ConfigurationException { final Ref exceptionRef = Ref.create(); - DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { - public void run() { - try { - ProjectJdksConfigurable.super.apply(); - boolean modifiedJdks = false; - for (int i = 0; i < myRoot.getChildCount(); i++) { - final NamedConfigurable configurable = ((MyNode)myRoot.getChildAt(i)).getConfigurable(); - if (configurable.isModified()) { - configurable.apply(); - modifiedJdks = true; - } - } - - if (myProjectJdksModel.isModified() || modifiedJdks) { - myProjectJdksModel.apply(ProjectJdksConfigurable.this); - } - myProjectJdksModel.setProjectSdk(getSelectedJdk()); - } - catch (ConfigurationException e) { - exceptionRef.set(e); + try { + ProjectJdksConfigurable.super.apply(); + boolean modifiedJdks = false; + for (int i = 0; i < myRoot.getChildCount(); i++) { + final NamedConfigurable configurable = ((MyNode)myRoot.getChildAt(i)).getConfigurable(); + if (configurable.isModified()) { + configurable.apply(); + modifiedJdks = true; } } - }); + + if (myProjectJdksModel.isModified() || modifiedJdks) { + myProjectJdksModel.apply(ProjectJdksConfigurable.this); + } + myProjectJdksModel.setProjectSdk(getSelectedJdk()); + } + catch (ConfigurationException e) { + exceptionRef.set(e); + } if (!exceptionRef.isNull()) { throw exceptionRef.get(); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java index fd9e39c1df39..605c9bbd6555 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java @@ -336,21 +336,16 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se } } final Ref exceptionRef = Ref.create(); - DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { - @Override - public void run() { - try { - for (Configurable each : myName2Config) { - if (each.isModified()) { - each.apply(); - } - } - } - catch (ConfigurationException e) { - exceptionRef.set(e); + try { + for (Configurable each : myName2Config) { + if (each.isModified()) { + each.apply(); } } - }); + } + catch (ConfigurationException e) { + exceptionRef.set(e); + } if (!exceptionRef.isNull()) { throw exceptionRef.get(); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java index 6bd996658679..4bdc77b87e59 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java @@ -296,23 +296,18 @@ public class ArtifactsStructureConfigurable extends BaseStructureConfigurable { checkForEmptyAndDuplicatedNames("Artifact", CommonBundle.getErrorTitle(), ArtifactConfigurableBase.class); super.apply(); - DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { - @Override - public void run() { - myPackagingEditorContext.getManifestFilesInfo().saveManifestFiles(); - final ModifiableArtifactModel modifiableModel = myPackagingEditorContext.getActualModifiableModel(); - if (modifiableModel != null) { - new WriteAction() { - @Override - protected void run(@NotNull final Result result) { - modifiableModel.commit(); - } - }.execute(); - myPackagingEditorContext.resetModifiableModel(); + myPackagingEditorContext.getManifestFilesInfo().saveManifestFiles(); + final ModifiableArtifactModel modifiableModel = myPackagingEditorContext.getActualModifiableModel(); + if (modifiableModel != null) { + new WriteAction() { + @Override + protected void run(@NotNull final Result result) { + modifiableModel.commit(); } - } - }); - + }.execute(); + myPackagingEditorContext.resetModifiableModel(); + } + reset(); // TODO: fix to not reset on apply! } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java index 2c6de42b8cf0..158330edb020 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java @@ -820,6 +820,11 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { } return false; } + + @Override + protected boolean canStartInBackground() { + return false; + } }.analyze(); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/packaging/PackagingEditorUtil.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/packaging/PackagingEditorUtil.java deleted file mode 100644 index 87b414050c31..000000000000 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/packaging/PackagingEditorUtil.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2000-2009 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.openapi.roots.ui.configuration.packaging; - -import com.intellij.openapi.project.ProjectBundle; -import com.intellij.openapi.roots.OrderRootType; -import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.packaging.impl.ui.LibraryElementPresentation; -import org.jetbrains.annotations.NotNull; - -/** - * @author nik - */ -public class PackagingEditorUtil { - private PackagingEditorUtil() { - } - - public static String getLibraryItemText(final @NotNull Library library, final boolean includeTableName) { - String name = library.getName(); - VirtualFile[] files = library.getFiles(OrderRootType.CLASSES); - if (name != null) { - return name + (includeTableName ? LibraryElementPresentation.getLibraryTableComment(library) : ""); - } - else if (files.length > 0) { - return files[0].getName() + (includeTableName ? LibraryElementPresentation.getLibraryTableComment(library) : ""); - } - else { - return ProjectBundle.message("library.empty.item"); - } - } - -} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaPsiClassReferenceElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaPsiClassReferenceElement.java index 6a4f29ec6020..9f2bebed0662 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaPsiClassReferenceElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaPsiClassReferenceElement.java @@ -99,8 +99,12 @@ public class JavaPsiClassReferenceElement extends LookupItem implements return psiClass; } - final PsiClass retrieve = (PsiClass)((PsiAnchor)myClass).retrieve(); - assert retrieve != null : myQualifiedName; + PsiAnchor anchor = (PsiAnchor)myClass; + final PsiClass retrieve = (PsiClass)anchor.retrieve(); + if (retrieve == null) { + throw new AssertionError(myQualifiedName + "; anchor=" + anchor + "; diagnostics=" + + (anchor instanceof PsiAnchor.StubIndexReference ? ((PsiAnchor.StubIndexReference)anchor).diagnoseNull() : null)); + } myCache = new WeakReference(retrieve); return retrieve; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index 8aef4d37865d..8dd6432cf6af 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -27,11 +27,11 @@ import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.filters.ElementExtractorFilter; import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.filters.GeneratorFilter; import com.intellij.psi.filters.OrFilter; -import com.intellij.psi.filters.getters.*; +import com.intellij.psi.filters.getters.ExpectedTypesGetter; +import com.intellij.psi.filters.getters.InstanceOfLeftPartTypeGetter; +import com.intellij.psi.filters.getters.JavaMembersGetter; import com.intellij.psi.filters.types.AssignableFromFilter; -import com.intellij.psi.filters.types.AssignableGroupFilter; import com.intellij.psi.filters.types.AssignableToFilter; import com.intellij.psi.impl.source.PsiLabelReference; import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference; @@ -77,9 +77,6 @@ public class JavaSmartCompletionContributor extends CompletionContributor { psiElement().afterLeaf( psiElement().withText(PsiKeyword.THROW)))); static final ElementPattern AFTER_THROW_NEW = psiElement().afterLeaf(psiElement().withText(PsiKeyword.NEW).afterLeaf(PsiKeyword.THROW)); - private static final OrFilter THROWABLE_TYPE_FILTER = new OrFilter( - new GeneratorFilter(AssignableGroupFilter.class, new ThrowsListGetter()), - new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE)); public static final ElementPattern INSIDE_EXPRESSION = or( psiElement().withParent(PsiExpression.class).andNot(psiElement().withParent(PsiLiteralExpression.class)).andNot(psiElement().withParent(PsiMethodReferenceExpression.class)), psiElement().inside(PsiClassObjectAccessExpression.class), @@ -113,13 +110,19 @@ public class JavaSmartCompletionContributor extends CompletionContributor { private static ElementFilter getReferenceFilter(PsiElement element) { //throw new foo if (AFTER_THROW_NEW.accepts(element)) { - return new ElementExtractorFilter(THROWABLE_TYPE_FILTER); + return THROWABLES_FILTER; } //new xxx.yyy if (psiElement().afterLeaf(psiElement().withText(".")).withSuperParent(2, psiElement(PsiNewExpression.class)).accepts(element)) { if (((PsiNewExpression)element.getParent().getParent()).getClassReference() == element.getParent()) { - return new GeneratorFilter(AssignableGroupFilter.class, new ExpectedTypesGetter()); + PsiType[] types = ExpectedTypesGetter.getExpectedTypes(element, false); + return new OrFilter(ContainerUtil.map2Array(types, ElementFilter.class, new Function() { + @Override + public ElementFilter fun(PsiType type) { + return new AssignableFromFilter(type); + } + })); } } @@ -177,7 +180,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { final PsiElement element = parameters.getPosition(); final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset()); if (reference != null) { - final ElementFilter filter = getReferenceFilter(element); + ElementFilter filter = getReferenceFilter(element); if (filter != null) { final List infos = Arrays.asList(getExpectedTypes(parameters)); for (final LookupElement item : completeReference(element, reference, filter, true, false, parameters, result.getPrefixMatcher())) { @@ -187,9 +190,12 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } } else if (INSIDE_TYPECAST_EXPRESSION.accepts(element)) { - for (final LookupElement item : completeReference(element, reference, new GeneratorFilter(AssignableToFilter.class, new CastTypeGetter()), false, true, parameters, - result.getPrefixMatcher())) { - result.addElement(item); + final PsiTypeCastExpression cast = PsiTreeUtil.getContextOfType(element, PsiTypeCastExpression.class, true); + if (cast != null && cast.getCastType() != null) { + filter = new AssignableToFilter(cast.getCastType().getType()); + for (final LookupElement item : completeReference(element, reference, filter, false, true, parameters, result.getPrefixMatcher())) { + result.addElement(item); + } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java index 604e4db19817..ed26f09a0aaf 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java @@ -170,7 +170,7 @@ public class MarkerType { boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); boolean isSuperAbstract = superMethod.hasModifierProperty(PsiModifier.ABSTRACT); - String postfix = MessageFormat.format(" via sub-class {0}", ClassPresentationUtil.getNameForClass(subClass, false)); + String postfix = MessageFormat.format(" via sub-class {0}", ClassPresentationUtil.getNameForClass(subClass, true)); @NonNls String pattern = DaemonBundle.message(isSuperAbstract && !isAbstract ? "method.implements" : "method.overrides") + postfix; diff --git a/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java b/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java index 82142fc63df5..c28218c6dffe 100644 --- a/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/navigation/JavaGotoSuperHandler.java @@ -102,11 +102,11 @@ public class JavaGotoSuperHandler implements PresentableCodeInsightActionHandler final PsiElement containingElement = PsiTreeUtil.getParentOfType(element, PsiFunctionalExpression.class, PsiMember.class); if (containingElement instanceof PsiClass) { presentation.setText(ActionsBundle.actionText("GotoSuperClass")); - presentation.setDescription(ActionsBundle.actionText("GotoSuperClass")); + presentation.setDescription(ActionsBundle.actionDescription("GotoSuperClass")); } else { presentation.setText(ActionsBundle.actionText("GotoSuperMethod")); - presentation.setDescription(ActionsBundle.actionText("GotoSuperMethod")); + presentation.setDescription(ActionsBundle.actionDescription("GotoSuperMethod")); } } diff --git a/java/java-impl/src/com/intellij/psi/filters/GeneratorFilter.java b/java/java-impl/src/com/intellij/psi/filters/GeneratorFilter.java deleted file mode 100644 index e48161748db5..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/GeneratorFilter.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2000-2014 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.psi.filters; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.psi.PsiElement; -import com.intellij.reference.SoftReference; -import com.intellij.util.ReflectionUtil; - -/** - * Created by IntelliJ IDEA. - * User: ik - * Date: 20.03.2003 - * Time: 19:55:15 - * To change this template use Options | File Templates. - */ -public class GeneratorFilter implements ElementFilter{ - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.filters.GeneratorFilter"); - private final ContextGetter myGetter; - private final Class myFilterClass; - - public GeneratorFilter(Class filterClass, ContextGetter getter){ - myFilterClass = filterClass; - myGetter = getter; - } - - @Override - public boolean isClassAcceptable(Class hintClass){ - final ElementFilter filter = getFilter(); - return filter == null || filter.isClassAcceptable(hintClass); - } - - - private SoftReference myCachedElement = new SoftReference(null); - private SoftReference myCachedFilter = new SoftReference(null); - - private ElementFilter getFilter(){ - return myCachedFilter.get(); - } - - private ElementFilter getFilter(PsiElement context){ - ElementFilter filter = myCachedFilter.get(); - if(myCachedElement.get() != context || filter == null){ - filter = generateFilter(context); - myCachedFilter = new SoftReference(filter); - myCachedElement = new SoftReference(context); - } - return filter; - } - - @Override - public boolean isAcceptable(Object element, PsiElement context){ - if(element == null) return false; - final ElementFilter filter = getFilter(context); - return filter != null && filter.isAcceptable(element, context); - } - - private ElementFilter generateFilter(PsiElement context){ - try{ - final ElementFilter elementFilter = (ElementFilter) myFilterClass.newInstance(); - final Object[] initArgument = myGetter.get(context, null); - if(ReflectionUtil.isAssignable(InitializableFilter.class, myFilterClass) && initArgument != null){ - ((InitializableFilter)elementFilter).init(initArgument); - return elementFilter; - } - else{ - LOG.error("Filter initialization failed!"); - } - } - catch(InstantiationException e){ - LOG.error(e); - } - catch(IllegalAccessException e){ - LOG.error(e); - } - return null; - } - -} diff --git a/java/java-impl/src/com/intellij/psi/filters/TextFilter.java b/java/java-impl/src/com/intellij/psi/filters/TextFilter.java index 9ce318e019e1..8264f72c7015 100644 --- a/java/java-impl/src/com/intellij/psi/filters/TextFilter.java +++ b/java/java-impl/src/com/intellij/psi/filters/TextFilter.java @@ -17,7 +17,6 @@ package com.intellij.psi.filters; import com.intellij.psi.PsiType; import com.intellij.psi.xml.XmlTag; -import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls; /** @@ -29,14 +28,6 @@ import org.jetbrains.annotations.NonNls; */ public class TextFilter extends PlainTextFilter { - public TextFilter(){ - myValue = ArrayUtil.EMPTY_STRING_ARRAY; - } - - public TextFilter(@NonNls String value, boolean insensitiveFlag) { - super(value, insensitiveFlag); - } - public TextFilter(@NonNls String value){ super(value); } diff --git a/java/java-impl/src/com/intellij/psi/filters/types/AssignableGroupFilter.java b/java/java-impl/src/com/intellij/psi/filters/types/AssignableGroupFilter.java deleted file mode 100644 index ffbef70e7c50..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/types/AssignableGroupFilter.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2000-2009 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.psi.filters.types; - -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiSubstitutor; -import com.intellij.psi.PsiType; -import com.intellij.psi.filters.FalseFilter; -import com.intellij.psi.filters.InitializableFilter; -import com.intellij.psi.filters.OrFilter; - -/** - * Created by IntelliJ IDEA. - * User: ik - * Date: 20.03.2003 - * Time: 21:27:25 - * To change this template use Options | File Templates. - */ -public class AssignableGroupFilter extends OrFilter implements InitializableFilter{ - - @Override - public void init(Object[] classes){ - for (Object aClass : classes) { - if (aClass instanceof PsiClass) { - final PsiClass psiClass = (PsiClass)aClass; - PsiType type = JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory().createType(psiClass, PsiSubstitutor.EMPTY); - addFilter(new AssignableFromFilter(type)); - } - if (aClass instanceof PsiType) { - addFilter(new AssignableFromFilter((PsiType)aClass)); - } - } - addFilter(new FalseFilter()); - } -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/filters/types/AssignableToFilter.java b/java/java-impl/src/com/intellij/psi/filters/types/AssignableToFilter.java index c93a8c1152cd..10f9b49ea8be 100644 --- a/java/java-impl/src/com/intellij/psi/filters/types/AssignableToFilter.java +++ b/java/java-impl/src/com/intellij/psi/filters/types/AssignableToFilter.java @@ -15,15 +15,13 @@ */ package com.intellij.psi.filters.types; -import com.intellij.psi.*; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.filters.FilterUtil; -import com.intellij.psi.filters.InitializableFilter; -import com.intellij.psi.filters.OrFilter; import com.intellij.psi.infos.CandidateInfo; - -import java.util.ArrayList; -import java.util.List; +import org.jetbrains.annotations.NotNull; /** * Created by IntelliJ IDEA. @@ -32,36 +30,13 @@ import java.util.List; * Time: 20:53:38 * To change this template use Options | File Templates. */ -public class AssignableToFilter implements InitializableFilter{ - private PsiType myType = null; - private ElementFilter myFilter = null; +public class AssignableToFilter implements ElementFilter { + private final PsiType myType; - public AssignableToFilter(PsiType type){ + public AssignableToFilter(@NotNull PsiType type){ myType = type; } - public AssignableToFilter(){} - - @Override - public void init(Object[] type){ - myFilter = new OrFilter(); - final List filters = new ArrayList(); - for (final Object o : type) { - PsiType currentType = null; - if (o instanceof PsiType) { - currentType = (PsiType)o; - } - else if (o instanceof PsiClass) { - final PsiClass psiClass = (PsiClass)o; - currentType = JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory().createType(psiClass); - } - if (currentType != null) { - filters.add(new AssignableToFilter(currentType)); - } - } - myFilter = new OrFilter(filters.toArray(new ElementFilter[filters.size()])); - } - @Override public boolean isClassAcceptable(Class hintClass){ return true; @@ -69,31 +44,21 @@ public class AssignableToFilter implements InitializableFilter{ @Override public boolean isAcceptable(Object element, PsiElement context){ - if(myType != null){ - if(element == null) return false; - if (element instanceof PsiType) return myType.isAssignableFrom((PsiType) element); - PsiSubstitutor substitutor = null; - if(element instanceof CandidateInfo){ - final CandidateInfo info = (CandidateInfo)element; - substitutor = info.getSubstitutor(); - element = info.getElement(); - } + if(element == null) return false; + if (element instanceof PsiType) return myType.isAssignableFrom((PsiType) element); + PsiSubstitutor substitutor = null; + if(element instanceof CandidateInfo){ + final CandidateInfo info = (CandidateInfo)element; + substitutor = info.getSubstitutor(); + element = info.getElement(); + } - PsiType typeByElement = FilterUtil.getTypeByElement((PsiElement)element, context); - if(substitutor != null) typeByElement = substitutor.substitute(typeByElement); - return typeByElement != null && typeByElement.isAssignableFrom(myType) && !typeByElement.equals(myType); - } - else if(myFilter != null){ - if(element == null) return false; - return myFilter.isAcceptable(element, context); - } - else return false; + PsiType typeByElement = FilterUtil.getTypeByElement((PsiElement)element, context); + if(substitutor != null) typeByElement = substitutor.substitute(typeByElement); + return typeByElement != null && typeByElement.isAssignableFrom(myType) && !typeByElement.equals(myType); } public String toString(){ - if(myType != null) - return "assignable-to(" + myType + ")"; - else if(myFilter != null) return myFilter.toString(); - return "uninitialized-equals-filter"; + return "assignable-to(" + myType + ")"; } } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/SyntheticBlockBuilder.java b/java/java-impl/src/com/intellij/psi/formatter/java/CallChunkBlockBuilder.java similarity index 94% rename from java/java-impl/src/com/intellij/psi/formatter/java/SyntheticBlockBuilder.java rename to java/java-impl/src/com/intellij/psi/formatter/java/CallChunkBlockBuilder.java index 797c04e2846b..586c38f7b48b 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/SyntheticBlockBuilder.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/CallChunkBlockBuilder.java @@ -24,22 +24,21 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.JavaTokenType; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; -import com.intellij.psi.formatter.java.SyntheticCodeBlock; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; -import static com.intellij.psi.formatter.java.AbstractJavaBlock.*; +import static com.intellij.psi.formatter.java.AbstractJavaBlock.newJavaBlock; -public class SyntheticBlockBuilder { +public class CallChunkBlockBuilder { private final CommonCodeStyleSettings mySettings; private final CommonCodeStyleSettings.IndentOptions myIndentSettings; private final JavaCodeStyleSettings myJavaSettings; - public SyntheticBlockBuilder(@NotNull CommonCodeStyleSettings settings, @NotNull JavaCodeStyleSettings javaSettings) { + public CallChunkBlockBuilder(@NotNull CommonCodeStyleSettings settings, @NotNull JavaCodeStyleSettings javaSettings) { mySettings = settings; myIndentSettings = settings.getIndentOptions(); myJavaSettings = javaSettings; diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/ChainMethodCallsBlockBuilder.java b/java/java-impl/src/com/intellij/psi/formatter/java/ChainMethodCallsBlockBuilder.java index e5e3ed668fce..e80774e7d312 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/ChainMethodCallsBlockBuilder.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/ChainMethodCallsBlockBuilder.java @@ -21,6 +21,7 @@ import com.intellij.formatting.Indent; import com.intellij.formatting.Wrap; import com.intellij.lang.ASTNode; import com.intellij.psi.JavaTokenType; +import com.intellij.psi.PsiComment; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; import com.intellij.psi.impl.source.tree.JavaElementType; @@ -74,7 +75,7 @@ class ChainMethodCallsBlockBuilder { for (int i = 0; i < methodCall.size(); i++) { ChainedCallChunk currentCallChunk = methodCall.get(i); - if (isMethodCall(currentCallChunk)) { + if (isMethodCall(currentCallChunk) || isComment(currentCallChunk)) { if (myWrap == null) myWrap = createCallChunkWrap(i, methodCall); if (myChainedCallsAlignment == null) @@ -85,13 +86,21 @@ class ChainMethodCallsBlockBuilder { myChainedCallsAlignment = null; } - SyntheticBlockBuilder builder = new SyntheticBlockBuilder(mySettings, myJavaSettings); + CallChunkBlockBuilder builder = new CallChunkBlockBuilder(mySettings, myJavaSettings); blocks.add(builder.create(currentCallChunk.nodes, myWrap, myChainedCallsAlignment)); } return blocks; } + private static boolean isComment(ChainedCallChunk chunk) { + List nodes = chunk.nodes; + if (nodes.size() == 1) { + return nodes.get(0).getPsi() instanceof PsiComment; + } + return false; + } + private Wrap createCallChunkWrap(int chunkIndex, @NotNull List methodCall) { if (mySettings.WRAP_FIRST_METHOD_IN_CALL_CHAIN) { ChainedCallChunk next = chunkIndex + 1 < methodCall.size() ? methodCall.get(chunkIndex + 1) : null; @@ -119,7 +128,7 @@ class ChainMethodCallsBlockBuilder { List current = new ArrayList(); for (ASTNode node : nodes) { - if (node.getElementType() == JavaTokenType.DOT) { + if (node.getElementType() == JavaTokenType.DOT || node.getPsi() instanceof PsiComment) { result.add(new ChainedCallChunk(current)); current = new ArrayList(); } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/SyntheticCodeBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/SyntheticCodeBlock.java index bdfb015a4ad8..7cc75fd34bf5 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/SyntheticCodeBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/SyntheticCodeBlock.java @@ -140,7 +140,12 @@ public class SyntheticCodeBlock implements Block, JavaBlock{ if (myChildAttributes != null) { return myChildAttributes; } else { - return new ChildAttributes(getIndent(), null); + Alignment alignment = null; + if (mySubBlocks.size() > newChildIndex) { + Block block = mySubBlocks.get(newChildIndex); + alignment = block.getAlignment(); + } + return new ChildAttributes(getIndent(), alignment); } } diff --git a/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java b/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java index a10f13120ef4..804637a35db8 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java @@ -343,6 +343,12 @@ public class InlineUtil { PsiElement resolved = resolveResult.getElement(); if (resolved instanceof PsiTypeParameter) { PsiType newType = resolveResult.getSubstitutor().putAll(substitutor).substitute((PsiTypeParameter)resolved); + if (newType instanceof PsiCapturedWildcardType) { + newType = ((PsiCapturedWildcardType)newType).getUpperBound(); + } + if (newType instanceof PsiWildcardType) { + newType = ((PsiWildcardType)newType).getBound(); + } if (newType == null) { newType = PsiType.getJavaLangObject(resolved.getManager(), resolved.getResolveScope()); } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java index 5ab4cf678da7..ba88fcba0696 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java @@ -64,7 +64,8 @@ public class PsiCapturedWildcardType extends PsiType.Stub { } final PsiCapturedWildcardType captured = (PsiCapturedWildcardType)o; - if (!myContext.equals(captured.myContext)) { + final PsiManager manager = myContext.getManager(); + if (!manager.areElementsEquivalent(myContext, captured.myContext)) { return false; } @@ -72,7 +73,8 @@ public class PsiCapturedWildcardType extends PsiType.Stub { return false; } - if ((myContext instanceof PsiReferenceExpression || myContext instanceof PsiMethodCallExpression) && !Comparing.equal(myParameter, captured.myParameter)) { + if ((myContext instanceof PsiReferenceExpression || myContext instanceof PsiMethodCallExpression) && + !manager.areElementsEquivalent(myParameter, captured.myParameter)) { return false; } diff --git a/java/java-tests/testData/codeInsight/clsHighlighting/libs/CaptureContext-sources.jar b/java/java-tests/testData/codeInsight/clsHighlighting/libs/CaptureContext-sources.jar new file mode 100644 index 000000000000..f4c861ecfe45 Binary files /dev/null and b/java/java-tests/testData/codeInsight/clsHighlighting/libs/CaptureContext-sources.jar differ diff --git a/java/java-tests/testData/codeInsight/clsHighlighting/libs/CaptureContext.jar b/java/java-tests/testData/codeInsight/clsHighlighting/libs/CaptureContext.jar new file mode 100644 index 000000000000..b9c545ae08e5 Binary files /dev/null and b/java/java-tests/testData/codeInsight/clsHighlighting/libs/CaptureContext.jar differ diff --git a/java/java-tests/testData/refactoring/inlineMethod/SubstitutionForWildcards.java b/java/java-tests/testData/refactoring/inlineMethod/SubstitutionForWildcards.java new file mode 100644 index 000000000000..7c5960100438 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/SubstitutionForWildcards.java @@ -0,0 +1,16 @@ +interface Pair { + A get(); +} + +class B { + void f(Pair p) { + V v = p.get(); + } + + { + Pair p = null; + f(p); + } +} + + diff --git a/java/java-tests/testData/refactoring/inlineMethod/SubstitutionForWildcards.java.after b/java/java-tests/testData/refactoring/inlineMethod/SubstitutionForWildcards.java.after new file mode 100644 index 000000000000..1bbd347e20c6 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/SubstitutionForWildcards.java.after @@ -0,0 +1,13 @@ +interface Pair { + A get(); +} + +class B { + + { + Pair p = null; + String v = p.get(); + } +} + + diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java index 8383550b3e5c..55741e1f36a5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java @@ -15,13 +15,33 @@ */ package com.intellij.codeInsight; +import com.intellij.openapi.project.Project; import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.source.PsiFileImpl; +import com.intellij.psi.search.GlobalSearchScope; public class ClsGenerics18HighlightingTest extends ClsGenericsHighlightingTest { public void testIDEA121866() { doTest(); } public void testIDEA127714() { doTest(); } + public void testCaptureContext() { + String name = getTestName(false); + addLibrary(name + ".jar", name + "-sources.jar"); + Project project = myFixture.getProject(); + PsiClass aClass = JavaPsiFacade.getInstance(project).findClass("a.Pair", GlobalSearchScope.allScope(project)); + assertNotNull(aClass); + PsiFile containingFile = aClass.getContainingFile(); + PsiElement navigationElement = containingFile.getNavigationElement(); + assertInstanceOf(navigationElement, PsiFileImpl.class); + myFixture.openFileInEditor(((PsiFile)navigationElement).getVirtualFile()); + myFixture.checkHighlighting(); + } + @Override protected LanguageLevel getLanguageLevel() { return LanguageLevel.JDK_1_8; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenericsHighlightingTest.java index b656156df36f..fb0027867dc5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenericsHighlightingTest.java @@ -29,6 +29,7 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.testFramework.IdeaTestCase; +import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.testFramework.fixtures.*; @@ -36,7 +37,7 @@ import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; public abstract class ClsGenericsHighlightingTest extends UsefulTestCase { - private CodeInsightTestFixture myFixture; + protected CodeInsightTestFixture myFixture; private Module myModule; @Override @@ -47,6 +48,7 @@ public abstract class ClsGenericsHighlightingTest extends UsefulTestCase { myFixture.setTestDataPath(PathManagerEx.getTestDataPath() + "/codeInsight/clsHighlighting"); JavaModuleFixtureBuilder builder = projectBuilder.addModule(JavaModuleFixtureBuilder.class); builder.setLanguageLevel(getLanguageLevel()); + builder.addJdk(IdeaTestUtil.getMockJdk18Path().getPath()); myFixture.setUp(); myModule = builder.getFixture().getModule(); } @@ -72,7 +74,7 @@ public abstract class ClsGenericsHighlightingTest extends UsefulTestCase { myFixture.checkHighlighting(); } - private void addLibrary(@NotNull final String... libraryPath) { + protected void addLibrary(@NotNull final String... libraryPath) { ModuleRootModificationUtil.updateModel(myModule, new Consumer() { @Override public void consume(ModifiableRootModel model) { @@ -95,7 +97,8 @@ public abstract class ClsGenericsHighlightingTest extends UsefulTestCase { assertNotNull(libJarLocal); VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(libJarLocal); assertNotNull(jarRoot); - libraryModel.addRoot(jarRoot, OrderRootType.CLASSES); + libraryModel.addRoot(jarRoot, jarRoot.getName().contains("-sources") ? OrderRootType.SOURCES + : OrderRootType.CLASSES); } libraryModel.commit(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GutterIntentionsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GutterIntentionsTest.java index c162b6485491..ce67f1b1aa7d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GutterIntentionsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GutterIntentionsTest.java @@ -15,27 +15,39 @@ */ package com.intellij.codeInsight.daemon; +import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.ide.highlighter.JavaFileType; -import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import java.util.List; /** * @author Dmitry Avdeev */ -public class GutterIntentionsTest extends LightPlatformCodeInsightFixtureTestCase { +public class GutterIntentionsTest extends LightCodeInsightFixtureTestCase { public void testEmptyIntentions() throws Exception { myFixture.configureByText(JavaFileType.INSTANCE, "class Foo {\n" + " private String test() {\n" + " return null;\n" + - " }"); + " }" + + "}"); + myFixture.findAllGutters(); List intentions = myFixture.getAvailableIntentions(); assertEmpty(intentions); } - @Override - protected boolean isWriteActionRequired() { - return false; + public void testOptions() throws Exception { + myFixture.configureByText(JavaFileType.INSTANCE, "public class Foo {\n" + + " public static void main(String[] args) {}" + + "}"); + assertEquals(1, myFixture.findGuttersAtCaret().size()); + + ShowIntentionsPass.IntentionsInfo intentions = new ShowIntentionsPass.IntentionsInfo(); + ShowIntentionsPass.getActionsToShow(getEditor(), getFile(), intentions, -1); + assertEquals(1, intentions.guttersToShow.size()); + List options = intentions.guttersToShow.get(0).getOptions(myFixture.getElementAtCaret(), getEditor()); + assertNotNull(options); + assertNotEmpty(options); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy index dc4fc95fc78a..2a4df962e8d7 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy @@ -14,6 +14,7 @@ * limitations under the License. */ package com.intellij.codeInsight.template + import com.intellij.JavaTestUtil import com.intellij.codeInsight.CodeInsightSettings import com.intellij.codeInsight.lookup.Lookup @@ -36,6 +37,7 @@ import com.intellij.util.ui.UIUtil import org.jetbrains.annotations.NotNull import static com.intellij.codeInsight.template.Template.Property.USE_STATIC_IMPORT_IF_POSSIBLE + /** * @author spleaner */ @@ -288,7 +290,7 @@ class Foo { public void testToar() throws Throwable { configure(); startTemplate("toar", "other") - state.gotoEnd(); + state.gotoEnd(false); checkResult(); } @@ -954,6 +956,39 @@ class Foo { return calculateResult(params, context) } } + + public void "test add new line on enter outside editing variable"() { + myFixture.configureByText 'a.java', """ +class Foo {{ + +}} +""" + myFixture.type 'soutv\tabc' + myFixture.editor.caretModel.moveCaretRelatively(3, 0, false, false, false) + myFixture.type '\n' + myFixture.checkResult """ +class Foo {{ + System.out.println("true = " + abc); + +}} +""" + } + + public void "test type tab character on tab outside editing variable"() { + myFixture.configureByText 'a.java', """ +class Foo {{ + +}} +""" + myFixture.type 'soutv\tabc' + myFixture.editor.caretModel.moveCaretRelatively(3, 0, false, false, false) + myFixture.type '\t' + myFixture.checkResult """ +class Foo {{ + System.out.println("true = " + abc); +}} +""" + } public void "test multicaret expanding with space"() { myFixture.configureByText "a.java", """\ diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaEnterActionTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaEnterActionTest.java index fd6ba563d2c0..ec8f9de21ace 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaEnterActionTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaEnterActionTest.java @@ -16,7 +16,9 @@ package com.intellij.psi.formatter.java; import com.intellij.codeInsight.AbstractEnterActionTestCase; +import com.intellij.lang.java.JavaLanguage; import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; import java.io.IOException; @@ -101,4 +103,55 @@ public class JavaEnterActionTest extends AbstractEnterActionTestCase { " \n" + "}"); } + + public void testEnter_BetweenChainedMethodCalls() throws IOException { + doTextTest("java", + "class T {\n" + + " public void main() {\n" + + " ActionBarPullToRefresh.from(getActivity())\n" + + " .theseChildrenArePullable(eventsListView)\n" + + " .listener(this)\n" + + " .useViewDelegate(StickyListHeadersListView.class, new AbsListViewDelegate())\n" + + " .setup(mPullToRefreshLayout);\n" + + " }\n" + + "}", + "class T {\n" + + " public void main() {\n" + + " ActionBarPullToRefresh.from(getActivity())\n" + + " .theseChildrenArePullable(eventsListView)\n" + + " .listener(this)\n" + + " .useViewDelegate(StickyListHeadersListView.class, new AbsListViewDelegate())\n" + + " \n" + + " .setup(mPullToRefreshLayout);\n" + + " }\n" + + "}"); + } + + public void testEnter_BetweenAlignedChainedMethodCalls() throws IOException { + CodeStyleSettings settings = getCodeStyleSettings(); + CommonCodeStyleSettings javaCommon = settings.getCommonSettings(JavaLanguage.INSTANCE); + javaCommon.ALIGN_MULTILINE_CHAINED_METHODS = true; + setCodeStyleSettings(settings); + + doTextTest("java", + "class T {\n" + + " public void main() {\n" + + " ActionBarPullToRefresh.from(getActivity())\n" + + " .theseChildrenArePullable(eventsListView)\n" + + " .listener(this)\n" + + " .useViewDelegate(StickyListHeadersListView.class, new AbsListViewDelegate())\n" + + " .setup(mPullToRefreshLayout);\n" + + " }\n" + + "}", + "class T {\n" + + " public void main() {\n" + + " ActionBarPullToRefresh.from(getActivity())\n" + + " .theseChildrenArePullable(eventsListView)\n" + + " .listener(this)\n" + + " .useViewDelegate(StickyListHeadersListView.class, new AbsListViewDelegate())\n" + + " \n" + + " .setup(mPullToRefreshLayout);\n" + + " }\n" + + "}"); + } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java index c45fa4cfdbdd..9e8c2979df7d 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java @@ -768,4 +768,48 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest { "}\n" ); } + + public void test_AlignComments_BetweenChainedMethodCalls() { + getSettings().ALIGN_MULTILINE_CHAINED_METHODS = true; + doMethodTest( + "ActionBarPullToRefresh.from(getActivity())\n" + + " // Mark the ListView as pullable\n" + + " .theseChildrenArePullable(eventsListView)\n" + + " // Set the OnRefreshListener\n" + + " .listener(this)\n" + + " // Use the AbsListView delegate for StickyListHeadersListView\n" + + " .useViewDelegate(StickyListHeadersListView.class, new AbsListViewDelegate())\n" + + " // Finally commit the setup to our PullToRefreshLayout\n" + + " .setup(mPullToRefreshLayout);", + "ActionBarPullToRefresh.from(getActivity())\n" + + " // Mark the ListView as pullable\n" + + " .theseChildrenArePullable(eventsListView)\n" + + " // Set the OnRefreshListener\n" + + " .listener(this)\n" + + " // Use the AbsListView delegate for StickyListHeadersListView\n" + + " .useViewDelegate(StickyListHeadersListView.class, new AbsListViewDelegate())\n" + + " // Finally commit the setup to our PullToRefreshLayout\n" + + " .setup(mPullToRefreshLayout);" + ); + } + + public void test_AlignComments_2() { + getSettings().ALIGN_MULTILINE_CHAINED_METHODS = true; + doClassTest( + "public String returnWithBuilder2() {\n" + + " return MoreObjects\n" + + " .toStringHelper(this)\n" + + " .add(\"value\", value)\n" + + " // comment\n" + + " .toString();\n" + + " }", + "public String returnWithBuilder2() {\n" + + " return MoreObjects\n" + + " .toStringHelper(this)\n" + + " .add(\"value\", value)\n" + + " // comment\n" + + " .toString();\n" + + "}" + ); + } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java index 59081bafecaa..032838650c89 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java @@ -185,6 +185,10 @@ public class InlineMethodTest extends LightRefactoringTestCase { doTest(); } + public void testSubstitutionForWildcards() throws Exception { + doTest(); + } + public void testParamNameConflictsWithLocalVar() throws Exception { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java b/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java index c1273eb10eac..cddb960084d4 100644 --- a/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java +++ b/java/java-tests/testSrc/com/intellij/roots/RootsChangedTest.java @@ -126,25 +126,22 @@ public class RootsChangedTest extends ModuleTestCase { public void testEditLibraryForModuleLoadFromXml() throws IOException { final File tempDirectory = createTempDirectory(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - File moduleFile = - PathManagerEx.findFileUnderProjectHome("java/java-tests/testData/moduleRootManager/rootsChanged/emptyModule/a.iml", RootsChangedTest.this.getClass()); - Module a = loadModule(moduleFile, true); - assertEventsCount(1); + ApplicationManager.getApplication().runWriteAction(() -> { + File moduleFile = + PathManagerEx.findFileUnderProjectHome("java/java-tests/testData/moduleRootManager/rootsChanged/emptyModule/a.iml", RootsChangedTest.this.getClass()); + Module a = loadModule(moduleFile, true); + assertEventsCount(1); - final Sdk jdk = IdeaTestUtil.getMockJdk17(); - ProjectJdkTable.getInstance().addJdk(jdk); - assertEventsCount(0); + final Sdk jdk = IdeaTestUtil.getMockJdk17(); + ProjectJdkTable.getInstance().addJdk(jdk); + assertEventsCount(0); - ModuleRootModificationUtil.setModuleSdk(a, jdk); - assertEventsCount(1); + ModuleRootModificationUtil.setModuleSdk(a, jdk); + assertEventsCount(1); - final SdkModificator sdkModificator = jdk.getSdkModificator(); - sdkModificator.addRoot(getVirtualFile(tempDirectory), OrderRootType.CLASSES); - sdkModificator.commitChanges(); - } + final SdkModificator sdkModificator = jdk.getSdkModificator(); + sdkModificator.addRoot(getVirtualFile(tempDirectory), OrderRootType.CLASSES); + sdkModificator.commitChanges(); }); assertEventsCount(1); @@ -152,77 +149,71 @@ public class RootsChangedTest extends ModuleTestCase { public void testModuleJdkEditing() throws Exception { final File tempDirectory = createTempDirectory(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - final Module moduleA = createModule("a.iml"); - final Module moduleB = createModule("b.iml"); - assertEventsCount(2); + ApplicationManager.getApplication().runWriteAction(() -> { + final Module moduleA = createModule("a.iml"); + final Module moduleB = createModule("b.iml"); + assertEventsCount(2); - final Sdk jdk = IdeaTestUtil.getMockJdk17(); - ProjectJdkTable.getInstance().addJdk(jdk); - assertEventsCount(0); + final Sdk jdk = IdeaTestUtil.getMockJdk17(); + ProjectJdkTable.getInstance().addJdk(jdk); + assertEventsCount(0); - final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel(); - final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel(); - rootModelA.setSdk(jdk); - rootModelB.setSdk(jdk); - ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB}; - ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel()); - assertEventsCount(1); + final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel(); + final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel(); + rootModelA.setSdk(jdk); + rootModelB.setSdk(jdk); + ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB}; + ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel()); + assertEventsCount(1); - final SdkModificator sdkModificator = jdk.getSdkModificator(); - sdkModificator.addRoot(getVirtualFile(tempDirectory), OrderRootType.CLASSES); - sdkModificator.commitChanges(); - assertEventsCount(1); + final SdkModificator sdkModificator = jdk.getSdkModificator(); + sdkModificator.addRoot(getVirtualFile(tempDirectory), OrderRootType.CLASSES); + sdkModificator.commitChanges(); + assertEventsCount(1); - ProjectJdkTable.getInstance().removeJdk(jdk); - assertEventsCount(1); - } + ProjectJdkTable.getInstance().removeJdk(jdk); + assertEventsCount(1); }); } public void testInheritedJdkEditing() throws Exception { final File tempDirectory = createTempDirectory(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - final Module moduleA = createModule("a.iml"); - final Module moduleB = createModule("b.iml"); - assertEventsCount(2); + ApplicationManager.getApplication().runWriteAction(() -> { + final Module moduleA = createModule("a.iml"); + final Module moduleB = createModule("b.iml"); + assertEventsCount(2); - final Sdk jdk = IdeaTestUtil.getMockJdk17("AAA"); - ProjectJdkTable.getInstance().addJdk(jdk); - assertEventsCount(0); + final Sdk jdk = IdeaTestUtil.getMockJdk17("AAA"); + ProjectJdkTable.getInstance().addJdk(jdk); + assertEventsCount(0); - final Sdk jdkBBB = IdeaTestUtil.getMockJdk17("BBB"); - ProjectJdkTable.getInstance().addJdk(jdk); - assertEventsCount(0); + final Sdk jdkBBB = IdeaTestUtil.getMockJdk17("BBB"); + ProjectJdkTable.getInstance().addJdk(jdk); + assertEventsCount(0); - ProjectRootManager.getInstance(myProject).setProjectSdk(jdkBBB); - assertEventsCount(0); + ProjectRootManager.getInstance(myProject).setProjectSdk(jdkBBB); + assertEventsCount(0); - final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel(); - final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel(); - rootModelA.inheritSdk(); - rootModelB.inheritSdk(); - ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB}; - if (rootModels.length > 0) { - ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel()); - } - assertEventsCount(1); - - ProjectRootManager.getInstance(myProject).setProjectSdk(jdk); - assertEventsCount(1); - - final SdkModificator sdkModificator = jdk.getSdkModificator(); - sdkModificator.addRoot(getVirtualFile(tempDirectory), OrderRootType.CLASSES); - sdkModificator.commitChanges(); - assertEventsCount(1); - - ProjectJdkTable.getInstance().removeJdk(jdk); - assertEventsCount(1); + final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel(); + final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel(); + rootModelA.inheritSdk(); + rootModelB.inheritSdk(); + ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB}; + if (rootModels.length > 0) { + ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel()); } + assertEventsCount(1); + + ProjectRootManager.getInstance(myProject).setProjectSdk(jdk); + assertEventsCount(1); + + final SdkModificator sdkModificator = jdk.getSdkModificator(); + sdkModificator.addRoot(getVirtualFile(tempDirectory), OrderRootType.CLASSES); + sdkModificator.commitChanges(); + assertEventsCount(1); + + ProjectJdkTable.getInstance().removeJdk(jdk); + assertEventsCount(1); }); } @@ -231,102 +222,96 @@ public class RootsChangedTest extends ModuleTestCase { final Module moduleB = createModule("b.iml"); assertEventsCount(2); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - final Library libraryA = libraryTable.createLibrary("A"); - final Library.ModifiableModel libraryModifiableModel = libraryA.getModifiableModel(); - libraryModifiableModel.addRoot("file:///a", OrderRootType.CLASSES); - libraryModifiableModel.commit(); - assertEventsCount(0); + ApplicationManager.getApplication().runWriteAction(() -> { + final Library libraryA = libraryTable.createLibrary("A"); + final Library.ModifiableModel libraryModifiableModel = libraryA.getModifiableModel(); + libraryModifiableModel.addRoot("file:///a", OrderRootType.CLASSES); + libraryModifiableModel.commit(); + assertEventsCount(0); - final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel(); - final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel(); - rootModelA.addLibraryEntry(libraryA); - rootModelB.addLibraryEntry(libraryA); - rootModelA.addInvalidLibrary("Q", libraryTable.getTableLevel()); - rootModelB.addInvalidLibrary("Q", libraryTable.getTableLevel()); - ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB}; - if (rootModels.length > 0) { - ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel()); - } - assertEventsCount(1); + final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel(); + final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel(); + rootModelA.addLibraryEntry(libraryA); + rootModelB.addLibraryEntry(libraryA); + rootModelA.addInvalidLibrary("Q", libraryTable.getTableLevel()); + rootModelB.addInvalidLibrary("Q", libraryTable.getTableLevel()); + ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB}; + if (rootModels.length > 0) { + ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel()); + } + assertEventsCount(1); - final Library.ModifiableModel libraryModifiableModel2 = libraryA.getModifiableModel(); - final File tmpDir; - try { - tmpDir = FileUtil.createTempDirectory(getTestName(true), ""); - } - catch (IOException e) { - throw new RuntimeException(e); - } + final Library.ModifiableModel libraryModifiableModel2 = libraryA.getModifiableModel(); + final File tmpDir; + try { + tmpDir = FileUtil.createTempDirectory(getTestName(true), ""); + } + catch (IOException e) { + throw new RuntimeException(e); + } - try { - final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tmpDir); - assertNotNull(file); + try { + final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tmpDir); + assertNotNull(file); - libraryModifiableModel2.addRoot(file.getUrl(), OrderRootType.CLASSES); - libraryModifiableModel2.commit(); - assertEventsCount(1); - } - finally { - FileUtil.delete(tmpDir); - } - - libraryTable.removeLibrary(libraryA); - assertEventsCount(1); - - final Library libraryQ = libraryTable.createLibrary("Q"); - assertEventsCount(1); - - libraryTable.removeLibrary(libraryQ); + libraryModifiableModel2.addRoot(file.getUrl(), OrderRootType.CLASSES); + libraryModifiableModel2.commit(); assertEventsCount(1); } + finally { + FileUtil.delete(tmpDir); + } + + libraryTable.removeLibrary(libraryA); + assertEventsCount(1); + + final Library libraryQ = libraryTable.createLibrary("Q"); + assertEventsCount(1); + + libraryTable.removeLibrary(libraryQ); + assertEventsCount(1); }); } private void verifyLibraryTableEditingInUncommittedModel(final LibraryTable libraryTable) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - final Module moduleA = createModule("a.iml"); - final Module moduleB = createModule("b.iml"); - assertEventsCount(2); + ApplicationManager.getApplication().runWriteAction(() -> { + final Module moduleA = createModule("a.iml"); + final Module moduleB = createModule("b.iml"); + assertEventsCount(2); - final Library libraryA = libraryTable.createLibrary("A"); - final Library.ModifiableModel libraryModifiableModel = libraryA.getModifiableModel(); - libraryModifiableModel.addRoot("file:///a", OrderRootType.CLASSES); - libraryModifiableModel.commit(); - assertEventsCount(0); + final Library libraryA = libraryTable.createLibrary("A"); + final Library.ModifiableModel libraryModifiableModel = libraryA.getModifiableModel(); + libraryModifiableModel.addRoot("file:///a", OrderRootType.CLASSES); + libraryModifiableModel.commit(); + assertEventsCount(0); - final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel(); - final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel(); - rootModelA.addLibraryEntry(libraryA); - rootModelB.addLibraryEntry(libraryA); - final Library.ModifiableModel libraryModifiableModel2 = libraryA.getModifiableModel(); - libraryModifiableModel2.addRoot("file:///b", OrderRootType.CLASSES); - libraryModifiableModel2.commit(); - assertEventsCount(0); + final ModifiableRootModel rootModelA = ModuleRootManager.getInstance(moduleA).getModifiableModel(); + final ModifiableRootModel rootModelB = ModuleRootManager.getInstance(moduleB).getModifiableModel(); + rootModelA.addLibraryEntry(libraryA); + rootModelB.addLibraryEntry(libraryA); + final Library.ModifiableModel libraryModifiableModel2 = libraryA.getModifiableModel(); + libraryModifiableModel2.addRoot("file:///b", OrderRootType.CLASSES); + libraryModifiableModel2.commit(); + assertEventsCount(0); - libraryTable.removeLibrary(libraryA); - assertEventsCount(0); + libraryTable.removeLibrary(libraryA); + assertEventsCount(0); - rootModelA.addInvalidLibrary("Q", libraryTable.getTableLevel()); - rootModelB.addInvalidLibrary("Q", libraryTable.getTableLevel()); - assertEventsCount(0); + rootModelA.addInvalidLibrary("Q", libraryTable.getTableLevel()); + rootModelB.addInvalidLibrary("Q", libraryTable.getTableLevel()); + assertEventsCount(0); - final Library libraryQ = libraryTable.createLibrary("Q"); - assertEventsCount(0); + final Library libraryQ = libraryTable.createLibrary("Q"); + assertEventsCount(0); - ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB}; - if (rootModels.length > 0) { - ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel()); - } - assertEventsCount(1); - - libraryTable.removeLibrary(libraryQ); - assertEventsCount(1); + ModifiableRootModel[] rootModels = new ModifiableRootModel[]{rootModelA, rootModelB}; + if (rootModels.length > 0) { + ModifiableModelCommitter.multiCommit(rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel()); } + assertEventsCount(1); + + libraryTable.removeLibrary(libraryQ); + assertEventsCount(1); }); } diff --git a/lib/cucumber-core-1.2.2.jar b/lib/cucumber-core-1.2.4.jar similarity index 53% rename from lib/cucumber-core-1.2.2.jar rename to lib/cucumber-core-1.2.4.jar index e47c15323e6a..d5920945f9ac 100644 Binary files a/lib/cucumber-core-1.2.2.jar and b/lib/cucumber-core-1.2.4.jar differ diff --git a/lib/cucumber-java-1.2.2.jar b/lib/cucumber-java-1.2.2.jar deleted file mode 100644 index d39de623cf6c..000000000000 Binary files a/lib/cucumber-java-1.2.2.jar and /dev/null differ diff --git a/lib/cucumber-java-1.2.4.jar b/lib/cucumber-java-1.2.4.jar new file mode 100644 index 000000000000..b9da4ab20d9f Binary files /dev/null and b/lib/cucumber-java-1.2.4.jar differ diff --git a/lib/cucumber-java8-1.2.2.jar b/lib/cucumber-java8-1.2.4.jar similarity index 93% rename from lib/cucumber-java8-1.2.2.jar rename to lib/cucumber-java8-1.2.4.jar index 09c30ec3de52..c49c190c41ea 100644 Binary files a/lib/cucumber-java8-1.2.2.jar and b/lib/cucumber-java8-1.2.4.jar differ diff --git a/platform/analysis-impl/src/com/intellij/packageDependencies/BackwardDependenciesBuilder.java b/platform/analysis-impl/src/com/intellij/packageDependencies/BackwardDependenciesBuilder.java index 828096c4930f..6529a73770b2 100644 --- a/platform/analysis-impl/src/com/intellij/packageDependencies/BackwardDependenciesBuilder.java +++ b/platform/analysis-impl/src/com/intellij/packageDependencies/BackwardDependenciesBuilder.java @@ -51,7 +51,7 @@ public class BackwardDependenciesBuilder extends DependenciesBuilder { public BackwardDependenciesBuilder(final Project project, final AnalysisScope scope, final @Nullable AnalysisScope scopeOfInterest) { super(project, scope, scopeOfInterest); - myForwardScope = ApplicationManager.getApplication().runReadAction(new Computable() { + myForwardScope = scopeOfInterest != null ? scopeOfInterest : ApplicationManager.getApplication().runReadAction(new Computable() { @Override public AnalysisScope compute() { return getScope().getNarrowedComplementaryScope(getProject()); diff --git a/platform/bootstrap/src/com/intellij/idea/Main.java b/platform/bootstrap/src/com/intellij/idea/Main.java index 17dccd320b5b..09d96cd48ee6 100644 --- a/platform/bootstrap/src/com/intellij/idea/Main.java +++ b/platform/bootstrap/src/com/intellij/idea/Main.java @@ -285,7 +285,7 @@ public class Main { else { message.append("Internal error. Please report to https://"); boolean studio = "AndroidStudio".equalsIgnoreCase(System.getProperty(PLATFORM_PREFIX_PROPERTY)); - message.append(studio ? "code.google.com/p/android/issues" : "youtrack.jetbrains.com"); + message.append(studio ? "code.google.com/p/android/issues" : "intellij-support.jetbrains.com/hc/en-us/requests/new"); message.append("\n\n"); } diff --git a/platform/core-api/src/com/intellij/openapi/application/RunResult.java b/platform/core-api/src/com/intellij/openapi/application/RunResult.java index 5494b179b2d0..f55437c6107f 100644 --- a/platform/core-api/src/com/intellij/openapi/application/RunResult.java +++ b/platform/core-api/src/com/intellij/openapi/application/RunResult.java @@ -40,8 +40,7 @@ public class RunResult extends Result { catch (Throwable t) { myThrowable = t; if (!myActionRunnable.isSilentExecution()) { - ExceptionUtil.rethrowUnchecked(t); - throw new RuntimeException(myThrowable); + ExceptionUtil.rethrowAllAsUnchecked(t); } } finally { @@ -67,8 +66,7 @@ public class RunResult extends Result { @NotNull public RunResult throwException() throws RuntimeException, Error { if (myThrowable != null) { - ExceptionUtil.rethrowUnchecked(myThrowable); - throw new RuntimeException(myThrowable); + ExceptionUtil.rethrowAllAsUnchecked(myThrowable); } return this; diff --git a/platform/core-impl/src/com/intellij/psi/WrappedElementAnchor.java b/platform/core-impl/src/com/intellij/psi/WrappedElementAnchor.java index c5e1ebebea4c..cde4726b7bfd 100644 --- a/platform/core-impl/src/com/intellij/psi/WrappedElementAnchor.java +++ b/platform/core-impl/src/com/intellij/psi/WrappedElementAnchor.java @@ -58,6 +58,6 @@ public class WrappedElementAnchor extends PsiAnchor { @Override public String toString() { - return "WrappedElementAnchor(" + myBaseAnchor.toString() + ")"; + return "WrappedElementAnchor(" + myBaseAnchor + "; provider=" + myAnchorProvider + ")"; } } diff --git a/platform/core-impl/src/com/intellij/psi/filters/NotFilter.java b/platform/core-impl/src/com/intellij/psi/filters/NotFilter.java index 9f9ee8f433bf..de029364a470 100644 --- a/platform/core-impl/src/com/intellij/psi/filters/NotFilter.java +++ b/platform/core-impl/src/com/intellij/psi/filters/NotFilter.java @@ -25,24 +25,13 @@ import com.intellij.psi.PsiElement; * Time: 19:24:33 * To change this template use Options | File Templates. */ -public class NotFilter - implements ElementFilter{ - ElementFilter myFilter; - - public NotFilter(){} +public class NotFilter implements ElementFilter { + private final ElementFilter myFilter; public NotFilter(ElementFilter filter){ myFilter = filter; } - public void setFilter(ElementFilter filter){ - myFilter = filter; - } - - public ElementFilter getFilter(){ - return myFilter; - } - @Override public boolean isClassAcceptable(Class hintClass){ return myFilter.isClassAcceptable(hintClass); @@ -55,7 +44,7 @@ public class NotFilter public String toString(){ - return "!" + getFilter(); + return "!" + myFilter; } } diff --git a/platform/diff-impl/src/com/intellij/diff/requests/UnknownFileTypeDiffRequest.java b/platform/diff-impl/src/com/intellij/diff/requests/UnknownFileTypeDiffRequest.java index 53d0c74e4226..03a21984ff2d 100644 --- a/platform/diff-impl/src/com/intellij/diff/requests/UnknownFileTypeDiffRequest.java +++ b/platform/diff-impl/src/com/intellij/diff/requests/UnknownFileTypeDiffRequest.java @@ -22,6 +22,8 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.UnknownFileType; import com.intellij.openapi.fileTypes.ex.FileTypeChooser; +import com.intellij.openapi.project.DumbModePermission; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.vcs.changes.issueLinks.LinkMouseListenerBase; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.SimpleColoredComponent; @@ -46,11 +48,6 @@ public class UnknownFileTypeDiffRequest extends ComponentDiffRequest { myTitle = title; } - public UnknownFileTypeDiffRequest(@Nullable String title) { - myFileName = null; - myTitle = title; - } - @NotNull @Override public JComponent getComponent(@NotNull final DiffContext context) { @@ -61,8 +58,13 @@ public class UnknownFileTypeDiffRequest extends ComponentDiffRequest { label.append("Associate", SimpleTextAttributes.LINK_ATTRIBUTES, new Runnable() { @Override public void run() { - FileType type = FileTypeChooser.associateFileType(myFileName); - if (type != null) onSuccess(context); + DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + @Override + public void run() { + FileType type = FileTypeChooser.associateFileType(myFileName); + if (type != null) onSuccess(context); + } + }); } }); LinkMouseListenerBase.installSingleTagOn(label); diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java index b8cf3cebb390..92bc57ae9bfe 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java @@ -128,7 +128,7 @@ public class UISettings extends SimpleModificationTracker implements PersistentS public boolean SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true; public boolean NAVIGATE_TO_PREVIEW = false; public boolean SORT_BOOKMARKS = false; - public boolean MERGE_EQUAL_STACKTRACES = false; + public boolean MERGE_EQUAL_STACKTRACES = true; private final EventDispatcher myDispatcher = EventDispatcher.create(UISettingsListener.class); diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/markup/HighlighterLayer.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/markup/HighlighterLayer.java index 55eaea8dbefc..779b3f534315 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/markup/HighlighterLayer.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/markup/HighlighterLayer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -16,8 +16,8 @@ package com.intellij.openapi.editor.markup; public interface HighlighterLayer { - int CARET_ROW = 1000; - int SYNTAX = 2000; + int SYNTAX = 1000; + int CARET_ROW = 2000; int ADDITIONAL_SYNTAX = 3000; int GUARDED_BLOCKS = 3500; int WARNING = 4000; @@ -25,6 +25,6 @@ public interface HighlighterLayer { int ELEMENT_UNDER_CARET = 5500; int SELECTION = 6000; - int FIRST = CARET_ROW; + int FIRST = SYNTAX; int LAST = SELECTION; } diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/PlatformFacade.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/PlatformFacade.java index 1ac0444b75a1..3f4f3801edfe 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/PlatformFacade.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/service/project/PlatformFacade.java @@ -1,6 +1,5 @@ package com.intellij.openapi.externalSystem.service.project; -import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.project.*; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; @@ -60,8 +59,7 @@ public interface PlatformFacade { /** * Creates a module of the specified type at the specified path and adds it to the project - * to which the module manager is related. {@link #commit()} must be called to - * bring the changes in effect. + * to which the module manager is related. * * * @param project diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java index fff82f6b3448..f457d5fb67e7 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java @@ -26,6 +26,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.ExternalSystemAutoImportAware; import com.intellij.openapi.externalSystem.ExternalSystemManager; import com.intellij.openapi.externalSystem.model.*; +import com.intellij.openapi.externalSystem.model.Key; import com.intellij.openapi.externalSystem.model.project.LibraryData; import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.project.ProjectData; @@ -39,12 +40,10 @@ import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListen import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Conditions; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; @@ -446,6 +445,61 @@ public class ExternalSystemApiUtil { return null; } + public static void commitChangedModels(boolean synchronous, Project project, List models) { + final List changedModels = ContainerUtil.findAll(models, new Condition() { + @Override + public boolean value(Library.ModifiableModel model) { + return model.isChanged(); + } + }); + if (!changedModels.isEmpty()) { + executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) { + @Override + public void execute() { + for (Library.ModifiableModel modifiableModel : changedModels) { + modifiableModel.commit(); + } + } + }); + } + } + + public static void disposeModels(@NotNull Collection models) { + for (ModifiableRootModel model : models) { + if (!model.isDisposed()) { + model.dispose(); + } + } + } + + public static void commitModels(boolean synchronous, Project project, List models) { + final List changedModels = ContainerUtilRt.newArrayList(); + for (ModifiableRootModel modifiableRootModel : models) { + if (modifiableRootModel.isDisposed()) { + continue; + } + if (modifiableRootModel.isChanged()) { + changedModels.add(modifiableRootModel); + } else { + modifiableRootModel.dispose(); + } + } + // Commit only if there are changes. #executeProjectChangeAction acquires a write lock + if (!changedModels.isEmpty()) { + executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) { + @Override + public void execute() { + for (ModifiableRootModel modifiableRootModel : changedModels) { + // double check + if (!modifiableRootModel.isDisposed()) { + modifiableRootModel.commit(); + } + } + } + }); + } + } + public static void executeProjectChangeAction(@NotNull final DisposeAwareProjectChange task) { executeProjectChangeAction(false, task); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/AbstractDependencyDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/AbstractDependencyDataService.java index 50373bf5d063..0cb388e88140 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/AbstractDependencyDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/AbstractDependencyDataService.java @@ -28,6 +28,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.util.Computable; import com.intellij.util.Consumer; +import com.intellij.util.ExceptionUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.MultiMap; @@ -133,15 +134,27 @@ public abstract class AbstractDependencyDataService> toRemoveComputable, - @NotNull final Collection> toIgnore, - @NotNull final ProjectData projectData, - @NotNull final Project project, - @NotNull final PlatformFacade platformFacade, - final boolean synchronous) { - Map> byModule = groupByModule(toRemoveComputable.compute()); - for (Map.Entry> entry : byModule.entrySet()) { - removeData(entry.getValue(), entry.getKey(), platformFacade, synchronous); + public void removeData(@NotNull Computable> toRemoveComputable, + @NotNull Collection> toIgnore, + @NotNull ProjectData projectData, + @NotNull Project project, + @NotNull PlatformFacade platformFacade, + boolean synchronous) { + List models = ContainerUtilRt.newArrayList(); + try { + Map> byModule = groupByModule(toRemoveComputable.compute()); + for (Map.Entry> entry : byModule.entrySet()) { + Module module = entry.getKey(); + Collection depsToRemove = entry.getValue(); + ModifiableRootModel model = platformFacade.getModuleModifiableModel(module); + removeData(depsToRemove, model); + models.add(model); + } + ExternalSystemApiUtil.commitModels(synchronous, project, models); + } + catch (Throwable t) { + ExternalSystemApiUtil.disposeModels(models); + ExceptionUtil.rethrowAllAsUnchecked(t); } } @@ -159,41 +172,25 @@ public abstract class AbstractDependencyDataService toRemove, - @NotNull final Module module, - @NotNull final PlatformFacade platformFacade, - boolean synchronous) { - if (toRemove.isEmpty()) { - return; - } - for (final ExportableOrderEntry dependency : toRemove) { - ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(dependency.getOwnerModule()) { - @Override - public void execute() { - final ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(module); - try { - // The thing is that intellij created order entry objects every time new modifiable model is created, - // that's why we can't use target dependency object as is but need to get a reference to the current - // entry object from the model instead. - for (OrderEntry entry : moduleRootModel.getOrderEntries()) { - if (entry instanceof ExportableOrderEntry) { - ExportableOrderEntry orderEntry = (ExportableOrderEntry)entry; - if (orderEntry.getPresentableName().equals(dependency.getPresentableName()) && - orderEntry.getScope().equals(dependency.getScope())) { - moduleRootModel.removeOrderEntry(entry); - break; - } - } - else if (entry.getPresentableName().equals(dependency.getPresentableName())) { - moduleRootModel.removeOrderEntry(entry); - break; - } - } - } - finally { - moduleRootModel.commit(); + @NotNull ModifiableRootModel moduleRootModel) { + for (ExportableOrderEntry dependency : toRemove) { + // The thing is that intellij created order entry objects every time new modifiable model is created, + // that's why we can't use target dependency object as is but need to get a reference to the current + // entry object from the model instead. + for (OrderEntry entry : moduleRootModel.getOrderEntries()) { + if (entry instanceof ExportableOrderEntry) { + ExportableOrderEntry orderEntry = (ExportableOrderEntry)entry; + if (orderEntry.getPresentableName().equals(dependency.getPresentableName()) && + orderEntry.getScope().equals(dependency.getScope())) { + moduleRootModel.removeOrderEntry(entry); + break; } } - }); + else if (entry.getPresentableName().equals(dependency.getPresentableName())) { + moduleRootModel.removeOrderEntry(entry); + break; + } + } } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ContentRootDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ContentRootDataService.java index 0392bd7ac6c7..abb013009b46 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ContentRootDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ContentRootDataService.java @@ -28,7 +28,6 @@ import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.service.project.PlatformFacade; import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings; import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; -import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.externalSystem.util.Order; @@ -36,7 +35,6 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ModifiableRootModel; -import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.roots.SourceFolder; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; @@ -44,7 +42,7 @@ import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; +import com.intellij.util.ExceptionUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; @@ -78,94 +76,95 @@ public class ContentRootDataService extends AbstractProjectDataService> toImport, + public void importData(@NotNull Collection> toImport, @Nullable ProjectData projectData, - @NotNull final Project project, - @NotNull final PlatformFacade platformFacade, - final boolean synchronous) { + @NotNull Project project, + @NotNull PlatformFacade platformFacade, + boolean synchronous) { if (toImport.isEmpty()) { return; } - MultiMap, DataNode> byModule = ExternalSystemApiUtil.groupBy(toImport, ProjectKeys.MODULE); - for (Map.Entry, Collection>> entry : byModule.entrySet()) { - final Module module = platformFacade.findIdeModule(entry.getKey().getData(), project); - if (module == null) { - LOG.warn(String.format( - "Can't import content roots. Reason: target module (%s) is not found at the ide. Content roots: %s", - entry.getKey(), entry.getValue() - )); - continue; + List models = ContainerUtilRt.newArrayList(); + try { + MultiMap, DataNode> byModule = ExternalSystemApiUtil.groupBy(toImport, ProjectKeys.MODULE); + for (Map.Entry, Collection>> entry : byModule.entrySet()) { + Module module = platformFacade.findIdeModule(entry.getKey().getData(), project); + if (module == null) { + LOG.warn(String.format( + "Can't import content roots. Reason: target module (%s) is not found at the ide. Content roots: %s", + entry.getKey(), entry.getValue() + )); + continue; + } + models.add(importData(entry.getValue(), module, platformFacade)); } - importData(entry.getValue(), module, synchronous); + ExternalSystemApiUtil.commitModels(synchronous, project, models); + } + catch (Throwable t) { + ExternalSystemApiUtil.disposeModels(models); + ExceptionUtil.rethrowAllAsUnchecked(t); } } - private static void importData(@NotNull final Collection> data, - @NotNull final Module module, - boolean synchronous) { - ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(module) { - @Override - public void execute() { - ModuleRootModificationUtil.updateModel(module, new Consumer() { - @Override - public void consume(ModifiableRootModel model) { - final ContentEntry[] contentEntries = model.getContentEntries(); - final Map contentEntriesMap = ContainerUtilRt.newHashMap(); - for(ContentEntry contentEntry : contentEntries) { - contentEntriesMap.put(contentEntry.getUrl(), contentEntry); - } + @NotNull + private static ModifiableRootModel importData(@NotNull Collection> data, + @NotNull Module module, + @NotNull PlatformFacade platformFacade) { + ModifiableRootModel model = platformFacade.getModuleModifiableModel(module); + ContentEntry[] contentEntries = model.getContentEntries(); + Map contentEntriesMap = ContainerUtilRt.newHashMap(); + for(ContentEntry contentEntry : contentEntries) { + contentEntriesMap.put(contentEntry.getUrl(), contentEntry); + } - boolean createEmptyContentRootDirectories = false; - if (!data.isEmpty()) { - ProjectSystemId projectSystemId = data.iterator().next().getData().getOwner(); - AbstractExternalSystemSettings externalSystemSettings = - ExternalSystemApiUtil.getSettings(module.getProject(), projectSystemId); + boolean createEmptyContentRootDirectories = false; + if (!data.isEmpty()) { + ProjectSystemId projectSystemId = data.iterator().next().getData().getOwner(); + AbstractExternalSystemSettings externalSystemSettings = + ExternalSystemApiUtil.getSettings(module.getProject(), projectSystemId); - String path = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY); - if (path != null) { - ExternalProjectSettings projectSettings = externalSystemSettings.getLinkedProjectSettings(path); - createEmptyContentRootDirectories = projectSettings != null && projectSettings.isCreateEmptyContentRootDirectories(); - } - } - - for (final DataNode node : data) { - final ContentRootData contentRoot = node.getData(); - - final ContentEntry contentEntry = findOrCreateContentRoot(model, contentRoot.getRootPath()); - contentEntry.clearExcludeFolders(); - contentEntry.clearSourceFolders(); - LOG.debug(String.format("Importing content root '%s' for module '%s'", contentRoot.getRootPath(), module.getName())); - for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.SOURCE)) { - createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.SOURCE, false, createEmptyContentRootDirectories); - } - for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST)) { - createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.TEST_SOURCE, false, createEmptyContentRootDirectories); - } - for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.RESOURCE)) { - createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaResourceRootType.RESOURCE, false, createEmptyContentRootDirectories); - } - for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST_RESOURCE)) { - createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaResourceRootType.TEST_RESOURCE, false, createEmptyContentRootDirectories); - } - for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.SOURCE_GENERATED)) { - createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.SOURCE, true, createEmptyContentRootDirectories); - } - for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST_GENERATED)) { - createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.TEST_SOURCE, true, createEmptyContentRootDirectories); - } - for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.EXCLUDED)) { - createExcludedRootIfAbsent(contentEntry, path, module.getName(), module.getProject()); - } - contentEntriesMap.remove(contentEntry.getUrl()); - } - for(ContentEntry contentEntry : contentEntriesMap.values()) { - model.removeContentEntry(contentEntry); - } - } - }); + String path = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY); + if (path != null) { + ExternalProjectSettings projectSettings = externalSystemSettings.getLinkedProjectSettings(path); + createEmptyContentRootDirectories = projectSettings != null && projectSettings.isCreateEmptyContentRootDirectories(); } - }); + } + + for (DataNode node : data) { + ContentRootData contentRoot = node.getData(); + + ContentEntry contentEntry = findOrCreateContentRoot(model, contentRoot.getRootPath()); + contentEntry.clearExcludeFolders(); + contentEntry.clearSourceFolders(); + LOG.debug(String.format("Importing content root '%s' for module '%s'", contentRoot.getRootPath(), module.getName())); + for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.SOURCE)) { + createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.SOURCE, false, createEmptyContentRootDirectories); + } + for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST)) { + createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.TEST_SOURCE, false, createEmptyContentRootDirectories); + } + for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.RESOURCE)) { + createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaResourceRootType.RESOURCE, false, createEmptyContentRootDirectories); + } + for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST_RESOURCE)) { + createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaResourceRootType.TEST_RESOURCE, false, createEmptyContentRootDirectories); + } + for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.SOURCE_GENERATED)) { + createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.SOURCE, true, createEmptyContentRootDirectories); + } + for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.TEST_GENERATED)) { + createSourceRootIfAbsent(contentEntry, path, module.getName(), JavaSourceRootType.TEST_SOURCE, true, createEmptyContentRootDirectories); + } + for (SourceRoot path : contentRoot.getPaths(ExternalSystemSourceType.EXCLUDED)) { + createExcludedRootIfAbsent(contentEntry, path, module.getName(), module.getProject()); + } + contentEntriesMap.remove(contentEntry.getUrl()); + } + for(ContentEntry contentEntry : contentEntriesMap.values()) { + model.removeContentEntry(contentEntry); + } + return model; } @NotNull diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java index ab16cfc045c4..24c4a94e0ebd 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java @@ -1,14 +1,12 @@ package com.intellij.openapi.externalSystem.service.project.manage; import com.intellij.ide.highlighter.ArchiveFileType; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.model.DataNode; import com.intellij.openapi.externalSystem.model.Key; import com.intellij.openapi.externalSystem.model.ProjectKeys; import com.intellij.openapi.externalSystem.model.project.LibraryData; import com.intellij.openapi.externalSystem.model.project.LibraryPathType; -import com.intellij.openapi.externalSystem.model.project.ModuleData; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.service.project.ExternalLibraryPathTypeMapper; import com.intellij.openapi.externalSystem.service.project.PlatformFacade; @@ -68,18 +66,23 @@ public class LibraryDataService extends AbstractProjectDataService> toImport, - @Nullable final ProjectData projectData, + @Nullable ProjectData projectData, @NotNull final Project project, @NotNull final PlatformFacade platformFacade, final boolean synchronous) { - for (DataNode dataNode : toImport) { - importLibrary(dataNode.getData(), project, platformFacade, synchronous); - } + ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) { + @Override + public void execute() { + for (DataNode dataNode : toImport) { + importLibrary(dataNode.getData(), project, platformFacade, synchronous); + } + } + }); } - private void importLibrary(@NotNull final LibraryData toImport, - @NotNull final Project project, - @NotNull final PlatformFacade platformFacade, + private void importLibrary(@NotNull LibraryData toImport, + @NotNull Project project, + @NotNull PlatformFacade platformFacade, boolean synchronous) { Map> libraryFiles = prepareLibraryFiles(toImport); @@ -88,14 +91,14 @@ public class LibraryDataService extends AbstractProjectDataService> prepareLibraryFiles(@NotNull LibraryData data) { Map> result = ContainerUtilRt.newHashMap(); for (LibraryPathType pathType : LibraryPathType.values()) { - final Set paths = data.getPaths(pathType); + Set paths = data.getPaths(pathType); if (paths.isEmpty()) { continue; } @@ -104,38 +107,32 @@ public class LibraryDataService extends AbstractProjectDataService> libraryFiles, - @NotNull final Project project, - @NotNull final PlatformFacade platformFacade, - boolean synchronous) + private void importLibrary(@NotNull String libraryName, + @NotNull Map> libraryFiles, + @NotNull Project project, + @NotNull PlatformFacade platformFacade) { - ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) { - @Override - public void execute() { - // Is assumed to be called from the EDT. - final LibraryTable libraryTable = platformFacade.getProjectLibraryTable(project); - final LibraryTable.ModifiableModel projectLibraryModel = libraryTable.getModifiableModel(); - final Library intellijLibrary; - try { - intellijLibrary = projectLibraryModel.createLibrary(libraryName); - } - finally { - projectLibraryModel.commit(); - } - final Library.ModifiableModel libraryModel = intellijLibrary.getModifiableModel(); - try { - registerPaths(libraryFiles, libraryModel, libraryName); - } - finally { - libraryModel.commit(); - } - } - }); + // Is assumed to be called from the EDT. + LibraryTable libraryTable = platformFacade.getProjectLibraryTable(project); + LibraryTable.ModifiableModel projectLibraryModel = libraryTable.getModifiableModel(); + Library intellijLibrary; + try { + intellijLibrary = projectLibraryModel.createLibrary(libraryName); + } + finally { + projectLibraryModel.commit(); + } + Library.ModifiableModel libraryModel = intellijLibrary.getModifiableModel(); + try { + registerPaths(libraryFiles, libraryModel, libraryName); + } + finally { + libraryModel.commit(); + } } @SuppressWarnings("MethodMayBeStatic") - public void registerPaths(@NotNull final Map> libraryFiles, + public void registerPaths(@NotNull Map> libraryFiles, @NotNull Library.ModifiableModel model, @NotNull String libraryName) { @@ -150,14 +147,14 @@ public class LibraryDataService extends AbstractProjectDataService> toRemove = ContainerUtilRt.newHashMap(); - final Map> toAdd = ContainerUtilRt.newHashMap(); + Map> toRemove = ContainerUtilRt.newHashMap(); + Map> toAdd = ContainerUtilRt.newHashMap(); for (LibraryPathType pathType : LibraryPathType.values()) { OrderRootType ideType = myLibraryPathTypeMapper.map(pathType); HashSet toAddPerType = ContainerUtilRt.newHashSet(externalLibrary.getPaths(pathType)); @@ -240,27 +237,22 @@ public class LibraryDataService extends AbstractProjectDataService> entry : toRemove.entrySet()) { - for (String path : entry.getValue()) { - model.removeRoot(path, entry.getKey()); - } - } - - for (Map.Entry> entry : toAdd.entrySet()) { - Map> roots = ContainerUtilRt.newHashMap(); - roots.put(entry.getKey(), ContainerUtil.map(entry.getValue(), PATH_TO_FILE)); - registerPaths(roots, model, externalLibrary.getInternalName()); - } - } - finally { - model.commit(); + Library.ModifiableModel model = ideLibrary.getModifiableModel(); + try { + for (Map.Entry> entry : toRemove.entrySet()) { + for (String path : entry.getValue()) { + model.removeRoot(path, entry.getKey()); } } - }); + + for (Map.Entry> entry : toAdd.entrySet()) { + Map> roots = ContainerUtilRt.newHashMap(); + roots.put(entry.getKey(), ContainerUtil.map(entry.getValue(), PATH_TO_FILE)); + registerPaths(roots, model, externalLibrary.getInternalName()); + } + } + finally { + model.commit(); + } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java index 40f7ba1cdb85..05682aa6e6fb 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDependencyDataService.java @@ -21,7 +21,6 @@ import com.intellij.openapi.externalSystem.model.Key; import com.intellij.openapi.externalSystem.model.ProjectKeys; import com.intellij.openapi.externalSystem.model.project.*; import com.intellij.openapi.externalSystem.service.project.PlatformFacade; -import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.externalSystem.util.Order; @@ -35,6 +34,8 @@ import com.intellij.openapi.roots.impl.ModuleLibraryOrderEntryImpl; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ExceptionUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; @@ -42,6 +43,7 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Set; @@ -78,17 +80,28 @@ public class LibraryDependencyDataService extends AbstractDependencyDataService< return; } - MultiMap, DataNode> byModule = ExternalSystemApiUtil.groupBy(toImport, MODULE); - for (Map.Entry, Collection>> entry : byModule.entrySet()) { - Module module = platformFacade.findIdeModule(entry.getKey().getData(), project); - if (module == null) { - LOG.warn(String.format( - "Can't import library dependencies %s. Reason: target module (%s) is not found at the ide and can't be imported", - entry.getValue(), entry.getKey() - )); - continue; + MyImporter importer = new MyImporter(platformFacade); + try { + MultiMap, DataNode> byModule = ExternalSystemApiUtil.groupBy(toImport, MODULE); + for (Map.Entry, Collection>> entry : byModule.entrySet()) { + Module module = platformFacade.findIdeModule(entry.getKey().getData(), project); + Collection> libraryDependency = entry.getValue(); + if (module == null) { + LOG.warn(String.format( + "Can't import library dependencies %s. Reason: target module (%s) is not found at the ide and can't be imported", + libraryDependency, entry.getKey() + )); + continue; + } + importer.importData(module, libraryDependency); } - importData(entry.getValue(), module, platformFacade, synchronous); + // change libraries first + ExternalSystemApiUtil.commitChangedModels(synchronous, project, importer.getLibraryModels()); + ExternalSystemApiUtil.commitModels(synchronous, project, importer.getModels()); + } + catch (Throwable t) { + ExternalSystemApiUtil.disposeModels(importer.getModels()); + ExceptionUtil.rethrowAllAsUnchecked(t); } } @@ -103,158 +116,157 @@ public class LibraryDependencyDataService extends AbstractDependencyDataService< return orderEntry.getLibraryName(); } - private void importData(@NotNull final Collection> nodesToImport, - @NotNull final Module module, - @NotNull final PlatformFacade platformFacade, - final boolean synchronous) { - ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(module) { - @Override - public void execute() { - // The general idea is to import all external project library dependencies and module libraries which don't present at the - // ide side yet and remove all project library dependencies and module libraries which present at the ide but not at - // the given collection. - // The trick is that we should perform module settings modification inside try/finally block against target root model. - // That means that we need to prepare all necessary data, obtain a model and modify it as necessary. - Map/* library paths */, LibraryDependencyData> moduleLibrariesToImport = ContainerUtilRt.newHashMap(); - Map projectLibrariesToImport = ContainerUtilRt.newHashMap(); - Set toImport = ContainerUtilRt.newLinkedHashSet(); + private class MyImporter { + private final PlatformFacade myPlatformFacade; + private final List myModels = ContainerUtilRt.newArrayList(); + private final List myLibraryModels = ContainerUtilRt.newArrayList(); - boolean hasUnresolved = false; - for (DataNode dependencyNode : nodesToImport) { - LibraryDependencyData dependencyData = dependencyNode.getData(); - LibraryData libraryData = dependencyData.getTarget(); - hasUnresolved |= libraryData.isUnresolved(); - switch (dependencyData.getLevel()) { - case MODULE: - if (!libraryData.isUnresolved()) { - Set paths = ContainerUtilRt.newHashSet(); - for (String path : libraryData.getPaths(LibraryPathType.BINARY)) { - paths.add(ExternalSystemApiUtil.toCanonicalPath(path) + dependencyData.getScope().name()); - } - moduleLibrariesToImport.put(paths, dependencyData); - toImport.add(dependencyData); + private MyImporter(PlatformFacade platformFacade) { + myPlatformFacade = platformFacade; + } + + public List getModels() { + return ContainerUtil.newUnmodifiableList(myModels); + } + + public List getLibraryModels() { + return ContainerUtil.newUnmodifiableList(myLibraryModels); + } + + public void importData(@NotNull Module module, @NotNull Collection> nodesToImport) { + // The general idea is to import all external project library dependencies and module libraries which don't present at the + // ide side yet and remove all project library dependencies and module libraries which present at the ide but not at + // the given collection. + // The trick is that we should perform module settings modification inside try/finally block against target root model. + // That means that we need to prepare all necessary data, obtain a model and modify it as necessary. + Map/* library paths */, LibraryDependencyData> moduleLibrariesToImport = ContainerUtilRt.newHashMap(); + Map projectLibrariesToImport = ContainerUtilRt.newHashMap(); + Set toImport = ContainerUtilRt.newLinkedHashSet(); + + boolean hasUnresolved = false; + for (DataNode dependencyNode : nodesToImport) { + LibraryDependencyData dependencyData = dependencyNode.getData(); + LibraryData libraryData = dependencyData.getTarget(); + hasUnresolved |= libraryData.isUnresolved(); + switch (dependencyData.getLevel()) { + case MODULE: + if (!libraryData.isUnresolved()) { + Set paths = ContainerUtilRt.newHashSet(); + for (String path : libraryData.getPaths(LibraryPathType.BINARY)) { + paths.add(ExternalSystemApiUtil.toCanonicalPath(path) + dependencyData.getScope().name()); } - break; - case PROJECT: - projectLibrariesToImport.put(libraryData.getInternalName() + dependencyData.getScope().name(), dependencyData); + moduleLibrariesToImport.put(paths, dependencyData); toImport.add(dependencyData); - } - } - - final ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(module); - LibraryTable moduleLibraryTable = moduleRootModel.getModuleLibraryTable(); - LibraryTable libraryTable = platformFacade.getProjectLibraryTable(module.getProject()); - try { - syncExistingAndRemoveObsolete(moduleLibrariesToImport, projectLibrariesToImport, toImport, moduleRootModel, hasUnresolved); - - // Import missing library dependencies. - if (!toImport.isEmpty()) { - importMissing(toImport, moduleRootModel, moduleLibraryTable, libraryTable, module); - } - } - finally { - moduleRootModel.commit(); - } - } - }); - } - - private void importMissing(@NotNull Set toImport, - @NotNull ModifiableRootModel moduleRootModel, - @NotNull LibraryTable moduleLibraryTable, - @NotNull LibraryTable libraryTable, - @NotNull Module module) { - for (final LibraryDependencyData dependencyData : toImport) { - final LibraryData libraryData = dependencyData.getTarget(); - final String libraryName = libraryData.getInternalName(); - switch (dependencyData.getLevel()) { - case MODULE: - final Library moduleLib = moduleLibraryTable.createLibrary(libraryName); - syncExistingLibraryDependency(dependencyData, moduleLib, moduleRootModel, module); - break; - case PROJECT: - final Library projectLib = libraryTable.getLibraryByName(libraryName); - if (projectLib == null) { - syncExistingLibraryDependency(dependencyData, moduleLibraryTable.createLibrary(libraryName), moduleRootModel, module); + } break; + case PROJECT: + projectLibrariesToImport.put(libraryData.getInternalName() + dependencyData.getScope().name(), dependencyData); + toImport.add(dependencyData); + } + } + + ModifiableRootModel moduleRootModel = myPlatformFacade.getModuleModifiableModel(module); + LibraryTable moduleLibraryTable = moduleRootModel.getModuleLibraryTable(); + LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject()); + syncExistingAndRemoveObsolete(moduleLibrariesToImport, projectLibrariesToImport, toImport, moduleRootModel, hasUnresolved); + + // Import missing library dependencies. + if (!toImport.isEmpty()) { + importMissing(toImport, moduleRootModel, moduleLibraryTable, libraryTable, module); + } + myModels.add(moduleRootModel); + } + + private void importMissing(@NotNull Set toImport, + @NotNull ModifiableRootModel moduleRootModel, + @NotNull LibraryTable moduleLibraryTable, + @NotNull LibraryTable libraryTable, + @NotNull Module module) { + for (LibraryDependencyData dependencyData : toImport) { + LibraryData libraryData = dependencyData.getTarget(); + String libraryName = libraryData.getInternalName(); + switch (dependencyData.getLevel()) { + case MODULE: + Library moduleLib = moduleLibraryTable.createLibrary(libraryName); + syncExistingLibraryDependency(dependencyData, moduleLib, moduleRootModel, module); + break; + case PROJECT: + Library projectLib = libraryTable.getLibraryByName(libraryName); + if (projectLib == null) { + syncExistingLibraryDependency(dependencyData, moduleLibraryTable.createLibrary(libraryName), moduleRootModel, module); + break; + } + LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(projectLib); + setLibraryScope(orderEntry, projectLib, module, dependencyData); + } + } + } + + private void setLibraryScope(@NotNull LibraryOrderEntry orderEntry, + @NotNull Library lib, + @NotNull Module module, + @NotNull LibraryDependencyData dependencyData) { + LOG.debug(String.format("Adding library dependency '%s' to module '%s'", lib.getName(), module.getName())); + orderEntry.setExported(dependencyData.isExported()); + orderEntry.setScope(dependencyData.getScope()); + LOG.debug(String.format("Configuring library dependency '%s' of module '%s' to be%s exported and have scope %s", lib.getName(), module.getName(), dependencyData.isExported() ? " not" : "", dependencyData.getScope())); + } + + private void syncExistingAndRemoveObsolete(@NotNull Map, LibraryDependencyData> moduleLibrariesToImport, + @NotNull Map projectLibrariesToImport, + @NotNull Set toImport, + @NotNull ModifiableRootModel moduleRootModel, + boolean hasUnresolvedLibraries) { + Set moduleLibraryKey = ContainerUtilRt.newHashSet(); + for (OrderEntry entry : moduleRootModel.getOrderEntries()) { + if (entry instanceof ModuleLibraryOrderEntryImpl) { + ModuleLibraryOrderEntryImpl moduleLibraryOrderEntry = (ModuleLibraryOrderEntryImpl)entry; + Library library = moduleLibraryOrderEntry.getLibrary(); + if (library == null) { + LOG.warn("Skipping module-level library entry because it doesn't have backing Library object. Entry: " + entry); + continue; + } + moduleLibraryKey.clear(); + for (VirtualFile file : library.getFiles(OrderRootType.CLASSES)) { + moduleLibraryKey.add(ExternalSystemApiUtil.getLocalFileSystemPath(file) + moduleLibraryOrderEntry.getScope().name()); + } + LibraryDependencyData existing = moduleLibrariesToImport.remove(moduleLibraryKey); + if (existing == null) { + moduleRootModel.removeOrderEntry(entry); + } + else { + syncExistingLibraryDependency(existing, library, moduleRootModel, moduleLibraryOrderEntry.getOwnerModule()); + toImport.remove(existing); } - LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(projectLib); - setLibraryScope(orderEntry, projectLib, module, dependencyData); - } - } - } - - private static void setLibraryScope(@NotNull LibraryOrderEntry orderEntry, - @NotNull Library lib, - @NotNull Module module, - @NotNull LibraryDependencyData dependencyData) { - LOG.debug(String.format("Adding library dependency '%s' to module '%s'", lib.getName(), module.getName())); - orderEntry.setExported(dependencyData.isExported()); - orderEntry.setScope(dependencyData.getScope()); - LOG.debug(String.format( - "Configuring library dependency '%s' of module '%s' to be%s exported and have scope %s", - lib.getName(), module.getName(), dependencyData.isExported() ? " not" : "", dependencyData.getScope() - )); - } - - private void syncExistingAndRemoveObsolete(@NotNull Map, LibraryDependencyData> moduleLibrariesToImport, - @NotNull Map projectLibrariesToImport, - @NotNull Set toImport, - @NotNull ModifiableRootModel moduleRootModel, - boolean hasUnresolvedLibraries) { - Set moduleLibraryKey = ContainerUtilRt.newHashSet(); - for (OrderEntry entry : moduleRootModel.getOrderEntries()) { - if (entry instanceof ModuleLibraryOrderEntryImpl) { - ModuleLibraryOrderEntryImpl moduleLibraryOrderEntry = (ModuleLibraryOrderEntryImpl)entry; - Library library = moduleLibraryOrderEntry.getLibrary(); - if (library == null) { - LOG.warn("Skipping module-level library entry because it doesn't have backing Library object. Entry: " + entry); - continue; } - moduleLibraryKey.clear(); - for (VirtualFile file : library.getFiles(OrderRootType.CLASSES)) { - moduleLibraryKey.add(ExternalSystemApiUtil.getLocalFileSystemPath(file) + moduleLibraryOrderEntry.getScope().name()); - } - LibraryDependencyData existing = moduleLibrariesToImport.remove(moduleLibraryKey); - if (existing == null) { - moduleRootModel.removeOrderEntry(entry); - } - else { - syncExistingLibraryDependency(existing, library, moduleRootModel, moduleLibraryOrderEntry.getOwnerModule()); - toImport.remove(existing); - } - } - else if (entry instanceof LibraryOrderEntry) { - final LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry)entry; - final String libraryName = libraryOrderEntry.getLibraryName(); - final LibraryDependencyData existing = projectLibrariesToImport.remove(libraryName + libraryOrderEntry.getScope().name()); - if (existing != null) { - toImport.remove(existing); - } - else if (!hasUnresolvedLibraries) { - // There is a possible case that a project has been successfully imported from external model and after - // that network/repo goes down. We don't want to drop existing binary mappings then. - moduleRootModel.removeOrderEntry(entry); + else if (entry instanceof LibraryOrderEntry) { + LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry)entry; + String libraryName = libraryOrderEntry.getLibraryName(); + LibraryDependencyData existing = projectLibrariesToImport.remove(libraryName + libraryOrderEntry.getScope().name()); + if (existing != null) { + toImport.remove(existing); + } + else if (!hasUnresolvedLibraries) { + // There is a possible case that a project has been successfully imported from external model and after + // that network/repo goes down. We don't want to drop existing binary mappings then. + moduleRootModel.removeOrderEntry(entry); + } } } } - } - private void syncExistingLibraryDependency(@NotNull LibraryDependencyData libraryDependencyData, - @NotNull Library library, - @NotNull ModifiableRootModel moduleRootModel, - @NotNull Module module) { - final Library.ModifiableModel libModel = library.getModifiableModel(); - try { - final String libraryName = libraryDependencyData.getInternalName(); + private void syncExistingLibraryDependency(@NotNull LibraryDependencyData libraryDependencyData, + @NotNull Library library, + @NotNull ModifiableRootModel moduleRootModel, + @NotNull Module module) { + Library.ModifiableModel libModel = library.getModifiableModel(); + String libraryName = libraryDependencyData.getInternalName(); Map> files = myLibraryManager.prepareLibraryFiles(libraryDependencyData.getTarget()); myLibraryManager.registerPaths(files, libModel, libraryName); LibraryOrderEntry orderEntry = moduleRootModel.findLibraryOrderEntry(library); assert orderEntry != null; setLibraryScope(orderEntry, library, module, libraryDependencyData); - } - finally { - libModel.commit(); + myLibraryModels.add(libModel); } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDataService.java index 065c29d8d4ef..6ef72d89abad 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDataService.java @@ -15,7 +15,6 @@ */ package com.intellij.openapi.externalSystem.service.project.manage; -import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.model.DataNode; @@ -39,6 +38,7 @@ import com.intellij.ui.CheckBoxList; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.components.JBScrollPane; import com.intellij.util.Consumer; +import com.intellij.util.ExceptionUtil; import com.intellij.util.Function; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; @@ -52,11 +52,10 @@ import java.awt.*; import java.io.File; import java.util.Collection; import java.util.List; -import java.util.Map; /** * Encapsulates functionality of importing external system module to the intellij project. - * + * * @author Denis Zhdanov * @since 2/7/12 2:49 PM */ @@ -74,82 +73,72 @@ public class ModuleDataService extends AbstractProjectDataService> toImport, + public void importData(@NotNull Collection> toImport, @Nullable ProjectData projectData, - @NotNull final Project project, - @NotNull final PlatformFacade platformFacade, - final boolean synchronous) { + @NotNull Project project, + @NotNull PlatformFacade platformFacade, + boolean synchronous) { if (toImport.isEmpty()) { return; } - ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(project) { - @Override - public void execute() { - final Collection> toCreate = filterExistingModules(toImport, project, platformFacade); - if (!toCreate.isEmpty()) { - createModules(toCreate, project, platformFacade); - } - for (DataNode node : toImport) { - Module module = platformFacade.findIdeModule(node.getData(), project); - if (module != null) { - syncPaths(module, platformFacade, node.getData()); - } - } - } - }); + Collection> toCreate = filterExistingModules(toImport, project, platformFacade); + if (!toCreate.isEmpty()) { + ExternalSystemApiUtil.commitModels(synchronous, project, createModules(project, platformFacade, toCreate)); + } + ExternalSystemApiUtil.commitModels(synchronous, project, syncModulesPaths(project, platformFacade, toImport)); } - private static void createModules(@NotNull final Collection> toCreate, - @NotNull final Project project, - @NotNull final PlatformFacade platformFacade) { - Application application = ApplicationManager.getApplication(); - final Map, Module> moduleMappings = ContainerUtilRt.newHashMap(); - application.runWriteAction(new Runnable() { + @NotNull + private static List createModules(@NotNull Project project, + @NotNull PlatformFacade platformFacade, + Collection> toCreate) { + List models = ContainerUtilRt.newArrayList(); + try { + for (DataNode moduleData : toCreate) { + models.add(createModule(project, platformFacade, moduleData)); + } + } + catch (Throwable t) { + ExternalSystemApiUtil.disposeModels(models); + ExceptionUtil.rethrowAllAsUnchecked(t); + } + return models; + } + + private static ModifiableRootModel createModule(@NotNull Project project, + @NotNull PlatformFacade platformFacade, + @NotNull DataNode module) { + ModuleData data = module.getData(); + Module created = platformFacade.newModule(project, data.getModuleFilePath(), data.getModuleTypeId()); + + // Ensure that the dependencies are clear (used to be not clear when manually removing the module and importing it via gradle) + final ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(created); + moduleRootModel.inheritSdk(); + setModuleOptions(created, module); + + RootPolicy visitor = new RootPolicy() { @Override - public void run() { - for (DataNode module : toCreate) { - importModule(module); - } + public Object visitLibraryOrderEntry(LibraryOrderEntry libraryOrderEntry, Object value) { + moduleRootModel.removeOrderEntry(libraryOrderEntry); + return value; } - private void importModule(@NotNull DataNode module) { - ModuleData data = module.getData(); - final Module created = platformFacade.newModule(project, data.getModuleFilePath(), data.getModuleTypeId()); - - // Ensure that the dependencies are clear (used to be not clear when manually removing the module and importing it via gradle) - final ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(created); - moduleRootModel.inheritSdk(); - setModuleOptions(created, module); - - RootPolicy visitor = new RootPolicy() { - @Override - public Object visitLibraryOrderEntry(LibraryOrderEntry libraryOrderEntry, Object value) { - moduleRootModel.removeOrderEntry(libraryOrderEntry); - return value; - } - - @Override - public Object visitModuleOrderEntry(ModuleOrderEntry moduleOrderEntry, Object value) { - moduleRootModel.removeOrderEntry(moduleOrderEntry); - return value; - } - }; - try { - for (OrderEntry orderEntry : moduleRootModel.getOrderEntries()) { - orderEntry.accept(visitor, null); - } - } - finally { - moduleRootModel.commit(); - } - moduleMappings.put(module, created); + @Override + public Object visitModuleOrderEntry(ModuleOrderEntry moduleOrderEntry, Object value) { + moduleRootModel.removeOrderEntry(moduleOrderEntry); + return value; } - }); + }; + for (OrderEntry orderEntry : moduleRootModel.getOrderEntries()) { + orderEntry.accept(visitor, null); + } + return moduleRootModel; } @NotNull private static Collection> filterExistingModules(@NotNull Collection> modules, - @NotNull Project project, @NotNull PlatformFacade platformFacade) + @NotNull Project project, + @NotNull PlatformFacade platformFacade) { Collection> result = ContainerUtilRt.newArrayList(); for (DataNode node : modules) { @@ -165,30 +154,46 @@ public class ModuleDataService extends AbstractProjectDataService syncModulesPaths(@NotNull Project project, + @NotNull PlatformFacade platformFacade, + Collection> toCreate) { + List models = ContainerUtilRt.newArrayList(); + try { + for (DataNode moduleData : toCreate) { + Module module = platformFacade.findIdeModule(moduleData.getData(), project); + if (module != null) { + models.add(syncPaths(module, platformFacade, moduleData.getData())); + } + } + } + catch (Throwable t) { + ExternalSystemApiUtil.disposeModels(models); + ExceptionUtil.rethrowAllAsUnchecked(t); + } + return models; + } + + @NotNull + private static ModifiableRootModel syncPaths(@NotNull Module module, @NotNull PlatformFacade platformFacade, @NotNull ModuleData data) { ModifiableRootModel modifiableModel = platformFacade.getModuleModifiableModel(module); CompilerModuleExtension extension = modifiableModel.getModuleExtension(CompilerModuleExtension.class); if (extension == null) { - modifiableModel.dispose(); LOG.warn(String.format("Can't sync paths for module '%s'. Reason: no compiler extension is found for it", module.getName())); - return; + return modifiableModel; + } + String compileOutputPath = data.getCompileOutputPath(ExternalSystemSourceType.SOURCE); + if (compileOutputPath != null) { + extension.setCompilerOutputPath(VfsUtilCore.pathToUrl(compileOutputPath)); } - try { - String compileOutputPath = data.getCompileOutputPath(ExternalSystemSourceType.SOURCE); - if (compileOutputPath != null) { - extension.setCompilerOutputPath(VfsUtilCore.pathToUrl(compileOutputPath)); - } - String testCompileOutputPath = data.getCompileOutputPath(ExternalSystemSourceType.TEST); - if (testCompileOutputPath != null) { - extension.setCompilerOutputPathForTests(VfsUtilCore.pathToUrl(testCompileOutputPath)); - } + String testCompileOutputPath = data.getCompileOutputPath(ExternalSystemSourceType.TEST); + if (testCompileOutputPath != null) { + extension.setCompilerOutputPathForTests(VfsUtilCore.pathToUrl(testCompileOutputPath)); + } - extension.inheritCompilerOutputPath(data.isInheritProjectCompileOutputPath()); - } - finally { - modifiableModel.commit(); - } + extension.inheritCompilerOutputPath(data.isInheritProjectCompileOutputPath()); + return modifiableModel; } @NotNull @@ -340,7 +345,7 @@ public class ModuleDataService extends AbstractProjectDataService, DataNode> byModule = ExternalSystemApiUtil.groupBy(toImport, MODULE); - for (Map.Entry, Collection>> entry : byModule.entrySet()) { - Module ideModule = platformFacade.findIdeModule(entry.getKey().getData(), project); - if (ideModule == null) { - LOG.warn(String.format( - "Can't import module dependencies %s. Reason: target module (%s) is not found at the ide and can't be imported", - entry.getValue(), entry.getKey() - )); - continue; + List models = ContainerUtilRt.newArrayList(); + try { + MultiMap, DataNode> byModule = ExternalSystemApiUtil.groupBy(toImport, MODULE); + for (Map.Entry, Collection>> entry : byModule.entrySet()) { + Module ideModule = platformFacade.findIdeModule(entry.getKey().getData(), project); + if (ideModule == null) { + LOG.warn(String.format( + "Can't import module dependencies %s. Reason: target module (%s) is not found at the ide and can't be imported", + entry.getValue(), entry.getKey() + )); + continue; + } + models.add(importData(entry.getValue(), ideModule, platformFacade)); } - importData(entry.getValue(), ideModule, platformFacade, synchronous); + ExternalSystemApiUtil.commitModels(synchronous, project, models); + } + catch (Throwable t) { + ExternalSystemApiUtil.disposeModels(models); + ExceptionUtil.rethrowAllAsUnchecked(t); } } @@ -93,62 +96,54 @@ public class ModuleDependencyDataService extends AbstractDependencyDataService> toImport, - @NotNull final Module module, - @NotNull final PlatformFacade platformFacade, - final boolean synchronous) + @NotNull + private ModifiableRootModel importData(@NotNull Collection> toImport, + @NotNull Module module, + @NotNull PlatformFacade platformFacade) { - ExternalSystemApiUtil.executeProjectChangeAction(synchronous, new DisposeAwareProjectChange(module) { - @Override - public void execute() { - ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); - Map , ModuleOrderEntry> toRemove = ContainerUtilRt.newHashMap(); - for (OrderEntry entry : moduleRootManager.getOrderEntries()) { - if (entry instanceof ModuleOrderEntry) { - ModuleOrderEntry e = (ModuleOrderEntry)entry; - toRemove.put(Pair.create(e.getModuleName(), e.getScope()), e); - } + ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); + Map, ModuleOrderEntry> toRemove = + ContainerUtilRt.newHashMap(); + for (OrderEntry entry : moduleRootManager.getOrderEntries()) { + if (entry instanceof ModuleOrderEntry) { + ModuleOrderEntry e = (ModuleOrderEntry)entry; + toRemove.put(Pair.create(e.getModuleName(), e.getScope()), e); + } + } + + ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(module); + for (DataNode dependencyNode : toImport) { + ModuleDependencyData dependencyData = dependencyNode.getData(); + toRemove.remove(Pair.create(dependencyData.getInternalName(), dependencyData.getScope())); + String moduleName = dependencyData.getInternalName(); + Module ideDependencyModule = platformFacade.findIdeModule(moduleName, module.getProject()); + + ModuleOrderEntry orderEntry; + if (module.equals(ideDependencyModule)) { + // skip recursive module dependency check + continue; + } + else { + if (ideDependencyModule == null) { + LOG.warn(String.format("Can't import module dependency for '%s' module. Reason: target module (%s) is not found at the ide", + module.getName(), dependencyData)); } - - final ModifiableRootModel moduleRootModel = platformFacade.getModuleModifiableModel(module); - try { - for (DataNode dependencyNode : toImport) { - final ModuleDependencyData dependencyData = dependencyNode.getData(); - toRemove.remove(Pair.create(dependencyData.getInternalName(), dependencyData.getScope())); - final String moduleName = dependencyData.getInternalName(); - Module ideDependencyModule = platformFacade.findIdeModule(moduleName, module.getProject()); - - ModuleOrderEntry orderEntry; - if (module.equals(ideDependencyModule)) { - // skip recursive module dependency check - continue; - } else { - if(ideDependencyModule == null) { - LOG.warn(String.format( - "Can't import module dependency for '%s' module. Reason: target module (%s) is not found at the ide", - module.getName(), dependencyData - )); - } - orderEntry = platformFacade.findIdeModuleDependency(dependencyData, moduleRootModel); - if (orderEntry == null) { - orderEntry = ideDependencyModule == null - ? moduleRootModel.addInvalidModuleEntry(moduleName) - : moduleRootModel.addModuleOrderEntry(ideDependencyModule); - } - } - - orderEntry.setScope(dependencyData.getScope()); - orderEntry.setExported(dependencyData.isExported()); - } - } - finally { - moduleRootModel.commit(); - } - - if (!toRemove.isEmpty()) { - removeData(toRemove.values(), module, platformFacade, synchronous); + orderEntry = platformFacade.findIdeModuleDependency(dependencyData, moduleRootModel); + if (orderEntry == null) { + orderEntry = ideDependencyModule == null + ? moduleRootModel.addInvalidModuleEntry(moduleName) + : moduleRootModel.addModuleOrderEntry(ideDependencyModule); } } - }); + + orderEntry.setScope(dependencyData.getScope()); + orderEntry.setExported(dependencyData.isExported()); + } + + if (!toRemove.isEmpty()) { + removeData(toRemove.values(), moduleRootModel); + } + + return moduleRootModel; } } diff --git a/platform/indexing-impl/src/com/intellij/openapi/module/impl/scopes/LibraryScope.java b/platform/indexing-impl/src/com/intellij/openapi/module/impl/scopes/LibraryScope.java index f78b69704db3..abf16ba38d9b 100644 --- a/platform/indexing-impl/src/com/intellij/openapi/module/impl/scopes/LibraryScope.java +++ b/platform/indexing-impl/src/com/intellij/openapi/module/impl/scopes/LibraryScope.java @@ -18,8 +18,7 @@ package com.intellij.openapi.module.impl.scopes; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.vfs.VfsUtilCore; -import com.intellij.util.PathUtil; +import com.intellij.openapi.roots.libraries.LibraryUtil; import org.jetbrains.annotations.NotNull; /** @@ -27,26 +26,18 @@ import org.jetbrains.annotations.NotNull; */ public class LibraryScope extends LibraryScopeBase { private final Library myLibrary; + private final String myLibraryName; public LibraryScope(Project project, Library library) { super(project, library.getFiles(OrderRootType.CLASSES), library.getFiles(OrderRootType.SOURCES)); + myLibraryName = LibraryUtil.getPresentableName(library); myLibrary = library; } @NotNull @Override public String getDisplayName() { - String name = myLibrary.getName(); - if (name == null) { - String[] urls = myLibrary.getUrls(OrderRootType.CLASSES); - if (urls.length > 0) { - name = PathUtil.getFileName(VfsUtilCore.urlToPath(urls[0])); - } - else { - name = "empty"; - } - } - return "Library '" + name + "'"; + return "Library '" + myLibraryName + "'"; } @Override diff --git a/platform/lang-api/src/com/intellij/codeInsight/daemon/LineMarkerProvider.java b/platform/lang-api/src/com/intellij/codeInsight/daemon/LineMarkerProvider.java index b03b9acd0997..b7965479a933 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/daemon/LineMarkerProvider.java +++ b/platform/lang-api/src/com/intellij/codeInsight/daemon/LineMarkerProvider.java @@ -32,26 +32,25 @@ public interface LineMarkerProvider { * Get line markers for this PsiElement. *

* NOTE for implementers: - * Please return line marker info for exact element you were asked for. - * For example, do not return class marker info if getLineMarkerInfo() was called for a method. - * Please return relevant line marker info for as small element as possible. - * For example, do not return method marker for PsiMethod. Instead, return it for the PsiIdentifier which is a name of this method. + * Please return line marker info for the exact element you were asked for, which is as small as possible. + * For example, instead of returning method marker for PsiMethod, + * return it for the PsiIdentifier which is a name of this method. *

- * More technical details: - * Inspection (specifically, LineMarkersPass) for performance reasons queries all LineMarkerProviders in two passes: + * More technical details:

+ * IDEA highlighting (specifically, LineMarkersPass) queries all LineMarkerProviders in two passes (for performance reasons): *

    *
  • first pass for all elements in visible area
  • *
  • second pass for all the rest elements
  • *
- * If providers return nothing for either area, its line markers are cleared. + * If providers returned nothing for both areas, its line markers are cleared. *

- * So if, for example a method, is half-visible (e.g. its name is visible but a part of its body isn't) and - * some poorly written LineMarkerProvider returns info for the PsiMethod instead of PsiIdentifier then following happens: + * So if, for example, a method is half-visible (e.g. its name is visible but a part of its body isn't) and + * some poorly written LineMarkerProvider returned info for the PsiMethod instead of PsiIdentifier then following would happen: *

    - *
  • the first pass removes line marker info because whole PsiMethod is not visible
  • - *
  • the second pass tries to add line marker info back because LineMarkerProvider is called for the PsiMethod at last
  • + *
  • the first pass would remove line marker info because the whole PsiMethod isn't visible
  • + *
  • the second pass would try to add line marker info back because LineMarkerProvider was called for the PsiMethod at last
  • *
- * As a result, line marker icon blinks annoyingly. + * As a result, line marker icon would blink annoyingly. */ @Nullable LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GutterIntentionAction.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GutterIntentionAction.java index d60d91397509..843006d41de7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GutterIntentionAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GutterIntentionAction.java @@ -26,30 +26,36 @@ import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiFile; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; import com.intellij.util.IconUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * @author Dmitry Avdeev */ -class GutterIntentionAction extends AbstractIntentionAction implements Comparable { +class GutterIntentionAction extends AbstractIntentionAction implements Comparable, Iconable { private final AnAction myAction; private final int myOrder; + private final Icon myIcon; private String myText; - private GutterIntentionAction(AnAction action, int order) { + private GutterIntentionAction(AnAction action, int order, Icon icon) { myAction = action; myOrder = order; + myIcon = icon; } @Override @@ -96,10 +102,26 @@ class GutterIntentionAction extends AbstractIntentionAction implements Comparabl if (renderer == null || DumbService.isDumb(project) && !DumbService.isDumbAware(renderer)) { return; } - addActions(project, editor, psiFile, renderer.getClickAction(), descriptors, renderer, 0); - addActions(project, editor, psiFile, renderer.getMiddleButtonClickAction(), descriptors, renderer, 0); - addActions(project, editor, psiFile, renderer.getRightButtonClickAction(), descriptors, renderer, 0); - addActions(project, editor, psiFile, renderer.getPopupMenuActions(), descriptors, renderer, 0); + List list = new ArrayList(); + addActions(project, editor, psiFile, renderer.getClickAction(), list, renderer, 0); + addActions(project, editor, psiFile, renderer.getMiddleButtonClickAction(), list, renderer, 0); + addActions(project, editor, psiFile, renderer.getRightButtonClickAction(), list, renderer, 0); + addActions(project, editor, psiFile, renderer.getPopupMenuActions(), list, renderer, 0); + if (list.isEmpty()) return; + if (list.size() == 1) { + descriptors.addAll(list); + } + else { + HighlightInfo.IntentionActionDescriptor first = list.get(0); + List options = ContainerUtil.map(list.subList(1, list.size()), + new Function() { + @Override + public IntentionAction fun(HighlightInfo.IntentionActionDescriptor descriptor) { + return descriptor.getAction(); + } + }); + descriptors.add(new HighlightInfo.IntentionActionDescriptor(first.getAction(), options, first.getDisplayName(), first.getIcon())); + } } private static void addActions(@NotNull Project project, @@ -119,11 +141,11 @@ class GutterIntentionAction extends AbstractIntentionAction implements Comparabl addActions(project, editor, psiFile, child, descriptors, renderer, i + order); } } - final IntentionAction gutterAction = new GutterIntentionAction(action, order); - if (!gutterAction.isAvailable(project, editor, psiFile)) return; Icon icon = action.getTemplatePresentation().getIcon(); if (icon == null) icon = renderer.getIcon(); if (icon.getIconWidth() < 16) icon = IconUtil.toSize(icon, 16, 16); + final IntentionAction gutterAction = new GutterIntentionAction(action, order, icon); + if (!gutterAction.isAvailable(project, editor, psiFile)) return; HighlightInfo.IntentionActionDescriptor descriptor = new HighlightInfo.IntentionActionDescriptor(gutterAction, Collections.emptyList(), null, icon) { @Nullable @@ -143,4 +165,9 @@ class GutterIntentionAction extends AbstractIntentionAction implements Comparabl } return 0; } + + @Override + public Icon getIcon(@IconFlags int flags) { + return myIcon; + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java index b1f077529590..e9d28c1fd51b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java @@ -48,9 +48,7 @@ import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.awt.*; import java.util.*; -import java.util.List; public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass implements DumbAware { private static final String PRESENTABLE_NAME = "Injected fragments"; @@ -421,9 +419,8 @@ public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass imp TextAttributes.ERASE_MARKER).createUnconditionally(); holder.add(info); - Color back = attributes.getBackgroundColor() == null ? myGlobalScheme.getDefaultBackground() : attributes.getBackgroundColor(); - Color fore = attributes.getForegroundColor() == null ? myGlobalScheme.getDefaultForeground() : attributes.getForegroundColor(); - forcedAttributes = new TextAttributes(fore, back, attributes.getEffectColor(), attributes.getEffectType(), attributes.getFontType()); + forcedAttributes = new TextAttributes(attributes.getForegroundColor(), attributes.getBackgroundColor(), + attributes.getEffectColor(), attributes.getEffectType(), attributes.getFontType()); } HighlightInfo info = diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java index b937ab865dc6..f7cd2ef0d1ee 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java @@ -104,8 +104,7 @@ public abstract class DockablePopupManager { myToolWindow.setAvailable(true, null); myToolWindow.setToHideOnEmptyContent(false); - final Rectangle rectangle = WindowManager.getInstance().getIdeFrame(myProject).suggestChildFrameBounds(); - myToolWindow.setDefaultState(ToolWindowAnchor.RIGHT, ToolWindowType.FLOATING, rectangle); + setToolwindowDefaultState(); ((ToolWindowEx)myToolWindow).setTitleActions(createRestorePopupAction()); @@ -139,6 +138,10 @@ public abstract class DockablePopupManager { doUpdateComponent(element, originalElement, component); } + protected void setToolwindowDefaultState() { + final Rectangle rectangle = WindowManager.getInstance().getIdeFrame(myProject).suggestChildFrameBounds(); + myToolWindow.setDefaultState(ToolWindowAnchor.RIGHT, ToolWindowType.FLOATING, rectangle); + } protected AnAction[] createActions() { ToggleAction toggleAutoUpdateAction = new ToggleAction(getAutoUpdateTitle(), getAutoUpdateDescription(), diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index 86f79899cd27..5e25eb75f3b4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -118,12 +118,7 @@ public class TemplateState implements Disposable { @Override public void commandStarted(CommandEvent event) { - if (myEditor != null) { - final int offset = myEditor.getCaretModel().getOffset(); - myDocumentChangesTerminateTemplate = myCurrentSegmentNumber >= 0 && - (offset < mySegments.getSegmentStart(myCurrentSegmentNumber) || - offset > mySegments.getSegmentEnd(myCurrentSegmentNumber)); - } + myDocumentChangesTerminateTemplate = isCaretOutsideCurrentSegment(); started = true; } @@ -170,6 +165,14 @@ public class TemplateState implements Disposable { CommandProcessor.getInstance().addCommandListener(myCommandListener, this); } + private boolean isCaretOutsideCurrentSegment() { + if (myEditor != null) { + final int offset = myEditor.getCaretModel().getOffset(); + return offset < mySegments.getSegmentStart(myCurrentSegmentNumber) || offset > mySegments.getSegmentEnd(myCurrentSegmentNumber); + } + return false; + } + private boolean isMultiCaretMode() { return myEditor != null && myEditor.getCaretModel().getCaretCount() > 1; } @@ -188,6 +191,9 @@ public class TemplateState implements Disposable { } public boolean isToProcessTab() { + if (isCaretOutsideCurrentSegment()) { + return false; + } if (ourLookupShown) { final LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); if (lookup != null && !lookup.isFocused()) { diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java index a9ef94ce42df..4bfbabc28e4d 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java @@ -1212,9 +1212,9 @@ public class FindDialog extends DialogWrapper { ButtonGroup bgScope = new ButtonGroup(); - bgScope.add(myRbDirectory); bgScope.add(myRbProject); bgScope.add(myRbModule); + bgScope.add(myRbDirectory); bgScope.add(myRbCustomScope); ActionListener validateAll = new ActionListener() { diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index 3c1a0851a7f5..290a003000d7 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -1652,6 +1652,7 @@ public class FormatProcessor { if (space.containsLineFeeds()) { myCurrentBlock = (LeafBlockWrapper)block; adjustIndent(); + adjustAlignmentsAfterCurrentBlock(); } } else if (block instanceof CompositeBlockWrapper) { @@ -1662,6 +1663,20 @@ public class FormatProcessor { } } + private void adjustAlignmentsAfterCurrentBlock() { + LeafBlockWrapper current = myCurrentBlock.getNextBlock(); + while (current != null && !current.getWhiteSpace().containsLineFeeds()) { + if (current.getAlignment() != null) { + myCurrentBlock = current; + WhiteSpace currentWhiteSpace = myCurrentBlock.getWhiteSpace(); + SpacingImpl currentSpaceProperty = myCurrentBlock.getSpaceProperty(); + currentWhiteSpace.arrangeSpaces(currentSpaceProperty); + adjustIndent(); + } + current = current.getNextBlock(); + } + } + @Override protected void prepare() { } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java index ac2326da6dac..79553d1d331f 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java @@ -22,6 +22,8 @@ import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.DumbModePermission; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.impl.DirectoryIndex; @@ -60,11 +62,16 @@ public abstract class MarkRootActionBase extends DumbAwareAction { modifyRoots(file, entry); } } - ApplicationManager.getApplication().runWriteAction(new Runnable() { + DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { @Override public void run() { - model.commit(); - module.getProject().save(); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + model.commit(); + module.getProject().save(); + } + }); } }); } diff --git a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java index 7c4ba49563f6..882cc6593303 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java @@ -30,12 +30,17 @@ import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class PsiAwareTextEditorImpl extends TextEditorImpl { private TextEditorBackgroundHighlighter myBackgroundHighlighter; - public PsiAwareTextEditorImpl(@NotNull final Project project, @NotNull final VirtualFile file, final TextEditorProvider provider) { - super(project, file, provider); + public PsiAwareTextEditorImpl(@NotNull Project project, @NotNull VirtualFile file, TextEditorProvider provider) { + this(project, file, provider, null); + } + + PsiAwareTextEditorImpl(@NotNull Project project, @NotNull VirtualFile file, TextEditorProvider provider, @Nullable String name) { + super(project, file, provider, name); } @NotNull diff --git a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorProvider.java b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorProvider.java index c28fea82162c..8f90f5c79aef 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorProvider.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorProvider.java @@ -74,7 +74,7 @@ public class PsiAwareTextEditorProvider extends TextEditorProvider implements As return new Builder() { @Override public FileEditor build() { - final PsiAwareTextEditorImpl editor = new PsiAwareTextEditorImpl(project, file, PsiAwareTextEditorProvider.this); + PsiAwareTextEditorImpl editor = new PsiAwareTextEditorImpl(project, file, PsiAwareTextEditorProvider.this, getFileEditorName()); if (finalState != null) { finalState.setToEditor(editor.getEditor()); } diff --git a/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeConfigurable.java b/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeConfigurable.java index 8d979438000d..ef7b2328edca 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeConfigurable.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeConfigurable.java @@ -117,23 +117,18 @@ public class FileTypeConfigurable extends BaseConfigurable implements Searchable } myOriginalToEditedMap.clear(); - DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - if (!myManager.isIgnoredFilesListEqualToCurrent(myFileTypePanel.myIgnoreFilesField.getText())) { - myManager.setIgnoredFilesList(myFileTypePanel.myIgnoreFilesField.getText()); - } - myManager.setPatternsTable(myTempFileTypes, myTempPatternsTable); - for (FileNameMatcher matcher : myReassigned.keySet()) { - myManager.getRemovedMappings().put(matcher, Pair.create(myReassigned.get(matcher), true)); - } + if (!myManager.isIgnoredFilesListEqualToCurrent(myFileTypePanel.myIgnoreFilesField.getText())) { + myManager.setIgnoredFilesList(myFileTypePanel.myIgnoreFilesField.getText()); + } + myManager.setPatternsTable(myTempFileTypes, myTempPatternsTable); + for (FileNameMatcher matcher : myReassigned.keySet()) { + myManager.getRemovedMappings().put(matcher, Pair.create(myReassigned.get(matcher), true)); + } - TemplateDataLanguagePatterns.getInstance().setAssocTable(myTempTemplateDataLanguages); - } - }); + TemplateDataLanguagePatterns.getInstance().setAssocTable(myTempTemplateDataLanguages); } }); } diff --git a/platform/lang-impl/src/com/intellij/packageDependencies/actions/AnalyzeDependenciesOnSpecifiedTargetHandler.java b/platform/lang-impl/src/com/intellij/packageDependencies/actions/AnalyzeDependenciesOnSpecifiedTargetHandler.java index 7aebba7dfe41..c8249248bcdb 100644 --- a/platform/lang-impl/src/com/intellij/packageDependencies/actions/AnalyzeDependenciesOnSpecifiedTargetHandler.java +++ b/platform/lang-impl/src/com/intellij/packageDependencies/actions/AnalyzeDependenciesOnSpecifiedTargetHandler.java @@ -23,6 +23,7 @@ import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindowId; +import com.intellij.packageDependencies.BackwardDependenciesBuilder; import com.intellij.packageDependencies.DependenciesBuilder; import com.intellij.packageDependencies.ForwardDependenciesBuilder; import com.intellij.psi.PsiFile; @@ -72,27 +73,6 @@ public class AnalyzeDependenciesOnSpecifiedTargetHandler extends DependenciesHan @Override protected DependenciesBuilder createDependenciesBuilder(AnalysisScope scope) { - return new ForwardDependenciesBuilder(myProject, scope) { - @Override - public void analyze() { - super.analyze(); - final Map> dependencies = getDependencies(); - for (Iterator leftTreeIterator = dependencies.keySet().iterator(); leftTreeIterator.hasNext(); ) { - final PsiFile leftTreeFile = leftTreeIterator.next(); - final Set files = dependencies.get(leftTreeFile); - final Iterator iterator = files.iterator(); - while (iterator.hasNext()) { - PsiFile next = iterator.next(); - final VirtualFile virtualFile = next.getVirtualFile(); - if (virtualFile == null || !myTargetScope.contains(virtualFile)) { - iterator.remove(); - } - } - if (files.isEmpty()) { - leftTreeIterator.remove(); - } - } - } - }; + return new BackwardDependenciesBuilder(myProject, new AnalysisScope(myTargetScope, myProject), scope); } } diff --git a/platform/lang-impl/src/com/intellij/psi/filters/PlainTextFilter.java b/platform/lang-impl/src/com/intellij/psi/filters/PlainTextFilter.java index 4adc4eb5014b..7df4f395755b 100644 --- a/platform/lang-impl/src/com/intellij/psi/filters/PlainTextFilter.java +++ b/platform/lang-impl/src/com/intellij/psi/filters/PlainTextFilter.java @@ -18,13 +18,12 @@ package com.intellij.psi.filters; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; -import com.intellij.util.ArrayUtil; /** * @author yole */ -public class PlainTextFilter implements ElementFilter, InitializableFilter { - protected String[] myValue; +public class PlainTextFilter implements ElementFilter { + protected final String[] myValue; protected boolean myCaseInsensitiveFlag = false; public PlainTextFilter(final String value, final boolean insensitiveFlag) { @@ -80,17 +79,6 @@ public class PlainTextFilter implements ElementFilter, InitializableFilter { return ret; } - @Override - public void init(Object[] fromGetter){ - try{ - myValue = new String[fromGetter.length]; - System.arraycopy(fromGetter, 0, myValue, 0, fromGetter.length); - } - catch(ClassCastException cce){ - myValue = ArrayUtil.EMPTY_STRING_ARRAY; - } - } - protected String getTextByElement(Object element){ String elementValue = null; if(element instanceof PsiNamedElement){ diff --git a/platform/lang-impl/src/com/intellij/psi/filters/position/AfterElement.java b/platform/lang-impl/src/com/intellij/psi/filters/position/AfterElement.java index e0c6888ac3d5..0c7516913c77 100644 --- a/platform/lang-impl/src/com/intellij/psi/filters/position/AfterElement.java +++ b/platform/lang-impl/src/com/intellij/psi/filters/position/AfterElement.java @@ -24,7 +24,6 @@ import org.jetbrains.annotations.Nullable; * User: spLeaner */ public class AfterElement extends PositionElementFilter { - public AfterElement(){} public AfterElement(ElementFilter filter){ setFilter(filter); diff --git a/platform/lang-impl/src/com/intellij/psi/filters/position/LeftNeighbour.java b/platform/lang-impl/src/com/intellij/psi/filters/position/LeftNeighbour.java index 43d38670668d..ff571e5298e5 100644 --- a/platform/lang-impl/src/com/intellij/psi/filters/position/LeftNeighbour.java +++ b/platform/lang-impl/src/com/intellij/psi/filters/position/LeftNeighbour.java @@ -28,7 +28,6 @@ import com.intellij.psi.filters.FilterPositionUtil; * To change this template use Options | File Templates. */ public class LeftNeighbour extends PositionElementFilter{ - public LeftNeighbour(){} public LeftNeighbour(ElementFilter filter){ setFilter(filter); diff --git a/platform/lang-impl/src/com/intellij/psi/filters/position/SuperParentFilter.java b/platform/lang-impl/src/com/intellij/psi/filters/position/SuperParentFilter.java index c2e8ae87b5aa..c4eebfe55c76 100644 --- a/platform/lang-impl/src/com/intellij/psi/filters/position/SuperParentFilter.java +++ b/platform/lang-impl/src/com/intellij/psi/filters/position/SuperParentFilter.java @@ -31,8 +31,6 @@ public class SuperParentFilter extends PositionElementFilter{ setFilter(filter); } - public SuperParentFilter(){} - @Override public boolean isAcceptable(Object element, PsiElement scope){ if (!(element instanceof PsiElement)) return false; diff --git a/platform/lang-impl/src/com/intellij/util/ui/tree/LanguagePerFileConfigurable.java b/platform/lang-impl/src/com/intellij/util/ui/tree/LanguagePerFileConfigurable.java index b5365e9722a5..3119d2e506bd 100644 --- a/platform/lang-impl/src/com/intellij/util/ui/tree/LanguagePerFileConfigurable.java +++ b/platform/lang-impl/src/com/intellij/util/ui/tree/LanguagePerFileConfigurable.java @@ -97,12 +97,7 @@ public abstract class LanguagePerFileConfigurable implements SearchableConfig @Override public void apply() throws ConfigurationException { - DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { - @Override - public void run() { - myMappings.setMappings(myTreeView.getValues()); - } - }); + myMappings.setMappings(myTreeView.getValues()); } @Override diff --git a/platform/platform-api/src/com/intellij/execution/configurations/EncodingEnvironmentUtil.java b/platform/platform-api/src/com/intellij/execution/configurations/EncodingEnvironmentUtil.java index d728cab1b188..f24f9f7def63 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/EncodingEnvironmentUtil.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/EncodingEnvironmentUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -16,22 +16,17 @@ package com.intellij.execution.configurations; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.vfs.encoding.EncodingManager; -import com.intellij.openapi.vfs.encoding.EncodingProjectManager; import com.intellij.util.EnvironmentUtil; -import com.intellij.util.PlatformUtils; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.nio.charset.Charset; import java.util.Locale; import java.util.Map; public class EncodingEnvironmentUtil { - private static final Logger LOG = Logger.getInstance(EncodingEnvironmentUtil.class); + private static final String LC_ALL = "LC_ALL"; private static final String LC_CTYPE = "LC_CTYPE"; private static final String LANG = "LANG"; @@ -43,7 +38,7 @@ public class EncodingEnvironmentUtil { *

* Unfortunately, Mac OSX has a special behavior:
* These environment variables aren't passed to an IDE, if the IDE is launched from Spotlight.
- * Unfortunately, even {@link com.intellij.util.EnvironmentUtil#getEnvironment()} doesn't have these variables.

+ * Unfortunately, even {@link EnvironmentUtil#getEnvironment()} doesn't have these variables.

* As a result, no encoding environment variables are passed to Ruby/Node.js/Python/other processes that are launched from IDE. * Thus, these processes wrongly assume that the default encoding is US-ASCII. *

@@ -54,22 +49,17 @@ public class EncodingEnvironmentUtil { * @param commandLine GeneralCommandLine instance */ public static void setLocaleEnvironmentIfMac(@NotNull GeneralCommandLine commandLine) { - if (SystemInfo.isMac) { - if (!isLocaleDefined(commandLine)) { - setLocaleEnvironment(commandLine.getEnvironment(), commandLine.getCharset()); - } + if (SystemInfo.isMac && !isLocaleDefined(commandLine)) { + setLocaleEnvironment(commandLine.getEnvironment(), commandLine.getCharset()); } } /** - * @deprecated Use {@link #setLocaleEnvironmentIfMac(GeneralCommandLine)} instead. To be removed in IDEA 15. + * Sets default encoding on Mac if it's undefined.
*/ - @Deprecated - public static void fixDefaultEncodingIfMac(@NotNull GeneralCommandLine commandLine, @Nullable Project project) { - if (SystemInfo.isMac) { - if (!isLocaleDefined(commandLine)) { - setLocaleEnvironment(commandLine.getEnvironment(), getCharset(project)); - } + public static void setLocaleEnvironmentIfMac(@NotNull Map env, @NotNull Charset charset) { + if (SystemInfo.isMac && !isLocaleDefined(env)) { + setLocaleEnvironment(env, charset); } } @@ -85,65 +75,15 @@ public class EncodingEnvironmentUtil { Locale locale = Locale.getDefault(); String language = locale.getLanguage(); String country = locale.getCountry(); - if (language.isEmpty() || country.isEmpty()) { - return "en_US." + charset.name(); - } - return language + "_" + country + "." + charset.name(); - } - - /** - * Sets default encoding on Mac if it's undefined.
- * @deprecated Use {@link #setLocaleEnvironmentIfMac(java.util.Map, java.nio.charset.Charset)} instead. To be removed in IDEA 15. - */ - @Deprecated - public static void fixDefaultEncodingIfMac(@NotNull Map env, @Nullable Project project) { - if (SystemInfo.isMac) { - if (!isLocaleDefined(env)) { - setLocaleEnvironment(env, getCharset(project)); - } - } - } - - /** - * Sets default encoding on Mac if it's undefined.
- */ - public static void setLocaleEnvironmentIfMac(@NotNull Map env, @NotNull Charset charset) { - if (SystemInfo.isMac) { - if (!isLocaleDefined(env)) { - setLocaleEnvironment(env, charset); - } - } + return (language.isEmpty() || country.isEmpty() ? "en_US" : language + "_" + country) + "." + charset.name(); } private static boolean isLocaleDefined(@NotNull GeneralCommandLine commandLine) { - Map env = commandLine.getEnvironment(); - if (isLocaleDefined(env)) { - return true; - } - if (commandLine.isPassParentEnvironment()) { - // 'parentEnv' calculation logic should be kept in sync with GeneralCommandLine.setupEnvironment - Map parentEnv = PlatformUtils.isAppCode() ? System.getenv() // Temporarily fix for OC-8606 - : EnvironmentUtil.getEnvironmentMap(); - if (isLocaleDefined(parentEnv)) { - return true; - } - } - return false; + return isLocaleDefined(commandLine.getEnvironment()) || + commandLine.isPassParentEnvironment() && isLocaleDefined(commandLine.getParentEnvironment()); } private static boolean isLocaleDefined(@NotNull Map env) { return env.containsKey(LC_ALL) || env.containsKey(LC_CTYPE) || env.containsKey(LANG); } - - @NotNull - private static Charset getCharset(@Nullable Project project) { - Charset charset; - if (project == null) { - charset = EncodingManager.getInstance().getDefaultCharset(); - } - else { - charset = EncodingProjectManager.getInstance(project).getDefaultCharset(); - } - return charset; - } } diff --git a/platform/platform-api/src/com/intellij/ui/GuiUtils.java b/platform/platform-api/src/com/intellij/ui/GuiUtils.java index ce60c6b53de5..ef133c5d3865 100644 --- a/platform/platform-api/src/com/intellij/ui/GuiUtils.java +++ b/platform/platform-api/src/com/intellij/ui/GuiUtils.java @@ -15,8 +15,8 @@ */ package com.intellij.ui; -import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; @@ -366,25 +366,8 @@ public class GuiUtils { return s; } - public static void invokeAndWait(@NotNull Runnable runnable) throws InvocationTargetException, InterruptedException { - Application application = ApplicationManager.getApplication(); - assert !application.isDispatchThread() : "Must not be invoked from AWT dispatch thread"; - if (application.isReadAccessAllowed()) { - // make ApplicationImpl catch deadlock situation with readLock held - application.invokeAndWait(runnable, application.getDefaultModalityState()); - return; - } - SwingUtilities.invokeAndWait(runnable); - } - public static void runOrInvokeAndWait(@NotNull Runnable runnable) throws InvocationTargetException, InterruptedException { - Application application = ApplicationManager.getApplication(); - if (application.isDispatchThread()) { - runnable.run(); - } - else { - invokeAndWait(runnable); - } + ApplicationManager.getApplication().invokeAndWait(runnable, ModalityState.defaultModalityState()); } public static JTextField createUndoableTextField() { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java index 28cd53649030..ece097b58724 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java @@ -1090,9 +1090,6 @@ public class Switcher extends AnAction implements DumbAware { @Override public void propertyChange(@NotNull PropertyChangeEvent evt) { - final JBList list = getSelectedList(); - final Object value = list.getSelectedValue(); - if (project.isDisposed()) { myPopup.cancel(); return; @@ -1107,11 +1104,6 @@ public class Switcher extends AnAction implements DumbAware { files.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT); toolWindows.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT); } - files.repaint(); - toolWindows.repaint(); - if (value != null) { - ScrollingUtil.ensureSelectionExists(getSelectedList(list)); - } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index c44e3ab1817a..0981b88549aa 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -117,7 +117,6 @@ import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.text.AttributedCharacterIterator; import java.text.AttributedString; import java.text.CharacterIterator; @@ -5726,31 +5725,17 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } private static T execute(final Computable computable) { - if (ApplicationManager.getApplication().isDispatchThread()) { - return computable.compute(); - } - else { - final Ref ref = Ref.create(); - try { - GuiUtils.invokeAndWait(new Runnable() { - @Override - public void run() { - ref.set(computable.compute()); - } - }); + final Ref ref = Ref.create(); + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + ref.set(computable.compute()); } - catch (InterruptedException e) { - LOG.error(e); - } - catch (InvocationTargetException e) { - LOG.error(e); - } - return ref.get(); - } + }, ModalityState.defaultModalityState()); + return ref.get(); } } - private class MyInputMethodHandler implements InputMethodRequests { private String composedText; private ProperTextRange composedTextRange; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java index a56f62af36c6..77ca36aa9622 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java @@ -455,14 +455,9 @@ public final class IterationState { } } - if (syntax != null && highlighter.getLayer() < HighlighterLayer.SYNTAX) { - if (fold != null) { - cachedAttributes.add(fold); - fold = null; - } - - cachedAttributes.add(syntax); - syntax = null; + if (fold != null && highlighter.getLayer() < HighlighterLayer.GUARDED_BLOCKS) { + cachedAttributes.add(fold); + fold = null; } if (guard != null && highlighter.getLayer() < HighlighterLayer.GUARDED_BLOCKS) { @@ -475,6 +470,11 @@ public final class IterationState { caret = null; } + if (syntax != null && highlighter.getLayer() < HighlighterLayer.SYNTAX) { + cachedAttributes.add(syntax); + syntax = null; + } + TextAttributes textAttributes = highlighter.getTextAttributes(); if (textAttributes != null && textAttributes != TextAttributes.ERASE_MARKER) { cachedAttributes.add(textAttributes); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/IterationState.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/IterationState.java index bc74c684fb90..32fcf0e0732e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/IterationState.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/IterationState.java @@ -507,14 +507,9 @@ public class IterationState { } } - if (syntax != null && highlighter.getLayer() < HighlighterLayer.SYNTAX) { - if (fold != null) { - cachedAttributes.add(fold); - fold = null; - } - - cachedAttributes.add(syntax); - syntax = null; + if (fold != null && highlighter.getLayer() < HighlighterLayer.GUARDED_BLOCKS) { + cachedAttributes.add(fold); + fold = null; } if (guard != null && highlighter.getLayer() < HighlighterLayer.GUARDED_BLOCKS) { @@ -527,6 +522,11 @@ public class IterationState { caret = null; } + if (syntax != null && highlighter.getLayer() < HighlighterLayer.SYNTAX) { + cachedAttributes.add(syntax); + syntax = null; + } + TextAttributes textAttributes = highlighter.getTextAttributes(); if (textAttributes != null && textAttributes != TextAttributes.ERASE_MARKER) { cachedAttributes.add(textAttributes); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorProviderManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorProviderManagerImpl.java index 2fffb9fc1f2c..4db1bef7bd67 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorProviderManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorProviderManagerImpl.java @@ -101,7 +101,7 @@ public final class FileEditorProviderManagerImpl extends FileEditorProviderManag ContainerUtil.retainAll(sharedProviders, new Condition() { @Override public boolean value(FileEditorProvider provider) { - return !(provider instanceof TextEditorProvider); + return !(provider instanceof TextEditorProvider) || !((TextEditorProvider)provider).isDefaultFileEditorProvider(); } }); } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java index 3da9961a8ca8..6a2aee47ae40 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java @@ -24,7 +24,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.beans.PropertyChangeListener; @@ -34,16 +36,20 @@ import java.beans.PropertyChangeSupport; * @author Vladimir Kondratyev */ public class TextEditorImpl extends UserDataHolderBase implements TextEditor { + public static final String DEFAULT_NAME = "Text"; + protected final Project myProject; private final PropertyChangeSupport myChangeSupport; @NotNull private final TextEditorComponent myComponent; private final TextEditorProvider myProvider; + private final String myName; - TextEditorImpl(@NotNull final Project project, @NotNull final VirtualFile file, final TextEditorProvider provider) { + TextEditorImpl(@NotNull final Project project, @NotNull final VirtualFile file, final TextEditorProvider provider, @Nullable String name) { myProject = project; myProvider = provider; myChangeSupport = new PropertyChangeSupport(this); myComponent = createEditorComponent(project, file); + myName = ObjectUtils.notNull(name, DEFAULT_NAME); } @NotNull @@ -84,7 +90,7 @@ public class TextEditorImpl extends UserDataHolderBase implements TextEditor { @Override @NotNull public String getName() { - return "Text"; + return myName; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java index d14bd13505ca..d10f273f9041 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java @@ -75,9 +75,9 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { @Override @NotNull - public FileEditor createEditor(@NotNull Project project, @NotNull final VirtualFile file) { + public FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) { LOG.assertTrue(accept(project, file)); - return new TextEditorImpl(project, file, this); + return new TextEditorImpl(project, file, this, getFileEditorName()); } @Override @@ -304,6 +304,15 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { }); } + public boolean isDefaultFileEditorProvider() { + return true; + } + + @Nullable + protected String getFileEditorName() { + return null; + } + protected class EditorWrapper extends UserDataHolderBase implements TextEditor { private final Editor myEditor; @@ -331,7 +340,7 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { @Override @NotNull public String getName() { - return "Text"; + return TextEditorImpl.DEFAULT_NAME; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java index 5998c7e432a8..d17ac8ab6991 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java @@ -500,7 +500,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent boolean wasDetectedAsBinary = BitUtil.isSet(flags, AUTO_DETECTED_AS_BINARY_MASK); boolean wasAutoDetectRun = BitUtil.isSet(flags, AUTO_DETECT_WAS_RUN_MASK); if (wasAutoDetectRun && (wasDetectedAsText || wasDetectedAsBinary)) { - return wasDetectedAsText ? FileTypes.PLAIN_TEXT : UnknownFileType.INSTANCE; + return wasDetectedAsText ? PlainTextFileType.INSTANCE : UnknownFileType.INSTANCE; } } FileType fileType = file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY); @@ -568,9 +568,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent @NotNull private FileType getAutoDetectedType(@NotNull VirtualFile file, int id) { long flags = packedFlags.get(id); - return BitUtil.isSet(flags, AUTO_DETECTED_AS_TEXT_MASK) ? FileTypes.PLAIN_TEXT : + return BitUtil.isSet(flags, AUTO_DETECTED_AS_TEXT_MASK) ? PlainTextFileType.INSTANCE : BitUtil.isSet(flags, AUTO_DETECTED_AS_BINARY_MASK) ? UnknownFileType.INSTANCE : - ObjectUtils.notNull(file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY), FileTypes.PLAIN_TEXT); + ObjectUtils.notNull(file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY), PlainTextFileType.INSTANCE); } @NotNull @@ -581,8 +581,8 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent } private void cacheAutoDetectedFileType(@NotNull VirtualFile file, @NotNull FileType fileType) { - boolean wasAutodetectedAsText = fileType == FileTypes.PLAIN_TEXT; - boolean wasAutodetectedAsBinary = fileType == FileTypes.UNKNOWN; + boolean wasAutodetectedAsText = fileType == PlainTextFileType.INSTANCE; + boolean wasAutodetectedAsBinary = fileType == UnknownFileType.INSTANCE; int flags = BitUtil.set(0, AUTO_DETECTED_AS_TEXT_MASK, wasAutodetectedAsText); flags = BitUtil.set(flags, AUTO_DETECTED_AS_BINARY_MASK, wasAutodetectedAsBinary); @@ -1263,7 +1263,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent } private static boolean shouldSave(@NotNull FileType fileType) { - return fileType != FileTypes.UNKNOWN && !fileType.isReadOnly(); + return fileType != UnknownFileType.INSTANCE && !fileType.isReadOnly(); } // ------------------------------------------------------------------------- diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/SingleConfigurableEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/SingleConfigurableEditor.java index 612715b43bfa..7435c9c00eaa 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/ex/SingleConfigurableEditor.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/SingleConfigurableEditor.java @@ -24,6 +24,8 @@ import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.options.BaseConfigurable; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.DumbModePermission; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; @@ -171,24 +173,30 @@ public class SingleConfigurableEditor extends DialogWrapper { @Override protected void doOKAction() { - try { - if (myConfigurable.isModified()) { - myConfigurable.apply(); - mySaveAllOnClose = true; - } - } - catch (ConfigurationException e) { - if (e.getMessage() != null) { - if (myProject != null) { - Messages.showMessageDialog(myProject, e.getMessage(), e.getTitle(), Messages.getErrorIcon()); + DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + @Override + public void run() { + try { + if (myConfigurable.isModified()) { + myConfigurable.apply(); + mySaveAllOnClose = true; + } } - else { - Messages.showMessageDialog(getRootPane(), e.getMessage(), e.getTitle(), Messages.getErrorIcon()); + catch (ConfigurationException e) { + if (e.getMessage() != null) { + if (myProject != null) { + Messages.showMessageDialog(myProject, e.getMessage(), e.getTitle(), Messages.getErrorIcon()); + } + else { + Messages.showMessageDialog(getRootPane(), e.getMessage(), e.getTitle(), Messages.getErrorIcon()); + } + } + return; } + + SingleConfigurableEditor.super.doOKAction(); } - return; - } - super.doOKAction(); + }); } protected static String createDimensionKey(Configurable configurable) { @@ -231,25 +239,30 @@ public class SingleConfigurableEditor extends DialogWrapper { @Override public void actionPerformed(ActionEvent event) { if (myPerformAction) return; - try { - myPerformAction = true; - if (myConfigurable.isModified()) { - myConfigurable.apply(); - mySaveAllOnClose = true; - setCancelButtonText(CommonBundle.getCloseButtonText()); + DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + @Override + public void run() { + try { + myPerformAction = true; + if (myConfigurable.isModified()) { + myConfigurable.apply(); + mySaveAllOnClose = true; + setCancelButtonText(CommonBundle.getCloseButtonText()); + } + } + catch (ConfigurationException e) { + if (myProject != null) { + Messages.showMessageDialog(myProject, e.getMessage(), e.getTitle(), Messages.getErrorIcon()); + } + else { + Messages.showMessageDialog(getRootPane(), e.getMessage(), e.getTitle(), + Messages.getErrorIcon()); + } + } finally { + myPerformAction = false; + } } - } - catch (ConfigurationException e) { - if (myProject != null) { - Messages.showMessageDialog(myProject, e.getMessage(), e.getTitle(), Messages.getErrorIcon()); - } - else { - Messages.showMessageDialog(getRootPane(), e.getMessage(), e.getTitle(), - Messages.getErrorIcon()); - } - } finally { - myPerformAction = false; - } + }); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/ConfigurableEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/ConfigurableEditor.java index 1aab26df8b22..94d5c5fb7146 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/ConfigurableEditor.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/ConfigurableEditor.java @@ -31,6 +31,8 @@ import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.options.ex.ConfigurableCardPanel; import com.intellij.openapi.options.ex.ConfigurableExtensionPointUtil; import com.intellij.openapi.options.ex.ConfigurableVisitor; +import com.intellij.openapi.project.DumbModePermission; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; @@ -73,7 +75,12 @@ class ConfigurableEditor extends AbstractEditor implements AnActionListener, AWT private final AbstractAction myApplyAction = new AbstractAction(CommonBundle.getApplyButtonText()) { @Override public void actionPerformed(ActionEvent event) { - apply(); + DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + @Override + public void run() { + apply(); + } + }); } }; private final AbstractAction myResetAction = new AbstractAction(RESET_NAME) { diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java index 68e67037b690..ca1631b6368f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java @@ -25,6 +25,8 @@ import com.intellij.openapi.options.ConfigurableGroup; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.options.ex.ConfigurableVisitor; +import com.intellij.openapi.project.DumbModePermission; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.ActionCallback; @@ -197,16 +199,20 @@ public class IdeSettingsDialog extends DialogWrapper implements DataProvider { public void doOKAction() { myEditor.flushModifications(); - if (myEditor.canApply()) { - myEditor.apply(); - if (!updateStatus()) return; - } + DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + public void run() { + if (myEditor.canApply()) { + myEditor.apply(); + if (!updateStatus()) return; + } - saveCurrentConfigurable(); + saveCurrentConfigurable(); - ApplicationManager.getApplication().saveAll(); + ApplicationManager.getApplication().saveAll(); - super.doOKAction(); + IdeSettingsDialog.super.doOKAction(); + } + }); } @@ -284,7 +290,12 @@ public class IdeSettingsDialog extends DialogWrapper implements DataProvider { } public void actionPerformed(final ActionEvent e) { - myEditor.apply(); + DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + @Override + public void run() { + myEditor.apply(); + } + }); myEditor.revalidate(); myEditor.repaint(); updateStatus(); diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditorDialog.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditorDialog.java index 13ea327f7b86..79c6c5ff5d50 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditorDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditorDialog.java @@ -26,6 +26,8 @@ import com.intellij.openapi.options.ConfigurableGroup; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.options.ex.Settings; +import com.intellij.openapi.project.DumbModePermission; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.ActionCallback; @@ -170,16 +172,20 @@ public class OptionsEditorDialog extends DialogWrapper implements DataProvider{ protected void doOKAction() { myEditor.flushModifications(); - if (myEditor.canApply()) { - myEditor.apply(); - if (!updateStatus()) return; - } + DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + public void run() { + if (myEditor.canApply()) { + myEditor.apply(); + if (!updateStatus()) return; + } - saveCurrentConfigurable(); + saveCurrentConfigurable(); - ApplicationManager.getApplication().saveAll(); + ApplicationManager.getApplication().saveAll(); - super.doOKAction(); + OptionsEditorDialog.super.doOKAction(); + } + }); } @@ -295,7 +301,12 @@ public class OptionsEditorDialog extends DialogWrapper implements DataProvider{ } public void actionPerformed(final ActionEvent e) { - myEditor.apply(); + DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + @Override + public void run() { + myEditor.apply(); + } + }); myEditor.revalidate(); myEditor.repaint(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java index 915cd2d85031..322565a05e7d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java @@ -21,6 +21,8 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurableGroup; +import com.intellij.openapi.project.DumbModePermission; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import org.jetbrains.annotations.NonNls; @@ -140,10 +142,15 @@ public class SettingsDialog extends DialogWrapper implements DataProvider { @Override public void doOKAction() { - if (myEditor.apply()) { - ApplicationManager.getApplication().saveAll(); - super.doOKAction(); - } + DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() { + @Override + public void run() { + if (myEditor.apply()) { + ApplicationManager.getApplication().saveAll(); + SettingsDialog.super.doOKAction(); + } + } + }); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java index e8ebea95c75b..7158a5c424fd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java @@ -110,7 +110,7 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project } @TestOnly - boolean isLight() { + public boolean isLight() { return myLight; } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java index b45c38c28e06..8cd0449808f8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java @@ -144,8 +144,14 @@ public class VfsData { if (segment != null || !create) return segment; return ourSegments.cacheOrGet(key, new Segment()); } + + public static class FileAlreadyCreatedException extends Exception { + private FileAlreadyCreatedException(String message) { + super(message); + } + } - public static void initFile(int id, Segment segment, int nameId, @NotNull Object data) { + public static void initFile(int id, Segment segment, int nameId, @NotNull Object data) throws FileAlreadyCreatedException { assert id > 0; int offset = getOffset(id); @@ -154,12 +160,12 @@ public class VfsData { Object existingData = segment.myObjectArray.get(offset); if (existingData != null) { int parent = FSRecords.getParent(id); - String msg = "File already created: " + existingData + "; parentId=" + parent; + String msg = "File already created: " + nameId + ", data=" + existingData + "; parentId=" + parent; if (parent > 0) { msg += "; parent.name=" + FSRecords.getName(parent); msg += "; parent.children=" + Arrays.toString(FSRecords.listAll(id)); } - throw new AssertionError(msg); + throw new FileAlreadyCreatedException(msg); } segment.myObjectArray.set(offset, data); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsRootAccess.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsRootAccess.java index aa900b5f6c7b..2af9c380fb9a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsRootAccess.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsRootAccess.java @@ -114,6 +114,13 @@ public class VfsRootAccess { final Set allowed = new THashSet(FileUtil.PATH_HASHING_STRATEGY); allowed.add(FileUtil.toSystemIndependentName(PathManager.getHomePath())); + // In plugin development environment PathManager.getHomePath() returns path like "~/.IntelliJIdea/system/plugins-sandbox/test" when running tests + // The following is to avoid errors in tests like "File accessed outside allowed roots: file://C:/Program Files/idea/lib/idea.jar" + final String homePath2 = PathManager.getHomePathFor(Application.class); + if (homePath2 != null) { + allowed.add(FileUtil.toSystemIndependentName(homePath2)); + } + try { URL outUrl = Application.class.getResource("/"); if (outUrl != null) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index 807cacc1d226..02c40461b312 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -216,8 +216,13 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { private VirtualFileSystemEntry createChild(int nameId, int id, @NotNull NewVirtualFileSystem delegate) { final int attributes = ourPersistence.getFileAttributes(id); VfsData.Segment segment = VfsData.getSegment(id, true); - VfsData.initFile(id, segment, nameId, - PersistentFS.isDirectory(attributes) ? new VfsData.DirectoryData() : KeyFMap.EMPTY_MAP); + try { + VfsData.initFile(id, segment, nameId, + PersistentFS.isDirectory(attributes) ? new VfsData.DirectoryData() : KeyFMap.EMPTY_MAP); + } + catch (VfsData.FileAlreadyCreatedException e) { + throw new RuntimeException("dir=" + myId + "; dir.children=" + Arrays.toString(FSRecords.listAll(myId)), e); + } LOG.assertTrue(!(getFileSystem() instanceof Win32LocalFileSystem)); VirtualFileSystemEntry child = VfsData.getFileById(id, this); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java index 16ed50c905d2..77cceb507291 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -908,14 +908,14 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone try { VfsData.initFile(rootId, segment, -1, directoryData); } - catch (AssertionError e) { + catch (VfsData.FileAlreadyCreatedException e) { for (Map.Entry entry : myRoots.entrySet()) { final VirtualFileSystemEntry existingRoot = entry.getValue(); if (Math.abs(existingRoot.getId()) == rootId) { throw new RuntimeException("Duplicate FS roots: " + rootUrl + " and " + entry.getKey() + ", id=" + rootId + ", valid=" + existingRoot.isValid(), e); } } - throw new RuntimeException("No root duplication, roots" + Arrays.toString(FSRecords.listAll(1)), e); + throw new RuntimeException("No root duplication, roots=" + Arrays.toString(FSRecords.listAll(1)), e); } incStructuralModificationCount(); mark = writeAttributesToRecord(rootId, 0, newRoot, fs, attributes); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java index 017687985f23..fa5d3f2ea735 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java @@ -37,10 +37,7 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.util.ActionCallback; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.IdeRootPaneNorthExtension; @@ -53,6 +50,7 @@ import com.intellij.openapi.wm.impl.status.*; import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame; import com.intellij.ui.*; import com.intellij.ui.mac.MacMainFrameDecorator; +import com.intellij.util.Alarm; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -136,6 +134,25 @@ public class IdeFrameImpl extends JFrame implements IdeFrameEx, DataProvider { } }; Toolkit.getDefaultToolkit().addPropertyChangeListener("win.xpstyle.themeActive", myWindowsBorderUpdater); + if (!SystemInfo.isJavaVersionAtLeast("1.8")) { + final Ref myDimensionRef = new Ref(new Dimension()); + final Alarm alarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + final Runnable runnable = new Runnable() { + @Override + public void run() { + if (isDisplayable() && !getSize().equals(myDimensionRef.get())) { + Rectangle bounds = getBounds(); + bounds.width--; + setBounds(bounds); + bounds.width++; + setBounds(bounds); + myDimensionRef.set(getSize()); + } + alarm.addRequest(this, 50); + } + }; + alarm.addRequest(runnable, 50); + } } IdeMenuBar.installAppMenuIfNeeded(this); diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java index 24bf8a69769e..667db0fb292d 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java @@ -21,6 +21,7 @@ import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.impl.DelegateColorScheme; import com.intellij.openapi.editor.event.DocumentListener; import com.intellij.openapi.editor.ex.*; @@ -76,13 +77,23 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, protected abstract String getText(JTable table, Object value, int row, int column); + @Nullable + protected TextAttributes getTextAttributes(JTable table, Object value, int row, int column) { + return null; + } + + @NotNull + protected EditorColorsScheme getColorScheme(final JTable table) { + return getEditorPanel(table).getEditor().getColorsScheme(); + } + @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column) { RendererComponent panel = getEditorPanel(table); EditorEx editor = panel.getEditor(); editor.getColorsScheme().setEditorFontSize(table.getFont().getSize()); String text = getText(table, value, row, column); - panel.setText(text, null, selected); + panel.setText(text, getTextAttributes(table, value, row, column), selected); editor.getColorsScheme().setColor(EditorColors.SELECTION_BACKGROUND_COLOR, table.getSelectionBackground()); editor.getColorsScheme().setColor(EditorColors.SELECTION_FOREGROUND_COLOR, table.getSelectionForeground()); diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java b/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java index c6553dcfec70..c9012b7e9a81 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java @@ -16,6 +16,7 @@ package com.intellij.util.ui.table; import com.intellij.openapi.Disposable; +import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.ui.EditorTextFieldCellRenderer; @@ -39,5 +40,16 @@ public abstract class EditorTextFieldJBTableRowRenderer extends EditorTextFieldC return getText(table, row); } + @Nullable + @Override + protected final TextAttributes getTextAttributes(JTable table, Object value, int row, int column) { + return getTextAttributes(table, row); + } + protected abstract String getText(JTable table, int row); + + @Nullable + protected TextAttributes getTextAttributes(JTable table, int row) { + return null; + } } diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 1c82db3534a7..0cc55dff9ecd 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -472,9 +472,9 @@ action.GotoImplementation.description=Navigate to the implementation(s) of the s action.GotoTypeDeclaration.text=_Type Declaration action.GotoTypeDeclaration.description=Navigate to the declaration of the symbol's type at caret action.GotoSuperMethod.text=S_uper Method -action.GotoSuperMethod.description=Navigate to the declaration of the method that current method overrides or implements +action.GotoSuperMethod.description=Navigate to the declaration of a method that the current method overrides or implements action.GotoSuperClass.text=S_uper Class -action.GotoSuperClass.description=Navigate to the declaration of the class that current class extends or implements +action.GotoSuperClass.description=Navigate to the declaration of a class that the current class extends or implements action.GotoTest.text=T_est action.GotoTest.description=Navigate to the test of the selected class action.GotoTestSubject.text=T_est Subject @@ -732,7 +732,7 @@ action.ToggleTemporaryLineBreakpoint.text=Toggle Temporary Line Breakpoint action.ToggleTemporaryLineBreakpoint.description=Toggle temporary line breakpoint at caret action.ViewBreakpoints.text=View Brea_kpoints... action.ViewBreakpoints.description=View and manage all breakpoints and watchpoints -action.EditBreakpoint.text=Edit +action.EditBreakpoint.text=Edit breakpoint action.ExportThreads.text=Export T_hreads... action.ExportThreads.description=Save all threads information to a text file or clipboard action.Runner.RestoreLayout.text=Restore Layout diff --git a/platform/platform-resources-en/src/messages/XDebuggerBundle.properties b/platform/platform-resources-en/src/messages/XDebuggerBundle.properties index a38e9a4eb5e8..f06cb2f4939c 100644 --- a/platform/platform-resources-en/src/messages/XDebuggerBundle.properties +++ b/platform/platform-resources-en/src/messages/XDebuggerBundle.properties @@ -9,9 +9,9 @@ debugger.hotswap.display.name=HotSwap xdebugger.default.content.title=Debug xdebugger.debugger.tab.title=Debugger -xdebugger.remove.line.breakpoint.action.text=Remove -xdebugger.disable.breakpoint.action.text=Disable -xdebugger.enable.breakpoint.action.text=Enable +xdebugger.remove.line.breakpoint.action.text=Remove breakpoint +xdebugger.disable.breakpoint.action.text=Disable breakpoint +xdebugger.enable.breakpoint.action.text=Enable breakpoint xdebugger.view.breakpoint.properties.action=Properties xdebugger.view.breakpoint.reveal.action=Show Breakpoints Dialog xdebugger.view.breakpoint.edit.action=Edit diff --git a/platform/platform-tests/testData/editor/painting/caretRowWinsOverSyntaxEvenInPresenceOfHighlighter.png b/platform/platform-tests/testData/editor/painting/caretRowWinsOverSyntaxEvenInPresenceOfHighlighter.png new file mode 100644 index 000000000000..c8fb28e88f96 Binary files /dev/null and b/platform/platform-tests/testData/editor/painting/caretRowWinsOverSyntaxEvenInPresenceOfHighlighter.png differ diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorPaintingTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorPaintingTest.java index 78033338073b..0e5c30e7b38d 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorPaintingTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorPaintingTest.java @@ -16,6 +16,12 @@ package com.intellij.openapi.editor; import com.intellij.openapi.application.ex.PathManagerEx; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.editor.highlighter.HighlighterClient; +import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.editor.impl.AbstractEditorTest; import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.editor.impl.view.FontLayoutService; @@ -24,6 +30,7 @@ import com.intellij.openapi.editor.markup.HighlighterTargetArea; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; +import com.intellij.psi.tree.IElementType; import com.intellij.rt.execution.junit.FileComparisonFailure; import com.intellij.testFramework.MockFontLayoutService; import com.intellij.testFramework.TestDataFile; @@ -56,6 +63,13 @@ public class EditorPaintingTest extends AbstractEditorTest { addRangeHighlighter(2, 3, HighlighterLayer.ERROR, Color.black, null); checkResult(); } + + public void testCaretRowWinsOverSyntaxEvenInPresenceOfHighlighter() throws Exception { + initText("foo"); + ((EditorEx)myEditor).setHighlighter(new UniformHighlighter(new TextAttributes(null, Color.red, null, null, Font.PLAIN))); + addRangeHighlighter(0, 3, 0, null, Color.blue); + checkResult(); + } private static void addRangeHighlighter(int startOffset, int endOffset, int layer, Color foregroundColor, Color backgroundColor) { myEditor.getMarkupModel().addRangeHighlighter(startOffset, endOffset, layer, @@ -262,4 +276,84 @@ public class EditorPaintingTest extends AbstractEditorTest { } } } + + private static class UniformHighlighter implements EditorHighlighter { + private final TextAttributes myAttributes; + private Document myDocument; + + private UniformHighlighter(TextAttributes attributes) { + myAttributes = attributes; + } + + @NotNull + @Override + public HighlighterIterator createIterator(int startOffset) { + return new Iterator(startOffset); + } + + @Override + public void setText(@NotNull CharSequence text) {} + + @Override + public void setEditor(@NotNull HighlighterClient editor) { + myDocument = editor.getDocument(); + } + + @Override + public void setColorScheme(@NotNull EditorColorsScheme scheme) {} + + @Override + public void beforeDocumentChange(DocumentEvent event) {} + + @Override + public void documentChanged(DocumentEvent event) {} + + private class Iterator implements HighlighterIterator { + private int myOffset; + + public Iterator(int startOffset) { + myOffset = startOffset; + } + + @Override + public TextAttributes getTextAttributes() { + return myAttributes; + } + + @Override + public int getStart() { + return myOffset; + } + + @Override + public int getEnd() { + return myDocument.getTextLength(); + } + + @Override + public IElementType getTokenType() { + return null; + } + + @Override + public void advance() { + myOffset = myDocument.getTextLength(); + } + + @Override + public void retreat() { + myOffset = 0; + } + + @Override + public boolean atEnd() { + return myOffset == myDocument.getTextLength(); + } + + @Override + public Document getDocument() { + return myDocument; + } + } + } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java index bbd0136c0f7c..da5025f8536d 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java @@ -556,5 +556,8 @@ public class FileTypesTest extends PlatformTestCase { FileType extensions = myFileTypeManager.getFileTypeByExtension("xxx"); assertEquals("IDL", extensions.getName()); myFileTypeManager.removeAssociatedExtension(idl, "xxx"); + myFileTypeManager.clearForTests(); + myFileTypeManager.initStandardFileTypes(); + myFileTypeManager.initComponent(); } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/impl/FileNameCacheMicroBenchmark.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/impl/FileNameCacheMicroBenchmark.java index 46a3462714e6..1751abc2e3cf 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/impl/FileNameCacheMicroBenchmark.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/impl/FileNameCacheMicroBenchmark.java @@ -36,18 +36,18 @@ import java.util.concurrent.Future; * @author peter */ public class FileNameCacheMicroBenchmark { - public static void main(String[] args) throws Exception { //noinspection SSBasedInspection - SwingUtilities.invokeLater(new Runnable() { + SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { try { IdeaTestFixture fixture = IdeaTestFixtureFactory.getFixtureFactory().createLightFixtureBuilder(LightProjectDescriptor.EMPTY_PROJECT_DESCRIPTOR).getFixture(); fixture.setUp(); - runTest(200); - runTest(50000); + runTest(200, "All names in cache"); + runTest(50000, "Cache almost overflows"); + runTest(120000, "Cache certain overflow"); fixture.tearDown(); } @@ -60,9 +60,8 @@ public class FileNameCacheMicroBenchmark { System.exit(0); } - private static void runTest(int nameCount) throws InterruptedException, ExecutionException { - System.out.println("-----------"); - System.out.println("nameCount = " + nameCount); + private static void runTest(int nameCount, String name) throws InterruptedException, ExecutionException { + System.out.println("----- " + name + " ------ name count: "+nameCount); TIntObjectHashMap map = generateNames(nameCount); final int[] ids = map.keys(); @@ -86,6 +85,7 @@ public class FileNameCacheMicroBenchmark { } private static void measureAverageTime(int[] ids, int threadCount) throws InterruptedException, ExecutionException { + System.out.println("Running "+threadCount+" threads"); TLongArrayList times = new TLongArrayList(); for (int i = 0; i < 11; i++) { long time = runThreads(ids, threadCount, 20000000); diff --git a/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryUtil.java b/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryUtil.java index 2fd5f9346db8..3025b80ee53d 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryUtil.java +++ b/platform/projectModel-api/src/com/intellij/openapi/roots/libraries/LibraryUtil.java @@ -26,6 +26,7 @@ import com.intellij.openapi.roots.*; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.PathUtil; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; @@ -169,7 +170,10 @@ public class LibraryUtil { if (name != null) { return name; } - final VirtualFile[] files = library.getFiles(OrderRootType.CLASSES); - return files.length > 0 ? files[0].getName() : "Empty Library"; + String[] urls = library.getUrls(OrderRootType.CLASSES); + if (urls.length > 0) { + return PathUtil.getFileName(VfsUtilCore.urlToPath(urls[0])); + } + return "Empty Library"; } } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleRootManagerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleRootManagerImpl.java index 47cf375aa525..033e7d285660 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleRootManagerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleRootManagerImpl.java @@ -127,7 +127,7 @@ public class ModuleRootManagerImpl extends ModuleRootManager implements ModuleCo } for (OrderEntry entry : ModuleRootManagerImpl.this.getOrderEntries()) { - assert !((RootModelComponentBase)entry).isDisposed(); + assert !((RootModelComponentBase)entry).isDisposed() : String.format("%s is not disposed!", entry.getPresentableName()); } } }; diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java index 3f724fd3dfb1..e8ab9eddc269 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryImpl.java @@ -589,7 +589,9 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi public void commit() { checkDisposed(); - mySource.commit(this); + if (isChanged()) { + mySource.commit(this); + } Disposer.dispose(this); } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java index 358301a9cb8d..525b1282b52d 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/LibraryTableBase.java @@ -167,6 +167,10 @@ public abstract class LibraryTableBase implements PersistentStateComponent addedLibraries = ContainerUtil.newIdentityTroveSet(model.myLibraries); addedLibraries.removeAll(myModel.myLibraries); @@ -221,8 +225,8 @@ public abstract class LibraryTableBase implements PersistentStateComponent + + diff --git a/platform/testFramework/src/com/intellij/testFramework/LeakHunter.java b/platform/testFramework/src/com/intellij/testFramework/LeakHunter.java index 9e83afc215ae..4e6ec007e776 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LeakHunter.java +++ b/platform/testFramework/src/com/intellij/testFramework/LeakHunter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -47,12 +47,6 @@ import java.util.Map; public class LeakHunter { private static final Map allFields = new THashMap(); private static final Field[] EMPTY_FIELD_ARRAY = new Field[0]; - private static final Processor NOT_DEFAULT_PROJECT = new Processor() { - @Override - public boolean process(Project project) { - return !project.isDefault(); - } - }; @NotNull private static Field[] getAllFields(@NotNull Class aClass) { @@ -158,8 +152,14 @@ public class LeakHunter { private static final Key REPORTED_LEAKED = Key.create("REPORTED_LEAKED"); @TestOnly public static void checkProjectLeak() throws Exception { - checkLeak(ApplicationManager.getApplication(), ProjectImpl.class); - checkLeak(Extensions.getRootArea(), ProjectImpl.class, NOT_DEFAULT_PROJECT); + Processor isReallyLeak = new Processor() { + @Override + public boolean process(Project project) { + return !project.isDefault() && !((ProjectImpl)project).isLight(); + } + }; + checkLeak(ApplicationManager.getApplication(), ProjectImpl.class, isReallyLeak); + checkLeak(Extensions.getRootArea(), ProjectImpl.class, isReallyLeak); } @TestOnly diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 96b335e1aa65..6c2f074c322f 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -939,6 +939,9 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig if (_performEditorAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM)) { return; } + if (_performEditorAction(IdeActions.ACTION_EDITOR_NEXT_TEMPLATE_VARIABLE)) { + return; + } performEditorAction(IdeActions.ACTION_EDITOR_ENTER); return; diff --git a/platform/usageView/src/com/intellij/usages/impl/rules/NonCodeUsageGroupingRule.java b/platform/usageView/src/com/intellij/usages/impl/rules/NonCodeUsageGroupingRule.java index 9a634361f47d..31201761f2f7 100644 --- a/platform/usageView/src/com/intellij/usages/impl/rules/NonCodeUsageGroupingRule.java +++ b/platform/usageView/src/com/intellij/usages/impl/rules/NonCodeUsageGroupingRule.java @@ -45,6 +45,10 @@ public class NonCodeUsageGroupingRule implements UsageGroupingRule { private static class CodeUsageGroup extends UsageGroupBase { private static final UsageGroup INSTANCE = new CodeUsageGroup(); + private CodeUsageGroup() { + super(1); + } + @Override @NotNull public String getText(UsageView view) { @@ -55,19 +59,15 @@ public class NonCodeUsageGroupingRule implements UsageGroupingRule { //noinspection HardCodedStringLiteral return "CodeUsages"; } - - @Override - public int compareTo(@NotNull UsageGroup usageGroup) { - if (usageGroup instanceof DynamicUsageGroup) { - return -1; - } - return usageGroup == this ? 0 : 1; - } } private static class UsageInGeneratedCodeGroup extends UsageGroupBase { public static final UsageGroup INSTANCE = new UsageInGeneratedCodeGroup(); + private UsageInGeneratedCodeGroup() { + super(2); + } + @Override @NotNull public String getText(UsageView view) { @@ -77,20 +77,19 @@ public class NonCodeUsageGroupingRule implements UsageGroupingRule { public String toString() { return "UsagesInGeneratedCode"; } - - @Override - public int compareTo(@NotNull UsageGroup usageGroup) { - return usageGroup == this ? 0 : -1; - } } private static class NonCodeUsageGroup extends UsageGroupBase { public static final UsageGroup INSTANCE = new NonCodeUsageGroup(); + private NonCodeUsageGroup() { + super(0); + } + @Override @NotNull public String getText(UsageView view) { - return view == null ? UsageViewBundle.message("node.group.code.usages") : view.getPresentation().getNonCodeUsagesString(); + return view == null ? UsageViewBundle.message("node.non.code.usages") : view.getPresentation().getNonCodeUsagesString(); } @Override @@ -101,13 +100,16 @@ public class NonCodeUsageGroupingRule implements UsageGroupingRule { //noinspection HardCodedStringLiteral return "NonCodeUsages"; } - public int compareTo(@NotNull UsageGroup usageGroup) { return usageGroup == this ? 0 : -1; } } private static class DynamicUsageGroup extends UsageGroupBase { public static final UsageGroup INSTANCE = new DynamicUsageGroup(); @NonNls private static final String DYNAMIC_CAPTION = "Dynamic usages"; + public DynamicUsageGroup() { + super(3); + } + @Override @NotNull public String getText(UsageView view) { @@ -124,7 +126,6 @@ public class NonCodeUsageGroupingRule implements UsageGroupingRule { //noinspection HardCodedStringLiteral return "DynamicUsages"; } - public int compareTo(@NotNull UsageGroup usageGroup) { return usageGroup == this ? 0 : 1; } } @Override diff --git a/platform/usageView/src/com/intellij/usages/impl/rules/UsageGroupBase.java b/platform/usageView/src/com/intellij/usages/impl/rules/UsageGroupBase.java index dbf213b6c11a..89ee481e3e41 100644 --- a/platform/usageView/src/com/intellij/usages/impl/rules/UsageGroupBase.java +++ b/platform/usageView/src/com/intellij/usages/impl/rules/UsageGroupBase.java @@ -1,5 +1,6 @@ package com.intellij.usages.impl.rules; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vcs.FileStatus; import com.intellij.usages.UsageGroup; import org.jetbrains.annotations.Nullable; @@ -10,6 +11,12 @@ import javax.swing.*; * @author nik */ public abstract class UsageGroupBase implements UsageGroup { + private final int myOrder; + + protected UsageGroupBase(int order) { + myOrder = order; + } + @Override public void update() { } @@ -43,4 +50,12 @@ public abstract class UsageGroupBase implements UsageGroup { public boolean canNavigateToSource() { return false; } + + @Override + public int compareTo(UsageGroup o) { + if (!(o instanceof UsageGroupBase)) { + return -1; + } + return Comparing.compare(myOrder, ((UsageGroupBase)o).myOrder); + } } diff --git a/platform/util/src/com/intellij/util/ExceptionUtil.java b/platform/util/src/com/intellij/util/ExceptionUtil.java index ff0ab77eb30b..0c6d3a06b12a 100644 --- a/platform/util/src/com/intellij/util/ExceptionUtil.java +++ b/platform/util/src/com/intellij/util/ExceptionUtil.java @@ -154,9 +154,15 @@ public class ExceptionUtil { public static void rethrowAll(@Nullable Throwable t) throws Exception { if (t != null) { - if (t instanceof Error) throw (Error)t; - if (t instanceof RuntimeException) throw (RuntimeException)t; + rethrowUnchecked(t); throw (Exception)t; } } + + public static void rethrowAllAsUnchecked(@Nullable Throwable t) { + if (t != null) { + rethrowUnchecked(t); + throw new RuntimeException(t); + } + } } diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java b/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java index 48b221d89573..8acb3891b389 100644 --- a/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java +++ b/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java @@ -33,6 +33,7 @@ import java.util.Arrays; import static com.intellij.openapi.util.io.IoTestUtil.assertTimestampsEqual; import static org.junit.Assert.*; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; public class FileAttributesReadingTest { @@ -397,7 +398,7 @@ public class FileAttributesReadingTest { @Test public void hardLink() throws Exception { //todo[Roman Shevchenko] currently it fails on new windows agents - assertFalse(SystemInfo.isWindows); + assumeFalse(SystemInfo.isWindows); final File target = FileUtil.createTempFile(myTempDirectory, "test.", ".txt"); final File link = IoTestUtil.createHardLink(target.getPath(), myTempDirectory.getPath() + "/link"); diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/lifecycle/PeriodicalTasksCloser.java b/platform/vcs-api/vcs-api-core/src/com/intellij/lifecycle/PeriodicalTasksCloser.java index 3b6a7ff2a5c6..34478d3403a6 100644 --- a/platform/vcs-api/vcs-api-core/src/com/intellij/lifecycle/PeriodicalTasksCloser.java +++ b/platform/vcs-api/vcs-api-core/src/com/intellij/lifecycle/PeriodicalTasksCloser.java @@ -21,7 +21,7 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; -import com.intellij.vcsUtil.Rethrow; +import com.intellij.util.ExceptionUtil; import org.jetbrains.annotations.NotNull; public class PeriodicalTasksCloser implements ApplicationComponent { @@ -85,7 +85,7 @@ public class PeriodicalTasksCloser implements ApplicationComponent { synchronized (myLock) { // allow NPE & assertion _catch_ only if project is closed and being disposed if (project.isOpen()) { - Rethrow.reThrowRuntime(t); + ExceptionUtil.rethrowAllAsUnchecked(t); } } throw new ProcessCanceledException(); diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/Rethrow.java b/platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/Rethrow.java index 6c42caaa3126..c8cf8e74f1ab 100644 --- a/platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/Rethrow.java +++ b/platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/Rethrow.java @@ -15,20 +15,21 @@ */ package com.intellij.vcsUtil; +import com.intellij.util.ExceptionUtil; + /** * @author irengrig + * + * @deprecated use {@link ExceptionUtil} instead */ public class Rethrow { private Rethrow() { } + /** + * @deprecated use {@link ExceptionUtil#rethrowAllAsUnchecked(Throwable)} instead + */ public static void reThrowRuntime(final Throwable t) { - if (t instanceof Error) { - throw (Error) t; - } - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } - throw new RuntimeException(t); + ExceptionUtil.rethrowAllAsUnchecked(t); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java index ae17cdee4c35..c2ba63815a0f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java @@ -55,7 +55,6 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import com.intellij.util.continuation.ContinuationPause; import com.intellij.util.messages.Topic; -import com.intellij.vcsUtil.Rethrow; import com.intellij.vcsUtil.VcsUtil; import org.jdom.Element; import org.jetbrains.annotations.CalledInAwt; @@ -761,7 +760,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec } catch (Throwable t) { LOG.debug(t); - Rethrow.reThrowRuntime(t); + ExceptionUtil.rethrowAllAsUnchecked(t); } finally { if (!myUpdater.isStopped()) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/CodeSmellDetectorImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/CodeSmellDetectorImpl.java index b97ee78e92ff..89f45cc3f3cf 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/CodeSmellDetectorImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/CodeSmellDetectorImpl.java @@ -43,8 +43,8 @@ import com.intellij.openapi.wm.ex.ProgressIndicatorEx; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; +import com.intellij.util.ExceptionUtil; import com.intellij.util.ui.MessageCategory; -import com.intellij.vcsUtil.Rethrow; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -139,8 +139,7 @@ public class CodeSmellDetectorImpl extends CodeSmellDetector { } }); if (!exception.isNull()) { - Exception t = exception.get(); - Rethrow.reThrowRuntime(t); + ExceptionUtil.rethrowAllAsUnchecked(exception.get()); } return result; diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/ui/DebuggerColors.java b/platform/xdebugger-api/src/com/intellij/xdebugger/ui/DebuggerColors.java index 8322ff735434..60887a0488ea 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/ui/DebuggerColors.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/ui/DebuggerColors.java @@ -32,7 +32,7 @@ public interface DebuggerColors { TextAttributesKey NOT_TOP_FRAME_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("NOT_TOP_FRAME_ATTRIBUTES"); ColorKey RECURSIVE_CALL_ATTRIBUTES = ColorKey.createColorKey("RECURSIVE_CALL_ATTRIBUTES", new Color(255, 255, 215)); - int BREAKPOINT_HIGHLIGHTER_LAYER = HighlighterLayer.SYNTAX + 1; + int BREAKPOINT_HIGHLIGHTER_LAYER = HighlighterLayer.CARET_ROW + 1; Key BREAKPOINT_HIGHLIGHTER_KEY = Key.create("BREAKPOINT_HIGHLIGHTER_KEY"); int EXECUTION_LINE_HIGHLIGHTERLAYER = HighlighterLayer.SELECTION - 1; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EditBreakpointAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EditBreakpointAction.java index a1642dbc9745..9683ba106986 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EditBreakpointAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/EditBreakpointAction.java @@ -16,12 +16,15 @@ package com.intellij.xdebugger.impl.actions; import com.intellij.idea.ActionsBundle; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.markup.GutterIconRenderer; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; import com.intellij.xdebugger.impl.DebuggerSupport; import org.jetbrains.annotations.NotNull; @@ -37,13 +40,16 @@ public class EditBreakpointAction extends XDebuggerActionBase implements DumbAwa myRenderer = breakpointRenderer; myBreakpoint = breakpoint; myDebuggerSupport = debuggerSupport; + AnAction action = ActionManager.getInstance().getAction("ViewBreakpoints"); + copyShortcutFrom(action); } @Override public void actionPerformed(AnActionEvent e) { final Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext()); - if (editor == null) return; - myDebuggerSupport.getEditBreakpointAction().editBreakpoint(getEventProject(e), editor, myBreakpoint, myRenderer); + Project project = getEventProject(e); + if (editor == null || project == null) return; + myDebuggerSupport.getEditBreakpointAction().editBreakpoint(project, editor, myBreakpoint, myRenderer); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/RemoveBreakpointGutterIconAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/RemoveBreakpointGutterIconAction.java index dadb944ba5c7..c8b34bb3ec03 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/RemoveBreakpointGutterIconAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/RemoveBreakpointGutterIconAction.java @@ -15,6 +15,8 @@ */ package com.intellij.xdebugger.impl.breakpoints; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.xdebugger.XDebuggerBundle; @@ -26,6 +28,8 @@ class RemoveBreakpointGutterIconAction extends DumbAwareAction { RemoveBreakpointGutterIconAction(XBreakpointBase breakpoint) { super(XDebuggerBundle.message("xdebugger.remove.line.breakpoint.action.text")); myBreakpoint = breakpoint; + AnAction action = ActionManager.getInstance().getAction("ToggleLineBreakpoint"); + copyShortcutFrom(action); } public void actionPerformed(final AnActionEvent e) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ToggleBreakpointGutterIconAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ToggleBreakpointGutterIconAction.java index 52734f6008da..010f8a2bf96f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ToggleBreakpointGutterIconAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ToggleBreakpointGutterIconAction.java @@ -15,6 +15,8 @@ */ package com.intellij.xdebugger.impl.breakpoints; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.xdebugger.XDebuggerBundle; @@ -29,6 +31,8 @@ class ToggleBreakpointGutterIconAction extends DumbAwareAction { ToggleBreakpointGutterIconAction(XBreakpoint breakpoint) { super(breakpoint.isEnabled() ? XDebuggerBundle.message("xdebugger.disable.breakpoint.action.text") : XDebuggerBundle.message("xdebugger.enable.breakpoint.action.text")); this.myBreakpoint = breakpoint; + AnAction action = ActionManager.getInstance().getAction("ToggleBreakpointEnabled"); + copyShortcutFrom(action); } public void actionPerformed(final AnActionEvent e) { diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/psi/PropertyKeyIndex.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/psi/PropertyKeyIndex.java index fabd11f08760..5f4acef71be1 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/psi/PropertyKeyIndex.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/psi/PropertyKeyIndex.java @@ -19,10 +19,15 @@ */ package com.intellij.lang.properties.psi; +import com.intellij.openapi.project.Project; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.stubs.StringStubIndexExtension; +import com.intellij.psi.stubs.StubIndex; import com.intellij.psi.stubs.StubIndexKey; import org.jetbrains.annotations.NotNull; +import java.util.Collection; + public class PropertyKeyIndex extends StringStubIndexExtension { public static final StubIndexKey KEY = StubIndexKey.createIndexKey("properties.index"); @@ -36,4 +41,9 @@ public class PropertyKeyIndex extends StringStubIndexExtension { public StubIndexKey getKey() { return KEY; } + + @Override + public Collection get(@NotNull String s, @NotNull Project project, @NotNull GlobalSearchScope scope) { + return StubIndex.getElements(getKey(), s, project, scope, Property.class); + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java index 71bca4152130..74e416eb29cb 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -158,7 +158,7 @@ public class CommandExecutor { } protected void beforeCreateProcess() throws SvnBindException { - EncodingEnvironmentUtil.fixDefaultEncodingIfMac(myCommandLine, null); + EncodingEnvironmentUtil.setLocaleEnvironmentIfMac(myCommandLine); setupLocale(); ensureMessageFile(); ensureTargetsAdded(); diff --git a/plugins/terminal/resources/META-INF/terminal-for-remote-servers.xml b/plugins/terminal/resources/META-INF/terminal-for-remote-servers.xml new file mode 100644 index 000000000000..bd0d49a7250b --- /dev/null +++ b/plugins/terminal/resources/META-INF/terminal-for-remote-servers.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/plugins/terminal/resources/META-INF/terminal.xml b/plugins/terminal/resources/META-INF/terminal.xml index e7f4360f44ad..7fa3b27a7c30 100644 --- a/plugins/terminal/resources/META-INF/terminal.xml +++ b/plugins/terminal/resources/META-INF/terminal.xml @@ -1,4 +1,6 @@ + com.intellij.modules.remoteServers + @@ -7,10 +9,6 @@ - - diff --git a/python/edu/interactive-learning-python/resources/META-INF/plugin.xml b/python/edu/interactive-learning-python/resources/META-INF/plugin.xml index 3fe9801d8ea4..34f5cf04a607 100644 --- a/python/edu/interactive-learning-python/resources/META-INF/plugin.xml +++ b/python/edu/interactive-learning-python/resources/META-INF/plugin.xml @@ -24,6 +24,7 @@ + diff --git a/python/edu/interactive-learning-python/src/com/jetbrains/edu/learning/PyStudyImportResolver.java b/python/edu/interactive-learning-python/src/com/jetbrains/edu/learning/PyStudyImportResolver.java new file mode 100644 index 000000000000..49916e779c97 --- /dev/null +++ b/python/edu/interactive-learning-python/src/com/jetbrains/edu/learning/PyStudyImportResolver.java @@ -0,0 +1,30 @@ +package com.jetbrains.edu.learning; + +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.QualifiedName; +import com.jetbrains.python.psi.impl.PyImportResolver; +import com.jetbrains.python.psi.resolve.QualifiedNameResolveContext; +import org.jetbrains.annotations.Nullable; + +public class PyStudyImportResolver implements PyImportResolver { + @Nullable + public PsiElement resolveImportReference(QualifiedName name, QualifiedNameResolveContext context, boolean withRoots) { + if (StudyTaskManager.getInstance(context.getProject()).getCourse() == null) { + return null; + } + final String nameString = name.toString(); + PsiFile containingFile = context.getFootholdFile(); + if (containingFile == null) return null; + + final PsiDirectory directory = containingFile.getContainingDirectory(); + if (directory == null) return null; + final PsiFile file = directory.findFile(nameString + ".py"); + if (file != null) { + return file; + } + + return null; + } +} diff --git a/python/edu/resources/idea/PyCharmEduApplicationInfo.xml b/python/edu/resources/idea/PyCharmEduApplicationInfo.xml index a282bce10a24..abdb7e038610 100644 --- a/python/edu/resources/idea/PyCharmEduApplicationInfo.xml +++ b/python/edu/resources/idea/PyCharmEduApplicationInfo.xml @@ -1,6 +1,6 @@ - + diff --git a/python/edu/resources/pycharm_edu_about.png b/python/edu/resources/pycharm_edu_about.png index d61aa053f093..27af2f3306d6 100644 Binary files a/python/edu/resources/pycharm_edu_about.png and b/python/edu/resources/pycharm_edu_about.png differ diff --git a/python/edu/resources/pycharm_edu_about@2x.png b/python/edu/resources/pycharm_edu_about@2x.png index 65afb5599597..e09744812030 100644 Binary files a/python/edu/resources/pycharm_edu_about@2x.png and b/python/edu/resources/pycharm_edu_about@2x.png differ diff --git a/python/edu/resources/pycharm_edu_logo.png b/python/edu/resources/pycharm_edu_logo.png index 501273d7b4cd..f443ed3c21c4 100644 Binary files a/python/edu/resources/pycharm_edu_logo.png and b/python/edu/resources/pycharm_edu_logo.png differ diff --git a/python/edu/resources/pycharm_edu_logo@2x.png b/python/edu/resources/pycharm_edu_logo@2x.png index e24f1c4f104e..f7f05c81e66d 100644 Binary files a/python/edu/resources/pycharm_edu_logo@2x.png and b/python/edu/resources/pycharm_edu_logo@2x.png differ diff --git a/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java b/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java index 0570852f163f..5c2c7beae823 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java +++ b/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java @@ -140,6 +140,7 @@ public class PyCharmEduInitialConfigurator { patchMainMenu(); uiSettings.SHOW_NAVIGATION_BAR = false; propertiesComponent.setValue(CONFIGURED_V1, true); + propertiesComponent.setValue("ShowDocumentationInToolWindow", true); } if (!propertiesComponent.getBoolean(CONFIGURED)) { diff --git a/python/educational/interactive-learning/resources/META-INF/plugin.xml b/python/educational/interactive-learning/resources/META-INF/plugin.xml index 202ea3b32537..b269cb3a3299 100644 --- a/python/educational/interactive-learning/resources/META-INF/plugin.xml +++ b/python/educational/interactive-learning/resources/META-INF/plugin.xml @@ -69,6 +69,8 @@ + processor, final boolean inherited, @NotNull TypeEvalContext context) { + // TODO: Implement + } + + @NotNull + @Override + public List getAncestorTypes(@NotNull final TypeEvalContext context) { + // TODO: Implement + return Collections.emptyList(); + } + @Override public boolean isValid() { return myClass.isValid(); diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java index 50b16502cb9a..dcc1990d3c41 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java @@ -74,7 +74,7 @@ public class PyJavaTypeProvider extends PyTypeProviderBase { final int index = params.indexOf(param); if (index < 0) return null; final List superMethodParameterTypes = new ArrayList(); - PySuperMethodsSearch.search(func).forEach(new Processor() { + PySuperMethodsSearch.search(func, context).forEach(new Processor() { public boolean process(final PsiElement psiElement) { if (psiElement instanceof PsiMethod) { final PsiMethod method = (PsiMethod)psiElement; diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java index 59505738f1ec..9d5613ba6dc0 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java @@ -38,7 +38,7 @@ import java.util.Map; * Represents a class declaration in source. */ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefiner, PyDocStringOwner, StubBasedPsiElement, - ScopeOwner, PyDecoratable, PyTypedElement, PyQualifiedNameOwner, PyStatementListContainer { + ScopeOwner, PyDecoratable, PyTypedElement, PyQualifiedNameOwner, PyStatementListContainer, PyWithAncestors { ArrayFactory ARRAY_FACTORY = new ArrayFactory() { @NotNull @Override @@ -51,14 +51,9 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine ASTNode getNameNode(); - /** - * Returns types of all ancestors from the hierarchy. - */ - @NotNull - List getAncestorTypes(@NotNull TypeEvalContext context); - /** * Returns only those ancestors from the hierarchy, that are resolved to PyClass PSI elements. + * * @param context type eval context (pass null to use loose, but better provide one) * @see #getAncestorTypes(TypeEvalContext) for the full list of ancestors. */ @@ -67,7 +62,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Returns types of expressions in the super classes list. - * + *

* If no super classes are specified, returns the type of the implicit super class for old- and new-style classes. * * @see #getAncestorTypes(TypeEvalContext) for the full list of ancestors. @@ -77,7 +72,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Returns only those super classes for expressions from the super classes list, that are resolved to PyClass PSI elements. - * + *

* If no super classes are specified, returns the implicit super class for old- and new-style classes. * * @see #getSuperClassTypes(TypeEvalContext) for the full list of super classes. @@ -88,7 +83,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Returns a PSI element for the super classes list. - * + *

* Operates at the AST level. */ @Nullable @@ -96,7 +91,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Returns PSI elements for the expressions in the super classes list. - * + *

* Operates at the AST level. */ @NotNull @@ -115,6 +110,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Get class properties. + * * @return Map [property_name] = [{@link com.jetbrains.python.psi.Property}] */ @NotNull @@ -122,7 +118,8 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Finds a method with given name. - * @param name what to look for + * + * @param name what to look for * @param inherited true: search in superclasses; false: only look for methods defined in this class. * @return */ @@ -134,8 +131,9 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine * If __init__ is defined, it is found first. This mimics the way initialization methods * are searched for and called by Python when a constructor call is made. * Since __new__ only makes sense for new-style classes, an old-style class never finds it with this method. + * * @param inherited true: search in superclasses, too. - * @param context TODO: DOC + * @param context TODO: DOC * @return a method that would be called first when an instance of this class is instantiated. */ @Nullable @@ -144,10 +142,9 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Finds a property with the specified name in the class or one of its ancestors. * - * - * @param name of the property + * @param name of the property * @param inherited - * @param context type eval (null to use loose context, but you better provide one) + * @param context type eval (null to use loose context, but you better provide one) * @return descriptor of property accessors, or null if such property does not exist. */ @Nullable @@ -155,11 +152,20 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Apply a processor to every method, looking at superclasses in method resolution order as needed. + * Consider using {@link PyClassLikeType#visitMembers(Processor, boolean, TypeEvalContext)} + * * @param processor what to apply * @param inherited true: search in superclasses, too. + * @param context loose context will be used if no context provided + * @see PyClassLikeType#visitMembers(Processor, boolean, TypeEvalContext) */ - boolean visitMethods(Processor processor, boolean inherited); + boolean visitMethods(Processor processor, boolean inherited, @Nullable TypeEvalContext context); + /** + * Consider using {@link PyClassLikeType#visitMembers(Processor, boolean, TypeEvalContext)} + * + * @see PyClassLikeType#visitMembers(Processor, boolean, TypeEvalContext) + */ boolean visitClassAttributes(Processor processor, boolean inherited, TypeEvalContext context); /** @@ -168,6 +174,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine * This method does not access AST if underlying PSI is stub based. * Note that only own attrs are fetched, not parent attrs. * If you need parent attributes, consider using {@link #getClassAttributesInherited(TypeEvalContext)} + * * @see #getClassAttributesInherited(TypeEvalContext) */ List getClassAttributes(); @@ -176,6 +183,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Returns all class attributes this class class contains, including inherited one. * Process may be heavy, depending or your context. + * * @param context context to use for this process * @return list of attrs. */ @@ -202,13 +210,14 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine PyClass findNestedClass(String name, boolean inherited); /** - * @return true if the class is new-style and descends from 'object'. * @param context + * @return true if the class is new-style and descends from 'object'. */ boolean isNewStyleClass(TypeEvalContext context); /** * Scan properties in order of definition, until processor returns true for one of them. + * * @param processor to check properties * @param inherited whether inherited properties need to be scanned, too * @return a property that processor accepted, or null. @@ -235,6 +244,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Returns the aggregated list of names defined in __slots__ attributes of the class and its ancestors. + * * @param context (will be used default if null) */ @Nullable @@ -253,12 +263,14 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine String getDocStringValue(); boolean processClassLevelDeclarations(@NotNull PsiScopeProcessor processor); + boolean processInstanceLevelDeclarations(@NotNull PsiScopeProcessor processor, @Nullable PsiElement location); //TODO: Add "addMetaClass" or move methods out of here + /** * Returns the type representing the metaclass of the class if it is explicitly set, null otherwise. - * + *

* The metaclass might be defined outside the class in case of Python 2 file-level __metaclass__ attributes. */ @Nullable @@ -266,14 +278,13 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine /** * Returns the expression that defines the metaclass of the class. - * + *

* Operates at the AST level. */ @Nullable PyExpression getMetaClassExpression(); /** - * * @param context eval context * @return {@link com.jetbrains.python.psi.types.PyType} casted if it has right type */ diff --git a/platform/core-impl/src/com/intellij/psi/filters/InitializableFilter.java b/python/psi-api/src/com/jetbrains/python/psi/PyWithAncestors.java similarity index 52% rename from platform/core-impl/src/com/intellij/psi/filters/InitializableFilter.java rename to python/psi-api/src/com/jetbrains/python/psi/PyWithAncestors.java index e6f326c7a070..fe2312eaed74 100644 --- a/platform/core-impl/src/com/intellij/psi/filters/InitializableFilter.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyWithAncestors.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -13,16 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package com.jetbrains.python.psi; -package com.intellij.psi.filters; +import com.jetbrains.python.psi.types.PyClassLikeType; +import com.jetbrains.python.psi.types.TypeEvalContext; +import org.jetbrains.annotations.NotNull; + +import java.util.List; /** - * Created by IntelliJ IDEA. - * User: ik - * Date: 22.04.2003 - * Time: 16:15:21 - * To change this template use Options | File Templates. + * Class or class-like entity with ancestors + * + * @author Ilya.Kazakevich */ -public interface InitializableFilter extends ElementFilter{ - void init(Object[] fromGetter); +public interface PyWithAncestors { + /** + * Returns types of all ancestors from the hierarchy. + */ + @NotNull + List getAncestorTypes(@NotNull TypeEvalContext context); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java index 361ab663d6be..8a279c94e4fb 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java @@ -15,8 +15,11 @@ */ package com.jetbrains.python.psi.types; +import com.intellij.psi.PsiElement; +import com.intellij.util.Processor; import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.PyWithAncestors; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import org.jetbrains.annotations.NotNull; @@ -27,7 +30,7 @@ import java.util.List; /** * @author vlan */ -public interface PyClassLikeType extends PyCallableType { +public interface PyClassLikeType extends PyCallableType, PyWithAncestors { boolean isDefinition(); PyClassLikeType toInstance(); @@ -43,6 +46,18 @@ public interface PyClassLikeType extends PyCallableType { @NotNull AccessDirection direction, @NotNull PyResolveContext resolveContext, boolean inherited); + // TODO: Pull to PyType at next iteration + /** + * Visits all class members. This method is better then bare class since it uses type info and supports not only classes but + * class-like structures as well. Consider using user-friendly wrapper {@link PyClassLikeTypeUtil#getMembersOfType(PyClassLikeType, Class, TypeEvalContext)} + * + * @param processor visitor + * @param inherited call on parents too + * @param context context to be used to resolve types + * @see PyClassLikeTypeUtil#getMembersOfType(PyClassLikeType, Class, TypeEvalContext) + */ + void visitMembers(@NotNull Processor processor, boolean inherited, @NotNull TypeEvalContext context); + boolean isValid(); @Nullable diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeTypeUtil.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeTypeUtil.java new file mode 100644 index 000000000000..263a8b367c04 --- /dev/null +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeTypeUtil.java @@ -0,0 +1,63 @@ +/* + * 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.jetbrains.python.psi.types; + +import com.intellij.psi.PsiElement; +import com.intellij.util.Processor; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Tools and wrappers around {@link PyClassLikeType} + * + * @author Ilya.Kazakevich + */ +public final class PyClassLikeTypeUtil { + private PyClassLikeTypeUtil() { + } + + /** + * Returns members of certain type from {@link PyClassLikeType} + * + * @param type type itself + * @param expectedMemberType expected member type + * @param context context to use + * @param expected member type + * @return collection of members + */ + @NotNull + public static Collection getMembersOfType(@NotNull final PyClassLikeType type, + @NotNull final Class expectedMemberType, + @NotNull final TypeEvalContext context) { + + final List result = new ArrayList(); + type.visitMembers(new Processor() { + @Override + public boolean process(final PsiElement t) { + if (expectedMemberType.isInstance(t)) { + @SuppressWarnings("unchecked") // Already checked + final T castedElement = (T)t; + result.add(castedElement); + } + return true; + } + }, true, context); + return result; + } +} diff --git a/python/src/com/jetbrains/python/PyCustomType.java b/python/src/com/jetbrains/python/PyCustomType.java index 56af324ab96a..0567d467e81d 100644 --- a/python/src/com/jetbrains/python/PyCustomType.java +++ b/python/src/com/jetbrains/python/PyCustomType.java @@ -178,6 +178,17 @@ public class PyCustomType implements PyClassLikeType { return resolveMember(name, location, direction, resolveContext, true); } + @NotNull + @Override + public final List getAncestorTypes(@NotNull final TypeEvalContext context) { + final Collection result = new LinkedHashSet(); + for (final PyClassLikeType type : myTypesToMimic) { + result.addAll(type.getAncestorTypes(context)); + } + + return new ArrayList(result); + } + @Override public final Object[] getCompletionVariants(final String completionPrefix, final PsiElement location, final ProcessingContext context) { final Collection lookupElements = new ArrayList(); @@ -241,6 +252,13 @@ public class PyCustomType implements PyClassLikeType { } } + @Override + public void visitMembers(@NotNull final Processor processor, final boolean inherited, @NotNull TypeEvalContext context) { + for (final PyClassLikeType type : myTypesToMimic) { + type.visitMembers(processor, inherited, context); + } + } + /** * Predicate that filters completion using {@link #myFilter} */ diff --git a/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java b/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java index 2985f8276b22..8f48b7f10e8e 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java @@ -35,7 +35,6 @@ import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.PyTargetExpression; import com.jetbrains.python.psi.PyUtil; -import com.jetbrains.python.psi.impl.blockEvaluator.PyEvaluationContext; import com.jetbrains.python.psi.search.PyClassInheritorsSearch; import com.jetbrains.python.psi.search.PyOverridingMethodsSearch; import com.jetbrains.python.psi.search.PySuperMethodsSearch; @@ -111,7 +110,8 @@ public class PyLineMarkerProvider implements LineMarkerProvider, PyLineSeparator @Nullable protected Query search(final PsiElement elt) { if (!(elt.getParent() instanceof PyFunction)) return null; - return PySuperMethodsSearch.search((PyFunction)elt.getParent()); + final TypeEvalContext context = TypeEvalContext.codeAnalysis(elt.getProject(), null); + return PySuperMethodsSearch.search((PyFunction)elt.getParent(), context); } }; @@ -180,7 +180,8 @@ public class PyLineMarkerProvider implements LineMarkerProvider, PyLineSeparator if (PyNames.INIT.equals(function.getName())) { return null; } - final PsiElement superMethod = PySuperMethodsSearch.search(function).findFirst(); + final TypeEvalContext context = TypeEvalContext.codeAnalysis(element.getProject(), null); + final PsiElement superMethod = PySuperMethodsSearch.search(function, context).findFirst(); if (superMethod != null) { PyClass superClass = null; if (superMethod instanceof PyFunction) { diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index 6f8ecba47696..6d85d760207d 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -40,8 +40,7 @@ import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyFunctionBuilder; import com.jetbrains.python.psi.impl.PyPsiUtils; -import com.jetbrains.python.psi.types.PyNoneType; -import com.jetbrains.python.psi.types.TypeEvalContext; +import com.jetbrains.python.psi.types.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -73,25 +72,32 @@ public class PyOverrideImplementUtil { } final PyClass pyClass = PsiTreeUtil.getParentOfType(element, PyClass.class, false); if (pyClass == null && element instanceof PsiWhiteSpace && element.getPrevSibling() instanceof PyClass) { - return (PyClass) element.getPrevSibling(); + return (PyClass)element.getPrevSibling(); } return pyClass; } public static void chooseAndOverrideMethods(final Project project, @NotNull final Editor editor, @NotNull final PyClass pyClass) { + + FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_OVERRIDE_IMPLEMENT); chooseAndOverrideOrImplementMethods(project, editor, pyClass); } private static void chooseAndOverrideOrImplementMethods(final Project project, - @NotNull final Editor editor, - @NotNull final PyClass pyClass) { + @NotNull final Editor editor, + @NotNull final PyClass pyClass) { LOG.assertTrue(pyClass.isValid()); ApplicationManager.getApplication().assertReadAccessAllowed(); - final Collection superFunctions = getAllSuperFunctions(pyClass); - chooseAndOverrideOrImplementMethods(project, editor, pyClass, superFunctions, "Select Methods to Override", false); + final Set result = new HashSet(); + TypeEvalContext context = TypeEvalContext.codeCompletion(project, null); + final Collection superFunctions = getAllSuperFunctions(pyClass, context); + + + result.addAll(superFunctions); + chooseAndOverrideOrImplementMethods(project, editor, pyClass, result, "Select Methods to Override", false); } public static void chooseAndOverrideOrImplementMethods(@NotNull final Project project, @@ -155,16 +161,17 @@ public class PyOverrideImplementUtil { final PyStatementList statementList = pyClass.getStatementList(); final int offset = editor.getCaretModel().getOffset(); PsiElement anchor = null; - for (PyStatement statement: statementList.getStatements()) { + for (PyStatement statement : statementList.getStatements()) { if (statement.getTextRange().getStartOffset() < offset || - (statement instanceof PyExpressionStatement && ((PyExpressionStatement)statement).getExpression() instanceof PyStringLiteralExpression)) { + (statement instanceof PyExpressionStatement && + ((PyExpressionStatement)statement).getExpression() instanceof PyStringLiteralExpression)) { anchor = statement; } } PyFunction element = null; for (PyMethodMember newMember : newMembers) { - PyFunction baseFunction = (PyFunction) newMember.getPsiElement(); + PyFunction baseFunction = (PyFunction)newMember.getPsiElement(); final PyFunctionBuilder builder = buildOverriddenFunction(pyClass, baseFunction, implement); PyFunction function = builder.addFunctionAfter(statementList, anchor, LanguageLevel.forElement(statementList)); element = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(function); @@ -210,7 +217,7 @@ public class PyOverrideImplementUtil { boolean hadStar = false; List parameters = new ArrayList(); - for (PyParameter parameter: baseParams) { + for (PyParameter parameter : baseParams) { final PyNamedParameter pyNamedParameter = parameter.getAsNamed(); if (pyNamedParameter != null) { String repr = pyNamedParameter.getRepr(false); @@ -244,7 +251,7 @@ public class PyOverrideImplementUtil { PsiElement outerClass = PsiTreeUtil.getParentOfType(pyClass, PyClass.class, true, PyFunction.class); String className = pyClass.getName(); final List nameResult = Lists.newArrayList(className); - while(outerClass != null) { + while (outerClass != null) { nameResult.add(0, ((PyClass)outerClass).getName()); outerClass = PsiTreeUtil.getParentOfType(outerClass, PyClass.class, true, PyFunction.class); } @@ -297,7 +304,7 @@ public class PyOverrideImplementUtil { final PyExpression[] superClassExpressions = fromClass.getSuperClassExpressions(); for (PyExpression expression : superClassExpressions) { if (expression instanceof PyReferenceExpression) { - PsiElement target = ((PyReferenceExpression) expression).getReference().resolve(); + PsiElement target = ((PyReferenceExpression)expression).getReference().resolve(); if (target == toClass) { return expression.getText(); } @@ -307,13 +314,24 @@ public class PyOverrideImplementUtil { } @NotNull - public static Collection getAllSuperFunctions(@NotNull PyClass pyClass) { + public static Collection getAllSuperFunctions(@NotNull PyClass pyClass, @NotNull TypeEvalContext context) { + + // This is a legacy approach. Should be removed soon since type-based members should be enough final Map superFunctions = new HashMap(); for (PyFunction function : pyClass.getMethods(true)) { if (!superFunctions.containsKey(function.getName())) { superFunctions.put(function.getName(), function); } } - return superFunctions.values(); + + + + final Set functions = new HashSet(superFunctions.values()); + final PyClassLikeType type = PyUtil.as(context.getType(pyClass), PyClassLikeType.class); + + if (type != null) { + functions.addAll(PyClassLikeTypeUtil.getMembersOfType(type, PyFunction.class, context)); + } + return functions; } } diff --git a/python/src/com/jetbrains/python/codeInsight/testIntegration/CreateTestAction.java b/python/src/com/jetbrains/python/codeInsight/testIntegration/CreateTestAction.java index 8accdeb59e63..c4eb05808086 100644 --- a/python/src/com/jetbrains/python/codeInsight/testIntegration/CreateTestAction.java +++ b/python/src/com/jetbrains/python/codeInsight/testIntegration/CreateTestAction.java @@ -83,7 +83,7 @@ public class CreateTestAction extends PsiElementBaseIntentionAction { methods.add(pyFunction); return true; } - }, false); + }, false, null); d.methodsSize(methods.size()); int i = 0; diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java index cf7659fcf975..d17062befeb3 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * 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. @@ -446,10 +446,9 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory envs = myCommandLineArgumentsProvider.getAdditionalEnvs(); if (envs != null) { - EncodingEnvironmentUtil.fixDefaultEncodingIfMac(envs, getProject()); + EncodingEnvironmentUtil.setLocaleEnvironmentIfMac(envs, EncodingProjectManager.getInstance(getProject()).getDefaultCharset()); } - final Process server = ProcessRunner - .createProcess(getWorkingDir(), envs, myCommandLineArgumentsProvider.getArguments()); + Process server = ProcessRunner.createProcess(getWorkingDir(), envs, myCommandLineArgumentsProvider.getArguments()); try { myPydevConsoleCommunication = new PydevConsoleCommunication(getProject(), myPorts[0], server, myPorts[1]); } diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java index ec2fc545ab22..54382198d8c3 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java @@ -107,6 +107,14 @@ class PyDocumentationBuilder { PythonDialectsTokenSetProvider.INSTANCE.getKeywordTokens().contains(elementDefinition.getNode().getElementType())) { buildForKeyword(elementDefinition.getText()); } + final String url = PythonDocumentationProvider.getUrlFor(myElement, myOriginalElement, true); + if (url != null) { + myEpilog.addItem(BR); + myEpilog.addWith(TagBold, $("External documentation:")); + myEpilog.addItem(BR); + myEpilog.addItem("").addItem(url).addItem(""); + } + if (myBody.isEmpty() && myEpilog.isEmpty()) { return null; // got nothing substantial to say! } diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index bf705cda01d4..a7c2d8eb5ba1 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -355,7 +355,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i } @Nullable - private static String getUrlFor(PsiElement element, PsiElement originalElement, boolean checkExistence) { + public static String getUrlFor(PsiElement element, PsiElement originalElement, boolean checkExistence) { PsiFileSystemItem file = element instanceof PsiFileSystemItem ? (PsiFileSystemItem)element : element.getContainingFile(); if (file == null) return null; if (PyNames.INIT_DOT_PY.equals(file.getName())) { diff --git a/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java b/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java index b4d50d6af945..f02f6bb0e35e 100644 --- a/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java +++ b/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java @@ -23,6 +23,7 @@ import com.intellij.psi.PsiFileSystemItem; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyImportedModule; import com.jetbrains.python.psi.search.PySuperMethodsSearch; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -57,7 +58,8 @@ public class PyFindUsagesHandlerFactory extends FindUsagesHandlerFactory { } if (element instanceof PyFunction) { if (!forHighlightUsages) { - final Collection superMethods = PySuperMethodsSearch.search((PyFunction)element, true).findAll(); + TypeEvalContext context = TypeEvalContext.userInitiated(element.getProject(), null); + final Collection superMethods = PySuperMethodsSearch.search((PyFunction)element, true, context).findAll(); if (superMethods.size() > 0) { final PsiElement next = superMethods.iterator().next(); // TODO should do this for Jython functions overriding Java methods too diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java b/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java index c48c4ffffbef..e9649ecabc15 100644 --- a/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java +++ b/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java @@ -28,6 +28,7 @@ import com.jetbrains.python.findUsages.PyFunctionFindUsagesHandler; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.search.PySuperMethodsSearch; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -128,7 +129,8 @@ public class PyStaticCallHierarchyUtil { @Nullable private static FindUsagesHandler createFindUsageHandler(@NotNull final PsiElement element) { if (element instanceof PyFunction) { - final Collection superMethods = PySuperMethodsSearch.search((PyFunction)element, true).findAll(); + final TypeEvalContext context = TypeEvalContext.userInitiated(element.getProject(), null); + final Collection superMethods = PySuperMethodsSearch.search((PyFunction)element, true, context).findAll(); if (superMethods.size() > 0) { final PsiElement next = superMethods.iterator().next(); if (next instanceof PyFunction && !isInObject((PyFunction)next)) { diff --git a/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java b/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java index 6e5a34b9194d..481db69e0594 100644 --- a/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java @@ -66,7 +66,7 @@ public class PyAbstractClassInspection extends PyInspection { return; } final Set toBeImplemented = new HashSet(); - final Collection functions = PyOverrideImplementUtil.getAllSuperFunctions(pyClass); + final Collection functions = PyOverrideImplementUtil.getAllSuperFunctions(pyClass, myTypeEvalContext); for (PyFunction method : functions) { if (isAbstractMethodForClass(method, pyClass)) { toBeImplemented.add(method); diff --git a/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java b/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java index fccf4233fb8e..70461514fa7d 100644 --- a/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyMethodMayBeStaticInspection.java @@ -64,7 +64,7 @@ public class PyMethodMayBeStaticInspection extends PyInspection { final PyClass containingClass = node.getContainingClass(); if (containingClass == null) return; if (PythonUnitTestUtil.isUnitTestCaseClass(containingClass)) return; - final PsiElement firstSuper = PySuperMethodsSearch.search(node).findFirst(); + final PsiElement firstSuper = PySuperMethodsSearch.search(node, myTypeEvalContext).findFirst(); if (firstSuper != null) return; final PyFunction firstOverride = PyOverridingMethodsSearch.search(node, true).findFirst(); if (firstOverride != null) return; diff --git a/python/src/com/jetbrains/python/inspections/PyMethodOverridingInspection.java b/python/src/com/jetbrains/python/inspections/PyMethodOverridingInspection.java index 99093da0fb99..9540013c42e0 100644 --- a/python/src/com/jetbrains/python/inspections/PyMethodOverridingInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyMethodOverridingInspection.java @@ -61,7 +61,7 @@ public class PyMethodOverridingInspection extends PyInspection { String name = function.getName(); if (PyNames.INIT.equals(name) || PyNames.NEW.equals(name)) return; // these are expected to change signature // real work - for (PsiElement psiElement : PySuperMethodsSearch.search(function)) { + for (PsiElement psiElement : PySuperMethodsSearch.search(function, myTypeEvalContext)) { if (psiElement instanceof PyFunction) { final PyFunction baseMethod = (PyFunction)psiElement; final PyClass baseClass = baseMethod.getContainingClass(); diff --git a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java index 8dd34f25f31d..7c245ee8324f 100644 --- a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java @@ -138,7 +138,7 @@ public class PyPep8NamingInspection extends PyInspection { } private boolean isOverriddenMethod(@NotNull PyFunction function) { - return PySuperMethodsSearch.search(function).findFirst() != null; + return PySuperMethodsSearch.search(function, myTypeEvalContext).findFirst() != null; } private boolean isIgnoredOrHasIgnoredAncestor(@NotNull PyClass pyClass) { diff --git a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java index 14e5c78e8c81..03410e2fb8e4 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java +++ b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java @@ -349,11 +349,11 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { return false; } - private static boolean ignoreUnusedParameters(PyFunction func, Set functionsWithInheritors) { + private boolean ignoreUnusedParameters(PyFunction func, Set functionsWithInheritors) { if (functionsWithInheritors.contains(func)) { return true; } - if (PySuperMethodsSearch.search(func).findFirst() != null || + if (PySuperMethodsSearch.search(func, myTypeEvalContext).findFirst() != null || PyOverridingMethodsSearch.search(func, true).findFirst() != null) { functionsWithInheritors.add(func); return true; diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyChangeSignatureQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyChangeSignatureQuickFix.java index 4565cc9050c9..091bd88bc82d 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyChangeSignatureQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyChangeSignatureQuickFix.java @@ -24,6 +24,7 @@ import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.search.PySuperMethodsSearch; +import com.jetbrains.python.psi.types.TypeEvalContext; import com.jetbrains.python.refactoring.changeSignature.PyChangeSignatureDialog; import com.jetbrains.python.refactoring.changeSignature.PyMethodDescriptor; import com.jetbrains.python.refactoring.changeSignature.PyParameterInfo; @@ -58,7 +59,8 @@ public class PyChangeSignatureQuickFix implements LocalQuickFix { assert cls != null; final String functionName = function.getName(); final String complementaryName = PyNames.NEW.equals(functionName) ? PyNames.INIT : PyNames.NEW; - final PyFunction complementaryMethod = myOverridenMethod ? (PyFunction)PySuperMethodsSearch.search(function).findFirst() + final TypeEvalContext context = TypeEvalContext.userInitiated(project, descriptor.getEndElement().getContainingFile()); + final PyFunction complementaryMethod = myOverridenMethod ? (PyFunction)PySuperMethodsSearch.search(function, context).findFirst() : cls.findMethodByName(complementaryName, true); assert complementaryMethod != null; diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 0ff40fc7f636..d43805f709b5 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -552,7 +552,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla public PyFunction findMethodByName(@Nullable final String name, boolean inherited) { if (name == null) return null; NameFinder proc = new NameFinder(name); - visitMethods(proc, inherited); + visitMethods(proc, inherited, null); return proc.getResult(); } @@ -920,11 +920,11 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla } } - public boolean visitMethods(Processor processor, boolean inherited) { - return visitMethods(processor, inherited, false, null); + public boolean visitMethods(Processor processor, boolean inherited, @Nullable final TypeEvalContext context) { + return visitMethods(processor, inherited, false, context); } - public boolean visitMethods(Processor processor, + private boolean visitMethods(Processor processor, boolean inherited, boolean skipClassObj, TypeEvalContext context) { PyFunction[] methods = getMethods(false); @@ -934,7 +934,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla if (skipClassObj && PyNames.FAKE_OLD_BASE.equals(ancestor.getName())) { continue; } - if (!ancestor.visitMethods(processor, false)) { + if (!ancestor.visitMethods(processor, false, null)) { return false; } } diff --git a/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java b/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java index 26d2c73f3f78..6a92bb1d1678 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java +++ b/python/src/com/jetbrains/python/psi/impl/references/KeywordArgumentCompletionUtil.java @@ -88,7 +88,7 @@ public class KeywordArgumentCompletionUtil { // nothing interesting besides self and **kwargs, let's look at superclass (PY-778) if (fromStatementCallCollector.isKwArgsTransit()) { - final PsiElement superMethod = PySuperMethodsSearch.search(def).findFirst(); + final PsiElement superMethod = PySuperMethodsSearch.search(def, context).findFirst(); if (superMethod instanceof PyFunction) { addKeywordArgumentVariants((PyFunction)superMethod, callExpr, ret, visited); } diff --git a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearch.java b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearch.java index 2e1020e78c10..41fc88fa2730 100644 --- a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearch.java +++ b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearch.java @@ -20,6 +20,8 @@ import com.intellij.psi.search.searches.ExtensibleQueryFactory; import com.intellij.util.Query; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.types.TypeEvalContext; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -43,10 +45,11 @@ public class PySuperMethodsSearch extends ExtensibleQueryFactory superMethods = new ArrayList(search(function, true).findAll()); + TypeEvalContext context = TypeEvalContext.userInitiated(function.getProject(), null); + List superMethods = new ArrayList(search(function, true, context).findAll()); while (superMethods.size() > 0) { function = getBaseMethod(superMethods, function.getContainingClass()); - superMethods = new ArrayList(search(function, true).findAll()); + superMethods = new ArrayList(search(function, true, context).findAll()); } return function; } @@ -54,10 +57,17 @@ public class PySuperMethodsSearch extends ExtensibleQueryFactory search(final PyFunction derivedMethod) { - final SearchParameters parameters = new SearchParameters(derivedMethod, false); + public static Query search(final PyFunction derivedMethod, @Nullable final TypeEvalContext context) { + final SearchParameters parameters = new SearchParameters(derivedMethod, false, context); return INSTANCE.createUniqueResultsQuery(parameters); } - public static Query search(final PyFunction derivedMethod, boolean deepSearch) { - final SearchParameters parameters = new SearchParameters(derivedMethod, deepSearch); + public static Query search(final PyFunction derivedMethod, final boolean deepSearch, @Nullable final TypeEvalContext context) { + final SearchParameters parameters = new SearchParameters(derivedMethod, deepSearch, context); return INSTANCE.createUniqueResultsQuery(parameters); } } diff --git a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java index 19754493c956..6a3fc84073f5 100644 --- a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java +++ b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java @@ -19,6 +19,9 @@ import com.intellij.psi.PsiElement; import com.intellij.util.Processor; import com.intellij.util.QueryExecutor; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.types.PyClassLikeType; +import com.jetbrains.python.psi.types.PyClassLikeTypeUtil; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import java.util.HashSet; @@ -28,7 +31,8 @@ import java.util.Set; * @author yole */ public class PySuperMethodsSearchExecutor implements QueryExecutor { - public boolean execute(@NotNull final PySuperMethodsSearch.SearchParameters queryParameters, @NotNull final Processor consumer) { + public boolean execute(@NotNull final PySuperMethodsSearch.SearchParameters queryParameters, + @NotNull final Processor consumer) { PyFunction func = queryParameters.getDerivedMethod(); String name = func.getName(); PyClass containingClass = func.getContainingClass(); @@ -56,6 +60,21 @@ public class PySuperMethodsSearchExecutor implements QueryExecutor findProperty(String name, AccessDirection direction, boolean inherited, @Nullable TypeEvalContext context) { + private Ref findProperty(String name, + AccessDirection direction, + boolean inherited, + @Nullable TypeEvalContext context) { Ref resultRef = null; Property property = myClass.findProperty(name, inherited, context); if (property != null) { @@ -340,6 +346,12 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { return null; } + @NotNull + @Override + public final List getAncestorTypes(@NotNull final TypeEvalContext context) { + return myClass.getAncestorTypes(context); + } + @Nullable private static PsiElement resolveClassMember(@NotNull PyClass cls, boolean isDefinition, @@ -460,6 +472,28 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { return ret.toArray(); } + @Override + public void visitMembers(@NotNull final Processor processor, + final boolean inherited, + @NotNull final TypeEvalContext context) { + + myClass.visitMethods(new MyProcessorWrapper(processor), false, context); + myClass.visitClassAttributes(new MyProcessorWrapper(processor), false, context); + + // TODO: accept instance attributes as well + + if (!inherited) { + return; + } + + for (final PyClassLikeType type : getAncestorTypes(context)) { + if (type != null) { + // "false" because getAncestorTypes returns ALL ancestors, not only direct parents + type.visitMembers(processor, false, context); + } + } + } + private void addOwnClassMembers(PsiElement expressionHook, Set namesAlready, boolean suppressParentheses, List ret) { PyClass containingClass = PsiTreeUtil.getParentOfType(expressionHook, PyClass.class); if (containingClass != null) { @@ -476,7 +510,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { myClass.processClassLevelDeclarations(processor); // We are here because of completion (see call stack), so we use code complete here - final TypeEvalContext context = (expressionHook != null ? TypeEvalContext.codeCompletion(myClass.getProject(), myClass.getContainingFile()) :null); + final TypeEvalContext context = + (expressionHook != null ? TypeEvalContext.codeCompletion(myClass.getProject(), myClass.getContainingFile()) : null); List slots = myClass.isNewStyleClass(null) ? myClass.getSlots( context) : null; if (slots != null) { @@ -621,4 +656,18 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } return new PyClassTypeImpl(pyClass, isDefinition); } + + private static final class MyProcessorWrapper implements Processor { + private final Processor myProcessor; + + private MyProcessorWrapper(@NotNull final Processor processor) { + myProcessor = processor; + } + + @Override + public boolean process(final T t) { + myProcessor.process(t); + return true; + } + } } diff --git a/python/testData/override/circle.py b/python/testData/override/circle.py new file mode 100644 index 000000000000..668b154e091a --- /dev/null +++ b/python/testData/override/circle.py @@ -0,0 +1,7 @@ +class Spam(Eggs): + def spam_methods(self): + pass + +class Eggs(Spam): + def my_methods(self): + pass diff --git a/python/testData/override/circle_after.py b/python/testData/override/circle_after.py new file mode 100644 index 000000000000..dd4c1d343e98 --- /dev/null +++ b/python/testData/override/circle_after.py @@ -0,0 +1,10 @@ +class Spam(Eggs): + def spam_methods(self): + pass + +class Eggs(Spam): + def spam_methods(self): + super(Eggs, self).spam_methods() + + def my_methods(self): + pass diff --git a/python/testSrc/com/jetbrains/python/PyOverrideTest.java b/python/testSrc/com/jetbrains/python/PyOverrideTest.java index f807b289ed06..e89eb6c6bb7c 100644 --- a/python/testSrc/com/jetbrains/python/PyOverrideTest.java +++ b/python/testSrc/com/jetbrains/python/PyOverrideTest.java @@ -54,6 +54,13 @@ public class PyOverrideTest extends PyTestCase { return file.getTopLevelClasses().get(index); } + /** + * Ensures loops in class hierarchy does not lead to SO + */ + public final void testCircle() throws Exception { + doTest(); + } + public void testSimple() { doTest(); } diff --git a/xml/impl/src/com/intellij/psi/filters/TagNameFilter.java b/xml/impl/src/com/intellij/psi/filters/TagNameFilter.java index e1846cd39127..5a7cdbd46c9c 100644 --- a/xml/impl/src/com/intellij/psi/filters/TagNameFilter.java +++ b/xml/impl/src/com/intellij/psi/filters/TagNameFilter.java @@ -16,7 +16,6 @@ package com.intellij.psi.filters; import com.intellij.psi.xml.XmlTag; -import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls; /** @@ -28,14 +27,6 @@ import org.jetbrains.annotations.NonNls; */ public class TagNameFilter extends PlainTextFilter { - public TagNameFilter(){ - myValue = ArrayUtil.EMPTY_STRING_ARRAY; - } - - public TagNameFilter(@NonNls String value, boolean insensitiveFlag) { - super(value, insensitiveFlag); - } - public TagNameFilter(@NonNls String value){ super(value); } diff --git a/xml/xml-psi-impl/src/com/intellij/psi/filters/TextContainFilter.java b/xml/xml-psi-impl/src/com/intellij/psi/filters/TextContainFilter.java index 9af97cf8adc2..5c7c0b2d407a 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/filters/TextContainFilter.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/filters/TextContainFilter.java @@ -21,20 +21,11 @@ import com.intellij.psi.PsiElement; * @author spleaner */ public class TextContainFilter extends XmlTextFilter { - public TextContainFilter(String[] values){ - super(values); - } - - public TextContainFilter(String value1, String value2){ - super(value1, value2); - } public TextContainFilter(String value){ super(value); } - public TextContainFilter(){} - @Override public boolean isAcceptable(Object element, PsiElement context){ if(element != null) { diff --git a/xml/xml-psi-impl/src/com/intellij/psi/filters/TextStartFilter.java b/xml/xml-psi-impl/src/com/intellij/psi/filters/TextStartFilter.java deleted file mode 100644 index 1ccac507996e..000000000000 --- a/xml/xml-psi-impl/src/com/intellij/psi/filters/TextStartFilter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2000-2014 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.psi.filters; - -import com.intellij.psi.PsiElement; - -/** - * Created by IntelliJ IDEA. - * User: ik - * Date: 27.08.2003 - * Time: 18:18:38 - * To change this template use Options | File Templates. - */ -public class TextStartFilter extends XmlTextFilter{ - public TextStartFilter(String[] values){ - super(values); - } - - public TextStartFilter(String value1, String value2){ - super(value1, value2); - } - - public TextStartFilter(String value){ - super(value); - } - - public TextStartFilter(){} - - @Override - public boolean isAcceptable(Object element, PsiElement context){ - if(element != null) { - for (final String value : myValue) { - if (value == null) { - return true; - } - String elementValue = getTextByElement(element); - if (elementValue == null) return false; - if (elementValue.startsWith(value)) return true; - } - } - - return false; - } -} diff --git a/xml/xml-psi-impl/src/com/intellij/psi/filters/XmlTextFilter.java b/xml/xml-psi-impl/src/com/intellij/psi/filters/XmlTextFilter.java index 265911962240..7eb4c0d9aabf 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/filters/XmlTextFilter.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/filters/XmlTextFilter.java @@ -18,7 +18,6 @@ package com.intellij.psi.filters; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.xml.XmlTag; -import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls; /** @@ -28,18 +27,8 @@ import org.jetbrains.annotations.NonNls; * Time: 13:57:35 * To change this template use Options | File Templates. */ -public class XmlTextFilter implements ElementFilter, InitializableFilter{ - protected String[] myValue; - private boolean myCaseInsensitiveFlag = false; - - public XmlTextFilter(){ - myValue = ArrayUtil.EMPTY_STRING_ARRAY; - } - public XmlTextFilter(@NonNls String value, boolean incensetiveFlag){ - myCaseInsensitiveFlag = incensetiveFlag; - myValue = new String[1]; - myValue[0] = value; - } +public class XmlTextFilter implements ElementFilter { + protected final String[] myValue; public XmlTextFilter(@NonNls String value){ myValue = new String[1]; @@ -50,12 +39,6 @@ public class XmlTextFilter implements ElementFilter, InitializableFilter{ myValue = values; } - public XmlTextFilter(@NonNls String value1, @NonNls String value2){ - myValue = new String[2]; - myValue[0] = value1; - myValue[1] = value2; - } - @Override public boolean isClassAcceptable(Class hintClass){ return true; @@ -64,17 +47,11 @@ public class XmlTextFilter implements ElementFilter, InitializableFilter{ @Override public boolean isAcceptable(Object element, PsiElement context){ if(element != null) { + String text = getTextByElement(element); for (final String value : myValue) { - if (value == null) { + if (value == null || value.equals(text)) { return true; } - final String elementText = getTextByElement(element); - if (myCaseInsensitiveFlag) { - if (value.equalsIgnoreCase(elementText)) return true; - } - else { - if (value.equals(elementText)) return true; - } } } @@ -93,17 +70,6 @@ public class XmlTextFilter implements ElementFilter, InitializableFilter{ return ret; } - @Override - public void init(Object[] fromGetter){ - try{ - myValue = new String[fromGetter.length]; - System.arraycopy(fromGetter, 0, myValue, 0, fromGetter.length); - } - catch(ClassCastException cce){ - myValue = ArrayUtil.EMPTY_STRING_ARRAY; - } - } - protected String getTextByElement(Object element){ String elementValue = null; if(element instanceof PsiNamedElement){ diff --git a/xml/xml-psi-impl/src/com/intellij/psi/filters/position/RootTagFilter.java b/xml/xml-psi-impl/src/com/intellij/psi/filters/position/RootTagFilter.java index 8d53d2d95e2f..3f8fdd3880ca 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/filters/position/RootTagFilter.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/filters/position/RootTagFilter.java @@ -32,7 +32,6 @@ public class RootTagFilter extends PositionElementFilter{ setFilter(filter); } - public RootTagFilter(){} @Override public boolean isAcceptable(Object element, PsiElement scope){ if (!(element instanceof XmlDocument)) return false;