private void PatchSourceContextProperty(ZMethod zMethod, Class methodClass, List<BasicBlock> basicBlocks)
{
Property contextProperty = (Property)Templates.GetMemberByName(methodClass.Members, "Context");
Method contextMethod = contextProperty.Getter;
Debug.Assert(contextMethod.Body.Statements[0] is System.Compiler.Switch);
System.Compiler.Switch switchStmt = (System.Compiler.Switch)contextMethod.Body.Statements[0];
foreach (BasicBlock block in basicBlocks)
{
SourceContext ctxt = new SourceContext(null, 0, 0);
//ctxt.Document = null;
//ctxt.StartPos = 0;
//ctxt.EndPos = 0;
if (block.SourceContext.StartPos != 0 || block.SourceContext.EndPos != 0)
{
// If the block says something explicit about its context, take that
// as final.
ctxt = block.SourceContext;
}
else
{
// The block doesn't say anything, so figure it out from the statements
// inside the block.
BasicBlock effectiveBlock = block;
//
// If we only fall through to another BB without any executable code,
// conditional branching, interleaving, or return - then consider our
// source context to be the next "real" thing that happens.
//
while ((effectiveBlock.Statement == null || effectiveBlock.SkipNormalizer) &&
effectiveBlock.ConditionalExpression == null &&
effectiveBlock.SourceContext.SourceText == null &&
effectiveBlock.MiddleOfTransition &&
!effectiveBlock.IsReturn && !effectiveBlock.PropagatesException)
{
effectiveBlock = effectiveBlock.UnconditionalTarget;
}
// See which source context is the most appropriate for this block.
if (effectiveBlock.Statement != null)
{
if (effectiveBlock.Statement.SourceContext.SourceText != null)
ctxt = effectiveBlock.Statement.SourceContext;
else
{
Block b = effectiveBlock.Statement as Block;
if (b != null)
{
for (int i = 0, n = b.Statements.Count; i < n; i++)
{
if (b.Statements[i] != null)
{
ctxt = b.Statements[i].SourceContext;
break;
}
}
}
}
}
else if (effectiveBlock.ConditionalExpression != null)
ctxt = effectiveBlock.ConditionalExpression.SourceContext;
else if (effectiveBlock.SourceContext.SourceText != null)
ctxt = effectiveBlock.SourceContext;
else
{
// For "return" blocks, show the closing brace as the source context.
ctxt.Document = zMethod.SourceContext.Document;
ctxt.EndPos = zMethod.SourceContext.EndPos;
ctxt.StartPos = ctxt.EndPos - 1;
}
}
if (ctxt.StartPos < 0)
ctxt.StartPos = 0;
SwitchCase newCase = new SwitchCase(
new QualifiedIdentifier(Identifier.For("Blocks"), Identifier.For(block.Name)),
new Block(new StatementList(
new Return(SourceContextConstructor(ctxt))))
);
switchStmt.Cases.Add(newCase);
}
}