/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.load.java.structure.impl;
import com.intellij.psi.*;
import org.jetbrains.annotations.
NotNull;
import org.jetbrains.annotations.
Nullable;
import org.jetbrains.kotlin.load.java.structure.
JavaClassifierType;
import org.jetbrains.kotlin.load.java.structure.
JavaType;
import java.util.
ArrayList;
import java.util.
Collections;
import java.util.
List;
public class
JavaClassifierTypeImpl extends
JavaTypeImpl<
PsiClassType> implements
JavaClassifierType {
private static class
ResolutionResult {
private final
JavaClassifierImpl<?>
classifier;
private final
PsiSubstitutor substitutor;
private final boolean
isRaw;
private
ResolutionResult(@
Nullable JavaClassifierImpl<?>
classifier, @
NotNull PsiSubstitutor substitutor, boolean
isRaw) {
this.
classifier =
classifier;
this.
substitutor =
substitutor;
this.
isRaw =
isRaw;
}
}
private
ResolutionResult resolutionResult;
public
JavaClassifierTypeImpl(@
NotNull PsiClassType psiClassType) {
super(
psiClassType);
}
@
Override
@
Nullable
public
JavaClassifierImpl<?>
getClassifier() {
resolve();
return
resolutionResult.
classifier;
}
@
NotNull
public
PsiSubstitutor getSubstitutor() {
resolve();
return
resolutionResult.
substitutor;
}
private void
resolve() {
if (
resolutionResult == null) {
PsiClassType.
ClassResolveResult result =
getPsi().
resolveGenerics();
PsiClass psiClass =
result.
getElement();
PsiSubstitutor substitutor =
result.
getSubstitutor();
resolutionResult = new
ResolutionResult(
psiClass == null ? null :
JavaClassifierImpl.
create(
psiClass),
substitutor,
PsiClassType.
isRaw(
result)
);
}
}
@
Override
@
NotNull
public
String getClassifierQualifiedName() {
return
ClassNamesUtilKt.
convertCanonicalNameToQName(
getPsi().
getCanonicalText());
}
@
Override
@
NotNull
public
String getPresentableText() {
return
getPsi().
getPresentableText();
}
@
Override
public boolean
isRaw() {
resolve();
return
resolutionResult.
isRaw;
}
@
Override
@
NotNull
public
List<
JavaType>
getTypeArguments() {
JavaClassifierImpl<?>
classifier =
getClassifier();
if (!(
classifier instanceof
JavaClassImpl)) return
Collections.
emptyList();
// parameters including ones from outer class
List<
PsiTypeParameter>
parameters =
getTypeParameters(
classifier.
getPsi());
PsiSubstitutor substitutor =
getSubstitutor();
List<
JavaType>
result = new
ArrayList<>(
parameters.
size());
for (
PsiTypeParameter typeParameter :
parameters) {
PsiType substitutedType =
substitutor.
substitute(
typeParameter);
result.
add(
substitutedType == null ? null :
JavaTypeImpl.
create(
substitutedType));
}
return
result;
}
// Copy-pasted from PsiUtil.typeParametersIterable
// The only change is using `Collections.addAll(result, typeParameters)` instead of reversing type parameters of `currentOwner`
// Result differs in cases like:
// class Outer<H1> {
// class Inner<H2, H3> {}
// }
//
// PsiUtil.typeParametersIterable returns H3, H2, H1
// But we would like to have H2, H3, H1 as such order is consistent with our type representation
@
NotNull
private static
List<
PsiTypeParameter>
getTypeParameters(@
NotNull PsiClass owner) {
List<
PsiTypeParameter>
result = null;
PsiTypeParameterListOwner currentOwner =
owner;
while (
currentOwner != null) {
PsiTypeParameter[]
typeParameters =
currentOwner.
getTypeParameters();
if (
typeParameters.length > 0) {
if (
result == null)
result = new
ArrayList<>(
typeParameters.length);
Collections.
addAll(
result,
typeParameters);
}
if (
currentOwner.
hasModifierProperty(
PsiModifier.
STATIC)) break;
currentOwner =
currentOwner.
getContainingClass();
}
if (
result == null) return
Collections.
emptyList();
return
result;
}
}