/* * Copyright 2008-2014 Bas Leijdekkers * * 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.siyeh.ig.fixes; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; import com.intellij.util.Query; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.ParenthesesUtils; import org.jetbrains.annotations.NotNull; public class ExtractParameterAsLocalVariableFix extends InspectionGadgetsFix { @Override @NotNull public String getFamilyName() { return InspectionGadgetsBundle.message( "extract.parameter.as.local.variable.quickfix"); } @Override public void doFix(Project project, ProblemDescriptor descriptor) { final PsiElement element = descriptor.getPsiElement(); if (!(element instanceof PsiExpression)) { return; } final PsiExpression expression = ParenthesesUtils.stripParentheses((PsiExpression)element); if (!(expression instanceof PsiReferenceExpression)) { return; } final PsiReferenceExpression parameterReference = (PsiReferenceExpression)expression; final PsiElement target = parameterReference.resolve(); if (!(target instanceof PsiParameter)) { return; } final PsiParameter parameter = (PsiParameter)target; final PsiElement declarationScope = parameter.getDeclarationScope(); final PsiElement body; if (declarationScope instanceof PsiMethod) { final PsiMethod method = (PsiMethod)declarationScope; body = method.getBody(); } else if (declarationScope instanceof PsiCatchSection) { final PsiCatchSection catchSection = (PsiCatchSection)declarationScope; body = catchSection.getCatchBlock(); } else if (declarationScope instanceof PsiLoopStatement) { final PsiLoopStatement forStatement = (PsiLoopStatement)declarationScope; final PsiStatement forBody = forStatement.getBody(); if (forBody instanceof PsiBlockStatement) { final PsiBlockStatement blockStatement = (PsiBlockStatement)forBody; body = blockStatement.getCodeBlock(); } else { body = forBody; } } else if (declarationScope instanceof PsiLambdaExpression) { final PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)declarationScope; body = lambdaExpression.getBody(); } else { return; } if (body == null) { return; } final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); final String parameterName = parameterReference.getText(); final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project); final String variableName = javaCodeStyleManager.suggestUniqueVariableName( parameterName, parameterReference, true); final SearchScope scope = parameter.getUseScope(); final Query<PsiReference> search = ReferencesSearch.search(parameter, scope); final PsiReference reference = search.findFirst(); if (reference == null) { return; } final PsiElement referenceElement = reference.getElement(); if (!(referenceElement instanceof PsiReferenceExpression)) { return; } final PsiReferenceExpression firstReference = (PsiReferenceExpression)referenceElement; final PsiElement[] children = body.getChildren(); final int startIndex; final int endIndex; if (body instanceof PsiCodeBlock) { startIndex = 1; endIndex = children.length - 1; } else { startIndex = 0; endIndex = children.length; } boolean newDeclarationCreated = false; final StringBuilder buffer = new StringBuilder(); for (int i = startIndex; i < endIndex; i++) { final PsiElement child = children[i]; newDeclarationCreated |= replaceVariableName(child, firstReference, variableName, parameterName, buffer); } if (body instanceof PsiExpression) { // expression lambda buffer.insert(0, "return "); buffer.append(';'); } final String replacementText; if (newDeclarationCreated) { replacementText = "{" + buffer + '}'; } else { final PsiType type = parameter.getType(); final String className = type.getCanonicalText(); replacementText = '{' + className + ' ' + variableName + " = " + parameterName + ';' + buffer + '}'; } final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); final PsiCodeBlock block = elementFactory.createCodeBlockFromText(replacementText, declarationScope); body.replace(block); codeStyleManager.reformat(declarationScope); } /** * @return true, if a declaration was introduced, false otherwise */ private static boolean replaceVariableName( PsiElement element, PsiReferenceExpression firstReference, String newName, String originalName, StringBuilder out) { if (element instanceof PsiReferenceExpression) { final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)element; if (element.equals(firstReference) && isLeftSideOfSimpleAssignment(referenceExpression)) { final PsiType type = firstReference.getType(); if (type != null) { out.append(type.getCanonicalText()); out.append(' '); out.append(newName); return true; } } final String text = element.getText(); if (text.equals(originalName)) { out.append(newName); return false; } } final PsiElement[] children = element.getChildren(); if (children.length == 0) { final String text = element.getText(); out.append(text); } else { boolean result = false; for (final PsiElement child : children) { if (result) { out.append(child.getText()); } else { result = replaceVariableName(child, firstReference, newName, originalName, out); } } return result; } return false; } private static boolean isLeftSideOfSimpleAssignment( PsiReferenceExpression reference) { if (reference == null) { return false; } final PsiElement parent = reference.getParent(); if (!(parent instanceof PsiAssignmentExpression)) { return false; } final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent; final IElementType tokenType = assignmentExpression.getOperationTokenType(); if (!JavaTokenType.EQ.equals(tokenType)) { return false; } final PsiExpression lExpression = assignmentExpression.getLExpression(); if (!reference.equals(lExpression)) { return false; } final PsiExpression rExpression = assignmentExpression.getRExpression(); if (rExpression instanceof PsiAssignmentExpression) { return false; } final PsiElement grandParent = parent.getParent(); return grandParent instanceof PsiExpressionStatement; } }