From 141b84fb72776acf122273958760c01e93e8a01a Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Tue, 23 Oct 2018 17:59:24 -0700 Subject: [PATCH] Correctly return cached blocks in the IncrementalBinder for things that use BindEmbeddedBlock. --- .../Portable/Binder/Binder_Statements.cs | 2 +- .../Compilation/MemberSemanticModel.cs | 5 +++ .../IOperation/IOperation/IOperationTests.cs | 33 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index e02d59058df..85fd5b6c379 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -1588,7 +1588,7 @@ protected virtual LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken) /// internal virtual uint LocalScopeDepth => Next.LocalScopeDepth; - internal BoundBlock BindEmbeddedBlock(BlockSyntax node, DiagnosticBag diagnostics) + internal virtual BoundBlock BindEmbeddedBlock(BlockSyntax node, DiagnosticBag diagnostics) { return BindBlock(node, diagnostics); } diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs index 4164dfe5ffe..9cdbe61e7b2 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs @@ -2085,6 +2085,11 @@ public override BoundStatement BindStatement(StatementSyntax node, DiagnosticBag return (BoundStatement)boundNode; } + internal override BoundBlock BindEmbeddedBlock(BlockSyntax node, DiagnosticBag diagnostics) + { + return (BoundBlock)TryGetBoundNodeFromMap(node) ?? base.BindEmbeddedBlock(node, diagnostics); + } + private BoundNode TryGetBoundNodeFromMap(CSharpSyntaxNode node) { ImmutableArray boundNodes = _semanticModel.GuardedGetBoundNodesFromMap(node); diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests.cs index 0636f4886af..e25fd8c2d48 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests.cs @@ -493,6 +493,39 @@ void M(int x) "); } + [Fact, WorkItem(26649, "https://github.com/dotnet/roslyn/issues/26649")] + public void IncrementalBindingReusesBlock() + { + var source = @" +class C +{ + void M() + { + try + { + } + catch (Exception e) + { + throw new Exception(); + } + } +}"; + + var compilation = CreateCompilation(source); + var syntaxTree = compilation.SyntaxTrees[0]; + var semanticModel = compilation.GetSemanticModel(syntaxTree); + + // We want to get the IOperation for the { throw new Exception(); } first, and then for the containing catch block, to + // force the semantic model to bind the inner first. It should reuse that inner block when binding the outer catch. + + var catchBlock = syntaxTree.GetRoot().DescendantNodes().OfType().Single(); + var exceptionBlock = catchBlock.Block; + + var blockOperation = semanticModel.GetOperation(exceptionBlock); + var catchOperation = (ICatchClauseOperation)semanticModel.GetOperation(catchBlock); + Assert.Same(blockOperation, catchOperation.Handler); + } + private static void VerifyRootAndModelForOperationAncestors( IOperation operation, SemanticModel model, -- GitLab