|
|
|
@ -184,16 +184,45 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
@@ -184,16 +184,45 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
|
|
|
|
|
protected internal override void VisitLdLoca(LdLoca inst) |
|
|
|
|
{ |
|
|
|
|
// 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.
|
|
|
|
|
if (!IsOutArgument(inst)) { |
|
|
|
|
EnsureInitialized(inst.Variable); |
|
|
|
|
} |
|
|
|
|
// The exception is if the variable is passed to an out parameter (handled in VisitCall).
|
|
|
|
|
EnsureInitialized(inst.Variable); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool IsOutArgument(ILInstruction inst) |
|
|
|
|
protected internal override void VisitCall(Call inst) |
|
|
|
|
{ |
|
|
|
|
return inst.Parent is CallInstruction call |
|
|
|
|
&& call.GetParameter(inst.ChildIndex)?.IsOut == true; |
|
|
|
|
HandleCall(inst); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|