/*
* 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 java.util.LinkedHashMap;
import java.util.Map;
import org.jetbrains.annotations.NotNull;
import consulo.annotations.RequiredReadAction;
import consulo.csharp.lang.psi.CSharpEnumConstantDeclaration;
import consulo.csharp.lang.psi.CSharpFieldDeclaration;
import consulo.csharp.lang.psi.CSharpFileFactory;
import consulo.csharp.lang.psi.CSharpModifier;
import consulo.csharp.lang.psi.CSharpModifierList;
import consulo.csharp.lang.psi.CSharpSoftTokens;
import consulo.csharp.lang.psi.CSharpTokens;
import consulo.csharp.lang.psi.CSharpTypeDeclaration;
import consulo.dotnet.psi.DotNetModifier;
import consulo.dotnet.psi.DotNetModifierListOwner;
import consulo.dotnet.psi.DotNetTypeDeclaration;
import consulo.dotnet.psi.DotNetVirtualImplementOwner;
import consulo.dotnet.psi.DotNetXXXAccessor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiParserFacade;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.tree.IElementType;
/**
* @author VISTALL
* @since 05.12.14
*/
public class CSharpModifierListImplUtil
{
public static final Map<CSharpModifier, IElementType> ourModifiers = new LinkedHashMap<CSharpModifier, IElementType>()
{
{
put(CSharpModifier.PUBLIC, CSharpTokens.PUBLIC_KEYWORD);
put(CSharpModifier.PROTECTED, CSharpTokens.PROTECTED_KEYWORD);
put(CSharpModifier.PRIVATE, CSharpTokens.PRIVATE_KEYWORD);
put(CSharpModifier.STATIC, CSharpTokens.STATIC_KEYWORD);
put(CSharpModifier.SEALED, CSharpTokens.SEALED_KEYWORD);
put(CSharpModifier.ABSTRACT, CSharpTokens.ABSTRACT_KEYWORD);
put(CSharpModifier.READONLY, CSharpTokens.READONLY_KEYWORD);
put(CSharpModifier.UNSAFE, CSharpTokens.UNSAFE_KEYWORD);
put(CSharpModifier.PARAMS, CSharpTokens.PARAMS_KEYWORD);
put(CSharpModifier.THIS, CSharpTokens.THIS_KEYWORD);
put(CSharpModifier.PARTIAL, CSharpSoftTokens.PARTIAL_KEYWORD);
put(CSharpModifier.INTERNAL, CSharpTokens.INTERNAL_KEYWORD);
put(CSharpModifier.REF, CSharpTokens.REF_KEYWORD);
put(CSharpModifier.OUT, CSharpTokens.OUT_KEYWORD);
put(CSharpModifier.VIRTUAL, CSharpTokens.VIRTUAL_KEYWORD);
put(CSharpModifier.NEW, CSharpTokens.NEW_KEYWORD);
put(CSharpModifier.OVERRIDE, CSharpTokens.OVERRIDE_KEYWORD);
put(CSharpModifier.ASYNC, CSharpSoftTokens.ASYNC_KEYWORD);
put(CSharpModifier.IN, CSharpSoftTokens.IN_KEYWORD);
put(CSharpModifier.EXTERN, CSharpSoftTokens.EXTERN_KEYWORD);
}
};
@RequiredReadAction
public static boolean hasModifier(@NotNull CSharpModifierList modifierList, @NotNull DotNetModifier modifier)
{
if(modifierList.hasModifierInTree(modifier))
{
return true;
}
CSharpModifier cSharpModifier = CSharpModifier.as(modifier);
PsiElement parent = modifierList.getParent();
switch(cSharpModifier)
{
case PUBLIC:
if(parent instanceof CSharpEnumConstantDeclaration)
{
return true;
}
if(parent instanceof DotNetVirtualImplementOwner && parent.getParent() instanceof CSharpTypeDeclaration && ((CSharpTypeDeclaration) parent.getParent()).isInterface())
{
return true;
}
break;
case READONLY:
if(parent instanceof CSharpEnumConstantDeclaration)
{
return true;
}
break;
case STATIC:
if(parent instanceof CSharpFieldDeclaration)
{
if(((CSharpFieldDeclaration) parent).isConstant() && parent.getParent() instanceof CSharpTypeDeclaration)
{
return true;
}
}
if(parent instanceof CSharpEnumConstantDeclaration)
{
return true;
}
if(parent instanceof DotNetXXXAccessor)
{
PsiElement superParent = parent.getParent();
return superParent instanceof DotNetModifierListOwner && ((DotNetModifierListOwner) superParent).hasModifier(DotNetModifier.STATIC);
}
break;
case INTERFACE_ABSTRACT:
if(parent instanceof DotNetVirtualImplementOwner && parent.getParent() instanceof CSharpTypeDeclaration && ((CSharpTypeDeclaration) parent.getParent()).isInterface())
{
return true;
}
if(parent instanceof DotNetXXXAccessor)
{
if(((DotNetXXXAccessor) parent).getCodeBlock() == null)
{
PsiElement accessorOwner = parent.getParent();
if(accessorOwner instanceof DotNetModifierListOwner && ((DotNetModifierListOwner) accessorOwner).hasModifier(modifier))
{
return true;
}
}
}
break;
case ABSTRACT:
if(parent instanceof DotNetTypeDeclaration && ((DotNetTypeDeclaration) parent).isInterface())
{
return true;
}
if(hasModifier(modifierList, CSharpModifier.INTERFACE_ABSTRACT))
{
return true;
}
if(parent instanceof DotNetXXXAccessor)
{
PsiElement superParent = parent.getParent();
return superParent instanceof DotNetModifierListOwner && ((DotNetModifierListOwner) superParent).hasModifier(DotNetModifier.ABSTRACT);
}
break;
case SEALED:
if(parent instanceof DotNetTypeDeclaration && (((DotNetTypeDeclaration) parent).isEnum() || ((DotNetTypeDeclaration) parent).isStruct()))
{
return true;
}
break;
}
return false;
}
@RequiredReadAction
public static void addModifier(@NotNull CSharpModifierList modifierList, @NotNull DotNetModifier modifier)
{
PsiElement anchor = modifierList.getLastChild();
CSharpFieldDeclaration field = CSharpFileFactory.createField(modifierList.getProject(), modifier.getPresentableText() + " int b");
PsiElement modifierElement = field.getModifierList().getModifierElement(modifier);
PsiElement psiElement = modifierList.addAfter(modifierElement, anchor);
modifierList.addAfter(PsiParserFacade.SERVICE.getInstance(modifierList.getProject()).createWhiteSpaceFromText(" "), psiElement);
}
public static void removeModifier(@NotNull CSharpModifierList modifierList, @NotNull DotNetModifier modifier)
{
CSharpModifier as = CSharpModifier.as(modifier);
PsiElement modifierElement = modifierList.getModifierElement(as);
if(modifierElement != null)
{
PsiElement next = modifierElement.getNextSibling();
if(next instanceof PsiWhiteSpace)
{
next.delete();
}
modifierElement.delete();
}
}
}