[groovy] substitute generic types by name in compiled traits

This commit is contained in:
Daniil Ovchinnikov
2015-08-26 19:55:06 +03:00
parent d478591cd6
commit 00bd837136
2 changed files with 119 additions and 12 deletions
@@ -0,0 +1,84 @@
/*
* Copyright 2000-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 com.intellij.psi.impl;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiSubstitutor;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeParameter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
public class DelegateSubstitutor implements PsiSubstitutor {
private final @NotNull PsiSubstitutor myDelegate;
public DelegateSubstitutor(@NotNull PsiSubstitutor delegate) {
myDelegate = delegate;
}
@Override
@Nullable
public PsiType substitute(@NotNull PsiTypeParameter typeParameter) {
return myDelegate.substitute(typeParameter);
}
@Override
public PsiType substitute(@Nullable PsiType type) {
return myDelegate.substitute(type);
}
@Override
public PsiType substituteWithBoundsPromotion(@NotNull PsiTypeParameter typeParameter) {
return myDelegate.substituteWithBoundsPromotion(typeParameter);
}
@Override
@NotNull
public PsiSubstitutor put(@NotNull PsiTypeParameter classParameter, PsiType mapping) {
return myDelegate.put(classParameter, mapping);
}
@Override
@NotNull
public PsiSubstitutor putAll(@NotNull PsiClass parentClass, PsiType[] mappings) {
return myDelegate.putAll(parentClass, mappings);
}
@Override
@NotNull
public PsiSubstitutor putAll(@NotNull PsiSubstitutor another) {
return myDelegate.putAll(another);
}
@Override
@NotNull
public Map<PsiTypeParameter, PsiType> getSubstitutionMap() {
return myDelegate.getSubstitutionMap();
}
@Override
public boolean isValid() {
return myDelegate.isValid();
}
@Override
public void ensureValid() {
myDelegate.ensureValid();
}
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.SimpleModificationTracker;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.DelegateSubstitutor;
import com.intellij.psi.impl.compiled.ClsClassImpl;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.*;
@@ -278,22 +279,44 @@ public class GrTypeDefinitionMembersCache {
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(trait.getProject());
final String helperFQN = trait.getQualifiedName();
final PsiClass traitHelper = psiFacade.findClass(helperFQN + "$Trait$Helper", trait.getResolveScope());
if (traitHelper != null) {
final PsiType classType = TypesUtil.createJavaLangClassType(
psiFacade.getElementFactory().createType(trait), trait.getProject(), trait.getResolveScope()
);
for (PsiMethod method : traitHelper.getMethods()) {
if (!method.hasModifierProperty(PsiModifier.STATIC)) continue;
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length <= 0) continue;
final PsiParameter self = parameters[0];
if (self.getType().equals(classType)) {
addCandidate(GrGdkMethodImpl.createGdkMethod(method, true, "via @Trait"), substitutor);
}
if (traitHelper == null) return;
final PsiType classType = TypesUtil.createJavaLangClassType(
psiFacade.getElementFactory().createType(trait), trait.getProject(), trait.getResolveScope()
);
final PsiSubstitutor delegateSubstitutor = getSubstitutor(substitutor, trait);
for (PsiMethod method : traitHelper.getMethods()) {
if (!method.hasModifierProperty(PsiModifier.STATIC)) continue;
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length <= 0) continue;
final PsiParameter self = parameters[0];
if (self.getType().equals(classType)) {
addCandidate(GrGdkMethodImpl.createGdkMethod(method, true, "via @Trait"), delegateSubstitutor);
}
}
}
}
@NotNull
private DelegateSubstitutor getSubstitutor(@NotNull final PsiSubstitutor substitutor,
@NotNull final PsiClass trait) {
final Map<String, PsiType> substitutionMap = ContainerUtil.newTroveMap();
for (PsiTypeParameter parameter : trait.getTypeParameters()) {
substitutionMap.put(parameter.getName(), substitutor.substitute(parameter));
}
return new DelegateSubstitutor(substitutor) {
@Override
public PsiType substitute(@Nullable PsiType type) {
final PsiType substituted = super.substitute(type);
if (type != null && (substituted == null || substituted.equals(type))) {
final PsiType byName = substitutionMap.get(type.getCanonicalText());
return byName == null ? substituted : byName;
}
else {
return substituted;
}
}
};
}
}.getResult();
for (CandidateInfo candidateInfo : concreteTraitMethods) {
List<GrMethod> methodsToAdd = getExpandingMethods(candidateInfo);