mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
IDEA-87401 Partially
This commit is contained in:
+3
-2
@@ -25,6 +25,7 @@ import com.intellij.codeInsight.generation.PsiMethodMember;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.impl.AssignFieldFromParameterAction;
|
||||
import com.intellij.codeInsight.intention.impl.CreateFieldFromParameterAction;
|
||||
import com.intellij.codeInsight.intention.impl.FieldFromParameterUtils;
|
||||
import com.intellij.ide.util.MemberChooser;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -385,12 +386,12 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction {
|
||||
}
|
||||
|
||||
if (o1 instanceof PsiField && o2 instanceof PsiParameter) {
|
||||
final PsiField field = CreateFieldFromParameterAction.getParameterAssignedToField((PsiParameter)o2);
|
||||
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 = CreateFieldFromParameterAction.getParameterAssignedToField((PsiParameter)o1);
|
||||
final PsiField field = FieldFromParameterUtils.getParameterAssignedToField((PsiParameter)o1);
|
||||
if (field == null) return -1;
|
||||
return field.getTextOffset() - o2.getTextOffset();
|
||||
}
|
||||
|
||||
+9
-17
@@ -36,21 +36,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class AssignFieldFromParameterAction extends BaseIntentionAction {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.AssignFieldFromParameterAction");
|
||||
|
||||
@Nullable
|
||||
private static PsiType getType(final PsiParameter myParameter) {
|
||||
if (myParameter == null) return null;
|
||||
PsiType type = myParameter.getType();
|
||||
if (type instanceof PsiEllipsisType) type = ((PsiEllipsisType)type).toArrayType();
|
||||
return type;
|
||||
}
|
||||
private static final Logger LOG = Logger.getInstance(AssignFieldFromParameterAction.class);
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
PsiParameter myParameter = CreateFieldFromParameterAction.findParameterAtCursor(file, editor);
|
||||
final PsiType type = getType(myParameter);
|
||||
PsiClass targetClass = myParameter == null ? null : PsiTreeUtil.getParentOfType(myParameter, PsiClass.class);
|
||||
final PsiParameter myParameter = FieldFromParameterUtils.findParameterAtCursor(file, editor);
|
||||
final PsiType type = FieldFromParameterUtils.getType(myParameter);
|
||||
final PsiClass targetClass = PsiTreeUtil.getParentOfType(myParameter, PsiClass.class);
|
||||
if (myParameter == null
|
||||
|| !myParameter.isValid()
|
||||
|| !myParameter.getManager().isInProject(myParameter)
|
||||
@@ -60,10 +52,10 @@ public class AssignFieldFromParameterAction extends BaseIntentionAction {
|
||||
|| !type.isValid()
|
||||
|| targetClass == null
|
||||
|| targetClass.isInterface()
|
||||
|| CreateFieldFromParameterAction.getParameterAssignedToField(myParameter) != null) {
|
||||
|| FieldFromParameterUtils.getParameterAssignedToField(myParameter) != null) {
|
||||
return false;
|
||||
}
|
||||
PsiField field = findFieldToAssign(myParameter);
|
||||
final PsiField field = findFieldToAssign(myParameter);
|
||||
if (field == null) return false;
|
||||
if (!field.getLanguage().isKindOf(JavaLanguage.INSTANCE)) return false;
|
||||
setText(CodeInsightBundle.message("intention.assign.field.from.parameter.text", field.getName()));
|
||||
@@ -79,7 +71,7 @@ public class AssignFieldFromParameterAction extends BaseIntentionAction {
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
PsiParameter myParameter = CreateFieldFromParameterAction.findParameterAtCursor(file, editor);
|
||||
PsiParameter myParameter = FieldFromParameterUtils.findParameterAtCursor(file, editor);
|
||||
if (!CodeInsightUtilBase.prepareFileForWrite(myParameter.getContainingFile())) return;
|
||||
|
||||
IdeDocumentHistory.getInstance(project).includeCurrentPlaceAsChangePlace();
|
||||
@@ -115,7 +107,7 @@ public class AssignFieldFromParameterAction extends BaseIntentionAction {
|
||||
PsiStatement assignmentStmt = factory.createStatementFromText(stmtText, methodBody);
|
||||
assignmentStmt = (PsiStatement)CodeStyleManager.getInstance(project).reformat(assignmentStmt);
|
||||
PsiStatement[] statements = methodBody.getStatements();
|
||||
int i = CreateFieldFromParameterAction.findFieldAssignmentAnchor(statements, null, targetClass, parameter);
|
||||
int i = FieldFromParameterUtils.findFieldAssignmentAnchor(statements, null, targetClass, parameter);
|
||||
PsiElement inserted;
|
||||
if (i == statements.length) {
|
||||
inserted = methodBody.add(assignmentStmt);
|
||||
@@ -138,7 +130,7 @@ public class AssignFieldFromParameterAction extends BaseIntentionAction {
|
||||
final boolean isMethodStatic = method.hasModifierProperty(PsiModifier.STATIC);
|
||||
|
||||
VariableKind kind = isMethodStatic ? VariableKind.STATIC_FIELD : VariableKind.FIELD;
|
||||
SuggestedNameInfo suggestedNameInfo = styleManager.suggestVariableName(kind, propertyName, null, getType(myParameter));
|
||||
SuggestedNameInfo suggestedNameInfo = styleManager.suggestVariableName(kind, propertyName, null, FieldFromParameterUtils.getSubstitutedType(myParameter));
|
||||
|
||||
final String fieldName = suggestedNameInfo.names[0];
|
||||
|
||||
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 com.intellij.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.CodeInsightUtilBase;
|
||||
import com.intellij.codeInsight.generation.ClassMember;
|
||||
import com.intellij.codeInsight.generation.MemberChooserObject;
|
||||
import com.intellij.codeInsight.generation.PsiMethodMember;
|
||||
import com.intellij.ide.util.MemberChooser;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.SuggestedNameInfo;
|
||||
import com.intellij.psi.codeStyle.VariableKind;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.ui.SimpleColoredComponent;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.ui.speedSearch.SpeedSearchUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ConcurrentWeakHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Danila Ponomarenko
|
||||
*/
|
||||
public class CreateAssignFieldsFromParametersAction extends BaseIntentionAction {
|
||||
private static final Logger LOG = Logger.getInstance(CreateFieldFromParameterAction.class);
|
||||
private static final Key<Map<SmartPsiElementPointer<PsiParameter>, Boolean>> PARAMS = Key.create("FIELDS_FROM_PARAMS");
|
||||
|
||||
private static final Object LOCK = new Object();
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
PsiParameter psiParameter = FieldFromParameterUtils.findParameterAtCursor(file, editor);
|
||||
PsiMethod method = findMethod(psiParameter, editor, file);
|
||||
if (method == null) return false;
|
||||
|
||||
final List<PsiParameter> parameters = getAvailableParameters(method);
|
||||
|
||||
synchronized (LOCK) {
|
||||
final Collection<SmartPsiElementPointer<PsiParameter>> params = getUnboundedParams(method);
|
||||
params.clear();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
params.add(SmartPointerManager.getInstance(project).createSmartPsiElementPointer(parameter));
|
||||
}
|
||||
if (params.size() <= 1) return false;
|
||||
if (psiParameter == null) {
|
||||
psiParameter = params.iterator().next().getElement();
|
||||
LOG.assertTrue(psiParameter != null);
|
||||
}
|
||||
|
||||
setText(CodeInsightBundle.message("intention.create.assign.fields.from.parameters.text", method.isConstructor() ? "Constructor" : "Method"));
|
||||
}
|
||||
return isAvailable(psiParameter);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethod findMethod(@Nullable PsiParameter parameter, @NotNull Editor editor, @NotNull PsiFile file) {
|
||||
if (parameter == null) {
|
||||
final PsiElement elementAt = file.findElementAt(editor.getCaretModel().getOffset());
|
||||
if (elementAt instanceof PsiIdentifier) {
|
||||
final PsiElement parent = elementAt.getParent();
|
||||
if (parent instanceof PsiMethod) {
|
||||
return (PsiMethod)parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
final PsiElement declarationScope = parameter.getDeclarationScope();
|
||||
if (declarationScope instanceof PsiMethod) {
|
||||
return (PsiMethod)declarationScope;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PsiParameter> getAvailableParameters(@NotNull PsiMethod method) {
|
||||
final List<PsiParameter> parameters = new ArrayList<PsiParameter>();
|
||||
for (PsiParameter parameter : method.getParameterList().getParameters()) {
|
||||
if (isAvailable(parameter)) {
|
||||
parameters.add(parameter);
|
||||
}
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private static boolean isAvailable(PsiParameter psiParameter) {
|
||||
final PsiType type = FieldFromParameterUtils.getSubstitutedType(psiParameter);
|
||||
PsiClass targetClass = PsiTreeUtil.getParentOfType(psiParameter, PsiClass.class);
|
||||
return psiParameter.isValid()
|
||||
&& psiParameter.getLanguage().isKindOf(JavaLanguage.INSTANCE)
|
||||
&& psiParameter.getDeclarationScope() instanceof PsiMethod
|
||||
&& ((PsiMethod)psiParameter.getDeclarationScope()).getBody() != null
|
||||
&& psiParameter.getManager().isInProject(psiParameter)
|
||||
&& type != null
|
||||
&& type.isValid()
|
||||
&& FieldFromParameterUtils.getParameterAssignedToField(psiParameter) == null
|
||||
&& targetClass != null
|
||||
&& !targetClass.isInterface()
|
||||
;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<SmartPsiElementPointer<PsiParameter>> getUnboundedParams(PsiMethod psiMethod) {
|
||||
Map<SmartPsiElementPointer<PsiParameter>, Boolean> params = psiMethod.getUserData(PARAMS);
|
||||
if (params == null) psiMethod.putUserData(PARAMS, params = new ConcurrentWeakHashMap<SmartPsiElementPointer<PsiParameter>, Boolean>(1));
|
||||
final Map<SmartPsiElementPointer<PsiParameter>, Boolean> finalParams = params;
|
||||
return new AbstractCollection<SmartPsiElementPointer<PsiParameter>>() {
|
||||
@Override
|
||||
public boolean add(SmartPsiElementPointer<PsiParameter> psiVariable) {
|
||||
return finalParams.put(psiVariable, Boolean.TRUE) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<SmartPsiElementPointer<PsiParameter>> iterator() {
|
||||
return finalParams.keySet().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return finalParams.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
finalParams.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return CodeInsightBundle.message("intention.create.assign.fields.from.parameters.family");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
invoke(project, editor, file, !ApplicationManager.getApplication().isUnitTestMode());
|
||||
}
|
||||
|
||||
private static void invoke(final Project project, Editor editor, PsiFile file, boolean isInteractive) {
|
||||
PsiParameter myParameter = FieldFromParameterUtils.findParameterAtCursor(file, editor);
|
||||
if (!CodeInsightUtilBase.prepareFileForWrite(file)) return;
|
||||
final PsiMethod method = myParameter != null ? (PsiMethod)myParameter.getDeclarationScope() : PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PsiMethod.class);
|
||||
LOG.assertTrue(method != null);
|
||||
final Collection<SmartPsiElementPointer<PsiParameter>> unboundedParams;
|
||||
synchronized (LOCK) {
|
||||
unboundedParams = getUnboundedParams(method);
|
||||
if (unboundedParams.isEmpty()) return;
|
||||
if (myParameter == null) {
|
||||
myParameter = unboundedParams.iterator().next().getElement();
|
||||
}
|
||||
}
|
||||
if (unboundedParams.size() > 1 && isInteractive) {
|
||||
ClassMember[] members = new ClassMember[unboundedParams.size()];
|
||||
ClassMember selection = null;
|
||||
int i = 0;
|
||||
for (SmartPsiElementPointer<PsiParameter> pointer : unboundedParams) {
|
||||
final PsiParameter parameter = pointer.getElement();
|
||||
final ParameterClassMember classMember = new ParameterClassMember(parameter);
|
||||
members[i++] = classMember;
|
||||
if (parameter == myParameter) {
|
||||
selection = classMember;
|
||||
}
|
||||
}
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
Arrays.sort(members, new Comparator<ClassMember>() {
|
||||
@Override
|
||||
public int compare(ClassMember o1, ClassMember o2) {
|
||||
return parameterList.getParameterIndex(((ParameterClassMember)o1).getParameter()) -
|
||||
parameterList.getParameterIndex(((ParameterClassMember)o2).getParameter());
|
||||
}
|
||||
});
|
||||
|
||||
final MemberChooser<ClassMember> chooser = new MemberChooser<ClassMember>(members, false, true, project);
|
||||
if (selection != null) {
|
||||
chooser.selectElements(new ClassMember[]{selection});
|
||||
}
|
||||
chooser.setTitle("Choose " + (method.isConstructor() ? "Constructor" : "Method") + " Parameters");
|
||||
chooser.setCopyJavadocVisible(false);
|
||||
chooser.show();
|
||||
if (chooser.getExitCode() != DialogWrapper.OK_EXIT_CODE) return;
|
||||
final List<ClassMember> selectedElements = chooser.getSelectedElements();
|
||||
if (selectedElements == null) return;
|
||||
|
||||
final HashSet<String> usedNames = new HashSet<String>();
|
||||
for (ClassMember selectedElement : selectedElements) {
|
||||
processParameter(project, ((ParameterClassMember)selectedElement).getParameter(), usedNames);
|
||||
}
|
||||
}
|
||||
else {
|
||||
processParameter(project, myParameter);
|
||||
}
|
||||
synchronized (LOCK) {
|
||||
unboundedParams.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static void processParameter(final Project project,
|
||||
final PsiParameter myParameter) {
|
||||
processParameter(project, myParameter, new HashSet<String>());
|
||||
}
|
||||
|
||||
private static void processParameter(final Project project,
|
||||
final PsiParameter myParameter,
|
||||
final Set<String> usedNames) {
|
||||
IdeDocumentHistory.getInstance(project).includeCurrentPlaceAsChangePlace();
|
||||
final PsiType type = FieldFromParameterUtils.getSubstitutedType(myParameter);
|
||||
final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(project);
|
||||
final String parameterName = myParameter.getName();
|
||||
String propertyName = styleManager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER);
|
||||
|
||||
final PsiClass targetClass = PsiTreeUtil.getParentOfType(myParameter, PsiClass.class);
|
||||
final PsiMethod method = (PsiMethod)myParameter.getDeclarationScope();
|
||||
|
||||
final boolean isMethodStatic = method.hasModifierProperty(PsiModifier.STATIC);
|
||||
|
||||
VariableKind kind = isMethodStatic ? VariableKind.STATIC_FIELD : VariableKind.FIELD;
|
||||
SuggestedNameInfo suggestedNameInfo = styleManager.suggestVariableName(kind, propertyName, null, type);
|
||||
String[] names = suggestedNameInfo.names;
|
||||
|
||||
final boolean isFinal = !isMethodStatic && method.isConstructor();
|
||||
final String fieldName = usedNames.add(names[0]) ? names[0] : JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName(names[0], myParameter, true);
|
||||
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
FieldFromParameterUtils.createFieldAndAddAssignment(
|
||||
project,
|
||||
targetClass,
|
||||
method,
|
||||
myParameter,
|
||||
type,
|
||||
fieldName,
|
||||
isMethodStatic,
|
||||
isFinal);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class ParameterClassMember implements ClassMember {
|
||||
private PsiParameter myParameter;
|
||||
|
||||
private ParameterClassMember(PsiParameter parameter) {
|
||||
myParameter = parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberChooserObject getParentNodeDelegate() {
|
||||
return new PsiMethodMember((PsiMethod)myParameter.getDeclarationScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderTreeNode(SimpleColoredComponent component, JTree tree) {
|
||||
SpeedSearchUtil.appendFragmentsForSpeedSearch(tree, getText(), SimpleTextAttributes.REGULAR_ATTRIBUTES, false, component);
|
||||
component.setIcon(myParameter.getIcon(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return myParameter.getName();
|
||||
}
|
||||
|
||||
public PsiParameter getParameter() {
|
||||
return myParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
-419
@@ -17,212 +17,53 @@ package com.intellij.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.CodeInsightUtilBase;
|
||||
import com.intellij.codeInsight.NullableNotNullManager;
|
||||
import com.intellij.codeInsight.generation.ClassMember;
|
||||
import com.intellij.codeInsight.generation.MemberChooserObject;
|
||||
import com.intellij.codeInsight.generation.PsiMethodMember;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.ide.util.MemberChooser;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.SuggestedNameInfo;
|
||||
import com.intellij.psi.codeStyle.VariableKind;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.ui.SimpleColoredComponent;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.ui.speedSearch.SpeedSearchUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ConcurrentWeakHashMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CreateFieldFromParameterAction implements IntentionAction {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.CreateFieldFromParameterAction");
|
||||
private static final Key<Map<SmartPsiElementPointer<PsiParameter>, Boolean>> PARAMS = Key.create("FIELDS_FROM_PARAMS");
|
||||
|
||||
private static final Object LOCK = new Object();
|
||||
|
||||
private String myName = "";
|
||||
private boolean myConstructor = false;
|
||||
|
||||
@Nullable
|
||||
private static PsiType[] getTypes(final PsiParameter parameter) {
|
||||
if (parameter == null) return null;
|
||||
PsiType type = parameter.getType();
|
||||
if (type instanceof PsiEllipsisType) type = ((PsiEllipsisType)type).toArrayType();
|
||||
if (type instanceof PsiArrayType) return new PsiType[]{type};
|
||||
final PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(type);
|
||||
final PsiClass psiClass = result.getElement();
|
||||
if (psiClass == null) return new PsiType[] {type};
|
||||
final HashSet<PsiTypeParameter> usedTypeParameters = new HashSet<PsiTypeParameter>();
|
||||
RefactoringUtil.collectTypeParameters(usedTypeParameters, parameter);
|
||||
for (Iterator<PsiTypeParameter> iterator = usedTypeParameters.iterator(); iterator.hasNext();) {
|
||||
PsiTypeParameter usedTypeParameter = iterator.next();
|
||||
if (parameter.getDeclarationScope() != usedTypeParameter.getOwner()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(parameter.getProject());
|
||||
PsiSubstitutor subst = PsiSubstitutor.EMPTY;
|
||||
for (PsiTypeParameter usedTypeParameter : usedTypeParameters) {
|
||||
subst = subst.put(usedTypeParameter, TypeConversionUtil.typeParameterErasure(usedTypeParameter));
|
||||
}
|
||||
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
|
||||
final Map<PsiTypeParameter, PsiType> typeMap = result.getSubstitutor().getSubstitutionMap();
|
||||
for (PsiTypeParameter typeParameter : typeMap.keySet()) {
|
||||
final PsiType psiType = typeMap.get(typeParameter);
|
||||
substitutor = substitutor.put(typeParameter, psiType != null ? subst.substitute(psiType) : null);
|
||||
}
|
||||
return new PsiType[]{psiClass instanceof PsiTypeParameter ? subst.substitute((PsiTypeParameter)psiClass) : elementFactory.createType(psiClass, substitutor)};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getText() {
|
||||
if (myName == null) {
|
||||
return CodeInsightBundle.message("intention.create.fields.from.parameters.text", myConstructor ? "Constructor" : "Method") ;
|
||||
}
|
||||
return CodeInsightBundle.message("intention.create.field.from.parameter.text", myName);
|
||||
}
|
||||
public class CreateFieldFromParameterAction extends BaseIntentionAction {
|
||||
private static final Logger LOG = Logger.getInstance(CreateFieldFromParameterAction.class);
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
PsiParameter psiParameter = findParameterAtCursor(file, editor);
|
||||
PsiMethod method = null;
|
||||
if (psiParameter == null) {
|
||||
final PsiElement elementAt = file.findElementAt(editor.getCaretModel().getOffset());
|
||||
if (elementAt instanceof PsiIdentifier) {
|
||||
final PsiElement parent = elementAt.getParent();
|
||||
if (parent instanceof PsiMethod) {
|
||||
method = (PsiMethod)parent;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final PsiElement declarationScope = psiParameter.getDeclarationScope();
|
||||
if (declarationScope instanceof PsiMethod) {
|
||||
method = (PsiMethod)declarationScope;
|
||||
}
|
||||
final PsiParameter parameter = FieldFromParameterUtils.findParameterAtCursor(file, editor);
|
||||
if (parameter == null || !isAvailable(parameter)) {
|
||||
return false;
|
||||
}
|
||||
if (method == null) return false;
|
||||
setText(CodeInsightBundle.message("intention.create.field.from.parameter.text", parameter.getName()));
|
||||
|
||||
final List<PsiParameter> parameters = new ArrayList<PsiParameter>();
|
||||
for (PsiParameter parameter : method.getParameterList().getParameters()) {
|
||||
if (isAvailable(parameter)) {
|
||||
parameters.add(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (LOCK) {
|
||||
final Collection<SmartPsiElementPointer<PsiParameter>> params = getUnboundedParams(method);
|
||||
params.clear();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
params.add(SmartPointerManager.getInstance(project).createSmartPsiElementPointer(parameter));
|
||||
}
|
||||
if (params.isEmpty()) return false;
|
||||
if (psiParameter == null) {
|
||||
psiParameter = params.iterator().next().getElement();
|
||||
LOG.assertTrue(psiParameter != null);
|
||||
}
|
||||
myName = params.size() > 1 && !ApplicationManager.getApplication().isUnitTestMode() ? null : psiParameter.getName();
|
||||
myConstructor = method.isConstructor();
|
||||
}
|
||||
return isAvailable(psiParameter);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isAvailable(PsiParameter psiParameter) {
|
||||
final PsiType[] types = getTypes(psiParameter);
|
||||
PsiClass targetClass = PsiTreeUtil.getParentOfType(psiParameter, PsiClass.class);
|
||||
final PsiType type = FieldFromParameterUtils.getSubstitutedType(psiParameter);
|
||||
final PsiClass targetClass = PsiTreeUtil.getParentOfType(psiParameter, PsiClass.class);
|
||||
return psiParameter.isValid()
|
||||
&& psiParameter.getLanguage().isKindOf(JavaLanguage.INSTANCE)
|
||||
&& psiParameter.getDeclarationScope() instanceof PsiMethod
|
||||
&& ((PsiMethod)psiParameter.getDeclarationScope()).getBody() != null
|
||||
&& psiParameter.getManager().isInProject(psiParameter)
|
||||
&& types != null
|
||||
&& types[0].isValid()
|
||||
&& getParameterAssignedToField(psiParameter) == null
|
||||
&& type != null
|
||||
&& type.isValid()
|
||||
&& FieldFromParameterUtils.getParameterAssignedToField(psiParameter) == null
|
||||
&& targetClass != null
|
||||
&& !targetClass.isInterface()
|
||||
;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<SmartPsiElementPointer<PsiParameter>> getUnboundedParams(PsiMethod psiMethod) {
|
||||
Map<SmartPsiElementPointer<PsiParameter>, Boolean> params = psiMethod.getUserData(PARAMS);
|
||||
if (params == null) psiMethod.putUserData(PARAMS, params = new ConcurrentWeakHashMap<SmartPsiElementPointer<PsiParameter>, Boolean>(1));
|
||||
final Map<SmartPsiElementPointer<PsiParameter>, Boolean> finalParams = params;
|
||||
return new AbstractCollection<SmartPsiElementPointer<PsiParameter>>() {
|
||||
@Override
|
||||
public boolean add(SmartPsiElementPointer<PsiParameter> psiVariable) {
|
||||
return finalParams.put(psiVariable, Boolean.TRUE) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<SmartPsiElementPointer<PsiParameter>> iterator() {
|
||||
return finalParams.keySet().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return finalParams.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
finalParams.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiField getParameterAssignedToField(final PsiParameter parameter) {
|
||||
for (PsiReference reference : ReferencesSearch.search(parameter, new LocalSearchScope(parameter.getDeclarationScope()), false)) {
|
||||
if (!(reference instanceof PsiReferenceExpression)) continue;
|
||||
final PsiReferenceExpression expression = (PsiReferenceExpression)reference;
|
||||
if (!(expression.getParent() instanceof PsiAssignmentExpression)) continue;
|
||||
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expression.getParent();
|
||||
if (assignmentExpression.getRExpression() != expression) continue;
|
||||
final PsiExpression lExpression = assignmentExpression.getLExpression();
|
||||
if (!(lExpression instanceof PsiReferenceExpression)) continue;
|
||||
final PsiElement element = ((PsiReferenceExpression)lExpression).resolve();
|
||||
if (element instanceof PsiField) return (PsiField)element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static PsiParameter findParameterAtCursor(final PsiFile file, final Editor editor) {
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
final PsiParameterList parameterList = PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiParameterList.class, false);
|
||||
if (parameterList == null) return null;
|
||||
final PsiParameter[] parameters = parameterList.getParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
final TextRange range = parameter.getTextRange();
|
||||
if (range.getStartOffset() <= offset && offset <= range.getEndOffset()) return parameter;
|
||||
}
|
||||
return null;
|
||||
&& !targetClass.isInterface();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -233,97 +74,35 @@ public class CreateFieldFromParameterAction implements IntentionAction {
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
invoke(project, editor, file, !ApplicationManager.getApplication().isUnitTestMode());
|
||||
}
|
||||
final PsiParameter myParameter = FieldFromParameterUtils.findParameterAtCursor(file, editor);
|
||||
if (myParameter == null || !CodeInsightUtilBase.prepareFileForWrite(file)) return;
|
||||
|
||||
private static void invoke(final Project project, Editor editor, PsiFile file, boolean isInteractive) {
|
||||
PsiParameter myParameter = findParameterAtCursor(file, editor);
|
||||
if (!CodeInsightUtilBase.prepareFileForWrite(file)) return;
|
||||
final PsiMethod method = myParameter != null ? (PsiMethod)myParameter.getDeclarationScope() : PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PsiMethod.class);
|
||||
LOG.assertTrue(method != null);
|
||||
final Collection<SmartPsiElementPointer<PsiParameter>> unboundedParams;
|
||||
synchronized (LOCK) {
|
||||
unboundedParams = getUnboundedParams(method);
|
||||
if (unboundedParams.isEmpty()) return;
|
||||
if (myParameter == null) {
|
||||
myParameter = unboundedParams.iterator().next().getElement();
|
||||
}
|
||||
}
|
||||
if (unboundedParams.size() > 1 && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
ClassMember[] members = new ClassMember[unboundedParams.size()];
|
||||
ClassMember selection = null;
|
||||
int i = 0;
|
||||
for (SmartPsiElementPointer<PsiParameter> pointer : unboundedParams) {
|
||||
final PsiParameter parameter = pointer.getElement();
|
||||
final ParameterClassMember classMember = new ParameterClassMember(parameter);
|
||||
members[i++] = classMember;
|
||||
if (parameter == myParameter) {
|
||||
selection = classMember;
|
||||
}
|
||||
}
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
Arrays.sort(members, new Comparator<ClassMember>() {
|
||||
@Override
|
||||
public int compare(ClassMember o1, ClassMember o2) {
|
||||
return parameterList.getParameterIndex(((ParameterClassMember)o1).getParameter()) -
|
||||
parameterList.getParameterIndex(((ParameterClassMember)o2).getParameter());
|
||||
}
|
||||
});
|
||||
|
||||
final MemberChooser<ClassMember> chooser = new MemberChooser<ClassMember>(members, false, true, project);
|
||||
if (selection != null) {
|
||||
chooser.selectElements(new ClassMember[] {selection});
|
||||
}
|
||||
chooser.setTitle("Choose " + (method.isConstructor() ? "Constructor" : "Method") + " Parameters to Generate Fields");
|
||||
chooser.setCopyJavadocVisible(false);
|
||||
chooser.show();
|
||||
if (chooser.getExitCode() != DialogWrapper.OK_EXIT_CODE) return;
|
||||
final List<ClassMember> selectedElements = chooser.getSelectedElements();
|
||||
if (selectedElements == null) return;
|
||||
if (selectedElements.size() == 1) {
|
||||
processParameter(project, ((ParameterClassMember)selectedElements.get(0)).getParameter(), isInteractive);
|
||||
} else {
|
||||
//do not ask for names in batch
|
||||
final HashSet<String> usedNames = new HashSet<String>();
|
||||
for (ClassMember selectedElement : selectedElements) {
|
||||
processParameter(project, ((ParameterClassMember)selectedElement).getParameter(), false, usedNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
processParameter(project, myParameter, isInteractive);
|
||||
}
|
||||
synchronized (LOCK) {
|
||||
unboundedParams.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static void processParameter(final Project project,
|
||||
final PsiParameter myParameter,
|
||||
boolean isInteractive) {
|
||||
processParameter(project, myParameter, isInteractive, new HashSet<String>());
|
||||
}
|
||||
|
||||
private static void processParameter(final Project project,
|
||||
final PsiParameter myParameter,
|
||||
boolean isInteractive,
|
||||
final Set<String> usedNames) {
|
||||
IdeDocumentHistory.getInstance(project).includeCurrentPlaceAsChangePlace();
|
||||
final PsiType[] types = getTypes(myParameter);
|
||||
try {
|
||||
processParameter(project, myParameter, !ApplicationManager.getApplication().isUnitTestMode());
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void processParameter(final @NotNull Project project,
|
||||
final @NotNull PsiParameter myParameter,
|
||||
final boolean isInteractive) {
|
||||
final PsiType type = FieldFromParameterUtils.getSubstitutedType(myParameter);
|
||||
final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(project);
|
||||
final String parameterName = myParameter.getName();
|
||||
String propertyName = styleManager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER);
|
||||
|
||||
String fieldNameToCalc;
|
||||
boolean isFinalToCalc;
|
||||
PsiType type;
|
||||
final PsiClass targetClass = PsiTreeUtil.getParentOfType(myParameter, PsiClass.class);
|
||||
final PsiMethod method = (PsiMethod)myParameter.getDeclarationScope();
|
||||
|
||||
final boolean isMethodStatic = method.hasModifierProperty(PsiModifier.STATIC);
|
||||
|
||||
VariableKind kind = isMethodStatic ? VariableKind.STATIC_FIELD : VariableKind.FIELD;
|
||||
SuggestedNameInfo suggestedNameInfo = styleManager.suggestVariableName(kind, propertyName, null, types[0]);
|
||||
SuggestedNameInfo suggestedNameInfo = styleManager.suggestVariableName(kind, propertyName, null, type);
|
||||
String[] names = suggestedNameInfo.names;
|
||||
|
||||
if (isInteractive) {
|
||||
@@ -338,16 +117,16 @@ public class CreateFieldFromParameterAction implements IntentionAction {
|
||||
}
|
||||
names = ArrayUtil.toStringArray(namesList);
|
||||
|
||||
boolean myBeFinal = method.isConstructor();
|
||||
CreateFieldFromParameterDialog dialog = new CreateFieldFromParameterDialog(
|
||||
final CreateFieldFromParameterDialog dialog = new CreateFieldFromParameterDialog(
|
||||
project,
|
||||
names,
|
||||
targetClass, myBeFinal, types);
|
||||
targetClass,
|
||||
method.isConstructor(),
|
||||
type
|
||||
);
|
||||
dialog.show();
|
||||
|
||||
if (!dialog.isOK()) return;
|
||||
type = dialog.getType();
|
||||
if (type == null) return;
|
||||
fieldNameToCalc = dialog.getEnteredName();
|
||||
isFinalToCalc = dialog.isDeclareFinal();
|
||||
|
||||
@@ -355,94 +134,24 @@ public class CreateFieldFromParameterAction implements IntentionAction {
|
||||
}
|
||||
else {
|
||||
isFinalToCalc = !isMethodStatic && method.isConstructor();
|
||||
if (usedNames.add(names[0])) {
|
||||
fieldNameToCalc = names[0];
|
||||
}
|
||||
else {
|
||||
fieldNameToCalc = JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName(names[0], myParameter, true);
|
||||
}
|
||||
type= types[0];
|
||||
fieldNameToCalc = names[0];
|
||||
}
|
||||
|
||||
final boolean isFinal = isFinalToCalc;
|
||||
final String fieldName = fieldNameToCalc;
|
||||
final PsiType fieldType = type;
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
PsiManager psiManager = PsiManager.getInstance(project);
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory();
|
||||
|
||||
PsiField field = factory.createField(fieldName, fieldType);
|
||||
PsiModifierList modifierList = field.getModifierList();
|
||||
modifierList.setModifierProperty(PsiModifier.STATIC, isMethodStatic);
|
||||
modifierList.setModifierProperty(PsiModifier.FINAL, isFinal);
|
||||
|
||||
final NullableNotNullManager manager = NullableNotNullManager.getInstance(project);
|
||||
final String nullable = manager.getNullable(myParameter);
|
||||
if (nullable != null) {
|
||||
modifierList.addAfter(factory.createAnnotationFromText("@" + nullable, field), null);
|
||||
} else if (isFinal) {
|
||||
final String notNull = manager.getNotNull(myParameter);
|
||||
if (notNull != null) {
|
||||
modifierList.addAfter(factory.createAnnotationFromText("@" + notNull, field), null);
|
||||
}
|
||||
}
|
||||
|
||||
PsiCodeBlock methodBody = method.getBody();
|
||||
if (methodBody == null) return;
|
||||
PsiStatement[] statements = methodBody.getStatements();
|
||||
|
||||
Ref<Pair<PsiField, Boolean>> anchorRef = new Ref<Pair<PsiField, Boolean>>();
|
||||
int i = findFieldAssignmentAnchor(statements, anchorRef, targetClass, myParameter);
|
||||
Pair<PsiField, Boolean> fieldAnchor = anchorRef.get();
|
||||
|
||||
String stmtText = fieldName + " = " + parameterName + ";";
|
||||
if (fieldName.equals(parameterName)) {
|
||||
@NonNls String prefix = isMethodStatic ? targetClass.getName() == null ? "" : targetClass.getName() + "." : "this.";
|
||||
stmtText = prefix + stmtText;
|
||||
}
|
||||
|
||||
PsiStatement assignmentStmt = factory.createStatementFromText(stmtText, methodBody);
|
||||
assignmentStmt = (PsiStatement)CodeStyleManager.getInstance(project).reformat(assignmentStmt);
|
||||
|
||||
if (i == statements.length) {
|
||||
methodBody.add(assignmentStmt);
|
||||
}
|
||||
else {
|
||||
methodBody.addAfter(assignmentStmt, i > 0 ? statements[i - 1] : null);
|
||||
}
|
||||
|
||||
if (fieldAnchor != null) {
|
||||
PsiVariable psiVariable = fieldAnchor.getFirst();
|
||||
psiVariable.normalizeDeclaration();
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
final PsiField[] fields = targetClass.getFields();
|
||||
for (PsiField f : fields) {
|
||||
if (f.getName().equals(field.getName())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (fieldAnchor != null) {
|
||||
Boolean insertBefore = fieldAnchor.getSecond();
|
||||
PsiField inField = fieldAnchor.getFirst();
|
||||
if (insertBefore.booleanValue()) {
|
||||
targetClass.addBefore(field, inField);
|
||||
}
|
||||
else {
|
||||
targetClass.addAfter(field, inField);
|
||||
}
|
||||
}
|
||||
else {
|
||||
targetClass.add(field);
|
||||
}
|
||||
}
|
||||
FieldFromParameterUtils.createFieldAndAddAssignment(
|
||||
project,
|
||||
targetClass,
|
||||
method,
|
||||
myParameter,
|
||||
type,
|
||||
fieldName,
|
||||
isMethodStatic,
|
||||
isFinal);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
@@ -451,90 +160,8 @@ public class CreateFieldFromParameterAction implements IntentionAction {
|
||||
});
|
||||
}
|
||||
|
||||
static int findFieldAssignmentAnchor(final PsiStatement[] statements, @Nullable final Ref<Pair<PsiField, Boolean>> anchorRef,
|
||||
final PsiClass targetClass, final PsiParameter myParameter) {
|
||||
int i = 0;
|
||||
for (; i < statements.length; i++) {
|
||||
PsiStatement psiStatement = statements[i];
|
||||
|
||||
if (psiStatement instanceof PsiExpressionStatement) {
|
||||
PsiExpressionStatement expressionStatement = (PsiExpressionStatement)psiStatement;
|
||||
PsiExpression expression = expressionStatement.getExpression();
|
||||
|
||||
if (expression instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
|
||||
@NonNls String text = methodCallExpression.getMethodExpression().getText();
|
||||
|
||||
if (text.equals("super") || text.equals("this")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (expression instanceof PsiAssignmentExpression) {
|
||||
PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expression;
|
||||
PsiExpression lExpression = assignmentExpression.getLExpression();
|
||||
PsiExpression rExpression = assignmentExpression.getRExpression();
|
||||
|
||||
if (!(lExpression instanceof PsiReferenceExpression)) break;
|
||||
if (!(rExpression instanceof PsiReferenceExpression)) break;
|
||||
|
||||
PsiReferenceExpression lReference = (PsiReferenceExpression)lExpression;
|
||||
PsiReferenceExpression rReference = (PsiReferenceExpression)rExpression;
|
||||
|
||||
PsiElement lElement = lReference.resolve();
|
||||
PsiElement rElement = rReference.resolve();
|
||||
|
||||
if (!(lElement instanceof PsiField) || ((PsiField)lElement).getContainingClass() != targetClass) break;
|
||||
if (!(rElement instanceof PsiParameter)) break;
|
||||
|
||||
if (myParameter.getTextRange().getStartOffset() < rElement.getTextRange().getStartOffset()) {
|
||||
if (anchorRef != null) {
|
||||
anchorRef.set(Pair.create((PsiField)lElement, Boolean.TRUE));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (anchorRef != null) {
|
||||
anchorRef.set(Pair.create((PsiField)lElement, Boolean.FALSE));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class ParameterClassMember implements ClassMember {
|
||||
private PsiParameter myParameter;
|
||||
|
||||
private ParameterClassMember(PsiParameter parameter) {
|
||||
myParameter = parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberChooserObject getParentNodeDelegate() {
|
||||
return new PsiMethodMember((PsiMethod)myParameter.getDeclarationScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderTreeNode(SimpleColoredComponent component, JTree tree) {
|
||||
SpeedSearchUtil.appendFragmentsForSpeedSearch(tree, getText(), SimpleTextAttributes.REGULAR_ATTRIBUTES, false, component);
|
||||
component.setIcon(myParameter.getIcon(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return myParameter.getName();
|
||||
}
|
||||
|
||||
public PsiParameter getParameter() {
|
||||
return myParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+41
-39
@@ -66,7 +66,7 @@ class CreateFieldFromParameterDialog extends DialogWrapper {
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
if (myCbFinal.isEnabled()) {
|
||||
PropertiesComponent.getInstance().setValue(PROPERTY_NAME, ""+myCbFinal.isSelected());
|
||||
PropertiesComponent.getInstance().setValue(PROPERTY_NAME, "" + myCbFinal.isSelected());
|
||||
}
|
||||
|
||||
final PsiField[] fields = myTargetClass.getFields();
|
||||
@@ -97,11 +97,11 @@ class CreateFieldFromParameterDialog extends DialogWrapper {
|
||||
|
||||
public String getEnteredName() {
|
||||
if (myNameField instanceof JComboBox) {
|
||||
JComboBox combobox = (JComboBox) myNameField;
|
||||
return (String) combobox.getEditor().getItem();
|
||||
JComboBox combobox = (JComboBox)myNameField;
|
||||
return (String)combobox.getEditor().getItem();
|
||||
}
|
||||
else {
|
||||
return ((JTextField) myNameField).getText();
|
||||
return ((JTextField)myNameField).getText();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,46 +123,46 @@ class CreateFieldFromParameterDialog extends DialogWrapper {
|
||||
combobox.setMaximumRowCount(8);
|
||||
|
||||
combobox.registerKeyboardAction(
|
||||
new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (combobox.isPopupVisible()) {
|
||||
combobox.setPopupVisible(false);
|
||||
}
|
||||
else {
|
||||
doCancelAction();
|
||||
}
|
||||
new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (combobox.isPopupVisible()) {
|
||||
combobox.setPopupVisible(false);
|
||||
}
|
||||
},
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
||||
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
|
||||
else {
|
||||
doCancelAction();
|
||||
}
|
||||
}
|
||||
},
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
||||
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
|
||||
);
|
||||
|
||||
combobox.addItemListener(
|
||||
new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
updateOkStatus();
|
||||
}
|
||||
new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
updateOkStatus();
|
||||
}
|
||||
}
|
||||
);
|
||||
combobox.getEditor().getEditorComponent().addKeyListener(
|
||||
new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
updateOkStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
updateOkStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
updateOkStatus();
|
||||
}
|
||||
new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
updateOkStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
updateOkStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
updateOkStatus();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
@@ -203,7 +203,8 @@ class CreateFieldFromParameterDialog extends DialogWrapper {
|
||||
if (myTypes.length > 1) {
|
||||
myTypeSelector = new TypeSelector(myProject);
|
||||
myTypeSelector.setTypes(myTypes);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
myTypeSelector = new TypeSelector(myTypes[0], myProject);
|
||||
}
|
||||
panel.add(myTypeSelector.getComponent(), gbConstraints);
|
||||
@@ -240,7 +241,8 @@ class CreateFieldFromParameterDialog extends DialogWrapper {
|
||||
myCbFinal = new JCheckBox(CodeInsightBundle.message("dialog.create.field.from.parameter.declare.final.checkbox"));
|
||||
if (myFieldMayBeFinal) {
|
||||
myCbFinal.setSelected(PropertiesComponent.getInstance().isTrueValue(PROPERTY_NAME));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
myCbFinal.setSelected(false);
|
||||
myCbFinal.setEnabled(false);
|
||||
}
|
||||
@@ -264,7 +266,7 @@ class CreateFieldFromParameterDialog extends DialogWrapper {
|
||||
myNameField.requestFocusInWindow();
|
||||
}
|
||||
else {
|
||||
((JComboBox) myNameField).getEditor().getEditorComponent().requestFocusInWindow();
|
||||
((JComboBox)myNameField).getEditor().getEditorComponent().requestFocusInWindow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+259
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 com.intellij.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInsight.NullableNotNullManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Danila Ponomarenko
|
||||
*/
|
||||
public final class FieldFromParameterUtils {
|
||||
@Nullable
|
||||
public static PsiParameter findParameterAtCursor(@NotNull PsiFile file, @NotNull Editor editor) {
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
final PsiParameterList parameterList = PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiParameterList.class, false);
|
||||
if (parameterList == null) return null;
|
||||
final PsiParameter[] parameters = parameterList.getParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
final TextRange range = parameter.getTextRange();
|
||||
if (range.getStartOffset() <= offset && offset <= range.getEndOffset()) return parameter;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiType getType(@Nullable PsiParameter myParameter) {
|
||||
if (myParameter == null) return null;
|
||||
PsiType type = myParameter.getType();
|
||||
return type instanceof PsiEllipsisType ? ((PsiEllipsisType)type).toArrayType() : type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiType getSubstitutedType(@Nullable PsiParameter parameter) {
|
||||
if (parameter == null) return null;
|
||||
|
||||
final PsiType type = getType(parameter);
|
||||
|
||||
if (type instanceof PsiArrayType) {
|
||||
return type;
|
||||
}
|
||||
|
||||
final PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(type);
|
||||
final PsiClass psiClass = result.getElement();
|
||||
if (psiClass == null) return type;
|
||||
final HashSet<PsiTypeParameter> usedTypeParameters = new HashSet<PsiTypeParameter>();
|
||||
RefactoringUtil.collectTypeParameters(usedTypeParameters, parameter);
|
||||
for (Iterator<PsiTypeParameter> iterator = usedTypeParameters.iterator(); iterator.hasNext(); ) {
|
||||
PsiTypeParameter usedTypeParameter = iterator.next();
|
||||
if (parameter.getDeclarationScope() != usedTypeParameter.getOwner()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(parameter.getProject());
|
||||
PsiSubstitutor subst = PsiSubstitutor.EMPTY;
|
||||
for (PsiTypeParameter usedTypeParameter : usedTypeParameters) {
|
||||
subst = subst.put(usedTypeParameter, TypeConversionUtil.typeParameterErasure(usedTypeParameter));
|
||||
}
|
||||
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
|
||||
final Map<PsiTypeParameter, PsiType> typeMap = result.getSubstitutor().getSubstitutionMap();
|
||||
for (PsiTypeParameter typeParameter : typeMap.keySet()) {
|
||||
final PsiType psiType = typeMap.get(typeParameter);
|
||||
substitutor = substitutor.put(typeParameter, psiType != null ? subst.substitute(psiType) : null);
|
||||
}
|
||||
return psiClass instanceof PsiTypeParameter ? subst.substitute((PsiTypeParameter)psiClass) : elementFactory.createType(psiClass, substitutor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiField getParameterAssignedToField(final PsiParameter parameter) {
|
||||
for (PsiReference reference : ReferencesSearch.search(parameter, new LocalSearchScope(parameter.getDeclarationScope()), false)) {
|
||||
if (!(reference instanceof PsiReferenceExpression)) continue;
|
||||
final PsiReferenceExpression expression = (PsiReferenceExpression)reference;
|
||||
if (!(expression.getParent() instanceof PsiAssignmentExpression)) continue;
|
||||
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expression.getParent();
|
||||
if (assignmentExpression.getRExpression() != expression) continue;
|
||||
final PsiExpression lExpression = assignmentExpression.getLExpression();
|
||||
if (!(lExpression instanceof PsiReferenceExpression)) continue;
|
||||
final PsiElement element = ((PsiReferenceExpression)lExpression).resolve();
|
||||
if (element instanceof PsiField) return (PsiField)element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int findFieldAssignmentAnchor(final PsiStatement[] statements,
|
||||
final @Nullable Ref<Pair<PsiField, Boolean>> anchorRef,
|
||||
final PsiClass targetClass,
|
||||
final PsiParameter myParameter) {
|
||||
int i = 0;
|
||||
for (; i < statements.length; i++) {
|
||||
PsiStatement psiStatement = statements[i];
|
||||
|
||||
if (psiStatement instanceof PsiExpressionStatement) {
|
||||
PsiExpressionStatement expressionStatement = (PsiExpressionStatement)psiStatement;
|
||||
PsiExpression expression = expressionStatement.getExpression();
|
||||
|
||||
if (expression instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
|
||||
@NonNls String text = methodCallExpression.getMethodExpression().getText();
|
||||
|
||||
if (text.equals("super") || text.equals("this")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (expression instanceof PsiAssignmentExpression) {
|
||||
PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expression;
|
||||
PsiExpression lExpression = assignmentExpression.getLExpression();
|
||||
PsiExpression rExpression = assignmentExpression.getRExpression();
|
||||
|
||||
if (!(lExpression instanceof PsiReferenceExpression)) break;
|
||||
if (!(rExpression instanceof PsiReferenceExpression)) break;
|
||||
|
||||
PsiReferenceExpression lReference = (PsiReferenceExpression)lExpression;
|
||||
PsiReferenceExpression rReference = (PsiReferenceExpression)rExpression;
|
||||
|
||||
PsiElement lElement = lReference.resolve();
|
||||
PsiElement rElement = rReference.resolve();
|
||||
|
||||
if (!(lElement instanceof PsiField) || ((PsiField)lElement).getContainingClass() != targetClass) break;
|
||||
if (!(rElement instanceof PsiParameter)) break;
|
||||
|
||||
if (myParameter.getTextRange().getStartOffset() < rElement.getTextRange().getStartOffset()) {
|
||||
if (anchorRef != null) {
|
||||
anchorRef.set(Pair.create((PsiField)lElement, Boolean.TRUE));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (anchorRef != null) {
|
||||
anchorRef.set(Pair.create((PsiField)lElement, Boolean.FALSE));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public static void createFieldAndAddAssignment(final @NotNull Project project,
|
||||
final @NotNull PsiClass targetClass,
|
||||
final @NotNull PsiMethod method,
|
||||
final @NotNull PsiParameter parameter,
|
||||
final @NotNull PsiType fieldType, final @NotNull String fieldName,
|
||||
final boolean isStatic, final boolean isFinal) throws IncorrectOperationException {
|
||||
|
||||
PsiManager psiManager = PsiManager.getInstance(project);
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory();
|
||||
|
||||
PsiField field = factory.createField(fieldName, fieldType);
|
||||
PsiModifierList modifierList = field.getModifierList();
|
||||
|
||||
if (modifierList == null) return;
|
||||
modifierList.setModifierProperty(PsiModifier.STATIC, isStatic);
|
||||
modifierList.setModifierProperty(PsiModifier.FINAL, isFinal);
|
||||
|
||||
final NullableNotNullManager manager = NullableNotNullManager.getInstance(project);
|
||||
final String nullable = manager.getNullable(parameter);
|
||||
if (nullable != null) {
|
||||
modifierList.addAfter(factory.createAnnotationFromText("@" + nullable, field), null);
|
||||
}
|
||||
else if (isFinal) {
|
||||
final String notNull = manager.getNotNull(parameter);
|
||||
if (notNull != null) {
|
||||
modifierList.addAfter(factory.createAnnotationFromText("@" + notNull, field), null);
|
||||
}
|
||||
}
|
||||
|
||||
PsiCodeBlock methodBody = method.getBody();
|
||||
if (methodBody == null) return;
|
||||
PsiStatement[] statements = methodBody.getStatements();
|
||||
|
||||
Ref<Pair<PsiField, Boolean>> anchorRef = new Ref<Pair<PsiField, Boolean>>();
|
||||
int i = findFieldAssignmentAnchor(statements, anchorRef, targetClass, parameter);
|
||||
Pair<PsiField, Boolean> fieldAnchor = anchorRef.get();
|
||||
|
||||
String stmtText = fieldName + " = " + parameter.getName() + ";";
|
||||
if (fieldName.equals(parameter.getName())) {
|
||||
@NonNls String prefix = isStatic ? targetClass.getName() == null ? "" : targetClass.getName() + "." : "this.";
|
||||
stmtText = prefix + stmtText;
|
||||
}
|
||||
|
||||
PsiStatement assignmentStmt = factory.createStatementFromText(stmtText, methodBody);
|
||||
assignmentStmt = (PsiStatement)CodeStyleManager.getInstance(project).reformat(assignmentStmt);
|
||||
|
||||
if (i == statements.length) {
|
||||
methodBody.add(assignmentStmt);
|
||||
}
|
||||
else {
|
||||
methodBody.addAfter(assignmentStmt, i > 0 ? statements[i - 1] : null);
|
||||
}
|
||||
|
||||
if (fieldAnchor != null) {
|
||||
PsiVariable psiVariable = fieldAnchor.getFirst();
|
||||
psiVariable.normalizeDeclaration();
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
final PsiField[] fields = targetClass.getFields();
|
||||
for (PsiField f : fields) {
|
||||
if (f.getName().equals(field.getName())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (fieldAnchor != null) {
|
||||
Boolean insertBefore = fieldAnchor.getSecond();
|
||||
PsiField inField = fieldAnchor.getFirst();
|
||||
if (insertBefore.booleanValue()) {
|
||||
targetClass.addBefore(field, inField);
|
||||
}
|
||||
else {
|
||||
targetClass.addAfter(field, inField);
|
||||
}
|
||||
}
|
||||
else {
|
||||
targetClass.add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private FieldFromParameterUtils() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user