/* * 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; import static consulo.csharp.lang.psi.CSharpReferenceExpression.ResolveToKind; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.intellij.lang.ASTNode; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiLanguageInjectionHost; import com.intellij.psi.ResolveResult; import com.intellij.psi.ResolveState; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.impl.source.tree.injected.Place; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.CommonProcessors; import com.intellij.util.ObjectUtil; import com.intellij.util.Processor; import consulo.annotations.RequiredReadAction; import consulo.csharp.lang.doc.psi.CSharpDocRoot; import consulo.csharp.lang.psi.*; import consulo.csharp.lang.psi.impl.CSharpNullableTypeUtil; import consulo.csharp.lang.psi.impl.source.injection.CSharpForInjectionFragmentHolder; import consulo.csharp.lang.psi.impl.source.resolve.CSharpResolveOptions; import consulo.csharp.lang.psi.impl.source.resolve.CSharpResolveResultWithExtractor; import consulo.csharp.lang.psi.impl.source.resolve.CompletionResolveScopeProcessor; import consulo.csharp.lang.psi.impl.source.resolve.ExecuteTarget; import consulo.csharp.lang.psi.impl.source.resolve.MemberResolveScopeProcessor; import consulo.csharp.lang.psi.impl.source.resolve.SimpleNamedScopeProcessor; import consulo.csharp.lang.psi.impl.source.resolve.SortedMemberResolveScopeProcessor; import consulo.csharp.lang.psi.impl.source.resolve.StubScopeProcessor; import consulo.csharp.lang.psi.impl.source.resolve.cache.CSharpResolveCache; import consulo.csharp.lang.psi.impl.source.resolve.extensionResolver.ExtensionResolveScopeProcessor; import consulo.csharp.lang.psi.impl.source.resolve.handlers.*; import consulo.csharp.lang.psi.impl.source.resolve.sorter.StaticVsInstanceComparator; import consulo.csharp.lang.psi.impl.source.resolve.sorter.TypeLikeComparator; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpDynamicTypeRef; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpElementGroupTypeRef; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpGenericExtractor; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpLambdaTypeRef; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpTypeRefByTypeDeclaration; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpTypeRefFromGenericParameter; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpTypeRefFromNamespace; import consulo.csharp.lang.psi.impl.source.resolve.util.CSharpResolveUtil; import consulo.csharp.lang.psi.resolve.AttributeByNameSelector; import consulo.csharp.lang.psi.resolve.CSharpElementGroup; import consulo.csharp.lang.psi.resolve.CSharpResolveSelector; import consulo.csharp.lang.psi.resolve.ExtensionMethodByNameSelector; import consulo.csharp.lang.psi.resolve.MemberByNameSelector; import consulo.csharp.lang.psi.resolve.StaticResolveSelectors; import consulo.dotnet.psi.*; import consulo.dotnet.resolve.DotNetGenericExtractor; import consulo.dotnet.resolve.DotNetNamespaceAsElement; import consulo.dotnet.resolve.DotNetPointerTypeRef; import consulo.dotnet.resolve.DotNetTypeRef; import consulo.dotnet.resolve.DotNetTypeResolveResult; import consulo.dotnet.util.ArrayUtil2; /** * @author VISTALL * @since 17.06.14 */ public class CSharpReferenceExpressionImplUtil { public static class OurResolver implements CSharpResolveCache.PolyVariantResolver<CSharpReferenceExpressionEx> { public static final OurResolver INSTANCE = new OurResolver(); @RequiredReadAction @NotNull @Override public ResolveResult[] resolve(@NotNull CSharpReferenceExpressionEx ref, boolean incompleteCode, boolean resolveFromParent) { if(!incompleteCode) { return ref.multiResolveImpl(ref.kind(), resolveFromParent); } else { return CSharpResolveUtil.filterValidResults(ref.multiResolve(false, resolveFromParent)); } } } public static final TokenSet ourReferenceElements = TokenSet.orSet(CSharpTokenSets.NATIVE_TYPES, TokenSet.create(CSharpTokens.THIS_KEYWORD, CSharpTokens.BASE_KEYWORD, CSharpTokens.IDENTIFIER, CSharpSoftTokens.GLOBAL_KEYWORD)); public static final TokenSet ourAccessTokens = TokenSet.create(CSharpTokens.ARROW, CSharpTokens.DOT, CSharpTokens.PLUS, CSharpTokens.COLONCOLON, CSharpTokens.NULLABE_CALL); private static KindProcessor[] ourProcessors = new KindProcessor[ResolveToKind.VALUES.length]; static { for(int i = 0; i < ResolveToKind.VALUES.length; i++) { ResolveToKind value = ResolveToKind.VALUES[i]; KindProcessor kindProcessor; switch(value) { case GENERIC_PARAMETER_FROM_PARENT: kindProcessor = new GenericFromParentKindProcessor(); break; case QUALIFIED_NAMESPACE: case SOFT_QUALIFIED_NAMESPACE: kindProcessor = new QualifiedNamespaceKindProcessor(); break; case NATIVE_TYPE_WRAPPER: kindProcessor = new NativeTypeWrapperKindProcessor(); break; case METHOD: case ARRAY_METHOD: case CONSTRUCTOR: case BASE_CONSTRUCTOR: case THIS_CONSTRUCTOR: kindProcessor = new MethodLikeKindProcessor(); break; case TYPE_LIKE: case NAMEOF: kindProcessor = new TypeLikeKindProcessor(); break; case ANY_MEMBER: kindProcessor = new AnyMemberKindProcessor(); break; case FIELD_OR_PROPERTY: kindProcessor = new FieldOrPropertyKindProcessor(); break; case PARAMETER: kindProcessor = new ParameterKindProcessor(); break; case THIS: kindProcessor = new ThisKindProcessor(); break; case BASE: kindProcessor = new BaseKindProcessor(); break; case ROOT_NAMESPACE: kindProcessor = new RootNamespaceKindProcessor(); break; case LABEL: kindProcessor = new LabelKindProcessor(); break; case PARAMETER_FROM_PARENT: kindProcessor = new ParameterFromParentKindProcessor(); break; case EXPRESSION_OR_TYPE_LIKE: kindProcessor = new ExpressionOrTypeLikeKindProcessor(); break; default: kindProcessor = new DummyKindProcessor(value); break; } ourProcessors[i] = kindProcessor; } } @RequiredReadAction public static boolean isReferenceTo(CSharpReferenceExpression referenceExpression, PsiElement element) { final ResolveResult firstValidResult = CSharpResolveUtil.findValidOrFirstMaybeResult(referenceExpression.multiResolve(false)); if(firstValidResult == null) { return false; } return isReferenceTo(firstValidResult, element); } @RequiredReadAction private static boolean isReferenceTo(@NotNull ResolveResult resolveResult, PsiElement element) { PsiElement psiElement = resolveResult.getElement(); if(element instanceof DotNetNamespaceAsElement && psiElement instanceof DotNetNamespaceAsElement) { if(Comparing.equal(((DotNetNamespaceAsElement) psiElement).getPresentableQName(), ((DotNetNamespaceAsElement) element).getPresentableQName())) { return true; } } if(element.getManager().areElementsEquivalent(element, psiElement)) { return true; } return false; } public static boolean isConstructorKind(ResolveToKind kind) { switch(kind) { case CONSTRUCTOR: case BASE_CONSTRUCTOR: case THIS_CONSTRUCTOR: return true; default: return false; } } @Nullable public static CSharpCallArgumentListOwner findCallArgumentListOwner(ResolveToKind kind, CSharpReferenceExpression referenceExpression) { PsiElement parent = referenceExpression.getParent(); CSharpCallArgumentListOwner p = null; if(CSharpReferenceExpressionImplUtil.isConstructorKind(kind) || kind == ResolveToKind.PARAMETER) { p = PsiTreeUtil.getParentOfType(referenceExpression, CSharpCallArgumentListOwner.class); } else if(parent instanceof CSharpCallArgumentListOwner) { p = (CSharpCallArgumentListOwner) parent; } return p; } @NotNull @RequiredReadAction public static DotNetTypeRef toTypeRef(@NotNull CSharpReferenceExpressionEx referenceExpressionEx, boolean resolveFromParent) { ResolveResult[] resolveResults = referenceExpressionEx.multiResolve(false, resolveFromParent); if(resolveResults.length == 0) { return DotNetTypeRef.ERROR_TYPE; } ResolveResult resolveResult = CSharpResolveUtil.findFirstValidResult(resolveResults); if(resolveResult == null) { return DotNetTypeRef.ERROR_TYPE; } DotNetTypeRef typeRef = CSharpReferenceExpressionImplUtil.toTypeRef(resolveResult); if(CSharpNullableTypeUtil.containsNullableCalls(referenceExpressionEx)) { return CSharpNullableTypeUtil.boxIfNeed(typeRef, referenceExpressionEx); } return typeRef; } @NotNull @RequiredReadAction public static DotNetTypeRef toTypeRefWithoutCaching(@NotNull CSharpReferenceExpressionEx referenceExpressionEx, @NotNull ResolveToKind kind, boolean resolveFromParent) { ResolveResult[] resolveResults = referenceExpressionEx.multiResolveImpl(kind, resolveFromParent); if(resolveResults.length == 0) { return DotNetTypeRef.ERROR_TYPE; } ResolveResult firstValidResult = CSharpResolveUtil.findFirstValidResult(resolveResults); if(firstValidResult == null) { return DotNetTypeRef.ERROR_TYPE; } return CSharpReferenceExpressionImplUtil.toTypeRef(firstValidResult); } @RequiredReadAction public static int getTypeArgumentListSize(@Nullable PsiElement element) { if(!(element instanceof CSharpReferenceExpression)) { return 0; } DotNetTypeList typeArgumentList = ((CSharpReferenceExpression) element).getTypeArgumentList(); if(typeArgumentList == null) { return 0; } return typeArgumentList.getTypesCount(); } @RequiredReadAction public static TextRange getRangeInElement(@NotNull CSharpReferenceExpression referenceExpression) { PsiElement referenceElement = referenceExpression.getReferenceElement(); if(referenceElement == null) { return TextRange.EMPTY_RANGE; } int startOffset = referenceElement.getStartOffsetInParent(); return new TextRange(startOffset, referenceElement.getTextLength() + startOffset); } @NotNull @RequiredReadAction public static ResolveToKind kind(@NotNull CSharpReferenceExpression referenceExpression) { return CachedValuesManager.getCachedValue(referenceExpression, () -> CachedValueProvider.Result.create(kindImpl(referenceExpression), PsiModificationTracker.MODIFICATION_COUNT)); } @NotNull @RequiredReadAction private static ResolveToKind kindImpl(@NotNull CSharpReferenceExpression referenceExpression) { if(referenceExpression.isGlobalElement()) { return ResolveToKind.ROOT_NAMESPACE; } PsiElement tempElement = referenceExpression.getParent(); if(tempElement instanceof CSharpGenericConstraintImpl) { DotNetGenericParameterListOwner parameterListOwner = PsiTreeUtil.getParentOfType(referenceExpression, DotNetGenericParameterListOwner.class); if(parameterListOwner == null) { return ResolveToKind.ANY_MEMBER; } return ResolveToKind.GENERIC_PARAMETER_FROM_PARENT; } else if(tempElement instanceof CSharpNamespaceDeclarationImpl) { return ResolveToKind.SOFT_QUALIFIED_NAMESPACE; } else if(tempElement instanceof CSharpNameOfExpressionImpl) { return ResolveToKind.NAMEOF; } else if(tempElement instanceof DotNetUserType) { PsiElement parent = tempElement.getParent(); CSharpLocalVariable localVariable = PsiTreeUtil.getParentOfType(tempElement, CSharpLocalVariable.class); if(localVariable != null) { if(localVariable.getParent() instanceof CSharpCatchStatementImpl) { // catch be without name return ResolveToKind.TYPE_LIKE; } if(CSharpPsiUtilImpl.isNullOrEmpty(localVariable)) { return ResolveToKind.EXPRESSION_OR_TYPE_LIKE; } } if(parent instanceof CSharpCallArgumentListOwner && ((CSharpCallArgumentListOwner) parent).canResolve()) { return ResolveToKind.CONSTRUCTOR; } return ResolveToKind.TYPE_LIKE; } else if(tempElement instanceof CSharpUsingNamespaceStatement) { return ResolveToKind.QUALIFIED_NAMESPACE; } else if(tempElement instanceof CSharpConstructorSuperCallImpl) { CSharpReferenceExpression expression = ((CSharpConstructorSuperCallImpl) tempElement).getExpression(); PsiElement referenceElement = expression.getReferenceElement(); if(referenceElement == null) { return ResolveToKind.CONSTRUCTOR; } IElementType elementType = referenceElement.getNode().getElementType(); if(elementType == CSharpTokens.BASE_KEYWORD) { return ResolveToKind.BASE_CONSTRUCTOR; } else if(elementType == CSharpTokens.THIS_KEYWORD) { return ResolveToKind.THIS_CONSTRUCTOR; } return ResolveToKind.CONSTRUCTOR; } else if(tempElement instanceof CSharpAttribute) { return ResolveToKind.CONSTRUCTOR; } else if(tempElement instanceof CSharpNamedCallArgument) { if(((CSharpNamedCallArgument) tempElement).getArgumentNameReference() == referenceExpression) { return ResolveToKind.PARAMETER; } } else if(tempElement instanceof CSharpNamedFieldOrPropertySet) { if(((CSharpFieldOrPropertySet) tempElement).getNameElement() == referenceExpression) { return ResolveToKind.FIELD_OR_PROPERTY; } } else if(tempElement instanceof CSharpReferenceExpression) { CSharpNamespaceDeclarationImpl netNamespaceDeclaration = PsiTreeUtil.getParentOfType(referenceExpression, CSharpNamespaceDeclarationImpl.class); if(netNamespaceDeclaration != null) { DotNetReferenceExpression namespaceReference = netNamespaceDeclaration.getNamespaceReference(); if(namespaceReference != null && PsiTreeUtil.isAncestor(namespaceReference, referenceExpression, false)) { return ResolveToKind.SOFT_QUALIFIED_NAMESPACE; } } if(PsiTreeUtil.getParentOfType(referenceExpression, CSharpUsingNamespaceStatementImpl.class) != null) { return ResolveToKind.QUALIFIED_NAMESPACE; } CSharpUserType userType = PsiTreeUtil.getParentOfType(referenceExpression, CSharpUserType.class); if(userType != null) { CSharpLocalVariable localVariable = PsiTreeUtil.getParentOfType(userType, CSharpLocalVariable.class); if(localVariable != null) { if(localVariable.getParent() instanceof CSharpCatchStatementImpl) { // catch be without name return ResolveToKind.TYPE_LIKE; } if(CSharpPsiUtilImpl.isNullOrEmpty(localVariable)) { return ResolveToKind.EXPRESSION_OR_TYPE_LIKE; } } return ResolveToKind.TYPE_LIKE; } if(PsiTreeUtil.getParentOfType(referenceExpression, CSharpAttribute.class) != null) { return ResolveToKind.TYPE_LIKE; } } else if(tempElement instanceof CSharpMethodCallExpressionImpl) { return ResolveToKind.METHOD; } else if(tempElement instanceof CSharpGotoStatementImpl) { return ResolveToKind.LABEL; } else if(tempElement instanceof CSharpForInjectionFragmentHolder) { return ((CSharpForInjectionFragmentHolder) tempElement).getKind(); } tempElement = referenceExpression.getReferenceElement(); ASTNode node = tempElement == null ? null : tempElement.getNode(); if(node == null) { return ResolveToKind.ANY_MEMBER; } IElementType elementType = node.getElementType(); if(CSharpTokenSets.NATIVE_TYPES.contains(elementType)) { return ResolveToKind.NATIVE_TYPE_WRAPPER; } else if(elementType == CSharpTokens.THIS_KEYWORD) { return ResolveToKind.THIS; } else if(elementType == CSharpTokens.BASE_KEYWORD) { return ResolveToKind.BASE; } return ResolveToKind.ANY_MEMBER; } @Nullable public static PsiElement resolveByTypeKind(@NotNull DotNetReferenceExpression referenceExpression, boolean attributeSuffix) { assert referenceExpression instanceof CSharpReferenceExpressionEx; ResolveToKind kind = ResolveToKind.TYPE_LIKE; if(attributeSuffix) { kind = ResolveToKind.ATTRIBUTE; } ResolveResult[] resultWithWeights = ((CSharpReferenceExpressionEx) referenceExpression).multiResolveImpl(kind, true); if(resultWithWeights.length == 0) { return null; } return resultWithWeights[0].getElement(); } @NotNull @RequiredReadAction public static ResolveResult[] multiResolveImpl(ResolveToKind kind, final CSharpCallArgumentListOwner callArgumentListOwner, final CSharpQualifiedNonReference element, boolean resolveFromParent) { ResolveResult[] resolveResults = buildSelectorAndMultiResolve(kind, callArgumentListOwner, element, resolveFromParent); if(element instanceof CSharpReferenceExpression) { int typeArgumentListSize = getTypeArgumentListSize(element); if(typeArgumentListSize > 0) { DotNetTypeRef[] typeArgumentListRefs = ((CSharpReferenceExpression) element).getTypeArgumentListRefs(); for(int i = 0; i < resolveResults.length; i++) { ResolveResult resolveResult = resolveResults[i]; PsiElement resolveResultElement = resolveResult.getElement(); if(resolveResultElement instanceof CSharpTypeDeclaration) { Map<DotNetGenericParameter, DotNetTypeRef> map = new HashMap<DotNetGenericParameter, DotNetTypeRef>(); DotNetGenericParameter[] genericParameters = ((CSharpTypeDeclaration) resolveResultElement).getGenericParameters(); for(int j = 0; j < typeArgumentListRefs.length; j++) { DotNetTypeRef typeArgumentListRef = typeArgumentListRefs[j]; DotNetGenericParameter genericParameter = ArrayUtil2.safeGet(genericParameters, j); if(genericParameter == null) { continue; } map.put(genericParameter, typeArgumentListRef); } resolveResults[i] = CSharpResolveResultWithExtractor.withExtractor(resolveResult, CSharpGenericExtractor.create(map)); } } } } return resolveResults; } @NotNull @RequiredReadAction public static ResolveResult[] buildSelectorAndMultiResolve(@NotNull ResolveToKind kind, @Nullable final CSharpCallArgumentListOwner callArgumentListOwner, @NotNull final CSharpQualifiedNonReference element, boolean resolveFromParent) { return buildSelectorAndMultiResolve(kind, callArgumentListOwner, element, null, resolveFromParent); } @NotNull @RequiredReadAction public static ResolveResult[] buildSelectorAndMultiResolve(@NotNull ResolveToKind kind, @Nullable final CSharpCallArgumentListOwner callArgumentListOwner, @NotNull final CSharpQualifiedNonReference element, @Nullable final PsiElement forceQualifierElement, boolean resolveFromParent) { CSharpResolveSelector selector = StaticResolveSelectors.NONE; switch(kind) { case NATIVE_TYPE_WRAPPER: case THIS: case BASE: case ROOT_NAMESPACE: break; case ARRAY_METHOD: selector = StaticResolveSelectors.INDEX_METHOD_GROUP; break; case CONSTRUCTOR: case BASE_CONSTRUCTOR: case THIS_CONSTRUCTOR: selector = StaticResolveSelectors.CONSTRUCTOR_GROUP; break; case TYPE_LIKE: if(element instanceof CSharpReferenceExpression && ((CSharpReferenceExpression) element).isGlobalElement()) { kind = ResolveToKind.ROOT_NAMESPACE; break; } default: case ATTRIBUTE: String referenceName = element.getReferenceName(); if(referenceName == null) { return ResolveResult.EMPTY_ARRAY; } if(kind == ResolveToKind.ATTRIBUTE) { String referenceNameWithAt = element.getReferenceNameWithAt(); assert referenceNameWithAt != null; selector = new AttributeByNameSelector(referenceNameWithAt); kind = ResolveToKind.TYPE_LIKE; //remap to type search } else { selector = new MemberByNameSelector(referenceName); } break; } CommonProcessors.CollectProcessor<ResolveResult> processor = new CommonProcessors.CollectProcessor<ResolveResult>(); collectResults(new CSharpResolveOptions(kind, selector, element, callArgumentListOwner, false, resolveFromParent), DotNetGenericExtractor.EMPTY, forceQualifierElement, processor); return processor.toArray(ResolveResult.ARRAY_FACTORY); } @RequiredReadAction public static void collectResults(@NotNull CSharpResolveOptions options, @NotNull Processor<ResolveResult> processor) { collectResults(options, DotNetGenericExtractor.EMPTY, null, processor); } @RequiredReadAction public static void collectResults(@NotNull CSharpResolveOptions options, @NotNull DotNetGenericExtractor defaultExtractor, @Nullable PsiElement forceQualifierElement, @NotNull final Processor<ResolveResult> processor) { final ResolveToKind kind = options.getKind(); KindProcessor kindProcessor = ourProcessors[kind.ordinal()]; kindProcessor.process(options, defaultExtractor, forceQualifierElement, processor); } @NotNull @RequiredReadAction public static ResolveResult[] tryResolveFromQualifier(@NotNull CSharpReferenceExpressionEx referenceExpressionEx, @NotNull PsiElement qualifierElement) { ResolveToKind kind = referenceExpressionEx.kind(); return buildSelectorAndMultiResolve(kind, findCallArgumentListOwner(kind, referenceExpressionEx), referenceExpressionEx, qualifierElement, false); } @RequiredReadAction public static void processAnyMember(@NotNull CSharpResolveOptions options, @NotNull DotNetGenericExtractor defaultExtractor, @Nullable PsiElement forceQualifierElement, @NotNull Processor<ResolveResult> processor) { PsiElement qualifier = options.getQualifier(); @NotNull PsiElement element = options.getElement(); ResolveToKind kind = options.getKind(); CSharpCallArgumentListOwner callArgumentListOwner = options.getCallArgumentListOwner(); CSharpResolveSelector selector = options.getSelector(); boolean completion = options.isCompletion(); PsiElement scopeElement = element; CSharpCodeFragment codeFragment = PsiTreeUtil.getParentOfType(element, CSharpCodeFragment.class); if(codeFragment != null) { scopeElement = codeFragment.getScopeElement(); if(scopeElement == null) { scopeElement = element; } } if(isConstructorKind(kind)) { CSharpReferenceExpressionEx referenceExpression = (CSharpReferenceExpressionEx) element; DotNetTypeRef typeRef = DotNetTypeRef.ERROR_TYPE; PsiElement referenceElement = referenceExpression.getReferenceElement(); if(referenceElement == null) { return; } switch(kind) { case THIS_CONSTRUCTOR: typeRef = referenceExpression.toTypeRefWithoutCaching(ResolveToKind.THIS, true); break; case BASE_CONSTRUCTOR: typeRef = referenceExpression.toTypeRefWithoutCaching(ResolveToKind.BASE, true); break; default: if(callArgumentListOwner instanceof CSharpNewExpression) { typeRef = ((CSharpNewExpression) callArgumentListOwner).toTypeRef(true); } else if(callArgumentListOwner instanceof DotNetAttribute) { typeRef = ((DotNetAttribute) callArgumentListOwner).toTypeRef(); } break; } DotNetTypeResolveResult typeResolveResult = typeRef.resolve(); PsiElement resolveElement = typeResolveResult.getElement(); if(resolveElement == null) { return; } ResolveState resolveState = ResolveState.initial(); resolveState = resolveState.put(CSharpResolveUtil.EXTRACTOR, typeResolveResult.getGenericExtractor()); if(selector != null) { resolveState = resolveState.put(CSharpResolveUtil.SELECTOR, selector); } StubScopeProcessor memberProcessor = createMemberProcessor(options, processor); CSharpResolveUtil.walkChildren(memberProcessor, resolveElement, true, false, resolveState); return; } PsiElement target = ObjectUtil.notNull(forceQualifierElement, element); DotNetGenericExtractor extractor = defaultExtractor; DotNetTypeRef qualifierTypeRef = DotNetTypeRef.ERROR_TYPE; if(forceQualifierElement == null && qualifier instanceof DotNetExpression) { qualifierTypeRef = ((DotNetExpression) qualifier).toTypeRef(false); if(element instanceof CSharpReferenceExpression) { CSharpReferenceExpression.AccessType memberAccessType = ((CSharpReferenceExpression) element).getMemberAccessType(); switch(memberAccessType) { case ARROW: if(qualifierTypeRef instanceof DotNetPointerTypeRef) { qualifierTypeRef = ((DotNetPointerTypeRef) qualifierTypeRef).getInnerTypeRef(); } break; } } DotNetTypeResolveResult typeResolveResult = qualifierTypeRef.resolve(); PsiElement resolve = typeResolveResult.getElement(); if(resolve != null) { target = resolve; extractor = typeResolveResult.getGenericExtractor(); } else { return; } } else if(forceQualifierElement != null) { qualifierTypeRef = toTypeRef(forceQualifierElement); } if(!target.isValid()) { return; } ResolveState resolveState = ResolveState.initial(); resolveState = resolveState.put(CSharpResolveUtil.EXTRACTOR, extractor); if(selector != null) { resolveState = resolveState.put(CSharpResolveUtil.SELECTOR, selector); } if(target != element) { StubScopeProcessor memberProcessor = createMemberProcessor(options, processor); if(!CSharpResolveUtil.walkChildren(memberProcessor, target, false, true, resolveState)) { consumeSorted(memberProcessor); return; } if((kind == ResolveToKind.METHOD || kind == ResolveToKind.ANY_MEMBER) && element instanceof CSharpReferenceExpression) { // walk for extensions ExtensionResolveScopeProcessor extensionProcessor = new ExtensionResolveScopeProcessor(qualifierTypeRef, (CSharpReferenceExpression) element, completion, memberProcessor, callArgumentListOwner); resolveState = resolveState.put(CSharpResolveUtil.EXTRACTOR, extractor); resolveState = resolveState.put(CSharpResolveUtil.SELECTOR, new ExtensionMethodByNameSelector(((CSharpReferenceExpression) element).getReferenceName())); Couple<PsiElement> resolveLayers = getResolveLayers(scopeElement, scopeElement != element); //PsiElement last = resolveLayers.getFirst(); PsiElement targetToWalkChildren = resolveLayers.getSecond(); if(!CSharpResolveUtil.walkChildren(extensionProcessor, targetToWalkChildren, true, false, resolveState)) { consumeSorted(memberProcessor); return; } CSharpResolveUtil.walkUsing(extensionProcessor, targetToWalkChildren, null, resolveState); extensionProcessor.consumeAsMethodGroup(); } consumeSorted(memberProcessor); } else { Couple<PsiElement> resolveLayers = getResolveLayers(scopeElement, scopeElement != element); PsiElement last = resolveLayers.getFirst(); PsiElement targetToWalkChildren = resolveLayers.getSecond(); StubScopeProcessor memberProcessor = createMemberProcessor(options, processor); // if resolving is any member, first we need process locals and then go to fields and other if(kind == ResolveToKind.ANY_MEMBER || kind == ResolveToKind.METHOD || kind == ResolveToKind.NAMEOF) { SimpleNamedScopeProcessor localProcessor = new SimpleNamedScopeProcessor(memberProcessor, completion, ExecuteTarget.LOCAL_VARIABLE_OR_PARAMETER); CSharpResolveUtil.treeWalkUp(localProcessor, target, element, last, resolveState); } if(!CSharpResolveUtil.walkChildren(memberProcessor, targetToWalkChildren, true, true, resolveState)) { consumeSorted(memberProcessor); return; } if(!CSharpResolveUtil.walkGenericParameterList(memberProcessor, processor, element, null, resolveState)) { consumeSorted(memberProcessor); return; } CSharpResolveUtil.walkUsing(memberProcessor, element, null, resolveState); consumeSorted(memberProcessor); } } private static void consumeSorted(StubScopeProcessor memberProcessor) { if(memberProcessor instanceof SortedMemberResolveScopeProcessor) { ((SortedMemberResolveScopeProcessor) memberProcessor).consumeAll(); } } @SuppressWarnings("unchecked") public static <T extends PsiElement> T findParentOrNextIfDoc(PsiElement element, Class<T> clazz) { CSharpGenericConstraintList constraintList = PsiTreeUtil.getParentOfType(element, CSharpGenericConstraintList.class); if(constraintList != null) { PsiElement parent = constraintList.getParent(); if(parent != null && clazz.isInstance(parent)) { return (T) parent; } return null; } CSharpDocRoot docRoot = PsiTreeUtil.getParentOfType(element, CSharpDocRoot.class); if(docRoot != null) { PsiElement docRootParent = docRoot.getParent(); if(docRootParent != null && clazz.isInstance(docRootParent)) { return (T) docRootParent; } } return null; } @NotNull @RequiredReadAction public static StubScopeProcessor createMemberProcessor(@NotNull CSharpResolveOptions options, @NotNull Processor<ResolveResult> resultProcessor) { ResolveToKind kind = options.getKind(); PsiElement element = options.getElement(); boolean completion = options.isCompletion(); ExecuteTarget[] targets; Comparator<ResolveResult> sorter = null; switch(kind) { case TYPE_LIKE: targets = new ExecuteTarget[]{ ExecuteTarget.GENERIC_PARAMETER, ExecuteTarget.TYPE, ExecuteTarget.DELEGATE_METHOD, ExecuteTarget.NAMESPACE, ExecuteTarget.TYPE_DEF }; sorter = TypeLikeComparator.create(element); break; case QUALIFIED_NAMESPACE: targets = new ExecuteTarget[]{ExecuteTarget.NAMESPACE}; break; case FIELD_OR_PROPERTY: targets = new ExecuteTarget[]{ ExecuteTarget.FIELD, ExecuteTarget.PROPERTY, ExecuteTarget.EVENT }; break; case ARRAY_METHOD: targets = new ExecuteTarget[]{ExecuteTarget.ELEMENT_GROUP}; break; case METHOD: targets = new ExecuteTarget[]{ ExecuteTarget.ELEMENT_GROUP, ExecuteTarget.FIELD, ExecuteTarget.PROPERTY, ExecuteTarget.EVENT, ExecuteTarget.LOCAL_VARIABLE_OR_PARAMETER }; break; case CONSTRUCTOR: case THIS_CONSTRUCTOR: case BASE_CONSTRUCTOR: targets = new ExecuteTarget[]{ ExecuteTarget.ELEMENT_GROUP }; break; case NAMEOF: targets = ExecuteTarget.values(); break; default: targets = new ExecuteTarget[]{ ExecuteTarget.MEMBER, ExecuteTarget.TYPE_DEF, ExecuteTarget.ELEMENT_GROUP }; sorter = StaticVsInstanceComparator.create(element); if(completion) { // append generic when completion due at ANY_MEMBER it dont resolved targets = ArrayUtil.append(targets, ExecuteTarget.GENERIC_PARAMETER); } break; } if(options.isCompletion()) { return new CompletionResolveScopeProcessor(options, resultProcessor, targets); } else { if(sorter != null) { return new SortedMemberResolveScopeProcessor(options, resultProcessor, sorter, targets); } else { return new MemberResolveScopeProcessor(options, resultProcessor, targets); } } } /** * @return couple of psieelement, first is the last element for walk, second is the stub member for walk */ @NotNull public static Couple<PsiElement> getResolveLayers(final PsiElement element, boolean strict) { PsiElement last = null; PsiElement targetToWalkChildren = null; PsiElement temp = strict ? element : element.getParent(); loop: while(temp != null) { ProgressIndicatorProvider.checkCanceled(); if(temp instanceof DotNetType) { DotNetStatement statement = PsiTreeUtil.getParentOfType(temp, DotNetStatement.class); if(statement == null) { PsiElement listOwner = PsiTreeUtil.getParentOfType(temp, DotNetModifierListOwner.class); if(listOwner != null) { Couple<PsiElement> resolveLayers = getResolveLayers(listOwner, true); last = resolveLayers.getFirst(); targetToWalkChildren = resolveLayers.getSecond(); break; } } } else if(temp instanceof DotNetParameter) { targetToWalkChildren = PsiTreeUtil.getParentOfType(temp, DotNetParameterListOwner.class); assert targetToWalkChildren != null; last = targetToWalkChildren.getParent(); } else if(temp instanceof CSharpAttribute) { last = temp; targetToWalkChildren = PsiTreeUtil.getParentOfType(temp, DotNetTypeDeclaration.class); if(targetToWalkChildren == null) { targetToWalkChildren = PsiTreeUtil.getParentOfType(temp, DotNetModifierListOwner.class); } break; } else if(temp instanceof DotNetFieldDeclaration || temp instanceof DotNetPropertyDeclaration || temp instanceof DotNetEventDeclaration || temp instanceof DotNetLikeMethodDeclaration) { last = temp.getParent(); targetToWalkChildren = temp.getParent(); break; } else if(temp instanceof DotNetXXXAccessor) { last = temp; targetToWalkChildren = temp.getParent().getParent(); break; } else if(temp instanceof DotNetTypeDeclaration) { last = temp; targetToWalkChildren = temp.getParent(); break; } else if(temp instanceof CSharpForInjectionFragmentHolder) { Place shreds = InjectedLanguageUtil.getShreds(temp.getContainingFile()); if(shreds != null) { for(PsiLanguageInjectionHost.Shred shred : shreds) { temp = shred.getHost(); continue loop; } } } else if(temp instanceof CSharpCodeFragment) { temp = ((CSharpCodeFragment) temp).getScopeElement(); continue; } temp = temp.getParent(); } if(targetToWalkChildren == null) { targetToWalkChildren = element.getContainingFile(); } return Couple.of(last, targetToWalkChildren); } @RequiredReadAction public static boolean isSoft(@NotNull CSharpReferenceExpression referenceExpression) { ResolveToKind kind = referenceExpression.kind(); switch(kind) { case SOFT_QUALIFIED_NAMESPACE: return true; case METHOD: case ARRAY_METHOD: case ANY_MEMBER: DotNetExpression qualifier = referenceExpression.getQualifier(); if(qualifier == null) { return false; } DotNetTypeRef typeRef = qualifier.toTypeRef(false); return typeRef instanceof CSharpDynamicTypeRef; } return false; } @NotNull @RequiredReadAction public static DotNetTypeRef toTypeRef(@Nullable PsiElement resolve) { return toTypeRef(resolve, DotNetGenericExtractor.EMPTY); } @NotNull @RequiredReadAction public static DotNetTypeRef toTypeRef(@NotNull ResolveResult resolveResult) { PsiElement element = resolveResult.getElement(); DotNetGenericExtractor extractor = DotNetGenericExtractor.EMPTY; if(resolveResult instanceof CSharpResolveResultWithExtractor) { extractor = ((CSharpResolveResultWithExtractor) resolveResult).getExtractor(); } return toTypeRef(element, extractor); } @NotNull @RequiredReadAction public static DotNetTypeRef toTypeRef(@Nullable PsiElement resolvedElement, @NotNull DotNetGenericExtractor extractor) { if(resolvedElement instanceof DotNetNamespaceAsElement) { return new CSharpTypeRefFromNamespace((DotNetNamespaceAsElement) resolvedElement); } else if(resolvedElement instanceof DotNetTypeDeclaration) { return new CSharpTypeRefByTypeDeclaration((DotNetTypeDeclaration) resolvedElement, extractor); } else if(resolvedElement instanceof CSharpTypeDefStatement) { return ((CSharpTypeDefStatement) resolvedElement).toTypeRef(); } else if(resolvedElement instanceof DotNetGenericParameter) { return new CSharpTypeRefFromGenericParameter((DotNetGenericParameter) resolvedElement); } else if(resolvedElement instanceof CSharpMethodDeclaration) { return new CSharpLambdaTypeRef((CSharpMethodDeclaration) resolvedElement); } else if(resolvedElement instanceof DotNetVariable) { return ((DotNetVariable) resolvedElement).toTypeRef(true); } else if(resolvedElement instanceof CSharpElementGroup) { return new CSharpElementGroupTypeRef((CSharpElementGroup<?>) resolvedElement); } return DotNetTypeRef.ERROR_TYPE; } }