mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
in-place change signature: avoid deadlock; avoid suggestions on new; highlight range in the box - hide highlighting on caret movement; dismiss current highlighting
This commit is contained in:
+305
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* 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.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.util.CanonicalTypes;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usageView.UsageViewUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: 11/3/11
|
||||
*/
|
||||
class DetectedJavaChangeInfo extends JavaChangeInfoImpl {
|
||||
private PsiMethod mySuperMethod;
|
||||
private String[] myModifiers;
|
||||
|
||||
DetectedJavaChangeInfo(String newVisibility,
|
||||
PsiMethod method,
|
||||
CanonicalTypes.Type newType,
|
||||
@NotNull ParameterInfoImpl[] newParms,
|
||||
ThrownExceptionInfo[] newExceptions,
|
||||
String newName, String oldName) {
|
||||
super(newVisibility, method, newName, newType, newParms, newExceptions, false, new HashSet<PsiMethod>(), new HashSet<PsiMethod>(), oldName);
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
myModifiers = new String[parameters.length];
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
PsiParameter parameter = parameters[i];
|
||||
final PsiModifierList modifierList = parameter.getModifierList();
|
||||
if (modifierList != null) {
|
||||
final String text = modifierList.getText();
|
||||
myModifiers[i] = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static DetectedJavaChangeInfo createFromMethod(PsiMethod method) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
return null;
|
||||
}
|
||||
final DetectedJavaChangeInfo fromMethod = new DetectedJavaChangeInfo(newVisibility, method, newReturnType, parameterInfos, null, method.getName(), method.getName());
|
||||
final PsiMethod deepestSuperMethod = method.findDeepestSuperMethod();
|
||||
if (deepestSuperMethod != null) {
|
||||
if (!deepestSuperMethod.getManager().isInProject(deepestSuperMethod)) return null;
|
||||
}
|
||||
fromMethod.setSuperMethod(deepestSuperMethod);
|
||||
return fromMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupPropagationEnabled(PsiParameter[] parameters, ParameterInfoImpl[] newParams) {
|
||||
isPropagationEnabled = false;
|
||||
}
|
||||
|
||||
public PsiMethod getSuperMethod() {
|
||||
if (mySuperMethod == null) {
|
||||
return getMethod();
|
||||
}
|
||||
return mySuperMethod;
|
||||
}
|
||||
|
||||
public void setSuperMethod(PsiMethod superMethod) {
|
||||
mySuperMethod = superMethod;
|
||||
}
|
||||
|
||||
public String[] getModifiers() {
|
||||
return myModifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkMethodEquality() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
ChangeInfo createNextInfo(final PsiMethod method) {
|
||||
final DetectedJavaChangeInfo fromMethod = createFromMethod(method);
|
||||
if (fromMethod == null) return null;
|
||||
if (!this.equals(fromMethod)) {
|
||||
if (!createParametersInfo(fromMethod.newParms)) return null;
|
||||
if (fromMethod.isReturnTypeChanged() || (fromMethod.newReturnType != null && getNewReturnType() == null) ||
|
||||
(fromMethod.newReturnType != null && getNewReturnType() != null && !Comparing.strEqual(getNewReturnType().getTypeText(),
|
||||
fromMethod.newReturnType.getTypeText()))) {
|
||||
final String visibility = fromMethod.getNewVisibility();
|
||||
if (Comparing.strEqual(visibility, PsiModifier.PRIVATE) &&
|
||||
!fromMethod.isArrayToVarargs() &&
|
||||
!fromMethod.isExceptionSetOrOrderChanged() &&
|
||||
!fromMethod.isExceptionSetChanged() &&
|
||||
!fromMethod.isNameChanged() &&
|
||||
!fromMethod.isParameterSetOrOrderChanged() &&
|
||||
!fromMethod.isParameterNamesChanged() &&
|
||||
!fromMethod.isParameterTypesChanged()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final DetectedJavaChangeInfo javaChangeInfo =
|
||||
new DetectedJavaChangeInfo(newVisibility, method, newReturnType, fromMethod.newParms, getNewExceptions(), method.getName(), getOldName()) {
|
||||
@Override
|
||||
protected void fillOldParams(PsiMethod method) {
|
||||
oldParameterNames = DetectedJavaChangeInfo.this.getOldParameterNames();
|
||||
oldParameterTypes = DetectedJavaChangeInfo.this.getOldParameterTypes();
|
||||
if (!method.isConstructor()) {
|
||||
try {
|
||||
isReturnTypeChanged = isReturnTypeChanged ||
|
||||
(DetectedJavaChangeInfo.this.getNewReturnType() != null
|
||||
? !Comparing.strEqual(DetectedJavaChangeInfo.this.getNewReturnType().getTypeText(), newReturnType.getTypeText())
|
||||
: newReturnType != null);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
isReturnTypeChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
javaChangeInfo.setSuperMethod(getSuperMethod());
|
||||
return javaChangeInfo;
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
ChangeSignatureProcessor createChangeSignatureProcessor(final PsiMethod method) {
|
||||
return new ChangeSignatureProcessor(method.getProject(), new DetectedJavaChangeInfo(getNewVisibility(), getSuperMethod(),
|
||||
getNewReturnType(),
|
||||
(ParameterInfoImpl[])getNewParameters(),
|
||||
getNewExceptions(), getNewName(),
|
||||
method.getName()) {
|
||||
@Override
|
||||
protected void fillOldParams(PsiMethod method) {
|
||||
super.fillOldParams(method);
|
||||
oldParameterNames = DetectedJavaChangeInfo.this.getOldParameterNames();
|
||||
oldParameterTypes = DetectedJavaChangeInfo.this.getOldParameterTypes();
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
protected void performRefactoring(UsageInfo[] usages) {
|
||||
super.performRefactoring(usages);
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(method.getProject());
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
for (int i = 0; i < getModifiers().length; i++) {
|
||||
final String modifier = getModifiers()[i];
|
||||
final PsiModifierList modifierList = parameters[i].getModifierList();
|
||||
if (modifierList != null && !Comparing.strEqual(modifier, modifierList.getText())) {
|
||||
final PsiModifierList newModifierList =
|
||||
elementFactory.createParameterFromText((modifier.isEmpty() ? "" : modifier + " ") + "type name", method).getModifierList();
|
||||
if (newModifierList != null) {
|
||||
modifierList.replace(newModifierList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean createParametersInfo(ParameterInfoImpl[] parameterInfos) {
|
||||
final JavaParameterInfo[] oldParameters = getNewParameters();
|
||||
final String[] oldParameterNames = getOldParameterNames();
|
||||
final String[] oldParameterTypes = getOldParameterTypes();
|
||||
final Map<JavaParameterInfo, Integer> untouchedParams = new HashMap<JavaParameterInfo, Integer>();
|
||||
for (int i = 0; i < parameterInfos.length; i++) {
|
||||
ParameterInfoImpl parameterInfo = parameterInfos[i];
|
||||
JavaParameterInfo oldParameter = null;
|
||||
for (JavaParameterInfo parameter : oldParameters) {
|
||||
if (Comparing.strEqual(parameter.getName(), parameterInfo.getName()) &&
|
||||
Comparing.strEqual(parameter.getTypeText(), parameterInfo.getTypeText())) {
|
||||
oldParameter = parameter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldParameter != null) {
|
||||
parameterInfos[i] = new ParameterInfoImpl(oldParameter.getOldIndex(),
|
||||
oldParameter.getName(),
|
||||
oldParameter.getTypeWrapper(),
|
||||
null);
|
||||
untouchedParams.put(parameterInfos[i], oldParameter.getOldIndex());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < parameterInfos.length; i++) {
|
||||
ParameterInfoImpl parameterInfo = parameterInfos[i];
|
||||
if (!untouchedParams.containsKey(parameterInfo)) {
|
||||
JavaParameterInfo oldParameter = null;
|
||||
if (oldParameters.length > i && oldParameterNames.length > i) {
|
||||
if (Comparing.strEqual(oldParameterNames[i], parameterInfo.getName()) ||
|
||||
Comparing.strEqual(oldParameterTypes[i], parameterInfo.getTypeText())) {
|
||||
if (!untouchedParams.containsValue(oldParameters[i].getOldIndex())) {
|
||||
oldParameter = oldParameters[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
final CanonicalTypes.Type typeWrapper = parameterInfo.getTypeWrapper();
|
||||
if (!typeWrapper.isValid()) return false;
|
||||
parameterInfos[i] = new ParameterInfoImpl(oldParameter != null ? oldParameter.getOldIndex() : -1,
|
||||
parameterInfo.getName(),
|
||||
typeWrapper,
|
||||
null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean perform(ChangeInfo initialChangeInfo, final String oldText, boolean silently) {
|
||||
final PsiMethod method = getSuperMethod();
|
||||
|
||||
final PsiMethod currentMethod = (PsiMethod)initialChangeInfo.getMethod();
|
||||
if (silently || ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
temporallyRevertChanges(currentMethod, oldText);
|
||||
createChangeSignatureProcessor(method).run();
|
||||
return true;
|
||||
}
|
||||
final JavaMethodDescriptor descriptor = new JavaMethodDescriptor(currentMethod) {
|
||||
@Override
|
||||
public String getReturnTypeText() {
|
||||
return getNewReturnType().getTypeText();
|
||||
}
|
||||
};
|
||||
final JavaChangeSignatureDialog dialog =
|
||||
new JavaChangeSignatureDialog(method.getProject(), descriptor, true, method) {
|
||||
protected BaseRefactoringProcessor createRefactoringProcessor() {
|
||||
return createChangeSignatureProcessor(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invokeRefactoring(final BaseRefactoringProcessor processor) {
|
||||
CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
temporallyRevertChanges(method, oldText);
|
||||
doRefactor(processor);
|
||||
}
|
||||
}, RefactoringBundle.message("changing.signature.of.0", UsageViewUtil.getDescriptiveName(currentMethod)), null);
|
||||
}
|
||||
|
||||
private void doRefactor(BaseRefactoringProcessor processor) {
|
||||
super.invokeRefactoring(processor);
|
||||
}
|
||||
};
|
||||
dialog.show();
|
||||
return dialog.isOK();
|
||||
}
|
||||
|
||||
private static void temporallyRevertChanges(final PsiElement psiElement, final String oldText) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final PsiFile file = psiElement.getContainingFile();
|
||||
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(psiElement.getProject());
|
||||
final Document document = documentManager.getDocument(file);
|
||||
if (document != null) {
|
||||
final TextRange textRange = psiElement.getTextRange();
|
||||
document.replaceString(textRange.getStartOffset(), textRange.getEndOffset(), oldText);
|
||||
documentManager.commitDocument(document);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -384,6 +384,10 @@ class JavaChangeInfoImpl implements JavaChangeInfo {
|
||||
return toRemoveParm;
|
||||
}
|
||||
|
||||
protected boolean checkMethodEquality() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -406,7 +410,7 @@ class JavaChangeInfoImpl implements JavaChangeInfo {
|
||||
if (retainsVarargs != that.retainsVarargs) return false;
|
||||
if (wasVararg != that.wasVararg) return false;
|
||||
if (!Arrays.equals(defaultValues, that.defaultValues)) return false;
|
||||
if (!method.equals(that.method)) return false;
|
||||
if (checkMethodEquality() && !method.equals(that.method)) return false;
|
||||
if (!Arrays.equals(newExceptions, that.newExceptions)) return false;
|
||||
if (!newName.equals(that.newName)) return false;
|
||||
if (newNameIdentifier != null ? !newNameIdentifier.equals(that.newNameIdentifier) : that.newNameIdentifier != null) return false;
|
||||
@@ -427,7 +431,9 @@ class JavaChangeInfoImpl implements JavaChangeInfo {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = newVisibility != null ? newVisibility.hashCode() : 0;
|
||||
result = 31 * result + method.hashCode();
|
||||
if (checkMethodEquality()) {
|
||||
result = 31 * result + method.hashCode();
|
||||
}
|
||||
result = 31 * result + oldName.hashCode();
|
||||
result = 31 * result +(oldType != null ? oldType.hashCode() : 0);
|
||||
result = 31 * result + Arrays.hashCode(oldParameterNames);
|
||||
|
||||
+87
-293
@@ -18,31 +18,18 @@ package com.intellij.refactoring.changeSignature;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.StdLanguages;
|
||||
import com.intellij.lang.java.JavaRefactoringSupportProvider;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
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.util.Comparing;
|
||||
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.BaseRefactoringProcessor;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.util.CanonicalTypes;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usageView.UsageViewUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: Sep 6, 2010
|
||||
@@ -51,85 +38,14 @@ public class JavaChangeSignatureDetector implements LanguageChangeSignatureDetec
|
||||
private static final Logger LOG = Logger.getInstance("#" + JavaChangeSignatureDetector.class.getName());
|
||||
|
||||
@Override
|
||||
public ChangeInfo createCurrentChangeSignature(final @NotNull PsiElement element,
|
||||
final @Nullable ChangeInfo changeInfo) {
|
||||
public ChangeInfo createInitialChangeInfo(final @NotNull PsiElement element) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class, false);
|
||||
if (method != null && isInsideMethodSignature(element, method) && (changeInfo == null || changeInfo instanceof MyJavaChangeInfo)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
return null;
|
||||
}
|
||||
final MyJavaChangeInfo fromMethod = new MyJavaChangeInfo(newVisibility, method, newReturnType, parameterInfos, null, method.getName(), method.getName());
|
||||
if (changeInfo == null) { //before replacement
|
||||
final PsiMethod deepestSuperMethod = method.findDeepestSuperMethod();
|
||||
if (deepestSuperMethod != null) {
|
||||
if (!deepestSuperMethod.getManager().isInProject(deepestSuperMethod)) return null;
|
||||
}
|
||||
fromMethod.setSuperMethod(deepestSuperMethod);
|
||||
return fromMethod;
|
||||
} else {
|
||||
final MyJavaChangeInfo info = (MyJavaChangeInfo)changeInfo;
|
||||
if (!info.getMethod().equals(method)) return null;
|
||||
if (!info.equals(fromMethod)) {
|
||||
if (!createParametersInfo(element, parameterInfos, info)) return null;
|
||||
if (info.isReturnTypeChanged()) {
|
||||
final String visibility = info.getNewVisibility();
|
||||
if (Comparing.strEqual(visibility, PsiModifier.PRIVATE) &&
|
||||
!info.isArrayToVarargs() &&
|
||||
!info.isExceptionSetOrOrderChanged() &&
|
||||
!info.isExceptionSetChanged() &&
|
||||
!info.isNameChanged() &&
|
||||
!info.isParameterSetOrOrderChanged() &&
|
||||
!info.isParameterNamesChanged() &&
|
||||
!info.isParameterTypesChanged()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
final MyJavaChangeInfo javaChangeInfo =
|
||||
new MyJavaChangeInfo(newVisibility, method, newReturnType, parameterInfos, info.getNewExceptions(), method.getName(), info.getOldName()) {
|
||||
@Override
|
||||
protected void fillOldParams(PsiMethod method) {
|
||||
oldParameterNames = info.getOldParameterNames();
|
||||
oldParameterTypes = info.getOldParameterTypes();
|
||||
if (!method.isConstructor()) {
|
||||
try {
|
||||
isReturnTypeChanged = info.isReturnTypeChanged ||
|
||||
(info.getNewReturnType() != null
|
||||
? !Comparing.strEqual(info.getNewReturnType().getTypeText(), newReturnType.getTypeText())
|
||||
: newReturnType != null);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
isReturnTypeChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
javaChangeInfo.setSuperMethod(info.getSuperMethod());
|
||||
return javaChangeInfo;
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return changeInfo;
|
||||
}
|
||||
if (method != null && isInsideMethodSignature(element, method)) {
|
||||
return DetectedJavaChangeInfo.createFromMethod(method);
|
||||
} else {
|
||||
final PsiVariable variable = PsiTreeUtil.getParentOfType(element, PsiVariable.class);
|
||||
if (variable != null && JavaRefactoringSupportProvider.mayRenameInplace(variable, element)) {
|
||||
return new RenameChangeInfo(variable, changeInfo) {
|
||||
return new RenameChangeInfo(variable, null) {
|
||||
@Override
|
||||
public Language getLanguage() {
|
||||
return StdLanguages.JAVA;
|
||||
@@ -140,143 +56,10 @@ public class JavaChangeSignatureDetector implements LanguageChangeSignatureDetec
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean createParametersInfo(PsiElement element,
|
||||
ParameterInfoImpl[] parameterInfos,
|
||||
MyJavaChangeInfo info) {
|
||||
|
||||
final JavaParameterInfo[] oldParameters = info.getNewParameters();
|
||||
final String[] oldParameterNames = info.getOldParameterNames();
|
||||
final String[] oldParameterTypes = info.getOldParameterTypes();
|
||||
final Map<JavaParameterInfo, Integer> untouchedParams = new HashMap<JavaParameterInfo, Integer>();
|
||||
for (int i = 0; i < parameterInfos.length; i++) {
|
||||
ParameterInfoImpl parameterInfo = parameterInfos[i];
|
||||
JavaParameterInfo oldParameter = null;
|
||||
for (JavaParameterInfo parameter : oldParameters) {
|
||||
if (Comparing.strEqual(parameter.getName(), parameterInfo.getName()) &&
|
||||
Comparing.strEqual(parameter.getTypeText(), parameterInfo.getTypeText())) {
|
||||
oldParameter = parameter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldParameter != null) {
|
||||
parameterInfos[i] = new ParameterInfoImpl(oldParameter.getOldIndex(),
|
||||
oldParameter.getName(),
|
||||
oldParameter.getTypeWrapper(),
|
||||
null);
|
||||
untouchedParams.put(parameterInfos[i], oldParameter.getOldIndex());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < parameterInfos.length; i++) {
|
||||
ParameterInfoImpl parameterInfo = parameterInfos[i];
|
||||
if (!untouchedParams.containsKey(parameterInfo)) {
|
||||
JavaParameterInfo oldParameter = null;
|
||||
if (oldParameters.length > i && oldParameterNames.length > i) {
|
||||
if (Comparing.strEqual(oldParameterNames[i], parameterInfo.getName()) ||
|
||||
Comparing.strEqual(oldParameterTypes[i], parameterInfo.getTypeText())) {
|
||||
if (!untouchedParams.containsValue(oldParameters[i].getOldIndex())) {
|
||||
oldParameter = oldParameters[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
final CanonicalTypes.Type typeWrapper = parameterInfo.getTypeWrapper();
|
||||
if (!typeWrapper.isValid()) return false;
|
||||
parameterInfos[i] = new ParameterInfoImpl(oldParameter != null ? oldParameter.getOldIndex() : - 1,
|
||||
parameterInfo.getName(),
|
||||
typeWrapper,
|
||||
null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static class MyJavaChangeInfo extends JavaChangeInfoImpl {
|
||||
private PsiMethod mySuperMethod;
|
||||
private String[] myModifiers;
|
||||
private MyJavaChangeInfo(String newVisibility,
|
||||
PsiMethod method,
|
||||
CanonicalTypes.Type newType,
|
||||
@NotNull ParameterInfoImpl[] newParms,
|
||||
ThrownExceptionInfo[] newExceptions,
|
||||
String newName, String oldName) {
|
||||
super(newVisibility, method, newName, newType, newParms, newExceptions, false,
|
||||
new HashSet<PsiMethod>(),
|
||||
new HashSet<PsiMethod>(), oldName);
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
myModifiers = new String[parameters.length];
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
PsiParameter parameter = parameters[i];
|
||||
final PsiModifierList modifierList = parameter.getModifierList();
|
||||
if (modifierList != null) {
|
||||
final String text = modifierList.getText();
|
||||
myModifiers[i] = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupPropagationEnabled(PsiParameter[] parameters, ParameterInfoImpl[] newParms) {
|
||||
isPropagationEnabled = false;
|
||||
}
|
||||
|
||||
public PsiMethod getSuperMethod() {
|
||||
if (mySuperMethod == null) {
|
||||
return getMethod();
|
||||
}
|
||||
return mySuperMethod;
|
||||
}
|
||||
|
||||
public void setSuperMethod(PsiMethod superMethod) {
|
||||
mySuperMethod = superMethod;
|
||||
}
|
||||
|
||||
public String[] getModifiers() {
|
||||
return myModifiers;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(final ChangeInfo changeInfo, @NotNull final String oldText, boolean silently) {
|
||||
if (changeInfo instanceof MyJavaChangeInfo) {
|
||||
final MyJavaChangeInfo info = (MyJavaChangeInfo)changeInfo;
|
||||
final PsiMethod method = info.getSuperMethod();
|
||||
|
||||
if (silently || ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
temporallyRevertChanges(info.getMethod(), oldText);
|
||||
createChangeSignatureProcessor(info, method).run();
|
||||
return true;
|
||||
}
|
||||
final JavaMethodDescriptor descriptor = new JavaMethodDescriptor(info.getMethod()) {
|
||||
@Override
|
||||
public String getReturnTypeText() {
|
||||
return info.getNewReturnType().getTypeText();
|
||||
}
|
||||
};
|
||||
final JavaChangeSignatureDialog dialog =
|
||||
new JavaChangeSignatureDialog(method.getProject(), descriptor, true, method) {
|
||||
protected BaseRefactoringProcessor createRefactoringProcessor() {
|
||||
return createChangeSignatureProcessor(info, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invokeRefactoring(final BaseRefactoringProcessor processor) {
|
||||
CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
temporallyRevertChanges(method, oldText);
|
||||
doRefactor(processor);
|
||||
}
|
||||
}, RefactoringBundle.message("changing.signature.of.0", UsageViewUtil.getDescriptiveName(info.getMethod())), null);
|
||||
}
|
||||
|
||||
private void doRefactor(BaseRefactoringProcessor processor) {
|
||||
super.invokeRefactoring(processor);
|
||||
}
|
||||
};
|
||||
dialog.show();
|
||||
return dialog.isOK();
|
||||
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;
|
||||
@@ -285,64 +68,90 @@ public class JavaChangeSignatureDetector implements LanguageChangeSignatureDetec
|
||||
|
||||
}
|
||||
|
||||
private static void temporallyRevertChanges(final PsiElement psiElement, final String oldText) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final PsiFile file = psiElement.getContainingFile();
|
||||
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(psiElement.getProject());
|
||||
final Document document = documentManager.getDocument(file);
|
||||
if (document != null) {
|
||||
final TextRange textRange = psiElement.getTextRange();
|
||||
document.replaceString(textRange.getStartOffset(), textRange.getEndOffset(), oldText);
|
||||
documentManager.commitDocument(document);
|
||||
}
|
||||
@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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static ChangeSignatureProcessor createChangeSignatureProcessor(final MyJavaChangeInfo info,
|
||||
final PsiMethod method) {
|
||||
return new ChangeSignatureProcessor(method.getProject(), new MyJavaChangeInfo(info.getNewVisibility(), info.getSuperMethod(),
|
||||
info.getNewReturnType(),
|
||||
(ParameterInfoImpl[])info.getNewParameters(),
|
||||
info.getNewExceptions(), info.getNewName(), method.getName()) {
|
||||
@Override
|
||||
protected void fillOldParams(PsiMethod method) {
|
||||
super.fillOldParams(method);
|
||||
oldParameterNames = info.getOldParameterNames();
|
||||
oldParameterTypes = info.getOldParameterTypes();
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
protected void performRefactoring(UsageInfo[] usages) {
|
||||
super.performRefactoring(usages);
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(method.getProject());
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
for (int i = 0; i < info.getModifiers().length; i++) {
|
||||
final String modifier = info.getModifiers()[i];
|
||||
final PsiModifierList modifierList = parameters[i].getModifierList();
|
||||
if (modifierList != null && !Comparing.strEqual(modifier, modifierList.getText())) {
|
||||
final PsiModifierList newModifierList =
|
||||
elementFactory.createParameterFromText((modifier.isEmpty() ? "" : modifier + " ") + "type name", method).getModifierList();
|
||||
if (newModifierList != null) {
|
||||
modifierList.replace(newModifierList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
else if (currentInfo instanceof JavaChangeInfo) {
|
||||
final PsiMethod method = (PsiMethod)currentInfo.getMethod();
|
||||
return getSignatureRange(method).contains(element.getTextRange());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChangeSignatureAvailable(PsiElement element, ChangeInfo currentInfo) {
|
||||
if (currentInfo instanceof JavaChangeInfo) {
|
||||
return isInsideMethodSignature(element, (PsiMethod)currentInfo.getMethod());
|
||||
} else if (currentInfo instanceof RenameChangeInfo) {
|
||||
final PsiElement nameIdentifier = ((RenameChangeInfo)currentInfo).getNameIdentifier();
|
||||
return nameIdentifier != null && nameIdentifier.getTextRange().contains(element.getTextRange());
|
||||
public boolean ignoreChanges(PsiElement element) {
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
|
||||
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 element.getContainingFile().getText().substring(signatureRange.getStartOffset(), signatureRange.getEndOffset());
|
||||
} else if (element instanceof PsiIdentifier && element.getParent() instanceof PsiNamedElement) {
|
||||
return element.getText();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChangeInfo createNextChangeInfo(String signature, @NotNull final ChangeInfo currentInfo, String initialName) {
|
||||
final Project project = currentInfo.getMethod().getProject();
|
||||
if (currentInfo instanceof RenameChangeInfo) {
|
||||
return currentInfo;
|
||||
}
|
||||
|
||||
final PsiMethod oldMethod = (PsiMethod)currentInfo.getMethod();
|
||||
if (oldMethod.isPhysical() && LanguageChangeSignatureDetectors.skipElement(oldMethod, initialName)) return null;
|
||||
|
||||
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 PsiCodeBlock body = method.getBody();
|
||||
final TextRange textRange = element.getTextRange();
|
||||
if (body != null) {
|
||||
return textRange.getEndOffset() <= body.getTextOffset() && textRange.getStartOffset() >= method.getModifierList().getTextRange().getEndOffset();
|
||||
}
|
||||
return textRange.getStartOffset() >= method.getModifierList().getTextRange().getEndOffset() &&
|
||||
textRange.getEndOffset() <= method.getTextRange().getEndOffset();
|
||||
}
|
||||
|
||||
private static TextRange getSignatureRange(PsiMethod method) {
|
||||
final PsiCodeBlock body = method.getBody();
|
||||
if (body != null) {
|
||||
return new TextRange(method.getTextRange().getStartOffset(), body.getTextOffset());
|
||||
}
|
||||
return new TextRange(method.getTextRange().getStartOffset(),
|
||||
method.getTextRange().getEndOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -390,19 +199,4 @@ public class JavaChangeSignatureDetector implements LanguageChangeSignatureDetec
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ignoreChanges(PsiElement element) {
|
||||
return PsiTreeUtil.getParentOfType(element, PsiImportList.class) != null;
|
||||
}
|
||||
|
||||
private static boolean isInsideMethodSignature(PsiElement element, @NotNull PsiMethod method) {
|
||||
final PsiCodeBlock body = method.getBody();
|
||||
final TextRange textRange = element.getTextRange();
|
||||
if (body != null) {
|
||||
return textRange.getEndOffset() <= body.getTextOffset() && textRange.getStartOffset() >= method.getModifierList().getTextRange().getEndOffset();
|
||||
}
|
||||
return textRange.getStartOffset() >= method.getModifierList().getTextRange().getEndOffset() &&
|
||||
textRange.getEndOffset() <= method.getTextRange().getEndOffset();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ public class JavaChangeSignatureHandler implements ChangeSignatureHandler {
|
||||
if (element instanceof PsiMethod) {
|
||||
final ChangeSignatureGestureDetector detector = ChangeSignatureGestureDetector.getInstance(project);
|
||||
final PsiIdentifier nameIdentifier = ((PsiMethod)element).getNameIdentifier();
|
||||
if (nameIdentifier != null && detector.isChangeSignatureAvailable(nameIdentifier)) {
|
||||
if (nameIdentifier != null && detector.isChangeSignatureAvailable(element)) {
|
||||
detector.changeSignature(element.getContainingFile(), false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,4 +2,5 @@ class Test {
|
||||
void foo(int i<caret>) {
|
||||
System.out.println(i);
|
||||
}
|
||||
void bar(){foo(1);}
|
||||
}
|
||||
@@ -2,4 +2,5 @@ class Test {
|
||||
void foo(int i, int param) {
|
||||
System.out.println(i);
|
||||
}
|
||||
void bar(){foo(1);}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
class Test {
|
||||
void myverylonagname(<caret>){}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package refactoring.changeSignatureGesture;
|
||||
interface I {
|
||||
void add(<caret>);
|
||||
}
|
||||
|
||||
public class IImpl implements I {
|
||||
public void add(){}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package refactoring.changeSignatureGesture;
|
||||
interface I {
|
||||
void add(int param);
|
||||
}
|
||||
|
||||
public class IImpl implements I {
|
||||
public void add(int param){}
|
||||
}
|
||||
@@ -2,4 +2,5 @@ class Test {
|
||||
void foo(int i<caret>) {
|
||||
System.out.println(i);
|
||||
}
|
||||
void bar(){foo();}
|
||||
}
|
||||
@@ -2,4 +2,5 @@ class Test {
|
||||
void foo(int iparam) {
|
||||
System.out.println(iparam);
|
||||
}
|
||||
void bar(){foo();}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
public class Test {
|
||||
void foo(<caret>){}
|
||||
void bar() {
|
||||
foo();
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,18 @@ public class ChangeSignatureGestureTest extends LightCodeInsightFixtureTestCase
|
||||
doTypingTest("param");
|
||||
}
|
||||
|
||||
public void testSpaces() {
|
||||
doTypingNoBorderTest(" ");
|
||||
}
|
||||
|
||||
public void testNoUsages() {
|
||||
doTypingNoBorderTest("int param");
|
||||
}
|
||||
|
||||
public void testOccurrencesInSameFile() {
|
||||
doTypingTest("int param");
|
||||
}
|
||||
|
||||
public void testNewParam() {
|
||||
doTypingTest(", int param");
|
||||
}
|
||||
|
||||
+11
-1
@@ -55,7 +55,17 @@ public class ChangeSignatureDetectorAction extends PsiElementBaseIntentionAction
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
|
||||
myAcceptText = ChangeSignatureGestureDetector.getInstance(project).getChangeSignatureAcceptText(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;
|
||||
}
|
||||
|
||||
|
||||
+80
-34
@@ -38,12 +38,15 @@ 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.PsiUtilBase;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -80,27 +83,11 @@ public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter impleme
|
||||
}
|
||||
|
||||
public boolean isChangeSignatureAvailable(@NotNull PsiElement element) {
|
||||
final MyDocumentChangeAdapter adapter = myListenerMap.get(PsiUtilBase.getVirtualFile(element));
|
||||
if (adapter != null && adapter.getCurrentInfo() != null) {
|
||||
final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(element.getLanguage());
|
||||
return detector != null && detector.isChangeSignatureAvailable(element, adapter.getCurrentInfo());
|
||||
}
|
||||
return false;
|
||||
final MyDocumentChangeAdapter adapter = myListenerMap.get(PsiUtilCore.getVirtualFile(element));
|
||||
return adapter != null && adapter.getCurrentInfo() != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getChangeSignatureAcceptText(@NotNull PsiElement element) {
|
||||
final MyDocumentChangeAdapter adapter = myListenerMap.get(PsiUtilBase.getVirtualFile(element));
|
||||
if (adapter != null && adapter.getCurrentInfo() != null) {
|
||||
final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(element.getLanguage());
|
||||
final ChangeInfo currentInfo = adapter.getCurrentInfo();
|
||||
if (detector != null && detector.isChangeSignatureAvailable(element, currentInfo)) {
|
||||
return currentInfo instanceof RenameChangeInfo ? ChangeSignatureDetectorAction.NEW_NAME
|
||||
: ChangeSignatureDetectorAction.CHANGE_SIGNATURE;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public boolean containsChangeSignatureChange(@NotNull PsiFile file) {
|
||||
return getChangeInfo(file) != null;
|
||||
@@ -112,6 +99,12 @@ public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter impleme
|
||||
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;
|
||||
@@ -119,7 +112,7 @@ public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter impleme
|
||||
final ChangeInfo currentInfo = changeBean.getCurrentInfo();
|
||||
if (currentInfo != null) {
|
||||
final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(currentInfo.getLanguage());
|
||||
if (detector.accept(currentInfo, changeBean.getInitialText(), silently)) {
|
||||
if (detector.performChange(currentInfo, changeBean.getInitialChangeInfo(), changeBean.getInitialText(), silently)) {
|
||||
changeBean.reinit();
|
||||
}
|
||||
}
|
||||
@@ -203,13 +196,11 @@ public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter impleme
|
||||
final LanguageChangeSignatureDetector detector = LanguageChangeSignatureDetectors.INSTANCE.forLanguage(child.getLanguage());
|
||||
if (detector == null) return;
|
||||
if (detector.ignoreChanges(child)) return;
|
||||
final ChangeInfo info = LanguageChangeSignatureDetectors.createCurrentChangeInfo(child, changeBean.getInitialChangeInfo());
|
||||
if (info == null) {
|
||||
final String currentSignature = detector.extractSignature(child, changeBean.getInitialChangeInfo());
|
||||
if (currentSignature == null) {
|
||||
changeBean.reinit();
|
||||
} else if (!info.equals(changeBean.getInitialChangeInfo())) {
|
||||
changeBean.setCurrentInfo(info);
|
||||
} else {
|
||||
changeBean.setCurrentInfo(null);
|
||||
changeBean.addSignature(currentSignature);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,13 +256,30 @@ public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter impleme
|
||||
}
|
||||
}
|
||||
|
||||
@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 PASTE_COMMAND_NAME = EditorBundle.message("paste.command.name");
|
||||
private final @NonNls String TYPING_COMMAND_NAME = EditorBundle.message("typing.in.editor.command.name");
|
||||
|
||||
private String myInitialText;
|
||||
private String myInitialName;
|
||||
private ChangeInfo myInitialChangeInfo;
|
||||
private ChangeInfo myCurrentInfo;
|
||||
|
||||
public void setCurrentInfo(ChangeInfo currentInfo) {
|
||||
myCurrentInfo = currentInfo;
|
||||
private final List<String> mySignatures = new ArrayList<String>();
|
||||
|
||||
public MyDocumentChangeAdapter() {
|
||||
}
|
||||
|
||||
public String getInitialText() {
|
||||
@@ -279,11 +287,42 @@ public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter impleme
|
||||
}
|
||||
|
||||
public ChangeInfo getCurrentInfo() {
|
||||
return myCurrentInfo;
|
||||
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;
|
||||
}
|
||||
|
||||
private final @NonNls String PASTE_COMMAND_NAME = EditorBundle.message("paste.command.name");
|
||||
private final @NonNls String TYPING_COMMAND_NAME = EditorBundle.message("typing.in.editor.command.name");
|
||||
public void addSignature(String signature) {
|
||||
synchronized (mySignatures) {
|
||||
if (!mySignatures.contains(signature)) {
|
||||
mySignatures.add(signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeDocumentChange(DocumentEvent e) {
|
||||
@@ -307,10 +346,14 @@ public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter impleme
|
||||
if (file != null) {
|
||||
final PsiElement element = file.findElementAt(e.getOffset());
|
||||
if (element != null) {
|
||||
final ChangeInfo info = LanguageChangeSignatureDetectors.createCurrentChangeInfo(element, myCurrentInfo);
|
||||
final ChangeInfo info = createInitialChangeInfo(element);
|
||||
if (info != null) {
|
||||
final TextRange textRange = info.getMethod().getTextRange();
|
||||
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;
|
||||
}
|
||||
@@ -325,10 +368,13 @@ public class ChangeSignatureGestureDetector extends PsiTreeChangeAdapter impleme
|
||||
}
|
||||
|
||||
public void reinit() {
|
||||
synchronized (mySignatures) {
|
||||
mySignatures.clear();
|
||||
}
|
||||
myInitialText = null;
|
||||
myInitialName = null;
|
||||
myInitialChangeInfo = null;
|
||||
myCurrentInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.codeHighlighting.Pass;
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory;
|
||||
import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar;
|
||||
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.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.components.AbstractProjectComponent;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors;
|
||||
import com.intellij.openapi.editor.markup.EffectType;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextEditorHighlightingPass createHighlightingPass(@NotNull final PsiFile file, @NotNull final Editor editor) {
|
||||
LanguageChangeSignatureDetector detector =
|
||||
LanguageChangeSignatureDetectors.INSTANCE.forLanguage(file.getLanguage());
|
||||
if (detector == null) return null;
|
||||
|
||||
return new ChangeSignaturePass(file.getProject(), file, editor);
|
||||
}
|
||||
|
||||
private static class ChangeSignaturePass extends TextEditorHighlightingPass {
|
||||
@NonNls private static final String SIGNATURE_SHOULD_BE_POSSIBLY_CHANGED = "Signature should be possibly changed";
|
||||
private final Project myProject;
|
||||
private PsiFile myFile;
|
||||
private Editor myEditor;
|
||||
|
||||
private TextRange myRange;
|
||||
|
||||
public ChangeSignaturePass(Project project, PsiFile file, Editor editor) {
|
||||
super(project, editor.getDocument(), false);
|
||||
myProject = project;
|
||||
myFile = file;
|
||||
myEditor = editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCollectInformation(ProgressIndicator progress) {
|
||||
myRange = null;
|
||||
final ChangeSignatureGestureDetector detector = ChangeSignatureGestureDetector.getInstance(myProject);
|
||||
final ChangeInfo changeInfo = detector.getInitialChangeInfo(myFile);
|
||||
if (changeInfo != null) {
|
||||
final PsiElement element = changeInfo.getMethod();
|
||||
int offset = myEditor.getCaretModel().getOffset();
|
||||
if (!element.getTextRange().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) {
|
||||
info = new HighlightInfo(new TextAttributes(null, null,
|
||||
myEditor.getColorsScheme().getAttributes(CodeInsightColors.WEAK_WARNING_ATTRIBUTES).getEffectColor(),
|
||||
EffectType.BOXED, Font.PLAIN),
|
||||
HighlightInfoType.INFORMATION, myRange.getStartOffset(), myRange.getEndOffset(),
|
||||
SIGNATURE_SHOULD_BE_POSSIBLY_CHANGED, SIGNATURE_SHOULD_BE_POSSIBLY_CHANGED,
|
||||
HighlightSeverity.INFORMATION, false, true, false);
|
||||
final ArrayList<IntentionAction> options = new ArrayList<IntentionAction>();
|
||||
options.add(new DismissNewSignatureIntentionAction(myProject, myFile));
|
||||
QuickFixAction.registerQuickFixAction(info, new ChangeSignatureDetectorAction(), options, null);
|
||||
}
|
||||
Collection<HighlightInfo> infos = info != null ? Collections.singletonList(info) : Collections.<HighlightInfo>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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
private final Project myProject;
|
||||
private final PsiFile myFile;
|
||||
|
||||
DismissNewSignatureIntentionAction(Project project, PsiFile file) {
|
||||
myProject = project;
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
@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(myProject).clearSignatureChange(myFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -28,17 +28,17 @@ import org.jetbrains.annotations.Nullable;
|
||||
public interface LanguageChangeSignatureDetector {
|
||||
String MOVE_PARAMETER = "Parameter Move";
|
||||
|
||||
@Nullable
|
||||
ChangeInfo createCurrentChangeSignature(final @NotNull PsiElement element,
|
||||
final @Nullable ChangeInfo changeInfo);
|
||||
@Nullable ChangeInfo createInitialChangeInfo(final @NotNull PsiElement element);
|
||||
@Nullable String extractSignature(PsiElement child, @NotNull ChangeInfo initialChangeInfo);
|
||||
boolean ignoreChanges(PsiElement element);
|
||||
@Nullable ChangeInfo createNextChangeInfo(String signature, @NotNull ChangeInfo currentInfo, String initialName);
|
||||
|
||||
boolean accept(ChangeInfo changeInfo, @NotNull String oldText, boolean silently);
|
||||
boolean performChange(ChangeInfo changeInfo, ChangeInfo initialChangeInfo, @NotNull String oldText, boolean silently);
|
||||
|
||||
boolean isChangeSignatureAvailableOnElement(PsiElement element, ChangeInfo currentInfo);
|
||||
@Nullable TextRange getHighlightingRange(ChangeInfo changeInfo);
|
||||
|
||||
boolean isChangeSignatureAvailable(PsiElement element, ChangeInfo currentInfo);
|
||||
|
||||
boolean isMoveParameterAvailable(PsiElement parameter, boolean left);
|
||||
|
||||
void moveParameter(PsiElement parameter, Editor editor, boolean left);
|
||||
|
||||
boolean ignoreChanges(PsiElement element);
|
||||
}
|
||||
|
||||
+25
-12
@@ -15,17 +15,17 @@
|
||||
*/
|
||||
package com.intellij.refactoring.changeSignature;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.LanguageExtension;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PsiSearchHelper;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: Sep 9, 2010
|
||||
*/
|
||||
* User: anna
|
||||
* Date: Sep 9, 2010
|
||||
*/
|
||||
class LanguageChangeSignatureDetectors extends LanguageExtension<LanguageChangeSignatureDetector> {
|
||||
public static final LanguageChangeSignatureDetectors INSTANCE = new LanguageChangeSignatureDetectors();
|
||||
|
||||
@@ -33,9 +33,22 @@ class LanguageChangeSignatureDetectors extends LanguageExtension<LanguageChangeS
|
||||
super("com.intellij.changeSignatureDetector");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static ChangeInfo createCurrentChangeInfo(@NotNull PsiElement element, @Nullable ChangeInfo changeInfo) {
|
||||
final LanguageChangeSignatureDetector detector = INSTANCE.forLanguage(element.getLanguage());
|
||||
return detector != null ? detector.createCurrentChangeSignature(element, changeInfo) : null;
|
||||
static boolean skipElement(PsiNamedElement psiNamedElement, String initialName) {
|
||||
final ProgressManager progressManager = ProgressManager.getInstance();
|
||||
final PsiSearchHelper searchHelper = PsiSearchHelper.SERVICE.getInstance(psiNamedElement.getProject());
|
||||
final GlobalSearchScope scope = GlobalSearchScope.projectScope(psiNamedElement.getProject());
|
||||
if (initialName == null) return true;
|
||||
PsiFile containingFile = psiNamedElement.getContainingFile();
|
||||
final PsiSearchHelper.SearchCostResult cheapEnoughToSearch = searchHelper.isCheapEnoughToSearch(initialName, scope, containingFile, progressManager.getProgressIndicator());
|
||||
if (cheapEnoughToSearch == PsiSearchHelper.SearchCostResult.ZERO_OCCURRENCES){
|
||||
String text = containingFile.getText();
|
||||
int idx = text.indexOf(initialName);
|
||||
//check another occurrences in the same file
|
||||
if (idx > 0 && text.indexOf(initialName, idx + initialName.length()) > 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,9 +519,6 @@
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.impl.EditFoldingOptionsAction</className>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<className>com.intellij.refactoring.changeSignature.ChangeSignatureDetectorAction</className>
|
||||
</intentionAction>
|
||||
|
||||
<!-- CodeInsightSettings -->
|
||||
<editorActionHandler action="EditorEnter" implementationClass="com.intellij.codeInsight.editorActions.EnterHandler" id="editorEnter"/>
|
||||
|
||||
@@ -134,6 +134,10 @@
|
||||
<implementation-class>com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory</implementation-class>
|
||||
<skipForDefaultProject/>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>com.intellij.refactoring.changeSignature.ChangeSignaturePassFactory</implementation-class>
|
||||
<skipForDefaultProject/>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>com.intellij.codeInsight.daemon.impl.CodeFoldingPassFactory</implementation-class>
|
||||
<skipForDefaultProject/>
|
||||
|
||||
Reference in New Issue
Block a user