From 5a16d4daa2060a7ae9f23195d96e8ee9201dd9b2 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Apr 2016 09:30:46 +0200 Subject: [PATCH 01/26] IDEA-154289 PsiClass and view provider can never agree on language --- .../src/com/intellij/psi/ClassFileViewProvider.java | 8 ++++++++ java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java | 7 +++++++ .../src/com/intellij/psi/SingleRootFileViewProvider.java | 8 ++++---- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java index 7ff44384c50d..18b5c8901fb4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java +++ b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java @@ -16,6 +16,8 @@ package com.intellij.psi; import com.intellij.ide.highlighter.JavaClassFileType; +import com.intellij.lang.Language; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; @@ -51,6 +53,12 @@ public class ClassFileViewProvider extends SingleRootFileViewProvider { super(manager, file, eventSystemEnabled, JavaClassFileType.INSTANCE); } + @NotNull + @Override + public Language getBaseLanguage() { + return JavaLanguage.INSTANCE; + } + @Override protected PsiFile createFile(@NotNull Project project, @NotNull VirtualFile file, @NotNull FileType fileType) { FileIndexFacade fileIndex = ServiceManager.getService(project, FileIndexFacade.class); diff --git a/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java b/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java index d5c0b71b712d..ab34446be4f8 100644 --- a/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java @@ -15,6 +15,7 @@ */ package com.intellij.psi; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.IoTestUtil; @@ -100,6 +101,12 @@ public class ClsPsiTest extends LightIdeaTestCase { assertFalse(aClass.isDeprecated()); } + public void testViewProviderHasJavaLanguage() { + PsiJavaFile file = getFile("MyClass"); + assertEquals(JavaLanguage.INSTANCE, file.getLanguage()); + assertEquals(JavaLanguage.INSTANCE, file.getViewProvider().getBaseLanguage()); + } + public void testClassMembers() { PsiClass aClass = getFile("MyClass").getClasses()[0]; diff --git a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java index 1cecb94c5bd7..e2d0b39bc816 100644 --- a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java +++ b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java @@ -293,12 +293,12 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi } public List getCachedPsiFiles() { - return ContainerUtil.createMaybeSingletonList(getCachedPsi(myBaseLanguage)); + return ContainerUtil.createMaybeSingletonList(getCachedPsi(getBaseLanguage())); } @NotNull public List getKnownTreeRoots() { - PsiFile psiFile = getCachedPsi(myBaseLanguage); + PsiFile psiFile = getCachedPsi(getBaseLanguage()); if (!(psiFile instanceof PsiFileImpl)) return Collections.emptyList(); FileElement element = ((PsiFileImpl)psiFile).getTreeElement(); return ContainerUtil.createMaybeSingletonList(element); @@ -457,7 +457,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi @NotNull @Override public SingleRootFileViewProvider createCopy(@NotNull final VirtualFile copy) { - return new SingleRootFileViewProvider(getManager(), copy, false, myBaseLanguage); + return new SingleRootFileViewProvider(getManager(), copy, false, getBaseLanguage()); } @Override @@ -572,7 +572,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi } public void markInvalidated() { - PsiFile psiFile = getCachedPsi(myBaseLanguage); + PsiFile psiFile = getCachedPsi(getBaseLanguage()); if (psiFile instanceof PsiFileEx) { ((PsiFileEx)psiFile).markInvalidated(); } From 905c8a06b1dcde96704c64d53ecaa24508fa1411 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Apr 2016 09:32:05 +0200 Subject: [PATCH 02/26] IDEA-154583 Resolve inside library through exported dependencies quirks --- .../com/intellij/roots/ModuleScopesTest.java | 20 +++++++++++++++++++ .../openapi/roots/impl/RootIndex.java | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/java/java-tests/testSrc/com/intellij/roots/ModuleScopesTest.java b/java/java-tests/testSrc/com/intellij/roots/ModuleScopesTest.java index ba5715407ecf..00e35eed1705 100644 --- a/java/java-tests/testSrc/com/intellij/roots/ModuleScopesTest.java +++ b/java/java-tests/testSrc/com/intellij/roots/ModuleScopesTest.java @@ -26,6 +26,7 @@ import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.roots.OrderEnumerator; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.impl.ResolveScopeManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.testFramework.ModuleTestCase; import com.intellij.testFramework.PsiTestUtil; @@ -309,4 +310,23 @@ public class ModuleScopesTest extends ModuleTestCase { assertEquals(deps, deps2); assertEquals(depsTests, depsTests2); } + + public void testHonorExportsWhenCalculatingLibraryScope() throws IOException { + Module a = createModule("a.iml", StdModuleTypes.JAVA); + Module b = createModule("b.iml", StdModuleTypes.JAVA); + Module c = createModule("c.iml", StdModuleTypes.JAVA); + ModuleRootModificationUtil.addDependency(a, b, DependencyScope.COMPILE, true); + ModuleRootModificationUtil.addDependency(b, c, DependencyScope.COMPILE, true); + + final VirtualFile libFile1 = myFixture.createFile("lib1/a.txt", ""); + final VirtualFile libFile2 = myFixture.createFile("lib2/a.txt", ""); + + ModuleRootModificationUtil.addModuleLibrary(a, "l", Collections.singletonList(libFile1.getParent().getUrl()), + Collections.emptyList(), Collections.emptyList(), DependencyScope.COMPILE, true); + ModuleRootModificationUtil.addModuleLibrary(c, "l", Collections.singletonList(libFile2.getParent().getUrl()), + Collections.emptyList(), Collections.emptyList(), DependencyScope.COMPILE, true); + + assertTrue(ResolveScopeManager.getElementResolveScope(getPsiManager().findFile(libFile1)).contains(libFile2)); + assertTrue(ResolveScopeManager.getElementResolveScope(getPsiManager().findFile(libFile2)).contains(libFile1)); + } } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java index 6dda1df689b2..b1cf97108d28 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java @@ -249,7 +249,7 @@ public class RootIndex { final Module depModule = moduleOrderEntry.getModule(); if (depModule != null) { Node node = graph.myNodes.get(depModule); - OrderEnumerator en = OrderEnumerator.orderEntries(depModule).exportedOnly(); + OrderEnumerator en = OrderEnumerator.orderEntries(depModule).exportedOnly().recursively(); if (node == null) { node = new Node(); node.myKey = depModule; From a1a901c150ff2ad93e475c9816d385a7d52f399b Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Apr 2016 10:01:13 +0200 Subject: [PATCH 03/26] assert that documents should be committed when highlighting starts --- .../daemon/impl/TextEditorBackgroundHighlighter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/TextEditorBackgroundHighlighter.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/TextEditorBackgroundHighlighter.java index 02efbed000a1..b055d834d5f3 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/TextEditorBackgroundHighlighter.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/TextEditorBackgroundHighlighter.java @@ -19,6 +19,7 @@ import com.intellij.codeHighlighting.BackgroundEditorHighlighter; import com.intellij.codeHighlighting.Pass; import com.intellij.codeHighlighting.TextEditorHighlightingPass; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; @@ -33,6 +34,7 @@ import java.util.Collections; import java.util.List; public class TextEditorBackgroundHighlighter implements BackgroundEditorHighlighter { + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.TextEditorBackgroundHighlighter"); private static final int[] EXCEPT_OVERRIDDEN = { Pass.UPDATE_FOLDING, Pass.POPUP_HINTS, @@ -75,7 +77,7 @@ public class TextEditorBackgroundHighlighter implements BackgroundEditorHighligh @NotNull List getPasses(@NotNull int[] passesToIgnore) { if (myProject.isDisposed()) return Collections.emptyList(); - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + LOG.assertTrue(!PsiDocumentManager.getInstance(myProject).hasUncommitedDocuments()); renewFile(); if (myFile == null) return Collections.emptyList(); if (myCompiled) { From 4fbd0023dc58a30ed9bd2eb6cc622afbd78f9ace Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Apr 2016 10:11:44 +0200 Subject: [PATCH 04/26] debugger editor: don't commit document, take text from it directly --- .../jetbrains/java/debugger/JavaDebuggerEditorsProvider.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java b/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java index fe92203e34ae..9146674a158f 100644 --- a/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java @@ -41,7 +41,6 @@ import java.util.Collections; import java.util.stream.Collectors; public class JavaDebuggerEditorsProvider extends XDebuggerEditorsProviderBase { - @NotNull @Override public FileType getFileType() { return JavaFileType.INSTANCE; @@ -70,10 +69,9 @@ public class JavaDebuggerEditorsProvider extends XDebuggerEditorsProviderBase { @NotNull @Override public XExpression createExpression(@NotNull Project project, @NotNull Document document, @Nullable Language language, @NotNull EvaluationMode mode) { - PsiDocumentManager.getInstance(project).commitDocument(document); PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); if (psiFile != null) { - return new XExpressionImpl(psiFile.getText(), language, StringUtil.nullize(((JavaCodeFragment)psiFile).importsToString()), mode); + return new XExpressionImpl(document.getText(), language, StringUtil.nullize(((JavaCodeFragment)psiFile).importsToString()), mode); } return super.createExpression(project, document, language, mode); } From 1f94bd04191350d36a551038c09093c7a19b4281 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Apr 2016 10:19:05 +0200 Subject: [PATCH 05/26] supply modality state for invokeLater at the end of settings dialog background loading --- .../platform-impl/src/com/intellij/ui/CardLayoutPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/CardLayoutPanel.java b/platform/platform-impl/src/com/intellij/ui/CardLayoutPanel.java index 4649ba58efa8..09602952bc3b 100644 --- a/platform/platform-impl/src/com/intellij/ui/CardLayoutPanel.java +++ b/platform/platform-impl/src/com/intellij/ui/CardLayoutPanel.java @@ -25,7 +25,7 @@ import com.intellij.util.ui.JBInsets; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; -import javax.swing.JComponent; +import javax.swing.*; import java.awt.*; import java.util.IdentityHashMap; import java.util.Iterator; @@ -137,7 +137,7 @@ public abstract class CardLayoutPanel extends JCompo } else callback.setRejected(); } - }, ModalityState.any()); + }, ModalityState.stateForComponent(CardLayoutPanel.this)); } else callback.setRejected(); } From 85601ec30c4e66ad0555d8e21d5fcf24bcbbfa96 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Apr 2016 10:23:35 +0200 Subject: [PATCH 06/26] support captured types in incomplete overloaded lambda completion (IDEA-155188) --- .../completion/JavaCompletionUtil.java | 24 +++++++++++-------- ...hCapturedSuperWildcardInAmbiguousCall.java | 8 +++++++ .../completion/Normal8CompletionTest.groovy | 4 ++++ 3 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/LambdaWithCapturedSuperWildcardInAmbiguousCall.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 3c4acda4294e..998e8bec4d2c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -270,16 +270,9 @@ public class JavaCompletionUtil { final int parameterIndex = lambdaExpression.getParameterList().getParameterIndex((PsiParameter)resolve); final Set set = new LinkedHashSet(); final boolean overloadsFound = LambdaUtil.processParentOverloads(lambdaExpression, functionalInterfaceType -> { - PsiType qualifierType = LambdaUtil.getLambdaParameterFromType(functionalInterfaceType, parameterIndex); + PsiType qualifierType = removeTopLevelWildcards(LambdaUtil.getLambdaParameterFromType(functionalInterfaceType, parameterIndex)); if (qualifierType == null) return; - if (qualifierType instanceof PsiWildcardType) { - PsiType bound = ((PsiWildcardType)qualifierType).getBound(); - if (bound != null) { - qualifierType = bound; - } - } - PsiReferenceExpression fakeRef = createReference("xxx.xxx", createContextWithXxxVariable(element, qualifierType)); set.addAll(processJavaQualifiedReference(fakeRef.getReferenceNameElement(), fakeRef, elementFilter, options, matcher, parameters)); }); @@ -288,10 +281,21 @@ public class JavaCompletionUtil { } } } - } + } return processJavaQualifiedReference(element, javaReference, elementFilter, options, matcher, parameters); } - + + @Nullable + private static PsiType removeTopLevelWildcards(@Nullable PsiType qualifierType) { + if (qualifierType instanceof PsiCapturedWildcardType) { + return removeTopLevelWildcards(((PsiCapturedWildcardType)qualifierType).getWildcard()); + } + if (qualifierType instanceof PsiWildcardType) { + return removeTopLevelWildcards(((PsiWildcardType)qualifierType).getBound()); + } + return qualifierType; + } + private static Set processJavaQualifiedReference(PsiElement element, PsiJavaReference javaReference, ElementFilter elementFilter, JavaCompletionProcessor.Options options, final PrefixMatcher matcher, CompletionParameters parameters) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/LambdaWithCapturedSuperWildcardInAmbiguousCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/LambdaWithCapturedSuperWildcardInAmbiguousCall.java new file mode 100644 index 000000000000..523e3e0b1aea --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/completion/normal/LambdaWithCapturedSuperWildcardInAmbiguousCall.java @@ -0,0 +1,8 @@ +import java.util.stream.*; +import java.util.*; + +class Foo { + void main(Stream stream) { + stream.collect(Collectors.toMap(o -> o.sub)) + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal8CompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal8CompletionTest.groovy index 0117e51fcf12..29a40fe7071c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal8CompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal8CompletionTest.groovy @@ -244,6 +244,10 @@ class Test88 { configureByTestName() myFixture.assertPreferredCompletionItems(0, 'substring', 'substring', 'subSequence') } + public void testLambdaWithCapturedSuperWildcardInAmbiguousCall() { + configureByTestName() + myFixture.assertPreferredCompletionItems(0, 'substring', 'substring', 'subSequence') + } public void testUnexpectedLambdaInAmbiguousCall() { doAntiTest() } public void testNoCollectorsInComment() { doAntiTest() } From 6c023ce5f29417702d6a18b019b0326e0c8f85f2 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Apr 2016 10:25:38 +0200 Subject: [PATCH 07/26] assert that popup onChosen handlers don't show dialogs directly and use finalRunnable instead --- .../intellij/ui/popup/list/ListPopupImpl.java | 30 ++++++++++++++----- .../intellij/ui/popup/tree/TreePopupImpl.java | 20 ++++++++++++- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/popup/list/ListPopupImpl.java b/platform/platform-impl/src/com/intellij/ui/popup/list/ListPopupImpl.java index bcc4de4428be..8a55f0a28b87 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/list/ListPopupImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/list/ListPopupImpl.java @@ -20,6 +20,8 @@ import com.intellij.ide.IdeEventQueue; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.util.text.StringUtil; @@ -43,8 +45,10 @@ import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.event.*; import java.util.Arrays; +import java.util.concurrent.atomic.AtomicBoolean; public class ListPopupImpl extends WizardPopup implements ListPopup { + private static final Logger LOG = Logger.getInstance("#com.intellij.ui.popup.list.ListPopupImpl"); private MyList myList; @@ -376,15 +380,27 @@ public class ListPopupImpl extends WizardPopup implements ListPopup { valuesSelected(selectedValues); + AtomicBoolean insideOnChosen = new AtomicBoolean(true); + ApplicationManager.getApplication().invokeLater(() -> { + if (insideOnChosen.get()) { + LOG.error("Showing dialogs from popup onChosen can result in focus issues. Please put the handler into BaseStep.doFinalStep or PopupStep.getFinalRunnable."); + } + }, ModalityState.any()); + final PopupStep nextStep; - if (listStep instanceof MultiSelectionListPopupStep) { - nextStep = ((MultiSelectionListPopupStep)listStep).onChosen(Arrays.asList(selectedValues), handleFinalChoices); + try { + if (listStep instanceof MultiSelectionListPopupStep) { + nextStep = ((MultiSelectionListPopupStep)listStep).onChosen(Arrays.asList(selectedValues), handleFinalChoices); + } + else if (e != null && listStep instanceof ListPopupStepEx) { + nextStep = ((ListPopupStepEx)listStep).onChosen(selectedValues[0], handleFinalChoices, e.getModifiers()); + } + else { + nextStep = listStep.onChosen(selectedValues[0], handleFinalChoices); + } } - else if (e != null && listStep instanceof ListPopupStepEx) { - nextStep = ((ListPopupStepEx)listStep).onChosen(selectedValues[0], handleFinalChoices, e.getModifiers()); - } - else { - nextStep = listStep.onChosen(selectedValues[0], handleFinalChoices); + finally { + insideOnChosen.set(false); } return handleNextStep(nextStep, selectedValues.length == 1 ? selectedValues[0] : null, e); } diff --git a/platform/platform-impl/src/com/intellij/ui/popup/tree/TreePopupImpl.java b/platform/platform-impl/src/com/intellij/ui/popup/tree/TreePopupImpl.java index 2748bc2525bf..92c6735883ff 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/tree/TreePopupImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/tree/TreePopupImpl.java @@ -18,6 +18,9 @@ package com.intellij.ui.popup.tree; import com.intellij.icons.AllIcons; import com.intellij.ide.util.treeView.AlphaComparator; import com.intellij.ide.util.treeView.NodeRenderer; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.PopupStep; @@ -41,8 +44,10 @@ import java.awt.event.*; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; public class TreePopupImpl extends WizardPopup implements TreePopup { + private static final Logger LOG = Logger.getInstance("#com.intellij.ui.popup.tree.TreePopupImpl"); private MyTree myWizardTree; private MouseMotionListener myMouseMotionListener; @@ -349,7 +354,20 @@ public class TreePopupImpl extends WizardPopup implements TreePopup { return; } - final PopupStep queriedStep = myStep.onChosen(userObject, handleFinalChoices); + AtomicBoolean insideOnChosen = new AtomicBoolean(true); + ApplicationManager.getApplication().invokeLater(() -> { + if (insideOnChosen.get()) { + LOG.error("Showing dialogs from popup onChosen can result in focus issues. Please put the handler into BaseStep.doFinalStep or PopupStep.getFinalRunnable."); + } + }, ModalityState.any()); + + final PopupStep queriedStep; + try { + queriedStep = myStep.onChosen(userObject, handleFinalChoices); + } + finally { + insideOnChosen.set(false); + } if (queriedStep == PopupStep.FINAL_CHOICE || !hasNextStep) { setFinalRunnable(myStep.getFinalRunnable()); setOk(true); From e1b2bde66281deaca5c4af7228892e77557a294e Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Apr 2016 10:45:43 +0200 Subject: [PATCH 08/26] SequentialModalProgressTask: use invokeLater with progress's modality state --- .../util/SequentialModalProgressTask.java | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/SequentialModalProgressTask.java b/platform/lang-impl/src/com/intellij/util/SequentialModalProgressTask.java index 40225ffa896a..5dc580aea3e2 100644 --- a/platform/lang-impl/src/com/intellij/util/SequentialModalProgressTask.java +++ b/platform/lang-impl/src/com/intellij/util/SequentialModalProgressTask.java @@ -15,11 +15,11 @@ */ package com.intellij.util; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -86,27 +86,18 @@ public class SequentialModalProgressTask extends Task.Modal { task.stop(); break; } - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - long start = System.currentTimeMillis(); - try { - while (!task.isDone() && System.currentTimeMillis() - start < myMinIterationTime) { - task.iteration(); - } - } - catch (RuntimeException e) { - task.stop(); - throw e; + ApplicationManager.getApplication().invokeAndWait(() -> { + long start = System.currentTimeMillis(); + try { + while (!task.isDone() && System.currentTimeMillis() - start < myMinIterationTime) { + task.iteration(); } } - }); - //if (ApplicationManager.getApplication().isDispatchThread()) { - // runnable.run(); - //} - //else { - // ApplicationManagerEx.getApplicationEx().suspendReadAccessAndRunWriteAction(runnable); - //} + catch (RuntimeException e) { + task.stop(); + throw e; + } + }, indicator.getModalityState()); } } From b6a60183db2f7ba64a805bbb47591304559e3f62 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Apr 2016 10:59:12 +0200 Subject: [PATCH 09/26] store only members in per-class per-name cache to save memory on Pair objects, determine substitutor by its declaring class when needed --- .../intellij/psi/impl/PsiClassImplUtil.java | 178 +++++++++--------- .../psi/impl/ScopedClassHierarchy.java | 33 ++++ 2 files changed, 125 insertions(+), 86 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java index 5f84c94de0ee..cb335d7b7314 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java @@ -28,10 +28,7 @@ import com.intellij.psi.impl.source.ClassInnerStuffCache; import com.intellij.psi.impl.source.PsiImmediateClassType; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; import com.intellij.psi.infos.MethodCandidateInfo; -import com.intellij.psi.scope.ElementClassFilter; -import com.intellij.psi.scope.ElementClassHint; -import com.intellij.psi.scope.NameHint; -import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.scope.*; import com.intellij.psi.scope.processor.FilterScopeProcessor; import com.intellij.psi.scope.processor.MethodResolverProcessor; import com.intellij.psi.search.*; @@ -42,7 +39,6 @@ import com.intellij.util.*; import com.intellij.util.containers.ConcurrentFactoryMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; -import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -150,15 +146,9 @@ public class PsiClassImplUtil { if (name == null) return Collections.emptyList(); if (checkBases) { - Map[]> allMethodsMap = getMap(aClass, type); - Pair[] list = allMethodsMap.get(name); + PsiMember[] list = getMap(aClass, type).get(name); if (list == null) return Collections.emptyList(); - List ret = new ArrayList(list.length); - for (final Pair info : list) { - ret.add(info.getFirst()); - } - - return ret; + return Arrays.asList(list); } else { PsiMember[] members = null; @@ -186,10 +176,7 @@ public class PsiClassImplUtil { @NotNull public static List> getAllWithSubstitutorsByMap(@NotNull PsiClass aClass, @NotNull MemberType type) { - Map[]> allMap = getMap(aClass, type); - Pair[] pairs = allMap.get(ALL); - //noinspection unchecked - return Arrays.>asList((Pair[])pairs); + return withSubstitutors(aClass, getMap(aClass, type).get(ALL)); } @NotNull @@ -211,7 +198,7 @@ public class PsiClassImplUtil { public enum MemberType {CLASS, FIELD, METHOD} - private static Map[]> getMap(@NotNull PsiClass aClass, @NotNull MemberType type) { + private static Map getMap(@NotNull PsiClass aClass, @NotNull MemberType type) { ParameterizedCachedValue, PsiClass> value = getValues(aClass); return value.getValue(aClass).get(aClass.getResolveScope()).get(type); } @@ -358,7 +345,7 @@ public class PsiClassImplUtil { return factory.createMethodFromText(text, null).getSignature(PsiSubstitutor.EMPTY); } - private static class MembersMap extends ConcurrentFactoryMap[]>> { + private static class MembersMap extends ConcurrentFactoryMap> { private final PsiClass myPsiClass; private final GlobalSearchScope myResolveScope; @@ -369,10 +356,10 @@ public class PsiClassImplUtil { @Nullable @Override - protected Map[]> create(final MemberType key) { - final Map>> map = new THashMap>>(); + protected Map create(final MemberType key) { + final Map> map = ContainerUtil.newTroveMap(); - final List> allMembers = new ArrayList>(); + final List allMembers = ContainerUtil.newArrayList(); map.put(ALL, allMembers); ElementClassFilter filter = key == MemberType.CLASS ? ElementClassFilter.CLASS : @@ -392,15 +379,14 @@ public class PsiClassImplUtil { if (key == MemberType.CLASS && element instanceof PsiClass || key == MemberType.METHOD && element instanceof PsiMethod || key == MemberType.FIELD && element instanceof PsiField) { - Pair info = Pair.create((PsiMember)element, substitutor); - allMembers.add(info); + allMembers.add((PsiMember)element); String currentName = ((PsiMember)element).getName(); - List> listByName = map.get(currentName); + List listByName = map.get(currentName); if (listByName == null) { - listByName = new ArrayList>(1); + listByName = ContainerUtil.newArrayList(); map.put(currentName, listByName); } - listByName.add(info); + listByName.add((PsiMember)element); } } @@ -413,10 +399,10 @@ public class PsiClassImplUtil { processDeclarationsInClassNotCached(myPsiClass, processor, ResolveState.initial(), null, null, myPsiClass, false, PsiUtil.getLanguageLevel(myPsiClass), myResolveScope); - Map[]> result = ContainerUtil.newTroveMap(); + Map result = ContainerUtil.newTroveMap(); for (String name : map.keySet()) { //noinspection unchecked - result.put(name, map.get(name).toArray(new Pair[0])); + result.put(name, map.get(name).toArray(PsiMember.EMPTY_ARRAY)); } return result; } @@ -494,20 +480,32 @@ public class PsiClassImplUtil { return processDeclarationsInClassNotCached(aClass, processor, state, visited, last, place, isRaw, languageLevel, resolveScope); } - private static boolean processCachedMembersByName(@NotNull PsiClass aClass, + private static boolean processCachedMembersByName(@NotNull final PsiClass aClass, @NotNull PsiScopeProcessor processor, @NotNull ResolveState state, @Nullable Set visited, PsiElement last, - @NotNull PsiElement place, - boolean isRaw, - @NotNull PsiSubstitutor substitutor, + @NotNull final PsiElement place, + final boolean isRaw, + @NotNull final PsiSubstitutor substitutor, @NotNull MembersMap value, String name, - @NotNull LanguageLevel languageLevel) { - final ElementClassHint classHint = processor.getHint(ElementClassHint.KEY); + @NotNull final LanguageLevel languageLevel) { + Function finalSubstitutor = new Function() { + final ScopedClassHierarchy hierarchy = ScopedClassHierarchy.getHierarchy(aClass, place.getResolveScope()); + final PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); + @Override + public PsiSubstitutor fun(PsiMember member) { + PsiClass containingClass = ObjectUtils.assertNotNull(member.getContainingClass()); + PsiSubstitutor superSubstitutor = hierarchy.getSuperMembersSubstitutor(containingClass, languageLevel); + PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(containingClass, + superSubstitutor == null ? PsiSubstitutor.EMPTY : superSubstitutor, + aClass, substitutor, factory, languageLevel); + return member instanceof PsiMethod ? checkRaw(isRaw, factory, (PsiMethod)member, finalSubstitutor) : finalSubstitutor; + } + }; - PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); + final ElementClassHint classHint = processor.getHint(ElementClassHint.KEY); if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.FIELD)) { final PsiField fieldByName = aClass.findFieldByName(name, false); @@ -516,23 +514,20 @@ public class PsiClassImplUtil { if (!processor.execute(fieldByName, state)) return false; } else { - final Map[]> allFieldsMap = value.get(MemberType.FIELD); + final Map allFieldsMap = value.get(MemberType.FIELD); - final Pair[] list = allFieldsMap.get(name); + final PsiMember[] list = allFieldsMap.get(name); if (list != null) { boolean resolved = false; - for (final Pair candidate : list) { - PsiMember candidateField = candidate.getFirst(); + for (final PsiMember candidateField : list) { PsiClass containingClass = candidateField.getContainingClass(); if (containingClass == null) { LOG.error("No class for field " + candidateField.getName() + " of " + candidateField.getClass()); continue; } - PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(containingClass, candidate.getSecond(), aClass, - substitutor, factory, languageLevel); processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass); - if (!processor.execute(candidateField, state.put(PsiSubstitutor.KEY, finalSubstitutor))) { + if (!processor.execute(candidateField, state.put(PsiSubstitutor.KEY, finalSubstitutor.fun(candidateField)))) { resolved = true; } } @@ -556,19 +551,16 @@ public class PsiClassImplUtil { if (!processor.execute(classByName, state)) return false; } else { - Map[]> allClassesMap = value.get(MemberType.CLASS); + Map allClassesMap = value.get(MemberType.CLASS); - Pair[] list = allClassesMap.get(name); + PsiMember[] list = allClassesMap.get(name); if (list != null) { boolean resolved = false; - for (final Pair candidate : list) { - PsiMember inner = candidate.getFirst(); + for (final PsiMember inner : list) { PsiClass containingClass = inner.getContainingClass(); if (containingClass != null) { - PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(containingClass, candidate.getSecond(), aClass, - substitutor, factory, languageLevel); processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass); - if (!processor.execute(inner, state.put(PsiSubstitutor.KEY, finalSubstitutor))) { + if (!processor.execute(inner, state.put(PsiSubstitutor.KEY, finalSubstitutor.fun(inner)))) { resolved = true; } } @@ -590,13 +582,13 @@ public class PsiClassImplUtil { return true; } } - Map[]> allMethodsMap = value.get(MemberType.METHOD); - Pair[] list = allMethodsMap.get(name); + Map allMethodsMap = value.get(MemberType.METHOD); + PsiMember[] list = allMethodsMap.get(name); if (list != null) { boolean resolved = false; - for (final Pair candidate : list) { + for (final PsiMember candidate : list) { ProgressIndicatorProvider.checkCanceled(); - PsiMethod candidateMethod = (PsiMethod)candidate.getFirst(); + PsiMethod candidateMethod = (PsiMethod)candidate; if (processor instanceof MethodResolverProcessor) { if (candidateMethod.isConstructor() != ((MethodResolverProcessor)processor).isConstructor()) continue; } @@ -605,19 +597,16 @@ public class PsiClassImplUtil { continue; } - PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(containingClass, candidate.getSecond(), aClass, - substitutor, factory, languageLevel); - finalSubstitutor = checkRaw(isRaw, factory, candidateMethod, finalSubstitutor); processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass); - if (!processor.execute(candidateMethod, state.put(PsiSubstitutor.KEY, finalSubstitutor))) { + if (!processor.execute(candidateMethod, state.put(PsiSubstitutor.KEY, finalSubstitutor.fun(candidateMethod)))) { resolved = true; } } if (resolved) return false; if (visited != null) { - for (Pair aList : list) { - visited.add(aList.getFirst().getContainingClass()); + for (PsiMember aList : list) { + visited.add(aList.getContainingClass()); } } } @@ -658,14 +647,14 @@ public class PsiClassImplUtil { } private static boolean processDeclarationsInClassNotCached(@NotNull PsiClass aClass, - @NotNull PsiScopeProcessor processor, - @NotNull ResolveState state, + @NotNull final PsiScopeProcessor processor, + @NotNull final ResolveState state, @Nullable Set visited, - PsiElement last, - @NotNull PsiElement place, - boolean isRaw, - @NotNull LanguageLevel languageLevel, - @NotNull GlobalSearchScope resolveScope) { + final PsiElement last, + @NotNull final PsiElement place, + final boolean isRaw, + @NotNull final LanguageLevel languageLevel, + @NotNull final GlobalSearchScope resolveScope) { if (visited == null) visited = new THashSet(); if (!visited.add(aClass)) return true; processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); @@ -722,8 +711,16 @@ public class PsiClassImplUtil { } } - return last instanceof PsiReferenceList || processSuperTypes(aClass, processor, visited, last, place, state, isRaw, factory, - languageLevel, resolveScope); + if (last instanceof PsiReferenceList) return true; + + final Set visited1 = visited; + return processSuperTypes(aClass, state.get(PsiSubstitutor.KEY), factory, languageLevel, resolveScope, new PairProcessor() { + @Override + public boolean process(PsiClass superClass, PsiSubstitutor finalSubstitutor) { + return processDeclarationsInClass(superClass, processor, state.put(PsiSubstitutor.KEY, finalSubstitutor), visited1, last, place, + languageLevel, isRaw, resolveScope); + } + }); } @Nullable @@ -739,23 +736,19 @@ public class PsiClassImplUtil { return ScopedClassHierarchy.getHierarchy(aClass, resolveScope).getImmediateSupersWithCapturing(); } - private static boolean processSuperTypes(@NotNull PsiClass aClass, - @NotNull PsiScopeProcessor processor, - @Nullable Set visited, - PsiElement last, - @NotNull PsiElement place, - @NotNull ResolveState state, - boolean isRaw, - @NotNull PsiElementFactory factory, - @NotNull LanguageLevel languageLevel, GlobalSearchScope resolveScope) { + static boolean processSuperTypes(@NotNull PsiClass aClass, + PsiSubstitutor substitutor, + @NotNull PsiElementFactory factory, + @NotNull LanguageLevel languageLevel, + GlobalSearchScope resolveScope, + PairProcessor processor) { boolean resolved = false; for (PsiClassType.ClassResolveResult superTypeResolveResult : getScopeCorrectedSuperTypes(aClass, resolveScope)) { PsiClass superClass = superTypeResolveResult.getElement(); assert superClass != null; PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superTypeResolveResult.getSubstitutor(), aClass, - state.get(PsiSubstitutor.KEY), factory, languageLevel); - if (!processDeclarationsInClass(superClass, processor, state.put(PsiSubstitutor.KEY, finalSubstitutor), visited, last, place, - languageLevel, isRaw, resolveScope)) { + substitutor, factory, languageLevel); + if (!processor.process(superClass, finalSubstitutor)) { resolved = true; } } @@ -986,11 +979,24 @@ public class PsiClassImplUtil { } return ret; } - Pair[] list = getMap(psiClass, MemberType.METHOD).get(name); - //noinspection unchecked - return list == null ? - Collections.>emptyList() : - Arrays.>asList((Pair[])list); + PsiMember[] list = getMap(psiClass, MemberType.METHOD).get(name); + if (list == null) return Collections.emptyList(); + return withSubstitutors(psiClass, list); + } + + @NotNull + private static List> withSubstitutors(@NotNull final PsiClass psiClass, PsiMember[] members) { + final ScopedClassHierarchy hierarchy = ScopedClassHierarchy.getHierarchy(psiClass, psiClass.getResolveScope()); + final LanguageLevel level = PsiUtil.getLanguageLevel(psiClass); + return ContainerUtil.map(members, new Function>() { + @Override + public Pair fun(PsiMember member) { + PsiClass containingClass = member.getContainingClass(); + PsiSubstitutor substitutor = containingClass == null ? null : hierarchy.getSuperMembersSubstitutor(containingClass, level); + //noinspection unchecked + return Pair.create((T)member, substitutor == null ? PsiSubstitutor.EMPTY : substitutor); + } + }); } @NotNull diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/ScopedClassHierarchy.java b/java/java-psi-impl/src/com/intellij/psi/impl/ScopedClassHierarchy.java index c8e8dece591d..3b9181141105 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/ScopedClassHierarchy.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/ScopedClassHierarchy.java @@ -18,6 +18,7 @@ package com.intellij.psi.impl; import com.intellij.openapi.util.RecursionGuard; import com.intellij.openapi.util.RecursionManager; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiSearchScopeUtil; @@ -25,8 +26,10 @@ import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.PairProcessor; import com.intellij.util.containers.ConcurrentFactoryMap; import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashMap; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -61,6 +64,14 @@ class ScopedClassHierarchy { private final GlobalSearchScope myResolveScope; private volatile Map mySupersWithSubstitutors; private volatile List myImmediateSupersWithCapturing; + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + private final Map> myAllSupersWithCapturing = new ConcurrentFactoryMap>() { + @Nullable + @Override + protected Map create(LanguageLevel key) { + return calcAllMemberSupers(key); + } + }; private ScopedClassHierarchy(PsiClass psiClass, GlobalSearchScope resolveScope) { myPlaceClass = psiClass; @@ -171,4 +182,26 @@ class ScopedClassHierarchy { } return list; } + + @NotNull + private Map calcAllMemberSupers(final LanguageLevel level) { + final Map map = ContainerUtil.newTroveMap(); + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(myPlaceClass.getProject()); + new PairProcessor() { + @Override + public boolean process(PsiClass eachClass, PsiSubstitutor eachSubstitutor) { + if (!map.containsKey(eachClass)) { + map.put(eachClass, eachSubstitutor); + PsiClassImplUtil.processSuperTypes(eachClass, eachSubstitutor, factory, level, myResolveScope, this); + } + return true; + } + }.process(myPlaceClass, PsiSubstitutor.EMPTY); + return map; + } + + @Nullable + PsiSubstitutor getSuperMembersSubstitutor(@NotNull PsiClass superClass, @NotNull LanguageLevel level) { + return myAllSupersWithCapturing.get(level).get(superClass); + } } From ecccb38c69d2a6ec1832ee8e9983e2c7f3a97ac2 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Apr 2016 11:04:34 +0200 Subject: [PATCH 10/26] vcs: show dialogs and perform write actions inside transactions --- .../com/intellij/dvcs/DvcsPlatformFacadeImpl.java | 9 ++------- .../src/git4idea/checkin/GitCheckinEnvironment.java | 10 +++------- .../src/git4idea/merge/GitConflictResolver.java | 12 +++++------- .../actions/AbstractShowPropertiesDiffAction.java | 5 ++--- 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/DvcsPlatformFacadeImpl.java b/platform/dvcs-impl/src/com/intellij/dvcs/DvcsPlatformFacadeImpl.java index fdc326812d19..697530bc2008 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/DvcsPlatformFacadeImpl.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/DvcsPlatformFacadeImpl.java @@ -20,6 +20,7 @@ import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.impl.LoadTextUtil; import com.intellij.openapi.project.Project; @@ -34,7 +35,6 @@ import com.intellij.openapi.vcs.changes.ChangeListManagerEx; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -115,12 +115,7 @@ public abstract class DvcsPlatformFacadeImpl implements DvcsPlatformFacade { @Override public void saveAllDocuments() { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - FileDocumentManager.getInstance().saveAllDocuments(); - } - }); + TransactionGuard.getInstance().submitTransactionAndWait(() -> FileDocumentManager.getInstance().saveAllDocuments()); } @NotNull diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java index 7b65d4bd05bb..67d8cccb001a 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java +++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java @@ -19,6 +19,7 @@ import com.intellij.CommonBundle; import com.intellij.dvcs.DvcsCommitAdditionalComponent; import com.intellij.dvcs.DvcsUtil; import com.intellij.dvcs.push.ui.VcsPushDialog; +import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -44,9 +45,7 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.textCompletion.DefaultTextCompletionValueDescriptor; import com.intellij.util.textCompletion.TextCompletionProvider; import com.intellij.util.textCompletion.TextFieldWithCompletion; -import com.intellij.util.textCompletion.ValuesCompletionProvider; import com.intellij.util.textCompletion.ValuesCompletionProvider.ValuesCompletionProviderDumbAware; -import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsUser; import com.intellij.vcs.log.VcsUserRegistry; @@ -227,11 +226,8 @@ public class GitCheckinEnvironment implements CheckinEnvironment { GitRepositoryManager manager = GitUtil.getRepositoryManager(myProject); Collection repositories = GitUtil.getRepositoriesFromRoots(manager, sortedChanges.keySet()); final List preselectedRepositories = ContainerUtil.newArrayList(repositories); - UIUtil.invokeLaterIfNeeded(new Runnable() { - public void run() { - new VcsPushDialog(myProject, preselectedRepositories, GitBranchUtil.getCurrentRepository(myProject)).show(); - } - }); + TransactionGuard.submitTransaction(myProject, () -> + new VcsPushDialog(myProject, preselectedRepositories, GitBranchUtil.getCurrentRepository(myProject)).show()); } return exceptions; } diff --git a/plugins/git4idea/src/git4idea/merge/GitConflictResolver.java b/plugins/git4idea/src/git4idea/merge/GitConflictResolver.java index d26a733e0b2d..3ccd55c6f55c 100644 --- a/plugins/git4idea/src/git4idea/merge/GitConflictResolver.java +++ b/plugins/git4idea/src/git4idea/merge/GitConflictResolver.java @@ -18,6 +18,7 @@ package git4idea.merge; import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -29,7 +30,6 @@ import com.intellij.openapi.vcs.merge.MergeProvider; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.UIUtil; import git4idea.GitPlatformFacade; import git4idea.GitUtil; import git4idea.GitVcs; @@ -224,12 +224,10 @@ public class GitConflictResolver { } private void showMergeDialog(final Collection initiallyUnmergedFiles) { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override public void run() { - final MergeProvider mergeProvider = myParams.reverse ? - new GitMergeProvider(myProject, true) : new GitMergeProvider(myProject, false); - myVcsHelper.showMergeDialog(new ArrayList(initiallyUnmergedFiles), mergeProvider, myParams.myMergeDialogCustomizer); - } + TransactionGuard.getInstance().submitTransactionAndWait(() -> { + final MergeProvider mergeProvider = myParams.reverse ? + new GitMergeProvider(myProject, true) : new GitMergeProvider(myProject, false); + myVcsHelper.showMergeDialog(new ArrayList(initiallyUnmergedFiles), mergeProvider, myParams.myMergeDialogCustomizer); }); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractShowPropertiesDiffAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractShowPropertiesDiffAction.java index bb4aeee00af8..cebef4909095 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractShowPropertiesDiffAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractShowPropertiesDiffAction.java @@ -17,6 +17,7 @@ package org.jetbrains.idea.svn.actions; import com.intellij.diff.DiffManager; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.progress.PerformInBackgroundOption; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -52,7 +53,6 @@ import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; -import javax.swing.*; import java.io.File; import java.util.ArrayList; import java.util.Collections; @@ -148,8 +148,7 @@ public abstract class AbstractShowPropertiesDiffAction extends AnAction implemen myException = exc; } - // since sometimes called from modal dialog (commit changes dialog) - SwingUtilities.invokeLater(new Runnable() { + TransactionGuard.submitTransaction(myProject, new Runnable() { public void run() { if (myException != null) { Messages.showErrorDialog(myException.getMessage(), myErrorTitle); From a7f0dcb0836e6d98aca7e6914913204ec86dba88 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 26 Apr 2016 11:56:52 +0200 Subject: [PATCH 11/26] [ui] tweaks desktop entry/launcher script configuration panels (IDEA-CR-10358) --- .../application/options/InitialConfigurationDialog.java | 8 ++++++++ .../intellij/ide/customize/CustomizeDesktopEntryStep.java | 1 + .../ide/customize/CustomizeLauncherScriptStep.java | 1 + 3 files changed, 10 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/application/options/InitialConfigurationDialog.java b/platform/lang-impl/src/com/intellij/application/options/InitialConfigurationDialog.java index 7fad0acfd1eb..dbc803f281e5 100644 --- a/platform/lang-impl/src/com/intellij/application/options/InitialConfigurationDialog.java +++ b/platform/lang-impl/src/com/intellij/application/options/InitialConfigurationDialog.java @@ -164,15 +164,23 @@ public class InitialConfigurationDialog extends DialogWrapper { final boolean canCreateLauncherScript = canCreateLauncherScript(); myCreateScriptPanel.setVisible(canCreateLauncherScript); + myCreateScriptCheckbox.setVisible(canCreateLauncherScript); myCreateScriptCheckbox.setSelected(false); if (canCreateLauncherScript) { myScriptPathTextField.setText(CreateLauncherScriptAction.defaultScriptPath()); + myScriptPathTextField.setEnabled(false); + myCreateScriptCheckbox.addChangeListener(e -> myScriptPathTextField.setEnabled(myCreateScriptCheckbox.isSelected())); } final boolean canCreateDesktopEntry = canCreateDesktopEntry(); myCreateEntryPanel.setVisible(canCreateDesktopEntry); + myCreateEntryCheckBox.setVisible(canCreateDesktopEntry); myCreateEntryCheckBox.setSelected(canCreateDesktopEntry); myGlobalEntryCheckBox.setSelected(false); + if (canCreateDesktopEntry) { + myGlobalEntryCheckBox.setEnabled(true); + myCreateEntryCheckBox.addChangeListener(e -> myGlobalEntryCheckBox.setEnabled(myCreateEntryCheckBox.isSelected())); + } myPreferencesLabel.setText("You can use " + CommonBundle.settingsActionPath() + " to configure any of these settings later."); diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeDesktopEntryStep.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeDesktopEntryStep.java index 97996df5e4ec..c637bb73251b 100644 --- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeDesktopEntryStep.java +++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeDesktopEntryStep.java @@ -68,6 +68,7 @@ public class CustomizeDesktopEntryStep extends AbstractCustomizeWizardStep { myCreateEntryCheckBox.setSelected(!"true".equals(System.getProperty("idea.debug.mode"))); myGlobalEntryCheckBox.setSelected(false); + myGlobalEntryCheckBox.setEnabled(myCreateEntryCheckBox.isSelected()); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeLauncherScriptStep.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeLauncherScriptStep.java index b1efc0596173..0cf41f15057e 100644 --- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeLauncherScriptStep.java +++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeLauncherScriptStep.java @@ -40,6 +40,7 @@ public class CustomizeLauncherScriptStep extends AbstractCustomizeWizardStep { myCreateScriptCheckBox.setSelected(false); myCreateScriptCheckBox.addChangeListener(e -> myScriptPathTextField.setEnabled(myCreateScriptCheckBox.isSelected())); + myScriptPathTextField.setEnabled(false); myScriptPathTextField.setText(CreateLauncherScriptAction.defaultScriptPath()); JPanel content = new JPanel(createSmallBorderLayout()); From 0e36e294e6b32be53647efda71753febac001c7a Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 26 Apr 2016 12:20:12 +0200 Subject: [PATCH 12/26] Cleanup (formatting) --- .../intellij/openapi/application/impl/ApplicationImpl.java | 3 +-- .../testSrc/com/intellij/ide/LocatorTest.java | 7 ++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index 71a6370004f0..857297f0a23b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -454,11 +454,10 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } @Override - protected void createComponents(@Nullable final ProgressIndicator indicator) { + protected void createComponents(@Nullable ProgressIndicator indicator) { // we cannot wrap "init()" call because ProgressManager instance could be created only after component registration (our "componentsRegistered" callback) Runnable task = () -> ApplicationImpl.super.createComponents(indicator); - if (indicator == null) { // no splash, no need to to use progress manager task.run(); diff --git a/platform/platform-tests/testSrc/com/intellij/ide/LocatorTest.java b/platform/platform-tests/testSrc/com/intellij/ide/LocatorTest.java index 7591970e4405..57a4fcbe13e7 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/LocatorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/ide/LocatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,9 +23,10 @@ import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.testFramework.PlatformTestCase; import java.io.File; +import java.io.IOException; public class LocatorTest extends PlatformTestCase { - public void test() throws Exception { + public void test() throws IOException { File locatorFile = new File(PathManager.getSystemPath() + "/" + ApplicationEx.LOCATOR_FILE_NAME); assertTrue("doesn't exist: " + locatorFile.getPath(), locatorFile.exists()); assertTrue("can't read: " + locatorFile.getPath(), locatorFile.canRead()); @@ -35,4 +36,4 @@ public class LocatorTest extends PlatformTestCase { assertEquals(home, PathManager.getHomePath()); } -} +} \ No newline at end of file From 588273e36ab60db8192b35a7599951a7c720f662 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Tue, 26 Apr 2016 13:21:40 +0300 Subject: [PATCH 13/26] cleanup yellow code, add toString for easier debugging, javadoc --- .../configuration/EnvironmentVariablesComponent.java | 6 ++++++ .../execution/configuration/EnvironmentVariablesData.java | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java b/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java index adbb73406e86..9f05946926fc 100644 --- a/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java +++ b/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java @@ -75,6 +75,9 @@ public class EnvironmentVariablesComponent extends LabeledComponent envs) { final Element envsElement = element.getChild(ENVS); if (envsElement != null) { @@ -108,6 +111,9 @@ public class EnvironmentVariablesComponent extends LabeledComponent envs) { final Element envsElement = new Element(ENVS); for (String envName : envs.keySet()) { diff --git a/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesData.java b/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesData.java index b52e1046487c..690567281961 100644 --- a/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesData.java +++ b/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesData.java @@ -35,7 +35,7 @@ import java.util.Map; */ public class EnvironmentVariablesData { - public static final EnvironmentVariablesData DEFAULT = new EnvironmentVariablesData(ImmutableMap.of(), true); + public static final EnvironmentVariablesData DEFAULT = new EnvironmentVariablesData(ImmutableMap.of(), true); @NonNls private static final String ENVS = "envs"; @NonNls private static final String PASS_PARENT_ENVS = "pass-parent-envs"; @NonNls private static final String ENV = EnvironmentVariablesComponent.ENV; @@ -77,6 +77,11 @@ public class EnvironmentVariablesData { return result; } + @Override + public String toString() { + return "envs=" + myEnvs + ", passParentEnvs=" + myPassParentEnvs; + } + @NotNull public static EnvironmentVariablesData readExternal(@NotNull Element element) { Element envsElement = element.getChild(ENVS); From 54f460c16f5f2f6b76581d6e839d08acd8c04a5a Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 26 Apr 2016 12:35:43 +0300 Subject: [PATCH 14/26] diff: replace EmptyAction.setupAction with ActionUtil.copyFrom EmptyAction.setupAction has a complex semantics, that is unnecesary in these cases --- .../com/intellij/diff/actions/ProxyUndoRedoAction.java | 8 +++++--- .../diff/actions/impl/FocusOppositePaneAction.java | 4 ++-- .../intellij/diff/actions/impl/GoToChangePopupAction.java | 4 ++-- .../com/intellij/diff/actions/impl/NextChangeAction.java | 4 ++-- .../intellij/diff/actions/impl/NextDifferenceAction.java | 4 ++-- .../intellij/diff/actions/impl/OpenInEditorAction.java | 4 ++-- .../com/intellij/diff/actions/impl/PrevChangeAction.java | 4 ++-- .../intellij/diff/actions/impl/PrevDifferenceAction.java | 4 ++-- .../diff/actions/impl/SetEditorSettingsAction.java | 3 ++- .../src/com/intellij/diff/impl/DiffRequestProcessor.java | 4 ++-- .../src/com/intellij/diff/merge/TextMergeViewer.java | 5 +++-- .../diff/tools/simple/ThreesideTextDiffViewerEx.java | 6 +++--- .../openapi/diff/impl/dir/actions/EnableEqual.java | 4 ++-- .../openapi/diff/impl/dir/actions/EnableLeft.java | 4 ++-- .../openapi/diff/impl/dir/actions/EnableNotEqual.java | 4 ++-- .../openapi/diff/impl/dir/actions/EnableRight.java | 4 ++-- .../openapi/vcs/actions/AnnotateDiffViewerAction.java | 4 ++-- .../org/jetbrains/idea/svn/difftool/SvnDiffViewer.java | 8 ++++++-- 18 files changed, 45 insertions(+), 37 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/actions/ProxyUndoRedoAction.java b/platform/diff-impl/src/com/intellij/diff/actions/ProxyUndoRedoAction.java index 1e7a30f62c59..7d0cfa41aaf1 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/ProxyUndoRedoAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/ProxyUndoRedoAction.java @@ -15,9 +15,10 @@ */ package com.intellij.diff.actions; +import com.intellij.diff.util.DiffUtil; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.EmptyAction; import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.TextEditor; @@ -35,6 +36,7 @@ public class ProxyUndoRedoAction extends DumbAwareAction { private final boolean myUndo; private ProxyUndoRedoAction(@NotNull UndoManager manager, @NotNull TextEditor editor, boolean undo) { + ActionUtil.copyFrom(this, undo ? IdeActions.ACTION_UNDO : IdeActions.ACTION_REDO); myUndoManager = manager; myEditor = editor; myUndo = undo; @@ -44,8 +46,8 @@ public class ProxyUndoRedoAction extends DumbAwareAction { UndoManager undoManager = project != null ? UndoManager.getInstance(project) : UndoManager.getGlobalInstance(); TextEditor textEditor = TextEditorProvider.getInstance().getTextEditor(editor); if (undoManager != null) { - EmptyAction.setupAction(new ProxyUndoRedoAction(undoManager, textEditor, true), IdeActions.ACTION_UNDO, component); - EmptyAction.setupAction(new ProxyUndoRedoAction(undoManager, textEditor, false), IdeActions.ACTION_REDO, component); + DiffUtil.registerAction(new ProxyUndoRedoAction(undoManager, textEditor, true), component); + DiffUtil.registerAction(new ProxyUndoRedoAction(undoManager, textEditor, false), component); } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java b/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java index b36ceee60582..e7a7e7ea9ec7 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java @@ -17,7 +17,7 @@ package com.intellij.diff.actions.impl; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.EmptyAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.project.DumbAware; import org.jetbrains.annotations.NotNull; @@ -34,7 +34,7 @@ public class FocusOppositePaneAction extends AnAction implements DumbAware { myScrollToPosition = scrollToPosition; setEnabledInModalContext(true); - EmptyAction.setupAction(this, getActionId(), null); + ActionUtil.copyFrom(this, getActionId()); } @Override diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/GoToChangePopupAction.java b/platform/diff-impl/src/com/intellij/diff/actions/impl/GoToChangePopupAction.java index 24e3cdef10ea..05a7c2cee916 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/GoToChangePopupAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/GoToChangePopupAction.java @@ -16,12 +16,12 @@ package com.intellij.diff.actions.impl; import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.EmptyAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.project.DumbAware; public abstract class GoToChangePopupAction extends AnAction implements DumbAware { public GoToChangePopupAction() { setEnabledInModalContext(true); - EmptyAction.setupAction(this, "GotoChangedFile", null); + ActionUtil.copyFrom(this, "GotoChangedFile"); } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/NextChangeAction.java b/platform/diff-impl/src/com/intellij/diff/actions/impl/NextChangeAction.java index 47234254286a..d6b44b503865 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/NextChangeAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/NextChangeAction.java @@ -16,12 +16,12 @@ package com.intellij.diff.actions.impl; import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.EmptyAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.project.DumbAware; public abstract class NextChangeAction extends AnAction implements DumbAware { public NextChangeAction() { setEnabledInModalContext(true); - EmptyAction.setupAction(this, "Diff.NextChange", null); + ActionUtil.copyFrom(this, "Diff.NextChange"); } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/NextDifferenceAction.java b/platform/diff-impl/src/com/intellij/diff/actions/impl/NextDifferenceAction.java index e3bde5ffe421..c27d3dcc24f9 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/NextDifferenceAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/NextDifferenceAction.java @@ -16,13 +16,13 @@ package com.intellij.diff.actions.impl; import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.EmptyAction; import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.project.DumbAware; public abstract class NextDifferenceAction extends AnAction implements DumbAware { public NextDifferenceAction() { setEnabledInModalContext(true); - EmptyAction.setupAction(this, IdeActions.ACTION_NEXT_DIFF, null); + ActionUtil.copyFrom(this, IdeActions.ACTION_NEXT_DIFF); } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/OpenInEditorAction.java b/platform/diff-impl/src/com/intellij/diff/actions/impl/OpenInEditorAction.java index 77dd3971d772..eac40c7011e8 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/OpenInEditorAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/OpenInEditorAction.java @@ -24,7 +24,7 @@ import com.intellij.ide.actions.EditSourceAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.DataKey; -import com.intellij.openapi.actionSystem.EmptyAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.DumbAware; @@ -38,7 +38,7 @@ public class OpenInEditorAction extends EditSourceAction implements DumbAware { @Nullable private final Runnable myAfterRunnable; public OpenInEditorAction(@Nullable Runnable afterRunnable) { - EmptyAction.setupAction(this, "EditSource", null); + ActionUtil.copyFrom(this, "EditSource"); myAfterRunnable = afterRunnable; } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/PrevChangeAction.java b/platform/diff-impl/src/com/intellij/diff/actions/impl/PrevChangeAction.java index c2b1970c0f02..04eacf2949a1 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/PrevChangeAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/PrevChangeAction.java @@ -16,12 +16,12 @@ package com.intellij.diff.actions.impl; import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.EmptyAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.project.DumbAware; public abstract class PrevChangeAction extends AnAction implements DumbAware { public PrevChangeAction() { setEnabledInModalContext(true); - EmptyAction.setupAction(this, "Diff.PrevChange", null); + ActionUtil.copyFrom(this, "Diff.PrevChange"); } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/PrevDifferenceAction.java b/platform/diff-impl/src/com/intellij/diff/actions/impl/PrevDifferenceAction.java index a799fc1befe1..101d8a270038 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/PrevDifferenceAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/PrevDifferenceAction.java @@ -16,13 +16,13 @@ package com.intellij.diff.actions.impl; import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.EmptyAction; import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.project.DumbAware; public abstract class PrevDifferenceAction extends AnAction implements DumbAware { public PrevDifferenceAction() { setEnabledInModalContext(true); - EmptyAction.setupAction(this, IdeActions.ACTION_PREVIOUS_DIFF, null); + ActionUtil.copyFrom(this, IdeActions.ACTION_PREVIOUS_DIFF); } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/SetEditorSettingsAction.java b/platform/diff-impl/src/com/intellij/diff/actions/impl/SetEditorSettingsAction.java index f691ce2308a9..a318bb6c2932 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/SetEditorSettingsAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/SetEditorSettingsAction.java @@ -19,6 +19,7 @@ import com.intellij.diff.tools.util.base.HighlightingLevel; import com.intellij.diff.tools.util.base.TextDiffSettingsHolder; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.EditorGutterComponentEx; import com.intellij.openapi.editor.impl.EditorImpl; @@ -159,7 +160,7 @@ public class SetEditorSettingsAction extends ActionGroup implements DumbAware { private abstract class EditorSettingToggleAction extends ToggleAction implements DumbAware, EditorSettingAction { private EditorSettingToggleAction(@NotNull String actionId) { - EmptyAction.setupAction(this, actionId, null); + ActionUtil.copyFrom(this, actionId); } @Override diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java b/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java index 47b561534aaa..def1fb25b190 100644 --- a/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java +++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java @@ -510,7 +510,7 @@ public abstract class DiffRequestProcessor implements Disposable { private class ShowInExternalToolAction extends DumbAwareAction { public ShowInExternalToolAction() { - EmptyAction.setupAction(this, "Diff.ShowInExternalTool", null); + ActionUtil.copyFrom(this, "Diff.ShowInExternalTool"); } @Override @@ -595,7 +595,7 @@ public abstract class DiffRequestProcessor implements Disposable { private class ShowActionGroupPopupAction extends DumbAwareAction { public ShowActionGroupPopupAction() { - EmptyAction.setupAction(this, "Diff.ShowSettingsPopup", null); + ActionUtil.copyFrom(this, "Diff.ShowSettingsPopup"); } @Override diff --git a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java index f6a2c08a8041..6f92f447ac2a 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java @@ -35,6 +35,7 @@ import com.intellij.diff.tools.util.base.TextDiffViewerUtil; import com.intellij.diff.util.*; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ReadAction; @@ -1161,7 +1162,7 @@ public class TextMergeViewer implements MergeTool.MergeViewer { public IgnoreSelectedChangesSideAction(@NotNull Side side, boolean shortcut) { super(shortcut); mySide = side; - EmptyAction.setupAction(this, mySide.select("Diff.IgnoreLeftSide", "Diff.IgnoreRightSide"), null); + ActionUtil.copyFrom(this, mySide.select("Diff.IgnoreLeftSide", "Diff.IgnoreRightSide")); } @Override @@ -1222,7 +1223,7 @@ public class TextMergeViewer implements MergeTool.MergeViewer { public ApplySelectedChangesAction(@NotNull Side side, boolean shortcut) { super(shortcut); mySide = side; - EmptyAction.setupAction(this, mySide.select("Diff.ApplyLeftSide", "Diff.ApplyRightSide"), null); + ActionUtil.copyFrom(this, mySide.select("Diff.ApplyLeftSide", "Diff.ApplyRightSide")); } @Override diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/ThreesideTextDiffViewerEx.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/ThreesideTextDiffViewerEx.java index 54d9377643c7..55a7e366f68b 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/ThreesideTextDiffViewerEx.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/ThreesideTextDiffViewerEx.java @@ -26,7 +26,7 @@ import com.intellij.diff.util.DiffDividerDrawUtil.DividerPaintable; import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.EmptyAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.DiffBundle; import com.intellij.openapi.editor.Editor; @@ -266,7 +266,7 @@ public abstract class ThreesideTextDiffViewerEx extends ThreesideTextDiffViewer private class PrevConflictAction extends DumbAwareAction { public PrevConflictAction() { - EmptyAction.setupAction(this, "Diff.PreviousConflict", null); + ActionUtil.copyFrom(this, "Diff.PreviousConflict"); } @Override @@ -278,7 +278,7 @@ public abstract class ThreesideTextDiffViewerEx extends ThreesideTextDiffViewer private class NextConflictAction extends DumbAwareAction { public NextConflictAction() { - EmptyAction.setupAction(this, "Diff.NextConflict", null); + ActionUtil.copyFrom(this, "Diff.NextConflict"); } @Override diff --git a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableEqual.java b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableEqual.java index b12a8709b0df..15c1e7e2cf09 100644 --- a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableEqual.java +++ b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableEqual.java @@ -16,7 +16,7 @@ package com.intellij.openapi.diff.impl.dir.actions; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.EmptyAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.diff.impl.dir.DirDiffTableModel; /** @@ -25,7 +25,7 @@ import com.intellij.openapi.diff.impl.dir.DirDiffTableModel; public class EnableEqual extends DirDiffAction { public EnableEqual(DirDiffTableModel model) { super(model); - EmptyAction.setupAction(this, "DirDiffMenu.EnableEqual", null); + ActionUtil.copyFrom(this, "DirDiffMenu.EnableEqual"); } @Override diff --git a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableLeft.java b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableLeft.java index b735215cbd7d..30ee758ebd55 100644 --- a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableLeft.java +++ b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableLeft.java @@ -16,7 +16,7 @@ package com.intellij.openapi.diff.impl.dir.actions; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.EmptyAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.diff.impl.dir.DirDiffTableModel; /** @@ -25,7 +25,7 @@ import com.intellij.openapi.diff.impl.dir.DirDiffTableModel; public class EnableLeft extends DirDiffAction { protected EnableLeft(DirDiffTableModel model) { super(model); - EmptyAction.setupAction(this, "DirDiffMenu.EnableLeft", null); + ActionUtil.copyFrom(this, "DirDiffMenu.EnableLeft"); } @Override diff --git a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableNotEqual.java b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableNotEqual.java index 5057eb65476a..9eb7db82326b 100644 --- a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableNotEqual.java +++ b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableNotEqual.java @@ -16,7 +16,7 @@ package com.intellij.openapi.diff.impl.dir.actions; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.EmptyAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.diff.impl.dir.DirDiffTableModel; /** @@ -25,7 +25,7 @@ import com.intellij.openapi.diff.impl.dir.DirDiffTableModel; public class EnableNotEqual extends DirDiffAction { protected EnableNotEqual(DirDiffTableModel model) { super(model); - EmptyAction.setupAction(this, "DirDiffMenu.EnableNotEqual", null); + ActionUtil.copyFrom(this, "DirDiffMenu.EnableNotEqual"); } @Override diff --git a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableRight.java b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableRight.java index 0e6830f307fc..0bb69f6d6ac3 100644 --- a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableRight.java +++ b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/actions/EnableRight.java @@ -16,7 +16,7 @@ package com.intellij.openapi.diff.impl.dir.actions; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.EmptyAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.diff.impl.dir.DirDiffTableModel; /** @@ -25,7 +25,7 @@ import com.intellij.openapi.diff.impl.dir.DirDiffTableModel; public class EnableRight extends DirDiffAction { protected EnableRight(DirDiffTableModel model) { super(model); - EmptyAction.setupAction(this, "DirDiffMenu.EnableRight", null); + ActionUtil.copyFrom(this, "DirDiffMenu.EnableRight"); } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java index 6af228909dfe..000b421b1021 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java @@ -35,8 +35,8 @@ import com.intellij.notification.NotificationType; import com.intellij.notification.impl.NotificationsManagerImpl; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.EmptyAction; import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; @@ -86,7 +86,7 @@ public class AnnotateDiffViewerAction extends ToggleAction implements DumbAware }; public AnnotateDiffViewerAction() { - EmptyAction.setupAction(this, "Annotate", null); + ActionUtil.copyFrom(this, "Annotate"); setEnabledInModalContext(true); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnDiffViewer.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnDiffViewer.java index ccce9564be54..47a9ea531469 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnDiffViewer.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnDiffViewer.java @@ -11,7 +11,11 @@ import com.intellij.diff.tools.ErrorDiffTool; import com.intellij.diff.util.DiffUtil; import com.intellij.ide.DataManager; import com.intellij.ide.impl.DataManagerImpl; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; @@ -295,7 +299,7 @@ public class SvnDiffViewer implements DiffViewer { private class ToggleHidePropertiesAction extends ToggleAction implements DumbAware { public ToggleHidePropertiesAction() { - EmptyAction.setupAction(this, "Subversion.TogglePropertiesDiff", null); + ActionUtil.copyFrom(this, "Subversion.TogglePropertiesDiff"); } @Override From 57c6cf695921559fd6e8d0fb5c6d908be39c4eef Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 26 Apr 2016 12:46:06 +0300 Subject: [PATCH 15/26] lst: replace EmptyAction.setupAction with ActionUtil.copyFrom EmptyAction.setupAction has a complex semantics, that is unnecesary in these cases --- .../openapi/vcs/actions/ShowChangeMarkerAction.java | 10 +++++----- .../vcs/actions/ShowNextChangeMarkerAction.java | 9 ++++----- .../vcs/actions/ShowPrevChangeMarkerAction.java | 7 ++++--- .../openapi/vcs/ex/BaseLineStatusRangeAction.java | 8 +------- .../openapi/vcs/ex/CopyLineStatusRangeAction.java | 10 ++++------ .../openapi/vcs/ex/LineStatusTrackerDrawing.java | 11 ++++++----- .../openapi/vcs/ex/RollbackLineStatusRangeAction.java | 3 +++ .../openapi/vcs/ex/ShowLineStatusRangeDiffAction.java | 5 +++-- 8 files changed, 30 insertions(+), 33 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowChangeMarkerAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowChangeMarkerAction.java index 954d1bc6abf2..2aecdd676040 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowChangeMarkerAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowChangeMarkerAction.java @@ -55,11 +55,6 @@ public abstract class ShowChangeMarkerAction extends AbstractVcsAction { }; } - @Override - protected boolean forceSyncUpdate(final AnActionEvent e) { - return true; - } - public ShowChangeMarkerAction() { myChangeMarkerContext = new ChangeMarkerContext() { @Override @@ -118,6 +113,11 @@ public abstract class ShowChangeMarkerAction extends AbstractVcsAction { LineStatusTrackerDrawing.moveToRange(range, editor, lineStatusTracker); } + @Override + protected boolean forceSyncUpdate(final AnActionEvent e) { + return true; + } + protected interface ChangeMarkerContext { Range getRange(VcsContext dataContext); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowNextChangeMarkerAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowNextChangeMarkerAction.java index 653f77e9c606..450802008200 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowNextChangeMarkerAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowNextChangeMarkerAction.java @@ -15,24 +15,23 @@ */ package com.intellij.openapi.vcs.actions; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.vcs.ex.LineStatusTracker; import com.intellij.openapi.vcs.ex.Range; -/** - * author: lesya - */ public class ShowNextChangeMarkerAction extends ShowChangeMarkerAction { - public ShowNextChangeMarkerAction(final Range range, final LineStatusTracker lineStatusTracker, final Editor editor) { super(range, lineStatusTracker, editor); + ActionUtil.copyFrom(this, "VcsShowNextChangeMarker"); } + @SuppressWarnings("unused") public ShowNextChangeMarkerAction() { + super(); } protected Range extractRange(LineStatusTracker lineStatusTracker, int line, Editor editor) { return lineStatusTracker.getNextRange(line); } - } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowPrevChangeMarkerAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowPrevChangeMarkerAction.java index d6b954416c7d..400cb985e6b6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowPrevChangeMarkerAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/ShowPrevChangeMarkerAction.java @@ -15,19 +15,20 @@ */ package com.intellij.openapi.vcs.actions; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.vcs.ex.LineStatusTracker; import com.intellij.openapi.vcs.ex.Range; -/** - * author: lesya - */ public class ShowPrevChangeMarkerAction extends ShowChangeMarkerAction { public ShowPrevChangeMarkerAction(final Range range, final LineStatusTracker lineStatusTracker, final Editor editor) { super(range, lineStatusTracker, editor); + ActionUtil.copyFrom(this, "VcsShowPrevChangeMarker"); } + @SuppressWarnings("unused") public ShowPrevChangeMarkerAction() { + super(); } protected Range extractRange(LineStatusTracker lineStatusTracker, int line, Editor editor) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/BaseLineStatusRangeAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/BaseLineStatusRangeAction.java index 1ee057e3fa26..7635f7168cf8 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/BaseLineStatusRangeAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/BaseLineStatusRangeAction.java @@ -19,17 +19,11 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.DumbAware; -import javax.swing.*; - -/** -* @author irengrig -*/ public abstract class BaseLineStatusRangeAction extends AnAction implements DumbAware { protected final LineStatusTracker myLineStatusTracker; protected final Range myRange; - BaseLineStatusRangeAction(final String text, final Icon icon, final LineStatusTracker lineStatusTracker, final Range range) { - super(text, null, icon); + BaseLineStatusRangeAction(final LineStatusTracker lineStatusTracker, final Range range) { myLineStatusTracker = lineStatusTracker; myRange = range; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/CopyLineStatusRangeAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/CopyLineStatusRangeAction.java index eb008f12aedf..3adfaf9640f2 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/CopyLineStatusRangeAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/CopyLineStatusRangeAction.java @@ -16,18 +16,16 @@ package com.intellij.openapi.vcs.ex; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.ide.CopyPasteManager; -import com.intellij.openapi.vcs.VcsBundle; -import com.intellij.util.PlatformIcons; import java.awt.datatransfer.StringSelection; -/** -* @author irengrig -*/ public class CopyLineStatusRangeAction extends BaseLineStatusRangeAction { CopyLineStatusRangeAction(final LineStatusTracker lineStatusTracker, final Range range) { - super(VcsBundle.message("action.name.copy.old.text"), PlatformIcons.COPY_ICON, lineStatusTracker, range); + super(lineStatusTracker, range); + ActionUtil.copyFrom(this, IdeActions.ACTION_COPY); } public boolean isEnabled() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java index 45892fece625..70907acef94a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs.ex; +import com.intellij.diff.util.DiffUtil; import com.intellij.icons.AllIcons; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; @@ -80,11 +81,11 @@ public class LineStatusTrackerDrawing { group.add(toggleWordDiff); JComponent editorComponent = myEditor.getComponent(); - EmptyAction.setupAction(localShowPrevAction, "VcsShowPrevChangeMarker", editorComponent); - EmptyAction.setupAction(localShowNextAction, "VcsShowNextChangeMarker", editorComponent); - EmptyAction.setupAction(rollback, IdeActions.SELECTED_CHANGES_ROLLBACK, editorComponent); - EmptyAction.setupAction(showDiff, "ChangesView.Diff", editorComponent); - EmptyAction.setupAction(copyRange, IdeActions.ACTION_COPY, editorComponent); + DiffUtil.registerAction(localShowPrevAction, editorComponent); + DiffUtil.registerAction(localShowNextAction, editorComponent); + DiffUtil.registerAction(rollback, editorComponent); + DiffUtil.registerAction(showDiff, editorComponent); + DiffUtil.registerAction(copyRange, editorComponent); final List actionList = ActionUtil.getActions(editorComponent); Disposer.register(parentDisposable, new Disposable() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusRangeAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusRangeAction.java index 7f71900654b6..980a3883459e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusRangeAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusRangeAction.java @@ -13,6 +13,8 @@ package com.intellij.openapi.vcs.ex; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.editor.Editor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,6 +25,7 @@ public class RollbackLineStatusRangeAction extends RollbackLineStatusAction { @NotNull private final Range myRange; public RollbackLineStatusRangeAction(@NotNull LineStatusTracker tracker, @NotNull Range range, @Nullable Editor editor) { + ActionUtil.copyFrom(this, IdeActions.SELECTED_CHANGES_ROLLBACK); myTracker = tracker; myEditor = editor; myRange = range; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java index 67ba09038d7f..a2fec889aed5 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java @@ -22,8 +22,8 @@ import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.DocumentContent; import com.intellij.diff.requests.DiffRequest; import com.intellij.diff.requests.SimpleDiffRequest; -import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; @@ -35,7 +35,8 @@ import org.jetbrains.annotations.Nullable; public class ShowLineStatusRangeDiffAction extends BaseLineStatusRangeAction { public ShowLineStatusRangeDiffAction(@NotNull LineStatusTracker lineStatusTracker, @NotNull Range range, @Nullable Editor editor) { - super(VcsBundle.message("action.name.show.difference"), AllIcons.Actions.Diff, lineStatusTracker, range); + super(lineStatusTracker, range); + ActionUtil.copyFrom(this, "ChangesView.Diff"); } @Override From a3c945258811d270dabdd674841a622b99efb024 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 26 Apr 2016 12:49:17 +0300 Subject: [PATCH 16/26] vcs: replace EmptyAction.setupAction with ActionUtil.copyFrom EmptyAction.setupAction has a complex semantics, that is unnecesary in these cases --- .../openapi/vcs/changes/actions/RollbackDialogAction.java | 7 +++---- .../openapi/vcs/changes/ui/ChangesBrowserBase.java | 4 +++- .../openapi/vcs/changes/ui/MultipleChangeListBrowser.java | 2 +- .../src/git4idea/ui/ChangesBrowserWithRollback.java | 4 +--- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/RollbackDialogAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/RollbackDialogAction.java index 288a0764ba76..dea319cf2b73 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/RollbackDialogAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/RollbackDialogAction.java @@ -15,14 +15,14 @@ */ package com.intellij.openapi.vcs.changes.actions; -import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ui.ChangesBrowserBase; @@ -36,8 +36,7 @@ import java.util.Arrays; */ public class RollbackDialogAction extends AnAction implements DumbAware { public RollbackDialogAction() { - super(VcsBundle.message("changes.action.rollback.text"), VcsBundle.message("changes.action.rollback.description"), - AllIcons.Actions.Rollback); + ActionUtil.copyFrom(this, IdeActions.CHANGES_VIEW_ROLLBACK); } public void actionPerformed(AnActionEvent e) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserBase.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserBase.java index 0c11fefc7a24..25c50de9e7f0 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserBase.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserBase.java @@ -20,6 +20,7 @@ import com.intellij.diff.util.DiffUserDataKeysEx; import com.intellij.ide.DeleteProvider; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.actionSystem.ex.CheckboxAction; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; @@ -369,7 +370,8 @@ public abstract class ChangesBrowserBase extends JPanel implements TypeSafeDa showDiff(); } }; - EmptyAction.setupAction(myDiffAction, "ChangesView.Diff", myViewer); + ActionUtil.copyFrom(myDiffAction, "ChangesView.Diff"); + myDiffAction.registerCustomShortcutSet(myViewer, null); toolBarGroup.add(myDiffAction); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/MultipleChangeListBrowser.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/MultipleChangeListBrowser.java index d9739569d1c8..4322039608b8 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/MultipleChangeListBrowser.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/MultipleChangeListBrowser.java @@ -324,7 +324,7 @@ public class MultipleChangeListBrowser extends ChangesBrowserBase { EmptyAction.registerWithShortcutSet(IdeActions.MOVE_TO_ANOTHER_CHANGE_LIST, CommonShortcuts.getMove(), myViewer); RollbackDialogAction rollback = new RollbackDialogAction(); - EmptyAction.setupAction(rollback, IdeActions.CHANGES_VIEW_ROLLBACK, this); + rollback.registerCustomShortcutSet(this, null); toolBarGroup.add(rollback); EditSourceForDialogAction editSourceAction = new EditSourceForDialogAction(this); diff --git a/plugins/git4idea/src/git4idea/ui/ChangesBrowserWithRollback.java b/plugins/git4idea/src/git4idea/ui/ChangesBrowserWithRollback.java index a33a7d13704a..e8deea22b86e 100644 --- a/plugins/git4idea/src/git4idea/ui/ChangesBrowserWithRollback.java +++ b/plugins/git4idea/src/git4idea/ui/ChangesBrowserWithRollback.java @@ -15,8 +15,6 @@ */ package git4idea.ui; -import com.intellij.openapi.actionSystem.EmptyAction; -import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vcs.changes.Change; @@ -41,7 +39,7 @@ public class ChangesBrowserWithRollback extends ChangesBrowser { super(project, null, changes, null, false, true, null, MyUseCase.LOCAL_CHANGES, null); myOriginalChanges = changes; RollbackDialogAction rollback = new RollbackDialogAction(); - EmptyAction.setupAction(rollback, IdeActions.CHANGES_VIEW_ROLLBACK, this); + rollback.registerCustomShortcutSet(this, null); addToolbarAction(rollback); setChangesToDisplay(changes); } From 62f9f421598a0d12a3902c7c759023b99bd49ac2 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Tue, 26 Apr 2016 13:45:52 +0300 Subject: [PATCH 17/26] more attributes generation with context --- .../codeInsight/intentions/XmlChooseColorIntentionAction.java | 2 +- .../htmlInspections/AddAttributeValueIntentionFix.java | 2 +- .../impl/source/tree/injected/XmlAttributeLiteralEscaper.java | 2 +- .../src/com/intellij/psi/impl/source/xml/XmlAttributeImpl.java | 2 +- .../com/intellij/psi/impl/source/xml/XmlAttributeValueImpl.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/xml/impl/src/com/intellij/codeInsight/intentions/XmlChooseColorIntentionAction.java b/xml/impl/src/com/intellij/codeInsight/intentions/XmlChooseColorIntentionAction.java index fe2e560cd2e5..2ccfea7fce21 100644 --- a/xml/impl/src/com/intellij/codeInsight/intentions/XmlChooseColorIntentionAction.java +++ b/xml/impl/src/com/intellij/codeInsight/intentions/XmlChooseColorIntentionAction.java @@ -82,7 +82,7 @@ public class XmlChooseColorIntentionAction extends PsiElementBaseIntentionAction if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return; final String newText = "#" + ColorUtil.toHex(color); final PsiManager manager = literal.getManager(); - final XmlAttribute newAttribute = XmlElementFactory.getInstance(manager.getProject()).createXmlAttribute("name", newText); + final XmlAttribute newAttribute = XmlElementFactory.getInstance(manager.getProject()).createAttribute("name", newText, element); final Runnable replaceRunnable = new Runnable() { @Override public void run() { diff --git a/xml/impl/src/com/intellij/codeInspection/htmlInspections/AddAttributeValueIntentionFix.java b/xml/impl/src/com/intellij/codeInspection/htmlInspections/AddAttributeValueIntentionFix.java index 500fdc4f4c8b..ace46d5af102 100644 --- a/xml/impl/src/com/intellij/codeInspection/htmlInspections/AddAttributeValueIntentionFix.java +++ b/xml/impl/src/com/intellij/codeInspection/htmlInspections/AddAttributeValueIntentionFix.java @@ -68,7 +68,7 @@ public class AddAttributeValueIntentionFix extends LocalQuickFixAndIntentionActi new WriteCommandAction(project) { @Override protected void run(@NotNull final Result result) { - final XmlAttribute attributeWithValue = XmlElementFactory.getInstance(getProject()).createXmlAttribute(attribute.getName(), ""); + final XmlAttribute attributeWithValue = XmlElementFactory.getInstance(getProject()).createAttribute(attribute.getName(), "", startElement); final PsiElement newAttribute = attribute.replace(attributeWithValue); if (editor != null && newAttribute != null && newAttribute instanceof XmlAttribute && newAttribute.isValid()) { diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/tree/injected/XmlAttributeLiteralEscaper.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/tree/injected/XmlAttributeLiteralEscaper.java index c04548e8c886..6de0b585ffd4 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/tree/injected/XmlAttributeLiteralEscaper.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/tree/injected/XmlAttributeLiteralEscaper.java @@ -33,7 +33,7 @@ public class XmlAttributeLiteralEscaper extends LiteralTextEscaper 0 ? getText().substring(0, 1) : ""; String contents = StringUtil.containsAnyChar(quoteChar, "'\"") ? StringUtil.trimEnd(StringUtil.trimStart(text, quoteChar), quoteChar) : text; - XmlAttribute newAttribute = XmlElementFactory.getInstance(getProject()).createXmlAttribute("q", contents); + XmlAttribute newAttribute = XmlElementFactory.getInstance(getProject()).createAttribute("q", contents, this); XmlAttributeValue newValue = newAttribute.getValueElement(); CheckUtil.checkWritable(this); From a8343b2712cdbdf917c11bedf66c197279e06904 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 22 Apr 2016 19:41:20 +0300 Subject: [PATCH 18/26] [groovy] support StreamingJsonBuilder (IDEA-155095) --- .../builder/BuilderMethodsContributor.java | 52 +++++++ .../StreamingJsonBuilderContributor.java | 95 ++++++++++++ ...reamingJsonBuilderDelegateContributor.java | 100 ++++++++++++ .../jetbrains/plugins/groovy/builder/Utils.kt | 24 +++ .../statements/expressions/TypesUtil.java | 7 + .../impl/synthetic/GrLightMethodBuilder.java | 15 ++ plugins/groovy/src/META-INF/plugin.xml | 2 + .../builder/StreamingJsonBuilderTest.groovy | 143 ++++++++++++++++++ 8 files changed, 438 insertions(+) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/BuilderMethodsContributor.java create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderContributor.java create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderDelegateContributor.java create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/Utils.kt create mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/BuilderMethodsContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/BuilderMethodsContributor.java new file mode 100644 index 000000000000..445d2ee5fe9c --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/BuilderMethodsContributor.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.builder; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import com.intellij.psi.ResolveState; +import com.intellij.psi.scope.ElementClassHint; +import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.util.Processor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; + +public abstract class BuilderMethodsContributor extends NonCodeMembersContributor { + + @Override + public void processDynamicElements(@NotNull PsiType qualifierType, + PsiClass clazz, + @NotNull PsiScopeProcessor processor, + @NotNull PsiElement place, + @NotNull ResolveState state) { + if (clazz == null) return; + + String name = ResolveUtil.getNameHint(processor); + if (name == null) return; + + if (!ResolveUtil.shouldProcessMethods(processor.getHint(ElementClassHint.KEY))) return; + + processDynamicMethods(qualifierType, clazz, name, place, e -> processor.execute(e, state)); + } + + abstract boolean processDynamicMethods(@NotNull PsiType qualifierType, + @NotNull PsiClass clazz, + @NotNull String name, + @NotNull PsiElement place, + @NotNull Processor processor); +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderContributor.java new file mode 100644 index 000000000000..1d44e4fd0a65 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderContributor.java @@ -0,0 +1,95 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.builder; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import com.intellij.util.Processor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierFlags; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder; + +import static com.intellij.psi.CommonClassNames.JAVA_UTIL_MAP; +import static org.jetbrains.plugins.groovy.builder.StreamingJsonBuilderDelegateContributor.addClosureParameter; + +public class StreamingJsonBuilderContributor extends BuilderMethodsContributor { + + private static final String FQN = "groovy.json.StreamingJsonBuilder"; + static final String ORIGIN_INFO = "via StreamingJsonBuilder"; + + @Nullable + @Override + protected String getParentClassName() { + return FQN; + } + + @Override + boolean processDynamicMethods(@NotNull PsiType qualifierType, + @NotNull PsiClass clazz, + @NotNull String name, + @NotNull PsiElement place, + @NotNull Processor processor) { + GrLightMethodBuilder method; + + // () + method = createMethod(name, place, qualifierType, clazz); + if (!processor.process(method)) return false; + + // (Closure) + method = createMethod(name, place, qualifierType, clazz); + addClosureParameter(method); + if (!processor.process(method)) return false; + + // (Map) + method = createMethod(name, place, qualifierType, clazz); + method.addParameter("args", JAVA_UTIL_MAP); + if (!processor.process(method)) return false; + + // (Map, Closure) + method = createMethod(name, place, qualifierType, clazz); + method.addParameter("args", JAVA_UTIL_MAP); + addClosureParameter(method); + if (!processor.process(method)) return false; + + // (Iterable, Closure) + method = createMethod(name, place, qualifierType, clazz); + method.addParameter("values", TypesUtil.createIterableType(place, null), false); + addClosureParameter(method); + if (!processor.process(method)) return false; + + // (Object[], Closure) + method = createMethod(name, place, qualifierType, clazz); + method.addParameter("values", TypesUtil.getJavaLangObject(place).createArrayType()); + addClosureParameter(method); + return processor.process(method); + } + + @NotNull + private static GrLightMethodBuilder createMethod(@NotNull String name, + @NotNull PsiElement place, + @NotNull PsiType returnType, + @NotNull PsiClass clazz) { + GrLightMethodBuilder method = new GrLightMethodBuilder(place.getManager(), name); + method.setModifiers(GrModifierFlags.PUBLIC_MASK); + method.setReturnType(returnType); + UtilsKt.setContainingClass(method, clazz); + method.setOriginInfo(ORIGIN_INFO); + return method; + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderDelegateContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderDelegateContributor.java new file mode 100644 index 000000000000..bf342384839f --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderDelegateContributor.java @@ -0,0 +1,100 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.builder; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiEllipsisType; +import com.intellij.psi.PsiType; +import com.intellij.util.Processor; +import com.siyeh.ig.psiutils.TypeUtils; +import groovy.lang.Closure; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierFlags; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter; + +import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrDelegatesToUtil.DELEGATES_TO_KEY; +import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrDelegatesToUtil.DELEGATES_TO_STRATEGY_KEY; +import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE; + +public class StreamingJsonBuilderDelegateContributor extends BuilderMethodsContributor { + + private static final String DELEGATE_FQN = "groovy.json.StreamingJsonBuilder.StreamingJsonDelegate"; + + @Nullable + @Override + protected String getParentClassName() { + return DELEGATE_FQN; + } + + @Override + boolean processDynamicMethods(@NotNull PsiType qualifierType, + @NotNull PsiClass clazz, + @NotNull String name, + @NotNull PsiElement place, + @NotNull Processor processor) { + GrLightMethodBuilder method; + + // (Object...) + method = createMethod(name, place, clazz); + method.addParameter("values", new PsiEllipsisType(TypeUtils.getObjectType(place))); + if (!processor.process(method)) return false; + + // (Closure) + method = createMethod(name, place, clazz); + addClosureParameter(method); + if (!processor.process(method)) return false; + + // (Iterable, Closure) + method = createMethod(name, place, clazz); + method.addParameter("values", TypesUtil.createIterableType(place, null)); + addClosureParameter(method); + if (!processor.process(method)) return false; + + // (Object[], Closure) + method = createMethod(name, place, clazz); + method.addParameter("values", TypesUtil.getJavaLangObject(place).createArrayType()); + addClosureParameter(method); + if (!processor.process(method)) return false; + + // (Object, Closure) + method = createMethod(name, place, clazz); + method.addParameter("value", TypesUtil.getJavaLangObject(place)); + addClosureParameter(method); + return processor.process(method); + } + + @NotNull + private static GrLightMethodBuilder createMethod(@NotNull String name, + @NotNull PsiElement place, + @NotNull PsiClass clazz) { + GrLightMethodBuilder method = new GrLightMethodBuilder(place.getManager(), name); + method.setModifiers(GrModifierFlags.PUBLIC_MASK); + method.setReturnType(TypesUtil.getJavaLangObject(place)); + UtilsKt.setContainingClass(method, clazz); + method.setOriginInfo(StreamingJsonBuilderContributor.ORIGIN_INFO); + return method; + } + + static void addClosureParameter(GrLightMethodBuilder method) { + GrLightParameter closureParam = method.addAndGetParameter("closure", GROOVY_LANG_CLOSURE); + closureParam.putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); + closureParam.putUserData(DELEGATES_TO_STRATEGY_KEY, Closure.DELEGATE_FIRST); + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/Utils.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/Utils.kt new file mode 100644 index 000000000000..48670ada9ddf --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/Utils.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.builder + +import com.intellij.psi.PsiClass +import com.intellij.psi.impl.compiled.ClsClassImpl +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder + +fun setContainingClass(method: GrLightMethodBuilder, clazz: PsiClass): Unit { + method.containingClass = (if (clazz is ClsClassImpl) clazz.sourceMirrorClass else null) ?: clazz +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index 6a16317c29f8..5689142a08cc 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -462,6 +462,13 @@ public class TypesUtil { return createTypeByFQClassName(fqName, context); } + @NotNull + public static PsiClassType createType(@NotNull PsiClass clazz, @Nullable PsiElement context, PsiType... parameters) { + return JavaPsiFacade.getInstance( + (context == null ? clazz : context).getProject() + ).getElementFactory().createType(clazz, parameters); + } + @NotNull public static PsiClassType getJavaLangObject(@NotNull PsiElement context) { return LazyFqnClassType.getLazyType(CommonClassNames.JAVA_LANG_OBJECT, context); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightMethodBuilder.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightMethodBuilder.java index c70d1bbaaf3b..98f2b74bd2ab 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightMethodBuilder.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightMethodBuilder.java @@ -260,17 +260,32 @@ public class GrLightMethodBuilder extends LightElement implements GrMethod, Orig return this; } + @NotNull + public GrLightMethodBuilder addParameter(@NotNull String name, @NotNull String type) { + return addParameter(name, type, false); + } + @NotNull public GrLightMethodBuilder addParameter(@NotNull String name, @NotNull String type, boolean isOptional) { return addParameter(name, JavaPsiFacade.getElementFactory(getProject()).createTypeFromText(type, this), isOptional); } + @NotNull + public GrLightMethodBuilder addParameter(@NotNull String name, @NotNull PsiType type) { + return addParameter(name, type, false); + } + @NotNull public GrLightMethodBuilder addParameter(@NotNull String name, @NotNull PsiType type, boolean isOptional) { GrLightParameter param = new GrLightParameter(name, type, this).setOptional(isOptional); return addParameter(param); } + @NotNull + public GrLightParameter addAndGetParameter(@NotNull String name, @NotNull String type) { + return addAndGetParameter(name, type, false); + } + @NotNull public GrLightParameter addAndGetParameter(@NotNull String name, @NotNull String type, boolean isOptional) { return addAndGetParameter(name, JavaPsiFacade.getElementFactory(getProject()).createTypeFromText(type, this), isOptional); diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 8f4e01c02072..83b0fcbf1ab6 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -111,6 +111,8 @@ + + diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy new file mode 100644 index 000000000000..56ac6d826d99 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy @@ -0,0 +1,143 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.builder + +import com.intellij.psi.PsiMethod +import com.intellij.testFramework.LightProjectDescriptor +import groovy.transform.CompileStatic +import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.LightGroovyTestCase +import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection +import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression + +@CompileStatic +class StreamingJsonBuilderTest extends LightGroovyTestCase { + final String basePath = null + final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + + void 'test highlighting'() { + myFixture.configureByText 'a.groovy', ''' +def builder = new groovy.json.StreamingJsonBuilder(null) +builder.people { + person { + string "fdsasdf" + mapCall( + city: 'A', + country: 'B', + zip: 12345, + ) + boolCall true + varArgs '1111', 22222 + empty() + cc { + foobar() + hellYeah(1,2,3) + } + } +} +''' + fixture.enableInspections GroovyAssignabilityCheckInspection, GrUnresolvedAccessInspection + fixture.checkHighlighting true, false, true + } + + void 'test builder calls resolve & return type'() { + [ + "builder.root()", + "builder.root {}", + "builder.root(a: 1, b: 2)", + "builder.root(a: 1, b: 2) {}", + "builder.root([1, 2, 3, 4]) {}", + "builder.root([] as Integer[], {})", + ].each { text -> + def file = fixture.configureByText('a.groovy', "def builder = new groovy.json.StreamingJsonBuilder(null);$text") as GroovyFile + def call = file.topStatements.last() as GrCallExpression + def method = call.resolveMethod() + assert method + assert call.type.canonicalText == 'groovy.json.StreamingJsonBuilder' + } + } + + void 'test builder inner calls resolve & return type'() { + [ + "noArg()", + "singleArg(1)", + "singleArg(new Object())", + "singleArg {}", + "singleArg([:])", + "doubleArg([:]) {}", + "doubleArg(1, 2)", + "doubleArg([], {})", + "doubleArg(new Object[0]) {}", + "doubleArg(new Object[0], {})", + "varArg(1, 2, 3)", + "varArg(1, 2d, '')", + "varArg(new Object(), [], {}, a: 1, 2d, [:], '')", + ].each { callText -> + [ + "builder.root {$callText}", + "builder.root(a: 1, b: 2) {$callText}", + "builder.root([1, 2, 3, 4]) {$callText}", + "builder.root([] as Integer[], {$callText})", + ].each { text -> + doTest(text) + } + } + } + + void 'test builder delegate inner calls resolve & return type'() { + [ + "noArg()", + "singleArg(1)", + "singleArg(new Object())", + "singleArg {}", + "singleArg([:])", + "doubleArg([:]) {}", + "doubleArg(1, 2)", + "doubleArg([], {})", + "doubleArg(new Object[0]) {}", + "doubleArg(new Object[0], {})", + "varArg(1, 2, 3)", + "varArg(1, 2d, '')", + "varArg(new Object(), [], {}, a: 1, 2d, [:], '')", + ].each { innerCallText -> + [ + "singleArg {$innerCallText}", + "doubleArg([:]) {$innerCallText}", + "doubleArg([], {$innerCallText})", + "doubleArg(new Object[0], {$innerCallText})", + "varArg(new Object(), [], {$innerCallText}, a: 1, 2d, [:], '')", + ].each { callText -> + ["builder.root {$callText}", + "builder.root(a: 1, b: 2) {$callText}", + "builder.root([1, 2, 3, 4]) {$callText}", + "builder.root([] as Integer[], {$callText})", + ].each { text -> + doTest(text) + } + } + } + } + + private void doTest(text) { + fixture.configureByText 'a.groovy', "def builder = new groovy.json.StreamingJsonBuilder(); $text" + def reference = fixture.getReferenceAtCaretPosition() as GrReferenceExpression + assert reference.resolve() instanceof PsiMethod + assert reference.type.canonicalText == 'java.lang.Object' + } +} From 44e49654e8885ae1565bb7b90bdafce934f2b24e Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 22 Apr 2016 19:49:17 +0300 Subject: [PATCH 19/26] [groovy] get rid of duplicated code --- .../builder/JsonBuilderContributor.java | 44 ++++++++----------- .../builder/JsonDelegateContributor.java | 35 +++++---------- 2 files changed, 30 insertions(+), 49 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonBuilderContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonBuilderContributor.java index 1485f6a877e3..1e338142e34e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonBuilderContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonBuilderContributor.java @@ -15,23 +15,22 @@ */ package org.jetbrains.plugins.groovy.builder; -import com.intellij.psi.*; -import com.intellij.psi.impl.compiled.ClsClassImpl; -import com.intellij.psi.scope.ElementClassHint; -import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiType; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder; -import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; -import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import static com.intellij.psi.CommonClassNames.JAVA_UTIL_MAP; import static org.jetbrains.plugins.groovy.builder.JsonDelegateContributor.DELEGATE_FQN; import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrDelegatesToUtil.DELEGATES_TO_KEY; import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE; -public class JsonBuilderContributor extends NonCodeMembersContributor { +public class JsonBuilderContributor extends BuilderMethodsContributor { private static final String FQN = "groovy.json.JsonBuilder"; static final String ORIGIN_INFO = "via JsonBuilder"; @@ -43,51 +42,44 @@ public class JsonBuilderContributor extends NonCodeMembersContributor { } @Override - public void processDynamicElements(@NotNull PsiType qualifierType, - PsiClass clazz, - @NotNull PsiScopeProcessor processor, - @NotNull PsiElement place, - @NotNull ResolveState state) { - if (clazz == null) return; - - String name = ResolveUtil.getNameHint(processor); - if (name == null) return; - - if (!ResolveUtil.shouldProcessMethods(processor.getHint(ElementClassHint.KEY))) return; - + boolean processDynamicMethods(@NotNull PsiType qualifierType, + @NotNull PsiClass clazz, + @NotNull String name, + @NotNull PsiElement place, + @NotNull Processor processor) { GrLightMethodBuilder method; // () method = createMethod(name, clazz, place); - if (!processor.execute(method, state)) return; + if (!processor.process(method)) return false; // (Closure) method = createMethod(name, clazz, place); method.addAndGetParameter("c", GROOVY_LANG_CLOSURE, false).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); - if (!processor.execute(method, state)) return; + if (!processor.process(method)) return false; // (Map) method = createMethod(name, clazz, place); method.addParameter("map", JAVA_UTIL_MAP, false); - if (!processor.execute(method, state)) return; + if (!processor.process(method)) return false; // (Map, Closure) method = createMethod(name, clazz, place); method.addParameter("map", JAVA_UTIL_MAP, false); method.addAndGetParameter("c", GROOVY_LANG_CLOSURE, false).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); - if (!processor.execute(method, state)) return; + if (!processor.process(method)) return false; // (Iterable, Closure) method = createMethod(name, clazz, place); method.addParameter("value", TypesUtil.createIterableType(place, null), false); method.addAndGetParameter("c", GROOVY_LANG_CLOSURE, false).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); - if (!processor.execute(method, state)) return; + if (!processor.process(method)) return false; // (Object[], Closure) method = createMethod(name, clazz, place); method.addParameter("value", TypesUtil.getJavaLangObject(place).createArrayType(), false); method.addAndGetParameter("c", GROOVY_LANG_CLOSURE, false).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); - processor.execute(method, state); + return processor.process(method); } @@ -98,7 +90,7 @@ public class JsonBuilderContributor extends NonCodeMembersContributor { method.setOriginInfo(ORIGIN_INFO); method.addModifier(PsiModifier.PUBLIC); method.setReturnType(JAVA_UTIL_MAP, context.getResolveScope()); - method.setContainingClass(clazz instanceof ClsClassImpl ? ((ClsClassImpl)clazz).getSourceMirrorClass() : clazz); + UtilsKt.setContainingClass(method, clazz); return method; } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonDelegateContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonDelegateContributor.java index a09733196b7b..92ab376449f7 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonDelegateContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonDelegateContributor.java @@ -16,20 +16,16 @@ package org.jetbrains.plugins.groovy.builder; import com.intellij.psi.*; -import com.intellij.psi.impl.compiled.ClsClassImpl; -import com.intellij.psi.scope.ElementClassHint; -import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder; -import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; -import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrDelegatesToUtil.DELEGATES_TO_KEY; import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE; -public class JsonDelegateContributor extends NonCodeMembersContributor { +public class JsonDelegateContributor extends BuilderMethodsContributor { static final String DELEGATE_FQN = "groovy.json.JsonDelegate"; @@ -40,18 +36,11 @@ public class JsonDelegateContributor extends NonCodeMembersContributor { } @Override - public void processDynamicElements(@NotNull PsiType qualifierType, - PsiClass clazz, - @NotNull PsiScopeProcessor processor, - @NotNull PsiElement place, - @NotNull ResolveState state) { - if (clazz == null) return; - - String name = ResolveUtil.getNameHint(processor); - if (name == null) return; - - if (!ResolveUtil.shouldProcessMethods(processor.getHint(ElementClassHint.KEY))) return; - + boolean processDynamicMethods(@NotNull PsiType qualifierType, + @NotNull PsiClass clazz, + @NotNull String name, + @NotNull PsiElement place, + @NotNull Processor processor) { JavaPsiFacade facade = JavaPsiFacade.getInstance(place.getProject()); GrLightMethodBuilder method; @@ -62,7 +51,7 @@ public class JsonDelegateContributor extends NonCodeMembersContributor { genericType = facade.getElementFactory().createType(method.addTypeParameter("T")); method.addParameter("value", genericType, false); method.setReturnType(genericType); - if (!processor.execute(method, state)) return; + if (!processor.process(method)) return false; // List (T[], Closure) method = createMethod(name, clazz, place); @@ -70,7 +59,7 @@ public class JsonDelegateContributor extends NonCodeMembersContributor { method.addParameter("values", genericType.createArrayType(), false); method.addAndGetParameter("c", GROOVY_LANG_CLOSURE, false).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); method.setReturnType(TypesUtil.createListType(place, genericType)); - if (!processor.execute(method, state)) return; + if (!processor.process(method)) return false; // List (Iterable, Closure) method = createMethod(name, clazz, place); @@ -78,14 +67,14 @@ public class JsonDelegateContributor extends NonCodeMembersContributor { method.addParameter("values", TypesUtil.createIterableType(place, genericType), false); method.addAndGetParameter("c", GROOVY_LANG_CLOSURE, false).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); method.setReturnType(TypesUtil.createListType(place, genericType)); - if (!processor.execute(method, state)) return; + if (!processor.process(method)) return false; // List (T...) method = createMethod(name, clazz, place); genericType = facade.getElementFactory().createType(method.addTypeParameter("T")); method.addAndGetParameter("values", new PsiEllipsisType(genericType), false); method.setReturnType(TypesUtil.createListType(place, genericType)); - processor.execute(method, state); + return processor.process(method); } private static GrLightMethodBuilder createMethod(@NotNull String name, @@ -94,7 +83,7 @@ public class JsonDelegateContributor extends NonCodeMembersContributor { GrLightMethodBuilder method = new GrLightMethodBuilder(context.getManager(), name); method.setOriginInfo(JsonBuilderContributor.ORIGIN_INFO); method.addModifier(PsiModifier.PUBLIC); - method.setContainingClass(clazz instanceof ClsClassImpl ? ((ClsClassImpl)clazz).getSourceMirrorClass() : clazz); + UtilsKt.setContainingClass(method, clazz); return method; } } From bc767bcdd0abf42da0c84ce9f5719f5958463e07 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 22 Apr 2016 20:50:36 +0300 Subject: [PATCH 20/26] [groovy] do not resolve dynamic methods as getters --- .../builder/BuilderMethodsContributor.java | 4 ++-- .../groovy/lang/resolve/ResolveUtil.kt | 23 ++++++++++++++++++ .../processors/DynamicMembersHint.java | 24 +++++++++++++++++++ .../processors/GroovyResolverProcessor.java | 10 ++++++-- .../groovy/builder/JsonBuilderTest.groovy | 4 ++++ .../builder/StreamingJsonBuilderTest.groovy | 8 +++++++ 6 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/DynamicMembersHint.java diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/BuilderMethodsContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/BuilderMethodsContributor.java index 445d2ee5fe9c..4f84a1b31908 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/BuilderMethodsContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/BuilderMethodsContributor.java @@ -19,12 +19,12 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import com.intellij.psi.ResolveState; -import com.intellij.psi.scope.ElementClassHint; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt; public abstract class BuilderMethodsContributor extends NonCodeMembersContributor { @@ -39,7 +39,7 @@ public abstract class BuilderMethodsContributor extends NonCodeMembersContributo String name = ResolveUtil.getNameHint(processor); if (name == null) return; - if (!ResolveUtil.shouldProcessMethods(processor.getHint(ElementClassHint.KEY))) return; + if (!ResolveUtilKt.shouldProcessDynamicMethods(processor)) return; processDynamicMethods(qualifierType, clazz, name, place, e -> processor.execute(e, state)); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt new file mode 100644 index 000000000000..5eeebe124c08 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.resolve + +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.plugins.groovy.lang.resolve.processors.DynamicMembersHint + +fun shouldProcessDynamicMethods(processor: PsiScopeProcessor): Boolean { + return processor.getHint(DynamicMembersHint.KEY)?.shouldProcessMethods() ?: false +} \ No newline at end of file diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/DynamicMembersHint.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/DynamicMembersHint.java new file mode 100644 index 000000000000..cdb607917c07 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/DynamicMembersHint.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.resolve.processors; + +import com.intellij.openapi.util.Key; + +public interface DynamicMembersHint { + Key KEY = Key.create("groovy.dynamic.members.hint"); + + boolean shouldProcessMethods(); +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java index e234a454ba98..05233ec4d4ea 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java @@ -32,6 +32,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyMethodResult; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; @@ -50,7 +51,7 @@ import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.isAccessible import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.isStaticsOK; import static org.jetbrains.plugins.groovy.lang.resolve.processors.AccessorResolverProcessor.*; -public abstract class GroovyResolverProcessor implements PsiScopeProcessor, ElementClassHint, NameHint { +public abstract class GroovyResolverProcessor implements PsiScopeProcessor, ElementClassHint, NameHint, DynamicMembersHint { protected final @NotNull GrReferenceExpression myRef; private final @NotNull String myName; @@ -204,7 +205,7 @@ public abstract class GroovyResolverProcessor implements PsiScopeProcessor, Elem @Nullable @Override public T getHint(@NotNull Key hintKey) { - if (hintKey == ElementClassHint.KEY || hintKey == NameHint.KEY) { + if (hintKey == ElementClassHint.KEY || hintKey == NameHint.KEY || hintKey == DynamicMembersHint.KEY) { return (T)this; } return null; @@ -235,6 +236,11 @@ public abstract class GroovyResolverProcessor implements PsiScopeProcessor, Elem return myName; } + @Override + public boolean shouldProcessMethods() { + return myRef.getParent() instanceof GrCallExpression; + } + @NotNull public abstract List getCandidates(); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/JsonBuilderTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/JsonBuilderTest.groovy index 2ee929cadb4c..e075d91d145b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/JsonBuilderTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/JsonBuilderTest.groovy @@ -49,11 +49,15 @@ builder.people { boolCall true varArgs '1111', 22222 empty() + someProperty } + someProperty } +builder.root builder.root(new Object()) builder.root(new Object[0]) +builder.root([new Object(), new Object()]) builder.root([], new Object(), {}) ''' fixture.enableInspections GroovyAssignabilityCheckInspection, GrUnresolvedAccessInspection diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy index 56ac6d826d99..16e672089f2b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy @@ -49,8 +49,16 @@ builder.people { foobar() hellYeah(1,2,3) } + someProperty } + someProperty } + +builder.root +builder.root(new Object()) +builder.root(new Object[0]) +builder.root([new Object(), new Object()]) +builder.root([], new Object(), {}) ''' fixture.enableInspections GroovyAssignabilityCheckInspection, GrUnresolvedAccessInspection fixture.checkHighlighting true, false, true From 7a3a2f24df65e0afa29f3da9573b0789fefd60e3 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 22 Apr 2016 21:59:35 +0300 Subject: [PATCH 21/26] [groovy] prefer regular methods over dynamic --- .../resolve/processors/GroovyResolverProcessor.java | 2 +- .../groovy/builder/StreamingJsonBuilderTest.groovy | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java index 05233ec4d4ea..f1b20293bf97 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java @@ -238,7 +238,7 @@ public abstract class GroovyResolverProcessor implements PsiScopeProcessor, Elem @Override public boolean shouldProcessMethods() { - return myRef.getParent() instanceof GrCallExpression; + return myRef.getParent() instanceof GrCallExpression && !myCandidates.containsKey(GroovyResolveKind.METHOD); } @NotNull diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy index 16e672089f2b..ade0672446dd 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.builder import com.intellij.psi.PsiMethod +import com.intellij.psi.impl.compiled.ClsMethodImpl import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor @@ -148,4 +149,14 @@ builder.root([], new Object(), {}) assert reference.resolve() instanceof PsiMethod assert reference.type.canonicalText == 'java.lang.Object' } + + void 'test do not override existing methods'() { + def file = myFixture.configureByText('a.groovy', ''' +new groovy.json.StreamingJsonBuilder().call {} +''') as GroovyFile + def call = file.topStatements.last() as GrCallExpression + def method = call.resolveMethod() + assert method + assert method instanceof ClsMethodImpl + } } From 9dbf0999edb4599d381ff779a1232b93d6d88d38 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 22 Apr 2016 22:24:05 +0300 Subject: [PATCH 22/26] [groovy] disable changing call() to () operator until better times --- .../changeToOperator/transformations/Transformations.java | 2 +- .../plugins/groovy/inspections/GrChangeToOperatorTest.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/changeToOperator/transformations/Transformations.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/changeToOperator/transformations/Transformations.java index 897e440ac6ef..c02886b9f577 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/changeToOperator/transformations/Transformations.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/changeToOperator/transformations/Transformations.java @@ -46,7 +46,7 @@ public class Transformations { result.put(PREVIOUS, new UnaryTransformation(mDEC)); result.put(AS_BOOLEAN, new AsBooleanTransformation()); - result.put(CALL, new CallTransformation()); + //result.put(CALL, new CallTransformation()); } private void addBinary() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToOperatorTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToOperatorTest.groovy index 58775427bcec..9fdc9a1ecda9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToOperatorTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToOperatorTest.groovy @@ -37,7 +37,7 @@ public class GrChangeToOperatorTest extends LightGroovyTestCase { assertValid(/a.bitwiseNegate()/, /~a/) assertValid(/a.negative()/, /-a/) assertValid(/a.positive()/, /+a/) - assertValid(/a.call()/, /a()/) +// assertValid(/a.call()/, /a()/) assertValid(/a.next()/, /++a/) assertValid(/a.previous()/, /--a/) } From 4649323d6b544bc9b40199d0ba7c2e08504a8f03 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 25 Apr 2016 15:33:41 +0300 Subject: [PATCH 23/26] [groovy] move shortcuts to default methods of GrReferenceElement --- .../groovy/lang/psi/GrReferenceElement.java | 13 ++++++++--- .../GrReferenceExpressionImpl.java | 12 ---------- .../GrLightClassReferenceElement.java | 22 +++---------------- .../types/GrCodeReferenceElementImpl.java | 15 +------------ 4 files changed, 14 insertions(+), 48 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GrReferenceElement.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GrReferenceElement.java index e56cc95376c6..9f4fd20116e3 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GrReferenceElement.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GrReferenceElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; +import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; /** * @author ven @@ -32,10 +33,16 @@ public interface GrReferenceElement extends GroovyPsiEleme @Nullable String getReferenceName(); + @Nullable @Override - PsiElement resolve(); + default PsiElement resolve() { + return advancedResolve().getElement(); + } - GroovyResolveResult advancedResolve(); + @NotNull + default GroovyResolveResult advancedResolve() { + return PsiImplUtil.extractUniqueResult(multiResolve(false)); + } @Override @NotNull diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 08671ebd47be..479ad9c0342b 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -198,12 +198,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl POLY_RESOLVER = new PolyVariantResolver() { @Override @NotNull @@ -601,12 +595,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl Date: Mon, 25 Apr 2016 17:11:16 +0300 Subject: [PATCH 24/26] [groovy] move shortcuts to default methods of GrCall --- .../api/statements/expressions/GrCall.java | 11 ++++++--- .../typedef/members/GrEnumConstant.java | 7 ++++++ .../GrConstructorInvocationImpl.java | 12 ---------- .../expressions/GrMethodCallImpl.java | 23 ------------------- .../expressions/GrNewExpressionImpl.java | 13 ----------- .../expressions/path/GrIndexPropertyImpl.java | 14 +---------- .../enumConstant/GrEnumConstantImpl.java | 14 +---------- 7 files changed, 17 insertions(+), 77 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrCall.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrCall.java index 9026d677b3a1..e393abc12cbc 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrCall.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrCall.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; /** * @author ven @@ -48,10 +49,14 @@ public interface GrCall extends GroovyPsiElement { GroovyResolveResult[] getCallVariants(@Nullable GrExpression upToArgument); @Nullable - PsiMethod resolveMethod(); + default PsiMethod resolveMethod() { + return PsiImplUtil.extractUniqueElement(multiResolve(false)); + } @NotNull - GroovyResolveResult advancedResolve(); + default GroovyResolveResult advancedResolve() { + return PsiImplUtil.extractUniqueResult(multiResolve(false)); + } @NotNull GroovyResolveResult[] multiResolve(boolean incompleteCode); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/typedef/members/GrEnumConstant.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/typedef/members/GrEnumConstant.java index 66df925958a3..61dcc5abedf8 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/typedef/members/GrEnumConstant.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/typedef/members/GrEnumConstant.java @@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members; import com.intellij.psi.PsiEnumConstant; +import com.intellij.psi.PsiMethod; import com.intellij.util.ArrayFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,4 +47,10 @@ public interface GrEnumConstant extends GrField, GrConstructorCall, PsiEnumConst @Nullable @Override GrArgumentList getArgumentList(); + + @Nullable + @Override + default PsiMethod resolveMethod() { + return GrConstructorCall.super.resolveMethod(); + } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java index 9180933083e4..645e0b0902fe 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java @@ -29,7 +29,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgument import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; -import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrCallImpl; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -115,17 +114,6 @@ public class GrConstructorInvocationImpl extends GrCallImpl implements GrConstru return new GroovyResolveResult[]{new GroovyResolveResultImpl(aClass, this, null, PsiSubstitutor.EMPTY, true, true)}; } - @Override - public PsiMethod resolveMethod() { - return PsiImplUtil.extractUniqueElement(multiResolve(false)); - } - - @NotNull - @Override - public GroovyResolveResult advancedResolve() { - return PsiImplUtil.extractUniqueResult(multiResolve(false)); - } - @Override @Nullable public PsiClass getDelegatedClass() { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrMethodCallImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrMethodCallImpl.java index da0673c63a90..dd7265ead727 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrMethodCallImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrMethodCallImpl.java @@ -19,7 +19,6 @@ import com.intellij.lang.ASTNode; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentationProviders; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiType; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; @@ -85,28 +84,6 @@ public abstract class GrMethodCallImpl extends GrCallExpressionImpl implements G throw new IncorrectOperationException("invoked expression must not be null"); } - @Override - public PsiMethod resolveMethod() { - final GrExpression methodExpr = getInvokedExpression(); - if (methodExpr instanceof GrReferenceExpression) { - final PsiElement resolved = ((GrReferenceExpression) methodExpr).resolve(); - return resolved instanceof PsiMethod ? (PsiMethod) resolved : null; - } - - return null; - } - - @NotNull - @Override - public GroovyResolveResult advancedResolve() { - final GrExpression methodExpr = getInvokedExpression(); - if (methodExpr instanceof GrReferenceExpression) { - return ((GrReferenceExpression) methodExpr).advancedResolve(); - } - - return GroovyResolveResult.EMPTY_RESULT; - } - @Override public PsiType getType() { return TypeInferenceHelper.getCurrentContext().getExpressionType(this, METHOD_CALL_TYPES_CALCULATOR); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java index e29428255b0c..230d8328187f 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java @@ -46,7 +46,6 @@ import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnonymousClassType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClassReferenceType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; -import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path.GrCallExpressionImpl; import org.jetbrains.plugins.groovy.lang.psi.util.GrInnerClassConstructorUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; @@ -195,18 +194,6 @@ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewEx return findChildByClass(GrTypeArgumentList.class); } - @Override - @Nullable - public PsiMethod resolveMethod() { - return PsiImplUtil.extractUniqueElement(multiResolve(false)); - } - - @NotNull - @Override - public GroovyResolveResult advancedResolve() { - return PsiImplUtil.extractUniqueResult(multiResolve(false)); - } - @Override @NotNull public GroovyResolveResult[] getCallVariants(@Nullable GrExpression upToArgument) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java index 6bc581ffed01..aa277cd2f786 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -354,18 +354,6 @@ public class GrIndexPropertyImpl extends GrExpressionImpl implements GrIndexProp return GrClosableBlock.EMPTY_ARRAY; } - @Override - public PsiMethod resolveMethod() { - return PsiImplUtil.extractUniqueElement(multiResolve(false)); - } - - @NotNull - @Override - public GroovyResolveResult advancedResolve() { - GroovyResolveResult[] results = multiResolve(false); - return results.length == 1 ? results[0] : GroovyResolveResult.EMPTY_RESULT; - } - @Override public PsiReference getReference() { return myReference; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java index 30f683599880..d15af1a646eb 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +37,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEn import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; -import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.GrFieldImpl; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrFieldStub; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; @@ -159,11 +158,6 @@ public class GrEnumConstantImpl extends GrFieldImpl implements GrEnumConstant { return GrClosableBlock.EMPTY_ARRAY; } - @Override - public PsiMethod resolveMethod() { - return PsiImplUtil.extractUniqueElement(multiResolve(false)); - } - @NotNull @Override public JavaResolveResult resolveMethodGenerics() { @@ -199,12 +193,6 @@ public class GrEnumConstantImpl extends GrFieldImpl implements GrEnumConstant { return myReference; } - @NotNull - @Override - public GroovyResolveResult advancedResolve() { - return PsiImplUtil.extractUniqueResult(multiResolve(false)); - } - @Override public PsiMethod resolveConstructor() { return resolveMethod(); From 6a053b5a0c7ee16651987ca185fbfc75f586dd5e Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 25 Apr 2016 19:03:59 +0300 Subject: [PATCH 25/26] [groovy] refactor & move MarkupBuilder support with other builders --- ...MarkupBuilderNonCodeMemberContributor.java | 73 ++++++++----------- .../groovy/lang/GroovyCoreEnvironment.java | 4 +- plugins/groovy/src/META-INF/plugin.xml | 2 +- .../XmlMarkupBuilderTest.groovy | 2 +- 4 files changed, 36 insertions(+), 45 deletions(-) rename plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/{markup => builder}/XmlMarkupBuilderNonCodeMemberContributor.java (55%) rename plugins/groovy/test/org/jetbrains/plugins/groovy/{markup => builder}/XmlMarkupBuilderTest.groovy (98%) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/markup/XmlMarkupBuilderNonCodeMemberContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/XmlMarkupBuilderNonCodeMemberContributor.java similarity index 55% rename from plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/markup/XmlMarkupBuilderNonCodeMemberContributor.java rename to plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/XmlMarkupBuilderNonCodeMemberContributor.java index 54106d41e991..e5c8398ceb11 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/markup/XmlMarkupBuilderNonCodeMemberContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/XmlMarkupBuilderNonCodeMemberContributor.java @@ -13,28 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.plugins.groovy.markup; +package org.jetbrains.plugins.groovy.builder; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; -import com.intellij.psi.ResolveState; -import com.intellij.psi.scope.ElementClassHint; -import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder; -import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; -import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import static com.intellij.psi.CommonClassNames.*; import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks.GrDelegatesToUtil.DELEGATES_TO_KEY; import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE; -public class XmlMarkupBuilderNonCodeMemberContributor extends NonCodeMembersContributor { +public class XmlMarkupBuilderNonCodeMemberContributor extends BuilderMethodsContributor { private static final String FQN = "groovy.xml.MarkupBuilder"; + private static final String ORIGIN_INFO = "via MarkupBuilder"; @Nullable @Override @@ -43,71 +40,65 @@ public class XmlMarkupBuilderNonCodeMemberContributor extends NonCodeMembersCont } @Override - public void processDynamicElements(@NotNull PsiType qualifierType, - PsiClass aClass, - @NotNull PsiScopeProcessor processor, - @NotNull PsiElement place, - @NotNull ResolveState state) { - String name = ResolveUtil.getNameHint(processor); - if (name == null) return; - - if (!ResolveUtil.shouldProcessMethods(processor.getHint(ElementClassHint.KEY))) return; - + boolean processDynamicMethods(@NotNull PsiType qualifierType, + @NotNull PsiClass clazz, + @NotNull String name, + @NotNull PsiElement place, + @NotNull Processor processor) { GrLightMethodBuilder res; // () - res = new GrLightMethodBuilder(aClass.getManager(), name); - res.setReturnType(JAVA_LANG_STRING, place.getResolveScope()); - res.setOriginInfo("via MarkupBuilder"); - if (!processor.execute(res, state)) return; + res = createMethod(name, clazz, place); + if (!processor.process(res)) return false; // (Closure) - res = new GrLightMethodBuilder(aClass.getManager(), name); + res = createMethod(name, clazz, place); res.addAndGetParameter("body", GROOVY_LANG_CLOSURE, false).putUserData(DELEGATES_TO_KEY, FQN); - res.setReturnType(JAVA_LANG_STRING, place.getResolveScope()); - res.setOriginInfo("via MarkupBuilder"); - if (!processor.execute(res, state)) return; + if (!processor.process(res)) return false; // (Object, Closure) - res = new GrLightMethodBuilder(aClass.getManager(), name); + res = createMethod(name, clazz, place); res.addParameter("value", JAVA_LANG_OBJECT, false); res.addAndGetParameter("body", GROOVY_LANG_CLOSURE, false).putUserData(DELEGATES_TO_KEY, FQN); - res.setReturnType(JAVA_LANG_STRING, place.getResolveScope()); - res.setOriginInfo("via MarkupBuilder"); - if (!processor.execute(res, state)) return; + if (!processor.process(res)) return false; // (Map, Closure) - res = new GrLightMethodBuilder(aClass.getManager(), name); + res = createMethod(name, clazz, place); res.addParameter("attributes", JAVA_UTIL_MAP, false); res.addAndGetParameter("body", GROOVY_LANG_CLOSURE, false).putUserData(DELEGATES_TO_KEY, FQN); - res.setReturnType(JAVA_LANG_STRING, place.getResolveScope()); - res.setOriginInfo("via MarkupBuilder"); - if (!processor.execute(res, state)) return; + if (!processor.process(res)) return false; // (Map) // (Map, Object) // (Map, Object, Closure) - res = new GrLightMethodBuilder(aClass.getManager(), name); - res.setReturnType(JAVA_LANG_STRING, place.getResolveScope()); + res = createMethod(name, clazz, place); res.addParameter("attributes", JAVA_UTIL_MAP, false); res.addParameter("value", JAVA_LANG_OBJECT, true); res.addAndGetParameter("body", GROOVY_LANG_CLOSURE, true).putUserData(DELEGATES_TO_KEY, FQN); - res.setOriginInfo("via MarkupBuilder"); for (GrReflectedMethod method : res.getReflectedMethods()) { - if (!processor.execute(method, state)) return; + if (!processor.process(method)) return false; } // (Object) // (Object, Map) // (Object, Map, Closure) - res = new GrLightMethodBuilder(aClass.getManager(), name); - res.setReturnType(JAVA_LANG_STRING, place.getResolveScope()); + res = createMethod(name, clazz, place); res.addParameter("value", JAVA_LANG_OBJECT, false); res.addParameter("attributes", JAVA_UTIL_MAP, true); res.addAndGetParameter("body", GROOVY_LANG_CLOSURE, true).putUserData(DELEGATES_TO_KEY, FQN); - res.setOriginInfo("via MarkupBuilder"); for (GrReflectedMethod method : res.getReflectedMethods()) { - if (!processor.execute(method, state)) return; + if (!processor.process(method)) return false; } + + return true; + } + + @NotNull + private static GrLightMethodBuilder createMethod(@NotNull String name, @NotNull PsiClass clazz, @NotNull PsiElement place) { + GrLightMethodBuilder res = new GrLightMethodBuilder(place.getManager(), name); + res.setReturnType(JAVA_LANG_STRING, place.getResolveScope()); + res.setOriginInfo(ORIGIN_INFO); + UtilsKt.setContainingClass(res, clazz); + return res; } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyCoreEnvironment.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyCoreEnvironment.java index 985baa491281..eba235bcf1b1 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyCoreEnvironment.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyCoreEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,6 +56,7 @@ import org.jetbrains.plugins.groovy.annotator.GrKeywordAndDeclarationHighlightFa import org.jetbrains.plugins.groovy.annotator.GrReferenceHighlighterFactory; import org.jetbrains.plugins.groovy.annotator.GroovyFrameworkConfigNotification; import org.jetbrains.plugins.groovy.annotator.checkers.*; +import org.jetbrains.plugins.groovy.builder.XmlMarkupBuilderNonCodeMemberContributor; import org.jetbrains.plugins.groovy.codeInsight.GroovyClsCustomNavigationPolicy; import org.jetbrains.plugins.groovy.codeInspection.GroovyQuickFixFactory; import org.jetbrains.plugins.groovy.codeInspection.declaration.GrMethodMayBeStaticInspectionFilter; @@ -96,7 +97,6 @@ import org.jetbrains.plugins.groovy.lang.resolve.ast.*; import org.jetbrains.plugins.groovy.lang.resolve.noncode.GrCollectionTypeMembersProvider; import org.jetbrains.plugins.groovy.lang.resolve.noncode.MixinMemberContributor; import org.jetbrains.plugins.groovy.lang.stubs.GroovyShortNamesCache; -import org.jetbrains.plugins.groovy.markup.XmlMarkupBuilderNonCodeMemberContributor; import org.jetbrains.plugins.groovy.spock.SpockMemberContributor; import org.jetbrains.plugins.groovy.spock.SpockPomDeclarationSearcher; import org.jetbrains.plugins.groovy.structure.GroovyStructureViewFactory; diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 83b0fcbf1ab6..bab08806e0a6 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -108,7 +108,7 @@ - + diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/markup/XmlMarkupBuilderTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/XmlMarkupBuilderTest.groovy similarity index 98% rename from plugins/groovy/test/org/jetbrains/plugins/groovy/markup/XmlMarkupBuilderTest.groovy rename to plugins/groovy/test/org/jetbrains/plugins/groovy/builder/XmlMarkupBuilderTest.groovy index f7717fc47ee5..0ce0d6e7cbc4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/markup/XmlMarkupBuilderTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/XmlMarkupBuilderTest.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.plugins.groovy.markup +package org.jetbrains.plugins.groovy.builder import com.intellij.psi.impl.compiled.ClsMethodImpl import org.jetbrains.plugins.groovy.LightGroovyTestCase From e8de1be521a59a13048e28562d63d1f50dfa403d Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 25 Apr 2016 21:08:29 +0300 Subject: [PATCH 26/26] [groovy] resolve `call()` in @DelegatesTo processing --- .../statements/blocks/GrDelegatesToUtil.java | 36 +++++++++++-- .../resolve/ResolveWithDelegatesToTest.groovy | 51 +++++++++++++++++++ 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java index 82dac2def4ff..6ba4716a04d5 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java @@ -17,9 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks; import com.intellij.openapi.util.Key; import com.intellij.psi.*; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.psi.util.*; import com.intellij.util.ArrayUtil; import groovy.lang.Closure; import org.jetbrains.annotations.NotNull; @@ -37,10 +35,14 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; +import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; + +import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getArgumentTypes; /** * @author Max Medvedev @@ -55,7 +57,7 @@ public class GrDelegatesToUtil { GrCall call = getContainingCall(closableBlock); if (call == null) return null; - GroovyResolveResult result = call.advancedResolve(); + GroovyResolveResult result = resolveActualCall(call); if (GdkMethodUtil.isWithOrIdentity(result.getElement())) { final GrExpression qualifier = inferCallQualifier((GrMethodCall)call); @@ -270,6 +272,32 @@ public class GrDelegatesToUtil { return null; } + @NotNull + static GroovyResolveResult resolveActualCall(@NotNull GrCall call) { + if (call instanceof GrMethodCall) { + return CachedValuesManager.getCachedValue(call, () -> CachedValueProvider.Result.create( + doResolveActualCall((GrMethodCall)call), PsiModificationTracker.MODIFICATION_COUNT + )); + } + else { + return call.advancedResolve(); + } + } + + @NotNull + private static GroovyResolveResult doResolveActualCall(@NotNull GrMethodCall call) { + GroovyResolveResult result = call.advancedResolve(); + if (result.getElement() instanceof PsiMethod && !result.isInvokedOnProperty()) { + return result; + } + GrExpression expression = call.getInvokedExpression(); + PsiType type = expression.getType(); + if (type == null) return result; + + GroovyResolveResult[] calls = ResolveUtil.getMethodCandidates(type, "call", expression, getArgumentTypes(expression, false)); + return PsiImplUtil.extractUniqueResult(calls); + } + public static class DelegatesToInfo { final PsiType myClassToDelegate; final int myStrategy; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy index 2c0dd0906a78..dd7871c185d3 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy @@ -347,6 +347,7 @@ test() ''', 'LinkedHashMap' } + void testShouldChooseMethodFromOwnerInJava() { myFixture.configureByText("Abc.java", '''\ import groovy.lang.Closure; @@ -737,4 +738,54 @@ doX { final containingClass = resolved.containingClass.name assertEquals(resolvedClass, containingClass) } + + void 'test delegate within implicit call()'() { + assertScript '''\ +class A { + def call(@DelegatesTo(Boo) Closure c) {} +} + +class Boo { + def foo() {} +} + +def a = new A() +a { + foo() +} +''', 'Boo' + } + + void 'test delegate within index property'() { + assertScript '''\ +class A { + def getAt(@DelegatesTo(Boo) Closure c) {} +} + +class Boo { + def foo() {} +} + +def a = new A() +a[{ + foo() +}] +''', 'Boo' + } + + void 'test delegate within constructor argument'() { + assertScript '''\ +class A { + A(@DelegatesTo(Boo) Closure c) {} +} + +class Boo { + def foo() {} +} + +new A({ + foo() +}) +''', 'Boo' + } }