| /* |
| * Copyright 2000-2014 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.refactoring.typeCook.deductive; |
| |
| import com.intellij.psi.*; |
| import com.intellij.psi.search.GlobalSearchScope; |
| import com.intellij.psi.util.PsiTreeUtil; |
| import com.intellij.psi.util.PsiUtil; |
| import org.jetbrains.annotations.NotNull; |
| |
| import java.util.*; |
| |
| /** |
| * @author db |
| */ |
| public class PsiTypeVariableFactory { |
| private int myCurrent = 0; |
| private final List<Set<PsiTypeVariable>> myClusters = new LinkedList<Set<PsiTypeVariable>>(); |
| private final Map<Integer, Set<PsiTypeVariable>> myVarCluster = new HashMap<Integer, Set<PsiTypeVariable>>(); |
| |
| public final int getNumber() { |
| return myCurrent; |
| } |
| |
| public final void registerCluster(final Set<PsiTypeVariable> cluster) { |
| myClusters.add(cluster); |
| |
| for (final PsiTypeVariable aCluster : cluster) { |
| myVarCluster.put(new Integer(aCluster.getIndex()), cluster); |
| } |
| } |
| |
| public final List<Set<PsiTypeVariable>> getClusters() { |
| return myClusters; |
| } |
| |
| public final Set<PsiTypeVariable> getClusterOf(final int var) { |
| return myVarCluster.get(new Integer(var)); |
| } |
| |
| public final PsiTypeVariable create() { |
| return create(null); |
| } |
| |
| public final PsiTypeVariable create(final PsiElement context) { |
| return new PsiTypeVariable() { |
| private final int myIndex = myCurrent++; |
| private final PsiElement myContext = context; |
| |
| @Override |
| public boolean isValidInContext(final PsiType type) { |
| if (myContext == null) { |
| return true; |
| } |
| |
| if (type == null) { |
| return true; |
| } |
| |
| return type.accept(new PsiTypeVisitor<Boolean>() { |
| @Override |
| public Boolean visitType(final PsiType type) { |
| return Boolean.TRUE; |
| } |
| |
| @Override |
| public Boolean visitArrayType(final PsiArrayType arrayType) { |
| return arrayType.getDeepComponentType().accept(this); |
| } |
| |
| @Override |
| public Boolean visitWildcardType(final PsiWildcardType wildcardType) { |
| final PsiType bound = wildcardType.getBound(); |
| |
| if (bound != null) { |
| bound.accept(this); |
| } |
| |
| return Boolean.TRUE; |
| } |
| |
| @Override |
| public Boolean visitClassType(final PsiClassType classType) { |
| final PsiClassType.ClassResolveResult result = classType.resolveGenerics(); |
| final PsiClass aClass = result.getElement(); |
| final PsiSubstitutor aSubst = result.getSubstitutor(); |
| |
| if (aClass != null) { |
| final PsiManager manager = aClass.getManager(); |
| final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); |
| |
| if (aClass instanceof PsiTypeParameter) { |
| final PsiTypeParameterListOwner owner = PsiTreeUtil.getParentOfType(myContext, PsiTypeParameterListOwner.class); |
| |
| if (owner != null) { |
| boolean found = false; |
| |
| for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(owner)) { |
| found = manager.areElementsEquivalent(typeParameter, aClass); |
| if (found) break; |
| } |
| |
| if (!found) { |
| return Boolean.FALSE; |
| } |
| } |
| else { |
| return Boolean.FALSE; |
| } |
| } |
| else if (!facade.getResolveHelper().isAccessible(aClass, myContext, null)) { |
| return Boolean.FALSE; |
| } |
| |
| for (PsiTypeParameter parm : PsiUtil.typeParametersIterable(aClass)) { |
| final PsiType type = aSubst.substitute(parm); |
| |
| if (type != null) { |
| final Boolean b = type.accept(this); |
| |
| if (!b.booleanValue()) { |
| return Boolean.FALSE; |
| } |
| } |
| } |
| |
| return Boolean.TRUE; |
| } |
| else { |
| return Boolean.FALSE; |
| } |
| } |
| }).booleanValue(); |
| } |
| |
| @Override |
| @NotNull |
| public String getPresentableText() { |
| return "$" + myIndex; |
| } |
| |
| @Override |
| @NotNull |
| public String getCanonicalText() { |
| return getPresentableText(); |
| } |
| |
| @Override |
| @NotNull |
| public String getInternalCanonicalText() { |
| return getCanonicalText(); |
| } |
| |
| @Override |
| public boolean isValid() { |
| return true; |
| } |
| |
| @Override |
| public boolean equalsToText(@NotNull String text) { |
| return text.equals(getPresentableText()); |
| } |
| |
| @Override |
| public GlobalSearchScope getResolveScope() { |
| return null; |
| } |
| |
| @Override |
| @NotNull |
| public PsiType[] getSuperTypes() { |
| return EMPTY_ARRAY; |
| } |
| |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (!(o instanceof PsiTypeVariable)) return false; |
| |
| final PsiTypeVariable psiTypeVariable = (PsiTypeVariable)o; |
| |
| if (myIndex != psiTypeVariable.getIndex()) return false; |
| |
| return true; |
| } |
| |
| public int hashCode() { |
| return myIndex; |
| } |
| |
| @Override |
| public int getIndex() { |
| return myIndex; |
| } |
| }; |
| } |
| } |