/* * 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.source.resolve.type; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.psi.PsiElement; import consulo.annotations.RequiredReadAction; import consulo.csharp.lang.psi.CSharpMethodDeclaration; import consulo.csharp.lang.psi.CSharpReferenceExpression; import consulo.csharp.lang.psi.CSharpSimpleParameterInfo; import consulo.csharp.lang.psi.CSharpTypeDefStatement; import consulo.csharp.lang.psi.impl.CSharpTypeUtil; import consulo.csharp.lang.psi.impl.source.resolve.type.wrapper.GenericUnwrapTool; import consulo.dotnet.psi.DotNetGenericParameter; import consulo.dotnet.psi.DotNetGenericParameterListOwner; import consulo.dotnet.resolve.DotNetGenericExtractor; import consulo.dotnet.resolve.DotNetTypeRef; import consulo.dotnet.resolve.DotNetTypeRefWithCachedResult; import consulo.dotnet.resolve.DotNetTypeResolveResult; /** * @author VISTALL * @since 20.10.14 */ public class CSharpUserTypeRef extends DotNetTypeRefWithCachedResult { public static class Result<T extends PsiElement> extends SingleNullableStateResolveResult { protected final T myElement; protected final DotNetGenericExtractor myExtractor; public Result(T element, DotNetGenericExtractor extractor) { myElement = element; myExtractor = extractor; } @Nullable @Override public PsiElement getElement() { return myElement; } @NotNull @Override public DotNetGenericExtractor getGenericExtractor() { return myExtractor; } @RequiredReadAction @Override public boolean isNullableImpl() { PsiElement element = getElement(); return element == null || CSharpTypeUtil.isNullableElement(element); } } public static class LambdaResult extends Result<CSharpMethodDeclaration> implements CSharpLambdaResolveResult { private final NotNullLazyValue<CSharpSimpleParameterInfo[]> myParameterInfosValue; private final NotNullLazyValue<PsiElement> myElementValue; private final NotNullLazyValue<DotNetTypeRef> myReturnTypRefValue; private final NotNullLazyValue<DotNetTypeRef[]> myParameterTypeRefsValue; private final PsiElement myScope; @RequiredReadAction public LambdaResult(@NotNull PsiElement scope, @NotNull CSharpMethodDeclaration element, @NotNull DotNetGenericExtractor extractor) { super(element, extractor); myScope = scope; myParameterInfosValue = NotNullLazyValue.createValue(() -> { CSharpSimpleParameterInfo[] parameterInfos = myElement.getParameterInfos(); if(myExtractor == DotNetGenericExtractor.EMPTY) { return parameterInfos; } CSharpSimpleParameterInfo[] temp = new CSharpSimpleParameterInfo[parameterInfos.length]; for(int i = 0; i < parameterInfos.length; i++) { CSharpSimpleParameterInfo parameterInfo = parameterInfos[i]; DotNetTypeRef typeRef = GenericUnwrapTool.exchangeTypeRef(parameterInfo.getTypeRef(), getGenericExtractor(), myScope); temp[i] = new CSharpSimpleParameterInfo(parameterInfo.getIndex(), parameterInfo.getName(), parameterInfo.getElement(), typeRef); } return temp; }); myElementValue = NotNullLazyValue.createValue(() -> CSharpLambdaResolveResultUtil.createTypeFromDelegate(myElement, myExtractor)); myReturnTypRefValue = NotNullLazyValue.createValue(() -> GenericUnwrapTool.exchangeTypeRef(myElement.getReturnTypeRef(), getGenericExtractor(), scope)); myParameterTypeRefsValue = NotNullLazyValue.createValue(() -> GenericUnwrapTool.exchangeTypeRefs(myElement.getParameterTypeRefs(), getGenericExtractor(), myScope)); } @NotNull @Override @RequiredReadAction public CSharpSimpleParameterInfo[] getParameterInfos() { return myParameterInfosValue.getValue(); } @Nullable @Override public PsiElement getElement() { return myElementValue.getValue(); } @RequiredReadAction @NotNull @Override public DotNetTypeRef getReturnTypeRef() { return myReturnTypRefValue.getValue(); } @RequiredReadAction @Override public boolean isInheritParameters() { return false; } @RequiredReadAction @NotNull @Override public DotNetTypeRef[] getParameterTypeRefs() { return myParameterTypeRefsValue.getValue(); } @RequiredReadAction @Override public boolean isNullableImpl() { return true; } @NotNull @Override public CSharpMethodDeclaration getTarget() { return myElement; } } protected final CSharpReferenceExpression myReferenceExpression; public CSharpUserTypeRef(@NotNull CSharpReferenceExpression referenceExpression) { myReferenceExpression = referenceExpression; } @RequiredReadAction @NotNull @Override public String toString() { DotNetTypeRef[] argumentTypeRefs = myReferenceExpression.getTypeArgumentListRefs(); StringBuilder builder = new StringBuilder(); builder.append(myReferenceExpression.getReferenceName()); if(argumentTypeRefs.length > 0) { builder.append("<"); for(int i = 0; i < argumentTypeRefs.length; i++) { if(i != 0) { builder.append(", "); } DotNetTypeRef argument = argumentTypeRefs[i]; builder.append(argument.toString()); } builder.append(">"); } return builder.toString(); } @NotNull @Override @RequiredReadAction public DotNetTypeResolveResult resolveResult() { PsiElement resolve = myReferenceExpression.resolve(); if(resolve instanceof CSharpMethodDeclaration && ((CSharpMethodDeclaration) resolve).isDelegate()) { return new LambdaResult(myReferenceExpression, (CSharpMethodDeclaration) resolve, createExtractor(resolve)); } else if(resolve instanceof CSharpTypeDefStatement) { DotNetTypeRef typeRef = ((CSharpTypeDefStatement) resolve).toTypeRef(); return typeRef.resolve(); } return new Result<>(resolve, createExtractor(resolve)); } @NotNull public CSharpReferenceExpression getReferenceExpression() { return myReferenceExpression; } @NotNull @RequiredReadAction private DotNetGenericExtractor createExtractor(PsiElement resolved) { DotNetTypeRef[] typeArgumentListRefs = myReferenceExpression.getTypeArgumentListRefs(); if(typeArgumentListRefs.length == 0) { return DotNetGenericExtractor.EMPTY; } if(resolved instanceof DotNetGenericParameterListOwner) { DotNetGenericParameter[] genericParameters = ((DotNetGenericParameterListOwner) resolved).getGenericParameters(); if(genericParameters.length == typeArgumentListRefs.length) { return CSharpGenericExtractor.create(genericParameters, typeArgumentListRefs); } } return DotNetGenericExtractor.EMPTY; } @NotNull @RequiredReadAction public String getReferenceText() { DotNetTypeRef[] argumentTypeRefs = myReferenceExpression.getTypeArgumentListRefs(); StringBuilder builder = new StringBuilder(); builder.append(myReferenceExpression.getReferenceName()); if(argumentTypeRefs.length > 0) { builder.append("<"); for(int i = 0; i < argumentTypeRefs.length; i++) { if(i != 0) { builder.append(", "); } DotNetTypeRef argument = argumentTypeRefs[i]; builder.append(argument.toString()); } builder.append(">"); } return builder.toString(); } }