diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy index 686fc6bfc5ac..b462263eeba3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -19,6 +19,7 @@ package com.intellij.codeInsight.folding; import com.intellij.codeInsight.folding.impl.CodeFoldingManagerImpl import com.intellij.codeInsight.folding.impl.JavaCodeFoldingSettingsImpl import com.intellij.find.FindManager +import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.application.ex.PathManagerEx import com.intellij.openapi.editor.FoldRegion import com.intellij.openapi.editor.ex.FoldingModelEx @@ -35,10 +36,10 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase * @since 1/17/11 1:00 PM */ public class JavaFoldingTest extends LightCodeInsightFixtureTestCase { - + def JavaCodeFoldingSettingsImpl myFoldingSettings def JavaCodeFoldingSettingsImpl myFoldingStateToRestore - + @Override public void setUp() { super.setUp() @@ -65,7 +66,7 @@ import java.util.Map; class Foo { List a; Map b; } """ - + assert myFixture.editor.foldingModel.getCollapsedRegionAtOffset(10) myFixture.type 'import ' @@ -118,25 +119,25 @@ class Test { } } """ - + configure text def foldingModel = myFixture.editor.foldingModel as FoldingModelImpl def closureStartFold = foldingModel.getCollapsedRegionAtOffset(text.indexOf("Runnable")) assertNotNull closureStartFold assertFalse closureStartFold.expanded - + assertNotNull closureStartFold.group def closureFolds = foldingModel.getGroupedRegions(closureStartFold.group) assertNotNull closureFolds assertEquals(2, closureFolds.size()) - + def closureEndFold = closureFolds.get(1) assertFalse closureEndFold.expanded - + myFixture.editor.caretModel.moveToOffset(closureEndFold.startOffset + 1) assertTrue closureStartFold.expanded assertTrue closureEndFold.expanded - + changeFoldRegions { closureStartFold.expanded = false } assertTrue closureStartFold.expanded assertTrue closureEndFold.expanded @@ -172,7 +173,7 @@ class Test { assertNotNull closureFolds assertEquals(2, closureFolds.size()) } - + public void "test builder style setter"() { myFoldingSettings.COLLAPSE_ACCESSORS = true def text = """\ @@ -379,22 +380,22 @@ class Test { FindManager.getInstance(project).findNextUsageInEditor(TextEditorProvider.getInstance().getTextEditor(myFixture.editor)) assertEquals('test1', myFixture.editor.selectionModel.selectedText) } - + public void testCustomFolding() { myFixture.testFolding("$PathManagerEx.testDataPath/codeInsight/folding/${getTestName(false)}.java"); } - + public void "test move methods"() { def initialText = '''\ class Test { void test1() { } - + void test2() { } } ''' - + Closure fold = { String methodName -> def text = myFixture.editor.document.text def nameIndex = text.indexOf(methodName) @@ -444,7 +445,7 @@ class Test { assertEquals(2, folds[0].startOffset) assertEquals(6, folds[0].endOffset) } - + private def configure(String text) { myFixture.configureByText("a.java", text) CodeFoldingManagerImpl.getInstance(getProject()).buildInitialFoldings(myFixture.editor); @@ -458,21 +459,21 @@ class Test { int field; int field2; int field3; - + int getField() { return field; } - + void setField(int f) { field = f; } - + void setField2(int f){field2=f;} // normal method folding here // normal method folding here void setField3(int f){ - + field2=f; } @@ -480,10 +481,10 @@ class Test { PsiClass fooClass = JavaPsiFacade.getInstance(project).findClass('Foo', GlobalSearchScope.allScope(project)) def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } assert regions.size() == 6 - + checkAccessorFolding(regions[0], regions[1], fooClass.methods[0]) checkAccessorFolding(regions[2], regions[3], fooClass.methods[1]) - + assert regions[4].placeholderText == '{...}' assert regions[5].placeholderText == '{...}' } @@ -504,7 +505,7 @@ class Test { int someMethod() { return 0; } - + }""" PsiClass fooClass = JavaPsiFacade.getInstance(project).findClass('Foo', GlobalSearchScope.allScope(project)) def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } @@ -516,7 +517,7 @@ class Test { configure """class Foo { int someVeryVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVariable; - // don't create folding that would exceed the right margin + // don't create folding that would exceed the right margin int getSomeVeryVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVariable() { return someVeryVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVariable; } @@ -529,4 +530,18 @@ class Test { private def changeFoldRegions(Closure op) { myFixture.editor.foldingModel.runBatchFoldingOperationDoNotCollapseCaret(op) } + + public void "test unselect word should go inside folding group"() { + configure """class Foo { + int field; + + int getField() { + return field; + } + +}""" + assertSize 2, myFixture.editor.foldingModel.allFoldRegions + myFixture.performEditorAction(IdeActions.ACTION_EDITOR_UNSELECT_WORD_AT_CARET) + assert 'return field;' == myFixture.editor.selectionModel.selectedText + } } diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java index 36aa425366f5..b1f34cc2880d 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java @@ -66,40 +66,43 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx @Override @NotNull public RangeHighlighter addLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { - if (lineNumber >= getDocument().getLineCount() || lineNumber < 0) { + if (isNotValidLine(lineNumber)) { throw new IndexOutOfBoundsException("lineNumber:" + lineNumber + ". Must be in [0, " + (getDocument().getLineCount() - 1) + "]"); } // The rationale why we don't bind to the line start offset here is that following: suppose particular breakpoint is hit // during debugging. We may want to type at the active line indent and highlighted string will be moved one line // down as well then. - int offset = getFirstNonspaceCharOffset(getDocument(), lineNumber); - + int offset = getFirstNonSpaceCharOffset(getDocument(), lineNumber); return addRangeHighlighter(offset, offset, layer, textAttributes, HighlighterTargetArea.LINES_IN_RANGE); } @Override + @Nullable public RangeHighlighter addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { - if (lineNumber >= getDocument().getLineCount() || lineNumber < 0) return null; - - int offset = getFirstNonspaceCharOffset(getDocument(), lineNumber); + if (isNotValidLine(lineNumber)) { + return null; + } + int offset = getFirstNonSpaceCharOffset(getDocument(), lineNumber); return addRangeHighlighterAndChangeAttributes(offset, offset, layer, textAttributes, HighlighterTargetArea.LINES_IN_RANGE, true, null); } - private static int getFirstNonspaceCharOffset(@NotNull Document doc, int lineNumber) { - int lineStart = doc.getLineStartOffset(lineNumber); - int lineEnd = doc.getLineEndOffset(lineNumber); - CharSequence text = doc.getCharsSequence(); - int offset = lineStart; + private boolean isNotValidLine(int lineNumber) { + return lineNumber >= getDocument().getLineCount() || lineNumber < 0; + } + + private static int getFirstNonSpaceCharOffset(@NotNull Document document, int lineNumber) { + int lineStart = document.getLineStartOffset(lineNumber); + int lineEnd = document.getLineEndOffset(lineNumber); + CharSequence text = document.getImmutableCharSequence(); for (int i = lineStart; i < lineEnd; i++) { char c = text.charAt(i); if (c != ' ' && c != '\t') { - offset = i; - break; + return i; } } - return offset; + return lineStart; } // NB: Can return invalid highlighters diff --git a/platform/lang-impl/src/com/intellij/execution/console/ProcessBackedConsoleExecuteActionHandler.java b/platform/lang-impl/src/com/intellij/execution/console/ProcessBackedConsoleExecuteActionHandler.java index cc3a58b872a7..2c957a4ed2da 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/ProcessBackedConsoleExecuteActionHandler.java +++ b/platform/lang-impl/src/com/intellij/execution/console/ProcessBackedConsoleExecuteActionHandler.java @@ -75,6 +75,6 @@ public class ProcessBackedConsoleExecuteActionHandler extends BaseConsoleExecute @Override public boolean value(LanguageConsoleImpl console) { - return isProcessTerminated(); + return !isProcessTerminated(); } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginsTableRenderer.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginsTableRenderer.java index 04daa90f4ea8..174ca5a3f372 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginsTableRenderer.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginsTableRenderer.java @@ -131,7 +131,7 @@ public class PluginsTableRenderer extends DefaultTableCellRenderer { if (!isSelected) { myName.setForeground(JBColor.RED); } - myName.setIcon(AllIcons.Nodes.Pluginobsolete); + myStatus.setIcon(AllIcons.Nodes.Pluginobsolete); } //todo[kb] set proper icon //myStatus.setText("v." + pluginNode.getInstalledVersion() + (hasNewerVersion ? (" -> " + pluginNode.getVersion()) : "")); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java index fbd04aa62711..62c73e2c76de 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java @@ -17,6 +17,7 @@ package com.intellij.openapi.diff.impl; import com.intellij.icons.AllIcons; import com.intellij.ide.actions.EditSourceAction; +import com.intellij.idea.ActionsBundle; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.Application; @@ -126,6 +127,9 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid private AnAction getEditSourceAction() { AnAction editSourceAction = new EditSourceAction(); editSourceAction.getTemplatePresentation().setIcon(AllIcons.Actions.EditSource); + editSourceAction.getTemplatePresentation().setText(ActionsBundle.actionText("EditSource")); + editSourceAction.getTemplatePresentation().setDescription(ActionsBundle.actionText("EditSource")); + editSourceAction.registerCustomShortcutSet(CommonShortcuts.getEditSource(), myPanel, DiffPanelImpl.this); return editSourceAction; } }; @@ -202,9 +206,6 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid } private void registerActions() { - // EditSourceAction is not enabled in modal context, so we need to register it here explicitly - new EditSourceAction().registerCustomShortcutSet(CommonShortcuts.getEditSource(), myPanel, this); - //control+tab switches editors new AnAction(){ @Override diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacMainFrameDecorator.java b/platform/platform-impl/src/com/intellij/ui/mac/MacMainFrameDecorator.java index c563f9bf1a90..1e2cfd4dd9d4 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacMainFrameDecorator.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacMainFrameDecorator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -230,7 +230,8 @@ public class MacMainFrameDecorator extends IdeFrameDecorator implements UISettin @Override public void windowEnteredFullScreen(AppEvent.FullScreenEvent event) { // We can get the notification when the frame has been disposed - if (myFrame == null/*|| ORACLE_BUG_ID_8003173*/) return; + JRootPane rootPane = frame.getRootPane(); + if (rootPane != null) rootPane.putClientProperty(FULL_SCREEN, Boolean.TRUE); enterFullscreen(); myFrame.validate(); } diff --git a/platform/platform-impl/src/com/intellij/ui/messages/SheetMessage.java b/platform/platform-impl/src/com/intellij/ui/messages/SheetMessage.java index 76803e02e1c0..e90078aa7a19 100755 --- a/platform/platform-impl/src/com/intellij/ui/messages/SheetMessage.java +++ b/platform/platform-impl/src/com/intellij/ui/messages/SheetMessage.java @@ -15,8 +15,10 @@ */ package com.intellij.ui.messages; +import com.apple.eawt.FullScreenUtilities; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.ui.JBColor; +import com.intellij.ui.mac.MacMainFrameDecorator; import com.intellij.util.ui.Animator; import com.intellij.util.ui.UIUtil; @@ -37,6 +39,7 @@ public class SheetMessage { private Image staticImage; private int imageHeight; + private boolean restoreFullscreenButton; public SheetMessage(final Window owner, final String title, @@ -68,10 +71,22 @@ public class SheetMessage { startAnimation(true); myWindow.setSize(myController.SHEET_WIDTH, myController.SHEET_HEIGHT); + restoreFullscreenButton = couldBeInFullScreen(); + if (restoreFullscreenButton) { + FullScreenUtilities.setWindowCanFullScreen(myParent, false); + } myWindow.setVisible(true); setPositionRelativeToParent(); } + private boolean couldBeInFullScreen() { + if (myParent instanceof JFrame) { + JRootPane rootPane = ((JFrame)myParent).getRootPane(); + return rootPane.getClientProperty(MacMainFrameDecorator.FULL_SCREEN) == null; + } + return false; + } + public boolean toBeShown() { return !myController.getDoNotAskResult(); } @@ -123,6 +138,9 @@ public class SheetMessage { myWindow.setContentPane(myController.getPanel(myWindow)); myController.requestFocus(); } else { + if (restoreFullscreenButton) { + FullScreenUtilities.setWindowCanFullScreen(myParent, true); + } myWindow.dispose(); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java index 6722c38841be..1b70575fd711 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java @@ -31,7 +31,10 @@ import com.intellij.util.xmlb.XmlSerializer; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.XSourcePosition; -import com.intellij.xdebugger.breakpoints.*; +import com.intellij.xdebugger.breakpoints.SuspendPolicy; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.XBreakpointProperties; +import com.intellij.xdebugger.breakpoints.XBreakpointType; import com.intellij.xdebugger.impl.DebuggerSupport; import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.XDebuggerSupport; @@ -88,10 +91,12 @@ public class XBreakpointBase, P extends XBreakpointP myBreakpointManager.fireBreakpointChanged(this); } + @Override public XSourcePosition getSourcePosition() { return getType().getSourcePosition(this); } + @Override public Navigatable getNavigatable() { XSourcePosition position = getSourcePosition(); if (position == null) { @@ -100,10 +105,12 @@ public class XBreakpointBase, P extends XBreakpointP return position.createNavigatable(getProject()); } + @Override public boolean isEnabled() { return myState.isEnabled(); } + @Override public void setEnabled(final boolean enabled) { if (enabled != isEnabled()) { myState.setEnabled(enabled); @@ -111,11 +118,13 @@ public class XBreakpointBase, P extends XBreakpointP } } + @Override @NotNull public SuspendPolicy getSuspendPolicy() { return myState.getSuspendPolicy(); } + @Override public void setSuspendPolicy(@NotNull SuspendPolicy policy) { if (myState.getSuspendPolicy() != policy) { myState.setSuspendPolicy(policy); @@ -123,10 +132,12 @@ public class XBreakpointBase, P extends XBreakpointP } } + @Override public boolean isLogMessage() { return myState.isLogMessage(); } + @Override public void setLogMessage(final boolean logMessage) { if (logMessage != isLogMessage()) { myState.setLogMessage(logMessage); @@ -134,10 +145,12 @@ public class XBreakpointBase, P extends XBreakpointP } } + @Override public String getLogExpression() { return myState.getLogExpression(); } + @Override public void setLogExpression(@Nullable final String expression) { if (!Comparing.equal(getLogExpression(), expression)) { myState.setLogExpression(expression); @@ -145,10 +158,12 @@ public class XBreakpointBase, P extends XBreakpointP } } + @Override public String getCondition() { return myState.getCondition(); } + @Override public void setCondition(@Nullable final String condition) { if (!Comparing.equal(condition, getCondition())) { myState.setCondition(condition); @@ -165,11 +180,13 @@ public class XBreakpointBase, P extends XBreakpointP return true; } + @Override @Nullable public P getProperties() { return myProperties; } + @Override @NotNull public XBreakpointType getType() { return myType; @@ -350,16 +367,19 @@ public class XBreakpointBase, P extends XBreakpointP } protected class BreakpointGutterIconRenderer extends GutterIconRenderer { + @Override @NotNull public Icon getIcon() { return XBreakpointBase.this.getIcon(); } + @Override @Nullable public AnAction getClickAction() { return new RemoveBreakpointGutterIconAction(XBreakpointBase.this); } + @Override @Nullable public AnAction getMiddleButtonClickAction() { return new ToggleBreakpointGutterIconAction(XBreakpointBase.this); @@ -376,11 +396,13 @@ public class XBreakpointBase, P extends XBreakpointP return Alignment.RIGHT; } + @Override @Nullable public ActionGroup getPopupMenuActions() { return null; } + @Override @Nullable public String getTooltipText() { return getDescription(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java index d945c4209cdf..efeae4e528c9 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java @@ -459,6 +459,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta myBreakpoints = breakpoints; } + @SuppressWarnings("UnusedDeclaration") public void setDefaultBreakpoints(List defaultBreakpoints) { myDefaultBreakpoints = defaultBreakpoints; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java index f478fe4cc453..1b4a15f27961 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java @@ -149,7 +149,7 @@ public class XLineBreakpointImpl

extends XBreak if (mySourcePosition == null) { new ReadAction() { @Override - protected void run(final Result result) { + protected void run(@NotNull Result result) { mySourcePosition = XDebuggerUtil.getInstance().createPosition(getFile(), getLine()); } }.execute(); @@ -201,8 +201,7 @@ public class XLineBreakpointImpl

extends XBreak public void updatePosition() { if (myHighlighter != null && myHighlighter.isValid()) { - Document document = myHighlighter.getDocument(); - setLine(document.getLineNumber(myHighlighter.getStartOffset())); + setLine(myHighlighter.getDocument().getLineNumber(myHighlighter.getStartOffset())); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointManager.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointManager.java index d1bae1470fa5..e689e30f85f6 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointManager.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointManager.java @@ -18,8 +18,6 @@ package com.intellij.xdebugger.impl.breakpoints; import com.intellij.ide.startup.StartupManagerEx; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; @@ -43,6 +41,7 @@ import com.intellij.openapi.vfs.VirtualFileEvent; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.VirtualFileUrlChangeAdapter; import com.intellij.psi.PsiDocumentManager; +import com.intellij.util.SmartList; import com.intellij.util.containers.BidirectionalMap; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; @@ -53,7 +52,6 @@ import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; import java.awt.event.MouseEvent; -import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -101,7 +99,7 @@ public class XLineBreakpointManager { @Override public void fileDeleted(@NotNull VirtualFileEvent event) { - List> toRemove = new ArrayList>(); + List> toRemove = new SmartList>(); for (XLineBreakpointImpl breakpoint : myBreakpoints.keySet()) { if (breakpoint.getFileUrl().equals(event.getFile().getUrl())) { toRemove.add(breakpoint); @@ -164,12 +162,14 @@ public class XLineBreakpointManager { } } - private void updateBreakpoints(final Document document) { + private void updateBreakpoints(@NotNull Document document) { Collection breakpoints = myBreakpoints.getKeysByValue(document); - if (breakpoints == null) return; + if (breakpoints == null) { + return; + } TIntHashSet lines = new TIntHashSet(); - final List> toRemove = new ArrayList>(); + List> toRemove = new SmartList>(); for (XLineBreakpointImpl breakpoint : breakpoints) { breakpoint.updatePosition(); if (!breakpoint.isValid() || !lines.add(breakpoint.getLine())) { @@ -181,20 +181,25 @@ public class XLineBreakpointManager { } private void removeBreakpoints(final List> toRemove) { - new WriteAction() { + if (toRemove.isEmpty()) { + return; + } + + ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override - protected void run(@NotNull final Result result) { + public void run() { for (XBreakpoint breakpoint : toRemove) { XDebuggerManager.getInstance(myProject).getBreakpointManager().removeBreakpoint(breakpoint); } } - }.execute(); + }); } public void breakpointChanged(final XLineBreakpointImpl breakpoint) { if (ApplicationManager.getApplication().isDispatchThread()) { breakpoint.updateUI(); - } else { + } + else { queueBreakpointUpdate(breakpoint); } } @@ -266,7 +271,6 @@ public class XLineBreakpointManager { @Override public void run() { if (!myProject.isDisposed() && myProject.isInitialized() && file.isValid()) { - XDebuggerUtil.getInstance().toggleLineBreakpoint(myProject, file, line, mouseEvent.isAltDown()); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java index 33ad9e2c2ecf..970b39123c7c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java @@ -836,7 +836,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { return LocalQuickFix.EMPTY_ARRAY; } - final List signatures = GrClosureSignatureUtil.generateSimpleSignature(signature); + final List signatures = GrClosureSignatureUtil.generateSimpleSignatures(signature); List> allErrors = new ArrayList>(); for (GrClosureSignature closureSignature : signatures) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/signatures/GrMultiSignature.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/signatures/GrMultiSignature.java index 8d59457ea7ed..5bcf8b3f5afa 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/signatures/GrMultiSignature.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/signatures/GrMultiSignature.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * 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. @@ -15,9 +15,9 @@ */ package org.jetbrains.plugins.groovy.lang.psi.api.signatures; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; /** * @author Max Medvedev @@ -37,7 +37,7 @@ public interface GrMultiSignature extends GrSignature { } @Override - public GrSignature curry(@NotNull PsiType[] args, int position, @NotNull GroovyPsiElement context) { + public GrSignature curry(@NotNull PsiType[] args, int position, @NotNull PsiElement context) { return this; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/signatures/GrSignature.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/signatures/GrSignature.java index d168f7d8a4de..92d21404c194 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/signatures/GrSignature.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/signatures/GrSignature.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * 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. @@ -15,10 +15,10 @@ */ package org.jetbrains.plugins.groovy.lang.psi.api.signatures; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; /** * @author Max Medvedev @@ -27,7 +27,7 @@ public interface GrSignature { boolean isValid(); @Nullable - GrSignature curry(@NotNull PsiType[] args, int position, @NotNull GroovyPsiElement context); + GrSignature curry(@NotNull PsiType[] args, int position, @NotNull PsiElement context); void accept(GrSignatureVisitor visitor); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClassReferenceType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClassReferenceType.java index aa74648937e4..67be74d92a9b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClassReferenceType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClassReferenceType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -43,18 +43,7 @@ public class GrClassReferenceType extends PsiClassType { @Override @Nullable public PsiClass resolve() { - ResolveResult[] results = multiResolve(); - if (results.length == 1) { - PsiElement only = results[0].getElement(); - return only instanceof PsiClass ? (PsiClass) only : null; - } - - return null; - } - - //reference resolve is cached - private GroovyResolveResult[] multiResolve() { - return myReferenceElement.multiResolve(false); + return resolveGenerics().getElement(); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java index 7689a6ce28bc..e2efdadc0445 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java @@ -42,7 +42,7 @@ public class GrClosureType extends GrLiteralClassType { private final GrSignature mySignature; private volatile PsiType[] myTypeArgs = null; - private GrClosureType(@NotNull LanguageLevel languageLevel, + private GrClosureType(LanguageLevel languageLevel, @NotNull GlobalSearchScope scope, @NotNull JavaPsiFacade facade, @NotNull GrSignature closureSignature, @@ -52,7 +52,7 @@ public class GrClosureType extends GrLiteralClassType { if (!shouldInferTypeParameters) myTypeArgs = PsiType.EMPTY_ARRAY; } - private GrClosureType(@NotNull LanguageLevel level, + private GrClosureType(LanguageLevel level, @NotNull GlobalSearchScope scope, @NotNull JavaPsiFacade facade, @NotNull GrSignature signature, diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java index 738ac06fa1cb..8559f53e9f7e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -33,7 +33,7 @@ public abstract class GrLiteralClassType extends PsiClassType { protected final JavaPsiFacade myFacade; private final GroovyPsiManager myGroovyPsiManager; - public GrLiteralClassType(@NotNull LanguageLevel languageLevel, @NotNull GlobalSearchScope scope, @NotNull JavaPsiFacade facade) { + public GrLiteralClassType(LanguageLevel languageLevel, @NotNull GlobalSearchScope scope, @NotNull JavaPsiFacade facade) { super(languageLevel); myScope = scope; myFacade = facade; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosableSignatureImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosableSignatureImpl.java new file mode 100644 index 000000000000..3d1357d3a82e --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosableSignatureImpl.java @@ -0,0 +1,137 @@ +/* + * 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 org.jetbrains.plugins.groovy.lang.psi.impl.signatures; + +import com.intellij.psi.PsiArrayType; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.PsiType; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature; +import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature; +import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignatureVisitor; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter; + +/** +* Created by Max Medvedev on 26/02/14 +*/ +class GrClosableSignatureImpl implements GrClosureSignature { + private final GrClosableBlock myBlock; + + public GrClosableSignatureImpl(GrClosableBlock block) { + myBlock = block; + } + + @NotNull + @Override + public PsiSubstitutor getSubstitutor() { + return PsiSubstitutor.EMPTY; + } + + @NotNull + @Override + public GrClosureParameter[] getParameters() { + GrParameter[] parameters = myBlock.getAllParameters(); + + return ContainerUtil.map(parameters, new Function() { + @Override + public GrClosureParameter fun(final GrParameter parameter) { + return new GrClosureParameterImpl(parameter); + } + }, new GrClosureParameter[parameters.length]); + } + + @Override + public int getParameterCount() { + return myBlock.getAllParameters().length; + } + + @Override + public boolean isVarargs() { + GrParameter last = ArrayUtil.getLastElement(myBlock.getAllParameters()); + return last != null && last.getType() instanceof PsiArrayType; + } + + @Nullable + @Override + public PsiType getReturnType() { + return myBlock.getReturnType(); + } + + @Override + public boolean isCurried() { + return false; + } + + @Override + public boolean isValid() { + return myBlock.isValid(); + } + + @Nullable + @Override + public GrSignature curry(@NotNull PsiType[] args, int position, @NotNull PsiElement context) { + return GrClosureSignatureUtil.curryImpl(this, args, position, context); + } + + @Override + public void accept(GrSignatureVisitor visitor) { + visitor.visitClosureSignature(this); + } + + private static class GrClosureParameterImpl implements GrClosureParameter { + private final GrParameter myParameter; + + public GrClosureParameterImpl(GrParameter parameter) { + myParameter = parameter; + } + + @Nullable + @Override + public PsiType getType() { + return myParameter.getType(); + } + + @Override + public boolean isOptional() { + return myParameter.isOptional(); + } + + @Nullable + @Override + public GrExpression getDefaultInitializer() { + return myParameter.getInitializerGroovy(); + } + + @Override + public boolean isValid() { + return myParameter.isValid(); + } + + @Nullable + @Override + public String getName() { + return myParameter.getName(); + } + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java index 8806fa09cf45..8f47ea01e728 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java @@ -50,7 +50,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; -import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureParameterImpl; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import java.util.*; @@ -98,30 +97,20 @@ public class GrClosureSignatureUtil { ContainerUtil.map(types, new Function() { @Override public GrClosureParameter fun(PsiType type) { - return new GrClosureParameterImpl(type, null, false, null); + return new GrImmediateClosureParameterImpl(type, null, false, null); } }, parameters); - return new GrClosureSignatureImpl(parameters, null, false, false); + return new GrImmediateClosureSignatureImpl(parameters, null, false, false); } @NotNull public static GrClosureSignature createSignature(final GrClosableBlock block) { - return new GrClosureSignatureImpl(block.getAllParameters(), null) { - @Override - public PsiType getReturnType() { - return block.getReturnType(); - } - - @Override - public boolean isValid() { - return block.isValid(); - } - }; + return new GrClosableSignatureImpl(block); } public static GrClosureSignature createSignature(final PsiMethod method, PsiSubstitutor substitutor) { - return new GrClosureSignatureImpl(method.getParameterList().getParameters(), null, substitutor) { + return new GrImmediateClosureSignatureImpl(method.getParameterList().getParameters(), null, substitutor) { @Override public PsiType getReturnType() { return getSubstitutor().substitute(PsiUtil.getSmartReturnType(method)); @@ -136,7 +125,7 @@ public class GrClosureSignatureUtil { public static GrClosureSignature removeParam(final GrClosureSignature signature, int i) { final GrClosureParameter[] newParams = ArrayUtil.remove(signature.getParameters(), i); - return new GrClosureSignatureImpl(newParams, null, newParams.length > 0 && signature.isVarargs(), false) { + return new GrImmediateClosureSignatureImpl(newParams, null, newParams.length > 0 && signature.isVarargs(), false) { @Override public PsiType getReturnType() { return signature.getReturnType(); @@ -151,15 +140,14 @@ public class GrClosureSignatureUtil { public static GrClosureSignature createSignatureWithErasedParameterTypes(final PsiMethod method) { final PsiParameter[] params = method.getParameterList().getParameters(); - final GrClosureParameter[] closureParams = new GrClosureParameter[params.length]; - for (int i = 0; i < params.length; i++) { - PsiParameter param = params[i]; - PsiType type = TypeConversionUtil.erasure(param.getType()); - closureParams[i] = - new GrClosureParameterImpl(type, GrClosureParameterImpl.getParameterName(param), GrClosureParameterImpl.isParameterOptional(param), - GrClosureParameterImpl.getDefaultInitializer(param)); - } - return new GrClosureSignatureImpl(closureParams, null, GrClosureParameterImpl.isVararg(closureParams), false) { + final GrClosureParameter[] closureParams = ContainerUtil.map(params, new Function() { + @Override + public GrClosureParameter fun(PsiParameter parameter) { + return GrImmediateClosureParameterImpl.createErasedParameter(parameter); + } + }, new GrClosureParameter[params.length]); + + return new GrImmediateClosureSignatureImpl(closureParams, null, GrImmediateClosureParameterImpl.isVararg(closureParams), false) { @Override public PsiType getReturnType() { return PsiUtil.getSmartReturnType(method); @@ -181,13 +169,16 @@ public class GrClosureSignatureUtil { @NotNull public static GrClosureSignature rawSignature(@NotNull final GrClosureSignature signature) { final GrClosureParameter[] params = signature.getParameters(); - final GrClosureParameter[] closureParams = new GrClosureParameter[params.length]; - for (int i = 0; i < params.length; i++) { - GrClosureParameter param = params[i]; - PsiType type = TypeConversionUtil.erasure(param.getType()); - closureParams[i] = new GrClosureParameterImpl(type, param.getName(), param.isOptional(), param.getDefaultInitializer()); - } - return new GrClosureSignatureImpl(closureParams, null, GrClosureParameterImpl.isVararg(closureParams), false) { + + final GrClosureParameter[] closureParams = ContainerUtil.map(params, new Function() { + @Override + public GrClosureParameter fun(GrClosureParameter parameter) { + PsiType type = TypeConversionUtil.erasure(parameter.getType()); + return new GrImmediateClosureParameterImpl(type, parameter.getName(), parameter.isOptional(), parameter.getDefaultInitializer()); + } + }, new GrClosureParameter[params.length]); + + return new GrImmediateClosureSignatureImpl(closureParams, null, GrImmediateClosureParameterImpl.isVararg(closureParams), false) { @Override public PsiType getReturnType() { return signature.getReturnType(); @@ -202,7 +193,7 @@ public class GrClosureSignatureUtil { public static GrClosureSignature createSignature(PsiParameter[] parameters, @Nullable PsiType returnType) { - return new GrClosureSignatureImpl(parameters, returnType); + return new GrImmediateClosureSignatureImpl(parameters, returnType); } @@ -349,6 +340,46 @@ public class GrClosureSignatureUtil { return ApplicabilityResult.applicable; } + static GrSignature curryImpl(GrClosureSignature original, PsiType[] args, int position, PsiElement context) { + GrClosureParameter[] params = original.getParameters(); + + List newParams = new ArrayList(params.length); + List opts = new ArrayList(params.length); + List optInds = new ArrayList(params.length); + + if (position == -1) { + position = params.length - args.length; + } + + if (position < 0 || position >= params.length) return GrMultiSignature.EMPTY_SIGNATURE; + + for (int i = 0; i < params.length; i++) { + if (params[i].isOptional()) { + opts.add(params[i]); + optInds.add(i); + } + else { + newParams.add(params[i]); + } + } + + final PsiType rtype = original.getReturnType(); + final ArrayList result = new ArrayList(); + checkAndAddSignature(result, args, position, newParams, rtype, context); + + for (int i = 0; i < opts.size(); i++) { + newParams.add(optInds.get(i), opts.get(i)); + checkAndAddSignature(result, args, position, newParams, rtype, context); + } + + if (result.size() == 1) { + return result.get(0); + } + else { + return new GrMultiSignatureImpl(result.toArray(new GrClosureSignature[result.size()])); + } + } + public enum ApplicabilityResult { applicable, inapplicable, canBeApplicable, ambiguous; @@ -470,7 +501,7 @@ public class GrClosureSignatureUtil { int position, List params, PsiType returnType, - @NotNull GroovyPsiElement context) { + @NotNull PsiElement context) { final int last = position + args.length; if (last > params.size()) return; @@ -488,7 +519,7 @@ public class GrClosureSignatureUtil { _p[j++] = params.get(i); } - list.add(new GrClosureSignatureImpl(_p, returnType, _p.length > 0 && _p[_p.length - 1].getType() instanceof PsiArrayType, true)); + list.add(new GrImmediateClosureSignatureImpl(_p, returnType, _p.length > 0 && _p[_p.length - 1].getType() instanceof PsiArrayType, true)); } @@ -999,7 +1030,7 @@ public class GrClosureSignatureUtil { return new MapResultWithError(map, errors); } - public static List generateSimpleSignature(@NotNull GrSignature signature) { + public static List generateSimpleSignatures(@NotNull GrSignature signature) { final List result = new ArrayList(); signature.accept(new GrRecursiveSignatureVisitor() { @Override @@ -1008,17 +1039,17 @@ public class GrClosureSignatureUtil { final ArrayList parameters = new ArrayList(original.length); for (GrClosureParameter parameter : original) { - parameters.add(new GrClosureParameterImpl(parameter.getType(), parameter.getName(), false, null)); + parameters.add(new GrImmediateClosureParameterImpl(parameter.getType(), parameter.getName(), false, null)); } final int pcount = signature.isVarargs() ? signature.getParameterCount() - 2 : signature.getParameterCount() - 1; for (int i = pcount; i >= 0; i--) { if (original[i].isOptional()) { - result.add(new GrClosureSignatureImpl(parameters.toArray(new GrClosureParameter[parameters.size()]), signature.getReturnType(), signature.isVarargs(), false)); + result.add(new GrImmediateClosureSignatureImpl(parameters.toArray(new GrClosureParameter[parameters.size()]), signature.getReturnType(), signature.isVarargs(), false)); parameters.remove(i); } } - result.add(new GrClosureSignatureImpl(parameters.toArray(new GrClosureParameter[parameters.size()]), signature.getReturnType(), signature.isVarargs(), false)); + result.add(new GrImmediateClosureSignatureImpl(parameters.toArray(new GrClosureParameter[parameters.size()]), signature.getReturnType(), signature.isVarargs(), false)); } }); return result; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureParameterImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrImmediateClosureParameterImpl.java similarity index 80% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureParameterImpl.java rename to plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrImmediateClosureParameterImpl.java index e5401b6a4ac4..ef047f557d6d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureParameterImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrImmediateClosureParameterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.plugins.groovy.lang.psi.impl.types; +package org.jetbrains.plugins.groovy.lang.psi.impl.signatures; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; +import com.intellij.psi.util.TypeConversionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -26,23 +27,30 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter; /** * @author Maxim.Medvedev */ -public class GrClosureParameterImpl implements GrClosureParameter { +public class GrImmediateClosureParameterImpl implements GrClosureParameter { @Nullable final PsiType myType; @Nullable private final String myName; final boolean myOptional; @Nullable final GrExpression myDefaultInitializer; - public GrClosureParameterImpl(@Nullable PsiType type, @Nullable String name, boolean optional, GrExpression defaultInitializer) { + public GrImmediateClosureParameterImpl(@Nullable PsiType type, @Nullable String name, boolean optional, GrExpression defaultInitializer) { myType = type; myName = name; myOptional = optional; myDefaultInitializer = optional ? defaultInitializer : null; } - public GrClosureParameterImpl(@NotNull PsiParameter parameter, @NotNull PsiSubstitutor substitutor) { + public GrImmediateClosureParameterImpl(@NotNull PsiParameter parameter, @NotNull PsiSubstitutor substitutor) { this(substitutor.substitute(getParameterType(parameter)), getParameterName(parameter), isParameterOptional(parameter), getDefaultInitializer(parameter)); } + @NotNull + public static GrImmediateClosureParameterImpl createErasedParameter(@NotNull PsiParameter param) { + PsiType type = TypeConversionUtil.erasure(param.getType()); + return new GrImmediateClosureParameterImpl(type, getParameterName(param), isParameterOptional(param), getDefaultInitializer(param)); + } + + @Nullable private static PsiType getParameterType(@NotNull PsiParameter parameter) { return parameter instanceof GrParameter ? ((GrParameter)parameter).getDeclaredType() : parameter.getType(); @@ -71,7 +79,6 @@ public class GrClosureParameterImpl implements GrClosureParameter { } } - @Nullable public PsiType getType() { return myType; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrImmediateClosureSignatureImpl.java similarity index 67% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureImpl.java rename to plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrImmediateClosureSignatureImpl.java index ddf887dc5e3c..a09b2f7d318a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrImmediateClosureSignatureImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -20,34 +20,30 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature; -import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrMultiSignature; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignatureVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; -import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureParameterImpl; - -import java.util.ArrayList; -import java.util.List; /** * @author Maxim.Medvedev */ -public class GrClosureSignatureImpl implements GrClosureSignature { +public class GrImmediateClosureSignatureImpl implements GrClosureSignature { private final boolean myIsVarargs; private final boolean myCurried; @Nullable private final PsiType myReturnType; @NotNull private final GrClosureParameter[] myParameters; @NotNull private final PsiSubstitutor mySubstitutor; - public GrClosureSignatureImpl(@NotNull PsiParameter[] parameters, @Nullable PsiType returnType, @NotNull PsiSubstitutor substitutor) { + public GrImmediateClosureSignatureImpl(@NotNull PsiParameter[] parameters, + @Nullable PsiType returnType, + @NotNull PsiSubstitutor substitutor) { myReturnType = substitutor.substitute(returnType); final int length = parameters.length; myParameters = new GrClosureParameter[length]; for (int i = 0; i < length; i++) { - myParameters[i] = new GrClosureParameterImpl(parameters[i], substitutor); + myParameters[i] = new GrImmediateClosureParameterImpl(parameters[i], substitutor); } if (length > 0) { myIsVarargs = myParameters[length - 1].getType() instanceof PsiArrayType; @@ -59,11 +55,11 @@ public class GrClosureSignatureImpl implements GrClosureSignature { myCurried = false; } - public GrClosureSignatureImpl(PsiParameter[] parameters, @Nullable PsiType returnType) { + public GrImmediateClosureSignatureImpl(PsiParameter[] parameters, @Nullable PsiType returnType) { this(parameters, returnType, PsiSubstitutor.EMPTY); } - GrClosureSignatureImpl(@NotNull GrClosureParameter[] params, @Nullable PsiType returnType, boolean isVarArgs, boolean isCurried) { + GrImmediateClosureSignatureImpl(@NotNull GrClosureParameter[] params, @Nullable PsiType returnType, boolean isVarArgs, boolean isCurried) { myParameters = params; myReturnType = returnType; myIsVarargs = isVarArgs; @@ -99,44 +95,8 @@ public class GrClosureSignatureImpl implements GrClosureSignature { } @Nullable - public GrSignature curry(@NotNull PsiType[] args, int position, @NotNull GroovyPsiElement context) { - GrClosureParameter[] params = myParameters; - - List newParams = new ArrayList(params.length); - List opts = new ArrayList(params.length); - List optInds = new ArrayList(params.length); - - if (position == -1) { - position = params.length - args.length; - } - - if (position < 0 || position >= params.length) return GrMultiSignature.EMPTY_SIGNATURE; - - for (int i = 0; i < params.length; i++) { - if (params[i].isOptional()) { - opts.add(params[i]); - optInds.add(i); - } - else { - newParams.add(params[i]); - } - } - - final PsiType rtype = getReturnType(); - final ArrayList result = new ArrayList(); - GrClosureSignatureUtil.checkAndAddSignature(result, args, position, newParams, rtype, context); - - for (int i = 0; i < opts.size(); i++) { - newParams.add(optInds.get(i), opts.get(i)); - GrClosureSignatureUtil.checkAndAddSignature(result, args, position, newParams, rtype, context); - } - - if (result.size() == 1) { - return result.get(0); - } - else { - return new GrMultiSignatureImpl(result.toArray(new GrClosureSignature[result.size()])); - } + public GrSignature curry(@NotNull PsiType[] args, int position, @NotNull PsiElement context) { + return GrClosureSignatureUtil.curryImpl(this, args, position, context); } public boolean isValid() { @@ -173,7 +133,7 @@ public class GrClosureSignatureImpl implements GrClosureSignature { final PsiType type = GenericsUtil.getGreatestLowerBound(parameters1[i].getType(), parameters2[i].getType()); boolean opt = parameters1[i].isOptional() && parameters2[i].isOptional(); String name = StringUtil.equals(parameters1[i].getName(), parameters2[i].getName()) ? parameters1[i].getName() : null; - params[i] = new GrClosureParameterImpl(type, name, opt, null); + params[i] = new GrImmediateClosureParameterImpl(type, name, opt, null); } final PsiType s1type = signature1.getReturnType(); final PsiType s2type = signature2.getReturnType(); @@ -182,7 +142,7 @@ public class GrClosureSignatureImpl implements GrClosureSignature { returnType = TypesUtil.getLeastUpperBound(s1type, s2type, manager); } boolean isVarArgs = signature1.isVarargs() && signature2.isVarargs(); - return new GrClosureSignatureImpl(params, returnType, isVarArgs, false); + return new GrImmediateClosureSignatureImpl(params, returnType, isVarArgs, false); } return null; //todo } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrMultiSignatureImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrMultiSignatureImpl.java index c944410b1d09..7667510b4014 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrMultiSignatureImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrMultiSignatureImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * 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. @@ -15,9 +15,9 @@ */ package org.jetbrains.plugins.groovy.lang.psi.impl.signatures; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrMultiSignature; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature; @@ -51,7 +51,7 @@ public class GrMultiSignatureImpl implements GrMultiSignature { } @Override - public GrSignature curry(@NotNull PsiType[] args, int position, @NotNull GroovyPsiElement context) { + public GrSignature curry(@NotNull PsiType[] args, int position, @NotNull PsiElement context) { List newClosures = new ArrayList(); for (GrClosureSignature old : mySignatures) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java index d2a514e81bf9..2cfbec56512d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -118,7 +118,7 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock @NotNull PsiScopeProcessor nonCodeProcessor, @NotNull ResolveState state, @NotNull PsiElement place) { - GrDelegatesToUtil.DelegatesToInfo info = GrDelegatesToUtil.getDelegateToInfo(place, this); + GrDelegatesToUtil.DelegatesToInfo info = GrDelegatesToUtil.getDelegatesToInfo(place, this); if (info == null) { return null; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java index 01b96c51d9ca..313065afc5d7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -44,7 +44,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; */ public class GrDelegatesToUtil { @Nullable - static DelegatesToInfo getDelegateToInfo(@NotNull PsiElement place, @NotNull final GrClosableBlock closableBlock) { + static DelegatesToInfo getDelegatesToInfo(@NotNull PsiElement place, @NotNull final GrClosableBlock closableBlock) { GrCall call = getContainingCall(closableBlock); if (call == null) return null; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index e1d565aa9fe8..6734a226fd0b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -47,7 +47,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.impl.*; -import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrImmediateClosureSignatureImpl; import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrTypeConverter; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -545,8 +545,8 @@ public class TypesUtil { if (signature1 instanceof GrClosureSignature && signature2 instanceof GrClosureSignature) { if (((GrClosureSignature)signature1).getParameterCount() == ((GrClosureSignature)signature2).getParameterCount()) { - final GrClosureSignature signature = GrClosureSignatureImpl.getLeastUpperBound(((GrClosureSignature)signature1), - ((GrClosureSignature)signature2), manager); + final GrClosureSignature signature = GrImmediateClosureSignatureImpl.getLeastUpperBound(((GrClosureSignature)signature1), + ((GrClosureSignature)signature2), manager); if (signature != null) { GlobalSearchScope scope = clType1.getResolveScope().intersectWith(clType2.getResolveScope()); final LanguageLevel languageLevel = ComparatorUtil.max(clType1.getLanguageLevel(), clType2.getLanguageLevel()); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java index 7f104ea2ee4b..0b1cb265cb45 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java @@ -16,8 +16,6 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.synthetic; import com.intellij.navigation.NavigationItem; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiIntersectionType; import com.intellij.psi.PsiType; @@ -69,12 +67,7 @@ public class ClosureSyntheticParameter extends GrLightParameter implements Navig public PsiType getTypeGroovy() { assert isValid(); - return RecursionManager.doPreventingRecursion(this, false, new Computable() { - @Override - public PsiType compute() { - return TypeInferenceHelper.getCurrentContext().getExpressionType(ClosureSyntheticParameter.this, TYPES_CALCULATOR); - } - }); + return TypeInferenceHelper.getCurrentContext().getExpressionType(this, TYPES_CALCULATOR); } @Nullable diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrGenericTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrGenericTypeConverter.java index e9a7c7490c04..cb403a47d4de 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrGenericTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrGenericTypeConverter.java @@ -1,3 +1,18 @@ +/* + * 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 org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; import com.intellij.psi.*; @@ -25,12 +40,8 @@ public class GrGenericTypeConverter extends GrTypeConverter { return null; } - - PsiClassType.ClassResolveResult lresult = ((PsiClassType)ltype).resolveGenerics(); - PsiClassType.ClassResolveResult rresult = ((PsiClassType)rtype).resolveGenerics(); - - PsiClass lclass = lresult.getElement(); - PsiClass rclass = rresult.getElement(); + PsiClass lclass = ((PsiClassType)ltype).resolve(); + PsiClass rclass = ((PsiClassType)rtype).resolve(); if (lclass == null || rclass == null) return null; @@ -38,6 +49,9 @@ public class GrGenericTypeConverter extends GrTypeConverter { if (!InheritanceUtil.isInheritorOrSelf(rclass, lclass, true)) return null; + PsiClassType.ClassResolveResult lresult = ((PsiClassType)ltype).resolveGenerics(); + PsiClassType.ClassResolveResult rresult = ((PsiClassType)rtype).resolveGenerics(); + if (typeParametersAgree(lclass, rclass, lresult.getSubstitutor(), rresult.getSubstitutor(), context)) return Boolean.TRUE; return null; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/LightGroovyTestCase.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/LightGroovyTestCase.groovy index 29518e9bb841..c9959b70c668 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/LightGroovyTestCase.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/LightGroovyTestCase.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -22,6 +22,8 @@ import com.intellij.testFramework.LightProjectDescriptor import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable + /** * @author peter */ @@ -247,7 +249,7 @@ public abstract class TestCase extends junit.framework.Assert implements junit.f ''') } - public static void assertType(String expected, PsiType actual) { + public static void assertType(@Nullable String expected, @Nullable PsiType actual) { if (expected == null) { assertNull(actual) return diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInference2_3Test.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInference2_3Test.groovy index d86e176ddd83..7382469e50e4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInference2_3Test.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInference2_3Test.groovy @@ -137,7 +137,6 @@ class Thing { ''', 'java.lang.Integer') } - void testSamInference4() { doTest(''' interface Action { @@ -154,4 +153,56 @@ def foo() { ''', 'java.lang.String') } + + void testSamInference5() { + doTest(''' +interface Action { + void execute(T t) +} + +public void exec(T t, Action f) { +} + + +def foo() { + exec('foo') {it.toUpperCase() } +} + +''', 'java.lang.String') + } + + void testSamInference6() { + doTest(''' +interface Action { + void execute(T t) +} + +public void exec(T t, Action f) { +} + + +def foo() { + exec('foo') {print it.toUpperCase() } +} + +''', 'java.lang.String') + } + + void testSamInference7() { + doTest(''' +interface CustomCallable { + T call() +} + +class Thing { + static T customType(CustomCallable callable) { + } + + static void run() { + customType { it } + } +}''', null) + } + + } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTestBase.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTestBase.groovy index 52c1e14ecfdd..fbbd630fcf8a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTestBase.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTestBase.groovy @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.lang.resolve import org.intellij.lang.annotations.Language +import org.jetbrains.annotations.Nullable 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.api.statements.expressions.GrExpression @@ -35,14 +36,14 @@ abstract class TypeInferenceTestBase extends GroovyResolveTestCase { myFixture.addClass("package java.math; public class BigDecimal extends Number implements Comparable {}"); } - protected void doTest(@Language("Groovy") String text, String type) { + protected void doTest(@Language("Groovy") String text, @Nullable String type) { def file = myFixture.configureByText('_.groovy', text) def ref = file.findReferenceAt(myFixture.editor.caretModel.offset) as GrReferenceExpression def actual = ref.type assertType(type, actual) } - protected void doExprTest(@Language("Groovy") String text, String expectedType) { + protected void doExprTest(@Language("Groovy") String text, @Nullable String expectedType) { GroovyFile file = myFixture.configureByText('_.groovy', text) as GroovyFile GrStatement lastStatement = file.statements.last() assertInstanceOf lastStatement, GrExpression diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index 6581eb0e4a5b..2d5a0b6f9000 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -563,6 +563,7 @@ refactoring.extract.method.error.cannot.perform.refactoring.with.local=Cannot pe # extract superclass refactoring.extract.super.target.path.outside.roots=Target directory is outside the project. Must be within content roots +refactoring.extract.super.target.class.already.exists=Class ''{0}'' already exists in this module refactoring.extract.super.name.0.must.be.ident=Name ''{0}'' is invalid. Must be a valid Python identifier refactoring.extract.super.class.no.members.allowed=None of members could be extracted diff --git a/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassPresenterImpl.java b/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassPresenterImpl.java index a61d7a6fed07..87ec445b036d 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassPresenterImpl.java +++ b/python/src/com/jetbrains/python/refactoring/classes/extractSuperclass/PyExtractSuperclassPresenterImpl.java @@ -6,13 +6,17 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.classMembers.MemberInfoModel; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PythonLanguage; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyElement; +import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyUtil; import com.jetbrains.python.refactoring.classes.PyMemberInfoStorage; import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo; @@ -47,8 +51,9 @@ class PyExtractSuperclassPresenterImpl extends MembersBasedPresenterNoPreviewImp throw new BadDataException(PyBundle.message("refactoring.extract.super.name.0.must.be.ident", myView.getSuperClassName())); } boolean rootFound = false; + final File moduleFile = new File(myView.getModuleFile()); try { - final String targetDir = FileUtil.toSystemIndependentName(new File(myView.getModuleFile()).getCanonicalPath()); + final String targetDir = FileUtil.toSystemIndependentName(moduleFile.getCanonicalPath()); for (final VirtualFile file : ProjectRootManager.getInstance(project).getContentRoots()) { if (StringUtil.startsWithIgnoreCase(targetDir, file.getPath())) { rootFound = true; @@ -61,6 +66,19 @@ class PyExtractSuperclassPresenterImpl extends MembersBasedPresenterNoPreviewImp if (!rootFound) { throw new BadDataException(PyBundle.message("refactoring.extract.super.target.path.outside.roots")); } + + // TODO: Cover with test. It can't be done for now, because testFixture reports root path incorrectly + // PY-12173 + myView.getModuleFile(); + final VirtualFile moduleVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(moduleFile); + if (moduleVirtualFile != null) { + final PsiFile psiFile = PsiManager.getInstance(project).findFile(moduleVirtualFile); + if (psiFile instanceof PyFile) { + if (((PyFile)psiFile).findTopLevelClass(myView.getSuperClassName()) != null) { + throw new BadDataException(PyBundle.message("refactoring.extract.super.target.class.already.exists", myView.getSuperClassName())); + } + } + } } @Override @@ -71,9 +89,9 @@ class PyExtractSuperclassPresenterImpl extends MembersBasedPresenterNoPreviewImp PyUtil.filterOutObject(myStorage.getClassMemberInfos(myClassUnderRefactoring)); myView.configure( new PyExtractSuperclassInitializationInfo(myModel, pyMemberInfos, defaultFilePath, - roots)); + roots) + ); myView.initAndShow(); - } @NotNull diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpHandler.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpHandler.java index 6dcb3b6a13a2..4fa0eac3a4ef 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpHandler.java +++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpHandler.java @@ -17,8 +17,6 @@ package com.jetbrains.python.refactoring.classes.pullUp; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.refactoring.RefactoringBundle; -import com.intellij.refactoring.util.CommonRefactoringUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.refactoring.classes.PyClassRefactoringHandler; @@ -39,14 +37,10 @@ public class PyPullUpHandler extends PyClassRefactoringHandler { @NotNull final PyMemberInfoStorage infoStorage, @NotNull final Editor editor) { //TODO: Move to vp (presenter) as well + final PyPullUpNothingToRefactorMessage nothingToRefactor = new PyPullUpNothingToRefactorMessage(project, editor, classUnderRefactoring); - if (PyAncestorsUtils.getAncestorsUnderUserControl(classUnderRefactoring).isEmpty() || - infoStorage.getClassMemberInfos(classUnderRefactoring).isEmpty()) { - CommonRefactoringUtil.showErrorHint(project, editor, PyBundle - .message("refactoring.pull.up.error.cannot.perform.refactoring.no.base.classes", - classUnderRefactoring.getName()), RefactoringBundle.message("pull.members.up.title"), - "members.pull.up" - ); + if (PyAncestorsUtils.getAncestorsUnderUserControl(classUnderRefactoring).isEmpty()) { + nothingToRefactor.showNothingToRefactor(); return; } @@ -62,13 +56,13 @@ public class PyPullUpHandler extends PyClassRefactoringHandler { @NotNull @Override public PyPullUpView createView(@NotNull final PyPullUpPresenter presenter) { - return new PyPullUpViewSwingImpl(project, presenter, classUnderRefactoring); + return new PyPullUpViewSwingImpl(project, presenter, classUnderRefactoring, nothingToRefactor); } } ); - } + @Override protected String getTitle() { return REFACTORING_NAME; diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpNothingToRefactorMessage.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpNothingToRefactorMessage.java new file mode 100644 index 000000000000..cbb599c34695 --- /dev/null +++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpNothingToRefactorMessage.java @@ -0,0 +1,48 @@ +package com.jetbrains.python.refactoring.classes.pullUp; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.util.CommonRefactoringUtil; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.psi.PyClass; +import org.jetbrains.annotations.NotNull; + +/** + * Displays "nothing to refactor" message + * @author Ilya.Kazakevich + */ +class PyPullUpNothingToRefactorMessage { + + @NotNull + private final Project myProject; + @NotNull + private final Editor myEditor; + @NotNull + private final PyClass myClassUnderRefactoring; + + /** + * + * @param project project to be used + * @param editor editor to be used + * @param classUnderRefactoring class user refactors + */ + PyPullUpNothingToRefactorMessage(@NotNull final Project project, + @NotNull final Editor editor, + @NotNull final PyClass classUnderRefactoring) { + myProject = project; + myEditor = editor; + myClassUnderRefactoring = classUnderRefactoring; + } + + /** + * Display message + */ + void showNothingToRefactor() { + CommonRefactoringUtil.showErrorHint(myProject, myEditor, PyBundle + .message("refactoring.pull.up.error.cannot.perform.refactoring.no.base.classes", + myClassUnderRefactoring.getName()), RefactoringBundle.message("pull.members.up.title"), + "members.pull.up" + ); + } +} diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterImpl.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterImpl.java index 74276974a392..b78433aee44e 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterImpl.java +++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpPresenterImpl.java @@ -55,7 +55,22 @@ class PyPullUpPresenterImpl extends MembersBasedPresenterWithPreviewImpl info : myStorage.getClassMemberInfos(myClassUnderRefactoring)) { + if (myModel.isMemberEnabled(info)) { + atLeastOneEnabled = true; + } + } + + + if (atLeastOneEnabled) { + myView.initAndShow(); + } else { + myView.showNothingToRefactor(); + } } @Override diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpView.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpView.java index b0a42e048282..0a770ea08bff 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpView.java +++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpView.java @@ -31,4 +31,9 @@ public interface PyPullUpView extends MembersBasedView> infos = getMemberInfos(sut); final Capture>> conflictCapture = new Capture>>(); @@ -123,7 +124,6 @@ public class PyPullUpPresenterTest extends PyRefactoringPresenterTestCase