/*
* 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.msil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import consulo.csharp.lang.psi.CSharpMethodDeclaration;
import consulo.csharp.lang.psi.ToNativeElementTransformers;
import consulo.csharp.lang.psi.impl.CSharpTypeUtil;
import consulo.csharp.lang.psi.impl.msil.transformer.MsilToNativeElementTransformer;
import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpLambdaTypeRef;
import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpUserTypeRef;
import consulo.csharp.lang.psi.impl.source.resolve.type.SingleNullableStateResolveResult;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.psi.PsiElement;
import consulo.annotations.RequiredReadAction;
import consulo.dotnet.DotNetTypes;
import consulo.dotnet.psi.DotNetGenericParameter;
import consulo.dotnet.psi.DotNetGenericParameterListOwner;
import consulo.dotnet.psi.DotNetInheritUtil;
import consulo.dotnet.resolve.DotNetGenericExtractor;
import consulo.dotnet.resolve.DotNetTypeRef;
import consulo.dotnet.resolve.DotNetTypeRefWithCachedResult;
import consulo.dotnet.resolve.DotNetTypeResolveResult;
import consulo.internal.dotnet.msil.decompiler.util.MsilHelper;
import consulo.msil.lang.psi.MsilClassEntry;
import consulo.msil.lang.psi.MsilMethodEntry;
import consulo.msil.lang.psi.impl.type.MsilClassGenericTypeRefImpl;
import consulo.msil.lang.psi.impl.type.MsilMethodGenericTypeRefImpl;
/**
* @author VISTALL
* @since 23.05.14
*/
public class MsilDelegateTypeRef extends DotNetTypeRefWithCachedResult
{
private static class MsilResult extends SingleNullableStateResolveResult
{
private final PsiElement myElement;
private final DotNetTypeResolveResult myResolveResult;
public MsilResult(PsiElement element, DotNetTypeResolveResult resolveResult)
{
myElement = element;
myResolveResult = resolveResult;
}
@Nullable
@Override
@RequiredReadAction
public PsiElement getElement()
{
return ToNativeElementTransformers.transform(myElement);
}
@NotNull
@Override
public DotNetGenericExtractor getGenericExtractor()
{
return myResolveResult.getGenericExtractor();
}
@Override
@RequiredReadAction
public boolean isNullableImpl()
{
return CSharpTypeUtil.isNullableElement(getElement());
}
}
private NotNullLazyValue<DotNetTypeResolveResult> myResultValue = new NotNullLazyValue<DotNetTypeResolveResult>()
{
@NotNull
@Override
@RequiredReadAction
protected DotNetTypeResolveResult compute()
{
final DotNetTypeRef msilTypeRef = myTypeRef;
final DotNetTypeResolveResult resolveResult = msilTypeRef.resolve();
final PsiElement element = resolveResult.getElement();
if(element == null)
{
return DotNetTypeResolveResult.EMPTY;
}
if(element instanceof MsilClassEntry)
{
MsilClassEntry msilClassEntry = (MsilClassEntry) element;
if(DotNetInheritUtil.isInheritor(msilClassEntry, DotNetTypes.System.MulticastDelegate, false))
{
PsiElement transformedElement = ToNativeElementTransformers.transform(element);
if(transformedElement instanceof CSharpMethodDeclaration)
{
return new CSharpLambdaTypeRef((CSharpMethodDeclaration) transformedElement).resolve();
}
}
}
else if(element instanceof DotNetGenericParameter)
{
if(msilTypeRef instanceof MsilMethodGenericTypeRefImpl)
{
MsilMethodGenericTypeRefImpl methodGenericTypeRef = (MsilMethodGenericTypeRefImpl) msilTypeRef;
MsilMethodEntry msilMethodEntry = methodGenericTypeRef.getParent();
MsilClassEntry rootClassEntry = MsilToNativeElementTransformer.findRootClassEntry((MsilClassEntry) msilMethodEntry.getParent());
PsiElement wrappedElement = ToNativeElementTransformers.transform(rootClassEntry);
if(wrappedElement == rootClassEntry)
{
return DotNetTypeResolveResult.EMPTY;
}
PsiElement elementByOriginal = MsilToNativeElementTransformer.findElementByOriginal(wrappedElement, msilMethodEntry);
if(elementByOriginal instanceof DotNetGenericParameterListOwner)
{
DotNetGenericParameter[] genericParameters = ((DotNetGenericParameterListOwner) elementByOriginal).getGenericParameters();
return new CSharpUserTypeRef.Result<PsiElement>(genericParameters[methodGenericTypeRef.getIndex()], DotNetGenericExtractor.EMPTY);
}
}
else if(msilTypeRef instanceof MsilClassGenericTypeRefImpl)
{
MsilClassEntry msilClassEntry = ((MsilClassGenericTypeRefImpl) msilTypeRef).getParent();
MsilClassEntry rootClassEntry = MsilToNativeElementTransformer.findRootClassEntry(msilClassEntry);
PsiElement wrappedElement = ToNativeElementTransformers.transform(rootClassEntry);
if(wrappedElement == rootClassEntry)
{
return DotNetTypeResolveResult.EMPTY;
}
PsiElement elementByOriginal = MsilToNativeElementTransformer.findElementByOriginal(wrappedElement, msilClassEntry);
if(elementByOriginal instanceof DotNetGenericParameterListOwner)
{
final String genericName = msilTypeRef.toString();
PsiElement owner = elementByOriginal;
while(owner instanceof DotNetGenericParameterListOwner)
{
DotNetGenericParameter[] genericParameters = ((DotNetGenericParameterListOwner) owner).getGenericParameters();
for(DotNetGenericParameter genericParameter : genericParameters)
{
if(genericName.equals(genericParameter.getName()))
{
return new CSharpUserTypeRef.Result<PsiElement>(genericParameter, DotNetGenericExtractor.EMPTY);
}
}
owner = owner.getParent();
}
}
}
return DotNetTypeResolveResult.EMPTY;
}
return new MsilResult(element, resolveResult);
}
};
@NotNull
private final PsiElement myScope;
private DotNetTypeRef myTypeRef;
public MsilDelegateTypeRef(@NotNull PsiElement scope, @NotNull DotNetTypeRef typeRef)
{
myScope = scope;
myTypeRef = typeRef;
}
@RequiredReadAction
@NotNull
@Override
protected DotNetTypeResolveResult resolveResult()
{
return myResultValue.getValue();
}
@RequiredReadAction
@NotNull
@Override
public String toString()
{
return MsilHelper.prepareForUser(myTypeRef.toString());
}
}