mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-123484: generate stub type definition for implicit trait type mixing
This commit is contained in:
+19
-4
@@ -44,6 +44,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.dsl.CustomMembersGenerator;
|
||||
import org.jetbrains.plugins.groovy.dsl.holders.NonCodeMembersHolder;
|
||||
import org.jetbrains.plugins.groovy.extensions.NamedArgumentDescriptor;
|
||||
import org.jetbrains.plugins.groovy.lang.completion.GrPropertyForCompletion;
|
||||
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment;
|
||||
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocCommentOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.impl.GrDocCommentUtil;
|
||||
@@ -59,8 +60,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTraitType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.completion.GrPropertyForCompletion;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrImplicitVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
@@ -234,7 +235,6 @@ public class GroovyDocumentationProvider implements CodeDocumentationProvider, E
|
||||
buffer.append(LINE_SEPARATOR);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
private static String generateClassInfo(PsiClass aClass) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
GroovyFile file = (GroovyFile)aClass.getContainingFile();
|
||||
@@ -303,8 +303,11 @@ public class GroovyDocumentationProvider implements CodeDocumentationProvider, E
|
||||
}
|
||||
|
||||
|
||||
public static void appendTypeString(StringBuilder buffer, final PsiType type, PsiElement context) {
|
||||
if (type != null) {
|
||||
public static void appendTypeString(@NotNull StringBuilder buffer, @Nullable PsiType type, PsiElement context) {
|
||||
if (type instanceof GrTraitType) {
|
||||
generateTraitType(buffer, ((GrTraitType)type), context);
|
||||
}
|
||||
else if (type != null) {
|
||||
JavaDocInfoGenerator.generateType(buffer, type, context);
|
||||
}
|
||||
else {
|
||||
@@ -312,6 +315,18 @@ public class GroovyDocumentationProvider implements CodeDocumentationProvider, E
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateTraitType(@NotNull StringBuilder buffer, @NotNull GrTraitType type, PsiElement context) {
|
||||
PsiClassType exprType = type.getExprType();
|
||||
List<PsiClassType> traitTypes = type.getTraitTypes();
|
||||
appendTypeString(buffer, exprType, context);
|
||||
buffer.append(" as ");
|
||||
for (PsiClassType traitType : traitTypes) {
|
||||
appendTypeString(buffer, traitType, context);
|
||||
buffer.append(", ");
|
||||
}
|
||||
buffer.delete(buffer.length() - 2, buffer.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public List<String> getUrlFor(PsiElement element, PsiElement originalElement) {
|
||||
|
||||
@@ -17,11 +17,10 @@ package org.jetbrains.plugins.groovy.lang.psi.impl;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.VolatileNotNullLazyValue;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiAnnotation;
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.PsiTypeVisitor;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -37,32 +36,49 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrSafeCa
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClassTypeElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Max Medvedev on 20/05/14
|
||||
*/
|
||||
public class GrTraitType extends PsiType {
|
||||
public class GrTraitType extends PsiClassType {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(GrTraitType.class);
|
||||
|
||||
private final GrExpression myOriginal;
|
||||
private final GlobalSearchScope myResolveScope;
|
||||
|
||||
private final PsiClassType myExprType;
|
||||
private final List<PsiClassType> myTraitTypes;
|
||||
|
||||
private final GlobalSearchScope myResolveScope;
|
||||
|
||||
private final VolatileNotNullLazyValue<PsiType[]> myParameters = new VolatileNotNullLazyValue<PsiType[]>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected PsiType[] compute() {
|
||||
List<PsiType> result = ContainerUtil.newArrayList();
|
||||
ContainerUtil.addAll(result, myExprType.getParameters());
|
||||
for (PsiClassType type : myTraitTypes) {
|
||||
ContainerUtil.addAll(result, type.getParameters());
|
||||
}
|
||||
return result.toArray(new PsiType[result.size()]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public GrTraitType(@NotNull GrExpression original,
|
||||
@NotNull PsiClassType exprType,
|
||||
@NotNull List<PsiClassType> traitTypes,
|
||||
@NotNull GlobalSearchScope resolveScope) {
|
||||
super(PsiAnnotation.EMPTY_ARRAY);
|
||||
@NotNull GlobalSearchScope resolveScope, LanguageLevel languageLevel) {
|
||||
super(languageLevel);
|
||||
myOriginal = original;
|
||||
myResolveScope = resolveScope;
|
||||
myExprType = exprType;
|
||||
@@ -112,9 +128,33 @@ public class GrTraitType extends PsiType {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <A> A accept(@NotNull PsiTypeVisitor<A> visitor) {
|
||||
return visitor.visitType(this);
|
||||
public LanguageLevel getLanguageLevel() {
|
||||
return myLanguageLevel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClassType setLanguageLevel(@NotNull LanguageLevel languageLevel) {
|
||||
return new GrTraitType(myOriginal, myExprType, myTraitTypes, myResolveScope, languageLevel);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiClass resolve() {
|
||||
return getMockTypeDefinition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiType[] getParameters() {
|
||||
return myParameters.getValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -126,6 +166,32 @@ public class GrTraitType extends PsiType {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ClassResolveResult resolveGenerics() {
|
||||
return CachedValuesManager.getCachedValue(myOriginal, new CachedValueProvider<ClassResolveResult>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<ClassResolveResult> compute() {
|
||||
final GrTypeDefinition definition = new MockTypeBuilder().buildMockTypeDefinition();
|
||||
final PsiSubstitutor substitutor = new SubstitutorBuilder(definition).buildSubstitutor();
|
||||
|
||||
return Result.<ClassResolveResult>create(new TraitResolveResult(definition, substitutor), PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClassType rawType() {
|
||||
return new GrTraitType(myOriginal, myExprType.rawType(), ContainerUtil.map(myTraitTypes, new Function<PsiClassType, PsiClassType>() {
|
||||
@Override
|
||||
public PsiClassType fun(PsiClassType type) {
|
||||
return type.rawType();
|
||||
}
|
||||
}), myResolveScope, myLanguageLevel);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GlobalSearchScope getResolveScope() {
|
||||
@@ -138,7 +204,7 @@ public class GrTraitType extends PsiType {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<GrTypeDefinition> compute() {
|
||||
return Result.create(buildMockTypeDefinition(), PsiModificationTracker.MODIFICATION_COUNT);
|
||||
return Result.create(new MockTypeBuilder().buildMockTypeDefinition(), PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -151,39 +217,6 @@ public class GrTraitType extends PsiType {
|
||||
return Collections.unmodifiableList(myTraitTypes);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GrTypeDefinition buildMockTypeDefinition() {
|
||||
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myOriginal.getProject());
|
||||
try {
|
||||
GrTypeDefinition definition = factory.createTypeDefinition("class ___________Temp______ <T> extends Super implements Trait {}");
|
||||
replaceReferenceWith(factory, definition.getExtendsClause(), myExprType);
|
||||
addReferencesWith(factory, definition.getImplementsClause(), myTraitTypes);
|
||||
return definition;
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void addReferencesWith(GroovyPsiElementFactory factory, GrImplementsClause clause, List<PsiClassType> traitTypes) {
|
||||
clause.getReferenceElementsGroovy()[0].delete();
|
||||
for (PsiClassType type : traitTypes) {
|
||||
GrCodeReferenceElement ref = ((GrClassTypeElement)factory.createTypeElement(type)).getReferenceElement();
|
||||
clause.add(ref);
|
||||
}
|
||||
}
|
||||
|
||||
private static void replaceReferenceWith(@NotNull GroovyPsiElementFactory factory,
|
||||
@Nullable GrReferenceList clause,
|
||||
@NotNull PsiClassType type) {
|
||||
LOG.assertTrue(clause != null);
|
||||
GrCodeReferenceElement mockSuperReference = clause.getReferenceElementsGroovy()[0];
|
||||
|
||||
GrClassTypeElement superTypeElement = ((GrClassTypeElement)factory.createTypeElement(type));
|
||||
GrCodeReferenceElement superReference = superTypeElement.getReferenceElement();
|
||||
mockSuperReference.replace(superReference);
|
||||
}
|
||||
|
||||
public GrTraitType erasure() {
|
||||
PsiClassType exprType = (PsiClassType)TypeConversionUtil.erasure(myExprType);
|
||||
List<PsiClassType> traitTypes = ContainerUtil.map(myTraitTypes, new Function<PsiClassType, PsiClassType>() {
|
||||
@@ -192,7 +225,7 @@ public class GrTraitType extends PsiType {
|
||||
return (PsiClassType)TypeConversionUtil.erasure(type);
|
||||
}
|
||||
});
|
||||
return new GrTraitType(myOriginal, exprType, traitTypes, myResolveScope);
|
||||
return new GrTraitType(myOriginal, exprType, traitTypes, myResolveScope, LanguageLevel.JDK_1_5);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -206,7 +239,8 @@ public class GrTraitType extends PsiType {
|
||||
PsiType type = typeElement.getType();
|
||||
if (!GrTraitUtil.isTrait(PsiTypesUtil.getPsiClass(type))) return null;
|
||||
|
||||
return new GrTraitType(safeCastExpression, ((PsiClassType)exprType), Collections.singletonList((PsiClassType)type), safeCastExpression.getResolveScope());
|
||||
return new GrTraitType(safeCastExpression, ((PsiClassType)exprType), Collections.singletonList((PsiClassType)type), safeCastExpression.getResolveScope(),
|
||||
LanguageLevel.JDK_1_5);
|
||||
}
|
||||
|
||||
|
||||
@@ -215,6 +249,155 @@ public class GrTraitType extends PsiType {
|
||||
@NotNull PsiClassType exprType,
|
||||
@NotNull List<PsiClassType> traitTypes,
|
||||
@NotNull GlobalSearchScope resolveScope) {
|
||||
return new GrTraitType(context, exprType, traitTypes, resolveScope);
|
||||
return new GrTraitType(context, exprType, traitTypes, resolveScope, LanguageLevel.JDK_1_5);
|
||||
}
|
||||
|
||||
private static class TraitResolveResult implements ClassResolveResult {
|
||||
|
||||
private final GrTypeDefinition myDefinition;
|
||||
private final PsiSubstitutor mySubstitutor;
|
||||
|
||||
public TraitResolveResult(GrTypeDefinition definition, PsiSubstitutor substitutor) {
|
||||
myDefinition = definition;
|
||||
mySubstitutor = substitutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GrTypeDefinition getElement() {
|
||||
return myDefinition;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiSubstitutor getSubstitutor() {
|
||||
return mySubstitutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPackagePrefixPackageReference() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccessible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStaticsScopeCorrect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getCurrentFileResolveScope() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidResult() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class MockTypeBuilder {
|
||||
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myOriginal.getProject());
|
||||
|
||||
@Nullable
|
||||
public GrTypeDefinition buildMockTypeDefinition() {
|
||||
try {
|
||||
|
||||
StringBuilder buffer = new StringBuilder("class _____________Temp___________ ");
|
||||
prepareGenerics(buffer);
|
||||
buffer.append(" extends Super implements Trait {}");
|
||||
GrTypeDefinition definition = factory.createTypeDefinition(buffer.toString());
|
||||
replaceReferenceWith(definition.getExtendsClause(), myExprType);
|
||||
addReferencesWith(definition.getImplementsClause(), myTraitTypes, myExprType.getParameterCount());
|
||||
return definition;
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareGenerics(StringBuilder buffer) {
|
||||
int count = myExprType.getParameterCount();
|
||||
for (PsiClassType trait : myTraitTypes) {
|
||||
count += trait.getParameterCount();
|
||||
}
|
||||
if (count == 0) return;
|
||||
|
||||
buffer.append('<');
|
||||
for (int i = 0; i < count; i++) {
|
||||
buffer.append("T").append(i).append(",");
|
||||
}
|
||||
buffer.replace(buffer.length() - 1, buffer.length(), ">");
|
||||
}
|
||||
|
||||
private void addReferencesWith(@Nullable GrImplementsClause clause, @NotNull List<PsiClassType> traitTypes, int parameterOffset) {
|
||||
LOG.assertTrue(clause != null);
|
||||
clause.getReferenceElementsGroovy()[0].delete();
|
||||
for (PsiClassType type : traitTypes) {
|
||||
processType(clause, type, parameterOffset);
|
||||
parameterOffset += type.getParameterCount();
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceReferenceWith(@Nullable GrReferenceList clause, @NotNull PsiClassType type) {
|
||||
LOG.assertTrue(clause != null);
|
||||
clause.getReferenceElementsGroovy()[0].delete();
|
||||
processType(clause, type, 0);
|
||||
}
|
||||
|
||||
private void processType(@NotNull GrReferenceList clause, @NotNull PsiClassType type, int parameterOffset) {
|
||||
PsiClass resolved = type.resolve();
|
||||
if (resolved != null) {
|
||||
String qname = resolved.getQualifiedName();
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(qname);
|
||||
int parameterCount = type.getParameterCount();
|
||||
if (parameterCount > 0) {
|
||||
buffer.append('<');
|
||||
for (int i = 0; i < parameterCount; i++) {
|
||||
buffer.append("T").append(parameterOffset + i).append(',');
|
||||
}
|
||||
buffer.replace(buffer.length() - 1, buffer.length(), ">");
|
||||
}
|
||||
|
||||
GrCodeReferenceElement ref = factory.createCodeReferenceElementFromText(buffer.toString());
|
||||
clause.add(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SubstitutorBuilder {
|
||||
|
||||
private final GrTypeParameter[] myParameters;
|
||||
private int myOffset = 0;
|
||||
|
||||
public SubstitutorBuilder(@NotNull GrTypeDefinition definition) {
|
||||
GrTypeParameterList typeParameterList = definition.getTypeParameterList();
|
||||
myParameters = typeParameterList != null ? typeParameterList.getTypeParameters() : GrTypeParameter.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor buildSubstitutor() {
|
||||
if (myParameters.length == 0) return PsiSubstitutor.EMPTY;
|
||||
|
||||
Map<PsiTypeParameter, PsiType> map = ContainerUtil.newLinkedHashMap();
|
||||
putMappingAndReturnOffset(map, myExprType);
|
||||
for (PsiClassType type : myTraitTypes) {
|
||||
putMappingAndReturnOffset(map, type);
|
||||
}
|
||||
|
||||
return JavaPsiFacade.getElementFactory(myOriginal.getProject()).createSubstitutor(map);
|
||||
}
|
||||
|
||||
private void putMappingAndReturnOffset(@NotNull Map<PsiTypeParameter, PsiType> map, @NotNull PsiClassType type) {
|
||||
PsiType[] args = type.getParameters();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
map.put(myParameters[myOffset + i], args[i]);
|
||||
}
|
||||
myOffset += args.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user