/*
* Copyright 2013-2017 consulo.io
*
* 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 consulo.csharp.lang.psi.impl;
import gnu.trove.THashSet;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.ObjectUtil;
import com.intellij.util.SmartList;
import consulo.annotations.RequiredReadAction;
import consulo.csharp.lang.CSharpCastType;
import consulo.csharp.lang.psi.*;
import consulo.csharp.lang.psi.impl.resolve.CSharpResolveContextUtil;
import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpArrayTypeRef;
import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpFastImplicitTypeRef;
import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpLambdaResolveResult;
import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpNullTypeRef;
import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpRefTypeRef;
import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpUserTypeRef;
import consulo.csharp.lang.psi.impl.source.resolve.type.wrapper.GenericUnwrapTool;
import consulo.csharp.lang.psi.resolve.CSharpElementGroup;
import consulo.csharp.lang.psi.resolve.CSharpResolveContext;
import consulo.dotnet.DotNetTypes;
import consulo.dotnet.psi.DotNetGenericParameter;
import consulo.dotnet.psi.DotNetGenericParameterList;
import consulo.dotnet.psi.DotNetGenericParameterListOwner;
import consulo.dotnet.psi.DotNetLikeMethodDeclaration;
import consulo.dotnet.psi.DotNetTypeDeclaration;
import consulo.dotnet.resolve.DotNetGenericExtractor;
import consulo.dotnet.resolve.DotNetPointerTypeRef;
import consulo.dotnet.resolve.DotNetTypeRef;
import consulo.dotnet.resolve.DotNetTypeRefUtil;
import consulo.dotnet.resolve.DotNetTypeResolveResult;
import consulo.dotnet.util.ArrayUtil2;
/**
* @author VISTALL
* @since 08.01.14
*/
public class CSharpTypeUtil
{
public static class InheritResult
{
private final boolean mySuccess;
private final boolean myConversion;
private final CSharpConversionMethodDeclaration myConversionMethod;
//private final String myExceptionText = ExceptionUtil.getThrowableText(new Exception());
public InheritResult(boolean success, boolean conversion)
{
this(success, conversion, null);
}
public InheritResult(boolean success, CSharpConversionMethodDeclaration conversionMethod)
{
this(success, conversionMethod != null, conversionMethod);
}
public InheritResult(boolean success, boolean conversion, CSharpConversionMethodDeclaration conversionMethod)
{
mySuccess = success;
myConversion = conversion;
myConversionMethod = conversionMethod;
}
public boolean isConversion()
{
return myConversion;
}
@Nullable
public CSharpConversionMethodDeclaration getConversionMethod()
{
return myConversionMethod;
}
public boolean isSuccess()
{
return mySuccess;
}
}
public static final InheritResult FAIL = new InheritResult(false, null);
public static final InheritResult SIMPLE_SUCCESS = new InheritResult(true, null);
@RequiredReadAction
public static boolean isErrorTypeRef(@NotNull DotNetTypeRef typeRef)
{
if(typeRef == DotNetTypeRef.ERROR_TYPE)
{
return true;
}
else if(typeRef instanceof CSharpUserTypeRef)
{
return typeRef.resolve().getElement() == null;
}
return false;
}
@RequiredReadAction
public static boolean isNullableElement(@Nullable PsiElement element)
{
if(element instanceof DotNetTypeDeclaration)
{
if(DotNetTypes.System.Nullable$1.equals(((DotNetTypeDeclaration) element).getVmQName()))
{
// special case - compiler box element in new Nullable<int>(null);
return true;
}
return !((DotNetTypeDeclaration) element).isStruct() && !((DotNetTypeDeclaration) element).isEnum();
}
else if(element instanceof DotNetGenericParameter)
{
CSharpGenericConstraint genericConstraint = CSharpGenericConstraintUtil.findGenericConstraint((DotNetGenericParameter) element);
if(genericConstraint != null)
{
for(CSharpGenericConstraintValue genericConstraintValue : genericConstraint.getGenericConstraintValues())
{
if(genericConstraintValue instanceof CSharpGenericConstraintKeywordValue)
{
IElementType keywordElementType = ((CSharpGenericConstraintKeywordValue) genericConstraintValue).getKeywordElementType();
if(keywordElementType == CSharpTokens.STRUCT_KEYWORD)
{
return false;
}
else if(keywordElementType == CSharpTokens.CLASS_KEYWORD)
{
return true;
}
}
else if(genericConstraintValue instanceof CSharpGenericConstraintTypeValue)
{
DotNetTypeRef dotNetTypeRef = ((CSharpGenericConstraintTypeValue) genericConstraintValue).toTypeRef();
DotNetTypeResolveResult typeResolveResult = dotNetTypeRef.resolve();
if(typeResolveResult.isNullable())
{
return true;
}
}
}
}
return false;
}
return true;
}
@Nullable
@RequiredReadAction
public static Pair<DotNetTypeDeclaration, DotNetGenericExtractor> findTypeInSuper(@NotNull DotNetTypeRef typeRef, @NotNull String vmQName)
{
DotNetTypeResolveResult typeResolveResult = typeRef.resolve();
PsiElement resolve = typeResolveResult.getElement();
if(!(resolve instanceof DotNetTypeDeclaration))
{
return null;
}
String otherVQName = ((DotNetTypeDeclaration) resolve).getVmQName();
if(vmQName.equals(otherVQName))
{
return Pair.create((DotNetTypeDeclaration) resolve, typeResolveResult.getGenericExtractor());
}
for(DotNetTypeRef superType : ((DotNetTypeDeclaration) resolve).getExtendTypeRefs())
{
Pair<DotNetTypeDeclaration, DotNetGenericExtractor> typeInSuper = findTypeInSuper(superType, vmQName);
if(typeInSuper != null)
{
return typeInSuper;
}
}
return null;
}
@Nullable
@RequiredReadAction
public static DotNetTypeResolveResult findTypeRefFromExtends(@NotNull DotNetTypeRef typeRef, @NotNull DotNetTypeRef otherTypeRef, @NotNull PsiElement scope)
{
DotNetTypeResolveResult typeResolveResult = otherTypeRef.resolve();
PsiElement element = typeResolveResult.getElement();
if(!(element instanceof CSharpTypeDeclaration))
{
return null;
}
return findTypeRefFromExtends(typeRef, (DotNetTypeDeclaration) element, scope, new THashSet<String>());
}
@Nullable
@RequiredReadAction
public static DotNetTypeResolveResult findTypeRefFromExtends(@NotNull final DotNetTypeRef typeRef,
@NotNull final DotNetTypeDeclaration typeDeclaration,
@NotNull final PsiElement scope,
@NotNull Set<String> processed)
{
final DotNetTypeResolveResult typeResolveResult = typeRef.resolve();
final PsiElement resolvedElement = typeResolveResult.getElement();
if(!(resolvedElement instanceof DotNetTypeDeclaration))
{
return null;
}
if(typeDeclaration.isEquivalentTo(resolvedElement))
{
return typeResolveResult;
}
if(!processed.add(((DotNetTypeDeclaration) resolvedElement).getVmQName()))
{
return null;
}
DotNetTypeRef[] extendTypeRefs = ((DotNetTypeDeclaration) resolvedElement).getExtendTypeRefs();
for(DotNetTypeRef extendTypeRef : extendTypeRefs)
{
extendTypeRef = GenericUnwrapTool.exchangeTypeRef(extendTypeRef, typeResolveResult.getGenericExtractor(), scope);
DotNetTypeResolveResult findTypeRefFromExtends = findTypeRefFromExtends(extendTypeRef, typeDeclaration, scope, processed);
if(findTypeRefFromExtends != null)
{
return findTypeRefFromExtends;
}
}
return null;
}
@RequiredReadAction
public static boolean isInheritableWithImplicit(@NotNull DotNetTypeRef top, @NotNull DotNetTypeRef target, @NotNull PsiElement scope)
{
return isInheritable(top, target, scope, CSharpCastType.IMPLICIT).isSuccess();
}
@RequiredReadAction
public static boolean isInheritableWithExplicit(@NotNull DotNetTypeRef top, @NotNull DotNetTypeRef target, @NotNull PsiElement scope)
{
return isInheritable(top, target, scope, CSharpCastType.EXPLICIT).isSuccess();
}
/**
* We have expression
* int a = "test";
* <p/>
* "test" - string type, ill be 'target' parameter
* int - int type, ill 'top'
* return false due it not be casted
*/
@RequiredReadAction
public static boolean isInheritable(@NotNull DotNetTypeRef top, @NotNull DotNetTypeRef target, @NotNull PsiElement scope)
{
return isInheritable(top, target, scope, null).isSuccess();
}
@NotNull
@RequiredReadAction
public static InheritResult isInheritable(@NotNull DotNetTypeRef top, @NotNull DotNetTypeRef target, @NotNull PsiElement scope, @Nullable CSharpCastType castType)
{
if(top == DotNetTypeRef.ERROR_TYPE || target == DotNetTypeRef.ERROR_TYPE)
{
return fail();
}
if(top.equals(target))
{
return SIMPLE_SUCCESS;
}
if(target instanceof CSharpFastImplicitTypeRef)
{
DotNetTypeRef implicitTypeRef = ((CSharpFastImplicitTypeRef) target).doMirror(top, scope);
if(implicitTypeRef != null)
{
return new InheritResult(true, ((CSharpFastImplicitTypeRef) target).isConversion());
}
}
if(target instanceof CSharpRefTypeRef && top instanceof CSharpRefTypeRef)
{
if(((CSharpRefTypeRef) target).getType() != ((CSharpRefTypeRef) top).getType())
{
return fail();
}
return isInheritable(((CSharpRefTypeRef) top).getInnerTypeRef(), ((CSharpRefTypeRef) target).getInnerTypeRef(), scope, castType);
}
if(target instanceof CSharpRefTypeRef)
{
target = ((CSharpRefTypeRef) target).getInnerTypeRef();
}
if(top instanceof CSharpRefTypeRef)
{
top = ((CSharpRefTypeRef) top).getInnerTypeRef();
}
if(target instanceof DotNetPointerTypeRef || top instanceof DotNetPointerTypeRef)
{
if(target instanceof DotNetPointerTypeRef && !(top instanceof DotNetPointerTypeRef))
{
return fail();
}
if(top instanceof DotNetPointerTypeRef && !(target instanceof DotNetPointerTypeRef))
{
return fail();
}
DotNetTypeRef topInnerTypeRef = ((DotNetPointerTypeRef) top).getInnerTypeRef();
// void* is unknown type for all
if(DotNetTypeRefUtil.isVmQNameEqual(topInnerTypeRef, scope, DotNetTypes.System.Void))
{
return SIMPLE_SUCCESS;
}
return isTypeEqual(topInnerTypeRef, ((DotNetPointerTypeRef) target).getInnerTypeRef(), scope) ? SIMPLE_SUCCESS : fail();
}
if(target instanceof CSharpArrayTypeRef && top instanceof CSharpArrayTypeRef)
{
if(((CSharpArrayTypeRef) target).getDimensions() != ((CSharpArrayTypeRef) top).getDimensions())
{
return fail();
}
return isInheritable(((CSharpArrayTypeRef) top).getInnerTypeRef(), ((CSharpArrayTypeRef) target).getInnerTypeRef(), scope, castType);
}
DotNetTypeResolveResult topTypeResolveResult = top.resolve();
DotNetTypeResolveResult targetTypeResolveResult = target.resolve();
if(topTypeResolveResult instanceof CSharpLambdaResolveResult && targetTypeResolveResult instanceof CSharpLambdaResolveResult)
{
if(!((CSharpLambdaResolveResult) targetTypeResolveResult).isInheritParameters())
{
DotNetTypeRef[] targetParameters = ((CSharpLambdaResolveResult) targetTypeResolveResult).getParameterTypeRefs();
DotNetTypeRef[] topParameters = ((CSharpLambdaResolveResult) topTypeResolveResult).getParameterTypeRefs();
if(topParameters.length != targetParameters.length)
{
return fail();
}
for(int i = 0; i < targetParameters.length; i++)
{
DotNetTypeRef targetParameter = targetParameters[i];
DotNetTypeRef topParameter = topParameters[i];
if(targetParameter == DotNetTypeRef.AUTO_TYPE)
{
continue;
}
if(!isInheritable(topParameter, targetParameter, scope, castType).isSuccess())
{
return fail();
}
}
}
DotNetTypeRef targetReturnType = ((CSharpLambdaResolveResult) targetTypeResolveResult).getReturnTypeRef();
DotNetTypeRef topReturnType = ((CSharpLambdaResolveResult) topTypeResolveResult).getReturnTypeRef();
boolean result = targetReturnType == DotNetTypeRef.AUTO_TYPE || isInheritable(topReturnType, targetReturnType, scope, castType).isSuccess();
return result ? SIMPLE_SUCCESS : FAIL;
}
PsiElement topElement = topTypeResolveResult.getElement();
PsiElement targetElement = targetTypeResolveResult.getElement();
if(topElement == null && targetElement == null && top instanceof CSharpUserTypeRef && target instanceof CSharpUserTypeRef)
{
return ((CSharpUserTypeRef) top).getReferenceText().equals(((CSharpUserTypeRef) target).getReferenceText()) ? SIMPLE_SUCCESS : FAIL;
}
if(topTypeResolveResult.isNullable() && target instanceof CSharpNullTypeRef)
{
return SIMPLE_SUCCESS;
}
if(!topTypeResolveResult.isNullable() && target instanceof CSharpNullTypeRef)
{
return fail();
}
DotNetGenericExtractor topGenericExtractor = topTypeResolveResult.getGenericExtractor();
if(castType != null)
{
if(topElement instanceof DotNetTypeDeclaration)
{
InheritResult inheritResult = haveImplicitOrExplicitOperatorTo(top, target, (DotNetTypeDeclaration) topElement, topGenericExtractor, scope, castType);
if(inheritResult.isSuccess())
{
return inheritResult;
}
}
if(targetElement instanceof DotNetTypeDeclaration)
{
InheritResult inheritResult = haveImplicitOrExplicitOperatorTo(top, target, (DotNetTypeDeclaration) targetElement, targetTypeResolveResult.getGenericExtractor(), scope,
castType);
if(inheritResult.isSuccess())
{
return inheritResult;
}
}
}
// dont allow not nullable type to nullable
if(!topTypeResolveResult.isNullable() && targetTypeResolveResult.isNullable())
{
return fail();
}
if(topGenericExtractor != DotNetGenericExtractor.EMPTY && topElement instanceof DotNetTypeDeclaration)
{
DotNetTypeDeclaration topTypeDeclaration = (DotNetTypeDeclaration) topElement;
DotNetTypeResolveResult typeFromSuper = findTypeRefFromExtends(target, topTypeDeclaration, scope, new THashSet<String>());
if(typeFromSuper == null)
{
return fail();
}
DotNetGenericExtractor superGenericExtractor = typeFromSuper.getGenericExtractor();
if(targetElement instanceof DotNetTypeDeclaration)
{
// we already check for equals inside findTypeRefFromExtends
DotNetGenericParameter[] genericParameters = ((DotNetTypeDeclaration) topElement).getGenericParameters();
for(DotNetGenericParameter genericParameter : genericParameters)
{
DotNetTypeRef topExtractedTypeRef = topGenericExtractor.extract(genericParameter);
DotNetTypeRef superExtractedTypeRef = superGenericExtractor.extract(genericParameter);
if(topExtractedTypeRef == null || superExtractedTypeRef == null)
{
return fail();
}
if(genericParameter.hasModifier(CSharpModifier.OUT))
{
if(!isInheritable(topExtractedTypeRef, superExtractedTypeRef, scope, null).isSuccess())
{
return fail();
}
}
else if(genericParameter.hasModifier(CSharpModifier.IN))
{
if(!isInheritable(superExtractedTypeRef, topExtractedTypeRef, scope, null).isSuccess())
{
return fail();
}
}
else
{
if(!isTypeEqual(topExtractedTypeRef, superExtractedTypeRef, scope))
{
return fail();
}
}
}
return SIMPLE_SUCCESS;
}
}
else
{
if(topElement != null && topElement.isEquivalentTo(targetElement))
{
return SIMPLE_SUCCESS;
}
}
if(topElement instanceof CSharpTypeDefStatement)
{
return isInheritable(((CSharpTypeDefStatement) topElement).toTypeRef(), target, scope, castType);
}
if(targetElement instanceof CSharpTypeDefStatement)
{
return isInheritable(top, ((CSharpTypeDefStatement) targetElement).toTypeRef(), scope, castType);
}
if(topElement instanceof DotNetTypeDeclaration && targetElement instanceof DotNetTypeDeclaration)
{
if(((DotNetTypeDeclaration) targetElement).isInheritor(((DotNetTypeDeclaration) topElement).getVmQName(), true))
{
return SIMPLE_SUCCESS;
}
}
if(topElement instanceof CSharpGenericParameter)
{
DotNetTypeRef[] extendTypes = ((CSharpGenericParameter) topElement).getExtendTypeRefs();
for(DotNetTypeRef extendType : extendTypes)
{
InheritResult inheritable = isInheritable(extendType, target, scope, castType);
if(inheritable.isSuccess())
{
return inheritable;
}
}
}
if(targetElement instanceof CSharpGenericParameter)
{
DotNetTypeRef[] extendTypes = ((CSharpGenericParameter) targetElement).getExtendTypeRefs();
for(DotNetTypeRef extendType : extendTypes)
{
InheritResult inheritable = isInheritable(top, extendType, scope, castType);
if(inheritable.isSuccess())
{
return inheritable;
}
}
}
return fail();
}
private static InheritResult fail()
{
//return FAIL;
return new InheritResult(false, null);
}
@NotNull
@RequiredReadAction
private static InheritResult haveImplicitOrExplicitOperatorTo(@NotNull DotNetTypeRef to,
@NotNull DotNetTypeRef from,
@NotNull DotNetTypeDeclaration typeDeclaration,
@NotNull DotNetGenericExtractor extractor,
@NotNull PsiElement scope,
@NotNull CSharpCastType explicitOrImplicit)
{
CSharpResolveContext context = CSharpResolveContextUtil.createContext(DotNetGenericExtractor.EMPTY, scope.getResolveScope(), typeDeclaration);
CSharpElementGroup<CSharpConversionMethodDeclaration> conversionMethodGroup = context.findConversionMethodGroup(explicitOrImplicit, true);
if(conversionMethodGroup == null)
{
return fail();
}
// we need swap to vs from for explicit
if(explicitOrImplicit == CSharpCastType.EXPLICIT)
{
DotNetTypeRef temp = to;
to = from;
from = temp;
}
for(CSharpConversionMethodDeclaration declaration : conversionMethodGroup.getElements())
{
// extract here
declaration = GenericUnwrapTool.extract(declaration, extractor);
if(!isInheritable(declaration.getReturnTypeRef(), to, scope))
{
continue;
}
DotNetTypeRef[] parameters = declaration.getParameterTypeRefs();
DotNetTypeRef parameterTypeRef = ArrayUtil2.safeGet(parameters, 0);
if(parameterTypeRef == null)
{
continue;
}
if(isInheritable(parameterTypeRef, from, scope))
{
return new InheritResult(true, declaration);
}
}
return fail();
}
@NotNull
@RequiredReadAction
public static List<DotNetTypeRef> getImplicitOrExplicitTypeRefs(@NotNull DotNetTypeRef fromTypeRef,
@NotNull DotNetTypeRef leftTypeRef,
@NotNull CSharpCastType explicitOrImplicit,
@NotNull PsiElement scope)
{
DotNetTypeResolveResult typeResolveResult = fromTypeRef.resolve();
PsiElement typeResolveResultElement = typeResolveResult.getElement();
if(!(typeResolveResultElement instanceof DotNetTypeDeclaration))
{
return Collections.emptyList();
}
CSharpResolveContext context = CSharpResolveContextUtil.createContext(DotNetGenericExtractor.EMPTY, scope.getResolveScope(), typeResolveResultElement);
CSharpElementGroup<CSharpConversionMethodDeclaration> conversionMethodGroup = context.findConversionMethodGroup(explicitOrImplicit, true);
if(conversionMethodGroup == null)
{
return Collections.emptyList();
}
DotNetGenericExtractor extractor = typeResolveResult.getGenericExtractor();
List<DotNetTypeRef> list = new SmartList<DotNetTypeRef>();
for(CSharpConversionMethodDeclaration declaration : conversionMethodGroup.getElements())
{
// extract here
declaration = GenericUnwrapTool.extract(declaration, extractor);
DotNetTypeRef[] parameters = declaration.getParameterTypeRefs();
DotNetTypeRef parameterTypeRef = ArrayUtil2.safeGet(parameters, 0);
if(parameterTypeRef == null)
{
continue;
}
if(!isInheritable(parameterTypeRef, leftTypeRef, scope))
{
continue;
}
list.add(declaration.getReturnTypeRef());
}
return list;
}
@RequiredReadAction
public static boolean isTypeEqual(@NotNull DotNetTypeRef t1, @NotNull DotNetTypeRef t2, @NotNull PsiElement scope)
{
if(t1 == DotNetTypeRef.ERROR_TYPE || t2 == DotNetTypeRef.ERROR_TYPE)
{
return false;
}
t1 = GenericUnwrapTool.exchangeTypeRef(t1, GenericUnwrapTool.TypeDefCleanFunction.INSTANCE, scope);
t2 = GenericUnwrapTool.exchangeTypeRef(t2, GenericUnwrapTool.TypeDefCleanFunction.INSTANCE, scope);
if(t1 instanceof CSharpArrayTypeRef && t2 instanceof CSharpArrayTypeRef)
{
return ((CSharpArrayTypeRef) t1).getDimensions() == ((CSharpArrayTypeRef) t2).getDimensions() && isTypeEqual(((CSharpArrayTypeRef) t1).getInnerTypeRef(),
((CSharpArrayTypeRef) t2).getInnerTypeRef(), scope);
}
DotNetTypeResolveResult resolveResult1 = t1.resolve();
DotNetTypeResolveResult resolveResult2 = t2.resolve();
if(resolveResult1.isNullable() != resolveResult2.isNullable())
{
return false;
}
PsiElement element1 = resolveResult1.getElement();
PsiElement element2 = resolveResult2.getElement();
if(element1 == null && element2 == null && t1 instanceof CSharpUserTypeRef && t2 instanceof CSharpUserTypeRef)
{
return ((CSharpUserTypeRef) t1).getReferenceText().equals(((CSharpUserTypeRef) t2).getReferenceText());
}
if(element1 == null || element2 == null)
{
return false;
}
if(element1 instanceof DotNetGenericParameter && element2 instanceof DotNetGenericParameter)
{
if(isMethodGeneric(element1) && isMethodGeneric(element2) && ((DotNetGenericParameter) element1).getIndex() == ((DotNetGenericParameter) element2).getIndex())
{
return true;
}
if(isTypeGeneric(element1) && isTypeGeneric(element2) && ((DotNetGenericParameter) element1).getIndex() == ((DotNetGenericParameter) element2).getIndex())
{
return true;
}
}
if(!element1.isEquivalentTo(element2))
{
return false;
}
if(element1 instanceof DotNetGenericParameterListOwner)
{
assert element2 instanceof DotNetGenericParameterListOwner;
DotNetGenericParameter[] genericParameters1 = ((DotNetGenericParameterListOwner) element1).getGenericParameters();
DotNetGenericParameter[] genericParameters2 = ((DotNetGenericParameterListOwner) element2).getGenericParameters();
if(genericParameters1.length != genericParameters2.length)
{
return false;
}
DotNetGenericExtractor genericExtractor1 = resolveResult1.getGenericExtractor();
DotNetGenericExtractor genericExtractor2 = resolveResult2.getGenericExtractor();
for(int i = 0; i < genericParameters1.length; i++)
{
DotNetGenericParameter genericParameter1 = genericParameters1[i];
DotNetGenericParameter genericParameter2 = genericParameters2[i];
DotNetTypeRef extractedRef1 = genericExtractor1.extract(genericParameter1);
DotNetTypeRef extractedRef2 = genericExtractor2.extract(genericParameter2);
if(extractedRef1 == null && extractedRef2 == null)
{
continue;
}
if(!isTypeEqual(ObjectUtil.notNull(extractedRef1, DotNetTypeRef.ERROR_TYPE), ObjectUtil.notNull(extractedRef2, DotNetTypeRef.ERROR_TYPE), scope))
{
return false;
}
}
}
return true;
}
@RequiredReadAction
private static boolean isMethodGeneric(PsiElement element)
{
if(!(element instanceof DotNetGenericParameter))
{
return false;
}
PsiElement parent = element.getParent();
if(!(parent instanceof DotNetGenericParameterList))
{
return false;
}
PsiElement parentParent = parent.getParent();
return parentParent instanceof DotNetLikeMethodDeclaration;
}
@RequiredReadAction
private static boolean isTypeGeneric(PsiElement element)
{
if(!(element instanceof DotNetGenericParameter))
{
return false;
}
PsiElement parent = element.getParent();
if(!(parent instanceof DotNetGenericParameterList))
{
return false;
}
PsiElement parentParent = parent.getParent();
return parentParent instanceof CSharpTypeDeclaration;
}
@Nullable
@RequiredReadAction
public static Pair<String, DotNetTypeDeclaration> resolveTypeElement(@NotNull DotNetTypeRef typeRef)
{
DotNetTypeResolveResult typeResolveResult = typeRef.resolve();
PsiElement typeResolveResultElement = typeResolveResult.getElement();
if(typeResolveResultElement instanceof DotNetTypeDeclaration)
{
return Pair.create(((DotNetTypeDeclaration) typeResolveResultElement).getVmQName(), (DotNetTypeDeclaration) typeResolveResultElement);
}
return null;
}
}