blob: fb9bf953a4e39f1eea60acd4b1063a5b2ffb013c [file] [log] [blame]
/*
* Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.inline;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrVariableDeclarationOwner;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
/**
* Utility class to solve name conflicts related to local variable names of method to be inlined
* @author ilyas
*/
public class InlineMethodConflictSolver {
private InlineMethodConflictSolver() {}
@NotNull
public static String suggestNewName(@NotNull String startName, @Nullable GrMethod method, @NotNull PsiElement call, String... otherNames) {
String newName;
int i = 1;
PsiElement parent = call.getParent();
while (!(parent instanceof GrVariableDeclarationOwner) && parent != null) {
parent = parent.getParent();
}
if (parent == null || isValidName(startName, parent, call) && isValid(startName, otherNames)) {
return startName;
}
do {
newName = startName + i;
i++;
} while (!((method == null || isValidNameInMethod(newName, method)) &&
isValidName(newName, parent, call) && isValid(newName, otherNames)));
return newName;
}
static boolean isValid(@Nullable String name, String ... otherNames) {
for (String otherName : otherNames) {
if (otherName.equals(name)) {
return false;
}
}
return true;
}
private static boolean isValidNameInMethod(@NotNull String name, @NotNull GrMethod method) {
for (GrParameter parameter : method.getParameters()) {
if (name.equals(parameter.getName())) return false;
}
final GrOpenBlock block = method.getBlock();
if (block != null) {
return isValidNameDown(name, block, null);
}
return true;
}
public static boolean isValidName(@NotNull String name, @NotNull PsiElement scopeElement, PsiElement call) {
if (isValidNameDown(name, scopeElement, call)) {
if (!(scopeElement instanceof GroovyFileBase)) {
return isValidNameUp(name, scopeElement, call);
} else {
return true;
}
} else {
return false;
}
}
private static boolean isValidNameDown(@NotNull String name, @NotNull PsiElement startElement, @Nullable PsiElement call) {
PsiElement child = startElement.getFirstChild();
while (child != null) {
// Do not check defined classes, methods, closures and blocks before
if (child instanceof GrTypeDefinition ||
child instanceof GrMethod ||
call != null && GroovyRefactoringUtil.isAppropriateContainerForIntroduceVariable(child) &&
child.getTextRange().getEndOffset() < call.getTextRange().getStartOffset()) {
child = child.getNextSibling();
continue;
}
if (child instanceof GrAssignmentExpression) {
GrExpression lValue = ((GrAssignmentExpression) child).getLValue();
if (lValue instanceof GrReferenceExpression) {
GrReferenceExpression expr = (GrReferenceExpression) lValue;
if (expr.getQualifierExpression() == null && name.equals(expr.getReferenceName())) {
return false;
}
}
}
if (child instanceof GrVariable && name.equals(((GrVariable) child).getName())) {
return false;
} else {
boolean inner = isValidNameDown(name, child, call);
if (!inner) return false;
}
child = child.getNextSibling();
}
return true;
}
private static boolean isValidNameUp(@NotNull String name, @NotNull PsiElement startElement, @Nullable PsiElement call) {
if (startElement instanceof PsiFile) {
return true;
}
PsiElement prevSibling = startElement.getPrevSibling();
while (prevSibling != null) {
if (!isValidNameDown(name, prevSibling, call)) {
return false;
}
prevSibling = prevSibling.getPrevSibling();
}
PsiElement parent = startElement.getParent();
return parent == null || parent instanceof PsiDirectory || isValidNameUp(name, parent, call);
}
}