mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
separate interface and implementation for PsiDiamondType
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
* Copyright 2000-2011 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.
|
||||
@@ -15,235 +15,17 @@
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: Jul 30, 2010
|
||||
*/
|
||||
public class PsiDiamondType extends PsiType {
|
||||
private final PsiManager myManager;
|
||||
private final PsiTypeElement myTypeElement;
|
||||
private static final Logger LOG = Logger.getInstance("#" + PsiDiamondType.class.getName());
|
||||
|
||||
public PsiDiamondType(PsiManager manager, PsiTypeElement psiTypeElement) {
|
||||
super(PsiAnnotation.EMPTY_ARRAY);
|
||||
myManager = manager;
|
||||
myTypeElement = psiTypeElement;
|
||||
public abstract class PsiDiamondType extends PsiType {
|
||||
public PsiDiamondType(PsiAnnotation[] annotations) {
|
||||
super(annotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCanonicalText() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalCanonicalText() {
|
||||
return "Diamond Type";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equalsToText(@NonNls String text) {
|
||||
return text != null && text.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> A accept(PsiTypeVisitor<A> visitor) {
|
||||
return visitor.visitType(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlobalSearchScope getResolveScope() {
|
||||
return GlobalSearchScope.allScope(myManager.getProject());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiType[] getSuperTypes() {
|
||||
return new PsiType[]{getJavaLangObject(myManager, getResolveScope())};
|
||||
}
|
||||
|
||||
public DiamondInferenceResult resolveInferredTypes() {
|
||||
final PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(myTypeElement, PsiNewExpression.class);
|
||||
if (newExpression == null) {
|
||||
return PsiDiamondType.DiamondInferenceResult.NULL_RESULT;
|
||||
}
|
||||
|
||||
return resolveInferredTypes(newExpression);
|
||||
}
|
||||
|
||||
public static DiamondInferenceResult resolveInferredTypes(PsiNewExpression newExpression) {
|
||||
return resolveInferredTypes(newExpression, newExpression);
|
||||
}
|
||||
|
||||
public static DiamondInferenceResult resolveInferredTypes(PsiNewExpression newExpression,
|
||||
PsiElement context) {
|
||||
final PsiAnonymousClass anonymousClass = newExpression.getAnonymousClass();
|
||||
if (anonymousClass != null) {
|
||||
final PsiElement resolve = anonymousClass.getBaseClassReference().resolve();
|
||||
if (resolve instanceof PsiClass) {
|
||||
return PsiDiamondType.DiamondInferenceResult.ANONYMOUS_INNER_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
final PsiReferenceParameterList referenceParameterList = PsiTreeUtil.getChildOfType(newExpression, PsiReferenceParameterList.class);
|
||||
if (referenceParameterList != null && referenceParameterList.getTypeParameterElements().length > 0) {
|
||||
return DiamondInferenceResult.EXPLICIT_CONSTRUCTOR_TYPE_ARGS;
|
||||
}
|
||||
|
||||
return resolveInferredTypesNoCheck(newExpression, context);
|
||||
}
|
||||
|
||||
public static DiamondInferenceResult resolveInferredTypesNoCheck(PsiNewExpression newExpression, PsiElement context) {
|
||||
final PsiClass psiClass = findClass(newExpression);
|
||||
if (psiClass == null) return DiamondInferenceResult.NULL_RESULT;
|
||||
final PsiExpressionList argumentList = newExpression.getArgumentList();
|
||||
if (argumentList == null) return DiamondInferenceResult.NULL_RESULT;
|
||||
final PsiMethod constructor = findConstructor(psiClass, newExpression);
|
||||
PsiTypeParameter[] params = getAllTypeParams(constructor, psiClass);
|
||||
PsiMethod staticFactory = generateStaticFactory(constructor, psiClass, params);
|
||||
if (staticFactory == null) {
|
||||
return DiamondInferenceResult.NULL_RESULT;
|
||||
}
|
||||
final PsiSubstitutor inferredSubstitutor = inferTypeParametersForStaticFactory(staticFactory, newExpression, context);
|
||||
final PsiTypeParameter[] parameters = staticFactory.getTypeParameters();
|
||||
final PsiTypeParameter[] classParameters = psiClass.getTypeParameters();
|
||||
final PsiJavaCodeReferenceElement classOrAnonymousClassReference = newExpression.getClassOrAnonymousClassReference();
|
||||
LOG.assertTrue(classOrAnonymousClassReference != null);
|
||||
final DiamondInferenceResult
|
||||
result = new DiamondInferenceResult(classOrAnonymousClassReference.getReferenceName() + "<>", newExpression.getProject());
|
||||
for (PsiTypeParameter parameter : parameters) {
|
||||
for (PsiTypeParameter classParameter : classParameters) {
|
||||
if (Comparing.strEqual(classParameter.getName(), parameter.getName())) {
|
||||
result.addInferredType(inferredSubstitutor.substitute(parameter));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private static PsiMethod findConstructor(PsiClass containingClass, PsiNewExpression newExpression) {
|
||||
final PsiExpressionList argumentList = newExpression.getArgumentList();
|
||||
final Project project = newExpression.getProject();
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
|
||||
final PsiResolveHelper resolveHelper = facade.getResolveHelper();
|
||||
final JavaResolveResult result =
|
||||
resolveHelper.resolveConstructor(facade.getElementFactory().createType(containingClass), argumentList, argumentList);
|
||||
return (PsiMethod)result.getElement();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClass findClass(PsiNewExpression newExpression) {
|
||||
final PsiJavaCodeReferenceElement classReference = newExpression.getClassOrAnonymousClassReference();
|
||||
if (classReference != null) {
|
||||
final String text = classReference.getReferenceName();
|
||||
if (text != null) {
|
||||
final Project project = newExpression.getProject();
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
|
||||
final PsiResolveHelper resolveHelper = facade.getResolveHelper();
|
||||
final PsiElement qualifierElement = classReference.getQualifier();
|
||||
final String qualifier = qualifierElement != null ? qualifierElement.getText() : "";
|
||||
return resolveHelper.resolveReferencedClass(StringUtil.getQualifiedName(qualifier, text), newExpression);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethod generateStaticFactory(@Nullable PsiMethod constructor, PsiClass containingClass, PsiTypeParameter[] params) {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
buf.append("public static ");
|
||||
buf.append("<");
|
||||
buf.append(StringUtil.join(params, new Function<PsiTypeParameter, String>() {
|
||||
@Override
|
||||
public String fun(PsiTypeParameter psiTypeParameter) {
|
||||
return psiTypeParameter.getName();
|
||||
}
|
||||
}, ", "));
|
||||
buf.append(">");
|
||||
|
||||
final String qualifiedName = containingClass.getQualifiedName();
|
||||
buf.append(qualifiedName != null ? qualifiedName : containingClass.getName());
|
||||
final PsiTypeParameter[] parameters = containingClass.getTypeParameters();
|
||||
buf.append("<");
|
||||
buf.append(StringUtil.join(parameters, new Function<PsiTypeParameter, String>() {
|
||||
@Override
|
||||
public String fun(PsiTypeParameter psiTypeParameter) {
|
||||
return psiTypeParameter.getName();
|
||||
}
|
||||
}, ", "));
|
||||
buf.append("> ");
|
||||
|
||||
String staticFactoryName = "staticFactory";
|
||||
final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(containingClass.getProject());
|
||||
staticFactoryName = styleManager.suggestUniqueVariableName(staticFactoryName, containingClass, false);
|
||||
buf.append(staticFactoryName);
|
||||
if (constructor == null) {
|
||||
buf.append("()");
|
||||
}
|
||||
else {
|
||||
buf.append("(").append(StringUtil.join(constructor.getParameterList().getParameters(), new Function<PsiParameter, String>() {
|
||||
int myIdx = 0;
|
||||
@Override
|
||||
public String fun(PsiParameter psiParameter) {
|
||||
return psiParameter.getType().getCanonicalText() + " p" + myIdx++;
|
||||
}
|
||||
}, ",")).append(")");
|
||||
}
|
||||
buf.append("{}");
|
||||
|
||||
return JavaPsiFacade.getElementFactory(containingClass.getProject()).createMethodFromText(buf.toString(), constructor != null ? constructor : containingClass);
|
||||
}
|
||||
|
||||
private static PsiTypeParameter[] getAllTypeParams(PsiTypeParameterListOwner listOwner, PsiClass containingClass) {
|
||||
Set<PsiTypeParameter> params = new LinkedHashSet<PsiTypeParameter>();
|
||||
if (listOwner != null) {
|
||||
Collections.addAll(params, listOwner.getTypeParameters());
|
||||
}
|
||||
Collections.addAll(params, containingClass.getTypeParameters());
|
||||
return params.toArray(new PsiTypeParameter[params.size()]);
|
||||
}
|
||||
|
||||
|
||||
private static PsiSubstitutor inferTypeParametersForStaticFactory(@NotNull PsiMethod staticFactoryMethod,
|
||||
PsiNewExpression expression,
|
||||
PsiElement parent) {
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(staticFactoryMethod.getProject());
|
||||
final PsiResolveHelper resolveHelper = facade.getResolveHelper();
|
||||
final PsiParameter[] parameters = staticFactoryMethod.getParameterList().getParameters();
|
||||
final PsiExpressionList argumentList = expression.getArgumentList();
|
||||
final PsiExpression[] expressions = argumentList.getExpressions();
|
||||
return resolveHelper
|
||||
.inferTypeArguments(staticFactoryMethod.getTypeParameters(), parameters, expressions, PsiSubstitutor.EMPTY, parent, false);
|
||||
}
|
||||
public abstract DiamondInferenceResult resolveInferredTypes();
|
||||
|
||||
public static class DiamondInferenceResult {
|
||||
public static final DiamondInferenceResult EXPLICIT_CONSTRUCTOR_TYPE_ARGS = new DiamondInferenceResult() {
|
||||
@@ -313,7 +95,7 @@ public class PsiDiamondType extends PsiType {
|
||||
public String getErrorMessage() {
|
||||
return myErrorMessage;
|
||||
}
|
||||
|
||||
|
||||
public boolean failedToInfer() {
|
||||
return myErrorMessage != null;
|
||||
}
|
||||
@@ -384,46 +166,4 @@ public class PsiDiamondType extends PsiType {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasDefaultConstructor(@NotNull final PsiClass psiClass) {
|
||||
final PsiMethod[] constructors = psiClass.getConstructors();
|
||||
for (PsiMethod method : constructors) {
|
||||
if (method.getParameterList().getParametersCount() == 0) return true;
|
||||
}
|
||||
return constructors.length == 0;
|
||||
}
|
||||
|
||||
public static boolean haveConstructorsGenericsParameters(@NotNull final PsiClass psiClass) {
|
||||
for (PsiMethod method : psiClass.getConstructors()) {
|
||||
for (PsiParameter parameter : method.getParameterList().getParameters()) {
|
||||
final PsiType type = parameter.getType();
|
||||
final Boolean accept = type.accept(new PsiTypeVisitor<Boolean>() {
|
||||
@Override
|
||||
public Boolean visitArrayType(PsiArrayType arrayType) {
|
||||
return arrayType.getComponentType().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitClassType(PsiClassType classType) {
|
||||
for (PsiType psiType : classType.getParameters()) {
|
||||
if (psiType != null) {
|
||||
final Boolean typaParamFound = psiType.accept(this);
|
||||
if (typaParamFound != null && typaParamFound) return true;
|
||||
}
|
||||
}
|
||||
return PsiUtil.resolveClassInType(classType) instanceof PsiTypeParameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitWildcardType(PsiWildcardType wildcardType) {
|
||||
final PsiType bound = wildcardType.getBound();
|
||||
if (bound == null) return false;
|
||||
return bound.accept(this);
|
||||
}
|
||||
});
|
||||
if (accept != null && accept.booleanValue()) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user