Browse Source

Fix #890: Correctly handle calls with out-parameters in definite assignment analysis.

pull/1087/head
Daniel Grunwald 8 years ago
parent
commit
a86a0586bb
  1. 43
      ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs

43
ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs

@ -184,16 +184,45 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
protected internal override void VisitLdLoca(LdLoca inst) protected internal override void VisitLdLoca(LdLoca inst)
{ {
// A variable needs to be initialized before we can take it by reference. // A variable needs to be initialized before we can take it by reference.
// The exception is if the variable is passed to an out parameter. // The exception is if the variable is passed to an out parameter (handled in VisitCall).
if (!IsOutArgument(inst)) { EnsureInitialized(inst.Variable);
EnsureInitialized(inst.Variable);
}
} }
static bool IsOutArgument(ILInstruction inst) protected internal override void VisitCall(Call inst)
{ {
return inst.Parent is CallInstruction call HandleCall(inst);
&& call.GetParameter(inst.ChildIndex)?.IsOut == true; }
protected internal override void VisitCallVirt(CallVirt inst)
{
HandleCall(inst);
}
protected internal override void VisitNewObj(NewObj inst)
{
HandleCall(inst);
}
void HandleCall(CallInstruction call)
{
bool hasOutArgs = false;
foreach (var arg in call.Arguments) {
if (arg.MatchLdLoca(out var v) && call.GetParameter(arg.ChildIndex)?.IsOut == true) {
// Visiting ldloca would require the variable to be initialized,
// but we don't need out arguments to be initialized.
hasOutArgs = true;
} else {
arg.AcceptVisitor(this);
}
}
// Mark out arguments as initialized, but only after the whole call:
if (hasOutArgs) {
foreach (var arg in call.Arguments) {
if (arg.MatchLdLoca(out var v) && call.GetParameter(arg.ChildIndex)?.IsOut == true) {
HandleStore(v);
}
}
}
} }
} }
} }

Loading…
Cancel
Save