/*
* 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;
import org.jetbrains.annotations.NotNull;
import consulo.annotations.RequiredReadAction;
import consulo.csharp.lang.psi.impl.source.CSharpPsiUtilImpl;
import consulo.csharp.lang.psi.impl.source.resolve.util.CSharpMethodImplUtil;
import consulo.dotnet.psi.DotNetGenericParameter;
import consulo.dotnet.psi.DotNetModifier;
import consulo.dotnet.psi.DotNetModifierListOwner;
import consulo.dotnet.psi.DotNetParameter;
import consulo.dotnet.psi.DotNetQualifiedElement;
import consulo.dotnet.resolve.DotNetNamespaceAsElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
/**
* @author VISTALL
* @since 31.12.14
*/
public class CSharpContextUtil
{
public enum ContextType
{
ANY,
STATIC,
// without qualifier we can access to static members
INSTANCE_WITH_STATIC,
INSTANCE;
public final boolean isAllowInstance()
{
return this == INSTANCE || this == INSTANCE_WITH_STATIC;
}
public final boolean isAllowStatic()
{
return this == ANY || this == STATIC || this == INSTANCE_WITH_STATIC;
}
}
@NotNull
@RequiredReadAction
public static CSharpContextUtil.ContextType getContextForResolved(@NotNull PsiElement element)
{
if(!(element instanceof DotNetModifierListOwner))
{
return ContextType.ANY;
}
if(CSharpPsiUtilImpl.isTypeLikeElement(element))
{
return ContextType.STATIC;
}
if(element instanceof CSharpConstructorDeclaration)
{
return CSharpContextUtil.ContextType.ANY;
}
if(element instanceof DotNetGenericParameter)
{
return ContextType.ANY;
}
if(CSharpMethodImplUtil.isExtensionWrapper(element))
{
return CSharpContextUtil.ContextType.INSTANCE;
}
if(((DotNetModifierListOwner) element).hasModifier(DotNetModifier.STATIC))
{
return CSharpContextUtil.ContextType.STATIC;
}
return CSharpContextUtil.ContextType.INSTANCE;
}
@NotNull
@RequiredReadAction
public static ContextType getParentContextTypeForReference(@NotNull CSharpReferenceExpression referenceExpression)
{
PsiElement qualifier = referenceExpression.getQualifier();
if(qualifier == null)
{
// object initializer can only initialize instance variables
PsiElement parent = referenceExpression.getParent();
if(parent instanceof CSharpFieldOrPropertySet && ((CSharpFieldOrPropertySet) parent).getNameElement() == referenceExpression)
{
return ContextType.INSTANCE;
}
PsiElement resolvedElement = referenceExpression.resolve();
if(resolvedElement instanceof CSharpTypeDeclaration ||
resolvedElement instanceof DotNetNamespaceAsElement ||
resolvedElement instanceof CSharpLocalVariable ||
resolvedElement instanceof CSharpLinqVariable ||
resolvedElement instanceof DotNetParameter ||
resolvedElement instanceof CSharpLambdaParameter ||
resolvedElement instanceof CSharpConstructorDeclaration)
{
return ContextType.ANY;
}
DotNetModifierListOwner qualifiedElement = (DotNetModifierListOwner) PsiTreeUtil.getParentOfType(referenceExpression, DotNetQualifiedElement.class);
if(qualifiedElement == null)
{
return ContextType.ANY;
}
if(qualifiedElement.hasModifier(DotNetModifier.STATIC) || CSharpPsiUtilImpl.isTypeLikeElement(qualifiedElement))
{
return ContextType.STATIC;
}
// if member is static we can use it inside instance elements
if(resolvedElement instanceof DotNetModifierListOwner && ((DotNetModifierListOwner) resolvedElement).hasModifier(DotNetModifier.STATIC))
{
return ContextType.ANY;
}
return ContextType.INSTANCE_WITH_STATIC;
}
else if(qualifier instanceof CSharpReferenceExpression)
{
CSharpReferenceExpression.ResolveToKind kind = ((CSharpReferenceExpression) qualifier).kind();
// this.<caret> and base.<caret> accept only instance elements
if(kind == CSharpReferenceExpression.ResolveToKind.BASE || kind == CSharpReferenceExpression.ResolveToKind.THIS)
{
return ContextType.INSTANCE;
}
PsiElement qualifiedResolvedElement = ((CSharpReferenceExpression) qualifier).resolve();
// Console.<caret>
if(isLikeType(qualifiedResolvedElement))
{
return ContextType.STATIC;
}
return ContextType.INSTANCE;
}
return ContextType.ANY;
}
private static boolean isLikeType(PsiElement element)
{
return CSharpPsiUtilImpl.isTypeLikeElement(element)||
element instanceof DotNetNamespaceAsElement ||
element instanceof CSharpTypeDefStatement;
}
}