package jetbrains.mps.idea.scopes;/* * 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. */ import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightMethod; import com.intellij.psi.scope.BaseScopeProcessor; import com.intellij.util.Consumer; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; import java.util.Set; public class IdeaScopesUtils { private static CompletionParameters createCompletionParameter(@NotNull final PsiElement position, @NotNull final PsiFile originalFile, final CompletionType completionType, int offset, final int invocationCount, Lookup lookup) { Constructor c = CompletionParameters.class.getDeclaredConstructors()[0]; c.setAccessible(true); try { if (c.getParameterTypes().length == 6) { return (CompletionParameters)c.newInstance(position, originalFile, completionType, offset, invocationCount, lookup); } else { return (CompletionParameters)c.newInstance(position, originalFile, completionType, offset, invocationCount, lookup, false); } } catch (Exception e) { throw new RuntimeException(e); } } public static List<String> getMembersFromClass_New(PsiClass clazz) { String methodText = "public static void scopes_test_239(" + clazz.getName() + " test) { test.? }"; PsiElementFactory elementFactory = JavaPsiFacade.getInstance(clazz.getProject()).getElementFactory(); PsiMethod psiMethod = elementFactory.createMethodFromText(methodText.replace("?", CompletionInitializationContext.DUMMY_IDENTIFIER), clazz); psiMethod = new LightMethod(clazz.getManager(), psiMethod, clazz); PsiReferenceExpression thisRef = (PsiReferenceExpression)psiMethod.getBody().getStatements()[0].getFirstChild(); PsiElement element = thisRef.getChildren()[3]; CompletionParameters _parameters = createCompletionParameter(element, element.getContainingFile(), CompletionType.BASIC, element.getTextRange().getStartOffset(), 1, null); JavaCompletionContributor contributor = new JavaCompletionContributor(); MyResultSet resultSet = new MyResultSet(contributor); contributor.fillCompletionVariants(_parameters, resultSet); return resultSet.result; } public static List<String> getMembersFromClass_Old(PsiClass clazz) { String methodText = "public static void scopes_test_239() { " + clazz.getName() + ".? }"; PsiElementFactory elementFactory = JavaPsiFacade.getInstance(clazz.getProject()).getElementFactory(); PsiMethod psiMethod = elementFactory.createMethodFromText(methodText.replace("?", CompletionInitializationContext.DUMMY_IDENTIFIER), clazz); psiMethod = new LightMethod(clazz.getManager(), psiMethod, clazz); PsiReferenceExpression thisRef = (PsiReferenceExpression)psiMethod.getBody().getStatements()[0].getFirstChild(); return getMembersFromReference(thisRef); } private static List<String> getMembersFromReference(PsiJavaReference reference) { MyProcessor processor = new MyProcessor(); reference.processVariants(processor); return processor.myResults; } private static String getMethodParametersPresentation(PsiMethod method) { return String.format("<%d>(%d)", method.getTypeParameters().length, method.getParameterList().getParametersCount()); } private static String getSignature(PsiElement element) { if (!(element instanceof PsiMember)) { return "Not psi member: " + element.toString(); } PsiMember member = (PsiMember)element; PsiClass memberClazz = member.getContainingClass(); boolean isStatic = member.getModifierList().hasModifierProperty(PsiModifier.STATIC); return (isStatic ? "static " : "") + memberClazz.getQualifiedName() + ":" + member.getName() + (member instanceof PsiMethod ? getMethodParametersPresentation((PsiMethod)member) : ""); } private static class MyProcessor extends BaseScopeProcessor { public final Set<Object> myResultNames = new THashSet<Object>(); public final List<String> myResults = new ArrayList<String>(); private static Object getUniqueId(Object element, PsiSubstitutor substitutor) { if (element instanceof PsiClass) { return ((PsiClass)element).getQualifiedName(); } if (element instanceof PsiPackage) { return ((PsiPackage)element).getQualifiedName(); } if (element instanceof PsiMethod) { return ((PsiMethod)element).getSignature(substitutor); } if (element instanceof PsiVariable) { return "#" + ((PsiVariable)element).getName(); } return null; } @Override public boolean execute(@NotNull PsiElement element, ResolveState state) { if (myResultNames.add(getUniqueId((PsiNamedElement)element, state.get(PsiSubstitutor.KEY)))) { myResults.add(getSignature(element)); } return true; } } private static class MyResultSet extends CompletionResultSet { public final List<String> result = new ArrayList<String>(); MyResultSet(CompletionContributor contributor) { super(new PlainPrefixMatcher(""), Consumer.EMPTY_CONSUMER, contributor); } @Override public void addElement(@NotNull LookupElement element) { // TODO: comment it when scopes supports inner classes if (element.getObject() instanceof PsiClass) { return; } if (element.getObject() instanceof PsiElement) { result.add(getSignature((PsiElement)element.getObject())); } } @NotNull @Override public CompletionResultSet withPrefixMatcher(@NotNull PrefixMatcher matcher) { return this; } @NotNull @Override public CompletionResultSet withPrefixMatcher(@NotNull String prefix) { return this; } @NotNull @Override public CompletionResultSet withRelevanceSorter(@NotNull CompletionSorter sorter) { return this; } @Override public void addLookupAdvertisement(@NotNull String s) { } @NotNull @Override public CompletionResultSet caseInsensitive() { return this; } @Override public void restartCompletionOnPrefixChange(ElementPattern<String> prefixCondition) { } @Override public void restartCompletionWhenNothingMatches() { } } }