From a9725caf48bef7b2efce9152b47d99cc5fe96973 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 14 Jan 2015 17:25:50 +0100 Subject: [PATCH 01/39] preserve generics signature on inner class make static fix (IDEA-135223) --- .../memory/InnerClassMayBeStaticInspection.java | 6 ++++-- .../PreserveGenericSignature.after.java | 16 ++++++++++++++++ .../PreserveGenericSignature.java | 16 ++++++++++++++++ .../memory/InnerClassMayBeStaticFixTest.java | 6 ++---- 4 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/PreserveGenericSignature.after.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/PreserveGenericSignature.java diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassMayBeStaticInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassMayBeStaticInspection.java index 6db808eb729d..751ce0a416f2 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassMayBeStaticInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassMayBeStaticInspection.java @@ -111,8 +111,10 @@ public class InnerClassMayBeStaticInspection extends BaseInspection { if (argumentList == null) { continue; } - final PsiExpression expression = - factory.createExpressionFromText("new " + classReference.getQualifiedName() + argumentList.getText(), innerClass); + final PsiReferenceParameterList parameterList = classReference.getParameterList(); + final String genericParameters = parameterList != null ? parameterList.getText() : ""; + final PsiExpression expression = factory + .createExpressionFromText("new " + classReference.getQualifiedName() + genericParameters + argumentList.getText(), innerClass); codeStyleManager.shortenClassReferences(newExpression.replace(expression)); } final PsiModifierList modifiers = innerClass.getModifierList(); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/PreserveGenericSignature.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/PreserveGenericSignature.after.java new file mode 100644 index 000000000000..47e556e9804b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/PreserveGenericSignature.after.java @@ -0,0 +1,16 @@ +class IdeaTest { + + public void test(){ + print(new InnerClass().foo(Integer.valueOf(1))); + } + + public void print(Integer foo){ + System.out.println(foo); + } + + static class InnerClass{ + public T foo(T bar){ + return bar; + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/PreserveGenericSignature.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/PreserveGenericSignature.java new file mode 100644 index 000000000000..30c074c91e8e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/PreserveGenericSignature.java @@ -0,0 +1,16 @@ +class IdeaTest { + + public void test(){ + print(new InnerClass().foo(Integer.valueOf(1))); + } + + public void print(Integer foo){ + System.out.println(foo); + } + + class InnerClass{ + public T foo(T bar){ + return bar; + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/memory/InnerClassMayBeStaticFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/memory/InnerClassMayBeStaticFixTest.java index 49a855ed605f..465427174cc4 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/memory/InnerClassMayBeStaticFixTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/memory/InnerClassMayBeStaticFixTest.java @@ -33,8 +33,6 @@ public class InnerClassMayBeStaticFixTest extends IGQuickFixesTestCase { } public void testSimple() { doTest(); } - - public void testAnonymousInside() { - doTest(); - } + public void testAnonymousInside() { doTest(); } + public void testPreserveGenericSignature() { doTest(); } } From 55e83bf6e5b3650058fd0251dc4734e1f9d697d0 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 14 Jan 2015 18:04:16 +0100 Subject: [PATCH 02/39] deep parameter delete: allow delete parameter when caller method has complex expression as argument --- .../SafeDeleteJavaCallerChooser.java | 47 ++++++++++++------- ...eParameterOtherTypeInBinaryExpression.java | 8 ++++ ...eterOtherTypeInBinaryExpression_after.java | 8 ++++ .../intellij/refactoring/SafeDeleteTest.java | 4 ++ 4 files changed, 49 insertions(+), 18 deletions(-) create mode 100644 java/java-tests/testData/refactoring/safeDelete/DeepDeleteParameterOtherTypeInBinaryExpression.java create mode 100644 java/java-tests/testData/refactoring/safeDelete/DeepDeleteParameterOtherTypeInBinaryExpression_after.java diff --git a/java/java-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteJavaCallerChooser.java b/java/java-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteJavaCallerChooser.java index a53c78a76a08..ef96f251d7c2 100644 --- a/java/java-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteJavaCallerChooser.java +++ b/java/java-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteJavaCallerChooser.java @@ -23,6 +23,7 @@ import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.changeSignature.MethodNodeBase; import com.intellij.refactoring.changeSignature.inCallers.JavaCallerChooser; @@ -111,37 +112,47 @@ abstract class SafeDeleteJavaCallerChooser extends JavaCallerChooser { final PsiExpression[] expressions = argumentList.getExpressions(); if (expressions.length > parameterIndex) { final PsiExpression expression = PsiUtil.deparenthesizeExpression(expressions[parameterIndex]); - if (expression instanceof PsiReferenceExpression) { - final PsiElement resolve = ((PsiReferenceExpression)expression).resolve(); - if (resolve instanceof PsiParameter && !((PsiParameter)resolve).isVarArgs()) { - final PsiElement scope = ((PsiParameter)resolve).getDeclarationScope(); + if (expression != null) { + final Set paramRefs = new HashSet(); + expression.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement resolve = expression.resolve(); + if (resolve instanceof PsiParameter) { + paramRefs.add((PsiParameter)resolve); + } + } + }); + + final PsiParameter parameter = ContainerUtil.getFirstItem(paramRefs); + if (parameter != null && !parameter.isVarArgs()) { + final PsiElement scope = parameter.getDeclarationScope(); if (scope instanceof PsiMethod && ((PsiMethod)scope).findDeepestSuperMethods().length == 0) { final Ref ref = new Ref(false); - if (ReferencesSearch.search(resolve, new LocalSearchScope(scope)).forEach(new Processor() { + if (ReferencesSearch.search(parameter, new LocalSearchScope(scope)).forEach(new Processor() { @Override public boolean process(PsiReference reference) { final PsiElement element = reference.getElement(); if (element instanceof PsiReferenceExpression) { - final PsiElement parent = element.getParent(); - if (parent instanceof PsiExpressionList) { - final PsiElement gParent = parent.getParent(); - if (gParent instanceof PsiCallExpression) { - final PsiMethod resolved = ((PsiCallExpression)gParent).resolveMethod(); - if (scope.equals(resolved)) { - return true; - } - if (nodeMethod.equals(resolved)) { - ref.set(true); - return true; - } + PsiElement parent = PsiTreeUtil.getParentOfType(element, PsiCallExpression.class); + while (parent != null) { + final PsiMethod resolved = ((PsiCallExpression)parent).resolveMethod(); + if (scope.equals(resolved)) { + return true; } + if (nodeMethod.equals(resolved)) { + ref.set(true); + return true; + } + parent = PsiTreeUtil.getParentOfType(parent, PsiCallExpression.class, true); } return false; } return true; } }) && ref.get()) { - return (PsiParameter)resolve; + return (PsiParameter)parameter; } } } diff --git a/java/java-tests/testData/refactoring/safeDelete/DeepDeleteParameterOtherTypeInBinaryExpression.java b/java/java-tests/testData/refactoring/safeDelete/DeepDeleteParameterOtherTypeInBinaryExpression.java new file mode 100644 index 000000000000..d39bbaa19d7b --- /dev/null +++ b/java/java-tests/testData/refactoring/safeDelete/DeepDeleteParameterOtherTypeInBinaryExpression.java @@ -0,0 +1,8 @@ +class Test { + void foo(String s) { + bar(s.length()); + bar(s.length() + 1); + } + + void bar(int i){} +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/safeDelete/DeepDeleteParameterOtherTypeInBinaryExpression_after.java b/java/java-tests/testData/refactoring/safeDelete/DeepDeleteParameterOtherTypeInBinaryExpression_after.java new file mode 100644 index 000000000000..d3f5fd3b4214 --- /dev/null +++ b/java/java-tests/testData/refactoring/safeDelete/DeepDeleteParameterOtherTypeInBinaryExpression_after.java @@ -0,0 +1,8 @@ +class Test { + void foo() { + bar(); + bar(); + } + + void bar(){} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java b/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java index 819922c4016f..477d15097cd0 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java @@ -80,6 +80,10 @@ public class SafeDeleteTest extends MultiFileTestCase { doSingleFileTest(); } + public void testDeepDeleteParameterOtherTypeInBinaryExpression() throws Exception { + doSingleFileTest(); + } + public void testImpossibleToDeepDeleteParameter() throws Exception { doSingleFileTest(); } From 574577fe730721929b7fbd5cf71166ade619817b Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 14 Jan 2015 18:27:57 +0100 Subject: [PATCH 03/39] introduce functional parameter: do not fold as functional interface creation would be in the place where local vars are not available --- .../IntroduceParameterHandler.java | 5 ++++ .../afterEnsureNotFolded.java | 27 +++++++++++++++++++ .../beforeEnsureNotFolded.java | 20 ++++++++++++++ .../IntroduceFunctionalParameterTest.java | 4 +++ 4 files changed, 56 insertions(+) create mode 100644 java/java-tests/testData/refactoring/introduceFunctionalParameter/afterEnsureNotFolded.java create mode 100644 java/java-tests/testData/refactoring/introduceFunctionalParameter/beforeEnsureNotFolded.java diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java index ec7fe89d622a..ba60d3378e85 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java @@ -704,6 +704,11 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { return false; } + @Override + protected boolean isFoldingApplicable() { + return false; + } + @Override public boolean prepare(@Nullable Pass pass) throws PrepareFailedException { final boolean prepare = super.prepare(pass); diff --git a/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterEnsureNotFolded.java b/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterEnsureNotFolded.java new file mode 100644 index 000000000000..b993040d6bd8 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterEnsureNotFolded.java @@ -0,0 +1,27 @@ +import java.util.function.Function; + +class Test { + + { + final int[] equals = new int[0]; + performTest(new Function() { + public String[] apply(String[] fields) { + System.out.println(); + return getIndexed(fields, equals); + } + }); + } + + private static void performTest(Function anObject) { + String[] fields = new String[0]; + + final String[] indexed = anObject.apply(fields); + + System.out.println(indexed); + } + + private static String[] getIndexed(String[] fields, int[] indices) { + return new String[indices.length]; + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceFunctionalParameter/beforeEnsureNotFolded.java b/java/java-tests/testData/refactoring/introduceFunctionalParameter/beforeEnsureNotFolded.java new file mode 100644 index 000000000000..bf6583dd6d98 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceFunctionalParameter/beforeEnsureNotFolded.java @@ -0,0 +1,20 @@ +class Test { + + { + performTest(new int[0]); + } + + private static void performTest(int[] equals) { + String[] fields = new String[0]; + + System.out.println(); + final String[] indexed = getIndexed(fields, equals); + + System.out.println(indexed); + } + + private static String[] getIndexed(String[] fields, int[] indices) { + return new String[indices.length]; + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFunctionalParameterTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFunctionalParameterTest.java index 31c26e2ae2cd..2f9702d095e1 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFunctionalParameterTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFunctionalParameterTest.java @@ -53,6 +53,10 @@ public class IntroduceFunctionalParameterTest extends LightRefactoringTestCase doTest(); } + public void testEnsureNotFolded() throws Exception { + doTest(); + } + @NotNull @Override protected String getTestDataPath() { From 79487fe48e32341fc01b828502d4d8e205996d7f Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 14 Jan 2015 19:32:38 +0100 Subject: [PATCH 04/39] method can be final: eliminate conflict between masks (IDEA-135056) --- .../InterfaceMethodInHierarchy/expected.xml | 4 ++++ .../InterfaceMethodInHierarchy/src/A.java | 20 +++++++++++++++++++ .../codeInspection/CanBeFinalTest.java | 9 +++++++++ .../reference/RefManagerImpl.java | 2 +- 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/inspection/canBeFinal/InterfaceMethodInHierarchy/expected.xml create mode 100644 java/java-tests/testData/inspection/canBeFinal/InterfaceMethodInHierarchy/src/A.java diff --git a/java/java-tests/testData/inspection/canBeFinal/InterfaceMethodInHierarchy/expected.xml b/java/java-tests/testData/inspection/canBeFinal/InterfaceMethodInHierarchy/expected.xml new file mode 100644 index 000000000000..d704d58ed391 --- /dev/null +++ b/java/java-tests/testData/inspection/canBeFinal/InterfaceMethodInHierarchy/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/canBeFinal/InterfaceMethodInHierarchy/src/A.java b/java/java-tests/testData/inspection/canBeFinal/InterfaceMethodInHierarchy/src/A.java new file mode 100644 index 000000000000..65a47c6772b0 --- /dev/null +++ b/java/java-tests/testData/inspection/canBeFinal/InterfaceMethodInHierarchy/src/A.java @@ -0,0 +1,20 @@ +interface A

{ + void accept(C

c); +} + +final class AImpl

implements A

{ + private final B

m_b = null; + + @Override + public final void accept(C

c) { + m_b.accept(c); + } +} + +interface B

{ + void accept(C

c); +} + +interface C

{} +interface D {} + diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/CanBeFinalTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/CanBeFinalTest.java index bb77b6b9bb18..08c7f6002c2a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/CanBeFinalTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/CanBeFinalTest.java @@ -102,4 +102,13 @@ public class CanBeFinalTest extends InspectionTestCase { doTest(tool); } + + public void testInterfaceMethodInHierarchy() throws Exception { + CanBeFinalInspection tool = new CanBeFinalInspection(); + tool.REPORT_CLASSES = false; + tool.REPORT_FIELDS = false; + tool.REPORT_METHODS = true; + + doTest(tool); + } } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java index b0af3b30cace..ce083ff09682 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java @@ -64,7 +64,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; public class RefManagerImpl extends RefManager { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.reference.RefManager"); - private int myLastUsedMask = 256 * 256 * 256 * 4; + private int myLastUsedMask = 256 * 256 * 256 * 8; @NotNull private final Project myProject; From bff6607dd646512a868967a17a8b2ddb8205baee Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 14 Jan 2015 21:14:51 +0100 Subject: [PATCH 05/39] introduce functional parameter as separate action: also works on single expressions; introduce parameter still introduces functional if nothing else is possible --- .../IntroduceFunctionalParameterAction.java | 88 ++++++++++++ .../introduceField/ElementToWorkOn.java | 1 + .../IntroduceParameterHandler.java | 127 ++++++++++-------- .../IntroduceVariableBase.java | 2 +- .../src/messages/ActionsBundle.properties | 2 + .../src/messages/RefactoringBundle.properties | 1 + .../src/idea/Keymap_Default.xml | 3 + resources/src/idea/JavaActions.xml | 6 +- 8 files changed, 172 insertions(+), 58 deletions(-) create mode 100644 java/java-impl/src/com/intellij/refactoring/actions/IntroduceFunctionalParameterAction.java diff --git a/java/java-impl/src/com/intellij/refactoring/actions/IntroduceFunctionalParameterAction.java b/java/java-impl/src/com/intellij/refactoring/actions/IntroduceFunctionalParameterAction.java new file mode 100644 index 000000000000..734d27dbc767 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/actions/IntroduceFunctionalParameterAction.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Created by IntelliJ IDEA. + * User: dsl + * Date: 06.05.2002 + * Time: 14:03:43 + * To change template for new class use + * Code Style | Class Templates options (Tools | IDE Options). + */ +package com.intellij.refactoring.actions; + +import com.intellij.lang.refactoring.RefactoringSupportProvider; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.HelpID; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.extractMethod.ExtractMethodHandler; +import com.intellij.refactoring.introduceParameter.IntroduceParameterHandler; +import com.intellij.refactoring.util.CommonRefactoringUtil; +import org.jetbrains.annotations.NotNull; + +public class IntroduceFunctionalParameterAction extends BasePlatformRefactoringAction { + private static final String REFACTORING_NAME = RefactoringBundle.message("introduce.functional.parameter.title"); + + @Override + protected boolean isAvailableInEditorOnly() { + return true; + } + + @Override + protected boolean isEnabledOnElements(@NotNull PsiElement[] elements) { + return false; + } + + @Override + protected RefactoringActionHandler getRefactoringHandler(@NotNull RefactoringSupportProvider provider) { + return new IntroduceParameterHandler() { + @Override + public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { + if (dataContext != null) { + final PsiFile file = CommonDataKeys.PSI_FILE.getData(dataContext); + final Editor editor = CommonDataKeys.EDITOR.getData(dataContext); + if (file != null && editor != null && !introduceStrategy(project, editor, file, elements)) { + showErrorMessage(project, editor); + } + } + } + + @Override + public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file, DataContext dataContext) { + ExtractMethodHandler.selectAndPass(project, editor, file, new Pass() { + @Override + public void pass(PsiElement[] elements) { + if (!introduceStrategy(project, editor, file, elements)) { + showErrorMessage(project, editor); + } + } + }); + } + + private void showErrorMessage(@NotNull Project project, Editor editor) { + String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("is.not.supported.in.the.current.context", REFACTORING_NAME)); + CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.INTRODUCE_PARAMETER); + } + }; + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/ElementToWorkOn.java b/java/java-impl/src/com/intellij/refactoring/introduceField/ElementToWorkOn.java index b1449bc92340..26bb4367b854 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/ElementToWorkOn.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/ElementToWorkOn.java @@ -43,6 +43,7 @@ public class ElementToWorkOn { public static final Key PREFIX = Key.create("prefix"); public static final Key SUFFIX = Key.create("suffix"); public static final Key TEXT_RANGE = Key.create("range"); + public static final Key REPLACE_NON_PHYSICAL = Key.create("replace_non_physical"); public static final Key OUT_OF_CODE_BLOCK= Key.create("out_of_code_block"); private ElementToWorkOn(PsiLocalVariable localVariable, PsiExpression expr) { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java index ba60d3378e85..7a6fe2485342 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java @@ -50,7 +50,6 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; @@ -528,68 +527,77 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { public boolean introduceStrategy(final Project project, final Editor editor, PsiFile file) { final SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.hasSelection()) { - final PsiElement[] elements = CodeInsightUtil - .findStatementsInRange(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); - if (elements.length > 0) { - final AbstractInplaceIntroducer inplaceIntroducer = AbstractInplaceIntroducer.getActiveIntroducer(editor); - if (inplaceIntroducer instanceof InplaceIntroduceParameterPopup) { - return false; - } - final List enclosingMethods = getEnclosingMethods(Util.getContainingMethod(elements[0])); - if (enclosingMethods.isEmpty()) { - return false; - } + final PsiElement[] elements = CodeInsightUtil.findStatementsInRange(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); + return introduceStrategy(project, editor, file, elements); + } + return false; + } - final PsiFile copy = PsiFileFactory.getInstance(project) - .createFileFromText(file.getName(), file.getFileType(), file.getText(), file.getModificationStamp(), false); + @VisibleForTesting + public boolean introduceStrategy(final Project project, final Editor editor, PsiFile file, final PsiElement[] elements) { + if (elements.length > 0) { + final AbstractInplaceIntroducer inplaceIntroducer = AbstractInplaceIntroducer.getActiveIntroducer(editor); + if (inplaceIntroducer instanceof InplaceIntroduceParameterPopup) { + return false; + } + final List enclosingMethods = getEnclosingMethods(Util.getContainingMethod(elements[0])); + if (enclosingMethods.isEmpty()) { + return false; + } - final PsiElement[] elementsCopy = CodeInsightUtil.findStatementsInRange(copy, - elements[0].getTextRange().getStartOffset(), + final PsiFile copy = PsiFileFactory.getInstance(project) + .createFileFromText(file.getName(), file.getFileType(), file.getText(), file.getModificationStamp(), false); + + final PsiExpression exprInRange = CodeInsightUtil.findExpressionInRange(copy, elements[0].getTextRange().getStartOffset(), + elements[elements.length - 1].getTextRange().getEndOffset()); + final PsiElement[] elementsCopy = exprInRange != null + ? new PsiElement[] {exprInRange} + : CodeInsightUtil.findStatementsInRange(copy, elements[0].getTextRange().getStartOffset(), elements[elements.length - 1].getTextRange().getEndOffset()); - final MyExtractMethodProcessor processor = new MyExtractMethodProcessor(project, editor, elementsCopy); - try { - if (!processor.prepare()) return false; - processor.showDialog(); + final MyExtractMethodProcessor processor = new MyExtractMethodProcessor(project, editor, elementsCopy); + try { + if (!processor.prepare()) return false; + processor.showDialog(); - //provide context for generated method to check exceptions compatibility - final PsiMethod emptyMethod = JavaPsiFacade.getElementFactory(project) - .createMethodFromText(processor.generateEmptyMethod("name").getText(), elements[0]); - final Collection types = FunctionalInterfaceSuggester.suggestFunctionalInterfaces(emptyMethod); - if (types.isEmpty()) { - return false; - } + //provide context for generated method to check exceptions compatibility + final PsiMethod emptyMethod = JavaPsiFacade.getElementFactory(project) + .createMethodFromText(processor.generateEmptyMethod("name").getText(), elements[0]); + final Collection types = FunctionalInterfaceSuggester.suggestFunctionalInterfaces(emptyMethod); + if (types.isEmpty()) { + return false; + } - if (types.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) { - final PsiType next = types.iterator().next(); - functionalInterfaceSelected(next, enclosingMethods, project, editor, processor, elements); + if (types.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) { + final PsiType next = types.iterator().next(); + functionalInterfaceSelected(next, enclosingMethods, project, editor, processor, elements); + } + else { + final Map classes = new LinkedHashMap(); + for (PsiType type : types) { + classes.put(PsiUtil.resolveClassInType(type), type); } - else { - final Map classes = new LinkedHashMap(); - for (PsiType type : types) { - classes.put(PsiUtil.resolveClassInType(type), type); - } - final PsiClass[] psiClasses = classes.keySet().toArray(new PsiClass[classes.size()]); - final String methodSignature = - PsiFormatUtil.formatMethod(emptyMethod, PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_TYPE); - final PsiType returnType = emptyMethod.getReturnType(); - LOG.assertTrue(returnType != null); - final String title = "Choose Applicable Functional Interface: " + methodSignature + " -> " + returnType.getPresentableText(); - NavigationUtil.getPsiElementPopup(psiClasses, new PsiClassListCellRenderer(), title, - new PsiElementProcessor() { - @Override - public boolean execute(@NotNull PsiClass psiClass) { - functionalInterfaceSelected(classes.get(psiClass), enclosingMethods, project, editor, processor, elements); - return true; - } - }).showInBestPositionFor(editor); - return true; - } - + final PsiClass[] psiClasses = classes.keySet().toArray(new PsiClass[classes.size()]); + final String methodSignature = + PsiFormatUtil.formatMethod(emptyMethod, PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_TYPE); + final PsiType returnType = emptyMethod.getReturnType(); + LOG.assertTrue(returnType != null); + final String title = "Choose Applicable Functional Interface: " + methodSignature + " -> " + returnType.getPresentableText(); + NavigationUtil.getPsiElementPopup(psiClasses, new PsiClassListCellRenderer(), title, + new PsiElementProcessor() { + @Override + public boolean execute(@NotNull PsiClass psiClass) { + functionalInterfaceSelected(classes.get(psiClass), enclosingMethods, project, editor, processor, + elements); + return true; + } + }).showInBestPositionFor(editor); return true; } - catch (IncorrectOperationException ignore) {} - catch (PrepareFailedException ignore) {} + + return true; } + catch (IncorrectOperationException ignore) {} + catch (PrepareFailedException ignore) {} } return false; } @@ -615,7 +623,8 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { final PsiType selectedType, final MyExtractMethodProcessor processor, final PsiElement[] elements) { - final PsiElement commonParent = elements.length > 1 ? PsiTreeUtil.findCommonParent(elements) : elements[0].getParent(); + final PsiElement commonParent = elements.length > 1 ? PsiTreeUtil.findCommonParent(elements) + : PsiTreeUtil.getParentOfType(elements[0].getParent(), PsiCodeBlock.class, false); if (commonParent == null) { LOG.error("Should have common parent:" + Arrays.toString(elements)); return; @@ -623,7 +632,8 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { final RangeMarker marker = editor.getDocument().createRangeMarker(commonParent.getTextRange()); final PsiElement[] copyElements = processor.getElements(); - final PsiElement containerCopy = copyElements.length > 1 ? PsiTreeUtil.findCommonParent(copyElements) : copyElements[0].getParent(); + final PsiElement containerCopy = copyElements.length > 1 ? PsiTreeUtil.findCommonParent(copyElements) + : PsiTreeUtil.getParentOfType(copyElements[0].getParent(), PsiCodeBlock.class, false); if (containerCopy == null) { LOG.error("Should have common parent:" + Arrays.toString(copyElements)); return; @@ -644,6 +654,11 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { LOG.assertTrue(method != null); final String interfaceMethodName = method.getName(); processor.setMethodName(interfaceMethodName); + + if (copyElements.length == 1) { + copyElements[0].putUserData(ElementToWorkOn.REPLACE_NON_PHYSICAL, true); + } + processor.doExtract(); final PsiMethod extractedMethod = processor.getExtractedMethod(); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index b63245fe10b6..84bc10e52484 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -1000,7 +1000,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { } else { expr2 = RefactoringUtil.outermostParenthesizedExpression(expr1); } - if (expr2.isPhysical()) { + if (expr2.isPhysical() || expr1.getUserData(ElementToWorkOn.REPLACE_NON_PHYSICAL) != null) { return expr2.replace(ref); } else { diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index cac75db369df..ed2e3bb493ac 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -612,6 +612,8 @@ action.IntroduceConstant.text=_Constant... action.IntroduceConstant.description=Replace selected expression with a constant (static final field) action.IntroduceParameter.text=_Parameter... action.IntroduceParameter.description=Turn the selected expression into method parameter +action.IntroduceFunctionalParameter.text=Functiona_l Parameter... +action.IntroduceFunctionalParameter.description=Replace selected statements with a call to new functional method parameter action.ExtractInterface.text=_Interface... action.ExtractInterface.description=Extract interface from the selected class action.ExtractModule.text=_Module... diff --git a/platform/platform-resources-en/src/messages/RefactoringBundle.properties b/platform/platform-resources-en/src/messages/RefactoringBundle.properties index e04615b8158d..b090b049ac86 100644 --- a/platform/platform-resources-en/src/messages/RefactoringBundle.properties +++ b/platform/platform-resources-en/src/messages/RefactoringBundle.properties @@ -787,3 +787,4 @@ rename.project.handler.title=Rename &project enter.new.project.name=Enter new project name: rename.project=Rename Project renames.project=Renames project +introduce.functional.parameter.title=Extract Functional Parameter diff --git a/platform/platform-resources/src/idea/Keymap_Default.xml b/platform/platform-resources/src/idea/Keymap_Default.xml index 8cd7594ebaaa..baf7d20c0c52 100644 --- a/platform/platform-resources/src/idea/Keymap_Default.xml +++ b/platform/platform-resources/src/idea/Keymap_Default.xml @@ -716,6 +716,9 @@ + + + diff --git a/resources/src/idea/JavaActions.xml b/resources/src/idea/JavaActions.xml index 6cc9ba83758f..7836da0b2add 100644 --- a/resources/src/idea/JavaActions.xml +++ b/resources/src/idea/JavaActions.xml @@ -68,10 +68,14 @@ - + + + + + From fd2ee29ddf1aa0dd83ec30b61ba79ed2a955dd5f Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 15 Jan 2015 12:55:05 +0300 Subject: [PATCH 06/39] IDEA-129734 IOOBE on decompiling certain method references --- .../decompiler/exps/InvocationExprent.java | 6 +- .../classes/pkg/TestClassLambda.class | Bin 4037 -> 4553 bytes .../testData/results/TestClassLambda.dec | 190 ++++++++++-------- .../testData/src/pkg/TestClassLambda.java | 6 + .../java/decompiler/IdeaDecompilerTest.java | 21 +- 5 files changed, 113 insertions(+), 110 deletions(-) diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java index 5ef7bf1821cc..2effc82a91ca 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -112,7 +112,9 @@ public class InvocationExprent extends Exprent { } else { // FIXME: remove the first parameter completely from the list. It's the object type for a virtual lambda method. - instance = lstParameters.get(0); + if (!lstParameters.isEmpty()) { + instance = lstParameters.get(0); + } } } else if (opcode == CodeConstants.opc_invokestatic) { diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestClassLambda.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassLambda.class index c6e62aa1a4d3dedfcb82e31eec752f6c5f59822d..80c85059b2c7fe46d2dd01d6b0cd66ca8a8ee608 100644 GIT binary patch literal 4553 zcmbVP_j}vc6+NINf}-Gvp=BqPyrVdjJQT?zc4W(zSE81(?8vbrr^65hNw6V+B|$ez z_nt}jo@v^qBW+{Xk!86__e#^puT9`}Ni4(b#l$y=#c!19H>r5Dinl0enlue-LV+@* zAil%2O?N;+L#FGfg2uhhgrT4{Yud)a(#*I~IHHeRoJqPy(aq{J;}g1qmg=B4GU|(r zHbq98Bcm;m(bmZ5CI#1L?#!OlPwPFFZcp{-w(YpOYdUt%V5QqH_QngwL@7u6c4d6| zl51K$lO;RnNe|iX9@Ewfvm<$H}rFqL>NG$?4Xxeivhw85-(hycXGvgE8Sp zqNrf0<;A2kGTli&8#6;f(4z8s$+9|0dRs8AMsRB%-ZWEY@g-Jt-sl+-vVl=Cri5*JksNhOg`9D~lvHdxLJIa;da;=G zeBUUEqTxpLYS@S#1y@%yCjim#R=iEc+cmrc?^N+F4e!Q#6r}bzj$3pKdVbh&r=5vn zYaH)Q;eD+t?n~kQ8t%sjRD4jwhwwlOyCqA<9bo(sjUb;XnEIo8Y0Gh zcvaQSVcngU5~14@&Wu;#_9gKX{8Yh`V1s(wt&GL8z8*gl^XeGq6&pR5GxD@$OD0># z>;AG=(HgYZv5Tb{CUV)finZiq(kblMbF^|*-I7t!?edKKIh`n!Y;UK88N97z+ft_c z#e-i+^Gog-o#kqFu*fZ-Ad?9fzH+7O;aW|76y;yB7)}}f7Gr?RsvcS1zN0H`k=cMk zIdtx+U8_{c24YrgYq-+YwXITaxuJ^Y-Q4&*qF4dz#_qV-{p*^=;LB3Q8l~PTSR+-` zk8U(bhj@;dIo&nrTB2agIH!#vX6ov?QKy#L{CBA2-({qUDty`fmPVWqx zcbN@gcDO8ua$r#?(}I#mijAEy+*dI!&z`f8+MDfUM-Uy5T?~DE?udEvmXMns{x2#dq+qEmJ3bT-RGfnH$05k z8BcnX%yA94mj4Rvl-XR-aXHh#l|w1@5j2c7G|r=ObgZ$-do{(qS6ua8YQlRZQvPfz zp7Q4B(UhG>{NA1Gx|c2R7XufNh@tvr`9A@c^Y*d=d-(S-f=*hnrDDN0S|$>00@4Bs;=+*1_E!S%uV%l7S-43 zrA{Apw$;TIRX_KMCXdMNBKPPb;)jm;r-Yynq`ayn$>RbCjjv%MK<^b_Fb z3cz8`3PoKPv3Tq}+Oq2|Uwi6VtQcRvgHd{D&$`iLkM;$83P9RueXce+|B3@ zlEFQ+u^&755y_kNv`)B7ba4eevTp!_tj`k4F4VS_3X*x!I7UDpEJB<-HmbR~-L*_oT%B$mk zsErSx(W4+1qIeKbp==XkZMzl1u(Ag*D+nWA#oIgP(N)Xb2Fmg%_`gl=qCU@)E9hU2 zI^X3?Dkg_gpud$4OKLA|qOaZ417vP_$BFK9h@F_jx?0*-llC=Og6pVtm|8L1hQIKg zB-)?w5B!KMo5HC|&kA}DQJ(3op2o9q Um)Cm^o{Q%NC@-zxy$rek0yDHyJ^%m! delta 1803 zcmaKs`&U#|6vsbzVCD{&ql_cCWJXX>-pClffD{BPGZa)bvj;K=0Y+djT4pub`(1W3 z%bsSb6(ypLilz22Q!9J7TK(7$^(XX0tJ-Jgt}t5m!`)|}y}$c=_TFcoduHmX$ zXmL-Zy`#NP@hFd(Jg#_xCrzGGY~yJIUtMo+q(9OZ-mtVi(%IYApXR~#@l2Y@b|23w zcJQ3Z^NO9k;G;~uFDhQ*Wl>)7Q6tN%ie0>>s32M?+kE+U8zhHY*R?5L=M5iw(%kIz zu}|?PZz-y{)L?u(!Htow?oe%CUwHG9uKtMPZ3cY2BMk5Q*smDmfMSS)CWmzF9!Ynk zuBJ#|S5Jpv-;*z9a#$sEgroNPjwyzDU-1F^OpYr~aMHlj+1}mVTdw$!0mVnu zC_dKO3F_>8_fXO&oU(s*2a<~T)c)PQQ`Xb=c2BOih|lz$p0Q7Os>FEK{=-vcX0p{F zz0mG;W!NjswVoo*8D!XlDe3k(v)KsRe;GkbhkdTa7j}QjZ)IO9&hxF}D(V%BsZ(63 z#Uhoa- z+4U-zIYVrg%qmQf5uGUZOB`=hg>$r5k1hn6&m`)|rjcAhl{+Y7Ox~&yRGv(DK8gZ4 zr%+Hc6DWz#mz^Q2HB2hfeYN_4>C)zl@odrJ2Xd{KH(46;el~Am%!VX=AIR8ZkjKhI#VD<}*$@8=yuqUm$!HaePR; z0g2POyNp4RiJU!g%R<4)kV^kFPWL5VWARZY8k{6^G=7nsBs_9f3e{0LO0Gc+`T%_e zuA~8x7amYAy9J4q#ZxRhU6AFS7aW!-mX0(rQEH>`EEDpTK1&aW;5C1(L}~t$Cwg`krN{~#?;Y#%jI{pf+;i!pUj!VS1x?I&_IGH&NJ;IJc&jv zmw1_2C%#g$Ng^uU50u8p+eMmQg1a%3_mUiMf-625iQpQpki*=#(ia%QBX7Xr$rc`6 zmnRTBLjLI9l?YZIjf4Gf&e3fD|0i7_1oHGQN^tS!CGyVqx%B&W;^#=o`XxEulcn=h$RJ0;mPnY3rF$!>Uxce6R=y!rQ|3h;-&3^;3d=%yY diff --git a/plugins/java-decompiler/engine/testData/results/TestClassLambda.dec b/plugins/java-decompiler/engine/testData/results/TestClassLambda.dec index 5a3e115454fc..553657980a1b 100644 --- a/plugins/java-decompiler/engine/testData/results/TestClassLambda.dec +++ b/plugins/java-decompiler/engine/testData/results/TestClassLambda.dec @@ -1,10 +1,12 @@ package pkg; +import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.OptionalInt; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.IntBinaryOperator; import java.util.function.Predicate; import java.util.function.Supplier; @@ -13,179 +15,189 @@ public class TestClassLambda { public int field = 0; public void testLambda() { - List var1 = Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4), Integer.valueOf(5), Integer.valueOf(6), Integer.valueOf(7)});// 27 - int var2 = (int)Math.random();// 28 - var1.forEach((var2x) -> {// 30 + List var1 = Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4), Integer.valueOf(5), Integer.valueOf(6), Integer.valueOf(7)});// 29 + int var2 = (int)Math.random();// 30 + var1.forEach((var2x) -> {// 32 int var3 = 2 * var2x.intValue(); System.out.println(var3 + var2 + this.field); }); } public void testLambda1() { - int var1 = (int)Math.random();// 37 + int var1 = (int)Math.random();// 39 Runnable var2 = () -> { System.out.println("hello1" + var1); - };// 38 + };// 40 Runnable var3 = () -> { System.out.println("hello2" + var1); - };// 39 + };// 41 } public void testLambda2() { - reduce((var0, var1) -> {// 43 + reduce((var0, var1) -> {// 45 return Math.max(var0, var1); }); } public void testLambda3() { - reduce(Math::max);// 47 + reduce(Math::max);// 49 } public void testLambda4() { - reduce(TestClassLambda::localMax);// 51 + reduce(TestClassLambda::localMax);// 53 } public void testLambda5() { - String var1 = "abcd";// 55 - function(var1::toString);// 56 + String var1 = "abcd";// 57 + function(var1::toString);// 58 } public void testLambda6() { - ArrayList var1 = new ArrayList();// 60 - int var2 = var1.size() * 2;// 61 - int var3 = var1.size() * 5;// 62 - var1.removeIf((var2x) -> {// 63 + ArrayList var1 = new ArrayList();// 62 + int var2 = var1.size() * 2;// 63 + int var3 = var1.size() * 5;// 64 + var1.removeIf((var2x) -> {// 65 return var2 >= var2x.length() && var2x.length() <= var3; }); } + public static void testLambda7(Annotation[] var0) { + Arrays.stream(var0).map(Annotation::annotationType);// 69 + } + public static OptionalInt reduce(IntBinaryOperator var0) { - return null;// 67 + return null;// 73 } public static String function(Supplier var0) { - return (String)var0.get();// 71 + return (String)var0.get();// 77 } public static int localMax(int var0, int var1) { - return 0;// 75 + return 0;// 81 } public void nestedLambdas() { - byte var1 = 5;// 79 + byte var1 = 5;// 85 Runnable var2 = () -> { Runnable var1x = () -> { System.out.println("hello2" + var1); }; System.out.println("hello1" + var1); - };// 80 + };// 86 } } class 'pkg/TestClassLambda' { method 'testLambda ()V' { - 7 15 - 8 15 - e 15 - f 15 - 15 15 - 16 15 - 1c 15 - 1d 15 - 23 15 - 24 15 - 2a 15 - 2c 15 - 33 15 - 35 15 - 39 15 - 3c 15 - 3d 16 - 40 16 - 41 16 - 4a 17 + 7 17 + 8 17 + e 17 + f 17 + 15 17 + 16 17 + 1c 17 + 1d 17 + 23 17 + 24 17 + 2a 17 + 2c 17 + 33 17 + 35 17 + 39 17 + 3c 17 + 3d 18 + 40 18 + 41 18 + 4a 19 } method 'testLambda1 ()V' { - 0 24 - 3 24 - 4 24 - b 27 - 12 30 + 0 26 + 3 26 + 4 26 + b 29 + 12 32 } method 'testLambda2 ()V' { - 5 34 + 5 36 } method 'testLambda3 ()V' { - 5 40 + 5 42 } method 'testLambda4 ()V' { - 5 44 + 5 46 } method 'testLambda5 ()V' { - 0 48 - 2 48 - e 49 + 0 50 + 2 50 + e 51 } method 'testLambda6 ()V' { - 7 53 - 9 54 - e 54 - f 54 - 10 54 - 12 55 - 17 55 - 18 55 - 19 55 - 22 56 + 7 55 + 9 56 + e 56 + f 56 + 10 56 + 12 57 + 17 57 + 18 57 + 19 57 + 22 58 + } + + method 'testLambda7 ([Ljava/lang/annotation/Annotation;)V' { + 1 64 + 9 64 } method 'reduce (Ljava/util/function/IntBinaryOperator;)Ljava/util/OptionalInt;' { - 0 62 - 1 62 + 0 68 + 1 68 } method 'function (Ljava/util/function/Supplier;)Ljava/lang/String;' { - 1 66 - 6 66 - 9 66 + 1 72 + 6 72 + 9 72 } method 'localMax (II)I' { - 0 70 - 1 70 + 0 76 + 1 76 } method 'nestedLambdas ()V' { - 0 74 - 1 74 - 8 80 + 0 80 + 1 80 + 8 86 } } Lines mapping: -27 <-> 16 -28 <-> 17 -30 <-> 18 -37 <-> 25 -38 <-> 28 -39 <-> 31 -43 <-> 35 -47 <-> 41 -51 <-> 45 -55 <-> 49 -56 <-> 50 -60 <-> 54 -61 <-> 55 +29 <-> 18 +30 <-> 19 +32 <-> 20 +39 <-> 27 +40 <-> 30 +41 <-> 33 +45 <-> 37 +49 <-> 43 +53 <-> 47 +57 <-> 51 +58 <-> 52 62 <-> 56 63 <-> 57 -67 <-> 63 -71 <-> 67 -75 <-> 71 -79 <-> 75 -80 <-> 81 +64 <-> 58 +65 <-> 59 +69 <-> 65 +73 <-> 69 +77 <-> 73 +81 <-> 77 +85 <-> 81 +86 <-> 87 diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestClassLambda.java b/plugins/java-decompiler/engine/testData/src/pkg/TestClassLambda.java index 1c29cd5292ad..860a5cdafb24 100644 --- a/plugins/java-decompiler/engine/testData/src/pkg/TestClassLambda.java +++ b/plugins/java-decompiler/engine/testData/src/pkg/TestClassLambda.java @@ -15,7 +15,9 @@ */ package pkg; +import java.lang.annotation.Annotation; import java.util.*; +import java.util.Arrays; import java.util.function.IntBinaryOperator; import java.util.function.Supplier; @@ -63,6 +65,10 @@ public class TestClassLambda { list.removeIf(s -> (bottom >= s.length() && s.length() <= top)); } + public static void testLambda7(Annotation[] annotations) { + Arrays.stream(annotations).map(Annotation::annotationType); + } + public static OptionalInt reduce(IntBinaryOperator op) { return null; } diff --git a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java index f2ed7234414e..ba87248bf961 100644 --- a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java +++ b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,6 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.registry.RegistryValue; @@ -38,12 +37,10 @@ import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import com.intellij.util.Alarm; import com.intellij.util.ThrowableRunnable; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.URLUtil; import org.jetbrains.annotations.NotNull; import java.awt.*; -import java.util.Set; public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase { @Override @@ -79,7 +76,7 @@ public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase { if (file.isDirectory()) { System.out.println(file.getPath()); } - else if (file.getFileType() == StdFileTypes.CLASS && !file.getName().contains("$") && !skip(file)) { + else if (file.getFileType() == StdFileTypes.CLASS && !file.getName().contains("$")) { PsiFile clsFile = getPsiManager().findFile(file); assertNotNull(file.getPath(), clsFile); PsiElement mirror = ((ClsFileImpl)clsFile).getMirror(); @@ -97,20 +94,6 @@ public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase { } return true; } - - private boolean skip(VirtualFile file) { - if (!SystemInfo.isJavaVersionAtLeast("1.8")) return false; - String path = file.getPath(); - int p = path.indexOf("!/"); - return p > 0 && knowProblems.contains(path.substring(p + 2)); - } - - // todo[r.sh] drop when IDEA-129734 get fixed - private final Set knowProblems = ContainerUtil.newHashSet( - "java/lang/reflect/AnnotatedElement.class", "java/util/stream/Nodes.class", "java/util/stream/FindOps.class", - "java/util/stream/Collectors.class", "java/util/stream/DistinctOps.class", "java/util/stream/IntPipeline.class", - "java/util/stream/LongPipeline.class", "java/util/stream/DoublePipeline.class" - ); }); } From fe7a855b9addbd95d9618a58bfc2a400afa20b99 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 15 Jan 2015 13:43:13 +0300 Subject: [PATCH 07/39] IDEA-96801 Exception in jsp --- .../psi/impl/JavaCodeBlockModificationListener.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java b/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java index 314f55c2f7fe..b99d4a319e36 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java +++ b/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.psi.*; import com.intellij.psi.impl.source.jsp.jspXml.JspDirective; import com.intellij.psi.util.PsiModificationTracker; -import com.intellij.psi.xml.XmlFile; import org.jetbrains.annotations.NotNull; public class JavaCodeBlockModificationListener implements PsiTreeChangePreprocessor { @@ -70,9 +69,11 @@ public class JavaCodeBlockModificationListener implements PsiTreeChangePreproces private void processChange(final PsiElement parent, final PsiElement child1, final PsiElement child2) { try { if (!isInsideCodeBlock(parent)) { - if (parent != null && isClassOwner(parent.getContainingFile()) || - isClassOwner(child1) || isClassOwner(child2) || isSourceDir(parent) || - (parent != null && isClassOwner(parent.getParent()))) { + if (isClassOwner(parent.getContainingFile()) || + isClassOwner(child1) || + isClassOwner(child2) || + isSourceDir(parent) || + isClassOwner(parent.getParent())) { myModificationTracker.incCounter(); } else { @@ -96,7 +97,7 @@ public class JavaCodeBlockModificationListener implements PsiTreeChangePreproces } private static boolean isClassOwner(final PsiElement element) { - return element instanceof PsiClassOwner && !(element instanceof XmlFile) || element instanceof JspDirective; + return element instanceof PsiClassOwner || element instanceof JspDirective; } private static boolean containsClassesInside(final PsiElement element) { From e9d87f981c1ee43c070e4299504576b2f4797ea3 Mon Sep 17 00:00:00 2001 From: Tor Norbye Date: Thu, 15 Jan 2015 13:42:10 +0300 Subject: [PATCH 08/39] IDEA-129977 Allow create-namespace fix to work on unbound XML attributes --- .../CreateNSDeclarationIntentionFix.java | 51 +++++++++++++++---- .../daemon/impl/analysis/ImportNSAction.java | 14 +++-- .../com/intellij/xml/XmlNamespaceHelper.java | 9 ++++ .../XmlUnboundNsPrefixInspection.java | 5 ++ 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java index 0a8a25b8fca3..6a58c80ba5b6 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java @@ -45,16 +45,14 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.cache.impl.id.IdTableBuilding; import com.intellij.psi.meta.PsiMetaData; -import com.intellij.psi.xml.XmlDocument; -import com.intellij.psi.xml.XmlFile; -import com.intellij.psi.xml.XmlTag; -import com.intellij.psi.xml.XmlToken; +import com.intellij.psi.xml.*; import com.intellij.ui.components.JBList; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; -import com.intellij.xml.XmlNamespaceHelper; import com.intellij.xml.XmlElementDescriptor; import com.intellij.xml.XmlExtension; +import com.intellij.xml.XmlNamespaceHelper; +import com.intellij.xml.XmlSchemaProvider; import com.intellij.xml.impl.schema.AnyXmlElementDescriptor; import com.intellij.xml.impl.schema.XmlNSDescriptorImpl; import com.intellij.xml.util.XmlUtil; @@ -63,7 +61,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; @@ -144,15 +142,32 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi return element != null && element.isValid(); } + /** Looks up the unbound namespaces and sorts them */ + @NotNull + private List getNamespaces(PsiElement element, XmlFile xmlFile) { + if (element instanceof XmlAttribute) { + element = element.getParent(); + } + Set set = getXmlExtension().guessUnboundNamespaces(element, xmlFile); + + final String match = getUnboundNamespaceForPrefix(myNamespacePrefix, xmlFile, set); + if (match != null) { + return Collections.singletonList(match); + } + + List namespaces = new ArrayList(set); + Collections.sort(namespaces); + return namespaces; + } + @Override public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { if (!FileModificationService.getInstance().prepareFileForWrite(file)) return; final PsiElement element = myElement.retrieve(); if (element == null) return; - final Set set = getXmlExtension().guessUnboundNamespaces(element, getFile()); - final String[] namespaces = ArrayUtil.toStringArray(set); - Arrays.sort(namespaces); + XmlFile xmlFile = getFile(); + final String[] namespaces = ArrayUtil.toStringArray(getNamespaces(element, xmlFile)); runActionOverSeveralAttributeValuesAfterLettingUserSelectTheNeededOne( namespaces, @@ -195,6 +210,22 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi editor); } + /** Given a prefix in a file and a set of candidate namespaces, returns the namespace that matches the prefix (if any) + * as determined by the {@link com.intellij.xml.XmlSchemaProvider#getDefaultPrefix(String, com.intellij.psi.xml.XmlFile)} + * implementations */ + @Nullable + public static String getUnboundNamespaceForPrefix(String prefix, XmlFile xmlFile, Set namespaces) { + final List providers = XmlSchemaProvider.getAvailableProviders(xmlFile); + for (XmlSchemaProvider provider : providers) { + for (String namespace : namespaces) { + if (prefix.equals(provider.getDefaultPrefix(namespace, xmlFile))) { + return namespace; + } + } + } + return null; + } + private String getTitle() { return XmlErrorMessages.message("select.namespace.title", StringUtil.capitalize(getXmlExtension().getNamespaceAlias(getFile()))); } @@ -216,7 +247,7 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi } final PsiElement element = myElement.retrieve(); if (element == null) return false; - final Set namespaces = getXmlExtension().guessUnboundNamespaces(element, getFile()); + final List namespaces = getNamespaces(element, getFile()); if (!namespaces.isEmpty()) { final String message = ShowAutoImportPass.getMessage(namespaces.size() > 1, namespaces.iterator().next()); final String title = getTitle(); diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/ImportNSAction.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/ImportNSAction.java index d3afcd58640c..24917fdeaee5 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/ImportNSAction.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/ImportNSAction.java @@ -25,27 +25,26 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.xml.XmlFile; import com.intellij.ui.components.JBList; +import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.xml.XmlNamespaceHelper; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.util.Arrays; import java.util.Collections; -import java.util.Set; +import java.util.List; /** * @author Dmitry Avdeev */ public class ImportNSAction implements QuestionAction { - private final Set myNamespaces; + private final List myNamespaces; private final XmlFile myFile; private final PsiElement myElement; private final Editor myEditor; private final String myTitle; - public ImportNSAction(final Set namespaces, XmlFile file, @NotNull PsiElement element, Editor editor, final String title) { - + public ImportNSAction(final List namespaces, XmlFile file, @NotNull PsiElement element, Editor editor, final String title) { myNamespaces = namespaces; myFile = file; myElement = element; @@ -55,9 +54,8 @@ public class ImportNSAction implements QuestionAction { @Override public boolean execute() { - final Object[] objects = myNamespaces.toArray(); - Arrays.sort(objects); - final JList list = new JBList(objects); + final String[] strings = ArrayUtil.toStringArray(myNamespaces); + final JList list = new JBList(strings); list.setCellRenderer(XmlNSRenderer.INSTANCE); list.setSelectedIndex(0); final int offset = myElement.getTextOffset(); diff --git a/xml/impl/src/com/intellij/xml/XmlNamespaceHelper.java b/xml/impl/src/com/intellij/xml/XmlNamespaceHelper.java index 797ae43a8ad3..058e989f3bb6 100644 --- a/xml/impl/src/com/intellij/xml/XmlNamespaceHelper.java +++ b/xml/impl/src/com/intellij/xml/XmlNamespaceHelper.java @@ -19,8 +19,10 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.IncorrectOperationException; @@ -55,6 +57,13 @@ public abstract class XmlNamespaceHelper { @Nullable public String getNamespacePrefix(PsiElement element) { + if (element instanceof XmlAttribute) { + XmlAttribute attribute = (XmlAttribute)element; + String prefix = attribute.getNamespacePrefix(); + if (!StringUtil.isEmpty(prefix)) { + return prefix; + } + } final PsiElement tag = element instanceof XmlTag ? element : element.getParent(); if (tag instanceof XmlTag) { return ((XmlTag)tag).getNamespacePrefix(); diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnboundNsPrefixInspection.java b/xml/xml-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnboundNsPrefixInspection.java index a8bd40221ce9..fc05a4849506 100644 --- a/xml/xml-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnboundNsPrefixInspection.java +++ b/xml/xml-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnboundNsPrefixInspection.java @@ -152,6 +152,11 @@ public class XmlUnboundNsPrefixInspection extends XmlSuppressableInspectionTool LocalQuickFix fix = isOnTheFly ? XmlQuickFixFactory.getInstance().createNSDeclarationIntentionFix(context, namespacePrefix, token) : null; reportTagProblem(element, localizedMessage, range, highlightType, fix, holder); } + else if (element instanceof XmlAttribute) { + LocalQuickFix fix = isOnTheFly ? XmlQuickFixFactory.getInstance().createNSDeclarationIntentionFix(element, namespacePrefix, token) : null; + XmlAttribute attribute = (XmlAttribute)element; + holder.registerProblem(attribute.getNameElement(), localizedMessage, highlightType, range, fix); + } else { holder.registerProblem(element, localizedMessage, highlightType, range); } From d8f9ca5058bc3573316137ab7d31b8531f63ec3b Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 15 Jan 2015 13:51:46 +0300 Subject: [PATCH 09/39] cleanup --- .../daemon/impl/analysis/CreateNSDeclarationIntentionFix.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java index 6a58c80ba5b6..0783da57f406 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java @@ -211,7 +211,7 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi } /** Given a prefix in a file and a set of candidate namespaces, returns the namespace that matches the prefix (if any) - * as determined by the {@link com.intellij.xml.XmlSchemaProvider#getDefaultPrefix(String, com.intellij.psi.xml.XmlFile)} + * as determined by the {@link XmlSchemaProvider#getDefaultPrefix(String, XmlFile)} * implementations */ @Nullable public static String getUnboundNamespaceForPrefix(String prefix, XmlFile xmlFile, Set namespaces) { From 12e212756378f87b0bcbc9a7fcf3228bca58e0e9 Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Thu, 15 Jan 2015 14:25:03 +0300 Subject: [PATCH 10/39] Better exception reporting --- .../platform-impl/src/com/intellij/ui/win/RecentTasks.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ui/win/RecentTasks.java b/platform/platform-impl/src/com/intellij/ui/win/RecentTasks.java index eecdc173f78d..c9380568672a 100644 --- a/platform/platform-impl/src/com/intellij/ui/win/RecentTasks.java +++ b/platform/platform-impl/src/com/intellij/ui/win/RecentTasks.java @@ -31,6 +31,9 @@ public class RecentTasks { private final static WeakReference openerThread = new WeakReference(Thread.currentThread()); + private final static String openerThreadName = + Thread.currentThread().getName(); + static { UrlClassLoader.loadPlatformLibrary("jumpListBridge"); } @@ -71,6 +74,6 @@ public class RecentTasks { private static void checkThread() { Thread t = openerThread.get(); if (t == null || !t.equals(Thread.currentThread())) - throw new RuntimeException("This class has to be used from the same thread"); + throw new RuntimeException("Current thread is " + Thread.currentThread().getName() + "This class has to be used from " + openerThreadName + " thread"); } } From a03dd53f021f877b86534445842aa4bbc731b096 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Thu, 15 Jan 2015 14:40:53 +0300 Subject: [PATCH 11/39] DBE-1065: fix status text painting --- .../intellij/ui/components/JBViewport.java | 8 +++++ .../src/com/intellij/util/ui/StatusText.java | 36 ++++++++++++++++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java index 15a4966a931f..c990d17bee2a 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java @@ -66,6 +66,8 @@ public class JBViewport extends JViewport implements ZoomableViewport { }; private StatusText myEmptyText; + private boolean myPaintingNow; + private ZoomingDelegate myZoomer; private Dimension myTempViewSize; @@ -112,6 +114,7 @@ public class JBViewport extends JViewport implements ZoomableViewport { @Override public void paint(Graphics g) { + myPaintingNow = true; if (myZoomer != null && myZoomer.isActive()) { myZoomer.paint(g); } @@ -122,6 +125,7 @@ public class JBViewport extends JViewport implements ZoomableViewport { myEmptyText.paint(this, g); } } + myPaintingNow = false; } @Nullable @@ -147,4 +151,8 @@ public class JBViewport extends JViewport implements ZoomableViewport { public void magnify(double magnification) { myZoomer.magnify(magnification); } + + public boolean isPaintingNow() { + return myPaintingNow; + } } diff --git a/platform/platform-api/src/com/intellij/util/ui/StatusText.java b/platform/platform-api/src/com/intellij/util/ui/StatusText.java index 479b968d4317..99e3046a8bed 100644 --- a/platform/platform-api/src/com/intellij/util/ui/StatusText.java +++ b/platform/platform-api/src/com/intellij/util/ui/StatusText.java @@ -20,6 +20,8 @@ import com.intellij.ui.ClickListener; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.UIBundle; +import com.intellij.ui.components.JBViewport; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -186,13 +188,37 @@ public abstract class StatusText { } public void paint(Component owner, Graphics g) { - boolean wrongComponent = owner != myOwner && owner != null && owner.getParent() != myOwner; - if (!isStatusVisible() || wrongComponent) return; + if (!isStatusVisible()) return; - Rectangle b = getTextComponentBound(); - myComponent.setBounds(0, 0, b.width, b.height); + if (owner == myOwner) { + doPaintStatusText(g, getTextComponentBound()); + } + else { + paintOnComponentUnderViewport(owner, g); + } + } - Graphics2D g2 = (Graphics2D)g.create(b.x, b.y, b.width, b.height); + private void paintOnComponentUnderViewport(Component component, Graphics g) { + JBViewport viewport = ObjectUtils.tryCast(myOwner, JBViewport.class); + if (viewport == null || viewport.getView() != component || viewport.isPaintingNow()) return; + + // We're painting a component which has a viewport as it's ancestor. + // As the viewport paints status text, we'll erase it, so we need to schedule a repaint for the viewport with status text's bounds. + // But it causes flicker, so we paint status text over the component first and then schedule the viewport repaint. + + Rectangle textBoundsInViewport = getTextComponentBound(); + + int xInOwner = textBoundsInViewport.x - component.getX(); + int yInOwner = textBoundsInViewport.y - component.getY(); + Rectangle textBoundsInOwner = new Rectangle(xInOwner, yInOwner, textBoundsInViewport.width, textBoundsInViewport.height); + doPaintStatusText(g, textBoundsInOwner); + + viewport.repaint(textBoundsInViewport); + } + + private void doPaintStatusText(Graphics g, Rectangle textComponentBounds) { + myComponent.setBounds(0, 0, textComponentBounds.width, textComponentBounds.height); + Graphics2D g2 = (Graphics2D)g.create(textComponentBounds.x, textComponentBounds.y, textComponentBounds.width, textComponentBounds.height); myComponent.paint(g2); g2.dispose(); } From ab3f2824d628e203221b50b1dd73fb8ba26a2525 Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Thu, 15 Jan 2015 14:41:44 +0300 Subject: [PATCH 12/39] =?UTF-8?q?Exception=20is=20fixed.=20We=20should=20n?= =?UTF-8?q?ot=20assume=20that=20=D1=84=D0=B4=D0=B4=20IdeFrame=20successors?= =?UTF-8?q?=20are=20frames.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/impl/GlassPaneDialogWrapperPeer.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java b/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java index 3a72b600a269..7717de4a616d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java @@ -131,8 +131,19 @@ public class GlassPaneDialogWrapperPeer extends DialogWrapperPeer implements Foc private void createDialog(final Window owner) throws GlasspanePeerUnavailableException { Window active = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(); if (!(active instanceof JDialog) && owner instanceof IdeFrame) { - final JFrame frame = (JFrame) owner; - final JComponent glassPane = (JComponent) frame.getGlassPane(); + + Component glassPane; + + // Not all successor of IdeFrame are frames + if (owner instanceof JFrame) { + glassPane = ((JFrame)owner).getGlassPane(); + } + else if (owner instanceof JDialog) { + glassPane = ((JDialog)owner).getGlassPane(); + } + else { + throw new IllegalStateException("Cannot find glass pane for " + owner.getClass().getName()); + } assert glassPane instanceof IdeGlassPaneEx : "GlassPane should be instance of IdeGlassPane!"; myDialog = new MyDialog((IdeGlassPaneEx) glassPane, myWrapper, myProject); From 85ba25f728d831315fd4a0a3824bf34cc479040d Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Thu, 15 Jan 2015 11:31:19 +0300 Subject: [PATCH 13/39] IDEA-122329 Sometimes Esc has to be pressed twice to go back to single selection --- .../codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index b4c00b6a7735..094a1fe6ab81 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -42,9 +42,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; -import com.intellij.openapi.editor.colors.EditorColorsListener; import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.ex.RangeHighlighterEx; import com.intellij.openapi.editor.impl.DocumentMarkupModel; import com.intellij.openapi.editor.markup.MarkupModel; @@ -662,6 +660,9 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx implements Pers } ApplicationManager.getApplication().assertIsDispatchThread(); hideLastIntentionHint(); + + if (editor.getCaretModel().getCaretCount() > 1) return; + IntentionHintComponent hintComponent = IntentionHintComponent.showIntentionHint(project, file, editor, intentions, false); if (hasToRecreate) { hintComponent.recreate(); From ea6cd44442fa1aa4ddc0d486df2a92aa83cd48bb Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Thu, 15 Jan 2015 13:05:52 +0100 Subject: [PATCH 14/39] Platform: GCUtil API added --- .../testFramework/PlatformTestUtil.java | 25 ++------- .../util/src/com/intellij/util/GCUtil.java | 51 +++++++++++++++++++ .../util/containers/ConcurrentMapsTest.java | 10 +--- .../util/containers/WeakListTest.java | 9 +--- 4 files changed, 60 insertions(+), 35 deletions(-) create mode 100644 platform/util/src/com/intellij/util/GCUtil.java diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java index 0d2486670e76..fcea0af52bc5 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java @@ -45,11 +45,7 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileFilter; import com.intellij.openapi.vfs.ex.temp.TempFileSystem; -import com.intellij.util.Alarm; -import com.intellij.util.ArrayUtil; -import com.intellij.util.ReflectionUtil; -import com.intellij.util.ThrowableRunnable; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.*; import com.intellij.util.containers.HashMap; import com.intellij.util.io.ZipUtil; import com.intellij.util.ui.UIUtil; @@ -68,8 +64,6 @@ import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.InvocationEvent; import java.io.*; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; import java.nio.charset.Charset; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; @@ -836,21 +830,12 @@ public class PlatformTestUtil { return StringUtil.convertLineSeparators(FileUtil.loadFile(new File(fileName))); } - public static void tryGcSoftlyReachableObjects() { - ReferenceQueue q = new ReferenceQueue(); - SoftReference ref = new SoftReference(new Object(), q); - List list = ContainerUtil.newArrayListWithCapacity(100 + useReference(ref)); - for (int i = 0; i < 100; i++) { - if (q.poll() != null) { - break; - } - list.add(new SoftReference(new byte[(int)Runtime.getRuntime().freeMemory() / 2])); - } + public static void gc() { + GCUtil.tryForceGC(); } - private static int useReference(SoftReference ref) { - Object o = ref.get(); - return o == null ? 0 : Math.abs(o.hashCode()) % 10; + public static void tryGcSoftlyReachableObjects() { + GCUtil.tryGcSoftlyReachableObjects(); } public static void withEncoding(@NotNull String encoding, @NotNull final Runnable r) { diff --git a/platform/util/src/com/intellij/util/GCUtil.java b/platform/util/src/com/intellij/util/GCUtil.java new file mode 100644 index 000000000000..2659d0f92d52 --- /dev/null +++ b/platform/util/src/com/intellij/util/GCUtil.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util; + +import com.intellij.util.containers.ContainerUtil; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.util.List; + +public class GCUtil { + public static void tryForceGC() { + tryGcSoftlyReachableObjects(); + WeakReference weakReference = new WeakReference(new Object()); + do { + System.gc(); + } + while (weakReference.get() != null); + } + + public static void tryGcSoftlyReachableObjects() { + ReferenceQueue q = new ReferenceQueue(); + SoftReference ref = new SoftReference(new Object(), q); + List list = ContainerUtil.newArrayListWithCapacity(100 + useReference(ref)); + for (int i = 0; i < 100; i++) { + if (q.poll() != null) { + break; + } + list.add(new SoftReference(new byte[(int)Runtime.getRuntime().freeMemory() / 2])); + } + } + + private static int useReference(SoftReference ref) { + Object o = ref.get(); + return o == null ? 0 : Math.abs(o.hashCode()) % 10; + } +} diff --git a/platform/util/testSrc/com/intellij/util/containers/ConcurrentMapsTest.java b/platform/util/testSrc/com/intellij/util/containers/ConcurrentMapsTest.java index f97d78434835..7ea422ed99b2 100644 --- a/platform/util/testSrc/com/intellij/util/containers/ConcurrentMapsTest.java +++ b/platform/util/testSrc/com/intellij/util/containers/ConcurrentMapsTest.java @@ -16,11 +16,10 @@ package com.intellij.util.containers; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.GCUtil; import gnu.trove.TObjectHashingStrategy; import org.junit.Test; -import java.lang.ref.SoftReference; -import java.util.List; import java.util.Map; import java.util.Set; @@ -96,12 +95,7 @@ public class ConcurrentMapsTest { } public static void tryGcSoftlyReachableObjects() { - SoftReference reference = new SoftReference(new Object()); - List list = ContainerUtil.newArrayList(); - while (reference.get() != null) { - int chunk = (int)Math.min(Runtime.getRuntime().freeMemory() / 2, Integer.MAX_VALUE); - list.add(new SoftReference(new byte[chunk])); - } + GCUtil.tryGcSoftlyReachableObjects(); } @Test(timeout = TIMEOUT) diff --git a/platform/util/testSrc/com/intellij/util/containers/WeakListTest.java b/platform/util/testSrc/com/intellij/util/containers/WeakListTest.java index f10676905241..3c0b1bf33ab9 100644 --- a/platform/util/testSrc/com/intellij/util/containers/WeakListTest.java +++ b/platform/util/testSrc/com/intellij/util/containers/WeakListTest.java @@ -15,9 +15,9 @@ */ package com.intellij.util.containers; +import com.intellij.util.GCUtil; import org.junit.Test; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -225,11 +225,6 @@ public class WeakListTest { } private static void gc() { - ConcurrentMapsTest.tryGcSoftlyReachableObjects(); - WeakReference weakReference = new WeakReference(new Object()); - do { - System.gc(); - } - while (weakReference.get() != null); + GCUtil.tryForceGC(); } } From 838e6a8931eab91ed9115f5876891fe0137c8723 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 15 Jan 2015 15:15:32 +0300 Subject: [PATCH 15/39] IDEA-135132 Usability issues with resource bundles: NPE in Tab Action on resource bundle editor fixed --- .../intellij/openapi/editor/actionSystem/EditorAction.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java index d93a508f97bd..e5b6abde7bbb 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/actionSystem/EditorAction.java @@ -21,6 +21,7 @@ import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -148,7 +149,10 @@ public abstract class EditorAction extends AnAction implements DumbAware { @Override public Object getData(String dataId) { if (PROJECT.is(dataId)) { - return editor.getProject(); + final Project project = editor.getProject(); + if (project != null) { + return project; + } } return original.getData(dataId); } From eca9ae19ef117de742b88cca4c97323e26aa61fa Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Thu, 15 Jan 2015 13:20:09 +0100 Subject: [PATCH 16/39] SE: respect searching in libraries for symbols --- .../intellij/ide/actions/SearchEverywhereAction.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 60dcc2ea2d06..4bcc12c7164f 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -1565,7 +1565,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private synchronized void buildSymbols(final String pattern) { - final SearchResult symbols = getSymbols(pattern, MAX_SYMBOLS, mySymbolsChooseByName); + final SearchResult symbols = getSymbols(pattern, MAX_SYMBOLS, showAll.get(), mySymbolsChooseByName); check(); if (symbols.size() > 0) { @@ -1670,7 +1670,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - private SearchResult getSymbols(String pattern, final int max, ChooseByNamePopup chooseByNamePopup) { + private SearchResult getSymbols(String pattern, final int max, final boolean includeLibs, ChooseByNamePopup chooseByNamePopup) { final SearchResult symbols = new SearchResult(); if (!Registry.is("search.everywhere.symbols")) { return symbols; @@ -1678,7 +1678,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA final GlobalSearchScope scope = GlobalSearchScope.projectScope(project); if (chooseByNamePopup == null) return symbols; final ChooseByNameItemProvider provider = chooseByNamePopup.getProvider(); - provider.filterElements(chooseByNamePopup, pattern, false, + provider.filterElements(chooseByNamePopup, pattern, includeLibs, myProgressIndicator, new Processor() { @Override public boolean process(Object o) { @@ -1687,7 +1687,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA final PsiFile file = element.getContainingFile(); if (!myListModel.contains(o) && //some elements are non-physical like DB columns - (file == null || (file.getVirtualFile() != null && scope.accept(file.getVirtualFile())))) { + (file == null || (file.getVirtualFile() != null && (includeLibs || scope.accept(file.getVirtualFile()))))) { symbols.add(o); } } @@ -2087,7 +2087,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA = id == WidgetID.CLASSES ? getClasses(pattern, showAll.get(), DEFAULT_MORE_STEP_COUNT, myClassChooseByName) : id == WidgetID.FILES ? getFiles(pattern, DEFAULT_MORE_STEP_COUNT, myFileChooseByName) : id == WidgetID.RUN_CONFIGURATIONS ? getConfigurations(pattern, DEFAULT_MORE_STEP_COUNT) - : id == WidgetID.SYMBOLS ? getSymbols(pattern, DEFAULT_MORE_STEP_COUNT, mySymbolsChooseByName) + : id == WidgetID.SYMBOLS ? getSymbols(pattern, DEFAULT_MORE_STEP_COUNT, showAll.get(), mySymbolsChooseByName) : id == WidgetID.ACTIONS ? getActionsOrSettings(pattern, DEFAULT_MORE_STEP_COUNT, true) : id == WidgetID.SETTINGS ? getActionsOrSettings(pattern, DEFAULT_MORE_STEP_COUNT, false) : new SearchResult(); From a20c09b911490b7243788cbe865de47dec7a32fa Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Thu, 15 Jan 2015 15:40:31 +0300 Subject: [PATCH 17/39] Exception is fixed. Check box can be null. --- .idea/codeStyleSettings.xml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml index 5593bda74b98..d9911d6a1d9a 100644 --- a/.idea/codeStyleSettings.xml +++ b/.idea/codeStyleSettings.xml @@ -107,6 +107,12 @@