diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java index 28d0b986e4e7..081894d41c38 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java @@ -83,6 +83,9 @@ public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement static PsiExpression createCastExpression(PsiExpression originalExpression, Project project, PsiType type) throws IncorrectOperationException { // remove nested casts PsiElement element = PsiUtil.deparenthesizeExpression(originalExpression); + if (element == null){ + return null; + } PsiElementFactory factory = JavaPsiFacade.getInstance(originalExpression.getProject()).getElementFactory(); PsiTypeCastExpression typeCast = (PsiTypeCastExpression)factory.createExpressionFromText("(Type)value", null); diff --git a/platform/core-api/src/com/intellij/psi/PsiInvalidElementAccessException.java b/platform/core-api/src/com/intellij/psi/PsiInvalidElementAccessException.java index 7c6ee80f41bd..c25da4246627 100644 --- a/platform/core-api/src/com/intellij/psi/PsiInvalidElementAccessException.java +++ b/platform/core-api/src/com/intellij/psi/PsiInvalidElementAccessException.java @@ -21,6 +21,7 @@ import com.intellij.lang.Language; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.lang.ref.SoftReference; @@ -31,23 +32,27 @@ public class PsiInvalidElementAccessException extends RuntimeException { private final SoftReference myElementReference; // to prevent leaks, since exceptions are stored in IdeaLogger public PsiInvalidElementAccessException(PsiElement element) { - this(element, null, null); + this(element, (String)null); } - public PsiInvalidElementAccessException(PsiElement element, String message) { - this(element, message, null); + public PsiInvalidElementAccessException(PsiElement element, @Nullable String message) { + this(element, getMessageWithReason(element, message), null); } - public PsiInvalidElementAccessException(PsiElement element, Throwable cause) { - this(element, null, cause); + public PsiInvalidElementAccessException(PsiElement element, @Nullable Throwable cause) { + this(element, getMessageWithReason(element, null), cause); } - public PsiInvalidElementAccessException(PsiElement element, String message, Throwable cause) { - super((element != null ? "Element: " + element.getClass() + " because: " + reason(element) : "Unknown psi element") + - (message == null ? "" : "; " + message), cause); + public PsiInvalidElementAccessException(PsiElement element, @Nullable String message, @Nullable Throwable cause) { + super(message, cause); myElementReference = new SoftReference(element); } + private static String getMessageWithReason(@Nullable PsiElement element, @Nullable String message) { + return (element != null ? "Element: " + element.getClass() + " because: " + reason(element) : "Unknown psi element") + + (message == null ? "" : "; " + message); + } + @NonNls @NotNull private static String reason(@NotNull PsiElement root){ @@ -71,6 +76,7 @@ public class PsiInvalidElementAccessException extends RuntimeException { return "psi is outdated"; } + @Nullable public PsiElement getPsiElement() { return myElementReference.get(); } diff --git a/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java b/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java index 2f5d7064a34f..83ecc5fe832e 100644 --- a/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java +++ b/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java @@ -144,7 +144,7 @@ public class StubBasedPsiElementBase extends ASTDelegateP } PsiFile psi = (PsiFile)stub.getPsi(); if (psi == null) { - throw new PsiInvalidElementAccessException(this); + throw new PsiInvalidElementAccessException(this, "no psi for file stub " + stub, null); } return psi; } diff --git a/platform/lang-impl/src/com/intellij/codeEditor/printing/PrintManager.java b/platform/lang-impl/src/com/intellij/codeEditor/printing/PrintManager.java index d4b62b4a2b4a..5990b5900346 100644 --- a/platform/lang-impl/src/com/intellij/codeEditor/printing/PrintManager.java +++ b/platform/lang-impl/src/com/intellij/codeEditor/printing/PrintManager.java @@ -16,6 +16,7 @@ package com.intellij.codeEditor.printing; +import com.intellij.CommonBundle; import com.intellij.ide.highlighter.HighlighterFactory; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.LangDataKeys; @@ -28,12 +29,14 @@ import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.progress.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; +import javax.swing.*; import java.awt.print.*; import java.util.ArrayList; import java.util.Collections; @@ -151,8 +154,14 @@ class PrintManager { printerJob.print(); } - catch(PrinterException e) { - LOG.error(e); + catch(final PrinterException e) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + Messages.showErrorDialog(project, e.getMessage(), CommonBundle.getErrorTitle()); + } + }); + LOG.info(e); } catch(ProcessCanceledException e) { printerJob.cancel(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/UnSelectWordHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/UnSelectWordHandler.java index 11b98547c2c6..1fc5e46dfb52 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/UnSelectWordHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/UnSelectWordHandler.java @@ -25,14 +25,9 @@ import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.*; import com.intellij.util.Processor; -import java.util.List; - public class UnSelectWordHandler extends EditorActionHandler { private final EditorActionHandler myOriginalHandler; @@ -59,6 +54,11 @@ public class UnSelectWordHandler extends EditorActionHandler { private static void doAction(Editor editor, PsiFile file) { + if (file instanceof PsiCompiledFile) { + file = ((PsiCompiledFile)file).getDecompiledPsiFile(); + if (file == null) return; + } + if (!editor.getSelectionModel().hasSelection()) { return; } diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/impl/StructureViewFactoryImpl.java b/platform/lang-impl/src/com/intellij/ide/structureView/impl/StructureViewFactoryImpl.java index 85bb2f9a4d19..e50070a49826 100644 --- a/platform/lang-impl/src/com/intellij/ide/structureView/impl/StructureViewFactoryImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/structureView/impl/StructureViewFactoryImpl.java @@ -55,6 +55,7 @@ public final class StructureViewFactoryImpl extends StructureViewFactoryEx imple @SuppressWarnings({"WeakerAccess"}) public boolean AUTOSCROLL_MODE = true; @SuppressWarnings({"WeakerAccess"}) public boolean AUTOSCROLL_FROM_SOURCE = false; @SuppressWarnings({"WeakerAccess"}) public String ACTIVE_ACTIONS = ""; + public boolean SHOW_TOOLBAR = false; } private final Project myProject; @@ -85,6 +86,7 @@ public final class StructureViewFactoryImpl extends StructureViewFactoryEx imple return myStructureViewWrapperImpl; } + @NotNull public State getState() { return myState; } diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java index 9b7decc6e5b1..68bc2e80aba6 100644 --- a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java +++ b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java @@ -154,6 +154,10 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre myAutoScrollToSourceHandler = new MyAutoScrollToSourceHandler(); myAutoScrollFromSourceHandler = new MyAutoScrollFromSourceHandler(myProject, this); + if (getSettings().SHOW_TOOLBAR) { + setToolbar(createToolbar()); + } + installTree(); myCopyPasteDelegator = new CopyPasteDelegator(myProject, getTree()) { @@ -164,6 +168,10 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre }; } + private JComponent createToolbar() { + return ActionManager.getInstance().createActionToolbar(ActionPlaces.STRUCTURE_VIEW_TOOLBAR, createActionGroup(), true).getComponent(); + } + private void installTree() { getTree().getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); myAutoScrollToSourceHandler.install(getTree()); @@ -367,7 +375,24 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre } public ActionGroup getGearActions() { - return createActionGroup(true); + DefaultActionGroup group = createActionGroup(true); + group.addAction(new ToggleAction("Show Toolbar") { + @Override + public boolean isSelected(AnActionEvent e) { + return getSettings().SHOW_TOOLBAR; + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + setToolbar(state ? createToolbar() : null); + getSettings().SHOW_TOOLBAR = state; + } + }).setAsSecondary(true); + return group; + } + + private StructureViewFactoryImpl.State getSettings() { + return ((StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject)).getState(); } public AnAction[] getTitleActions() { @@ -381,7 +406,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre return createActionGroup(false); } - protected ActionGroup createActionGroup(boolean togglesOnly) { + protected DefaultActionGroup createActionGroup(boolean togglesOnly) { DefaultActionGroup result = new DefaultActionGroup(); Sorter[] sorters = myTreeModel.getSorters(); for (final Sorter sorter : sorters) { @@ -522,9 +547,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre return; } - StructureViewFactoryImpl structureViewFactory = (StructureViewFactoryImpl)StructureViewFactoryEx.getInstance(myProject); - - if (!structureViewFactory.getState().AUTOSCROLL_FROM_SOURCE) { + if (!getSettings().AUTOSCROLL_FROM_SOURCE) { return; } @@ -612,11 +635,11 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre protected boolean isAutoScrollMode() { return myShouldAutoScroll && !myProject.isDisposed() - && ((StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject)).getState().AUTOSCROLL_MODE; + && getSettings().AUTOSCROLL_MODE; } protected void setAutoScrollMode(boolean state) { - ((StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject)).getState().AUTOSCROLL_MODE = state; + getSettings().AUTOSCROLL_MODE = state; } protected void scrollToSource(Component tree) { @@ -659,13 +682,11 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre } protected boolean isAutoScrollEnabled() { - StructureViewFactoryImpl structureViewFactory = (StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject); - return structureViewFactory.getState().AUTOSCROLL_FROM_SOURCE; + return getSettings().AUTOSCROLL_FROM_SOURCE; } protected void setAutoScrollEnabled(boolean state) { - StructureViewFactoryImpl structureViewFactory = (StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject); - structureViewFactory.getState().AUTOSCROLL_FROM_SOURCE = state; + getSettings().AUTOSCROLL_FROM_SOURCE = state; final FileEditor[] selectedEditors = FileEditorManager.getInstance(myProject).getSelectedEditors(); if (selectedEditors.length > 0 && state) { scrollToSelectedElement(); diff --git a/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java b/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java index ae0e4b15a1b8..9eb41468c81c 100644 --- a/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java +++ b/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java @@ -4,7 +4,6 @@ package com.intellij.openapi.paths; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.TextRange; -import com.intellij.psi.ElementManipulator; import com.intellij.psi.ElementManipulators; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; @@ -21,9 +20,7 @@ public abstract class PathReferenceProviderBase implements PathReferenceProvider public boolean createReferences(@NotNull final PsiElement psiElement, final @NotNull List references, final boolean soft) { - final ElementManipulator manipulator = ElementManipulators.getManipulator(psiElement); - assert manipulator != null; - final TextRange range = manipulator.getRangeInElement(psiElement); + final TextRange range = ElementManipulators.getValueTextRange(psiElement); int offset = range.getStartOffset(); int endOffset = range.getEndOffset(); final String elementText = psiElement.getText(); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java b/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java index 8ac88742c368..7493f93c75e2 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/SimpleToolWindowPanel.java @@ -74,13 +74,18 @@ public class SimpleToolWindowPanel extends JPanel implements QuickActionProvider }); } - public void setToolbar(JComponent c) { + public void setToolbar(@Nullable JComponent c) { + if (c == null) { + remove(myToolbar); + } myToolbar = c; - if (myVertical) { - add(c, BorderLayout.NORTH); - } else { - add(c, BorderLayout.WEST); + if (c != null) { + if (myVertical) { + add(c, BorderLayout.NORTH); + } else { + add(c, BorderLayout.WEST); + } } revalidate(); diff --git a/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java b/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java index 77f0d455880b..b4d192d6b53b 100644 --- a/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java +++ b/platform/platform-api/src/com/intellij/util/ui/tree/TreeUtil.java @@ -754,7 +754,7 @@ public final class TreeUtil { @NotNull public static ArrayList childrenToArray(@NotNull final TreeNode node) { - ApplicationManager.getApplication().assertIsDispatchThread(); + //ApplicationManager.getApplication().assertIsDispatchThread(); final ArrayList result = new ArrayList(); for(int i = 0; i < node.getChildCount(); i++){ TreeNode child = node.getChildAt(i); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java index 6d072c7bb84a..c97f898be30a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java @@ -39,6 +39,7 @@ import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileChooser.FileChooserFactory; import com.intellij.openapi.fileChooser.FileSaverDescriptor; +import com.intellij.openapi.fileChooser.FileSaverDialog; import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl; import com.intellij.openapi.fileTypes.BinaryFileTypeDecompilers; @@ -430,33 +431,42 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl @Nullable private static VirtualFile handleExternalDeletion(VirtualFile file) { String path = file.getPath(); - String[] options = {"Restore", "Save under a different name", "Discard changes"}; + int result = suggestToRestoreDeletedFile(path, new String[]{"Restore", "Save under a different name", "Discard changes"}); + if (result == 0) return createFile(new File(path)); + if (result == 1) return saveUnderDifferentName(file); + return null; + } + + @Nullable + private static VirtualFile saveUnderDifferentName(VirtualFile file) { + FileSaverDescriptor descriptor = new FileSaverDescriptor("Save File As...", "Save file under a different name"); + FileSaverDialog dialog = FileChooserFactory.getInstance().createSaveFileDialog(descriptor, (Project)null); + VirtualFileWrapper wrapper = dialog.save(findValidParent(file), file.getName()); + return wrapper == null ? null : createFile(wrapper.getFile()); + } + + private static int suggestToRestoreDeletedFile(String path, String[] options) { String message = "File has been deleted on disk: " + FileUtil.toSystemDependentName(path); - int result = Messages.showDialog(message, "File Deleted", options, 0, Messages.getQuestionIcon()); - File newFile; - if (result == 0) { - newFile = new File(path); - } else if (result == 1) { - VirtualFile validParent = file; - while (validParent != null && !validParent.isValid()) { - validParent = validParent.getParent(); - } - final VirtualFileWrapper wrapper = FileChooserFactory.getInstance().createSaveFileDialog( - new FileSaverDescriptor("Save File As...", "Save file under a different name"), (Project)null).save(validParent, file.getName()); - if (wrapper == null) { - return null; - } - newFile = wrapper.getFile(); - } else { - return null; - } + return Messages.showDialog(message, "File Deleted", options, 0, Messages.getQuestionIcon()); + } + + @Nullable + private static VirtualFile createFile(File newFile) { if (!FileUtil.createIfDoesntExist(newFile)) { return null; } - return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(newFile); } + @Nullable + private static VirtualFile findValidParent(VirtualFile file) { + VirtualFile validParent = file; + while (validParent != null && !validParent.isValid()) { + validParent = validParent.getParent(); + } + return validParent; + } + private static void updateModifiedProperty(@NotNull VirtualFile file) { for (Project project : ProjectManager.getInstance().getOpenProjects()) { FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index ff5fd8e1acb4..88cf11a366f7 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -440,6 +440,6 @@ - + diff --git a/plugins/groovy/resources/intentionDescriptions/RemoveRedundantClassPropertyIntention/after.groovy.template b/plugins/groovy/resources/intentionDescriptions/RemoveRedundantClassPropertyIntention/after.groovy.template new file mode 100644 index 000000000000..9a103df6a9b5 --- /dev/null +++ b/plugins/groovy/resources/intentionDescriptions/RemoveRedundantClassPropertyIntention/after.groovy.template @@ -0,0 +1 @@ +print String diff --git a/plugins/groovy/resources/intentionDescriptions/RemoveRedundantClassPropertyIntention/before.groovy.template b/plugins/groovy/resources/intentionDescriptions/RemoveRedundantClassPropertyIntention/before.groovy.template new file mode 100644 index 000000000000..0d7152414b19 --- /dev/null +++ b/plugins/groovy/resources/intentionDescriptions/RemoveRedundantClassPropertyIntention/before.groovy.template @@ -0,0 +1 @@ +print String.class diff --git a/plugins/groovy/resources/intentionDescriptions/RemoveRedundantClassPropertyIntention/description.html b/plugins/groovy/resources/intentionDescriptions/RemoveRedundantClassPropertyIntention/description.html new file mode 100644 index 000000000000..fa873b0f8636 --- /dev/null +++ b/plugins/groovy/resources/intentionDescriptions/RemoveRedundantClassPropertyIntention/description.html @@ -0,0 +1,5 @@ + + +This intention removes redundant explicit .class reference. + + \ No newline at end of file diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index e1c04efa8a23..3fe722e23a93 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -1178,6 +1178,11 @@ intention.category.groovy/intention.category.groovy.style org.jetbrains.plugins.groovy.intentions.style.ConvertToGeeseBracesIntention + + org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle + intention.category.groovy/intention.category.groovy.style + org.jetbrains.plugins.groovy.intentions.style.RemoveRedundantClassPropertyIntention + org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle intention.category.groovy/intention.category.groovy.style diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties index 3f7457df039e..a592fb0ddb12 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties @@ -173,4 +173,6 @@ remove.unnecessary.escape.characters.intention.family.name=Remove unnecessary es gr.break.string.on.line.breaks.intention.name=Break string on '\\n' gr.break.string.on.line.breaks.intention.family.name=Break string on '\\n' gr.create.missing.switch.branches.intention.name=Create missing 'switch' branches -gr.create.missing.switch.branches.intention.family.name=Create missing 'switch' branches \ No newline at end of file +gr.create.missing.switch.branches.intention.family.name=Create missing 'switch' branches +remove.redundant.class.property.intention.name=Remove redundant .class +remove.redundant.class.property.intention.family.name=Remove redundant .class \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/RemoveRedundantClassPropertyIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/RemoveRedundantClassPropertyIntention.java new file mode 100644 index 000000000000..375ab4dba165 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/RemoveRedundantClassPropertyIntention.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2012 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 org.jetbrains.plugins.groovy.intentions.style; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.intentions.base.Intention; +import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; + +/** + * @author Max Medvedev + */ +public class RemoveRedundantClassPropertyIntention extends Intention { + @Override + protected void processIntention(@NotNull PsiElement element, Project project, Editor editor) throws IncorrectOperationException { + if (element instanceof GrReferenceExpression) { + ((GrReferenceExpression)element).replaceWithExpression(((GrReferenceExpression)element).getQualifier(), true); + } + } + + @NotNull + @Override + protected PsiElementPredicate getElementPredicate() { + return new PsiElementPredicate() { + @Override + public boolean satisfiedBy(PsiElement element) { + if (element instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)element).getReferenceName())) { + GrExpression qualifier = ((GrReferenceExpression)element).getQualifier(); + if (qualifier instanceof GrReferenceExpression) { + return ((GrReferenceExpression)qualifier).resolve() instanceof PsiClass; + } + } + return false; + } + }; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java index a7326d954b37..850d1033955a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java @@ -23,18 +23,16 @@ import gnu.trove.TIntObjectProcedure; import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrClassInitializer; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ControlFlowBuilderUtil; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction; @@ -55,19 +53,13 @@ public class ReachingDefinitionsCollector { @NotNull public static FragmentVariableInfos obtainVariableFlowInformation(final GrStatement first, final GrStatement last) { - GroovyPsiElement context = PsiTreeUtil.getParentOfType(first, GrMethod.class, GrClosableBlock.class, GroovyFileBase.class, GrClassInitializer.class); - GrControlFlowOwner flowOwner; - if (context instanceof GrMethod) flowOwner = ((GrMethod) context).getBlock(); - else flowOwner = (GrControlFlowOwner) context; + GrControlFlowOwner flowOwner = ControlFlowUtils.findControlFlowOwner(first); assert flowOwner != null; assert PsiTreeUtil.isAncestor(flowOwner, last, true); final Instruction[] flow = flowOwner.getControlFlow(); - final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow); - final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice(); - final DFAEngine engine = new DFAEngine(flow, dfaInstance, lattice); - final DefinitionMap dfaResult = postprocess(engine.performForceDFA(), flow, dfaInstance); + final DefinitionMap dfaResult = inferDfaResult(flow); final LinkedHashSet fragmentInstructions = getFragmentInstructions(first, last, flow); final int[] postorder = ControlFlowBuilderUtil.postorder(flow); @@ -80,7 +72,7 @@ public class ReachingDefinitionsCollector { final PsiManager manager = first.getManager(); for (final Integer ref : fragmentReads) { - ReadWriteVariableInstruction rwInstruction = (ReadWriteVariableInstruction) flow[ref]; + ReadWriteVariableInstruction rwInstruction = (ReadWriteVariableInstruction)flow[ref]; String name = rwInstruction.getVariableName(); final int[] defs = dfaResult.getDefinitions(ref); if (!allDefsInFragment(defs, fragmentInstructions)) { @@ -89,22 +81,22 @@ public class ReachingDefinitionsCollector { } for (final Integer ref : reachableFromFragmentReads) { - ReadWriteVariableInstruction rwInstruction = (ReadWriteVariableInstruction) flow[ref]; - String name = rwInstruction.getVariableName(); - final int[] defs = dfaResult.getDefinitions(ref); - if (anyDefInFragment(defs, fragmentInstructions)) { - for (int def : defs) { - if (fragmentInstructions.contains(def)) { - PsiType outputType = getType(flow[def].getElement()); - addVariable(name, omap, manager, outputType); - } - } - - if (!allProperDefsInFragment(defs, ref, fragmentInstructions, postorder)) { - PsiType inputType = getType(rwInstruction.getElement()); - addVariable(name, imap, manager, inputType); + ReadWriteVariableInstruction rwInstruction = (ReadWriteVariableInstruction)flow[ref]; + String name = rwInstruction.getVariableName(); + final int[] defs = dfaResult.getDefinitions(ref); + if (anyDefInFragment(defs, fragmentInstructions)) { + for (int def : defs) { + if (fragmentInstructions.contains(def)) { + PsiType outputType = getType(flow[def].getElement()); + addVariable(name, omap, manager, outputType); } } + + if (!allProperDefsInFragment(defs, ref, fragmentInstructions, postorder)) { + PsiType inputType = getType(rwInstruction.getElement()); + addVariable(name, imap, manager, inputType); + } + } } addClosureUsages(imap, omap, first, last, flowOwner); @@ -123,14 +115,29 @@ public class ReachingDefinitionsCollector { }; } - private static void addClosureUsages(final Map imap, final Map omap, final GrStatement first, final GrStatement last, GrControlFlowOwner flowOwner) { + private static DefinitionMap inferDfaResult(Instruction[] flow) { + final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow); + final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice(); + final DFAEngine engine = new DFAEngine(flow, dfaInstance, lattice); + return postprocess(engine.performForceDFA(), flow, dfaInstance); + } + + private static void addClosureUsages(final Map imap, + final Map omap, + final GrStatement first, + final GrStatement last, + GrControlFlowOwner flowOwner) { flowOwner.accept(new GroovyRecursiveElementVisitor() { public void visitClosure(GrClosableBlock closure) { addUsagesInClosure(imap, omap, closure, first, last); super.visitClosure(closure); } - private void addUsagesInClosure(final Map imap, final Map omap, final GrClosableBlock closure, final GrStatement first, final GrStatement last) { + private void addUsagesInClosure(final Map imap, + final Map omap, + final GrClosableBlock closure, + final GrStatement first, + final GrStatement last) { closure.accept(new GroovyRecursiveElementVisitor() { public void visitReferenceExpression(GrReferenceExpression refExpr) { if (refExpr.isQualified()) { @@ -140,7 +147,7 @@ public class ReachingDefinitionsCollector { if (!(resolved instanceof GrVariable)) { return; } - GrVariable variable = (GrVariable) resolved; + GrVariable variable = (GrVariable)resolved; if (PsiTreeUtil.isAncestor(closure, variable, true)) { return; } @@ -169,7 +176,7 @@ public class ReachingDefinitionsCollector { } private static void addVariable(String name, Map map, PsiManager manager, PsiType type) { - VariableInfoImpl info = (VariableInfoImpl) map.get(name); + VariableInfoImpl info = (VariableInfoImpl)map.get(name); if (info == null) { info = new VariableInfoImpl(name, manager); map.put(name, info); @@ -181,7 +188,7 @@ public class ReachingDefinitionsCollector { final LinkedHashSet result = new LinkedHashSet(); for (final Integer i : instructions) { final Instruction instruction = flow[i]; - if (instruction instanceof ReadWriteVariableInstruction && !((ReadWriteVariableInstruction) instruction).isWrite()) { + if (isReadInsn(instruction)) { result.add(i); } } @@ -215,21 +222,27 @@ public class ReachingDefinitionsCollector { @Nullable private static PsiType getType(PsiElement element) { - if (element instanceof GrVariable) return ((GrVariable) element).getTypeGroovy(); - else if (element instanceof GrReferenceExpression) return ((GrReferenceExpression) element).getType(); + if (element instanceof GrVariable) { + return ((GrVariable)element).getTypeGroovy(); + } + else if (element instanceof GrReferenceExpression) return ((GrReferenceExpression)element).getType(); return null; } private static VariableInfo[] filterNonlocals(Map infos, GrStatement place) { List result = new ArrayList(); - for (Iterator iterator = infos.values().iterator(); iterator.hasNext();) { + for (Iterator iterator = infos.values().iterator(); iterator.hasNext(); ) { VariableInfo info = iterator.next(); String name = info.getName(); GroovyPsiElement property = ResolveUtil.resolveProperty(place, name); - if (property instanceof GrVariable) iterator.remove(); + if (property instanceof GrVariable) { + iterator.remove(); + } else if (property instanceof GrReferenceExpression) { GrMember member = PsiTreeUtil.getParentOfType(property, GrMember.class); - if (member == null) continue; + if (member == null) { + continue; + } else if (!member.hasModifierProperty(PsiModifier.STATIC)) { if (member.getContainingClass() instanceof GroovyScriptClass) { //binding variable @@ -277,20 +290,20 @@ public class ReachingDefinitionsCollector { return true; } - private static LinkedHashSet getReachable(final LinkedHashSet fragmentInsns, final Instruction[] flow, DefinitionMap dfaResult, final int[] postorder) { + private static LinkedHashSet getReachable(final LinkedHashSet fragmentInsns, + final Instruction[] flow, + final DefinitionMap dfaResult, + final int[] postorder) { final LinkedHashSet result = new LinkedHashSet(); - for (Instruction insn : flow) { - if (insn instanceof ReadWriteVariableInstruction && - !((ReadWriteVariableInstruction) insn).isWrite()) { + for (final Instruction insn : flow) { + if (isReadInsn(insn)) { final int ref = insn.num(); - for (int def : dfaResult.getDefinitions(ref)) { - if (fragmentInsns.contains(def)) { - if (!fragmentInsns.contains(ref) || postorder[ref] < postorder[def]) { - result.add(ref); - break; - } + for (final int def : dfaResult.getDefinitions(ref)) { + if (fragmentInsns.contains(def) && + (!fragmentInsns.contains(ref) || postorder[ref] < postorder[def] && checkPathIsOutsideOfFragment(def, ref, flow, fragmentInsns))) { + result.add(ref); + break; } - } } } @@ -298,6 +311,60 @@ public class ReachingDefinitionsCollector { return result; } + private static boolean checkPathIsOutsideOfFragment(int def, int ref, Instruction[] flow, LinkedHashSet fragmentInsns) { + Boolean path = findPath(flow[def], ref, fragmentInsns, false, new HashMap()); + assert path != null : "def=" + def + ", ref=" + ref; + return path.booleanValue(); + } + + /** + * return true if path is outside of fragment, null if there is no pathand false if path is inside fragment + */ + @Nullable + private static Boolean findPath(Instruction cur, + int destination, + LinkedHashSet fragmentInsns, + boolean wasOutside, + HashMap visited) { + wasOutside = wasOutside || !fragmentInsns.contains(cur.num()); + visited.put(cur, null); + Iterable instructions = cur.allSuccessors(); + + boolean pathExists = false; + for (Instruction i : instructions) { + if (i.num() == destination) return wasOutside; + + Boolean result; + if (visited.containsKey(i)) { + result = visited.get(i); + } + else { + result = findPath(i, destination, fragmentInsns, wasOutside, visited); + visited.put(i, result); + } + if (result != null) { + if (result.booleanValue()) { + visited.put(cur, true); + return true; + } + pathExists = true; + } + } + if (pathExists) { + visited.put(cur, false); + return false; + } + else { + visited.put(cur, null); + return null; + } + } + + + private static boolean isReadInsn(Instruction insn) { + return insn instanceof ReadWriteVariableInstruction && !((ReadWriteVariableInstruction)insn).isWrite(); + } + @SuppressWarnings({"UnusedDeclaration"}) private static String dumpDfaResult(ArrayList> dfaResult, ReachingDefinitionsDfaInstance dfa) { final StringBuffer buffer = new StringBuffer(); @@ -343,18 +410,21 @@ public class ReachingDefinitionsCollector { @Nullable public PsiType getType() { - if (myType instanceof PsiIntersectionType) return ((PsiIntersectionType) myType).getConjuncts()[0]; + if (myType instanceof PsiIntersectionType) return ((PsiIntersectionType)myType).getConjuncts()[0]; return myType; } void addSubtype(PsiType t) { if (t != null) { - if (myType == null) myType = t; + if (myType == null) { + myType = t; + } else { if (!myType.isAssignableFrom(t)) { if (t.isAssignableFrom(myType)) { myType = t; - } else { + } + else { myType = TypesUtil.getLeastUpperBound(myType, t, myManager); } } @@ -365,13 +435,13 @@ public class ReachingDefinitionsCollector { @NotNull private static DefinitionMap postprocess(@NotNull final ArrayList dfaResult, - @NotNull Instruction[] flow, - @NotNull ReachingDefinitionsDfaInstance dfaInstance) { + @NotNull Instruction[] flow, + @NotNull ReachingDefinitionsDfaInstance dfaInstance) { DefinitionMap result = new DefinitionMap(); for (int i = 0; i < flow.length; i++) { Instruction insn = flow[i]; if (insn instanceof ReadWriteVariableInstruction) { - ReadWriteVariableInstruction rwInsn = (ReadWriteVariableInstruction) insn; + ReadWriteVariableInstruction rwInsn = (ReadWriteVariableInstruction)insn; if (!rwInsn.isWrite()) { int idx = dfaInstance.getVarIndex(rwInsn.getVariableName()); result.copyFrom(dfaResult.get(i), idx, i); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/ReachingDefsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/ReachingDefsTest.groovy new file mode 100644 index 000000000000..0bded3f78935 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/ReachingDefsTest.groovy @@ -0,0 +1,81 @@ +package org.jetbrains.plugins.groovy + +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.annotations.NotNull +import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement +import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.FragmentVariableInfos +import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsCollector +import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo +import org.jetbrains.plugins.groovy.util.TestUtils + +/** + * @auther ven + */ +public class ReachingDefsTest extends LightCodeInsightFixtureTestCase { + + String basePath = TestUtils.testDataPath + 'groovy/reachingDefs/' + + public void testAssign() { doTest() } + public void testClosure() { doTest() } + public void testClosure1() { doTest() } + public void testEm1() { doTest() } + public void testEm2() { doTest() } + public void testEm3() { doTest() } + public void testIf1() { doTest() } + public void testInner() { doTest() } + public void testLocal1() { doTest() } + public void testLocal2() { doTest() } + public void testSimpl1() { doTest() } + public void testSimpl2() { doTest() } + public void testSimpl3() { doTest() } + public void testWhile1() { doTest() } + + public void doTest() { + final List data = TestUtils.readInput(testDataPath + getTestName(true) + ".test") + String text = data.get(0) + + myFixture.configureByText(GroovyFileType.GROOVY_FILE_TYPE, text) + + int selStart = myFixture.editor.selectionModel.selectionStart + int selEnd = myFixture.editor.selectionModel.selectionEnd + + final GroovyFile file = (GroovyFile)myFixture.file + final PsiElement start = file.findElementAt(selStart) + final PsiElement end = file.findElementAt(selEnd - 1) + final GrControlFlowOwner owner = PsiTreeUtil.getParentOfType(PsiTreeUtil.findCommonParent(start, end), GrControlFlowOwner, false) + assert owner != null + GrStatement firstStatement = getStatement(start, owner) + GrStatement lastStatement = getStatement(end, owner) + final FragmentVariableInfos fragmentVariableInfos = ReachingDefinitionsCollector.obtainVariableFlowInformation(firstStatement, lastStatement) + assertEquals(data.get(1), dumpInfo(fragmentVariableInfos).trim()) + } + + private static String dumpInfo(FragmentVariableInfos fragmentVariableInfos) { + StringBuilder builder = new StringBuilder() + builder.append("input:\n") + for (VariableInfo info : fragmentVariableInfos.inputVariableNames) { + builder.append(info.name).append("\n") + } + + builder.append("output:\n") + for (VariableInfo info : fragmentVariableInfos.outputVariableNames) { + builder.append(info.name).append("\n") + } + + return builder.toString() + } + + private static GrStatement getStatement(@NotNull PsiElement element, PsiElement context) { + while (element.parent != context) { + element = element.parent + assert element != null + } + + return (GrStatement) element + } + +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/ReachingDefsTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/ReachingDefsTest.java deleted file mode 100644 index 54c298a20188..000000000000 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/ReachingDefsTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.jetbrains.plugins.groovy; - -import com.intellij.psi.PsiElement; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; -import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.FragmentVariableInfos; -import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsCollector; -import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo; -import org.jetbrains.plugins.groovy.util.TestUtils; - -import java.util.List; - -/** - * @auther ven - */ -public class ReachingDefsTest extends LightCodeInsightFixtureTestCase { - - @Override - protected String getBasePath() { - return TestUtils.getTestDataPath() + "groovy/reachingDefs/"; - } - - public void testAssign() throws Throwable { doTest(); } - public void testClosure() throws Throwable { doTest(); } - public void testClosure1() throws Throwable { doTest(); } - public void testEm1() throws Throwable { doTest(); } - public void testEm2() throws Throwable { doTest(); } - public void testEm3() throws Throwable { doTest(); } - public void testIf1() throws Throwable { doTest(); } - public void testInner() throws Throwable { doTest(); } - public void testLocal1() throws Throwable { doTest(); } - public void testLocal2() throws Throwable { doTest(); } - public void testSimpl1() throws Throwable { doTest(); } - public void testSimpl2() throws Throwable { doTest(); } - public void testSimpl3() throws Throwable { doTest(); } - public void testWhile1() throws Throwable { doTest(); } - - public void doTest() throws Exception { - final List data = TestUtils.readInput(getTestDataPath() + getTestName(true) + ".test"); - String text = data.get(0); - - myFixture.configureByText(GroovyFileType.GROOVY_FILE_TYPE, text); - - int selStart = myFixture.getEditor().getSelectionModel().getSelectionStart(); - int selEnd = myFixture.getEditor().getSelectionModel().getSelectionEnd(); - - final GroovyFile file = (GroovyFile) myFixture.getFile(); - final PsiElement start = file.findElementAt(selStart); - final PsiElement end = file.findElementAt(selEnd - 1); - final GrControlFlowOwner owner = PsiTreeUtil.getParentOfType(PsiTreeUtil.findCommonParent(start, end), GrControlFlowOwner.class, false); - assert owner != null; - GrStatement firstStatement = getStatement(start, owner); - GrStatement lastStatement = getStatement(end, owner); - final FragmentVariableInfos fragmentVariableInfos = ReachingDefinitionsCollector.obtainVariableFlowInformation(firstStatement, lastStatement); - assertEquals(data.get(1), dumpInfo(fragmentVariableInfos).trim()); - } - - private static String dumpInfo(FragmentVariableInfos fragmentVariableInfos) { - StringBuilder builder = new StringBuilder(); - builder.append("input:\n"); - for (VariableInfo info : fragmentVariableInfos.getInputVariableNames()) { - builder.append(info.getName()).append("\n"); - } - - builder.append("output:\n"); - for (VariableInfo info : fragmentVariableInfos.getOutputVariableNames()) { - builder.append(info.getName()).append("\n"); - } - - return builder.toString(); - } - - private static GrStatement getStatement(@NotNull PsiElement element, PsiElement context) { - while (element.getParent() != context) { - element = element.getParent(); - assert element != null; - } - - return (GrStatement) element; - } - -} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.groovy index 729e0d436827..f8aad76058cd 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.groovy @@ -28,10 +28,7 @@ import org.jetbrains.plugins.groovy.util.TestUtils * @author ilyas */ public class ExtractMethodTest extends LightGroovyTestCase { - @Override - protected String getBasePath() { - return TestUtils.testDataPath + "groovy/refactoring/extractMethod/"; - } + final String basePath = TestUtils.testDataPath + 'groovy/refactoring/extractMethod/' private void doAntiTest(String errorMessage) { GroovyExtractMethodHandler handler = configureFromText(readInput().get(0)); @@ -94,7 +91,7 @@ public class ExtractMethodTest extends LightGroovyTestCase { public void testVen3() throws Throwable { doTest(); } public void testForIn() throws Throwable { doTest(); } public void testInCatch() {doTest();} - + public void testClosureIt() throws Throwable { doTest(); } public void testImplicitReturn() {doTest();} @@ -109,7 +106,7 @@ public class ExtractMethodTest extends LightGroovyTestCase { public void testLastBlockStatementInterruptsControlFlow() {doTest();} public void testAOOBE() {doTest();} - + public void testWildCardReturnType() {doTest();} public void testParamChangedInsideExtractedMethod() {doTest();} @@ -117,4 +114,6 @@ public class ExtractMethodTest extends LightGroovyTestCase { public void testArgsUsedOnlyInClosure() {doTest()} public void testArgsUsedOnlyInAnonymousClass() {doTest()} + + public void testTwoVars() {doTest()} } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/twoVars.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/twoVars.test new file mode 100644 index 000000000000..8d8c9ac58339 --- /dev/null +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/twoVars.test @@ -0,0 +1,24 @@ +def foo() { + int i = 0 + int j = 1 + while (condition) { + i = i + 1 + j = i + } + return j +} +----- +def foo() { + int j = testMethod() + return j +} + +private int testMethod() { + int i = 0 + int j = 1 + while (condition) { + i = i + 1 + j = i + } + return j +} diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven1.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven1.test index 9b486244e636..fa36c62fcbeb 100644 --- a/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven1.test +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven1.test @@ -1,6 +1,6 @@ protected static def getGeneratedFileNames() { def foo = 0 - while (true) { + while (cond) { println(foo) foo = "" } @@ -10,7 +10,7 @@ protected static def getGeneratedFileNames() { ----- protected static def getGeneratedFileNames() { def foo = 0 - while (true) { + while (cond) { foo = testMethod(foo) } diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven2.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven2.test index 422ed77aa7ec..62e574e82a50 100644 --- a/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven2.test +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven2.test @@ -1,6 +1,6 @@ protected static def getGeneratedFileNames() { foo = 0 - while (true) { + while (cond) { println(foo) foo = "" } @@ -10,7 +10,7 @@ protected static def getGeneratedFileNames() { ----- protected static def getGeneratedFileNames() { foo = 0 - while (true) { + while (cond) { foo = testMethod(foo) } diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven3.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven3.test index 422ed77aa7ec..d369982279ec 100644 --- a/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven3.test +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/ven3.test @@ -1,20 +1,18 @@ protected static def getGeneratedFileNames() { - foo = 0 + def foo = 0 while (true) { println(foo) foo = "" } - int t = foo } ----- protected static def getGeneratedFileNames() { - foo = 0 + def foo = 0 while (true) { foo = testMethod(foo) } - int t = foo } private static String testMethod(Serializable foo) { diff --git a/plugins/junit/src/com/intellij/execution/junit/TestClassFilter.java b/plugins/junit/src/com/intellij/execution/junit/TestClassFilter.java index dc24882b319e..84b5e3b91976 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestClassFilter.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestClassFilter.java @@ -20,12 +20,15 @@ import com.intellij.compiler.CompilerConfiguration; import com.intellij.execution.configurations.ConfigurationUtil; import com.intellij.execution.testframework.SourceScope; import com.intellij.ide.util.ClassFilter; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiUtilBase; +import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -49,10 +52,14 @@ public class TestClassFilter implements ClassFilter.ClassFilterWithScope { public Project getProject() { return myProject; } public boolean isAccepted(final PsiClass aClass) { - return ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(aClass) && - (aClass.isInheritor(myBase, true) || JUnitUtil.isTestClass(aClass)) - && !CompilerConfiguration.getInstance(getProject()).isExcludedFromCompilation(PsiUtilBase.getVirtualFile(aClass)) - ; + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + return ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(aClass) && + (aClass.isInheritor(myBase, true) || JUnitUtil.isTestClass(aClass)) + && !CompilerConfiguration.getInstance(getProject()).isExcludedFromCompilation(PsiUtilCore.getVirtualFile(aClass)); + } + }); } public TestClassFilter intersectionWith(final GlobalSearchScope scope) { @@ -78,9 +85,14 @@ public class TestClassFilter implements ClassFilter.ClassFilterWithScope { } return new TestClassFilter(testCase, sourceScope.getGlobalSearchScope()){ @Override - public boolean isAccepted(PsiClass aClass) { + public boolean isAccepted(final PsiClass aClass) { if (super.isAccepted(aClass)) { - final String qualifiedName = aClass.getQualifiedName(); + final String qualifiedName = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + return aClass.getQualifiedName(); + } + }); for (Pattern compilePattern : compilePatterns) { if (compilePattern.matcher(qualifiedName).matches()) { return true; diff --git a/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index 989b0b38c818..5e3e3ae101c1 100644 --- a/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -146,6 +146,7 @@ http https impl inbox +incrementer indextype indices infile diff --git a/plugins/testng/src/com/theoryinpractice/testng/model/TestClassFilter.java b/plugins/testng/src/com/theoryinpractice/testng/model/TestClassFilter.java index 981db9167a7d..2d99e6901f42 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/model/TestClassFilter.java +++ b/plugins/testng/src/com/theoryinpractice/testng/model/TestClassFilter.java @@ -18,7 +18,9 @@ package com.theoryinpractice.testng.model; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.execution.configurations.ConfigurationUtil; import com.intellij.ide.util.ClassFilter; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; import com.intellij.psi.search.GlobalSearchScope; @@ -60,35 +62,40 @@ public class TestClassFilter implements ClassFilter.ClassFilterWithScope return new TestClassFilter(this.scope.intersectWith(scope), project, includeConfig, checkClassCanBeInstantiated); } - public boolean isAccepted(PsiClass psiClass) { - if(!ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(psiClass)) return false; - //PsiManager manager = PsiManager.getInstance(project); - //if(manager.getEffectiveLanguageLevel().compareTo(LanguageLevel.JDK_1_5) < 0) return true; - boolean hasTest = TestNGUtil.hasTest(psiClass); - if (hasTest) { - if (checkClassCanBeInstantiated) { - final PsiMethod[] constructors = psiClass.getConstructors(); - if (constructors.length > 0) { - boolean canBeInstantiated = false; - for (PsiMethod constructor : constructors) { - if (constructor.getParameterList().getParametersCount() == 0) { - canBeInstantiated = true; - break; - } - if (AnnotationUtil.isAnnotated(constructor, Arrays.asList(GUICE_INJECTION, FACTORY_INJECTION), true)) { - canBeInstantiated = true; - break; + public boolean isAccepted(final PsiClass psiClass) { + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + if(!ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(psiClass)) return false; + //PsiManager manager = PsiManager.getInstance(project); + //if(manager.getEffectiveLanguageLevel().compareTo(LanguageLevel.JDK_1_5) < 0) return true; + boolean hasTest = TestNGUtil.hasTest(psiClass); + if (hasTest) { + if (checkClassCanBeInstantiated) { + final PsiMethod[] constructors = psiClass.getConstructors(); + if (constructors.length > 0) { + boolean canBeInstantiated = false; + for (PsiMethod constructor : constructors) { + if (constructor.getParameterList().getParametersCount() == 0) { + canBeInstantiated = true; + break; + } + if (AnnotationUtil.isAnnotated(constructor, Arrays.asList(GUICE_INJECTION, FACTORY_INJECTION), true)) { + canBeInstantiated = true; + break; + } + } + if (!canBeInstantiated){ + return false; + } } } - if (!canBeInstantiated){ - return false; - } + return true; } - } - return true; - } - return includeConfig && TestNGUtil.hasConfig(psiClass); + return includeConfig && TestNGUtil.hasConfig(psiClass); + } + }); } public Project getProject() { diff --git a/plugins/testng/src/com/theoryinpractice/testng/model/TestListenerFilter.java b/plugins/testng/src/com/theoryinpractice/testng/model/TestListenerFilter.java index 278f1eec17d1..5507f2db7051 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/model/TestListenerFilter.java +++ b/plugins/testng/src/com/theoryinpractice/testng/model/TestListenerFilter.java @@ -17,7 +17,9 @@ package com.theoryinpractice.testng.model; import com.intellij.execution.configurations.ConfigurationUtil; import com.intellij.ide.util.ClassFilter; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiClass; import com.intellij.psi.search.GlobalSearchScope; import com.theoryinpractice.testng.util.TestNGUtil; @@ -35,10 +37,15 @@ public class TestListenerFilter implements ClassFilter.ClassFilterWithScope this.project = project; } - public boolean isAccepted(PsiClass psiClass) { - if (!ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(psiClass)) return false; + public boolean isAccepted(final PsiClass psiClass) { + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + if (!ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(psiClass)) return false; - return TestNGUtil.inheritsITestListener(psiClass); + return TestNGUtil.inheritsITestListener(psiClass); + } + }); } public Project getProject() { diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java index b103b3e144ec..d3cd58be7562 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java +++ b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java @@ -19,7 +19,7 @@ import com.intellij.icons.AllIcons; import com.intellij.ide.BrowserUtil; import com.intellij.ide.browsers.chrome.ChromeSettings; import com.intellij.ide.browsers.firefox.FirefoxSettings; -import com.intellij.ide.browsers.impl.UrlOpenerImpl; +import com.intellij.ide.browsers.impl.DefaultUrlOpener; import com.intellij.openapi.components.*; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; @@ -217,7 +217,7 @@ public class BrowsersConfiguration implements PersistentStateComponent @Nullable final String url, final boolean forceOpenNewInstanceOnMac, String... parameters) { - UrlOpenerImpl.doLaunchBrowser(family, url, parameters, Conditions.alwaysTrue(), forceOpenNewInstanceOnMac); + DefaultUrlOpener.doLaunchBrowser(family, url, parameters, Conditions.alwaysTrue(), forceOpenNewInstanceOnMac); } public static void launchBrowser(final @NotNull BrowserFamily family, @@ -225,7 +225,7 @@ public class BrowsersConfiguration implements PersistentStateComponent final boolean forceOpenNewInstanceOnMac, final Condition browserSpecificParametersFilter, String... parameters) { - UrlOpenerImpl.doLaunchBrowser(family, url, parameters, browserSpecificParametersFilter, forceOpenNewInstanceOnMac); + DefaultUrlOpener.doLaunchBrowser(family, url, parameters, browserSpecificParametersFilter, forceOpenNewInstanceOnMac); } @Nullable diff --git a/xml/impl/src/com/intellij/ide/browsers/impl/UrlOpenerImpl.java b/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java similarity index 97% rename from xml/impl/src/com/intellij/ide/browsers/impl/UrlOpenerImpl.java rename to xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java index ad9b1b60c6df..260c9cc6f009 100644 --- a/xml/impl/src/com/intellij/ide/browsers/impl/UrlOpenerImpl.java +++ b/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java @@ -38,8 +38,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class UrlOpenerImpl extends UrlOpener { - private static final Logger LOG = Logger.getInstance(UrlOpenerImpl.class); +public class DefaultUrlOpener extends UrlOpener { + private static final Logger LOG = Logger.getInstance(DefaultUrlOpener.class); @Override public boolean openUrl(BrowsersConfiguration.BrowserFamily family, String url) {