diff --git a/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/Animal.cs b/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/Animal.cs index 434482e7..7de01ba9 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/Animal.cs +++ b/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/Animal.cs @@ -4,5 +4,8 @@ public abstract class Animal : LivingBeeing { [Computed] public abstract bool IsPet { get; } + + [Computed] + public abstract string SpeciesAndAge(); } } diff --git a/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/Dog.cs b/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/Dog.cs index 569e9c5f..9178b37f 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/Dog.cs +++ b/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/Dog.cs @@ -10,5 +10,8 @@ public class Dog : Animal { public override string Species => "Canis lupus"; public override bool IsPet => true; + + [Computed] + public override string SpeciesAndAge() => string.Concat(Species, " : ", Age); } } diff --git a/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/HoneyBee.cs b/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/HoneyBee.cs index cfd1988d..75146e4f 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/HoneyBee.cs +++ b/src/DelegateDecompiler.EntityFramework.Tests/EfItems/Abstracts/HoneyBee.cs @@ -5,5 +5,8 @@ public class HoneyBee : Animal public override string Species => "Apis mellifera"; public override bool IsPet => false; + + [Computed] + public override string SpeciesAndAge() => string.Concat(Species, " : ", Age); } } diff --git a/src/DelegateDecompiler.EntityFramework.Tests/TestGroup05BasicFeatures/Test01Select.cs b/src/DelegateDecompiler.EntityFramework.Tests/TestGroup05BasicFeatures/Test01Select.cs index 46ee384b..1f30f56a 100644 --- a/src/DelegateDecompiler.EntityFramework.Tests/TestGroup05BasicFeatures/Test01Select.cs +++ b/src/DelegateDecompiler.EntityFramework.Tests/TestGroup05BasicFeatures/Test01Select.cs @@ -235,6 +235,28 @@ public void TestSelectMultipleLevelsOfAbstractMembersOverTphHierarchy() } } + + [Test] + public void TestSelectAbstractMethodImplementedInDerivedCallingBasePropertyFromBaseType() + { + using (var env = new MethodEnvironment(classEnv)) + { + //SETUP + var linq = env.Db.LivingBeeing.OfType().ToList().Select(p => p.SpeciesAndAge()).ToList(); + + //ATTEMPT + env.AboutToUseDelegateDecompiler(); + var dd = env.Db.LivingBeeing.OfType().Select(p => p.SpeciesAndAge()) +#if NO_AUTO_DECOMPILE + .Decompile() +#endif + .ToList(); + + //VERIFY + env.CompareAndLogList(linq, dd); + } + } + [Test] public void TestSelectSelectMany() { diff --git a/src/DelegateDecompiler/Processors/CallProcessor.cs b/src/DelegateDecompiler/Processors/CallProcessor.cs index c092dd63..917476d9 100644 --- a/src/DelegateDecompiler/Processors/CallProcessor.cs +++ b/src/DelegateDecompiler/Processors/CallProcessor.cs @@ -50,6 +50,8 @@ static void Call(ProcessorState state, MethodInfo m) static Expression BuildMethodCallExpression(MethodInfo m, Address instance, Expression[] arguments, Address[] addresses) { + var callInstance = AlignInstanceToDeclaringType(instance, m); + if (m.Name == "Add" && instance.Expression != null && typeof(IEnumerable).IsAssignableFrom(instance.Type)) { switch (instance.Expression) @@ -75,13 +77,13 @@ static Expression BuildMethodCallExpression(MethodInfo m, Address instance, Expr { if (m.Name.StartsWith("get_") && arguments.Length == 0) { - return Expression.Property(instance, m); + return Expression.Property(callInstance, m); } if (m.Name.StartsWith("set_") && arguments.Length == 1) { var value = arguments.Single(); - var property = Expression.Property(instance, m).Member; + var property = Expression.Property(callInstance, m).Member; var expression = Processor.BuildAssignment(instance.Expression, property, value, out bool push); if (push) { @@ -165,11 +167,28 @@ static Expression BuildMethodCallExpression(MethodInfo m, Address instance, Expr } if (instance.Expression != null) - return Expression.Call(instance, m, arguments); + return Expression.Call(callInstance, m, arguments); return Expression.Call(null, m, arguments); } + static Address AlignInstanceToDeclaringType(Address instance, MethodInfo method) + { + if (instance.Expression == null || method.DeclaringType == null) + { + return instance; + } + + if (instance.Expression is UnaryExpression cast && + cast.NodeType == ExpressionType.Convert && + method.DeclaringType.IsAssignableFrom(cast.Operand.Type)) + { + return cast.Operand; + } + + return instance; + } + static bool TryParseOperator(MethodInfo m, out ExpressionType type) { switch (m.Name)