IDEA-86405 partial fix

This commit is contained in:
Danila Ponomarenko
2012-06-15 15:19:04 +04:00
parent af31dfe0f7
commit a423481233
@@ -25,6 +25,7 @@ import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
@@ -32,6 +33,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.impl.light.LightMethodBuilder;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtil;
@@ -100,7 +102,7 @@ public class GenerateMembersUtil {
element = element.getNextSibling();
}
if (element instanceof PsiField) {
PsiField field = (PsiField) element;
PsiField field = (PsiField)element;
PsiTypeElement typeElement = field.getTypeElement();
if (typeElement != null && !field.equals(typeElement.getParent())) {
field.normalizeDeclaration();
@@ -129,7 +131,7 @@ public class GenerateMembersUtil {
LOG.assertTrue(firstMember.isValid());
if (toEditMethodBody) {
PsiMethod method = (PsiMethod) firstMember;
PsiMethod method = (PsiMethod)firstMember;
PsiCodeBlock body = method.getBody();
if (body != null) {
PsiElement l = body.getFirstBodyElement();
@@ -154,7 +156,7 @@ public class GenerateMembersUtil {
int offset;
if (firstMember instanceof PsiMethod) {
PsiMethod method = (PsiMethod) firstMember;
PsiMethod method = (PsiMethod)firstMember;
PsiCodeBlock body = method.getBody();
if (body == null) {
offset = method.getTextRange().getStartOffset();
@@ -226,116 +228,187 @@ public class GenerateMembersUtil {
return substituteGenericMethod(method, substitutor, null);
}
public static PsiMethod substituteGenericMethod(PsiMethod method,
final PsiSubstitutor substitutor,
@Nullable final PsiElement target) {
Project project = method.getProject();
final JVMElementFactory factory;
if (target != null) {
factory = JVMElementFactories.getFactory(target.getLanguage(), method.getProject());
}
else {
factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
}
public static PsiMethod substituteGenericMethod(@NotNull PsiMethod sourceMethod,
@NotNull PsiSubstitutor substitutor,
@Nullable PsiElement target) {
final Project project = sourceMethod.getProject();
final JVMElementFactory factory = getFactory(sourceMethod, target);
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
final Module module = target != null ? ModuleUtil.findModuleForPsiElement(target) : null;
final GlobalSearchScope moduleScope = module != null ? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) : null;
try {
PsiType returnType = method.getReturnType();
//final LightMethodBuilder method = new LightMethodBuilder(PsiManager.getInstance(project),"");
PsiMethod newMethod;
if (method.isConstructor()) {
newMethod = factory.createConstructor();
newMethod.setName(method.getName());
}
else {
final PsiType substitutedReturnType = substituteType(substitutor, returnType);
newMethod = factory.createMethod(method.getName(), substitutedReturnType instanceof PsiWildcardType ? TypeConversionUtil.erasure(substitutedReturnType): substitutedReturnType);
}
VisibilityUtil.setVisibility(newMethod.getModifierList(), VisibilityUtil.getVisibilityModifier(method.getModifierList()));
PsiElement navigationElement = method.getNavigationElement();
PsiDocComment docComment = ((PsiDocCommentOwner)navigationElement).getDocComment();
if (docComment != null) {
newMethod.addAfter(docComment, null);
}
final Module module = target != null ? ModuleUtil.findModuleForPsiElement(target) : null;
final GlobalSearchScope moduleScope = module != null ? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) : null;
PsiParameter[] parameters = method.getParameterList().getParameters();
JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
Map<PsiType,Pair<String,Integer>> m = new HashMap<PsiType, Pair<String,Integer>>();
for (int i = 0; i < parameters.length; i++) {
PsiParameter parameter = parameters[i];
final PsiType parameterType = parameter.getType();
PsiType substituted = substituteType(substitutor, parameterType);
@NonNls String paramName = parameter.getName();
boolean isBaseNameGenerated = true;
final boolean isSubstituted = substituted.equals(parameterType);
if (!isSubstituted && isBaseNameGenerated(codeStyleManager, TypeConversionUtil.erasure(parameterType), paramName)) {
isBaseNameGenerated = false;
}
if (paramName == null || isBaseNameGenerated && !isSubstituted && isBaseNameGenerated(codeStyleManager, parameterType, paramName)) {
Pair<String, Integer> pair = m.get(substituted);
if (pair != null) {
paramName = pair.first + pair.second;
m.put(substituted, Pair.create(pair.first, pair.second.intValue() + 1));
}
else {
String[] names = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, substituted).names;
if (names.length > 0) {
paramName = names[0];
} else paramName = "p" + i;
m.put(substituted, new Pair<String, Integer>(paramName, 1));
}
}
if (paramName == null) paramName = "p" + i;
PsiParameter newParameter = factory.createParameter(paramName, substituted);
if (parameter.getLanguage() == newParameter.getLanguage()) {
PsiModifierList modifierList = newParameter.getModifierList();
modifierList = (PsiModifierList)modifierList.replace(parameter.getModifierList());
if (parameter.getLanguage() == JavaLanguage.INSTANCE) {
processAnnotations(project, modifierList, moduleScope);
}
}
else {
GenerateConstructorHandler.copyModifierList(factory,parameter, newParameter);
}
newMethod.getParameterList().add(newParameter);
}
for (PsiTypeParameter typeParam : method.getTypeParameters()) {
final PsiElement copy = typeParam.copy();
final Map<PsiElement, PsiElement> replacementMap = new HashMap<PsiElement, PsiElement>();
copy.accept(new JavaRecursiveElementVisitor(){
@Override
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
super.visitReferenceElement(reference);
final PsiElement resolve = reference.resolve();
if (resolve instanceof PsiTypeParameter) {
replacementMap.put(reference, factory.createReferenceElementByType((PsiClassType)substituteType(substitutor, factory.createType((PsiTypeParameter)resolve))));
}
}
});
newMethod.getTypeParameterList().add(RefactoringUtil.replaceElementsWithMap(copy, replacementMap));
}
PsiClassType[] thrownTypes = method.getThrowsList().getReferencedTypes();
for (PsiClassType thrownType : thrownTypes) {
newMethod.getThrowsList().add(factory.createReferenceElementByType((PsiClassType)substituteType(substitutor, thrownType)));
}
return newMethod;
final PsiMethod resultMethod = createMethod(factory, sourceMethod, substitutor);
copyDocComment(resultMethod, sourceMethod);
copyModifiers(sourceMethod.getModifierList(), resultMethod.getModifierList());
final PsiSubstitutor collisionResolvedSubstitutor = substituteTypeParameters(factory, sourceMethod.getTypeParameterList(), resultMethod.getTypeParameterList(), substitutor);
substituteParameters(project, factory, codeStyleManager, moduleScope, sourceMethod.getParameterList(), resultMethod.getParameterList(), collisionResolvedSubstitutor);
substituteThrows(factory, sourceMethod.getThrowsList(), resultMethod.getThrowsList(), collisionResolvedSubstitutor);
return resultMethod;
}
catch (IncorrectOperationException e) {
LOG.error(e);
return method;
return sourceMethod;
}
}
private static void copyModifiers(@NotNull PsiModifierList sourceModifierList,
@NotNull PsiModifierList targetModifierList) {
VisibilityUtil.setVisibility(targetModifierList, VisibilityUtil.getVisibilityModifier(sourceModifierList));
}
@NotNull
private static PsiSubstitutor substituteTypeParameters(@NotNull JVMElementFactory factory,
@Nullable PsiTypeParameterList sourceTypeParameterList,
@Nullable PsiTypeParameterList targetTypeParameterList,
@NotNull PsiSubstitutor substitutor) {
if (sourceTypeParameterList == null || targetTypeParameterList == null) {
return substitutor;
}
final Map<PsiTypeParameter, PsiType> substitutionMap = new HashMap<PsiTypeParameter, PsiType>(substitutor.getSubstitutionMap());
for (PsiTypeParameter typeParam : sourceTypeParameterList.getTypeParameters()) {
final PsiTypeParameter substitutedTypeParam = substituteTypeParameter(factory, typeParam, substitutor);
final PsiTypeParameter resolvedTypeParam = resolveTypeParametersCollision(factory,substitutedTypeParam,substitutor);
targetTypeParameterList.add(resolvedTypeParam);
if (substitutedTypeParam != resolvedTypeParam){
substitutionMap.put(typeParam, factory.createType(resolvedTypeParam));
}
}
return substitutionMap.isEmpty() ? substitutor : factory.createSubstitutor(substitutionMap);
}
@NotNull
private static PsiTypeParameter resolveTypeParametersCollision(@NotNull JVMElementFactory factory,
@NotNull PsiTypeParameter typeParam,
@NotNull PsiSubstitutor substitutor) {
for (PsiType type : substitutor.getSubstitutionMap().values()) {
if (Comparing.equal(type.getCanonicalText(), typeParam.getName())) {
final String newName = typeParam.getName() + "1";
final PsiTypeParameter newTypeParameter = factory.createTypeParameter(newName, typeParam.getSuperTypes());
substitutor.put(typeParam,factory.createType(newTypeParameter));
return newTypeParameter;
}
}
return typeParam;
}
@NotNull
private static PsiTypeParameter substituteTypeParameter(final @NotNull JVMElementFactory factory,
@NotNull PsiTypeParameter typeParameter,
final @NotNull PsiSubstitutor substitutor) {
final PsiElement copy = typeParameter.copy();
final Map<PsiElement, PsiElement> replacementMap = new HashMap<PsiElement, PsiElement>();
copy.accept(new JavaRecursiveElementVisitor() {
@Override
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
super.visitReferenceElement(reference);
final PsiElement resolve = reference.resolve();
if (resolve instanceof PsiTypeParameter) {
final PsiType type = factory.createType((PsiTypeParameter)resolve);
replacementMap.put(reference, factory.createReferenceElementByType((PsiClassType)substituteType(substitutor, type)));
}
}
});
return (PsiTypeParameter)RefactoringUtil.replaceElementsWithMap(copy, replacementMap);
}
private static void substituteParameters(@NotNull Project project,
@NotNull JVMElementFactory factory,
@NotNull JavaCodeStyleManager codeStyleManager,
@Nullable GlobalSearchScope moduleScope,
@NotNull PsiParameterList sourceParameterList,
@NotNull PsiParameterList targetParameterList,
@NotNull PsiSubstitutor substitutor) {
PsiParameter[] parameters = sourceParameterList.getParameters();
Map<PsiType, Pair<String, Integer>> m = new HashMap<PsiType, Pair<String, Integer>>();
for (int i = 0; i < parameters.length; i++) {
PsiParameter parameter = parameters[i];
final PsiType parameterType = parameter.getType();
final PsiType substituted = substituteType(substitutor, parameterType);
@NonNls String paramName = parameter.getName();
boolean isBaseNameGenerated = true;
final boolean isSubstituted = substituted.equals(parameterType);
if (!isSubstituted && isBaseNameGenerated(codeStyleManager, TypeConversionUtil.erasure(parameterType), paramName)) {
isBaseNameGenerated = false;
}
if (paramName == null || isBaseNameGenerated && !isSubstituted && isBaseNameGenerated(codeStyleManager, parameterType, paramName)) {
Pair<String, Integer> pair = m.get(substituted);
if (pair != null) {
paramName = pair.first + pair.second;
m.put(substituted, Pair.create(pair.first, pair.second.intValue() + 1));
}
else {
String[] names = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, substituted).names;
if (names.length > 0) {
paramName = names[0];
}
else {
paramName = "p" + i;
}
m.put(substituted, new Pair<String, Integer>(paramName, 1));
}
}
if (paramName == null) paramName = "p" + i;
final PsiParameter newParameter = factory.createParameter(paramName, substituted);
if (parameter.getLanguage() == newParameter.getLanguage()) {
PsiModifierList modifierList = newParameter.getModifierList();
modifierList = (PsiModifierList)modifierList.replace(parameter.getModifierList());
if (parameter.getLanguage() == JavaLanguage.INSTANCE) {
processAnnotations(project, modifierList, moduleScope);
}
}
else {
GenerateConstructorHandler.copyModifierList(factory, parameter, newParameter);
}
targetParameterList.add(newParameter);
}
}
private static void substituteThrows(@NotNull JVMElementFactory factory,
@NotNull PsiReferenceList sourceThrowsList,
@NotNull PsiReferenceList targetThrowsList,
@NotNull PsiSubstitutor substitutor) {
for (PsiClassType thrownType : sourceThrowsList.getReferencedTypes()) {
targetThrowsList.add(factory.createReferenceElementByType((PsiClassType)substituteType(substitutor, thrownType)));
}
}
private static void copyDocComment(PsiMethod source, PsiMethod target) {
final PsiElement navigationElement = source.getNavigationElement();
final PsiDocComment docComment = ((PsiDocCommentOwner)navigationElement).getDocComment();
if (docComment != null) {
target.addAfter(docComment, null);
}
}
@NotNull
private static PsiMethod createMethod(@NotNull JVMElementFactory factory,
@NotNull PsiMethod method,
@NotNull PsiSubstitutor substitutor) {
if (method.isConstructor()) {
return factory.createConstructor(method.getName());
}
final PsiType substitutedReturnType = substituteType(substitutor, method.getReturnType());
return factory.createMethod(method.getName(), substitutedReturnType instanceof PsiWildcardType ? TypeConversionUtil.erasure(substitutedReturnType) : substitutedReturnType);
}
@NotNull
private static JVMElementFactory getFactory(@NotNull PsiMethod method, @Nullable PsiElement target) {
if (target == null) {
return JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
}
return JVMElementFactories.getFactory(target.getLanguage(), method.getProject());
}
private static boolean isBaseNameGenerated(JavaCodeStyleManager codeStyleManager, PsiType parameterType, String paramName) {
final String[] baseSuggestions = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, parameterType).names;
boolean isBaseNameGenerated = false;
@@ -399,7 +472,7 @@ public class GenerateMembersUtil {
public static boolean shouldAddOverrideAnnotation(PsiElement context, boolean interfaceMethod) {
CodeStyleSettings style = CodeStyleSettingsManager.getSettings(context.getProject());
if (!style.INSERT_OVERRIDE_ANNOTATION) return false;
if (interfaceMethod) return PsiUtil.isLanguageLevel6OrHigher(context);
return PsiUtil.isLanguageLevel5OrHigher(context);
}