Exemple #1
0
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     AddAll(node.InnerLocals);
     base.VisitSwitchStatement(node);
     RemoveAll(node.InnerLocals);
     return(null);
 }
Exemple #2
0
        /// <summary>
        /// Is the switch statement one that could be interpreted as a C# 6 or earlier switch statement?
        /// </summary>
        private bool IsTraditionalSwitch(BoundSwitchStatement node)
        {
            // Before recursive patterns were introduced, we did not consider handling both 'true' and 'false' to
            // completely handle all case of a switch on a bool unless there was some patterny syntax or semantics
            // in the switch.  We had two different bound nodes and separate flow analysis handling for
            // "traditional" switch statements and "pattern-based" switch statements.  We simulate that behavior
            // by testing to see if this switch would have been handled under the old rules by the old compiler.

            // If we are in a recent enough language version, we treat the switch as a fully pattern-based switch
            // for the purposes of flow analysis.
            if (((CSharpParseOptions)node.Syntax.SyntaxTree.Options).LanguageVersion >= MessageID.IDS_FeatureRecursivePatterns.RequiredVersion())
            {
                return(false);
            }

            if (!node.Expression.Type.IsValidV6SwitchGoverningType())
            {
                return(false);
            }

            foreach (var sectionSyntax in ((SwitchStatementSyntax)node.Syntax).Sections)
            {
                foreach (var label in sectionSyntax.Labels)
                {
                    if (label.Kind() == SyntaxKind.CasePatternSwitchLabel)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
            public static BoundStatement Rewrite(LocalRewriter localRewriter, BoundSwitchStatement node)
            {
                var            rewriter = new SwitchLocalRewriter(node, localRewriter);
                BoundStatement result   = rewriter.LowerSwitchStatement(node);

                rewriter.Free();
                return(result);
            }
Exemple #4
0
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            // visit switch header
            VisitRvalue(node.Expression);

            // visit switch block
            VisitSwitchBlock(node);

            return(null);
        }
Exemple #5
0
        public override BoundStatement InstrumentSwitchStatement(BoundSwitchStatement original, BoundStatement rewritten)
        {
            SwitchStatementSyntax switchSyntax = (SwitchStatementSyntax)original.Syntax;
            TextSpan switchSequencePointSpan   = TextSpan.FromBounds(
                switchSyntax.SwitchKeyword.SpanStart,
                (switchSyntax.CloseParenToken != default) ? switchSyntax.CloseParenToken.Span.End : switchSyntax.Expression.Span.End);

            return(new BoundSequencePointWithSpan(
                       syntax: switchSyntax,
                       statementOpt: base.InstrumentSwitchStatement(original, rewritten),
                       span: switchSequencePointSpan,
                       hasErrors: false));
        }
Exemple #6
0
        private void VisitSwitchBlock(BoundSwitchStatement node)
        {
            var initialState    = State.Clone();
            var reachableLabels = node.DecisionDag.ReachableLabels;

            foreach (var section in node.SwitchSections)
            {
                foreach (var label in section.SwitchLabels)
                {
                    if (reachableLabels.Contains(label.Label) || label.HasErrors)
                    {
                        SetState(initialState.Clone());
                    }
                    else
                    {
                        SetUnreachable();
                    }

                    VisitPattern(label.Pattern);
                    SetState(StateWhenTrue);
                    if (label.WhenClause != null)
                    {
                        VisitCondition(label.WhenClause);
                        SetState(StateWhenTrue);
                    }

                    PendingBranches.Add(new PendingBranch(label, this.State, label.Label));
                }
            }

            // visit switch sections
            var afterSwitchState = UnreachableState();
            var switchSections   = node.SwitchSections;
            var iLastSection     = (switchSections.Length - 1);

            for (var iSection = 0; iSection <= iLastSection; iSection++)
            {
                VisitSwitchSection(switchSections[iSection], iSection == iLastSection);
                // Even though it is illegal for the end of a switch section to be reachable, in erroneous
                // code it may be reachable.  We treat that as an implicit break (branch to afterSwitchState).
                Join(ref afterSwitchState, ref this.State);
            }

            if (reachableLabels.Contains(node.BreakLabel) || node.DefaultLabel == null && IsTraditionalSwitch(node))
            {
                Join(ref afterSwitchState, ref initialState);
            }

            ResolveBreaks(afterSwitchState, node.BreakLabel);
        }
            private BoundStatement LowerSwitchStatement(BoundSwitchStatement node)
            {
                _factory.Syntax = node.Syntax;
                var result = ArrayBuilder <BoundStatement> .GetInstance();

                var outerVariables = ArrayBuilder <LocalSymbol> .GetInstance();

                var loweredSwitchGoverningExpression = _localRewriter.VisitExpression(node.Expression);

                if (!node.WasCompilerGenerated && _localRewriter.Instrument)
                {
                    // EnC: We need to insert a hidden sequence point to handle function remapping in case
                    // the containing method is edited while methods invoked in the expression are being executed.
                    var instrumentedExpression = _localRewriter._instrumenter.InstrumentSwitchStatementExpression(node, loweredSwitchGoverningExpression, _factory);
                    if (loweredSwitchGoverningExpression.ConstantValue == null)
                    {
                        loweredSwitchGoverningExpression = instrumentedExpression;
                    }
                    else
                    {
                        // If the expression is a constant, we leave it alone (the decision dag lowering code needs
                        // to see that constant). But we add an additional leading statement with the instrumented expression.
                        result.Add(_factory.ExpressionStatement(instrumentedExpression));
                    }
                }

                // The set of variables attached to the outer block
                outerVariables.AddRange(node.InnerLocals);

                // Evaluate the input and set up sharing for dag temps with user variables
                BoundDecisionDag decisionDag = ShareTempsIfPossibleAndEvaluateInput(node.DecisionDag, loweredSwitchGoverningExpression, result, out _);

                // lower the decision dag.
                (ImmutableArray <BoundStatement> loweredDag, ImmutableDictionary <SyntaxNode, ImmutableArray <BoundStatement> > switchSections) =
                    LowerDecisionDag(decisionDag);

                // then add the rest of the lowered dag that references that input
                result.Add(_factory.Block(loweredDag));

                // A branch to the default label when no switch case matches is included in the
                // decision dag, so the code in `result` is unreachable at this point.

                // Lower each switch section.
                foreach (BoundSwitchSection section in node.SwitchSections)
                {
                    _factory.Syntax = section.Syntax;
                    var sectionBuilder = ArrayBuilder <BoundStatement> .GetInstance();

                    sectionBuilder.AddRange(switchSections[section.Syntax]);
                    foreach (BoundSwitchLabel switchLabel in section.SwitchLabels)
                    {
                        sectionBuilder.Add(_factory.Label(switchLabel.Label));
                    }

                    // Add the translated body of the switch section
                    sectionBuilder.AddRange(_localRewriter.VisitList(section.Statements));

                    // By the semantics of the switch statement, the end of each section is required to be unreachable.
                    // So we can just seal the block and there is no need to follow it by anything.
                    ImmutableArray <BoundStatement> statements = sectionBuilder.ToImmutableAndFree();

                    if (section.Locals.IsEmpty)
                    {
                        result.Add(_factory.StatementList(statements));
                    }
                    else
                    {
                        // Lifetime of these locals is expanded to the entire switch body, as it is possible to capture
                        // them in a different section by using a local function as an intermediary.
                        outerVariables.AddRange(section.Locals);

                        // Note the language scope of the locals, even though they are included for the purposes of
                        // lifetime analysis in the enclosing scope.
                        result.Add(new BoundScope(section.Syntax, section.Locals, statements));
                    }
                }

                // Dispatch temps are in scope throughout the switch statement, as they are used
                // both in the dispatch section to hold temporary values from the translation of
                // the decision dag, and in the branches where the temp values are assigned to the
                // pattern variables of matched patterns.
                outerVariables.AddRange(_tempAllocator.AllTemps());

                _factory.Syntax = node.Syntax;
                result.Add(_factory.Label(node.BreakLabel));
                BoundStatement translatedSwitch = _factory.Block(outerVariables.ToImmutableAndFree(), node.InnerLocalFunctions, result.ToImmutableAndFree());

                // Only add instrumentation (such as a sequence point) if the node is not compiler-generated.
                if (!node.WasCompilerGenerated && _localRewriter.Instrument)
                {
                    translatedSwitch = _localRewriter._instrumenter.InstrumentSwitchStatement(node, translatedSwitch);
                }

                return(translatedSwitch);
            }
 private SwitchLocalRewriter(BoundSwitchStatement node, LocalRewriter localRewriter)
     : base(node.Syntax, localRewriter, node.SwitchSections.SelectAsArray(section => section.Syntax), isSwitchStatement: true)
 {
 }
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     return(SwitchLocalRewriter.Rewrite(this, node));
 }
Exemple #10
0
 public virtual BoundStatement InstrumentSwitchStatement(BoundSwitchStatement original, BoundStatement rewritten)
 {
     Debug.Assert(original.Syntax.Kind() == SyntaxKind.SwitchStatement);
     return(InstrumentStatement(original, rewritten));
 }
 public override BoundStatement InstrumentSwitchStatement(BoundSwitchStatement original, BoundStatement rewritten)
 {
     return(AddDynamicAnalysis(original, base.InstrumentSwitchStatement(original, rewritten)));
 }
Exemple #12
0
 public override BoundStatement InstrumentSwitchStatement(BoundSwitchStatement original, BoundStatement rewritten)
 {
     return(Previous.InstrumentSwitchStatement(original, rewritten));
 }