IDEA-51893: Quick Fix "​Create Field" when using Groovy named parameters
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / annotator / intentions / QuickfixUtil.java
blobcc819fbe7266566042c01cf711063ed3398d0989
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.jetbrains.plugins.groovy.annotator.intentions;
18 import com.intellij.openapi.editor.Editor;
19 import com.intellij.openapi.fileEditor.FileEditorManager;
20 import com.intellij.openapi.fileEditor.OpenFileDescriptor;
21 import com.intellij.openapi.module.Module;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.roots.ProjectRootManager;
24 import com.intellij.openapi.util.TextRange;
25 import com.intellij.openapi.vfs.ReadonlyStatusHandler;
26 import com.intellij.openapi.vfs.VirtualFile;
27 import com.intellij.psi.*;
28 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
29 import com.intellij.psi.codeStyle.SuggestedNameInfo;
30 import com.intellij.psi.codeStyle.VariableKind;
31 import com.intellij.psi.util.PsiTreeUtil;
32 import com.intellij.psi.util.PsiTypesUtil;
33 import com.intellij.util.ArrayUtil;
34 import gnu.trove.THashSet;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
37 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.MyPair;
38 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicElementSettings;
39 import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
40 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
41 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
42 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
43 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
44 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
45 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
46 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
47 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
48 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
50 import java.util.*;
52 /**
53 * User: Dmitry.Krasilschikov
54 * Date: 20.12.2007
56 public class QuickfixUtil {
57 @Nullable
58 public static PsiClass findTargetClass(GrReferenceExpression refExpr) {
59 final PsiClass psiClass;
60 if (refExpr.isQualified()) {
61 GrExpression qualifier = refExpr.getQualifierExpression();
62 PsiType type = qualifier.getType();
63 if (!(type instanceof PsiClassType)) return null;
65 psiClass = ((PsiClassType)type).resolve();
66 } else {
67 GroovyPsiElement context = PsiTreeUtil.getParentOfType(refExpr, GrTypeDefinition.class, GroovyFileBase.class);
68 if (context instanceof GrTypeDefinition) {
69 return (PsiClass)context;
70 } else if (context instanceof GroovyFileBase) return ((GroovyFileBase)context).getScriptClass();
71 return null;
73 return psiClass;
76 public static boolean isStaticCall(GrReferenceExpression refExpr) {
78 //todo: look more carefully
79 GrExpression qualifierExpression = refExpr.getQualifierExpression();
81 if (!(qualifierExpression instanceof GrReferenceExpression)) return false;
83 GrReferenceExpression referenceExpression = (GrReferenceExpression)qualifierExpression;
84 GroovyPsiElement resolvedElement = ResolveUtil.resolveProperty(referenceExpression, referenceExpression.getName());
86 if (resolvedElement == null) return false;
87 if (resolvedElement instanceof PsiClass) return true;
89 return false;
93 public static boolean ensureFileWritable(Project project, PsiFile file) {
94 final VirtualFile virtualFile = file.getVirtualFile();
95 final ReadonlyStatusHandler readonlyStatusHandler = ReadonlyStatusHandler.getInstance(project);
96 final ReadonlyStatusHandler.OperationStatus operationStatus = readonlyStatusHandler.ensureFilesWritable(virtualFile);
97 return !operationStatus.hasReadonlyFiles();
100 public static Editor positionCursor(@NotNull Project project, @NotNull PsiFile targetFile, @NotNull PsiElement element) {
101 TextRange range = element.getTextRange();
102 int textOffset = range.getStartOffset();
104 VirtualFile vFile = targetFile.getVirtualFile();
105 assert vFile != null;
106 OpenFileDescriptor descriptor = new OpenFileDescriptor(project, vFile, textOffset);
107 return FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
110 public static String[] getMethodArgumentsNames(Project project, PsiType[] types) {
111 Set<String> uniqNames = new LinkedHashSet<String>();
112 Set<String> nonUniqNames = new THashSet<String>();
113 for (PsiType type : types) {
114 final SuggestedNameInfo nameInfo =
115 JavaCodeStyleManager.getInstance(project).suggestVariableName(VariableKind.PARAMETER, null, null, type);
117 final String name = nameInfo.names[0];
118 if (uniqNames.contains(name)) {
119 int i = 2;
120 while (uniqNames.contains(name + i)) i++;
121 uniqNames.add(name + i);
122 nonUniqNames.add(name);
123 } else {
124 uniqNames.add(name);
128 final String[] result = new String[uniqNames.size()];
129 int i = 0;
130 for (String name : uniqNames) {
131 result[i] = nonUniqNames.contains(name) ? name + 1 : name;
132 i++;
134 return result;
137 public static List<MyPair> swapArgumentsAndTypes(String[] names, PsiType[] types) {
138 List<MyPair> result = new ArrayList<MyPair>();
140 if (names.length != types.length) return Collections.emptyList();
142 for (int i = 0; i < names.length; i++) {
143 String name = names[i];
144 final PsiType type = types[i];
146 result.add(new MyPair(name, type.getCanonicalText()));
149 return result;
152 public static boolean isCall(GrReferenceExpression referenceExpression) {
153 return referenceExpression.getParent() instanceof GrCall;
156 public static String[] getArgumentsTypes(List<MyPair> listOfPairs) {
157 final List<String> result = new ArrayList<String>();
159 if (listOfPairs == null) return new String[0];
160 for (MyPair listOfPair : listOfPairs) {
161 String type = PsiTypesUtil.unboxIfPossible(listOfPair.second);
162 result.add(type);
165 return ArrayUtil.toStringArray(result);
168 public static String[] getArgumentsNames(List<MyPair> listOfPairs) {
169 final ArrayList<String> result = new ArrayList<String>();
170 for (MyPair listOfPair : listOfPairs) {
171 String name = listOfPair.first;
172 result.add(name);
175 return ArrayUtil.toStringArray(result);
178 public static String shortenType(String typeText) {
179 if (typeText == null) return "";
180 final int i = typeText.lastIndexOf(".");
181 if (i != -1) {
182 return typeText.substring(i + 1);
184 return typeText;
187 public static Module getModuleByPsiFile(PsiFile containingFile) {
188 VirtualFile file;
189 if (containingFile != null) {
190 file = containingFile.getVirtualFile();
191 if (file == null) return null;
192 } else {
193 return null;
196 return ProjectRootManager.getInstance(containingFile.getProject()).getFileIndex().getModuleForFile(file);
200 public static DynamicElementSettings createSettings(GrReferenceExpression referenceExpression) {
201 DynamicElementSettings settings = new DynamicElementSettings();
202 final PsiClass containingClass = findTargetClass(referenceExpression);
204 assert containingClass != null;
205 String className = containingClass.getQualifiedName();
206 className = className == null ? containingClass.getContainingFile().getName() : className;
208 if (isStaticCall(referenceExpression)) {
209 settings.setStatic(true);
212 settings.setContainingClassName(className);
213 settings.setName(referenceExpression.getName());
215 if (isCall(referenceExpression)) {
216 List<PsiType> unboxedTypes = new ArrayList<PsiType>();
217 for (PsiType type : PsiUtil.getArgumentTypes(referenceExpression, false, false)) {
218 unboxedTypes.add(TypesUtil.unboxPrimitiveTypeWraperAndEraseGenerics(type));
220 final PsiType[] types = unboxedTypes.toArray(new PsiType[unboxedTypes.size()]);
221 final String[] names = getMethodArgumentsNames(referenceExpression.getProject(), types);
222 final List<MyPair> pairs = swapArgumentsAndTypes(names, types);
224 settings.setMethod(true);
225 settings.setPairs(pairs);
226 } else {
227 settings.setMethod(false);
229 return settings;
232 public static DynamicElementSettings createSettings(GrArgumentLabel label, PsiClass targetClass) {
233 DynamicElementSettings settings = new DynamicElementSettings();
235 assert targetClass != null;
236 String className = targetClass.getQualifiedName();
237 className = className == null ? targetClass.getContainingFile().getName() : className;
239 settings.setContainingClassName(className);
240 settings.setName(label.getName());
242 return settings;