From 848c1f215cb8415f6e1d0069e03d90d0fb465667 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Wed, 9 Nov 2016 18:16:23 +0100 Subject: [PATCH] inplace change signature: no detection, explicit action --- .../impl/config/QuickFixFactoryImpl.java | 9 - .../DetectedJavaChangeInfo.java | 70 +--- .../JavaChangeSignatureDetector.java | 148 +------ .../JavaChangeSignatureHandler.java | 72 +++- .../DeleteParamInSuperUsed.java | 2 +- .../changeSignatureGesture/Modifier.java | 2 +- .../Modifier_after.java | 4 + .../NoUsages_after.java | 4 + .../changeSignatureGesture/Simple_after.java | 4 +- .../ChangeSignatureGestureTest.java | 100 ++--- .../actions/BaseRefactoringAction.java | 7 +- .../ChangeSignatureDetectorAction.java | 74 ---- .../ChangeSignatureGestureDetector.java | 392 ------------------ .../DismissNewSignatureIntentionAction.java | 56 --- .../changeSignature/MoveParameterAction.java | 49 --- .../MoveParameterRightAction.java | 26 -- .../inplace/ApplyChangeSignatureAction.java | 80 ++++ .../ChangeSignaturePassFactory.java | 57 +-- .../inplace/EscapeHandler.java | 50 +++ .../inplace/InplaceChangeSignature.java | 213 ++++++++++ .../LanguageChangeSignatureDetector.java | 26 +- .../LanguageChangeSignatureDetectors.java | 7 +- .../{ => inplace}/RenameChangeInfo.java | 13 +- .../src/META-INF/LangExtensionPoints.xml | 2 +- .../src/META-INF/LangExtensions.xml | 1 + .../src/componentSets/Lang.xml | 7 +- .../util/resources/misc/registry.properties | 3 + 27 files changed, 550 insertions(+), 928 deletions(-) create mode 100644 java/java-tests/testData/refactoring/changeSignatureGesture/Modifier_after.java create mode 100644 java/java-tests/testData/refactoring/changeSignatureGesture/NoUsages_after.java delete mode 100644 platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDetectorAction.java delete mode 100644 platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureGestureDetector.java delete mode 100644 platform/lang-impl/src/com/intellij/refactoring/changeSignature/DismissNewSignatureIntentionAction.java delete mode 100644 platform/lang-impl/src/com/intellij/refactoring/changeSignature/MoveParameterAction.java delete mode 100644 platform/lang-impl/src/com/intellij/refactoring/changeSignature/MoveParameterRightAction.java create mode 100644 platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/ApplyChangeSignatureAction.java rename platform/lang-impl/src/com/intellij/refactoring/changeSignature/{ => inplace}/ChangeSignaturePassFactory.java (72%) create mode 100644 platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/EscapeHandler.java create mode 100644 platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/InplaceChangeSignature.java rename platform/lang-impl/src/com/intellij/refactoring/changeSignature/{ => inplace}/LanguageChangeSignatureDetector.java (50%) rename platform/lang-impl/src/com/intellij/refactoring/changeSignature/{ => inplace}/LanguageChangeSignatureDetectors.java (75%) rename platform/lang-impl/src/com/intellij/refactoring/changeSignature/{ => inplace}/RenameChangeInfo.java (89%) diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java index 58293d42b45e..0eeeba2474de 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java @@ -54,7 +54,6 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.ClassKind; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PropertyMemberType; -import com.intellij.refactoring.changeSignature.ChangeSignatureGestureDetector; import com.intellij.util.DocumentUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -703,14 +702,6 @@ public class QuickFixFactoryImpl extends QuickFixFactory { @NotNull @Override public IntentionAction createSafeDeleteFix(@NotNull PsiElement element) { - if (element instanceof PsiMethod) { - PsiMethod method = (PsiMethod)element; - PsiClass containingClass = method.getContainingClass(); - if (method.getReturnType() != null || containingClass != null && Comparing.strEqual(containingClass.getName(), method.getName())) { - //ignore methods with deleted return types as they are always marked as unused without any reason - ChangeSignatureGestureDetector.getInstance(method.getProject()).dismissForElement(method); - } - } return new SafeDeleteFix(element); } diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/DetectedJavaChangeInfo.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/DetectedJavaChangeInfo.java index 4399d8df447d..462de5a8c22e 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/DetectedJavaChangeInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/DetectedJavaChangeInfo.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. @@ -19,12 +19,13 @@ import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.changeSignature.inplace.InplaceChangeSignature; import com.intellij.refactoring.util.CanonicalTypes; import com.intellij.usageView.UsageInfo; import com.intellij.util.IncorrectOperationException; @@ -49,8 +50,8 @@ class DetectedJavaChangeInfo extends JavaChangeInfoImpl { CanonicalTypes.Type newType, @NotNull ParameterInfoImpl[] newParms, ThrownExceptionInfo[] newExceptions, - String newName, String oldName) { - super(newVisibility, method, newName, newType, newParms, newExceptions, false, new HashSet<>(), new HashSet<>(), oldName); + String newName, String oldName, final boolean delegate) { + super(newVisibility, method, newName, newType, newParms, newExceptions, delegate, new HashSet<>(), new HashSet<>(), oldName); final PsiParameter[] parameters = method.getParameterList().getParameters(); myModifiers = new String[parameters.length]; for (int i = 0; i < parameters.length; i++) { @@ -64,28 +65,17 @@ class DetectedJavaChangeInfo extends JavaChangeInfoImpl { } @Nullable - static DetectedJavaChangeInfo createFromMethod(PsiMethod method) { + static DetectedJavaChangeInfo createFromMethod(PsiMethod method, final boolean delegate) { final String newVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList()); final PsiType returnType = method.getReturnType(); - final CanonicalTypes.Type newReturnType; - final ParameterInfoImpl[] parameterInfos; - try { - newReturnType = returnType != null ? CanonicalTypes.createTypeWrapper(returnType) : null; - parameterInfos = ParameterInfoImpl.fromMethod(method); - for (ParameterInfoImpl parameterInfo : parameterInfos) { - if (!parameterInfo.getTypeWrapper().isValid()) { - return null; - } - } - - if (PsiTreeUtil.findChildOfType(method.getParameterList(), PsiErrorElement.class) != null) { + final CanonicalTypes.Type newReturnType = returnType != null ? CanonicalTypes.createTypeWrapper(returnType) : null; + final ParameterInfoImpl[] parameterInfos = ParameterInfoImpl.fromMethod(method); + for (ParameterInfoImpl parameterInfo : parameterInfos) { + if (!parameterInfo.getTypeWrapper().isValid()) { return null; } } - catch (IncorrectOperationException e) { - return null; - } - final DetectedJavaChangeInfo fromMethod = new DetectedJavaChangeInfo(newVisibility, method, newReturnType, parameterInfos, null, method.getName(), method.getName()); + final DetectedJavaChangeInfo fromMethod = new DetectedJavaChangeInfo(newVisibility, method, newReturnType, parameterInfos, null, method.getName(), method.getName(), delegate); final PsiMethod deepestSuperMethod = method.findDeepestSuperMethod(); if (deepestSuperMethod != null) { if (!deepestSuperMethod.getManager().isInProject(deepestSuperMethod)) return null; @@ -120,8 +110,8 @@ class DetectedJavaChangeInfo extends JavaChangeInfoImpl { } @Nullable - ChangeInfo createNextInfo(final PsiMethod method) { - final DetectedJavaChangeInfo fromMethod = createFromMethod(method); + DetectedJavaChangeInfo createNextInfo(final PsiMethod method, boolean delegate) { + final DetectedJavaChangeInfo fromMethod = createFromMethod(method, delegate); if (fromMethod == null) return null; if (!this.equals(fromMethod)) { if (!createParametersInfo(fromMethod.newParms)) return null; @@ -144,7 +134,7 @@ class DetectedJavaChangeInfo extends JavaChangeInfoImpl { try { final DetectedJavaChangeInfo javaChangeInfo = - new DetectedJavaChangeInfo(newVisibility, method, fromMethod.newReturnType, fromMethod.newParms, getNewExceptions(), method.getName(), getOldName()) { + new DetectedJavaChangeInfo(fromMethod.getNewVisibility(), getMethod(), fromMethod.newReturnType, fromMethod.newParms, getNewExceptions(), method.getName(), getOldName(), delegate) { @Override protected void fillOldParams(PsiMethod method) { oldParameterNames = DetectedJavaChangeInfo.this.getOldParameterNames(); @@ -184,7 +174,7 @@ class DetectedJavaChangeInfo extends JavaChangeInfoImpl { getNewReturnType(), (ParameterInfoImpl[])getNewParameters(), getNewExceptions(), getNewName(), - method.getName()) { + method.getName(), false) { @Override protected void fillOldParams(PsiMethod method) { super.fillOldParams(method); @@ -263,14 +253,18 @@ class DetectedJavaChangeInfo extends JavaChangeInfoImpl { boolean perform(ChangeInfo initialChangeInfo, final String oldText, boolean silently) { final PsiMethod method = getSuperMethod(); + Project project = initialChangeInfo.getMethod().getProject(); final PsiMethod currentMethod = (PsiMethod)initialChangeInfo.getMethod(); + final TextRange signatureRange = JavaChangeSignatureDetector.getSignatureRange(currentMethod); + final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + final Document document = documentManager.getDocument(currentMethod.getContainingFile()); if (silently || ApplicationManager.getApplication().isUnitTestMode()) { - final TextRange signatureRange = JavaChangeSignatureDetector.getSignatureRange(currentMethod); final String currentSignature = currentMethod.getContainingFile().getText().substring(signatureRange.getStartOffset(), signatureRange.getEndOffset()); - temporallyRevertChanges(currentMethod, oldText); + InplaceChangeSignature.temporallyRevertChanges(JavaChangeSignatureDetector.getSignatureRange(currentMethod), document, oldText, project); createChangeSignatureProcessor(method).run(); - temporallyRevertChanges(currentMethod, currentSignature, JavaChangeSignatureDetector.getSignatureRange(currentMethod)); + InplaceChangeSignature + .temporallyRevertChanges(JavaChangeSignatureDetector.getSignatureRange(currentMethod), document, currentSignature, project); return true; } final JavaMethodDescriptor descriptor = new JavaMethodDescriptor(currentMethod) { @@ -288,7 +282,7 @@ class DetectedJavaChangeInfo extends JavaChangeInfoImpl { @Override protected void invokeRefactoring(final BaseRefactoringProcessor processor) { CommandProcessor.getInstance().executeCommand(myProject, () -> { - temporallyRevertChanges(method, oldText); + InplaceChangeSignature.temporallyRevertChanges(JavaChangeSignatureDetector.getSignatureRange(currentMethod), document, oldText, project); doRefactor(processor); }, RefactoringBundle.message("changing.signature.of.0", DescriptiveNameUtil.getDescriptiveName(currentMethod)), null); } @@ -299,22 +293,4 @@ class DetectedJavaChangeInfo extends JavaChangeInfoImpl { }; return dialog.showAndGet(); } - - private static void temporallyRevertChanges(final PsiElement psiElement, final String oldText) { - temporallyRevertChanges(psiElement, oldText, psiElement.getTextRange()); - } - - private static void temporallyRevertChanges(final PsiElement psiElement, - final String oldText, - final TextRange textRange) { - ApplicationManager.getApplication().runWriteAction(() -> { - final PsiFile file = psiElement.getContainingFile(); - final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(psiElement.getProject()); - final Document document = documentManager.getDocument(file); - if (document != null) { - document.replaceString(textRange.getStartOffset(), textRange.getEndOffset(), oldText); - documentManager.commitDocument(document); - } - }); - } } diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDetector.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDetector.java index 3307b304c1a8..4df9ba000ccf 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDetector.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDetector.java @@ -15,75 +15,41 @@ */ package com.intellij.refactoring.changeSignature; -import com.intellij.lang.Language; -import com.intellij.lang.StdLanguages; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.changeSignature.inplace.LanguageChangeSignatureDetector; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * User: anna * Date: Sep 6, 2010 */ -public class JavaChangeSignatureDetector implements LanguageChangeSignatureDetector { +public class JavaChangeSignatureDetector implements LanguageChangeSignatureDetector { private static final Logger LOG = Logger.getInstance("#" + JavaChangeSignatureDetector.class.getName()); + @NotNull @Override - public ChangeInfo createInitialChangeInfo(final @NotNull PsiElement element) { - final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); - if (method != null && isInsideMethodSignature(element, method)) { - //do not initialize change signature on return type change - if (element.getTextRange().getEndOffset() <= method.getTextOffset()) return null; - return DetectedJavaChangeInfo.createFromMethod(method); - } else { - final PsiVariable variable = PsiTreeUtil.getParentOfType(element, PsiVariable.class); - if (variable != null) { - return new RenameChangeInfo(variable, null) { - @Override - public Language getLanguage() { - return StdLanguages.JAVA; - } - }; - } - } - return null; + public DetectedJavaChangeInfo createInitialChangeInfo(final @NotNull PsiElement element) { + return DetectedJavaChangeInfo.createFromMethod(PsiTreeUtil.getParentOfType(element, PsiMethod.class), false); } @Override - public boolean performChange(final ChangeInfo changeInfo, ChangeInfo initialChangeInfo, @NotNull final String oldText, boolean silently) { - if (changeInfo instanceof DetectedJavaChangeInfo) { - return ((DetectedJavaChangeInfo)changeInfo).perform(initialChangeInfo, oldText, silently); - } else if (changeInfo instanceof RenameChangeInfo) { - ((RenameChangeInfo)changeInfo).perform(); - return true; - } - return false; - + public void performChange(final DetectedJavaChangeInfo changeInfo, @NotNull final String oldText) { + changeInfo.perform(changeInfo, oldText, true); } @Override - public boolean isChangeSignatureAvailableOnElement(PsiElement element, ChangeInfo currentInfo) { - if (currentInfo instanceof RenameChangeInfo) { - final PsiElement nameIdentifier = ((RenameChangeInfo)currentInfo).getNameIdentifier(); - if (nameIdentifier != null) { - final TextRange nameIdentifierTextRange = nameIdentifier.getTextRange(); - return nameIdentifierTextRange.contains(element.getTextRange()) || - nameIdentifierTextRange.getEndOffset() == element.getTextOffset(); - } + public boolean isChangeSignatureAvailableOnElement(PsiElement element, DetectedJavaChangeInfo currentInfo) { + final PsiMethod method = currentInfo.getMethod(); + TextRange range = method.getTextRange(); + PsiCodeBlock body = method.getBody(); + if (body != null) { + range = new TextRange(range.getStartOffset(), body.getTextOffset()); } - else if (currentInfo instanceof JavaChangeInfo) { - final PsiMethod method = (PsiMethod)currentInfo.getMethod(); - return getSignatureRange(method).contains(element.getTextRange()); - } - return false; + return element.getContainingFile() == method.getContainingFile() && range.contains(element.getTextRange()); } @Override @@ -92,56 +58,28 @@ public class JavaChangeSignatureDetector implements LanguageChangeSignatureDetec return PsiTreeUtil.getParentOfType(element, PsiImportList.class) != null; } - @Nullable @Override - public TextRange getHighlightingRange(ChangeInfo changeInfo) { - if (changeInfo == null) return null; - if (changeInfo instanceof RenameChangeInfo) { - PsiElement nameIdentifier = ((RenameChangeInfo)changeInfo).getNameIdentifier(); - return nameIdentifier != null ? nameIdentifier.getTextRange() : null; - } - + public TextRange getHighlightingRange(@NotNull DetectedJavaChangeInfo changeInfo) { PsiElement method = changeInfo.getMethod(); - return method instanceof PsiMethod ? getSignatureRange((PsiMethod)method) : null; - } - - @Nullable - @Override - public String extractSignature(PsiElement element, @NotNull ChangeInfo initialChangeInfo) { - final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); - if (method != null && isInsideMethodSignature(element, method) && method == initialChangeInfo.getMethod()) { - final TextRange signatureRange = getSignatureRange(method); - return signatureRange.shiftRight(-signatureRange.getStartOffset()).substring(method.getText()); - } else if (element instanceof PsiIdentifier && element.getParent() instanceof PsiNamedElement) { - return element.getText(); - } - return null; + return method != null ? getSignatureRange((PsiMethod)method) : null; } @Override - public ChangeInfo createNextChangeInfo(String signature, @NotNull final ChangeInfo currentInfo, String initialName) { + public DetectedJavaChangeInfo createNextChangeInfo(String signature, @NotNull final DetectedJavaChangeInfo currentInfo, boolean delegate) { final PsiElement currentInfoMethod = currentInfo.getMethod(); if (currentInfoMethod == null) { return null; } final Project project = currentInfoMethod.getProject(); - if (currentInfo instanceof RenameChangeInfo) { - return currentInfo; - } - - final PsiMethod oldMethod = (PsiMethod)currentInfo.getMethod(); + + final PsiMethod oldMethod = currentInfo.getMethod(); String visibility = ""; PsiClass containingClass = oldMethod.getContainingClass(); if (containingClass != null && containingClass.isInterface()) { visibility = PsiModifier.PUBLIC + " "; } PsiMethod method = JavaPsiFacade.getElementFactory(project).createMethodFromText((visibility + signature).trim(), oldMethod); - return ((DetectedJavaChangeInfo)currentInfo).createNextInfo(method); - } - - private static boolean isInsideMethodSignature(PsiElement element, @NotNull PsiMethod method) { - final TextRange textRange = element.getTextRange(); - return getSignatureRange(method).contains(textRange); + return currentInfo.createNextInfo(method, delegate); } public static TextRange getSignatureRange(PsiMethod method) { @@ -149,50 +87,4 @@ public class JavaChangeSignatureDetector implements LanguageChangeSignatureDetec int startOffset = method.getTextRange().getStartOffset(); return new TextRange(startOffset, endOffset); } - - @Override - public boolean isMoveParameterAvailable(PsiElement element, boolean left) { - if (element instanceof PsiParameter) { - final PsiParameter parameter = (PsiParameter)element; - final PsiElement declarationScope = parameter.getDeclarationScope(); - if (declarationScope instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)declarationScope; - final int parameterIndex = method.getParameterList().getParameterIndex(parameter); - if (left) { - return parameterIndex > 0; - } else { - return parameterIndex < method.getParameterList().getParametersCount() - 1; - } - } - } - return false; - } - - @Override - public void moveParameter(final PsiElement element, final Editor editor, final boolean left) { - final PsiParameter parameter = (PsiParameter)element; - final PsiMethod method = (PsiMethod)parameter.getDeclarationScope(); - final int parameterIndex = method.getParameterList().getParameterIndex(parameter); - new WriteCommandAction(element.getProject(), MOVE_PARAMETER){ - @Override - protected void run(@NotNull Result result) throws Throwable { - final PsiParameterList parameterList = method.getParameterList(); - final PsiParameter[] parameters = parameterList.getParameters(); - final int deltaOffset = editor.getCaretModel().getOffset() - parameter.getTextRange().getStartOffset(); - final PsiParameter frst = left ? parameters[parameterIndex - 1] : parameter; - final PsiParameter scnd = left ? parameter : parameters[parameterIndex + 1]; - final int startOffset = frst.getTextRange().getStartOffset(); - final int endOffset = scnd.getTextRange().getEndOffset(); - - final PsiFile file = method.getContainingFile(); - final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(file); - if (document != null) { - final String comma_whitespace_between = - document.getText().substring(frst.getTextRange().getEndOffset(), scnd.getTextRange().getStartOffset()); - document.replaceString(startOffset, endOffset, scnd.getText() + comma_whitespace_between + frst.getText()); - editor.getCaretModel().moveToOffset(document.getText().indexOf(parameter.getText(), startOffset) + deltaOffset); - } - } - }.execute(); - } } diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureHandler.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureHandler.java index fde6c80c178b..d5d47bb85093 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 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. @@ -19,22 +19,31 @@ import com.intellij.codeInsight.JavaTargetElementEvaluator; import com.intellij.ide.util.SuperMethodWarningUtil; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.changeClassSignature.ChangeClassSignatureDialog; +import com.intellij.refactoring.changeSignature.inplace.InplaceChangeSignature; import com.intellij.refactoring.util.CommonRefactoringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; +import java.util.List; + public class JavaChangeSignatureHandler implements ChangeSignatureHandler { + private static final Logger LOG = Logger.getInstance(JavaChangeSignatureHandler.class); + public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); PsiElement element = findTargetMember(file, editor); @@ -45,16 +54,7 @@ public class JavaChangeSignatureHandler implements ChangeSignatureHandler { } private static void invokeOnElement(Project project, @Nullable Editor editor, PsiElement element) { - if (element instanceof PsiMethod) { - /*final ChangeSignatureGestureDetector detector = ChangeSignatureGestureDetector.getInstance(project); - final PsiIdentifier nameIdentifier = ((PsiMethod)element).getNameIdentifier(); - if (nameIdentifier != null && - editor != null && - editor.getDocument().isWritable() && - detector.isChangeSignatureAvailable(element)) { - detector.changeSignature(element.getContainingFile(), false); - return; - }*/ + if (element instanceof PsiMethod && ((PsiMethod)element).getNameIdentifier() != null) { invoke((PsiMethod) element, project, editor); } else if (element instanceof PsiClass) { @@ -92,8 +92,54 @@ public class JavaChangeSignatureHandler implements ChangeSignatureHandler { final PsiClass containingClass = method.getContainingClass(); final PsiReferenceExpression refExpr = editor != null ? JavaTargetElementEvaluator.findReferenceExpression(editor) : null; final boolean allowDelegation = containingClass != null && (!containingClass.isInterface() || PsiUtil.isLanguageLevel8OrHigher(containingClass)); - final DialogWrapper dialog = new JavaChangeSignatureDialog(project, method, allowDelegation, refExpr == null ? method : refExpr); - dialog.show(); + InplaceChangeSignature inplaceChangeSignature = InplaceChangeSignature.getCurrentRefactoring(editor); + ChangeInfo initialChange = inplaceChangeSignature != null ? inplaceChangeSignature.getStableChange() : null; + + boolean isInplace = Registry.is("inplace.change.signature") && editor != null && editor.getSettings().isVariableInplaceRenameEnabled() && (initialChange == null || initialChange.getMethod() != method); + PsiIdentifier nameIdentifier = method.getNameIdentifier(); + LOG.assertTrue(nameIdentifier != null); + if (isInplace) { + CommandProcessor.getInstance().executeCommand(project, () -> new InplaceChangeSignature(project, editor, nameIdentifier), REFACTORING_NAME, null); + } + else { + JavaMethodDescriptor methodDescriptor = new JavaMethodDescriptor(method); + if (initialChange != null) { + JavaChangeInfo currentInfo = (JavaChangeInfo)inplaceChangeSignature.getCurrentInfo(); + if (currentInfo != null) { + methodDescriptor = new JavaMethodDescriptor(method) { + @Override + public String getName() { + return currentInfo.getNewName(); + } + + @Override + public List getParameters() { + return Arrays.asList((ParameterInfoImpl[])currentInfo.getNewParameters()); + } + + @Override + public String getVisibility() { + return currentInfo.getNewVisibility(); + } + + + @Override + public int getParametersCount() { + return currentInfo.getNewParameters().length; + } + + @Nullable + @Override + public String getReturnTypeText() { + return currentInfo.getNewReturnType().getTypeText(); + } + }; + } + inplaceChangeSignature.cancel(); + } + final DialogWrapper dialog = new JavaChangeSignatureDialog(project, methodDescriptor, allowDelegation, refExpr == null ? method : refExpr); + dialog.show(); + } } private static void invoke(final PsiClass aClass, Editor editor) { diff --git a/java/java-tests/testData/refactoring/changeSignatureGesture/DeleteParamInSuperUsed.java b/java/java-tests/testData/refactoring/changeSignatureGesture/DeleteParamInSuperUsed.java index 080e28e0ae2b..4693138c92d3 100644 --- a/java/java-tests/testData/refactoring/changeSignatureGesture/DeleteParamInSuperUsed.java +++ b/java/java-tests/testData/refactoring/changeSignatureGesture/DeleteParamInSuperUsed.java @@ -5,7 +5,7 @@ public class Parent { } class Child extends Parent { - public void foo(float j, int i, String s ) { + public void foo(float j, int i, String s ) { } void bar() { diff --git a/java/java-tests/testData/refactoring/changeSignatureGesture/Modifier.java b/java/java-tests/testData/refactoring/changeSignatureGesture/Modifier.java index 0fe7f48dc2ea..a00b2b28f4ce 100644 --- a/java/java-tests/testData/refactoring/changeSignatureGesture/Modifier.java +++ b/java/java-tests/testData/refactoring/changeSignatureGesture/Modifier.java @@ -1,4 +1,4 @@ class Test { - void foo() { + void foo() { } } \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignatureGesture/Modifier_after.java b/java/java-tests/testData/refactoring/changeSignatureGesture/Modifier_after.java new file mode 100644 index 000000000000..c61cf44003d7 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignatureGesture/Modifier_after.java @@ -0,0 +1,4 @@ +class Test { + private void foo() { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignatureGesture/NoUsages_after.java b/java/java-tests/testData/refactoring/changeSignatureGesture/NoUsages_after.java new file mode 100644 index 000000000000..c1d60b16da53 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignatureGesture/NoUsages_after.java @@ -0,0 +1,4 @@ +package refactoring.changeSignatureGesture; +class Test { + private void myverylonagname(int param){} +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignatureGesture/Simple_after.java b/java/java-tests/testData/refactoring/changeSignatureGesture/Simple_after.java index 5cbb7db4d3aa..dc985d8d7ba5 100644 --- a/java/java-tests/testData/refactoring/changeSignatureGesture/Simple_after.java +++ b/java/java-tests/testData/refactoring/changeSignatureGesture/Simple_after.java @@ -1,6 +1,6 @@ class Test { - void foo(int iparam) { - System.out.println(iparam); + void foo(int i, int param) { + System.out.println(i); } void bar(){foo();} } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureGestureTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureGestureTest.java index d04f12b4684e..6433ec1cb1f6 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureGestureTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureGestureTest.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. @@ -25,64 +25,62 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actions.EditorActionUtil; import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.psi.*; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiTypeElement; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.refactoring.changeSignature.ChangeSignatureDetectorAction; -import com.intellij.refactoring.changeSignature.ChangeSignatureGestureDetector; +import com.intellij.refactoring.changeSignature.ChangeSignatureHandler; +import com.intellij.refactoring.changeSignature.inplace.ApplyChangeSignatureAction; +import com.intellij.refactoring.changeSignature.inplace.InplaceChangeSignature; +import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; -import java.util.List; +import java.util.Optional; /** * User: anna * Date: Sep 9, 2010 */ +@PlatformTestCase.WrapInCommand public class ChangeSignatureGestureTest extends LightCodeInsightFixtureTestCase { - private void doTest(final Runnable run, boolean shouldShow, final String hint) { + private void doTest(final Runnable run, boolean shouldShow) { myFixture.configureByFile("/refactoring/changeSignatureGesture/" + getTestName(false) + ".java"); myFixture.enableInspections(new UnusedDeclarationInspection()); - final ChangeSignatureGestureDetector detector = ChangeSignatureGestureDetector.getInstance(getProject()); final EditorEx editor = (EditorEx)myFixture.getEditor(); final Document document = editor.getDocument(); - try { - PsiManager.getInstance(getProject()).addPsiTreeChangeListener(detector); - detector.addDocListener(document); - new WriteCommandAction.Simple(getProject()) { - @Override - protected void run() throws Throwable { - run.run(); - } - }.execute().throwException(); + CommandProcessor.getInstance().executeCommand(myFixture.getProject(), () -> new InplaceChangeSignature(myFixture.getProject(), editor, myFixture.getFile().findElementAt(myFixture.getCaretOffset())), + ChangeSignatureHandler.REFACTORING_NAME, null); + new WriteCommandAction.Simple(getProject()) { + @Override + protected void run() throws Throwable { + run.run(); + } + }.execute().throwException(); - myFixture.doHighlighting(); - if (shouldShow) { - final IntentionAction intention = myFixture.findSingleIntention(hint); - myFixture.launchAction(intention); - myFixture.checkResultByFile("/refactoring/changeSignatureGesture/" + getTestName(false) + "_after.java"); - } - else { - final List intentionActions = myFixture.filterAvailableIntentions(hint); - assertEmpty(intentionActions); - } + myFixture.doHighlighting(); + Optional intentionAction = + myFixture.getAvailableIntentions().stream().filter(action -> action instanceof ApplyChangeSignatureAction).findFirst(); + if (shouldShow) { + final IntentionAction intention = intentionAction.orElse(null); + assertNotNull(intention); + myFixture.launchAction(intention); + myFixture.checkResultByFile("/refactoring/changeSignatureGesture/" + getTestName(false) + "_after.java"); } - finally { - detector.removeDocListener(document, editor.getVirtualFile()); - PsiManager.getInstance(getProject()).removePsiTreeChangeListener(detector); + else { + assertFalse(intentionAction.isPresent()); } } public void testSimple() { - doTypingTest("param"); + doTypingTest(", int param"); } - public void testSpaces() { - doTypingNoBorderTest(" "); - } public void testNoUsages() { - doTypingNoBorderTest("int param"); + doTypingTest("int param"); } public void testOccurrencesInSameFile() { @@ -97,18 +95,6 @@ public class ChangeSignatureGestureTest extends LightCodeInsightFixtureTestCase doTypingTest("int param"); } - public void testAddParameter2UnusedConstructor() { - doTypingNoBorderTest("int param"); - } - - public void testOnAnotherMethod() { - doTest(() -> { - myFixture.type("int param"); - final int nextMethodOffset = ((PsiJavaFile)myFixture.getFile()).getClasses()[0].getMethods()[1].getTextOffset(); - myFixture.getEditor().getCaretModel().moveToOffset(nextMethodOffset); - }, false, ChangeSignatureDetectorAction.CHANGE_SIGNATURE); - } - public void testAddParamChangeReturnType() { doTest(() -> { myFixture.type("int param"); @@ -125,7 +111,7 @@ public class ChangeSignatureGestureTest extends LightCodeInsightFixtureTestCase myFixture.type('\b'); } myFixture.type("boolean"); - }, true, ChangeSignatureDetectorAction.CHANGE_SIGNATURE); + }, true); } public void testNewParam() { @@ -140,24 +126,12 @@ public class ChangeSignatureGestureTest extends LightCodeInsightFixtureTestCase doTypingTest(", int param"); } - public void testRenameLocalVariable() { - doTypingTest("1", ChangeSignatureDetectorAction.NEW_NAME); - } - private void doTypingTest(final String param) { - doTypingTest(param, ChangeSignatureDetectorAction.CHANGE_SIGNATURE); - } - - private void doTypingTest(final String param, final String hint) { - doTest(() -> myFixture.type(param), true, hint); - } - - public void testReturnValue() { - doTypingNoBorderTest("void"); + doTest(() -> myFixture.type(param), true); } public void testModifier() { - doTypingNoBorderTest("private"); + doTypingTest("private "); } public void testAddParameterFinal() { @@ -165,7 +139,7 @@ public class ChangeSignatureGestureTest extends LightCodeInsightFixtureTestCase } private void doTypingNoBorderTest(final String param) { - doTest(() -> myFixture.type(param), false, ChangeSignatureDetectorAction.CHANGE_SIGNATURE); + doTest(() -> myFixture.type(param), false); } public void testDeleteParamInSuperUsed() { @@ -187,7 +161,7 @@ public class ChangeSignatureGestureTest extends LightCodeInsightFixtureTestCase CommandProcessor.getInstance().setCurrentCommandGroupId(EditorActionUtil.DELETE_COMMAND_GROUP); document.deleteString(selectionStart, selectionEnd); editor.getCaretModel().moveToOffset(selectionStart); - }, true, ChangeSignatureDetectorAction.CHANGE_SIGNATURE); + }, true); } @Override diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java index 7fbad12a03b0..a0928a10b475 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -104,12 +104,13 @@ public abstract class BaseRefactoringAction extends AnAction { return; } - if (!InplaceRefactoring.canStartAnotherRefactoring(editor, project, handler, elements)) { + InplaceRefactoring activeInplaceRenamer = InplaceRefactoring.getActiveInplaceRenamer(editor); + if (!InplaceRefactoring.canStartAnotherRefactoring(editor, project, handler, elements) && activeInplaceRenamer != null) { InplaceRefactoring.unableToStartWarning(project, editor); return; } - if (InplaceRefactoring.getActiveInplaceRenamer(editor) == null) { + if (activeInplaceRenamer == null) { final LookupEx lookup = LookupManager.getActiveLookup(editor); if (lookup instanceof LookupImpl) { Runnable command = () -> ((LookupImpl)lookup).finishLookup(Lookup.NORMAL_SELECT_CHAR); diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDetectorAction.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDetectorAction.java deleted file mode 100644 index 5fe93571cd32..000000000000 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDetectorAction.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2000-2010 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.refactoring.changeSignature; - -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.refactoring.BaseRefactoringIntentionAction; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; - -/** - * User: anna - * Date: Sep 6, 2010 - */ -public class ChangeSignatureDetectorAction extends BaseRefactoringIntentionAction { - public static final String CHANGE_SIGNATURE = "Apply signature change"; - public static final String NEW_NAME = "Apply new name"; - - private String myAcceptText; - - @NotNull - @Override - public String getText() { - final String text = myAcceptText; - return text != null ? text : CHANGE_SIGNATURE; - } - - @NotNull - @Override - public String getFamilyName() { - return CHANGE_SIGNATURE; - } - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - myAcceptText = null; - final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(element.getLanguage()); - if (detector != null) { - ChangeSignatureGestureDetector signatureGestureDetector = ChangeSignatureGestureDetector.getInstance(project); - PsiFile containingFile = element.getContainingFile(); - ChangeInfo changeInfo = signatureGestureDetector.getChangeInfo(containingFile); - ChangeInfo initialChangeInfo = signatureGestureDetector.getInitialChangeInfo(containingFile); - if (changeInfo != null && detector.isChangeSignatureAvailableOnElement(element, initialChangeInfo)) { - myAcceptText = changeInfo instanceof RenameChangeInfo ? NEW_NAME : CHANGE_SIGNATURE; - } - } - return myAcceptText != null; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - ChangeSignatureGestureDetector.getInstance(project).changeSignature(element.getContainingFile(), true); - } - - @Override - public boolean startInWriteAction() { - return false; - } -} diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureGestureDetector.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureGestureDetector.java deleted file mode 100644 index 7975f5864004..000000000000 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureGestureDetector.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * 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 com.intellij.refactoring.changeSignature; - -import com.intellij.codeInsight.template.TemplateManager; -import com.intellij.idea.ActionsBundle; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.EditorBundle; -import com.intellij.openapi.editor.EditorFactory; -import com.intellij.openapi.editor.actions.EditorActionUtil; -import com.intellij.openapi.editor.event.DocumentAdapter; -import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.editor.event.EditorFactoryEvent; -import com.intellij.openapi.editor.event.EditorFactoryListener; -import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileEditor.FileEditor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.TextEditor; -import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiUtilCore; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.HashMap; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * User: anna - * Date: Sep 6, 2010 - */ -public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter implements EditorFactoryListener, Disposable { - private final Map myListenerMap = new HashMap<>(); - private static final Logger LOG = Logger.getInstance("#" + ChangeSignatureGestureDetector.class.getName()); - private boolean myDeaf = false; - private final FileDocumentManager myDocumentManager; - private final PsiManager myPsiManager; - private final FileEditorManager myFileEditorManager; - private final Project myProject; - private final PsiDocumentManager myPsiDocumentManager; - - public ChangeSignatureGestureDetector(final PsiDocumentManager psiDocumentManager, - final FileDocumentManager documentManager, - final PsiManager psiManager, - final FileEditorManager fileEditorManager, - final Project project) { - myDocumentManager = documentManager; - myPsiDocumentManager = psiDocumentManager; - myPsiManager = psiManager; - myFileEditorManager = fileEditorManager; - myProject = project; - myPsiManager.addPsiTreeChangeListener(this, this); - EditorFactory.getInstance().addEditorFactoryListener(this, this); - Disposer.register(this, new Disposable() { - @Override - public void dispose() { - LOG.assertTrue(myListenerMap.isEmpty(), myListenerMap); - } - }); - } - - public static ChangeSignatureGestureDetector getInstance(Project project){ - return project.getComponent(ChangeSignatureGestureDetector.class); - } - - public boolean isChangeSignatureAvailable(@NotNull PsiElement element) { - final MyDocumentChangeAdapter adapter = myListenerMap.get(PsiUtilCore.getVirtualFile(element)); - if (adapter != null) { - final ChangeInfo currentInfo = adapter.getCurrentInfo(); - if (currentInfo != null && element.equals(adapter.getInitialChangeInfo().getMethod())) { - return true; - } - } - return false; - } - - public void dismissForElement(PsiElement method) { - final PsiFile psiFile = method.getContainingFile(); - final ChangeInfo initialChangeInfo = getInitialChangeInfo(psiFile); - if (initialChangeInfo != null && initialChangeInfo.getMethod() == method) { - clearSignatureChange(psiFile); - } - } - - public boolean containsChangeSignatureChange(@NotNull PsiFile file) { - return getChangeInfo(file) != null; - } - - @Nullable - public ChangeInfo getChangeInfo(@NotNull PsiFile file) { - final MyDocumentChangeAdapter adapter = myListenerMap.get(file.getVirtualFile()); - return adapter != null ? adapter.getCurrentInfo() : null; - } - - @Nullable - public ChangeInfo getInitialChangeInfo(@NotNull PsiFile file) { - final MyDocumentChangeAdapter adapter = myListenerMap.get(file.getVirtualFile()); - return adapter != null ? adapter.getInitialChangeInfo() : null; - } - - public void changeSignature(PsiFile file, final boolean silently) { - try { - myDeaf = true; - final MyDocumentChangeAdapter changeBean = myListenerMap.get(file.getVirtualFile()); - final ChangeInfo currentInfo = changeBean.getCurrentInfo(); - if (currentInfo != null) { - final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(currentInfo.getLanguage()); - if (detector.performChange(currentInfo, changeBean.getInitialChangeInfo(), changeBean.getInitialText(), silently)) { - changeBean.reinit(); - } - } - } - finally { - myDeaf = false; - } - } - - @Override - public void beforeChildRemoval(@NotNull PsiTreeChangeEvent event) { - final PsiElement child = event.getChild(); - if (child instanceof PsiFile) { - final PsiFile psiFile = (PsiFile)child; - final VirtualFile virtualFile = psiFile.getVirtualFile(); - if (virtualFile != null && myListenerMap.containsKey(virtualFile)) { - final Document document = myDocumentManager.getDocument(virtualFile); - if (document != null) { - removeDocListener(document, virtualFile); - } else { - myListenerMap.remove(virtualFile); - } - } - } - } - - @Override - public void childRemoved(@NotNull PsiTreeChangeEvent event) { - change(event.getParent()); - } - - @Override - public void childReplaced(@NotNull PsiTreeChangeEvent event) { - change(event.getChild()); - } - - @Override - public void childAdded(@NotNull PsiTreeChangeEvent event) { - change(event.getChild()); - } - - private void change(PsiElement child) { - if (myDeaf) return; - if (child == null || !child.isValid()) return; - final PsiFile file = child.getContainingFile(); - if (file != null) { - final MyDocumentChangeAdapter changeBean = myListenerMap.get(file.getVirtualFile()); - if (changeBean != null && changeBean.getInitialText() != null) { - final Editor editor = myFileEditorManager.getSelectedTextEditor(); - if (editor != null && TemplateManager.getInstance(myProject).getActiveTemplate(editor) != null) return; - final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(child.getLanguage()); - if (detector == null) return; - if (detector.ignoreChanges(child)) return; - final String currentSignature = detector.extractSignature(child, changeBean.getInitialChangeInfo()); - if (currentSignature == null) { - changeBean.reinit(); - } else { - changeBean.addSignature(currentSignature); - } - } - } - } - - @Override - public void editorCreated(@NotNull EditorFactoryEvent event) { - final Editor editor = event.getEditor(); - if (editor.getProject() != myProject) return; - addDocListener(editor.getDocument()); - } - - public void addDocListener(Document document) { - if (document == null) return; - final VirtualFile file = myDocumentManager.getFile(document); - if (file != null && file.isValid() && !myListenerMap.containsKey(file)) { - final PsiFile psiFile = myPsiManager.findFile(file); - if (psiFile == null || !psiFile.isPhysical()) return; - final MyDocumentChangeAdapter adapter = new MyDocumentChangeAdapter(); - document.addDocumentListener(adapter); - myListenerMap.put(file, adapter); - } - } - - @Override - public void editorReleased(@NotNull EditorFactoryEvent event) { - final EditorEx editor = (EditorEx)event.getEditor(); - final Document document = editor.getDocument(); - - VirtualFile file = myDocumentManager.getFile(document); - if (file == null) { - file = editor.getVirtualFile(); - } - if (file != null && file.isValid()) { - for (FileEditor fileEditor : myFileEditorManager.getAllEditors(file)) { - if (fileEditor instanceof TextEditor && ((TextEditor)fileEditor).getEditor() != editor) { - return; - } - } - } - removeDocListener(document, file); - } - - public void removeDocListener(Document document, VirtualFile file) { - final MyDocumentChangeAdapter adapter = myListenerMap.remove(file); - if (adapter != null) { - document.removeDocumentListener(adapter); - } - } - - public void clearSignatureChange(PsiFile file) { - final MyDocumentChangeAdapter adapter = myListenerMap.get(file.getVirtualFile()); - if (adapter != null) { - adapter.reinit(); - } - } - - @Nullable - private static ChangeInfo createCurrentChangeInfo(String signature, @NotNull ChangeInfo currentInfo, String initialName) { - final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(currentInfo.getLanguage()); - return detector != null ? detector.createNextChangeInfo(signature, currentInfo, initialName) : null; - } - - @Nullable - private static ChangeInfo createInitialChangeInfo(@NotNull PsiElement element) { - final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(element.getLanguage()); - return detector != null ? detector.createInitialChangeInfo(element) : null; - } - - private class MyDocumentChangeAdapter extends DocumentAdapter { - private final @NonNls String [] COMMANDS = { - EditorBundle.message("paste.command.name"), - EditorBundle.message("typing.in.editor.command.name"), - ActionsBundle.message("action.MoveElementLeft.text"), - ActionsBundle.message("action.MoveElementRight.text"), - "Cut", - LanguageChangeSignatureDetector.MOVE_PARAMETER - }; - - private String myInitialText; - private String myInitialName; - private ChangeInfo myInitialChangeInfo; - private ChangeInfo myCurrentInfo; - - private final List mySignatures = new ArrayList<>(); - - public MyDocumentChangeAdapter() { - } - - public String getInitialText() { - return myInitialText; - } - - public ChangeInfo getCurrentInfo() { - if (myInitialChangeInfo == null) return null; - synchronized (mySignatures) { - if (!mySignatures.isEmpty()) { - if (myCurrentInfo == null) { - myCurrentInfo = myInitialChangeInfo; - } - - for (String signature : mySignatures) { - if (myInitialText.equals(signature)) { - reinit(); - break; - } - try { - myCurrentInfo = createCurrentChangeInfo(signature, myCurrentInfo, myInitialName); - if (myCurrentInfo == null) { - reinit(); - break; - } - } - catch (IncorrectOperationException ignore) { - } - } - mySignatures.clear(); - } - } - if (myCurrentInfo instanceof RenameChangeInfo) return myCurrentInfo; - return myInitialChangeInfo != null && myInitialChangeInfo.equals(myCurrentInfo) ? null : myCurrentInfo; - } - - public void addSignature(String signature) { - synchronized (mySignatures) { - if (!mySignatures.contains(signature)) { - mySignatures.add(signature); - } - } - } - - @Override - public void beforeDocumentChange(DocumentEvent e) { - if (myDeaf) return; - if (DumbService.isDumb(myProject)) return; - if (myInitialText == null) { - final Document document = e.getDocument(); - final PsiDocumentManager documentManager = myPsiDocumentManager; - - if (!documentManager.isUncommited(document)) { - final CommandProcessor processor = CommandProcessor.getInstance(); - final String currentCommandName = processor.getCurrentCommandName(); - - if (!isPredefinedCommand(processor, currentCommandName)) return; - - final PsiFile file = documentManager.getPsiFile(document); - if (file != null) { - final PsiElement element = file.findElementAt(e.getOffset()); - if (element != null) { - final ChangeInfo info = createInitialChangeInfo(element); - if (info != null) { - final PsiElement method = info.getMethod(); - final TextRange textRange = method.getTextRange(); - if (document.getTextLength() <= textRange.getEndOffset()) return; - if (method instanceof PsiNameIdentifierOwner) { - myInitialName = ((PsiNameIdentifierOwner)method).getName(); - } - myInitialText = document.getText(textRange); - myInitialChangeInfo = info; - } - } - } - } - } - } - - private boolean isPredefinedCommand(CommandProcessor processor, String currentCommandName) { - if (Comparing.equal(EditorActionUtil.DELETE_COMMAND_GROUP, processor.getCurrentCommandGroupId())) { - return true; - } - - for (String commandName : COMMANDS) { - if (Comparing.strEqual(commandName, currentCommandName)){ - return true; - } - } - return false; - } - - public ChangeInfo getInitialChangeInfo() { - return myInitialChangeInfo; - } - - public void reinit() { - synchronized (mySignatures) { - mySignatures.clear(); - } - myInitialText = null; - myInitialName = null; - myInitialChangeInfo = null; - myCurrentInfo = null; - } - } - - @Override - public void dispose() { - - } -} diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/DismissNewSignatureIntentionAction.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/DismissNewSignatureIntentionAction.java deleted file mode 100644 index 46eb7ae6aa31..000000000000 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/DismissNewSignatureIntentionAction.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2000-2011 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.refactoring.changeSignature; - -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiFile; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NotNull; - -/** - * User: anna - * Date: 11/3/11 - */ -class DismissNewSignatureIntentionAction implements IntentionAction { - @NotNull - @Override - public String getText() { - return "Dismiss new signature"; - } - - @NotNull - @Override - public String getFamilyName() { - return getText(); - } - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return true; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - ChangeSignatureGestureDetector.getInstance(project).clearSignatureChange(file); - } - - @Override - public boolean startInWriteAction() { - return false; - } -} diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/MoveParameterAction.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/MoveParameterAction.java deleted file mode 100644 index 9af8aaa18004..000000000000 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/MoveParameterAction.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.intellij.refactoring.changeSignature; - -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.psi.PsiElement; - -/** - * User: anna - * Date: Sep 10, 2010 - */ -public abstract class MoveParameterAction extends AnAction{ - private final boolean myLeft; - private static final Logger LOG = Logger.getInstance("#" + MoveParameterAction.class.getName()); - - public MoveParameterAction(boolean left) { - super(); - myLeft = left; - } - - @Override - public void actionPerformed(AnActionEvent e) { - final DataContext dataContext = e.getDataContext(); - final PsiElement psiElement = CommonDataKeys.PSI_ELEMENT.getData(dataContext); - LOG.assertTrue(psiElement != null); - final Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - LanguageChangeSignatureDetectors.INSTANCE.forLanguage(psiElement.getLanguage()).moveParameter(psiElement, editor, myLeft); - } - - - @Override - public void update(AnActionEvent e) { - final Presentation presentation = e.getPresentation(); - presentation.setEnabled(false); - final DataContext dataContext = e.getDataContext(); - final Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - if (editor != null) { - final PsiElement psiElement = CommonDataKeys.PSI_ELEMENT.getData(dataContext); - if (psiElement != null) { - final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(psiElement.getLanguage()); - if (detector != null) { - final boolean available = detector.isMoveParameterAvailable(psiElement, myLeft); - presentation.setEnabled(available); - presentation.setVisible(available); - } - } - } - } -} diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/MoveParameterRightAction.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/MoveParameterRightAction.java deleted file mode 100644 index 8f2eb78f78ff..000000000000 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/MoveParameterRightAction.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2000-2010 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.refactoring.changeSignature; - -/** - * User: anna - * Date: Sep 10, 2010 - */ -public class MoveParameterRightAction extends MoveParameterAction { - public MoveParameterRightAction() { - super(false); - } -} diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/ApplyChangeSignatureAction.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/ApplyChangeSignatureAction.java new file mode 100644 index 000000000000..1fa0b434ae86 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/ApplyChangeSignatureAction.java @@ -0,0 +1,80 @@ +/* + * 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 com.intellij.refactoring.changeSignature.inplace; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.refactoring.BaseRefactoringIntentionAction; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.changeSignature.ChangeInfo; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +/** + * User: anna + * Date: Sep 6, 2010 + */ +public class ApplyChangeSignatureAction extends BaseRefactoringIntentionAction { + public static final String CHANGE_SIGNATURE = "Apply signature change"; + private final String myMethodName; + + public ApplyChangeSignatureAction(String methodName) { + myMethodName = methodName; + } + + @NotNull + @Override + public String getText() { + return RefactoringBundle.message("changing.signature.of.0", myMethodName); + } + + @NotNull + @Override + public String getFamilyName() { + return CHANGE_SIGNATURE; + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(element.getLanguage()); + if (detector != null) { + InplaceChangeSignature changeSignature = InplaceChangeSignature.getCurrentRefactoring(editor); + ChangeInfo currentInfo = changeSignature != null ? changeSignature.getCurrentInfo() : null; + if (currentInfo != null && detector.isChangeSignatureAvailableOnElement(element, currentInfo)) { + return true; + } + } + return false; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { + InplaceChangeSignature signatureGestureDetector = InplaceChangeSignature.getCurrentRefactoring(editor); + final String initialSignature = signatureGestureDetector.getInitialSignature(); + final ChangeInfo currentInfo = signatureGestureDetector.getCurrentInfo(); + signatureGestureDetector.detach(); + + final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(element.getLanguage()); + + detector.performChange(currentInfo, initialSignature); + } + + @Override + public boolean startInWriteAction() { + return false; + } +} diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignaturePassFactory.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/ChangeSignaturePassFactory.java similarity index 72% rename from platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignaturePassFactory.java rename to platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/ChangeSignaturePassFactory.java index 732a44452b6e..9e20a2f1902f 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignaturePassFactory.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/ChangeSignaturePassFactory.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. @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.refactoring.changeSignature; +package com.intellij.refactoring.changeSignature.inplace; -import com.intellij.codeHighlighting.Pass; import com.intellij.codeHighlighting.TextEditorHighlightingPass; import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory; import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar; @@ -23,7 +22,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil; import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction; -import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.lang.findUsages.DescriptiveNameUtil; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.CodeInsightColors; @@ -33,24 +32,23 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.refactoring.changeSignature.ChangeInfo; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.awt.*; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; public class ChangeSignaturePassFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory { public ChangeSignaturePassFactory(Project project, TextEditorHighlightingPassRegistrar highlightingPassRegistrar) { super(project); - highlightingPassRegistrar.registerTextEditorHighlightingPass(this, new int[]{Pass.UPDATE_ALL}, null, false, -1); + highlightingPassRegistrar.registerTextEditorHighlightingPass(this, null, null, true, -1); } @Override public TextEditorHighlightingPass createHighlightingPass(@NotNull final PsiFile file, @NotNull final Editor editor) { - LanguageChangeSignatureDetector detector = + LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(file.getLanguage()); if (detector == null) return null; @@ -63,58 +61,41 @@ public class ChangeSignaturePassFactory extends AbstractProjectComponent impleme private final PsiFile myFile; private final Editor myEditor; - private TextRange myRange; - public ChangeSignaturePass(Project project, PsiFile file, Editor editor) { - super(project, editor.getDocument(), false); + super(project, editor.getDocument(), true); myProject = project; myFile = file; myEditor = editor; } @Override - public void doCollectInformation(@NotNull ProgressIndicator progress) { - myRange = null; - final ChangeSignatureGestureDetector detector = ChangeSignatureGestureDetector.getInstance(myProject); - final ChangeInfo changeInfo = detector.getInitialChangeInfo(myFile); - if (changeInfo != null) { + public void doCollectInformation(@NotNull ProgressIndicator progress) {} + + @Override + public void doApplyInformationToEditor() { + HighlightInfo info = null; + final InplaceChangeSignature currentRefactoring = InplaceChangeSignature.getCurrentRefactoring(myEditor); + if (currentRefactoring != null) { + final ChangeInfo changeInfo = currentRefactoring.getStableChange(); final PsiElement element = changeInfo.getMethod(); int offset = myEditor.getCaretModel().getOffset(); if (element == null || !element.isValid()) return; final TextRange elementTextRange = element.getTextRange(); if (elementTextRange == null || !elementTextRange.contains(offset)) return; - final TextRange range = getHighlightingRange(changeInfo); - if (range != null && detector.isChangeSignatureAvailable(element)) { - myRange = range; - } - } - } - - @Override - public void doApplyInformationToEditor() { - HighlightInfo info = null; - if (myRange != null) { + final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(changeInfo.getLanguage()); + TextRange range = detector.getHighlightingRange(changeInfo); TextAttributes attributes = new TextAttributes(null, null, myEditor.getColorsScheme().getAttributes(CodeInsightColors.WEAK_WARNING_ATTRIBUTES) .getEffectColor(), null, Font.PLAIN); - HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(HighlightInfoType.INFORMATION).range(myRange); + HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(HighlightInfoType.INFORMATION).range(range); builder.textAttributes(attributes); builder.descriptionAndTooltip(SIGNATURE_SHOULD_BE_POSSIBLY_CHANGED); info = builder.createUnconditionally(); - final ArrayList options = new ArrayList<>(); - options.add(new DismissNewSignatureIntentionAction()); - QuickFixAction.registerQuickFixAction(info, new ChangeSignatureDetectorAction(), options, null); + QuickFixAction.registerQuickFixAction(info, new ApplyChangeSignatureAction(DescriptiveNameUtil.getDescriptiveName(element))); } Collection infos = info != null ? Collections.singletonList(info) : Collections.emptyList(); UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument, 0, myFile.getTextLength(), infos, getColorsScheme(), getId()); } - - @Nullable - private static TextRange getHighlightingRange(ChangeInfo changeInfo) { - if (changeInfo == null) return null; - final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(changeInfo.getLanguage()); - return detector != null ? detector.getHighlightingRange(changeInfo) : null; - } } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/EscapeHandler.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/EscapeHandler.java new file mode 100644 index 000000000000..7b4220dea49f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/EscapeHandler.java @@ -0,0 +1,50 @@ +/* + * 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 com.intellij.refactoring.changeSignature.inplace; + +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actionSystem.EditorActionHandler; + +public class EscapeHandler extends EditorActionHandler { + private final EditorActionHandler myOriginalHandler; + + public EscapeHandler(EditorActionHandler originalHandler) { + myOriginalHandler = originalHandler; + } + + @Override + public void execute(Editor editor, DataContext dataContext) { + InplaceChangeSignature currentRefactoring = InplaceChangeSignature.getCurrentRefactoring(editor); + if (currentRefactoring != null) { + currentRefactoring.cancel(); + return; + } + + if (myOriginalHandler.isEnabled(editor, dataContext)) { + myOriginalHandler.execute(editor, dataContext); + } + } + + @Override + public boolean isEnabled(Editor editor, DataContext dataContext) { + InplaceChangeSignature currentRefactoring = InplaceChangeSignature.getCurrentRefactoring(editor); + if (currentRefactoring != null) { + return true; + } + return myOriginalHandler.isEnabled(editor, dataContext); + } +} diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/InplaceChangeSignature.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/InplaceChangeSignature.java new file mode 100644 index 000000000000..f612d07b36b3 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/InplaceChangeSignature.java @@ -0,0 +1,213 @@ +/* + * 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 com.intellij.refactoring.changeSignature.inplace; + +import com.intellij.codeInsight.highlighting.HighlightManager; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.command.impl.FinishMarkAction; +import com.intellij.openapi.command.impl.StartMarkAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.VisualPosition; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.editor.markup.RangeHighlighter; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.ui.popup.BalloonBuilder; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilCore; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.changeSignature.ChangeInfo; +import com.intellij.refactoring.changeSignature.ChangeSignatureHandler; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.components.JBCheckBox; +import com.intellij.util.ui.PositionTracker; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.util.ArrayList; + +public class InplaceChangeSignature implements DocumentListener { + public static final Key INPLACE_CHANGE_SIGNATURE = Key.create("EditorInplaceChangeSignature"); + private ChangeInfo myCurrentInfo; + private ChangeInfo myStableChange; + private String myInitialSignature; + private Editor myEditor; + private LanguageChangeSignatureDetector myDetector; + + private final Project myProject; + private final PsiDocumentManager myDocumentManager; + private final ArrayList myHighlighters = new ArrayList<>(); + private StartMarkAction myMarkAction; + private Balloon myBalloon; + private boolean myDelegate; + + public InplaceChangeSignature(Project project, Editor editor, @NotNull PsiElement element) { + myDocumentManager = PsiDocumentManager.getInstance(project); + myProject = project; + try { + myMarkAction = StartMarkAction.start(editor, project, ChangeSignatureHandler.REFACTORING_NAME); + } + catch (StartMarkAction.AlreadyStartedException e) { + final int exitCode = Messages.showYesNoDialog(myProject, e.getMessage(), ChangeSignatureHandler.REFACTORING_NAME, "Navigate to Started", "Cancel", Messages.getErrorIcon()); + if (exitCode == Messages.CANCEL) return; + PsiElement method = myStableChange.getMethod(); + VirtualFile virtualFile = PsiUtilCore.getVirtualFile(method); + new OpenFileDescriptor(project, virtualFile, method.getTextOffset()).navigate(true); + return; + } + + + myEditor = editor; + myDetector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(element.getLanguage()); + myStableChange = myDetector.createInitialChangeInfo(element); + myInitialSignature = myDetector.extractSignature(myStableChange); + TextRange highlightingRange = myDetector.getHighlightingRange(myStableChange); + + HighlightManager highlightManager = HighlightManager.getInstance(myProject); + TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.LIVE_TEMPLATE_ATTRIBUTES); + highlightManager.addRangeHighlight(editor, highlightingRange.getStartOffset(), highlightingRange.getEndOffset(), attributes, false, myHighlighters); + for (RangeHighlighter highlighter : myHighlighters) { + highlighter.setGreedyToRight(true); + highlighter.setGreedyToLeft(true); + } + myEditor.getDocument().addDocumentListener(this); + showBalloon(); + myEditor.putUserData(INPLACE_CHANGE_SIGNATURE, this); + } + + @Nullable + public static InplaceChangeSignature getCurrentRefactoring(Editor editor) { + return editor.getUserData(INPLACE_CHANGE_SIGNATURE); + } + + public ChangeInfo getCurrentInfo() { + return myCurrentInfo; + } + + public String getInitialSignature() { + return myInitialSignature; + } + + @NotNull + public ChangeInfo getStableChange() { + return myStableChange; + } + + public void cancel() { + TextRange highlightingRange = myDetector.getHighlightingRange(getStableChange()); + Document document = myEditor.getDocument(); + String initialSignature = myInitialSignature; + detach(); + temporallyRevertChanges(highlightingRange, document, initialSignature, myProject); + } + + @Override + public void beforeDocumentChange(DocumentEvent event) {} + + @Override + public void documentChanged(DocumentEvent event) { + myDocumentManager.performWhenAllCommitted(() -> { + if (myDetector == null) { + return; + } + PsiFile file = myDocumentManager.getPsiFile(event.getDocument()); + if (file == null) { + return; + } + PsiElement element = file.findElementAt(event.getOffset()); + if (myDetector.ignoreChanges(element)) return; + + if (element instanceof PsiWhiteSpace) { + PsiElement method = myStableChange.getMethod(); + if (PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class) == method) { + return; + } + } + + if (!myDetector.isChangeSignatureAvailableOnElement(element, myStableChange)) { + detach(); + return; + } + + if (myCurrentInfo == null) { + myCurrentInfo = myStableChange; + } + String signature = myDetector.extractSignature(myCurrentInfo); + ChangeInfo changeInfo = myDetector.createNextChangeInfo(signature, myCurrentInfo, myDelegate); + if (changeInfo == null && myCurrentInfo != null) { + myStableChange = myCurrentInfo; + } + myCurrentInfo = changeInfo; + }); + } + + protected void showBalloon() { + JBCheckBox checkBox = new JBCheckBox(RefactoringBundle.message("delegation.panel.delegate.via.overloading.method")); + checkBox.addActionListener(e -> myDelegate = checkBox.isSelected()); + final BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createDialogBalloonBuilder(checkBox, null).setSmallVariant(true); + myBalloon = balloonBuilder.createBalloon(); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + final JBPopupFactory popupFactory = JBPopupFactory.getInstance(); + myBalloon.show(new PositionTracker(myEditor.getContentComponent()) { + @Override + public RelativePoint recalculateLocation(Balloon object) { + int offset = myStableChange.getMethod().getTextOffset(); + VisualPosition visualPosition = myEditor.offsetToVisualPosition(offset); + Point point = myEditor.visualPositionToXY(new VisualPosition(visualPosition.line, visualPosition.column)); + return new RelativePoint(myEditor.getContentComponent(), point); + } + }, Balloon.Position.above); + } + + public void detach() { + myEditor.getDocument().removeDocumentListener(this); + HighlightManager highlightManager = HighlightManager.getInstance(myProject); + for (RangeHighlighter highlighter : myHighlighters) { + highlightManager.removeSegmentHighlighter(myEditor, highlighter); + } + myHighlighters.clear(); + myBalloon.hide(); + FinishMarkAction.finish(myProject, myEditor, myMarkAction); + myEditor.putUserData(INPLACE_CHANGE_SIGNATURE, null); + } + + public static void temporallyRevertChanges(final TextRange signatureRange, + final Document document, + final String initialSignature, + Project project) { + WriteCommandAction.runWriteCommandAction(project, () -> { + document.replaceString(signatureRange.getStartOffset(), signatureRange.getEndOffset(), initialSignature); + PsiDocumentManager.getInstance(project).commitDocument(document); + }); + } +} diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/LanguageChangeSignatureDetector.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/LanguageChangeSignatureDetector.java similarity index 50% rename from platform/lang-impl/src/com/intellij/refactoring/changeSignature/LanguageChangeSignatureDetector.java rename to platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/LanguageChangeSignatureDetector.java index a67846d777ff..9ff3e3e21ed7 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/LanguageChangeSignatureDetector.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/LanguageChangeSignatureDetector.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.refactoring.changeSignature; +package com.intellij.refactoring.changeSignature.inplace; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; +import com.intellij.refactoring.changeSignature.ChangeInfo; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,20 +25,20 @@ import org.jetbrains.annotations.Nullable; * User: anna * Date: Sep 6, 2010 */ -public interface LanguageChangeSignatureDetector { - String MOVE_PARAMETER = "Parameter Move"; +public interface LanguageChangeSignatureDetector { - @Nullable ChangeInfo createInitialChangeInfo(final @NotNull PsiElement element); - @Nullable String extractSignature(PsiElement child, @NotNull ChangeInfo initialChangeInfo); + @NotNull C createInitialChangeInfo(final @NotNull PsiElement element); boolean ignoreChanges(PsiElement element); - @Nullable ChangeInfo createNextChangeInfo(String signature, @NotNull ChangeInfo currentInfo, String initialName); + @Nullable C createNextChangeInfo(String signature, @NotNull C currentInfo, boolean delegate); - boolean performChange(ChangeInfo changeInfo, ChangeInfo initialChangeInfo, @NotNull String oldText, boolean silently); + void performChange(C changeInfo, @NotNull String oldText); - boolean isChangeSignatureAvailableOnElement(PsiElement element, ChangeInfo currentInfo); - @Nullable TextRange getHighlightingRange(ChangeInfo changeInfo); + boolean isChangeSignatureAvailableOnElement(PsiElement element, C currentInfo); + TextRange getHighlightingRange(@NotNull C changeInfo); - boolean isMoveParameterAvailable(PsiElement parameter, boolean left); - void moveParameter(PsiElement parameter, Editor editor, boolean left); + default @NotNull String extractSignature(@NotNull C initialChangeInfo) { + final TextRange signatureRange = getHighlightingRange(initialChangeInfo); + return signatureRange.shiftRight(-signatureRange.getStartOffset()).substring(initialChangeInfo.getMethod().getText()); + } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/LanguageChangeSignatureDetectors.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/LanguageChangeSignatureDetectors.java similarity index 75% rename from platform/lang-impl/src/com/intellij/refactoring/changeSignature/LanguageChangeSignatureDetectors.java rename to platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/LanguageChangeSignatureDetectors.java index c0470ace8813..9a4400dd38dc 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/LanguageChangeSignatureDetectors.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/LanguageChangeSignatureDetectors.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.refactoring.changeSignature; +package com.intellij.refactoring.changeSignature.inplace; import com.intellij.lang.LanguageExtension; +import com.intellij.refactoring.changeSignature.ChangeInfo; /** * User: anna * Date: Sep 9, 2010 */ -class LanguageChangeSignatureDetectors extends LanguageExtension { +public class LanguageChangeSignatureDetectors extends LanguageExtension> { public static final LanguageChangeSignatureDetectors INSTANCE = new LanguageChangeSignatureDetectors(); LanguageChangeSignatureDetectors() { diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/RenameChangeInfo.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/RenameChangeInfo.java similarity index 89% rename from platform/lang-impl/src/com/intellij/refactoring/changeSignature/RenameChangeInfo.java rename to platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/RenameChangeInfo.java index 46f06774b2bf..1153bc6c571a 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/RenameChangeInfo.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/inplace/RenameChangeInfo.java @@ -1,20 +1,27 @@ /* - * Copyright 2000-2010 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. * 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.refactoring.changeSignature; +package com.intellij.refactoring.changeSignature.inplace; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.psi.*; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.changeSignature.ChangeInfo; +import com.intellij.refactoring.changeSignature.ParameterInfo; import com.intellij.refactoring.rename.RenameProcessor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index d56b7bd50c27..9845ba01859b 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -825,7 +825,7 @@ - + diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 8948df13a53f..4bf8716b0c48 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -956,6 +956,7 @@ + - com.intellij.refactoring.changeSignature.ChangeSignaturePassFactory + com.intellij.refactoring.changeSignature.inplace.ChangeSignaturePassFactory @@ -203,11 +203,6 @@ com.intellij.openapi.roots.impl.PushedFilePropertiesUpdaterImpl - - com.intellij.refactoring.changeSignature.ChangeSignatureGestureDetector - - - com.intellij.facet.pointers.FacetPointersManager com.intellij.facet.impl.pointers.FacetPointersManagerImpl diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 9bd3f471f841..2cfa497c4177 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -879,6 +879,9 @@ ide.remote.interpreters.use.rsync.description=Use rsync utility to synchronize r javafx.fxml.controller.from.loader=false javafx.fxml.controller.from.loader.description=Resolve FXML controllers specified with FXMLLoader.setController() +inplace.change.signature=false +inplace.change.signature.description=Enables change signature without dialog, inplace in the editor + low.memory.watcher.sync=true low.memory.watcher.sync.description=Whether LowMemoryWatcher runnables should be executed on the same thread that the low memory events come