/* * Copyright 2013-2017 consulo.io * * 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 consulo.csharp.ide.refactoring.changeSignature; import java.util.ArrayList; import java.util.List; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import consulo.csharp.lang.psi.CSharpAccessModifier; import consulo.csharp.lang.psi.CSharpCallArgumentList; import consulo.csharp.lang.psi.CSharpCallArgumentListOwner; import consulo.csharp.lang.psi.CSharpFileFactory; import consulo.csharp.lang.psi.CSharpMethodDeclaration; import consulo.csharp.lang.psi.CSharpModifier; import consulo.csharp.lang.psi.CSharpTypeRefPresentationUtil; import com.intellij.openapi.application.ReadActionProcessor; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.refactoring.changeSignature.ChangeInfo; import com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor; import com.intellij.refactoring.rename.ResolveSnapshotProvider; import com.intellij.usageView.UsageInfo; import com.intellij.util.PairFunction; import com.intellij.util.Processor; import com.intellij.util.containers.MultiMap; import consulo.annotations.RequiredReadAction; import consulo.dotnet.psi.DotNetExpression; import consulo.dotnet.psi.DotNetLikeMethodDeclaration; import consulo.dotnet.psi.DotNetModifierList; import consulo.dotnet.psi.DotNetParameter; import consulo.dotnet.psi.DotNetParameterList; import consulo.dotnet.psi.DotNetReferenceExpression; import consulo.internal.dotnet.msil.decompiler.textBuilder.util.StubBlockUtil; /** * @author VISTALL * @since 12.06.14 */ public class CSharpChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor { @NotNull @Override public UsageInfo[] findUsages(@NotNull final ChangeInfo info) { if(!(info instanceof CSharpChangeInfo)) { return UsageInfo.EMPTY_ARRAY; } final List<UsageInfo> list = new ArrayList<UsageInfo>(); final ReadActionProcessor<PsiReference> refProcessor = new ReadActionProcessor<PsiReference>() { @RequiredReadAction @Override public boolean processInReadAction(final PsiReference ref) { final PsiElement resolve = ref.resolve(); if(resolve != info.getMethod()) { return true; } TextRange rangeInElement = ref.getRangeInElement(); list.add(new UsageInfo(ref.getElement(), rangeInElement.getStartOffset(), rangeInElement.getEndOffset(), false)); return true; } }; ReferencesSearch.search(new ReferencesSearch.SearchParameters(info.getMethod(), info.getMethod().getResolveScope(), false)).forEach(refProcessor); return list.toArray(UsageInfo.EMPTY_ARRAY); } @NotNull @Override public MultiMap<PsiElement, String> findConflicts(@NotNull ChangeInfo info, Ref<UsageInfo[]> refUsages) { return MultiMap.emptyInstance(); } @Override @RequiredReadAction public boolean processUsage(@NotNull ChangeInfo changeInfo, @NotNull UsageInfo usageInfo, boolean beforeMethodChange, @NotNull UsageInfo[] usages) { if(!(changeInfo instanceof CSharpChangeInfo)) { return false; } PsiElement element = usageInfo.getElement(); if(!(element instanceof DotNetReferenceExpression)) { return false; } if(!beforeMethodChange) { return true; } if(changeInfo.isNameChanged()) { ((DotNetReferenceExpression) element).handleElementRename(changeInfo.getNewName()); } if(((CSharpChangeInfo) changeInfo).isParametersChanged()) { PsiElement parent = element.getParent(); if(parent instanceof CSharpCallArgumentListOwner) { CSharpCallArgumentList parameterList = ((CSharpCallArgumentListOwner) parent).getParameterList(); if(parameterList == null) { return true; } CSharpParameterInfo[] newParameters = ((CSharpChangeInfo) changeInfo).getNewParameters(); DotNetExpression[] expressions = parameterList.getExpressions(); String[] newArguments = new String[newParameters.length]; for(CSharpParameterInfo newParameter : newParameters) { if(newParameter.getOldIndex() != -1) { newArguments[newParameter.getNewIndex()] = expressions[newParameter.getOldIndex()].getText(); } else { newArguments[newParameter.getNewIndex()] = newParameter.getDefaultValue(); } } StringBuilder builder = new StringBuilder("test("); builder.append(StringUtil.join(newArguments, ", ")); builder.append(");"); CSharpCallArgumentListOwner call = (CSharpCallArgumentListOwner) CSharpFileFactory.createExpression(usageInfo.getProject(), builder.toString()); parameterList.replace(call.getParameterList()); } return true; } return false; } @Override @RequiredReadAction public boolean processPrimaryMethod(@NotNull ChangeInfo changeInfo) { if(!(changeInfo instanceof CSharpChangeInfo)) { return false; } CSharpChangeInfo sharpChangeInfo = (CSharpChangeInfo) changeInfo; DotNetLikeMethodDeclaration method = sharpChangeInfo.getMethod(); if(sharpChangeInfo.isNameChanged()) { assert method instanceof CSharpMethodDeclaration; method.setName(sharpChangeInfo.getNewName()); } StringBuilder builder = new StringBuilder(); CSharpAccessModifier newVisibility = sharpChangeInfo.getNewVisibility(); if(newVisibility != null) { builder.append(newVisibility.getPresentableText()).append(" "); } if(method instanceof CSharpMethodDeclaration) { if(changeInfo.isReturnTypeChanged()) { builder.append(((CSharpChangeInfo) changeInfo).getNewReturnType()).append(" "); } else { builder.append(CSharpTypeRefPresentationUtil.buildShortText(method.getReturnTypeRef(), method)).append(" "); } } builder.append(method.getName()); builder.append("("); StubBlockUtil.join(builder, sharpChangeInfo.getNewParameters(), new PairFunction<StringBuilder, CSharpParameterInfo, Void>() { @Nullable @Override public Void fun(StringBuilder stringBuilder, CSharpParameterInfo parameterInfo) { CSharpModifier modifier = parameterInfo.getModifier(); if(modifier != null) { stringBuilder.append(modifier.getPresentableText()).append(" "); } stringBuilder.append(parameterInfo.getTypeText()); stringBuilder.append(" "); stringBuilder.append(parameterInfo.getName()); return null; } }, ", "); builder.append(");"); DotNetLikeMethodDeclaration newMethod = CSharpFileFactory.createMethod(method.getProject(), builder); if(sharpChangeInfo.isReturnTypeChanged()) { method.getReturnType().replace(newMethod.getReturnType()); } if(newVisibility != null) { DotNetModifierList modifierList = method.getModifierList(); assert modifierList != null; for(CSharpAccessModifier value : CSharpAccessModifier.VALUES) { for(CSharpModifier modifier : value.getModifiers()) { modifierList.removeModifier(modifier); } } for(CSharpModifier modifier : newVisibility.getModifiers()) { modifierList.addModifier(modifier); } } if(sharpChangeInfo.isParametersChanged()) { CSharpParameterInfo[] newParameters = sharpChangeInfo.getNewParameters(); for(final CSharpParameterInfo newParameter : newParameters) { DotNetParameter originalParameter = newParameter.getParameter(); if(originalParameter != null) { ReferencesSearch.search(new ReferencesSearch.SearchParameters(originalParameter, originalParameter.getUseScope(), false)).forEach(new Processor<PsiReference>() { @Override public boolean process(PsiReference reference) { reference.handleElementRename(newParameter.getName()); return true; } }); originalParameter.setName(newParameter.getName()); } } DotNetParameterList parameterList = method.getParameterList(); if(parameterList != null) { parameterList.replace(newMethod.getParameterList()); } } return true; } @Override public boolean shouldPreviewUsages(@NotNull ChangeInfo changeInfo, @NotNull UsageInfo[] usages) { return false; } @Override public void registerConflictResolvers(@NotNull List<ResolveSnapshotProvider.ResolveSnapshot> snapshots, @NotNull ResolveSnapshotProvider resolveSnapshotProvider, @NotNull UsageInfo[] usages, @NotNull ChangeInfo changeInfo) { } }