// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Operations
{
public partial class ControlFlowGraph
{
///
/// Defines kinds of regions that can be present in a
///
public enum RegionKind
{
///
/// A root region encapsulating all s in a
///
Root,
///
/// Region with the only purpose to represent the life-time of locals.
/// PROTOTYPE(dataflow): We should clearly explain what "life-time" refers to here, or use a different term.
///
Locals,
///
/// Region representing a try region. For example,
///
Try,
///
/// Region representing
///
Filter,
///
/// Region representing
///
Catch,
///
/// Region representing a union of a and the corresponding catch regions.
/// Doesn't contain any s directly.
///
FilterAndHandler,
///
/// Region representing a union of a and all corresponding catch
/// and regions. Doesn't contain any s directly.
///
TryAndCatch,
///
/// Region representing
///
Finally,
///
/// Region representing a union of a and corresponding finally
/// region. Doesn't contain any s directly.
///
/// An that has a set of and a
/// at the same time is mapped to a region with region inside its region.
///
TryAndFinally,
///
/// Region representing the initialization for a VB Static
local variable. This region will only be executed
/// the first time a function is called.
///
StaticLocalInitializer,
}
///
/// Encapsulates information about regions of s in a .
/// Regions can overlap, but never cross each other boundaries.
///
public sealed class Region
{
///
/// Region's kind
///
public RegionKind Kind { get; }
///
/// Enclosing region. Null for
///
public Region Enclosing { get; private set; }
///
/// Target exception type for , ,
///
///
public ITypeSymbol ExceptionType { get; }
///
/// Ordinal () of the first within the region.
///
public int FirstBlockOrdinal { get; }
///
/// Ordinal () of the last within the region.
///
public int LastBlockOrdinal { get; }
///
/// Regions within this region
///
public ImmutableArray Regions { get; }
///
/// Locals for which this region represent the life-time.
///
public ImmutableArray Locals { get; }
internal Region(RegionKind kind, int firstBlockOrdinal, int lastBlockOrdinal,
ImmutableArray regions = default, ImmutableArray locals = default,
ITypeSymbol exceptionType = null)
{
Debug.Assert(firstBlockOrdinal >= 0);
Debug.Assert(lastBlockOrdinal >= firstBlockOrdinal);
Kind = kind;
FirstBlockOrdinal = firstBlockOrdinal;
LastBlockOrdinal = lastBlockOrdinal;
ExceptionType = exceptionType;
Locals = locals.NullToEmpty();
Regions = regions.NullToEmpty();
foreach(Region r in Regions)
{
Debug.Assert(r.Enclosing == null && r.Kind != RegionKind.Root);
r.Enclosing = this;
}
#if DEBUG
int previousLast;
switch (kind)
{
case RegionKind.TryAndFinally:
case RegionKind.FilterAndHandler:
Debug.Assert(Regions.Length == 2);
Debug.Assert(Regions[0].Kind == (kind == RegionKind.TryAndFinally ? RegionKind.Try : RegionKind.Filter));
Debug.Assert(Regions[1].Kind == (kind == RegionKind.TryAndFinally ? RegionKind.Finally : RegionKind.Catch));
Debug.Assert(Regions[0].FirstBlockOrdinal == firstBlockOrdinal);
Debug.Assert(Regions[1].LastBlockOrdinal == lastBlockOrdinal);
Debug.Assert(Regions[0].LastBlockOrdinal + 1 == Regions[1].FirstBlockOrdinal);
break;
case RegionKind.TryAndCatch:
Debug.Assert(Regions.Length >= 2);
Debug.Assert(Regions[0].Kind == RegionKind.Try);
Debug.Assert(Regions[0].FirstBlockOrdinal == firstBlockOrdinal);
previousLast = Regions[0].LastBlockOrdinal;
for (int i = 1; i < Regions.Length; i++)
{
Region r = Regions[i];
Debug.Assert(previousLast + 1 == r.FirstBlockOrdinal);
previousLast = r.LastBlockOrdinal;
Debug.Assert(r.Kind == RegionKind.FilterAndHandler || r.Kind == RegionKind.Catch);
}
Debug.Assert(previousLast == lastBlockOrdinal);
break;
case RegionKind.Root:
case RegionKind.Locals:
case RegionKind.Try:
case RegionKind.Filter:
case RegionKind.Catch:
case RegionKind.Finally:
case RegionKind.StaticLocalInitializer:
previousLast = firstBlockOrdinal - 1;
foreach (Region r in Regions)
{
Debug.Assert(previousLast < r.FirstBlockOrdinal);
previousLast = r.LastBlockOrdinal;
}
Debug.Assert(previousLast <= lastBlockOrdinal);
break;
default:
throw ExceptionUtilities.UnexpectedValue(kind);
}
#endif
}
internal bool ContainsBlock(int destinationOrdinal)
{
return FirstBlockOrdinal <= destinationOrdinal && LastBlockOrdinal >= destinationOrdinal;
}
}
}
}