| /* |
| * 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.psi.impl.source.resolve.reference.impl; |
| |
| import com.intellij.codeInsight.completion.InsertHandler; |
| import com.intellij.codeInsight.completion.InsertionContext; |
| import com.intellij.codeInsight.completion.JavaLookupElementBuilder; |
| import com.intellij.codeInsight.lookup.LookupElement; |
| import com.intellij.codeInsight.lookup.LookupElementBuilder; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.psi.*; |
| import com.intellij.psi.codeStyle.JavaCodeStyleManager; |
| import com.intellij.psi.impl.source.PsiClassReferenceType; |
| import com.intellij.psi.search.GlobalSearchScope; |
| import com.intellij.psi.util.*; |
| import com.intellij.util.IncorrectOperationException; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * @author Konstantin Bulenkov |
| */ |
| public class JavaLangClassMemberReference extends PsiReferenceBase<PsiLiteralExpression> implements InsertHandler<LookupElement> { |
| private final PsiExpression myContext; |
| |
| public JavaLangClassMemberReference(PsiLiteralExpression literal, PsiExpression context) { |
| super(literal); |
| myContext = context; |
| } |
| |
| @Override |
| public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { |
| return element; |
| } |
| |
| @Override |
| public PsiElement resolve() { |
| final String name = (String)getElement().getValue(); |
| final Type type = getType(); |
| |
| if (type != null) { |
| final PsiClass psiClass = getPsiClass(); |
| if (psiClass != null) { |
| PsiMember member; |
| if (type == Type.FIELD || type == Type.DECLARED_FIELD) { |
| member = psiClass.findFieldByName(name, false); |
| } else { |
| final PsiMethod[] methods = psiClass.findMethodsByName(name, false); |
| member = methods.length == 0 ? null : methods[0]; |
| } |
| |
| return member; |
| } |
| } |
| |
| return null; |
| } |
| |
| @Nullable |
| private PsiClass getPsiClass() { |
| if (myContext instanceof PsiClassObjectAccessExpression) { |
| return PsiTypesUtil.getPsiClass(((PsiClassObjectAccessExpression)myContext).getOperand().getType()); |
| } else if (myContext instanceof PsiMethodCallExpression) { |
| final PsiMethod method = ((PsiMethodCallExpression)myContext).resolveMethod(); |
| if (method != null && "forName".equals(method.getName()) && isClass(method.getContainingClass())) { |
| final PsiExpression[] expressions = ((PsiMethodCallExpression)myContext).getArgumentList().getExpressions(); |
| if (expressions.length == 1 && expressions[0] instanceof PsiLiteralExpression) { |
| final Object value = ((PsiLiteralExpression)expressions[0]).getValue(); |
| if (value instanceof String) { |
| final Project project = myContext.getProject(); |
| return JavaPsiFacade.getInstance(project).findClass(String.valueOf(value), GlobalSearchScope.allScope(project)); |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| private static boolean isClass(PsiClass aClass) { |
| return aClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(aClass.getQualifiedName()); |
| } |
| |
| @Nullable |
| private Type getType() { |
| boolean selfFound = false; |
| for (PsiElement child : myContext.getParent().getChildren()) { |
| if (!selfFound) { |
| if (child == myContext) { |
| selfFound = true; |
| } |
| continue; |
| } |
| |
| if (child instanceof PsiIdentifier) { |
| return Type.fromString(child.getText()); |
| } |
| } |
| return null; |
| } |
| |
| @NotNull |
| @Override |
| public Object[] getVariants() { |
| final Type type = getType(); |
| final PsiClass psiClass = getPsiClass(); |
| if (psiClass != null && type != null) { |
| if (type == Type.DECLARED_FIELD) { |
| return psiClass.getFields(); |
| } else if (type == Type.FIELD) { |
| final List<PsiField> fields = new ArrayList<PsiField>(); |
| for (PsiField field : psiClass.getFields()) { |
| if (isPublic(field)) { |
| fields.add(field); |
| } |
| } |
| return fields.toArray(); |
| } else if (type == Type.DECLARED_METHOD || type == Type.METHOD) { |
| final List<LookupElementBuilder> elements = new ArrayList<LookupElementBuilder>(); |
| for (PsiMethod method : psiClass.getMethods()) { |
| if (type == Type.DECLARED_METHOD || isPublic(method)) { |
| elements.add(JavaLookupElementBuilder.forMethod(method, PsiSubstitutor.EMPTY).withInsertHandler(this)); |
| } |
| } |
| return elements.toArray(); |
| } |
| } |
| return EMPTY_ARRAY; |
| } |
| |
| @Override |
| public void handleInsert(InsertionContext context, LookupElement item) { |
| final Object object = item.getObject(); |
| if (object instanceof PsiMethod) { |
| final PsiElement newElement = PsiUtilCore.getElementAtOffset(context.getFile(), context.getStartOffset()); |
| final int start = newElement.getTextRange().getEndOffset(); |
| final PsiElement params = newElement.getParent().getParent(); |
| final int end = params.getTextRange().getEndOffset() - 1; |
| final String types = getMethodTypes((PsiMethod)object); |
| context.getDocument().replaceString(start, end, types); |
| context.commitDocument(); |
| final PsiElement firstParam = PsiUtilCore.getElementAtOffset(context.getFile(), context.getStartOffset()); |
| final PsiMethodCallExpression methodCall = PsiTreeUtil.getParentOfType(firstParam, PsiMethodCallExpression.class); |
| if (methodCall != null) { |
| JavaCodeStyleManager.getInstance(context.getProject()).shortenClassReferences(methodCall); |
| } |
| } |
| } |
| |
| private static boolean isPublic(final PsiMember psiField) { |
| return psiField.hasModifierProperty(PsiModifier.PUBLIC); |
| } |
| |
| private static String getMethodTypes(PsiMethod method) { |
| final StringBuilder buf = new StringBuilder(); |
| for (PsiParameter parameter : method.getParameterList().getParameters()) { |
| buf.append(", ").append(TypeConversionUtil.erasure(parameter.getType()).getPresentableText()).append(".class"); |
| } |
| return buf.toString(); |
| } |
| |
| |
| enum Type { |
| FIELD, DECLARED_FIELD, METHOD, DECLARED_METHOD; |
| |
| @Nullable |
| static Type fromString(String s) { |
| if ("getField".equals(s)) return FIELD; |
| if ("getDeclaredField".equals(s)) return DECLARED_FIELD; |
| if ("getMethod".equals(s)) return METHOD; |
| if ("getDeclaredMethod".equals(s)) return DECLARED_METHOD; |
| return null; |
| } |
| } |
| } |