@Override public int compare(PsiVariable o1, PsiVariable o2) { if (o1 instanceof PsiParameter && ((PsiParameter) o1).isVarArgs()) return 1; if (o2 instanceof PsiParameter && ((PsiParameter) o2).isVarArgs()) return -1; if (o1 instanceof PsiField && o2 instanceof PsiField) { return o1.getTextOffset() - o2.getTextOffset(); } if (o1 instanceof PsiParameter && o2 instanceof PsiParameter) { return myParameterList.getParameterIndex((PsiParameter) o1) - myParameterList.getParameterIndex((PsiParameter) o2); } if (o1 instanceof PsiField && o2 instanceof PsiParameter) { final PsiField field = FieldFromParameterUtils.getParameterAssignedToField((PsiParameter) o2); if (field == null) return 1; return o1.getTextOffset() - field.getTextOffset(); } if (o1 instanceof PsiParameter && o2 instanceof PsiField) { final PsiField field = FieldFromParameterUtils.getParameterAssignedToField((PsiParameter) o1); if (field == null) return -1; return field.getTextOffset() - o2.getTextOffset(); } return 0; }
private static boolean addParameterToConstructor( final Project project, final PsiFile file, final Editor editor, final PsiMethod constructor, final PsiField[] fields) throws IncorrectOperationException { final PsiParameterList parameterList = constructor.getParameterList(); final PsiParameter[] parameters = parameterList.getParameters(); ParameterInfoImpl[] newParamInfos = new ParameterInfoImpl[parameters.length + fields.length]; final List<PsiVariable> params = new ArrayList<PsiVariable>(Arrays.asList(parameters)); Collections.addAll(params, fields); Collections.sort(params, new FieldParameterComparator(parameterList)); int i = 0; final HashMap<PsiField, String> usedFields = new HashMap<PsiField, String>(); for (PsiVariable param : params) { final PsiType paramType = param.getType(); if (param instanceof PsiParameter) { newParamInfos[i++] = new ParameterInfoImpl( parameterList.getParameterIndex((PsiParameter) param), param.getName(), paramType, param.getName()); } else { final String uniqueParameterName = getUniqueParameterName(parameters, param, usedFields); usedFields.put((PsiField) param, uniqueParameterName); newParamInfos[i++] = new ParameterInfoImpl(-1, uniqueParameterName, paramType, uniqueParameterName); } } final SmartPointerManager manager = SmartPointerManager.getInstance(project); final SmartPsiElementPointer constructorPointer = manager.createSmartPsiElementPointer(constructor); final PsiMethod fromText = JavaPsiFacade.getElementFactory(project) .createMethodFromText(createDummyMethod(constructor, newParamInfos), constructor); final PsiClass containingClass = constructor.getContainingClass(); if (containingClass == null) return false; final int minUsagesNumber = containingClass.findMethodsBySignature(fromText, false).length > 0 ? 0 : 1; final List<ParameterInfoImpl> parameterInfos = ChangeMethodSignatureFromUsageFix.performChange( project, editor, file, constructor, minUsagesNumber, newParamInfos, true, true); final ParameterInfoImpl[] resultParams = parameterInfos != null ? parameterInfos.toArray(new ParameterInfoImpl[parameterInfos.size()]) : newParamInfos; return ApplicationManager.getApplication() .runWriteAction( new Computable<Boolean>() { @Override public Boolean compute() { return doCreate( project, editor, parameters, constructorPointer, resultParams, usedFields); } }); }
public void inlineElement( final Project project, final Editor editor, final PsiElement psiElement) { final PsiParameter psiParameter = (PsiParameter) psiElement; final PsiParameterList parameterList = (PsiParameterList) psiParameter.getParent(); if (!(parameterList.getParent() instanceof PsiMethod)) { return; } final int index = parameterList.getParameterIndex(psiParameter); final PsiMethod method = (PsiMethod) parameterList.getParent(); String errorMessage = getCannotInlineMessage(psiParameter, method); if (errorMessage != null) { CommonRefactoringUtil.showErrorHint( project, editor, errorMessage, RefactoringBundle.message("inline.parameter.refactoring"), null); return; } final Ref<PsiExpression> refInitializer = new Ref<PsiExpression>(); final Ref<PsiExpression> refConstantInitializer = new Ref<PsiExpression>(); final Ref<PsiCallExpression> refMethodCall = new Ref<PsiCallExpression>(); final List<PsiReference> occurrences = Collections.synchronizedList(new ArrayList<PsiReference>()); final Collection<PsiFile> containingFiles = Collections.synchronizedSet(new HashSet<PsiFile>()); containingFiles.add(psiParameter.getContainingFile()); boolean result = ReferencesSearch.search(method) .forEach( new Processor<PsiReference>() { public boolean process(final PsiReference psiReference) { PsiElement element = psiReference.getElement(); final PsiElement parent = element.getParent(); if (parent instanceof PsiCallExpression) { final PsiCallExpression methodCall = (PsiCallExpression) parent; occurrences.add(psiReference); containingFiles.add(element.getContainingFile()); final PsiExpression[] expressions = methodCall.getArgumentList().getExpressions(); if (expressions.length <= index) return false; PsiExpression argument = expressions[index]; if (!refInitializer.isNull()) { return argument != null && PsiEquivalenceUtil.areElementsEquivalent( refInitializer.get(), argument) && PsiEquivalenceUtil.areElementsEquivalent( refMethodCall.get(), methodCall); } if (InlineToAnonymousConstructorProcessor.isConstant(argument) || getReferencedFinalField(argument) != null) { if (refConstantInitializer.isNull()) { refConstantInitializer.set(argument); } else if (!isSameConstant(argument, refConstantInitializer.get())) { return false; } } else if (!isRecursiveReferencedParameter(argument, psiParameter)) { if (!refConstantInitializer.isNull()) return false; refInitializer.set(argument); refMethodCall.set(methodCall); } } return true; } }); final int offset = editor.getCaretModel().getOffset(); final PsiElement refExpr = psiElement.getContainingFile().findElementAt(offset); final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(refExpr, PsiCodeBlock.class); if (codeBlock != null) { final PsiElement[] defs = DefUseUtil.getDefs(codeBlock, psiParameter, refExpr); if (defs.length == 1) { final PsiElement def = defs[0]; if (def instanceof PsiReferenceExpression && PsiUtil.isOnAssignmentLeftHand((PsiExpression) def)) { final PsiExpression rExpr = ((PsiAssignmentExpression) def.getParent()).getRExpression(); if (rExpr != null) { final PsiElement[] refs = DefUseUtil.getRefs(codeBlock, psiParameter, refExpr); if (InlineLocalHandler.checkRefsInAugmentedAssignmentOrUnaryModified(refs, def) == null) { new WriteCommandAction(project) { @Override protected void run(Result result) throws Throwable { for (final PsiElement ref : refs) { InlineUtil.inlineVariable( psiParameter, rExpr, (PsiJavaCodeReferenceElement) ref); } def.getParent().delete(); } }.execute(); return; } } } } } if (occurrences.isEmpty()) { CommonRefactoringUtil.showErrorHint( project, editor, "Method has no usages", RefactoringBundle.message("inline.parameter.refactoring"), null); return; } if (!result) { CommonRefactoringUtil.showErrorHint( project, editor, "Cannot find constant initializer for parameter", RefactoringBundle.message("inline.parameter.refactoring"), null); return; } if (!refInitializer.isNull()) { if (ApplicationManager.getApplication().isUnitTestMode()) { final InlineParameterExpressionProcessor processor = new InlineParameterExpressionProcessor( refMethodCall.get(), method, psiParameter, refInitializer.get(), method .getProject() .getUserData(InlineParameterExpressionProcessor.CREATE_LOCAL_FOR_TESTS)); processor.run(); } else { final boolean createLocal = ReferencesSearch.search(psiParameter).findAll().size() > 1; InlineParameterDialog dlg = new InlineParameterDialog( refMethodCall.get(), method, psiParameter, refInitializer.get(), createLocal); dlg.show(); } return; } if (refConstantInitializer.isNull()) { CommonRefactoringUtil.showErrorHint( project, editor, "Cannot find constant initializer for parameter", RefactoringBundle.message("inline.parameter.refactoring"), null); return; } final Ref<Boolean> isNotConstantAccessible = new Ref<Boolean>(); final PsiExpression constantExpression = refConstantInitializer.get(); constantExpression.accept( new JavaRecursiveElementVisitor() { @Override public void visitReferenceExpression(PsiReferenceExpression expression) { super.visitReferenceExpression(expression); final PsiElement resolved = expression.resolve(); if (resolved instanceof PsiMember && !PsiUtil.isAccessible((PsiMember) resolved, method, null)) { isNotConstantAccessible.set(Boolean.TRUE); } } }); if (!isNotConstantAccessible.isNull() && isNotConstantAccessible.get()) { CommonRefactoringUtil.showErrorHint( project, editor, "Constant initializer is not accessible in method body", RefactoringBundle.message("inline.parameter.refactoring"), null); return; } for (PsiReference psiReference : ReferencesSearch.search(psiParameter)) { final PsiElement element = psiReference.getElement(); if (element instanceof PsiExpression && PsiUtil.isAccessedForWriting((PsiExpression) element)) { CommonRefactoringUtil.showErrorHint( project, editor, "Inline parameter which has write usages is not supported", RefactoringBundle.message("inline.parameter.refactoring"), null); return; } } if (!ApplicationManager.getApplication().isUnitTestMode()) { String occurencesString = RefactoringBundle.message("occurences.string", occurrences.size()); String question = RefactoringBundle.message( "inline.parameter.confirmation", psiParameter.getName(), constantExpression.getText()) + " " + occurencesString; RefactoringMessageDialog dialog = new RefactoringMessageDialog( REFACTORING_NAME, question, HelpID.INLINE_VARIABLE, "OptionPane.questionIcon", true, project); dialog.show(); if (!dialog.isOK()) { return; } } final RefactoringEventData data = new RefactoringEventData(); data.addElement(psiElement.copy()); project .getMessageBus() .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC) .refactoringStarted(REFACTORING_ID, data); SameParameterValueInspection.InlineParameterValueFix.inlineSameParameterValue( method, psiParameter, constantExpression); project .getMessageBus() .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC) .refactoringDone(REFACTORING_ID, null); }