private static void processMethodUsage( PsiElement ref, JavaChangeInfo changeInfo, boolean toChangeArguments, boolean toCatchExceptions, PsiMethod callee, PsiSubstitutor subsitutor, final UsageInfo[] usages) throws IncorrectOperationException { if (changeInfo.isNameChanged()) { if (ref instanceof PsiJavaCodeReferenceElement) { PsiElement last = ((PsiJavaCodeReferenceElement) ref).getReferenceNameElement(); if (last instanceof PsiIdentifier && last.getText().equals(changeInfo.getOldName())) { last.replace(changeInfo.getNewNameIdentifier()); } } } final PsiMethod caller = RefactoringUtil.getEnclosingMethod(ref); if (toChangeArguments) { final PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref); LOG.assertTrue(list != null); boolean toInsertDefaultValue = needDefaultValue(changeInfo, caller); if (toInsertDefaultValue && ref instanceof PsiReferenceExpression) { final PsiExpression qualifierExpression = ((PsiReferenceExpression) ref).getQualifierExpression(); if (qualifierExpression instanceof PsiSuperExpression && callerSignatureIsAboutToChangeToo(caller, usages)) { toInsertDefaultValue = false; } } fixActualArgumentsList(list, changeInfo, toInsertDefaultValue, subsitutor); } if (toCatchExceptions) { if (!(ref instanceof PsiReferenceExpression && ((PsiReferenceExpression) ref).getQualifierExpression() instanceof PsiSuperExpression)) { if (needToCatchExceptions(changeInfo, caller)) { PsiClassType[] newExceptions = callee != null ? getCalleeChangedExceptionInfo(callee) : getPrimaryChangedExceptionInfo(changeInfo); fixExceptions(ref, newExceptions); } } } }
protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) { final UsageInfo[] usages = refUsages.get(); MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>(); final Set<PsiMember> members = new HashSet<PsiMember>(); members.add(myMethod); if (myTargetVariable instanceof PsiField) members.add((PsiMember) myTargetVariable); if (!myTargetClass.isInterface()) { RefactoringConflictsUtil.analyzeAccessibilityConflicts( members, myTargetClass, conflicts, myNewVisibility); } else { for (final UsageInfo usage : usages) { if (usage instanceof InheritorUsageInfo) { RefactoringConflictsUtil.analyzeAccessibilityConflicts( members, ((InheritorUsageInfo) usage).getInheritor(), conflicts, myNewVisibility); } } } if (myTargetVariable instanceof PsiParameter) { PsiParameter parameter = (PsiParameter) myTargetVariable; for (final UsageInfo usageInfo : usages) { if (usageInfo instanceof MethodCallUsageInfo) { final PsiElement methodCall = ((MethodCallUsageInfo) usageInfo).getMethodCallExpression(); if (methodCall instanceof PsiMethodCallExpression) { final PsiExpression[] expressions = ((PsiMethodCallExpression) methodCall).getArgumentList().getExpressions(); final int index = myMethod.getParameterList().getParameterIndex(parameter); if (index < expressions.length) { PsiExpression instanceValue = expressions[index]; instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue); if (instanceValue instanceof PsiLiteralExpression && ((PsiLiteralExpression) instanceValue).getValue() == null) { String message = RefactoringBundle.message( "0.contains.call.with.null.argument.for.parameter.1", RefactoringUIUtil.getDescription( ConflictsUtil.getContainer(methodCall), true), CommonRefactoringUtil.htmlEmphasize(parameter.getName())); conflicts.putValue(instanceValue, message); } } } else if (methodCall instanceof PsiMethodReferenceExpression) { conflicts.putValue(methodCall, "Method reference would be broken after move"); } } } } try { ConflictsUtil.checkMethodConflicts(myTargetClass, myMethod, getPatternMethod(), conflicts); } catch (IncorrectOperationException e) { } return showConflicts(conflicts, usages); }
@Override public boolean setupDefaultValues( ChangeInfo changeInfo, Ref<UsageInfo[]> refUsages, Project project) { if (!(changeInfo instanceof JavaChangeInfo)) return true; for (UsageInfo usageInfo : refUsages.get()) { if (usageInfo instanceof MethodCallUsageInfo) { MethodCallUsageInfo methodCallUsageInfo = (MethodCallUsageInfo) usageInfo; if (methodCallUsageInfo.isToChangeArguments()) { final PsiElement element = methodCallUsageInfo.getElement(); if (element == null) continue; final PsiMethod caller = RefactoringUtil.getEnclosingMethod(element); final boolean needDefaultValue = needDefaultValue(changeInfo, caller); if (needDefaultValue && (caller == null || !MethodSignatureUtil.isSuperMethod( methodCallUsageInfo.getReferencedMethod(), caller))) { final ParameterInfo[] parameters = changeInfo.getNewParameters(); for (ParameterInfo parameter : parameters) { final String defaultValue = parameter.getDefaultValue(); if (defaultValue == null && parameter.getOldIndex() == -1) { ((ParameterInfoImpl) parameter).setDefaultValue(""); if (!ApplicationManager.getApplication().isUnitTestMode()) { final PsiType type = ((ParameterInfoImpl) parameter) .getTypeWrapper() .getType(element, element.getManager()); final DefaultValueChooser chooser = new DefaultValueChooser( project, parameter.getName(), PsiTypesUtil.getDefaultValueOfType(type)); chooser.show(); if (chooser.isOK()) { if (chooser.feelLucky()) { parameter.setUseAnySingleVariable(true); } else { ((ParameterInfoImpl) parameter).setDefaultValue(chooser.getDefaultValue()); } } else { return false; } } } } } } } } return true; }
private static void fixJavadocsForChangedMethod( PsiMethod method, JavaChangeInfo changeInfo, int newParamsLength) throws IncorrectOperationException { final PsiParameter[] parameters = method.getParameterList().getParameters(); final JavaParameterInfo[] newParms = changeInfo.getNewParameters(); LOG.assertTrue(parameters.length <= newParamsLength); final Set<PsiParameter> newParameters = new HashSet<PsiParameter>(); final String[] oldParameterNames = changeInfo.getOldParameterNames(); for (int i = 0; i < newParamsLength; i++) { JavaParameterInfo newParm = newParms[i]; if (newParm.getOldIndex() < 0 || !newParm.getName().equals(oldParameterNames[newParm.getOldIndex()])) { newParameters.add(parameters[i]); } } RefactoringUtil.fixJavadocsForParams(method, newParameters); }
static PsiType getInitializerType( PsiType forcedType, PsiExpression parameterInitializer, PsiLocalVariable localVariable) { final PsiType initializerType; if (forcedType == null) { if (parameterInitializer == null) { if (localVariable != null) { initializerType = localVariable.getType(); } else { LOG.assertTrue(false); initializerType = null; } } else { if (localVariable == null) { initializerType = RefactoringUtil.getTypeByExpressionWithExpectedType(parameterInitializer); } else { initializerType = localVariable.getType(); } } } else { initializerType = forcedType; } return initializerType; }
private static void processPrimaryMethod( JavaChangeInfo changeInfo, PsiMethod method, PsiMethod baseMethod, boolean isOriginal) throws IncorrectOperationException { PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); if (changeInfo.isVisibilityChanged()) { PsiModifierList modifierList = method.getModifierList(); final String highestVisibility = isOriginal ? changeInfo.getNewVisibility() : VisibilityUtil.getHighestVisibility( changeInfo.getNewVisibility(), VisibilityUtil.getVisibilityModifier(modifierList)); VisibilityUtil.setVisibility(modifierList, highestVisibility); } if (changeInfo.isNameChanged()) { String newName = baseMethod == null ? changeInfo.getNewName() : RefactoringUtil.suggestNewOverriderName( method.getName(), baseMethod.getName(), changeInfo.getNewName()); if (newName != null && !newName.equals(method.getName())) { final PsiIdentifier nameId = method.getNameIdentifier(); assert nameId != null; nameId.replace( JavaPsiFacade.getInstance(method.getProject()) .getElementFactory() .createIdentifier(newName)); } } final PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : ChangeSignatureProcessor.calculateSubstitutor(method, baseMethod); if (changeInfo.isReturnTypeChanged()) { PsiType newTypeElement = changeInfo .getNewReturnType() .getType(changeInfo.getMethod().getParameterList(), method.getManager()); final PsiType returnType = substitutor.substitute(newTypeElement); // don't modify return type for non-Java overriders (EJB) if (method.getName().equals(changeInfo.getNewName())) { final PsiTypeElement typeElement = method.getReturnTypeElement(); if (typeElement != null) { typeElement.replace(factory.createTypeElement(returnType)); } } } PsiParameterList list = method.getParameterList(); PsiParameter[] parameters = list.getParameters(); final JavaParameterInfo[] parameterInfos = changeInfo.getNewParameters(); final int delta = baseMethod != null ? baseMethod.getParameterList().getParametersCount() - method.getParameterList().getParametersCount() : 0; PsiParameter[] newParms = new PsiParameter[Math.max(parameterInfos.length - delta, 0)]; final String[] oldParameterNames = changeInfo.getOldParameterNames(); final String[] oldParameterTypes = changeInfo.getOldParameterTypes(); for (int i = 0; i < newParms.length; i++) { JavaParameterInfo info = parameterInfos[i]; int index = info.getOldIndex(); if (index >= 0) { PsiParameter parameter = parameters[index]; newParms[i] = parameter; String oldName = oldParameterNames[index]; if (!oldName.equals(info.getName()) && oldName.equals(parameter.getName())) { PsiIdentifier newIdentifier = factory.createIdentifier(info.getName()); parameter.getNameIdentifier().replace(newIdentifier); } String oldType = oldParameterTypes[index]; if (!oldType.equals(info.getTypeText())) { parameter.normalizeDeclaration(); PsiType newType = substitutor.substitute( info.createType(changeInfo.getMethod().getParameterList(), method.getManager())); parameter.getTypeElement().replace(factory.createTypeElement(newType)); } } else { newParms[i] = createNewParameter(changeInfo, info, substitutor); } } resolveParameterVsFieldsConflicts(newParms, method, list, changeInfo.toRemoveParm()); fixJavadocsForChangedMethod(method, changeInfo, newParms.length); if (changeInfo.isExceptionSetOrOrderChanged()) { final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(changeInfo); fixPrimaryThrowsLists(method, newExceptions); } }
@Nullable private static PsiExpression createDefaultValue( JavaChangeInfo changeInfo, final PsiElementFactory factory, final JavaParameterInfo info, final PsiExpressionList list) throws IncorrectOperationException { if (info.isUseAnySingleVariable()) { final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper(); final PsiType type = info.getTypeWrapper().getType(changeInfo.getMethod(), list.getManager()); final VariablesProcessor processor = new VariablesProcessor(false) { protected boolean check(PsiVariable var, ResolveState state) { if (var instanceof PsiField && !resolveHelper.isAccessible((PsiField) var, list, null)) return false; if (var instanceof PsiLocalVariable && list.getTextRange().getStartOffset() <= var.getTextRange().getStartOffset()) return false; if (PsiTreeUtil.isAncestor(var, list, false)) return false; final PsiType varType = state.get(PsiSubstitutor.KEY).substitute(var.getType()); return type.isAssignableFrom(varType); } public boolean execute(PsiElement pe, ResolveState state) { super.execute(pe, state); return size() < 2; } }; PsiScopesUtil.treeWalkUp(processor, list, null); if (processor.size() == 1) { final PsiVariable result = processor.getResult(0); return factory.createExpressionFromText(result.getName(), list); } if (processor.size() == 0) { final PsiClass parentClass = PsiTreeUtil.getParentOfType(list, PsiClass.class); if (parentClass != null) { PsiClass containingClass = parentClass; final Set<PsiClass> containingClasses = new HashSet<PsiClass>(); while (containingClass != null) { if (type.isAssignableFrom(factory.createType(containingClass, PsiSubstitutor.EMPTY))) { containingClasses.add(containingClass); } containingClass = PsiTreeUtil.getParentOfType(containingClass, PsiClass.class); } if (containingClasses.size() == 1) { return RefactoringUtil.createThisExpression( parentClass.getManager(), containingClasses.contains(parentClass) ? null : containingClasses.iterator().next()); } } } } final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(list, PsiCallExpression.class); final String defaultValue = info.getDefaultValue(); return callExpression != null ? info.getValue(callExpression) : defaultValue.length() > 0 ? factory.createExpressionFromText(defaultValue, list) : null; }
protected void performRefactoring(UsageInfo[] usages) { try { PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); PsiType initializerType = getInitializerType(myForcedType, myParameterInitializer, myLocalVariable); setForcedType(initializerType); // Converting myParameterInitializer if (myParameterInitializer == null) { LOG.assertTrue(myLocalVariable != null); myParameterInitializer = factory.createExpressionFromText(myLocalVariable.getName(), myLocalVariable); } else if (myParameterInitializer instanceof PsiArrayInitializerExpression) { final PsiExpression newExprArrayInitializer = RefactoringUtil.createNewExpressionFromArrayInitializer( (PsiArrayInitializerExpression) myParameterInitializer, initializerType); myParameterInitializer = (PsiExpression) myParameterInitializer.replace(newExprArrayInitializer); } myInitializerWrapper = new JavaExpressionWrapper(myParameterInitializer); // Changing external occurences (the tricky part) IntroduceParameterUtil.processUsages(usages, this); if (myGenerateDelegate) { generateDelegate(myMethodToReplaceIn); if (myMethodToReplaceIn != myMethodToSearchFor) { final PsiMethod method = generateDelegate(myMethodToSearchFor); if (method.getContainingClass().isInterface()) { final PsiCodeBlock block = method.getBody(); if (block != null) { block.delete(); } } } } // Changing signature of initial method // (signature of myMethodToReplaceIn will be either changed now or have already been changed) LOG.assertTrue(initializerType.isValid()); final FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(myParameterName, myMethodToReplaceIn.getBody()); IntroduceParameterUtil.changeMethodSignatureAndResolveFieldConflicts( new UsageInfo(myMethodToReplaceIn), usages, this); if (myMethodToSearchFor != myMethodToReplaceIn) { IntroduceParameterUtil.changeMethodSignatureAndResolveFieldConflicts( new UsageInfo(myMethodToSearchFor), usages, this); } ChangeContextUtil.clearContextInfo(myParameterInitializer); // Replacing expression occurrences for (UsageInfo usage : usages) { if (usage instanceof ChangedMethodCallInfo) { PsiElement element = usage.getElement(); processChangedMethodCall(element); } else if (usage instanceof InternalUsageInfo) { PsiElement element = usage.getElement(); if (element instanceof PsiExpression) { element = RefactoringUtil.outermostParenthesizedExpression((PsiExpression) element); } if (element != null) { if (element.getParent() instanceof PsiExpressionStatement) { element.getParent().delete(); } else { PsiExpression newExpr = factory.createExpressionFromText(myParameterName, element); IntroduceVariableBase.replace((PsiExpression) element, newExpr, myProject); } } } } if (myLocalVariable != null && myRemoveLocalVariable) { myLocalVariable.normalizeDeclaration(); myLocalVariable.getParent().delete(); } fieldConflictsResolver.fix(); } catch (IncorrectOperationException ex) { LOG.error(ex); } }
private PsiMethod createMethodToAdd() { ChangeContextUtil.encodeContextInfo(myMethod, true); try { final PsiManager manager = myMethod.getManager(); final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); // correct internal references final PsiCodeBlock body = myMethod.getBody(); if (body != null) { final Map<PsiElement, PsiElement> replaceMap = new HashMap<PsiElement, PsiElement>(); body.accept( new JavaRecursiveElementVisitor() { @Override public void visitThisExpression(PsiThisExpression expression) { final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression); if (classReferencedByThis != null && !PsiTreeUtil.isAncestor(myMethod, classReferencedByThis, false)) { final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory(); String paramName = getParameterNameToCreate(classReferencedByThis); try { final PsiExpression refExpression = factory.createExpressionFromText(paramName, null); replaceMap.put(expression, refExpression); } catch (IncorrectOperationException e) { LOG.error(e); } } } @Override public void visitReferenceExpression(PsiReferenceExpression expression) { try { final PsiExpression qualifier = expression.getQualifierExpression(); final PsiElement resolved = expression.resolve(); if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression) qualifier).isReferenceTo(myTargetVariable)) { if (resolved instanceof PsiField) { for (PsiParameter parameter : myMethod.getParameterList().getParameters()) { if (Comparing.strEqual( parameter.getName(), ((PsiField) resolved).getName())) { qualifier.replace(factory.createExpressionFromText("this", null)); return; } } } // Target is a field, replace target.m -> m qualifier.delete(); return; } if (myTargetVariable.equals(resolved)) { PsiThisExpression thisExpression = RefactoringChangeUtil.createThisExpression( manager, PsiTreeUtil.isAncestor( myMethod, PsiTreeUtil.getParentOfType(expression, PsiClass.class), true) ? myTargetClass : null); replaceMap.put(expression, thisExpression); return; } else if (myMethod.equals(resolved)) { } else { PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression); if (classReferencedByThis != null) { final String paramName = getParameterNameToCreate(classReferencedByThis); if (paramName != null) { PsiReferenceExpression newQualifier = (PsiReferenceExpression) factory.createExpressionFromText(paramName, null); expression.setQualifierExpression(newQualifier); return; } } } super.visitReferenceExpression(expression); } catch (IncorrectOperationException e) { LOG.error(e); } } @Override public void visitNewExpression(PsiNewExpression expression) { try { final PsiExpression qualifier = expression.getQualifier(); if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression) qualifier).isReferenceTo(myTargetVariable)) { // Target is a field, replace target.new A() -> new A() qualifier.delete(); } else { final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression); if (classReferencedByThis != null) { if (qualifier != null) qualifier.delete(); final String paramName = getParameterNameToCreate(classReferencedByThis); final PsiExpression newExpression = factory.createExpressionFromText( paramName + "." + expression.getText(), null); replaceMap.put(expression, newExpression); } } super.visitNewExpression(expression); } catch (IncorrectOperationException e) { LOG.error(e); } } @Override public void visitMethodCallExpression(PsiMethodCallExpression expression) { correctMethodCall(expression, true); super.visitMethodCallExpression(expression); } }); for (PsiElement element : replaceMap.keySet()) { final PsiElement replacement = replaceMap.get(element); element.replace(replacement); } } final PsiMethod methodCopy = getPatternMethod(); final List<PsiParameter> newParameters = Arrays.asList(methodCopy.getParameterList().getParameters()); RefactoringUtil.fixJavadocsForParams(methodCopy, new HashSet<PsiParameter>(newParameters)); return methodCopy; } catch (IncorrectOperationException e) { LOG.error(e); return myMethod; } }