public override BoundNode VisitSwitchStatement(BoundSwitchStatement node) { AddAll(node.InnerLocals); base.VisitSwitchStatement(node); RemoveAll(node.InnerLocals); return(null); }
/// <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); }
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node) { // visit switch header VisitRvalue(node.Expression); // visit switch block VisitSwitchBlock(node); return(null); }
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)); }
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)); }
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))); }
public override BoundStatement InstrumentSwitchStatement(BoundSwitchStatement original, BoundStatement rewritten) { return(Previous.InstrumentSwitchStatement(original, rewritten)); }