/* * Copyright 2000-2013 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; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; /** * @author dsl */ public class PsiImmediateClassType extends PsiClassType { private final PsiClass myClass; private final PsiSubstitutor mySubstitutor; private final PsiManager myManager; private String myCanonicalText; private String myPresentableText; private String myInternalCanonicalText; private final ClassResolveResult myClassResolveResult = new ClassResolveResult() { @Override public PsiClass getElement() { return myClass; } @Override public PsiSubstitutor getSubstitutor() { return mySubstitutor; } @Override public boolean isValidResult() { return true; } @Override public boolean isAccessible() { return true; } @Override public boolean isStaticsScopeCorrect() { return true; } @Override public PsiElement getCurrentFileResolveScope() { return null; } @Override public boolean isPackagePrefixPackageReference() { return false; } }; public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor) { this(aClass, substitutor, null, PsiAnnotation.EMPTY_ARRAY); } public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel languageLevel) { this(aClass, substitutor, languageLevel, PsiAnnotation.EMPTY_ARRAY); } public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel languageLevel, @NotNull PsiAnnotation[] annotations) { super(languageLevel, annotations); myClass = aClass; myManager = aClass.getManager(); mySubstitutor = substitutor; assert substitutor.isValid(); } @Override public PsiClass resolve() { return myClass; } @Override public String getClassName() { return myClass.getName(); } @Override @NotNull public PsiType[] getParameters() { final PsiTypeParameter[] parameters = myClass.getTypeParameters(); if (parameters.length == 0) { return PsiType.EMPTY_ARRAY; } List<PsiType> lst = new ArrayList<PsiType>(); for (PsiTypeParameter parameter : parameters) { PsiType substituted = mySubstitutor.substitute(parameter); if (substituted != null) { lst.add(substituted); } } return lst.toArray(new PsiType[lst.size()]); } @Override @NotNull public ClassResolveResult resolveGenerics() { return myClassResolveResult; } @Override @NotNull public PsiClassType rawType() { return JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory().createType(myClass); } @Override public String getPresentableText() { if (myPresentableText == null) { StringBuilder buffer = new StringBuilder(); buildText(myClass, mySubstitutor, buffer, false, false); myPresentableText = buffer.toString(); } return myPresentableText; } @Override public String getCanonicalText() { if (myCanonicalText == null) { assert mySubstitutor.isValid(); StringBuilder buffer = new StringBuilder(); buildText(myClass, mySubstitutor, buffer, true, false); myCanonicalText = buffer.toString(); } return myCanonicalText; } @Override public String getInternalCanonicalText() { if (myInternalCanonicalText == null) { StringBuilder buffer = new StringBuilder(); buildText(myClass, mySubstitutor, buffer, true, true); myInternalCanonicalText = buffer.toString(); } return myInternalCanonicalText; } private void buildText(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @NotNull StringBuilder buffer, boolean canonical, boolean internal) { if (aClass instanceof PsiAnonymousClass) { ClassResolveResult baseResolveResult = ((PsiAnonymousClass) aClass).getBaseClassType().resolveGenerics(); PsiClass baseClass = baseResolveResult.getElement(); PsiSubstitutor baseSub = baseResolveResult.getSubstitutor(); if (baseClass != null) { buildText(baseClass, baseSub, buffer, canonical, internal); } return; } if (canonical == internal) { buffer.append(getAnnotationsTextPrefix(internal, false, true)); } PsiClass enclosingClass = null; if (!aClass.hasModifierProperty(PsiModifier.STATIC)) { final PsiElement parent = aClass.getParent(); if (parent instanceof PsiClass && !(parent instanceof PsiAnonymousClass)) { enclosingClass = (PsiClass)parent; } } if (enclosingClass != null) { buildText(enclosingClass, substitutor, buffer, canonical, false); buffer.append('.'); buffer.append(aClass.getName()); } else { final String name; if (!canonical) { name = aClass.getName(); } else { final String qualifiedName = aClass.getQualifiedName(); if (qualifiedName == null) { name = aClass.getName(); } else { name = qualifiedName; } } buffer.append(name); } PsiTypeParameter[] typeParameters = aClass.getTypeParameters(); if (typeParameters.length > 0) { StringBuilder pineBuffer = new StringBuilder(); pineBuffer.append('<'); for (int i = 0; i < typeParameters.length; i++) { PsiTypeParameter typeParameter = typeParameters[i]; PsiUtilCore.ensureValid(typeParameter); if (i > 0) pineBuffer.append(','); final PsiType substitutionResult = substitutor.substitute(typeParameter); if (substitutionResult == null) { pineBuffer = null; break; } PsiUtil.ensureValidType(substitutionResult); if (canonical) { if (internal) { pineBuffer.append(substitutionResult.getInternalCanonicalText()); } else { pineBuffer.append(substitutionResult.getCanonicalText()); } } else { pineBuffer.append(substitutionResult.getPresentableText()); } } if (pineBuffer != null) { buffer.append(pineBuffer); buffer.append('>'); } } } @Override public boolean isValid() { return myClass.isValid() && mySubstitutor.isValid(); } @Override public boolean equalsToText(String text) { PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory(); final PsiType patternType; try { patternType = factory.createTypeFromText(text, myClass); } catch (IncorrectOperationException e) { return false; } return equals(patternType); } @Override @NotNull public GlobalSearchScope getResolveScope() { return myClass.getResolveScope(); } @Override @NotNull public LanguageLevel getLanguageLevel() { if (myLanguageLevel != null) return myLanguageLevel; return PsiUtil.getLanguageLevel(myClass); } @NotNull @Override public PsiClassType setLanguageLevel(@NotNull final LanguageLevel languageLevel) { if (languageLevel.equals(myLanguageLevel)) return this; return new PsiImmediateClassType(myClass, mySubstitutor, languageLevel,getAnnotations()); } }