@ -65,10 +65,10 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -65,10 +65,10 @@ namespace ICSharpCode.Decompiler.CSharp
/// * Otherwise, the C# type of the resulting expression shall match the IL stack type,
/// and the evaluated values shall be the same.
/// </remarks>
class ExpressionBuilder : ILVisitor < TranslationContext , TranslatedExpression >
sealed class ExpressionBuilder : ILVisitor < TranslationContext , TranslatedExpression >
{
readonly IDecompilerTypeSystem typeSystem ;
readonly ITypeResolveContext decompilationContext ;
internal readonly ITypeResolveContext decompilationContext ;
internal readonly ILFunction currentFunction ;
internal readonly ICompilation compilation ;
internal readonly CSharpResolver resolver ;
@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.CSharp
expr . WithRR ( new ILVariableResolveResult ( variable , elementType ) ) ;
expr = new DirectionExpression ( FieldDirection . Ref , expr ) ;
return expr . WithRR ( new ByReferenceResolveResult ( elementType , isOut : false ) ) ;
return expr . WithRR ( new ByReferenceResolveResult ( elementType , ReferenceKind . Ref ) ) ;
} else {
return expr . WithRR ( new ILVariableResolveResult ( variable , variable . Type ) ) ;
}
@ -189,7 +189,35 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -189,7 +189,35 @@ namespace ICSharpCode.Decompiler.CSharp
internal bool HidesVariableWithName ( string name )
{
return currentFunction . Ancestors . OfType < ILFunction > ( ) . SelectMany ( f = > f . Variables ) . Any ( v = > v . Name = = name ) ;
return currentFunction . Ancestors . OfType < ILFunction > ( ) . Any ( HidesVariableOrNestedFunction ) ;
bool HidesVariableOrNestedFunction ( ILFunction function )
{
foreach ( var v in function . Variables ) {
if ( v . Name = = name )
return true ;
}
foreach ( var f in function . LocalFunctions . OfType < ILFunction > ( ) ) {
if ( f . Name = = name )
return true ;
}
return false ;
}
}
internal ILFunction ResolveLocalFunction ( IMethod method )
{
Debug . Assert ( method . IsLocalFunction ) ;
method = method . ReducedFrom ;
foreach ( var parent in currentFunction . Ancestors . OfType < ILFunction > ( ) ) {
var definition = parent . LocalFunctions . FirstOrDefault ( f = > f . Method = = method ) ;
if ( definition ! = null ) {
return definition ;
}
}
return null ;
}
bool RequiresQualifier ( IMember member , TranslatedExpression target )
@ -220,19 +248,20 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -220,19 +248,20 @@ namespace ICSharpCode.Decompiler.CSharp
bool targetCasted = false ;
var targetResolveResult = requireTarget ? target . ResolveResult : null ;
bool IsUnambiguousAccess ( )
bool IsUnambiguousAccess ( out MemberResolveResult result )
{
if ( targetResolveResult = = null ) {
var result = resolver . ResolveSimpleName ( field . Name , EmptyList < IType > . Instance , isInvocationTarget : false ) as MemberResolveResult ;
result = resolver . ResolveSimpleName ( field . Name , EmptyList < IType > . Instance , isInvocationTarget : false ) as MemberResolveResult ;
return ! ( result = = null | | result . IsError | | ! result . Member . Equals ( field , NormalizeTypeVisitor . TypeErasure ) ) ;
} else {
var lookup = new MemberLookup ( resolver . CurrentTypeDefinition , resolver . CurrentTypeDefinition . ParentModule ) ;
var result = lookup . Lookup ( target . ResolveResult , field . Name , EmptyList < IType > . Instance , false ) as MemberResolveResult ;
result = lookup . Lookup ( target . ResolveResult , field . Name , EmptyList < IType > . Instance , false ) as MemberResolveResult ;
return ! ( result = = null | | result . IsError | | ! result . Member . Equals ( field , NormalizeTypeVisitor . TypeErasure ) ) ;
}
}
while ( ! IsUnambiguousAccess ( ) ) {
MemberResolveResult mrr ;
while ( ! IsUnambiguousAccess ( out mrr ) ) {
if ( ! requireTarget ) {
requireTarget = true ;
targetResolveResult = target . ResolveResult ;
@ -244,13 +273,16 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -244,13 +273,16 @@ namespace ICSharpCode.Decompiler.CSharp
break ;
}
}
if ( mrr = = null ) {
mrr = new MemberResolveResult ( target . ResolveResult , field ) ;
}
if ( requireTarget ) {
return new MemberReferenceExpression ( target , field . Name )
. WithRR ( new Me mbe rResolveResult ( ta rget . ResolveResult , field ) ) ;
. WithRR ( mrr ) ;
} else {
return new IdentifierExpression ( field . Name )
. WithRR ( new Me mbe rResolveResult ( ta rget . ResolveResult , field ) ) ;
. WithRR ( mrr ) ;
}
}
@ -511,7 +543,9 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -511,7 +543,9 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLdTypeToken ( LdTypeToken inst , TranslationContext context )
{
return new MemberReferenceExpression ( new TypeOfExpression ( ConvertType ( inst . Type ) ) , "TypeHandle" )
var typeofExpr = new TypeOfExpression ( ConvertType ( inst . Type ) )
. WithRR ( new TypeOfResolveResult ( compilation . FindType ( KnownTypeCode . Type ) , inst . Type ) ) ;
return new MemberReferenceExpression ( typeofExpr , "TypeHandle" )
. WithILInstruction ( inst )
. WithRR ( new TypeOfResolveResult ( compilation . FindType ( new TopLevelTypeName ( "System" , "RuntimeTypeHandle" ) ) , inst . Type ) ) ;
}
@ -576,7 +610,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -576,7 +610,7 @@ namespace ICSharpCode.Decompiler.CSharp
// because the DirectionExpression might get removed by dereferencing instructions such as LdObj
return new DirectionExpression ( FieldDirection . Ref , expr . Expression )
. WithoutILInstruction ( )
. WithRR ( new ByReferenceResolveResult ( expr . ResolveResult , isOut : false ) ) ;
. WithRR ( new ByReferenceResolveResult ( expr . ResolveResult , ReferenceKind . Ref ) ) ;
}
protected internal override TranslatedExpression VisitStLoc ( StLoc inst , TranslationContext context )
@ -585,7 +619,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -585,7 +619,7 @@ namespace ICSharpCode.Decompiler.CSharp
if ( inst . Variable . Kind = = VariableKind . StackSlot & & ! loadedVariablesSet . Contains ( inst . Variable ) ) {
// Stack slots in the ILAst have inaccurate types (e.g. System.Object for StackType.O)
// so we should replace them with more accurate types where possible:
if ( ( inst . Variable . IsSingleDefinition | | IsOtherValueType ( translatedValue . Type ) | | inst . Variable . StackType = = StackType . Ref )
if ( CanUseTypeForStackSlot ( inst . Variable , translatedValue . Type )
& & inst . Variable . StackType = = translatedValue . Type . GetStackType ( )
& & translatedValue . Type . Kind ! = TypeKind . Null ) {
inst . Variable . Type = translatedValue . Type ;
@ -605,10 +639,31 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -605,10 +639,31 @@ namespace ICSharpCode.Decompiler.CSharp
return Assignment ( lhs , translatedValue ) . WithILInstruction ( inst ) ;
}
bool CanUseTypeForStackSlot ( ILVariable v , IType type )
{
return v . IsSingleDefinition
| | IsOtherValueType ( type )
| | v . StackType = = StackType . Ref
| | AllStoresUseConsistentType ( v . StoreInstructions , type ) ;
}
bool IsOtherValueType ( IType type )
{
return type . IsReferenceType = = false & & type . GetStackType ( ) = = StackType . O ;
}
bool AllStoresUseConsistentType ( IReadOnlyList < IStoreInstruction > storeInstructions , IType expectedType )
{
expectedType = expectedType . AcceptVisitor ( NormalizeTypeVisitor . TypeErasure ) ;
foreach ( var store in storeInstructions ) {
if ( ! ( store is StLoc stloc ) )
return false ;
IType type = stloc . Value . InferType ( compilation ) . AcceptVisitor ( NormalizeTypeVisitor . TypeErasure ) ;
if ( ! type . Equals ( expectedType ) )
return false ;
}
return true ;
}
}
protected internal override TranslatedExpression VisitComp ( Comp inst , TranslationContext context )
@ -1042,7 +1097,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1042,7 +1097,7 @@ namespace ICSharpCode.Decompiler.CSharp
. WithILInstruction ( inst )
. WithRR ( new ResolveResult ( elementType ) ) ;
return new DirectionExpression ( FieldDirection . Ref , expr )
. WithoutILInstruction ( ) . WithRR ( new ByReferenceResolveResult ( expr . Type , isOut : false ) ) ;
. WithoutILInstruction ( ) . WithRR ( new ByReferenceResolveResult ( expr . Type , ReferenceKind . Ref ) ) ;
}
return CallUnsafeIntrinsic ( name , new [ ] { left . Expression , Translate ( offsetInst ) . Expression } , brt , inst ) ;
} else {
@ -1333,7 +1388,13 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1333,7 +1388,13 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitUserDefinedCompoundAssign ( UserDefinedCompoundAssign inst , TranslationContext context )
{
var target = Translate ( inst . Target ) ;
IType loadType = inst . Method . Parameters [ 0 ] . Type ;
ExpressionWithResolveResult target ;
if ( inst . TargetKind = = CompoundTargetKind . Address ) {
target = LdObj ( inst . Target , loadType ) ;
} else {
target = Translate ( inst . Target , loadType ) ;
}
if ( UserDefinedCompoundAssign . IsStringConcat ( inst . Method ) ) {
Debug . Assert ( inst . Method . Parameters . Count = = 2 ) ;
var value = Translate ( inst . Value ) . ConvertTo ( inst . Method . Parameters [ 1 ] . Type , this , allowImplicitConversion : true ) ;
@ -1349,7 +1410,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1349,7 +1410,7 @@ namespace ICSharpCode.Decompiler.CSharp
. WithILInstruction ( inst )
. WithRR ( new OperatorResolveResult ( inst . Method . ReturnType , AssignmentExpression . GetLinqNodeType ( op . Value , false ) , inst . Method , inst . IsLifted , new [ ] { target . ResolveResult , value . ResolveResult } ) ) ;
} else {
UnaryOperatorType ? op = GetUnaryOperatorTypeFromMetadataName ( inst . Method . Name , inst . CompoundAssignmentType = = CompoundAssignmentTyp e. EvaluatesToOldValue ) ;
UnaryOperatorType ? op = GetUnaryOperatorTypeFromMetadataName ( inst . Method . Name , inst . EvalMode = = CompoundEvalMod e. EvaluatesToOldValue ) ;
Debug . Assert ( op ! = null ) ;
return new UnaryOperatorExpression ( op . Value , target )
@ -1428,10 +1489,15 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1428,10 +1489,15 @@ namespace ICSharpCode.Decompiler.CSharp
TranslatedExpression HandleCompoundAssignment ( NumericCompoundAssign inst , AssignmentOperatorType op )
{
var target = Translate ( inst . Target ) ;
ExpressionWithResolveResult target ;
if ( inst . TargetKind = = CompoundTargetKind . Address ) {
target = LdObj ( inst . Target , inst . Type ) ;
} else {
target = Translate ( inst . Target , inst . Type ) ;
}
TranslatedExpression resultExpr ;
if ( inst . CompoundAssignmentType = = CompoundAssignmentType . EvaluatesToOldValue ) {
if ( inst . EvalMode = = CompoundEvalMod e. EvaluatesToOldValue ) {
Debug . Assert ( op = = AssignmentOperatorType . Add | | op = = AssignmentOperatorType . Subtract ) ;
Debug . Assert ( inst . Value . MatchLdcI ( 1 ) ) ;
UnaryOperatorType unary ;
@ -1492,8 +1558,13 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1492,8 +1558,13 @@ namespace ICSharpCode.Decompiler.CSharp
TranslatedExpression HandleCompoundShift ( NumericCompoundAssign inst , AssignmentOperatorType op )
{
Debug . Assert ( inst . CompoundAssignmentType = = CompoundAssignmentType . EvaluatesToNewValue ) ;
var target = Translate ( inst . Target ) ;
Debug . Assert ( inst . EvalMode = = CompoundEvalMode . EvaluatesToNewValue ) ;
ExpressionWithResolveResult target ;
if ( inst . TargetKind = = CompoundTargetKind . Address ) {
target = LdObj ( inst . Target , inst . Type ) ;
} else {
target = Translate ( inst . Target , inst . Type ) ;
}
var value = Translate ( inst . Value ) ;
// Shift operators in C# always expect type 'int' on the right-hand-side
@ -1698,7 +1769,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1698,7 +1769,7 @@ namespace ICSharpCode.Decompiler.CSharp
if ( type . Kind = = TypeKind . ByReference ) {
return new DirectionExpression ( FieldDirection . Ref , expr . Expression )
. WithoutILInstruction ( )
. WithRR ( new ByReferenceResolveResult ( expr . ResolveResult , isOut : false ) ) ;
. WithRR ( new ByReferenceResolveResult ( expr . ResolveResult , ReferenceKind . Ref ) ) ;
}
return expr ;
}
@ -1830,22 +1901,28 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1830,22 +1901,28 @@ namespace ICSharpCode.Decompiler.CSharp
return SpecialType . UnknownType ;
}
IEnumerable < ParameterDeclaration > MakeParameters ( IReadOnlyList < IParameter > parameters , ILFunction function )
internal IEnumerable < ParameterDeclaration > MakeParameters ( IReadOnlyList < IParameter > parameters , ILFunction function )
{
var variables = function . Variables . Where ( v = > v . Kind = = VariableKind . Parameter ) . ToDictionary ( v = > v . Index ) ;
int i = 0 ;
foreach ( var parameter in parameters ) {
var pd = astBuilder . ConvertParameter ( parameter ) ;
if ( string . IsNullOrEmpty ( pd . Name ) & & ! pd . Type . IsArgList ( ) ) {
// needs to be consistent with logic in ILReader.CreateILVarable(ParameterDefinition)
pd . Name = "P_" + i ;
// if this is a local function, we have to skip the parameters for closure references
if ( settings . LocalFunctions & & function . Kind = = ILFunctionKind . LocalFunction & & IL . Transforms . LocalFunctionDecompiler . IsClosureParameter ( parameter , decompilationContext ) )
break ;
}
if ( settings . AnonymousTypes & & parameter . Type . ContainsAnonymousType ( ) )
pd . Type = null ;
ILVariable v ;
if ( variables . TryGetValue ( i , out v ) )
if ( variables . TryGetValue ( i , out var v ) )
pd . AddAnnotation ( new ILVariableResolveResult ( v , parameters [ i ] . Type ) ) ;
yield return pd ;
i + + ;
}
}
internal TranslatedExpression TranslateTarget ( ILInstruction target , bool nonVirtualInvocation ,
bool memberStatic , IType memberDeclaringType )
{
@ -1904,46 +1981,46 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -1904,46 +1981,46 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLdObj ( LdObj inst , TranslationContext context )
{
var target = Translate ( inst . Target ) ;
if ( TypeUtils . IsCompatiblePointerTypeForMemoryAccess ( target . Type , inst . Type ) ) {
TranslatedExpression result ;
var result = LdObj ( inst . Target , inst . Type ) ;
//if (target.Type.IsSmallIntegerType() && loadType.IsSmallIntegerType() && target.Type.GetSign() != loadType.GetSign())
// return result.ConvertTo(loadType, this);
return result . WithILInstruction ( inst ) ;
}
ExpressionWithResolveResult LdObj ( ILInstruction address , IType loadType )
{
var target = Translate ( address ) ;
if ( TypeUtils . IsCompatiblePointerTypeForMemoryAccess ( target . Type , loadType ) ) {
ExpressionWithResolveResult result ;
if ( target . Expression is DirectionExpression dirExpr ) {
// we can dereference the managed reference by stripping away the 'ref'
result = target . UnwrapChild ( dirExpr . Expression ) ;
result . Expression . AddAnnotation ( inst ) ; // add LdObj in addition to the existing ILInstruction annotation
} else if ( target . Type is PointerType pointerType ) {
if ( target . Expression is UnaryOperatorExpression uoe & & uoe . Operator = = UnaryOperatorType . AddressOf ) {
// We can dereference the pointer by stripping away the '&'
result = target . UnwrapChild ( uoe . Expression ) ;
result . Expression . AddAnnotation ( inst ) ; // add LdObj in addition to the existing ILInstruction annotation
} else {
// Dereference the existing pointer
result = new UnaryOperatorExpression ( UnaryOperatorType . Dereference , target . Expression )
. WithILInstruction ( inst )
. WithRR ( new ResolveResult ( pointerType . ElementType ) ) ;
}
} else {
// reference type behind non-DirectionExpression?
// this case should be impossible, but we can use a pointer cast
// just to make sure
target = target . ConvertTo ( new PointerType ( inst . Type ) , this ) ;
target = target . ConvertTo ( new PointerType ( load Type) , this ) ;
return new UnaryOperatorExpression ( UnaryOperatorType . Dereference , target . Expression )
. WithILInstruction ( inst )
. WithRR ( new ResolveResult ( inst . Type ) ) ;
. WithRR ( new ResolveResult ( loadType ) ) ;
}
// we don't convert result to inst.Type, because the LdObj type
// might be inaccurate (it's often System.Object for all reference types),
// and our parent node should already insert casts where necessary
if ( target . Type . IsSmallIntegerType ( ) & & inst . Type . IsSmallIntegerType ( ) & & target . Type . GetSign ( ) ! = inst . Type . GetSign ( ) )
return result . ConvertTo ( inst . Type , this ) ;
return result ;
} else {
// We need to cast the pointer type:
target = target . ConvertTo ( new PointerType ( inst . Type ) , this ) ;
target = target . ConvertTo ( new PointerType ( load Type) , this ) ;
return new UnaryOperatorExpression ( UnaryOperatorType . Dereference , target . Expression )
. WithILInstruction ( inst )
. WithRR ( new ResolveResult ( inst . Type ) ) ;
. WithRR ( new ResolveResult ( loadType ) ) ;
}
}
@ -2022,14 +2099,16 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2022,14 +2099,16 @@ namespace ICSharpCode.Decompiler.CSharp
nonVirtualInvocation : true ,
memberStatic : false ,
memberDeclaringType : underlyingTupleType ) ;
if ( translatedTarget . Type is TupleType tupleType & & tupleType . UnderlyingTyp e. Equals ( underlyingTupleType ) & & position < = tupleType . ElementNames . Length ) {
if ( translatedTarget . Type is TupleType tupleType & & NormalizeTypeVisitor . TypeErasur e. Equiv alentType s ( tupleType , underlyingTupleType ) & & position < = tupleType . ElementNames . Length ) {
string elementName = tupleType . ElementNames [ position - 1 ] ;
if ( elementName = = null ) {
elementName = "Item" + position ;
}
// tupleType.ElementTypes are more accurate w.r.t. nullability/dynamic than inst.Field.Type
var rr = new MemberResolveResult ( translatedTarget . ResolveResult , inst . Field ,
returnTypeOverride : tupleType . ElementTypes [ position - 1 ] ) ;
expr = new MemberReferenceExpression ( translatedTarget , elementName )
. WithRR ( new MemberResolveResult ( translatedTarget . ResolveResult , inst . Field ) )
. WithILInstruction ( inst ) ;
. WithRR ( rr ) . WithILInstruction ( inst ) ;
} else {
expr = ConvertField ( inst . Field , inst . Target ) . WithILInstruction ( inst ) ;
}
@ -2043,7 +2122,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2043,7 +2122,7 @@ namespace ICSharpCode.Decompiler.CSharp
} else {
// ldflda producing managed pointer
return new DirectionExpression ( FieldDirection . Ref , expr )
. WithoutILInstruction ( ) . WithRR ( new ByReferenceResolveResult ( expr . ResolveResult , isOut : false ) ) ;
. WithoutILInstruction ( ) . WithRR ( new ByReferenceResolveResult ( expr . ResolveResult , ReferenceKind . Ref ) ) ;
}
}
@ -2051,7 +2130,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2051,7 +2130,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
var expr = ConvertField ( inst . Field ) . WithILInstruction ( inst ) ;
return new DirectionExpression ( FieldDirection . Ref , expr )
. WithoutILInstruction ( ) . WithRR ( new ByReferenceResolveResult ( expr . Type , isOut : false ) ) ;
. WithoutILInstruction ( ) . WithRR ( new ByReferenceResolveResult ( expr . Type , ReferenceKind . Ref ) ) ;
}
protected internal override TranslatedExpression VisitLdElema ( LdElema inst , TranslationContext context )
@ -2066,7 +2145,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2066,7 +2145,7 @@ namespace ICSharpCode.Decompiler.CSharp
arrayExpr , inst . Indices . Select ( i = > TranslateArrayIndex ( i ) . Expression )
) . WithILInstruction ( inst ) . WithRR ( new ResolveResult ( arrayType . ElementType ) ) ;
return new DirectionExpression ( FieldDirection . Ref , expr )
. WithoutILInstruction ( ) . WithRR ( new ByReferenceResolveResult ( expr . Type , isOut : false ) ) ;
. WithoutILInstruction ( ) . WithRR ( new ByReferenceResolveResult ( expr . Type , ReferenceKind . Ref ) ) ;
}
TranslatedExpression TranslateArrayIndex ( ILInstruction i )
@ -2124,7 +2203,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2124,7 +2203,7 @@ namespace ICSharpCode.Decompiler.CSharp
. WithRR ( new ConversionResolveResult ( inst . Type , arg . ResolveResult , Conversion . UnboxingConversion ) ) ;
return new DirectionExpression ( FieldDirection . Ref , castExpression )
. WithILInstruction ( inst )
. WithRR ( new ByReferenceResolveResult ( castExpression . ResolveResult , isOut : false ) ) ;
. WithRR ( new ByReferenceResolveResult ( castExpression . ResolveResult , ReferenceKind . Ref ) ) ;
}
protected internal override TranslatedExpression VisitBox ( Box inst , TranslationContext context )
@ -2184,7 +2263,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2184,7 +2263,7 @@ namespace ICSharpCode.Decompiler.CSharp
Arguments = { Translate ( inst . Argument ) . Expression , new TypeReferenceExpression ( ConvertType ( inst . Type ) ) }
} . WithRR ( new ResolveResult ( inst . Type ) ) ;
return new DirectionExpression ( FieldDirection . Ref , expr . WithILInstruction ( inst ) ) . WithoutILInstruction ( )
. WithRR ( new ByReferenceResolveResult ( inst . Type , false ) ) ;
. WithRR ( new ByReferenceResolveResult ( inst . Type , ReferenceKind . Ref ) ) ;
}
protected internal override TranslatedExpression VisitBlock ( Block block , TranslationContext context )
@ -2197,8 +2276,6 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2197,8 +2276,6 @@ namespace ICSharpCode.Decompiler.CSharp
case BlockKind . CollectionInitializer :
case BlockKind . ObjectInitializer :
return TranslateObjectAndCollectionInitializer ( block ) ;
case BlockKind . PostfixOperator :
return TranslatePostfixOperator ( block ) ;
case BlockKind . CallInlineAssign :
return TranslateSetterCallAssignment ( block ) ;
case BlockKind . CallWithNamedArgs :
@ -2533,19 +2610,6 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2533,19 +2610,6 @@ namespace ICSharpCode.Decompiler.CSharp
. WithRR ( new ResolveResult ( stloc . Variable . Type ) ) ;
}
TranslatedExpression TranslatePostfixOperator ( Block block )
{
var targetInst = ( block . Instructions . ElementAtOrDefault ( 0 ) as StLoc ) ? . Value ;
var inst = ( block . Instructions . ElementAtOrDefault ( 1 ) as StLoc ) ? . Value as BinaryNumericInstruction ;
if ( targetInst = = null | | inst = = null | | ( inst . Operator ! = BinaryNumericOperator . Add & & inst . Operator ! = BinaryNumericOperator . Sub ) )
throw new ArgumentException ( "given Block is invalid!" ) ;
var op = inst . Operator = = BinaryNumericOperator . Add ? UnaryOperatorType . PostIncrement : UnaryOperatorType . PostDecrement ;
var target = Translate ( targetInst ) ;
return new UnaryOperatorExpression ( op , target )
. WithILInstruction ( block )
. WithRR ( resolver . WithCheckForOverflow ( inst . CheckForOverflow ) . ResolveUnaryOperator ( op , target . ResolveResult ) ) ;
}
/// <summary>
/// If expr is a constant integer expression, and its value fits into type,
/// convert the expression into the target type.
@ -2685,7 +2749,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2685,7 +2749,7 @@ namespace ICSharpCode.Decompiler.CSharp
new ConditionalExpression ( condition . Expression , trueBranch . Expression , falseBranch . Expression )
. WithILInstruction ( inst )
. WithRR ( conditionalResolveResult )
) . WithoutILInstruction ( ) . WithRR ( new ByReferenceResolveResult ( conditionalResolveResult , isOut : false ) ) ;
) . WithoutILInstruction ( ) . WithRR ( new ByReferenceResolveResult ( conditionalResolveResult , ReferenceKind . Ref ) ) ;
} else {
return new ConditionalExpression ( condition . Expression , trueBranch . Expression , falseBranch . Expression )
. WithILInstruction ( inst )
@ -2705,7 +2769,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2705,7 +2769,7 @@ namespace ICSharpCode.Decompiler.CSharp
var value = Translate ( inst . Value , targetTypeHint ) ;
return new DirectionExpression ( FieldDirection . Ref , value )
. WithILInstruction ( inst )
. WithRR ( new ByReferenceResolveResult ( value . ResolveResult , false ) ) ;
. WithRR ( new ByReferenceResolveResult ( value . ResolveResult , ReferenceKind . Ref ) ) ;
}
protected internal override TranslatedExpression VisitAwait ( Await inst , TranslationContext context )
@ -2860,7 +2924,7 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2860,7 +2924,7 @@ namespace ICSharpCode.Decompiler.CSharp
translatedExpression = translatedExpression . ConvertTo ( typeHint , this ) ;
}
if ( info . HasFlag ( CSharpArgumentInfoFlags . IsOut ) ) {
translatedExpression = ChangeDirectionExpressionToOut ( translatedExpression ) ;
translatedExpression = ChangeDirectionExpressionTo ( translatedExpression , ReferenceKind . Out ) ;
}
if ( info . HasFlag ( CSharpArgumentInfoFlags . NamedArgument ) & & ! string . IsNullOrWhiteSpace ( info . Name ) ) {
translatedExpression = new TranslatedExpression ( new NamedArgumentExpression ( info . Name , translatedExpression . Expression ) ) ;
@ -2869,16 +2933,16 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -2869,16 +2933,16 @@ namespace ICSharpCode.Decompiler.CSharp
return translatedExpression ;
}
internal static TranslatedExpression ChangeDirectionExpressionToOut ( TranslatedExpression input )
internal static TranslatedExpression ChangeDirectionExpressionTo ( TranslatedExpression input , ReferenceKind kind )
{
if ( ! ( input . Expression is DirectionExpression dirExpr & & input . ResolveResult is ByReferenceResolveResult brrr ) )
return input ;
dirExpr . FieldDirection = FieldDirection . Out ;
dirExpr . FieldDirection = ( FieldDirection ) kind ;
dirExpr . RemoveAnnotations < ByReferenceResolveResult > ( ) ;
if ( brrr . ElementResult = = null )
brrr = new ByReferenceResolveResult ( brrr . ElementType , isOut : true ) ;
brrr = new ByReferenceResolveResult ( brrr . ElementType , kind ) ;
else
brrr = new ByReferenceResolveResult ( brrr . ElementResult , isOut : true ) ;
brrr = new ByReferenceResolveResult ( brrr . ElementResult , kind ) ;
dirExpr . AddAnnotation ( brrr ) ;
return new TranslatedExpression ( dirExpr ) ;
}
@ -3044,7 +3108,12 @@ namespace ICSharpCode.Decompiler.CSharp
@@ -3044,7 +3108,12 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitDynamicCompoundAssign ( DynamicCompoundAssign inst , TranslationContext context )
{
var target = TranslateDynamicArgument ( inst . Target , inst . TargetArgumentInfo ) ;
ExpressionWithResolveResult target ;
if ( inst . TargetKind = = CompoundTargetKind . Address ) {
target = LdObj ( inst . Target , SpecialType . Dynamic ) ;
} else {
target = TranslateDynamicArgument ( inst . Target , inst . TargetArgumentInfo ) ;
}
var value = TranslateDynamicArgument ( inst . Value , inst . ValueArgumentInfo ) ;
var ae = new AssignmentExpression ( target , AssignmentExpression . GetAssignmentOperatorTypeFromExpressionType ( inst . Operation ) . Value , value ) ;