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.project.Project;
22 import com.intellij.openapi.util.TextRange;
23 import com.intellij.openapi.vfs.ReadonlyStatusHandler;
24 import com.intellij.openapi.vfs.VirtualFile;
25 import com.intellij.psi.*;
26 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
27 import com.intellij.psi.codeStyle.SuggestedNameInfo;
28 import com.intellij.psi.codeStyle.VariableKind;
29 import com.intellij.psi.util.PsiTreeUtil;
30 import com.intellij.psi.util.PsiTypesUtil;
31 import com.intellij.util.ArrayUtil;
32 import gnu.trove.THashSet;
33 import org.jetbrains.annotations.NotNull;
34 import org.jetbrains.annotations.Nullable;
35 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.MyPair;
36 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicElementSettings;
37 import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
38 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
39 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
40 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
41 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
42 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
43 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
44 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
45 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
46 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
51 * User: Dmitry.Krasilschikov
54 public class QuickfixUtil {
56 public static PsiClass findTargetClass(GrReferenceExpression refExpr) {
57 final PsiClass psiClass;
58 if (refExpr.isQualified()) {
59 GrExpression qualifier = refExpr.getQualifierExpression();
60 PsiType type = qualifier.getType();
61 if (!(type instanceof PsiClassType)) return null;
63 psiClass = ((PsiClassType)type).resolve();
65 GroovyPsiElement context = PsiTreeUtil.getParentOfType(refExpr, GrTypeDefinition.class, GroovyFileBase.class);
66 if (context instanceof GrTypeDefinition) {
67 return (PsiClass)context;
68 } else if (context instanceof GroovyFileBase) return ((GroovyFileBase)context).getScriptClass();
74 public static boolean isStaticCall(GrReferenceExpression refExpr) {
76 //todo: look more carefully
77 GrExpression qualifierExpression = refExpr.getQualifierExpression();
79 if (!(qualifierExpression instanceof GrReferenceExpression)) return false;
81 GrReferenceExpression referenceExpression = (GrReferenceExpression)qualifierExpression;
82 GroovyPsiElement resolvedElement = ResolveUtil.resolveProperty(referenceExpression, referenceExpression.getName());
84 if (resolvedElement == null) return false;
85 if (resolvedElement instanceof PsiClass) return true;
91 public static boolean ensureFileWritable(Project project, PsiFile file) {
92 final VirtualFile virtualFile = file.getVirtualFile();
93 final ReadonlyStatusHandler readonlyStatusHandler = ReadonlyStatusHandler.getInstance(project);
94 final ReadonlyStatusHandler.OperationStatus operationStatus = readonlyStatusHandler.ensureFilesWritable(virtualFile);
95 return !operationStatus.hasReadonlyFiles();
98 public static Editor positionCursor(@NotNull Project project, @NotNull PsiFile targetFile, @NotNull PsiElement element) {
99 TextRange range = element.getTextRange();
100 int textOffset = range.getStartOffset();
102 VirtualFile vFile = targetFile.getVirtualFile();
103 assert vFile != null;
104 OpenFileDescriptor descriptor = new OpenFileDescriptor(project, vFile, textOffset);
105 return FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
108 public static String[] getMethodArgumentsNames(Project project, PsiType[] types) {
109 Set<String> uniqNames = new LinkedHashSet<String>();
110 Set<String> nonUniqNames = new THashSet<String>();
111 for (PsiType type : types) {
112 final SuggestedNameInfo nameInfo =
113 JavaCodeStyleManager.getInstance(project).suggestVariableName(VariableKind.PARAMETER, null, null, type);
115 final String name = nameInfo.names[0];
116 if (uniqNames.contains(name)) {
118 while (uniqNames.contains(name + i)) i++;
119 uniqNames.add(name + i);
120 nonUniqNames.add(name);
126 final String[] result = new String[uniqNames.size()];
128 for (String name : uniqNames) {
129 result[i] = nonUniqNames.contains(name) ? name + 1 : name;
135 public static List<MyPair> swapArgumentsAndTypes(String[] names, PsiType[] types) {
136 List<MyPair> result = new ArrayList<MyPair>();
138 if (names.length != types.length) return Collections.emptyList();
140 for (int i = 0; i < names.length; i++) {
141 String name = names[i];
142 final PsiType type = types[i];
144 result.add(new MyPair(name, type.getCanonicalText()));
150 public static boolean isCall(GrReferenceExpression referenceExpression) {
151 return referenceExpression.getParent() instanceof GrCall;
154 public static String[] getArgumentsTypes(List<MyPair> listOfPairs) {
155 final List<String> result = new ArrayList<String>();
157 if (listOfPairs == null) return ArrayUtil.EMPTY_STRING_ARRAY;
158 for (MyPair listOfPair : listOfPairs) {
159 String type = PsiTypesUtil.unboxIfPossible(listOfPair.second);
163 return ArrayUtil.toStringArray(result);
166 public static String[] getArgumentsNames(List<MyPair> listOfPairs) {
167 final ArrayList<String> result = new ArrayList<String>();
168 for (MyPair listOfPair : listOfPairs) {
169 String name = listOfPair.first;
173 return ArrayUtil.toStringArray(result);
176 public static String shortenType(String typeText) {
177 if (typeText == null) return "";
178 final int i = typeText.lastIndexOf(".");
180 return typeText.substring(i + 1);
185 public static DynamicElementSettings createSettings(GrReferenceExpression referenceExpression) {
186 DynamicElementSettings settings = new DynamicElementSettings();
187 final PsiClass containingClass = findTargetClass(referenceExpression);
189 assert containingClass != null;
190 String className = containingClass.getQualifiedName();
191 className = className == null ? containingClass.getContainingFile().getName() : className;
193 if (isStaticCall(referenceExpression)) {
194 settings.setStatic(true);
197 settings.setContainingClassName(className);
198 settings.setName(referenceExpression.getName());
200 if (isCall(referenceExpression)) {
201 List<PsiType> unboxedTypes = new ArrayList<PsiType>();
202 for (PsiType type : PsiUtil.getArgumentTypes(referenceExpression, false)) {
203 unboxedTypes.add(TypesUtil.unboxPrimitiveTypeWrapperAndEraseGenerics(type));
205 final PsiType[] types = unboxedTypes.toArray(new PsiType[unboxedTypes.size()]);
206 final String[] names = getMethodArgumentsNames(referenceExpression.getProject(), types);
207 final List<MyPair> pairs = swapArgumentsAndTypes(names, types);
209 settings.setMethod(true);
210 settings.setPairs(pairs);
212 settings.setMethod(false);
217 public static DynamicElementSettings createSettings(GrArgumentLabel label, PsiClass targetClass) {
218 DynamicElementSettings settings = new DynamicElementSettings();
220 assert targetClass != null;
221 String className = targetClass.getQualifiedName();
222 className = className == null ? targetClass.getContainingFile().getName() : className;
224 settings.setContainingClassName(className);
225 settings.setName(label.getName());