/*
* 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 java.util.HashMap;
import java.util.Map;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.openapi.util.NullableLazyValue;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import consulo.annotations.RequiredReadAction;
import consulo.csharp.lang.psi.CSharpElementVisitor;
import consulo.csharp.lang.psi.CSharpGenericConstraint;
import consulo.csharp.lang.psi.CSharpGenericConstraintList;
import consulo.csharp.lang.psi.CSharpMethodDeclaration;
import consulo.csharp.lang.psi.CSharpModifier;
import consulo.csharp.lang.psi.CSharpTokens;
import consulo.csharp.lang.psi.impl.msil.typeParsing.SomeType;
import consulo.csharp.lang.psi.impl.msil.typeParsing.SomeTypeParser;
import consulo.csharp.lang.psi.impl.source.resolve.util.CSharpMethodImplUtil;
import consulo.dotnet.psi.DotNetType;
import consulo.dotnet.resolve.DotNetTypeRef;
import consulo.internal.dotnet.msil.decompiler.util.MsilHelper;
import consulo.msil.lang.psi.MsilClassEntry;
import consulo.msil.lang.psi.MsilMethodEntry;
/**
* @author VISTALL
* @since 23.05.14
*/
public class MsilMethodAsCSharpMethodDeclaration extends MsilMethodAsCSharpLikeMethodDeclaration implements CSharpMethodDeclaration
{
private static Map<String, Pair<String, IElementType>> ourOperatorNames = new HashMap<String, Pair<String, IElementType>>()
{
{
put("op_Addition", Pair.create("+", CSharpTokens.PLUS));
put("op_UnaryPlus", Pair.create("+", CSharpTokens.PLUS));
put("op_Subtraction", Pair.create("-", CSharpTokens.MINUS));
put("op_UnaryNegation", Pair.create("-", CSharpTokens.MINUS));
put("op_Multiply", Pair.create("*", CSharpTokens.MUL));
put("op_Division", Pair.create("/", CSharpTokens.DIV));
put("op_Modulus", Pair.create("%", CSharpTokens.PERC));
put("op_BitwiseAnd", Pair.create("&", CSharpTokens.AND));
put("op_BitwiseOr", Pair.create("|", CSharpTokens.OR));
put("op_ExclusiveOr", Pair.create("^", CSharpTokens.XOR));
put("op_LeftShift", Pair.create("<<", CSharpTokens.LTLT));
put("op_RightShift", Pair.create(">>", CSharpTokens.GTGT));
put("op_Equality", Pair.create("==", CSharpTokens.EQEQ));
put("op_Inequality", Pair.create("!=", CSharpTokens.NTEQ));
put("op_LessThan", Pair.create("<", CSharpTokens.LT));
put("op_LessThanOrEqual", Pair.create("<=", CSharpTokens.LTEQ));
put("op_GreaterThan", Pair.create(">", CSharpTokens.GT));
put("op_GreaterThanOrEqual", Pair.create(">=", CSharpTokens.GTEQ));
put("op_OnesComplement", Pair.create("~", CSharpTokens.TILDE));
put("op_LogicalNot", Pair.create("!", CSharpTokens.EXCL));
put("op_Increment", Pair.create("++", CSharpTokens.PLUSPLUS));
put("op_Decrement", Pair.create("--", CSharpTokens.MINUSMINUS));
}
};
private final NullableLazyValue<String> myNameValue = new NullableLazyValue<String>()
{
@Nullable
@Override
protected String compute()
{
Pair<String, IElementType> pair = ourOperatorNames.get(myOriginal.getName());
if(pair != null)
{
return pair.getFirst();
}
return myDelegate == null ? MsilMethodAsCSharpMethodDeclaration.super.getName() : MsilHelper.cutGenericMarker(myDelegate.getName());
}
};
private final NullableLazyValue<DotNetType> myTypeForImplementValue;
private final MsilClassEntry myDelegate;
@RequiredReadAction
public MsilMethodAsCSharpMethodDeclaration(PsiElement parent, @Nullable MsilClassEntry declaration, @NotNull GenericParameterContext genericParameterContext, @NotNull MsilMethodEntry methodEntry)
{
super(parent, CSharpModifier.EMPTY_ARRAY, methodEntry);
myDelegate = declaration;
setGenericParameterList(declaration != null ? declaration : methodEntry, genericParameterContext);
myTypeForImplementValue = NullableLazyValue.of(() ->
{
String nameFromBytecode = myOriginal.getNameFromBytecode();
String typeBeforeDot = StringUtil.getPackageName(nameFromBytecode);
SomeType someType = SomeTypeParser.parseType(typeBeforeDot, nameFromBytecode);
if(someType != null)
{
return new DummyType(getProject(), MsilMethodAsCSharpMethodDeclaration.this, someType);
}
return null;
});
}
@Override
public void accept(@NotNull CSharpElementVisitor visitor)
{
visitor.visitMethodDeclaration(this);
}
@RequiredReadAction
@Override
public String getName()
{
return myNameValue.getValue();
}
@RequiredReadAction
@Nullable
@Override
public String getPresentableParentQName()
{
return myDelegate == null ? super.getPresentableParentQName() : myDelegate.getPresentableParentQName();
}
@RequiredReadAction
@Nullable
@Override
public String getPresentableQName()
{
return myDelegate == null ? MsilHelper.append(getPresentableParentQName(), getName()) : MsilHelper.cutGenericMarker(myDelegate.getPresentableQName());
}
@Nullable
@Override
public CSharpGenericConstraintList getGenericConstraintList()
{
return myGenericConstraintListValue.getValue();
}
@NotNull
@Override
public CSharpGenericConstraint[] getGenericConstraints()
{
CSharpGenericConstraintList genericConstraintList = getGenericConstraintList();
return genericConstraintList == null ? CSharpGenericConstraint.EMPTY_ARRAY : genericConstraintList.getGenericConstraints();
}
@Override
public boolean isDelegate()
{
return myDelegate != null;
}
@Override
public boolean isOperator()
{
return ourOperatorNames.containsKey(myOriginal.getName());
}
@Override
public boolean isExtension()
{
return CSharpMethodImplUtil.isExtensionMethod(this);
}
@RequiredReadAction
@Nullable
@Override
public IElementType getOperatorElementType()
{
Pair<String, IElementType> pair = ourOperatorNames.get(myOriginal.getName());
if(pair == null)
{
return null;
}
return pair.getSecond();
}
@RequiredReadAction
@Nullable
@Override
public PsiElement getNameIdentifier()
{
return null;
}
@Nullable
@Override
public DotNetType getTypeForImplement()
{
return myTypeForImplementValue.getValue();
}
@NotNull
@Override
@RequiredReadAction
public DotNetTypeRef getTypeRefForImplement()
{
DotNetType typeForImplement = getTypeForImplement();
return typeForImplement != null ? typeForImplement.toTypeRef() : DotNetTypeRef.ERROR_TYPE;
}
@Nullable
@Override
protected Class<? extends PsiElement> getNavigationElementClass()
{
return CSharpMethodDeclaration.class;
}
@Nullable
public MsilClassEntry getDelegate()
{
return myDelegate;
}
}