From c8ef6d129ce84780d0d549d8674446b36371ef22 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Fri, 7 Oct 2022 08:59:16 -0700 Subject: [PATCH 1/4] Do not expose C# member semantic models directly to external consumers. This could occur when member semantic models were used to support/represent speculative semantic models. This change gets us one step closer to addressing #60801. --- .../Compilation/AttributeSemanticModel.cs | 31 +- .../Compilation/CSharpSemanticModel.cs | 54 +- .../Compilation/InitializerSemanticModel.cs | 34 +- ...ticModel.SpeculativeMemberSemanticModel.cs | 31 +- .../Compilation/MemberSemanticModel.cs | 56 +-- .../Compilation/MethodBodySemanticModel.cs | 73 ++- .../Compilation/PublicSemanticModel.cs | 13 + ...SpeculativeSemanticModelWithMemberModel.cs | 471 ++++++++++++++++++ .../SpeculativeSyntaxTreeSemanticModel.cs | 2 +- .../Compilation/SyntaxTreeSemanticModel.cs | 27 +- ...TreeSemanticModel_RegionAnalysisContext.cs | 2 +- .../Compilation/SemanticModelAPITests.cs | 11 + .../Core/Portable/Operations/Operation.cs | 2 +- 13 files changed, 644 insertions(+), 163 deletions(-) create mode 100644 src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs create mode 100644 src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs diff --git a/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs index c6b787d323405..7c9e25a3d0d7f 100644 --- a/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs @@ -17,16 +17,14 @@ internal sealed class AttributeSemanticModel : MemberSemanticModel { private readonly AliasSymbol _aliasOpt; - private AttributeSemanticModel( + internal AttributeSemanticModel( AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Binder rootBinder, - SyntaxTreeSemanticModel? containingSemanticModelOpt = null, - SyntaxTreeSemanticModel? parentSemanticModelOpt = null, - ImmutableDictionary? parentRemappedSymbolsOpt = null, - int speculatedPosition = 0) - : base(syntax, attributeType, new ExecutableCodeBinder(syntax, rootBinder.ContainingMember(), rootBinder), containingSemanticModelOpt, parentSemanticModelOpt, snapshotManagerOpt: null, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt, speculatedPosition) + PublicSemanticModel containingPublicSemanticModel, + ImmutableDictionary? parentRemappedSymbolsOpt = null) + : base(syntax, attributeType, new ExecutableCodeBinder(syntax, rootBinder.ContainingMember(), rootBinder), containingPublicSemanticModel, parentRemappedSymbolsOpt) { Debug.Assert(syntax != null); _aliasOpt = aliasOpt; @@ -44,12 +42,9 @@ public static AttributeSemanticModel Create(SyntaxTreeSemanticModel containingSe /// /// Creates a speculative AttributeSemanticModel that allows asking semantic questions about an attribute node that did not appear in the original source code. /// - public static AttributeSemanticModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Binder rootBinder, ImmutableDictionary parentRemappedSymbolsOpt, int position) + public static SpeculativeSemanticModelWithMemberModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Binder rootBinder, ImmutableDictionary parentRemappedSymbolsOpt, int position) { - Debug.Assert(parentSemanticModel != null); - Debug.Assert(rootBinder != null); - Debug.Assert(rootBinder.IsSemanticModelBinder); - return new AttributeSemanticModel(syntax, attributeType, aliasOpt, rootBinder, parentSemanticModelOpt: parentSemanticModel, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt, speculatedPosition: position); + return new SpeculativeSemanticModelWithMemberModel(parentSemanticModel, position, syntax, attributeType, aliasOpt, rootBinder, parentRemappedSymbolsOpt); } private NamedTypeSymbol AttributeType @@ -128,43 +123,43 @@ internal static bool IsNullableAnalysisEnabledIn(CSharpCompilation compilation, return compilation.IsNullableAnalysisEnabledIn(syntax); } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out SemanticModel? speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out PublicSemanticModel? speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel? speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out PublicSemanticModel? speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out SemanticModel? speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out PublicSemanticModel? speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out SemanticModel? speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out PublicSemanticModel? speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out SemanticModel? speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out PublicSemanticModel? speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out SemanticModel? speculativeModel) + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out PublicSemanticModel? speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out SemanticModel? speculativeModel) + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out PublicSemanticModel? speculativeModel) { speculativeModel = null; return false; diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs index 1e581738b374a..73b5d50ee2c50 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs @@ -2505,10 +2505,12 @@ public virtual DataFlowAnalysis AnalyzeDataFlow(StatementSyntax statement) public bool TryGetSpeculativeSemanticModelForMethodBody(int position, BaseMethodDeclarationSyntax method, out SemanticModel speculativeModel) { CheckModelAndSyntaxNodeToSpeculate(method); - return TryGetSpeculativeSemanticModelForMethodBodyCore((SyntaxTreeSemanticModel)this, position, method, out speculativeModel); + var result = TryGetSpeculativeSemanticModelForMethodBodyCore((SyntaxTreeSemanticModel)this, position, method, out PublicSemanticModel speculativeSyntaxTreeModel); + speculativeModel = speculativeSyntaxTreeModel; + return result; } - internal abstract bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out SemanticModel speculativeModel); + internal abstract bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out PublicSemanticModel speculativeModel); /// /// Get a SemanticModel object that is associated with a method body that did not appear in this source code. @@ -2530,10 +2532,12 @@ public bool TryGetSpeculativeSemanticModelForMethodBody(int position, BaseMethod public bool TryGetSpeculativeSemanticModelForMethodBody(int position, AccessorDeclarationSyntax accessor, out SemanticModel speculativeModel) { CheckModelAndSyntaxNodeToSpeculate(accessor); - return TryGetSpeculativeSemanticModelForMethodBodyCore((SyntaxTreeSemanticModel)this, position, accessor, out speculativeModel); + var result = TryGetSpeculativeSemanticModelForMethodBodyCore((SyntaxTreeSemanticModel)this, position, accessor, out PublicSemanticModel speculativeSyntaxTreeModel); + speculativeModel = speculativeSyntaxTreeModel; + return result; } - internal abstract bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out SemanticModel speculativeModel); + internal abstract bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out PublicSemanticModel speculativeModel); /// /// Get a SemanticModel object that is associated with a type syntax node that did not appear in @@ -2557,10 +2561,12 @@ public bool TryGetSpeculativeSemanticModelForMethodBody(int position, AccessorDe public bool TryGetSpeculativeSemanticModel(int position, TypeSyntax type, out SemanticModel speculativeModel, SpeculativeBindingOption bindingOption = SpeculativeBindingOption.BindAsExpression) { CheckModelAndSyntaxNodeToSpeculate(type); - return TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, type, bindingOption, out speculativeModel); + var result = TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, type, bindingOption, out PublicSemanticModel speculativeSyntaxTreeModel); + speculativeModel = speculativeSyntaxTreeModel; + return result; } - internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, TypeSyntax type, SpeculativeBindingOption bindingOption, out SemanticModel speculativeModel); + internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, TypeSyntax type, SpeculativeBindingOption bindingOption, out PublicSemanticModel speculativeModel); /// /// Get a SemanticModel object that is associated with a statement that did not appear in @@ -2581,10 +2587,12 @@ public bool TryGetSpeculativeSemanticModel(int position, TypeSyntax type, out Se public bool TryGetSpeculativeSemanticModel(int position, StatementSyntax statement, out SemanticModel speculativeModel) { CheckModelAndSyntaxNodeToSpeculate(statement); - return TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, statement, out speculativeModel); + var result = TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, statement, out PublicSemanticModel speculativeSyntaxTreeModel); + speculativeModel = speculativeSyntaxTreeModel; + return result; } - internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out SemanticModel speculativeModel); + internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out PublicSemanticModel speculativeModel); /// /// Get a SemanticModel object that is associated with an initializer that did not appear in @@ -2606,10 +2614,12 @@ public bool TryGetSpeculativeSemanticModel(int position, StatementSyntax stateme public bool TryGetSpeculativeSemanticModel(int position, EqualsValueClauseSyntax initializer, out SemanticModel speculativeModel) { CheckModelAndSyntaxNodeToSpeculate(initializer); - return TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, initializer, out speculativeModel); + var result = TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, initializer, out PublicSemanticModel speculativeSyntaxTreeModel); + speculativeModel = speculativeSyntaxTreeModel; + return result; } - internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out SemanticModel speculativeModel); + internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out PublicSemanticModel speculativeModel); /// /// Get a SemanticModel object that is associated with an expression body that did not appear in @@ -2631,10 +2641,12 @@ public bool TryGetSpeculativeSemanticModel(int position, EqualsValueClauseSyntax public bool TryGetSpeculativeSemanticModel(int position, ArrowExpressionClauseSyntax expressionBody, out SemanticModel speculativeModel) { CheckModelAndSyntaxNodeToSpeculate(expressionBody); - return TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, expressionBody, out speculativeModel); + var result = TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, expressionBody, out PublicSemanticModel speculativeSyntaxTreeModel); + speculativeModel = speculativeSyntaxTreeModel; + return result; } - internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out SemanticModel speculativeModel); + internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out PublicSemanticModel speculativeModel); /// /// Get a SemanticModel object that is associated with a constructor initializer that did not appear in @@ -2659,10 +2671,12 @@ public bool TryGetSpeculativeSemanticModel(int position, ArrowExpressionClauseSy public bool TryGetSpeculativeSemanticModel(int position, ConstructorInitializerSyntax constructorInitializer, out SemanticModel speculativeModel) { CheckModelAndSyntaxNodeToSpeculate(constructorInitializer); - return TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, constructorInitializer, out speculativeModel); + var result = TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, constructorInitializer, out PublicSemanticModel speculativeSyntaxTreeModel); + speculativeModel = speculativeSyntaxTreeModel; + return result; } - internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out SemanticModel speculativeModel); + internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out PublicSemanticModel speculativeModel); /// /// Get a SemanticModel object that is associated with a constructor initializer that did not appear in @@ -2686,10 +2700,12 @@ public bool TryGetSpeculativeSemanticModel(int position, ConstructorInitializerS public bool TryGetSpeculativeSemanticModel(int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) { CheckModelAndSyntaxNodeToSpeculate(constructorInitializer); - return TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, constructorInitializer, out speculativeModel); + var result = TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, constructorInitializer, out PublicSemanticModel speculativeSyntaxTreeModel); + speculativeModel = speculativeSyntaxTreeModel; + return result; } - internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel); + internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out PublicSemanticModel speculativeModel); /// /// Get a SemanticModel object that is associated with a cref that did not appear in @@ -2714,10 +2730,12 @@ public bool TryGetSpeculativeSemanticModel(int position, PrimaryConstructorBaseT public bool TryGetSpeculativeSemanticModel(int position, CrefSyntax crefSyntax, out SemanticModel speculativeModel) { CheckModelAndSyntaxNodeToSpeculate(crefSyntax); - return TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, crefSyntax, out speculativeModel); + var result = TryGetSpeculativeSemanticModelCore((SyntaxTreeSemanticModel)this, position, crefSyntax, out PublicSemanticModel speculativeSyntaxTreeModel); + speculativeModel = speculativeSyntaxTreeModel; + return result; } - internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CrefSyntax crefSyntax, out SemanticModel speculativeModel); + internal abstract bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CrefSyntax crefSyntax, out PublicSemanticModel speculativeModel); /// /// Get a SemanticModel object that is associated with an attribute that did not appear in diff --git a/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs index 4ad1169eee1e5..7b4a69ca859f3 100644 --- a/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs @@ -23,14 +23,12 @@ internal sealed class InitializerSemanticModel : MemberSemanticModel // create a SemanticModel for: // (a) A true field initializer (field = value) of a named type (incl. Enums) OR // (b) A parameter default value - private InitializerSemanticModel(CSharpSyntaxNode syntax, + internal InitializerSemanticModel(CSharpSyntaxNode syntax, Symbol symbol, Binder rootBinder, - SyntaxTreeSemanticModel containingSemanticModelOpt = null, - SyntaxTreeSemanticModel parentSemanticModelOpt = null, - ImmutableDictionary parentRemappedSymbolsOpt = null, - int speculatedPosition = 0) : - base(syntax, symbol, rootBinder, containingSemanticModelOpt, parentSemanticModelOpt, snapshotManagerOpt: null, parentRemappedSymbolsOpt, speculatedPosition) + PublicSemanticModel containingPublicSemanticModel, + ImmutableDictionary parentRemappedSymbolsOpt = null) : + base(syntax, symbol, rootBinder, containingPublicSemanticModel, parentRemappedSymbolsOpt) { Debug.Assert(!(syntax is ConstructorInitializerSyntax || syntax is PrimaryConstructorBaseTypeSyntax)); } @@ -68,15 +66,9 @@ internal static InitializerSemanticModel Create(SyntaxTreeSemanticModel containi /// Creates a speculative SemanticModel for an initializer node (field initializer, constructor initializer, or parameter default value) /// that did not appear in the original source code. /// - internal static InitializerSemanticModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, Symbol owner, CSharpSyntaxNode syntax, Binder rootBinder, ImmutableDictionary parentRemappedSymbolsOpt, int position) + internal static SpeculativeSemanticModelWithMemberModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, Symbol owner, EqualsValueClauseSyntax syntax, Binder rootBinder, ImmutableDictionary parentRemappedSymbolsOpt, int position) { - Debug.Assert(parentSemanticModel != null); - Debug.Assert(syntax != null); - Debug.Assert(syntax.IsKind(SyntaxKind.EqualsValueClause)); - Debug.Assert(rootBinder != null); - Debug.Assert(rootBinder.IsSemanticModelBinder); - - return new InitializerSemanticModel(syntax, owner, rootBinder, parentSemanticModelOpt: parentSemanticModel, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt, speculatedPosition: position); + return new SpeculativeSemanticModelWithMemberModel(parentSemanticModel, position, owner, syntax, rootBinder, parentRemappedSymbolsOpt); } protected internal override CSharpSyntaxNode GetBindableSyntaxNode(CSharpSyntaxNode node) @@ -208,7 +200,7 @@ private bool IsBindableInitializer(CSharpSyntaxNode node) } } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out PublicSemanticModel speculativeModel) { var binder = this.GetEnclosingBinder(position); if (binder == null) @@ -222,37 +214,37 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode return true; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out PublicSemanticModel speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out PublicSemanticModel speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out PublicSemanticModel speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out PublicSemanticModel speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out PublicSemanticModel speculativeModel) { speculativeModel = null; return false; } - internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out PublicSemanticModel speculativeModel) { speculativeModel = null; return false; diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.SpeculativeMemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.SpeculativeMemberSemanticModel.cs index 5fa9402d8cb66..8d4ed467b8c22 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.SpeculativeMemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.SpeculativeMemberSemanticModel.cs @@ -18,21 +18,26 @@ internal abstract partial class MemberSemanticModel /// Allows asking semantic questions about a TypeSyntax (or its descendants) within a member, that did not appear in the original source code. /// Typically, an instance is obtained by a call to SemanticModel.TryGetSpeculativeSemanticModel. /// - private sealed class SpeculativeMemberSemanticModel : MemberSemanticModel + internal sealed class SpeculativeMemberSemanticModel : MemberSemanticModel { /// /// Creates a speculative SemanticModel for a TypeSyntax node at a position within an existing MemberSemanticModel. /// - public SpeculativeMemberSemanticModel(SyntaxTreeSemanticModel parentSemanticModel, Symbol owner, TypeSyntax root, Binder rootBinder, NullableWalker.SnapshotManager snapshotManagerOpt, ImmutableDictionary parentRemappedSymbolsOpt, int position) - : base(root, owner, rootBinder, containingSemanticModelOpt: null, parentSemanticModelOpt: parentSemanticModel, snapshotManagerOpt, parentRemappedSymbolsOpt, speculatedPosition: position) + public SpeculativeMemberSemanticModel( + PublicSemanticModel containingPublicSemanticModel, + Symbol owner, + TypeSyntax root, + Binder rootBinder, + ImmutableDictionary parentRemappedSymbolsOpt) + : base(root, owner, rootBinder, containingPublicSemanticModel: containingPublicSemanticModel, parentRemappedSymbolsOpt) { - Debug.Assert(parentSemanticModel is not null); + Debug.Assert(containingPublicSemanticModel is not null); } protected override NullableWalker.SnapshotManager GetSnapshotManager() { // In this override, current nullability state cannot influence anything of speculatively bound expressions. - return _parentSnapshotManagerOpt; + return ((SpeculativeSemanticModelWithMemberModel)_containingPublicSemanticModel).ParentSnapshotManagerOpt; } protected override BoundNode RewriteNullableBoundNodesWithSnapshots( @@ -54,40 +59,40 @@ protected override void AnalyzeBoundNodeNullability(BoundNode boundRoot, Binder protected override bool IsNullableAnalysisEnabled() { - return _parentSemanticModelOpt.IsNullableAnalysisEnabledAtSpeculativePosition(OriginalPositionForSpeculation, Root); + return ((SyntaxTreeSemanticModel)_containingPublicSemanticModel.ParentModel).IsNullableAnalysisEnabledAtSpeculativePosition(_containingPublicSemanticModel.OriginalPositionForSpeculation, Root); } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out PublicSemanticModel speculativeModel) { throw ExceptionUtilities.Unreachable(); } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out PublicSemanticModel speculativeModel) { throw ExceptionUtilities.Unreachable(); } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out PublicSemanticModel speculativeModel) { throw ExceptionUtilities.Unreachable(); } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out PublicSemanticModel speculativeModel) { throw ExceptionUtilities.Unreachable(); } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out PublicSemanticModel speculativeModel) { throw ExceptionUtilities.Unreachable(); } - internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out PublicSemanticModel speculativeModel) { throw ExceptionUtilities.Unreachable(); } - internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out PublicSemanticModel speculativeModel) { throw ExceptionUtilities.Unreachable(); } diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs index 0acd9839f5b99..c78519ec21ecf 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs @@ -20,6 +20,7 @@ namespace Microsoft.CodeAnalysis.CSharp { /// /// Binding info for expressions and statements that are part of a member declaration. + /// Instances of this class should not be exposed to external consumers. /// internal abstract partial class MemberSemanticModel : CSharpSemanticModel { @@ -33,21 +34,10 @@ internal abstract partial class MemberSemanticModel : CSharpSemanticModel private NullableWalker.SnapshotManager _lazySnapshotManager; private ImmutableDictionary _lazyRemappedSymbols; private readonly ImmutableDictionary _parentRemappedSymbolsOpt; - /// - /// Only used when this is a speculative semantic model. - /// - private readonly NullableWalker.SnapshotManager _parentSnapshotManagerOpt; internal readonly Binder RootBinder; - /// - /// Field specific to a non-speculative MemberSemanticModel that must have a containing semantic model. - /// - private readonly SyntaxTreeSemanticModel _containingSemanticModelOpt; - - // Fields specific to a speculative MemberSemanticModel. - private readonly SyntaxTreeSemanticModel _parentSemanticModelOpt; - private readonly int _speculatedPosition; + private readonly PublicSemanticModel _containingPublicSemanticModel; private readonly Lazy _operationFactory; @@ -55,28 +45,19 @@ protected MemberSemanticModel( CSharpSyntaxNode root, Symbol memberSymbol, Binder rootBinder, - SyntaxTreeSemanticModel containingSemanticModelOpt, - SyntaxTreeSemanticModel parentSemanticModelOpt, - NullableWalker.SnapshotManager snapshotManagerOpt, - ImmutableDictionary parentRemappedSymbolsOpt, - int speculatedPosition) + PublicSemanticModel containingPublicSemanticModel, + ImmutableDictionary parentRemappedSymbolsOpt) { Debug.Assert(root != null); Debug.Assert((object)memberSymbol != null); - Debug.Assert(parentSemanticModelOpt == null ^ containingSemanticModelOpt == null); - Debug.Assert(containingSemanticModelOpt == null || !containingSemanticModelOpt.IsSpeculativeSemanticModel); - Debug.Assert(parentSemanticModelOpt == null || !parentSemanticModelOpt.IsSpeculativeSemanticModel, CSharpResources.ChainingSpeculativeModelIsNotSupported); - Debug.Assert(snapshotManagerOpt == null || parentSemanticModelOpt != null); + Debug.Assert(containingPublicSemanticModel.IsSpeculativeSemanticModel == (containingPublicSemanticModel is SpeculativeSemanticModelWithMemberModel)); _root = root; _memberSymbol = memberSymbol; this.RootBinder = rootBinder.WithAdditionalFlags(GetSemanticModelBinderFlags()); - _containingSemanticModelOpt = containingSemanticModelOpt; - _parentSemanticModelOpt = parentSemanticModelOpt; - _parentSnapshotManagerOpt = snapshotManagerOpt; + _containingPublicSemanticModel = containingPublicSemanticModel; _parentRemappedSymbolsOpt = parentRemappedSymbolsOpt; - _speculatedPosition = speculatedPosition; _operationFactory = new Lazy(() => new CSharpOperationFactory(this)); } @@ -85,7 +66,7 @@ public override CSharpCompilation Compilation { get { - return (_containingSemanticModelOpt ?? _parentSemanticModelOpt).Compilation; + return _containingPublicSemanticModel.Compilation; } } @@ -112,7 +93,7 @@ public sealed override bool IsSpeculativeSemanticModel { get { - return _parentSemanticModelOpt != null; + return _containingPublicSemanticModel.IsSpeculativeSemanticModel; } } @@ -120,7 +101,9 @@ public sealed override int OriginalPositionForSpeculation { get { - return _speculatedPosition; + // This property is not meaningful for member semantic models. + // An external consumer should never be able to access them directly. + throw ExceptionUtilities.Unreachable(); } } @@ -128,7 +111,9 @@ public sealed override CSharpSemanticModel ParentModel { get { - return _parentSemanticModelOpt; + // This property is not meaningful for member semantic models. + // An external consumer should never be able to access them directly. + throw ExceptionUtilities.Unreachable(); } } @@ -136,7 +121,7 @@ internal sealed override SemanticModel ContainingModelOrSelf { get { - return _containingSemanticModelOpt ?? (SemanticModel)this; + return _containingPublicSemanticModel; } } @@ -164,14 +149,14 @@ internal ImmutableDictionary GetRemappedSymbols() return _lazyRemappedSymbols; } - internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, TypeSyntax type, SpeculativeBindingOption bindingOption, out SemanticModel speculativeModel) + internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, TypeSyntax type, SpeculativeBindingOption bindingOption, out PublicSemanticModel speculativeModel) { var expression = SyntaxFactory.GetStandaloneExpression(type); var binder = this.GetSpeculativeBinder(position, expression, bindingOption); if (binder != null) { - speculativeModel = new SpeculativeMemberSemanticModel(parentModel, _memberSymbol, type, binder, GetSnapshotManager(), GetRemappedSymbols(), position); + speculativeModel = new SpeculativeSemanticModelWithMemberModel(parentModel, position, _memberSymbol, type, binder, GetRemappedSymbols(), GetSnapshotManager()); return true; } @@ -179,7 +164,7 @@ internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSeman return false; } - internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CrefSyntax crefSyntax, out SemanticModel speculativeModel) + internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CrefSyntax crefSyntax, out PublicSemanticModel speculativeModel) { // crefs can never legally appear within members. speculativeModel = null; @@ -1953,13 +1938,14 @@ protected void EnsureNullabilityAnalysisPerformedIfNecessary() // Not all speculative models are created with existing snapshots. Attributes, // TypeSyntaxes, and MethodBodies do not depend on existing state in a member, // and so the SnapshotManager can be null in these cases. - if (_parentSnapshotManagerOpt is null || !isNullableAnalysisEnabled) + var parentSnapshotManagerOpt = ((SpeculativeSemanticModelWithMemberModel)_containingPublicSemanticModel).ParentSnapshotManagerOpt; + if (parentSnapshotManagerOpt is null || !isNullableAnalysisEnabled) { rewriteAndCache(); return; } - boundRoot = NullableWalker.AnalyzeAndRewriteSpeculation(_speculatedPosition, boundRoot, binder, _parentSnapshotManagerOpt, out var newSnapshots, ref remappedSymbols); + boundRoot = NullableWalker.AnalyzeAndRewriteSpeculation(_containingPublicSemanticModel.OriginalPositionForSpeculation, boundRoot, binder, parentSnapshotManagerOpt, out var newSnapshots, ref remappedSymbols); GuardedAddBoundTreeForStandaloneSyntax(bindableRoot, boundRoot, newSnapshots, remappedSymbols); } else diff --git a/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs index eba9d23ee4424..d7abb6cebe7c9 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs @@ -43,16 +43,13 @@ internal InitialState( } #nullable disable - private MethodBodySemanticModel( + internal MethodBodySemanticModel( MethodSymbol owner, Binder rootBinder, CSharpSyntaxNode syntax, - SyntaxTreeSemanticModel containingSemanticModelOpt = null, - SyntaxTreeSemanticModel parentSemanticModelOpt = null, - NullableWalker.SnapshotManager snapshotManagerOpt = null, - ImmutableDictionary parentRemappedSymbolsOpt = null, - int speculatedPosition = 0) - : base(syntax, owner, rootBinder, containingSemanticModelOpt, parentSemanticModelOpt, snapshotManagerOpt, parentRemappedSymbolsOpt, speculatedPosition) + PublicSemanticModel containingPublicSemanticModel, + ImmutableDictionary parentRemappedSymbolsOpt = null) + : base(syntax, owner, rootBinder, containingPublicSemanticModel, parentRemappedSymbolsOpt) { Debug.Assert((object)owner != null); Debug.Assert(owner.Kind == SymbolKind.Method); @@ -112,7 +109,7 @@ internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, BindingDi /// /// Creates a speculative SemanticModel for a method body that did not appear in the original source code. /// - internal static MethodBodySemanticModel CreateSpeculative( + internal static SpeculativeSemanticModelWithMemberModel CreateSpeculative( SyntaxTreeSemanticModel parentSemanticModel, MethodSymbol owner, StatementSyntax syntax, @@ -121,60 +118,52 @@ internal static MethodBodySemanticModel CreateSpeculative( ImmutableDictionary parentRemappedSymbolsOpt, int position) { - Debug.Assert(parentSemanticModel != null); - Debug.Assert(syntax != null); - Debug.Assert(rootBinder != null); - Debug.Assert(rootBinder.IsSemanticModelBinder); + return CreateSpeculativeForNode(parentSemanticModel, owner, syntax, rootBinder, snapshotManagerOpt, parentRemappedSymbolsOpt, position); + } - return new MethodBodySemanticModel(owner, rootBinder, syntax, parentSemanticModelOpt: parentSemanticModel, snapshotManagerOpt: snapshotManagerOpt, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt, speculatedPosition: position); + private static SpeculativeSemanticModelWithMemberModel CreateSpeculativeForNode( + SyntaxTreeSemanticModel parentSemanticModel, + MethodSymbol owner, + CSharpSyntaxNode syntax, + Binder rootBinder, + NullableWalker.SnapshotManager snapshotManagerOpt, + ImmutableDictionary parentRemappedSymbolsOpt, + int position) + { + return new SpeculativeSemanticModelWithMemberModel(parentSemanticModel, position, owner, syntax, rootBinder, parentRemappedSymbolsOpt, snapshotManagerOpt); } /// /// Creates a speculative SemanticModel for an expression body that did not appear in the original source code. /// - internal static MethodBodySemanticModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, MethodSymbol owner, ArrowExpressionClauseSyntax syntax, Binder rootBinder, int position) + internal static SpeculativeSemanticModelWithMemberModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, MethodSymbol owner, ArrowExpressionClauseSyntax syntax, Binder rootBinder, int position) { - Debug.Assert(parentSemanticModel != null); - Debug.Assert(syntax != null); - Debug.Assert(rootBinder != null); - Debug.Assert(rootBinder.IsSemanticModelBinder); - - return new MethodBodySemanticModel(owner, rootBinder, syntax, parentSemanticModelOpt: parentSemanticModel, speculatedPosition: position); + return CreateSpeculativeForNode(parentSemanticModel, owner, syntax, rootBinder, snapshotManagerOpt: null, parentRemappedSymbolsOpt: null, position); } /// /// Creates a speculative SemanticModel for a constructor initializer that did not appear in the original source code. /// - internal static MethodBodySemanticModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, MethodSymbol owner, ConstructorInitializerSyntax syntax, Binder rootBinder, int position) + internal static SpeculativeSemanticModelWithMemberModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, MethodSymbol owner, ConstructorInitializerSyntax syntax, Binder rootBinder, int position) { - Debug.Assert(parentSemanticModel != null); - Debug.Assert(syntax != null); - Debug.Assert(rootBinder != null); - Debug.Assert(rootBinder.IsSemanticModelBinder); - - return new MethodBodySemanticModel(owner, rootBinder, syntax, parentSemanticModelOpt: parentSemanticModel, speculatedPosition: position); + return CreateSpeculativeForNode(parentSemanticModel, owner, syntax, rootBinder, snapshotManagerOpt: null, parentRemappedSymbolsOpt: null, position); } /// /// Creates a speculative SemanticModel for a constructor initializer that did not appear in the original source code. /// - internal static MethodBodySemanticModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, MethodSymbol owner, PrimaryConstructorBaseTypeSyntax syntax, Binder rootBinder, int position) + internal static SpeculativeSemanticModelWithMemberModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, MethodSymbol owner, PrimaryConstructorBaseTypeSyntax syntax, Binder rootBinder, int position) { - Debug.Assert(parentSemanticModel != null); - Debug.Assert(syntax != null); - Debug.Assert(rootBinder != null); - Debug.Assert(rootBinder.IsSemanticModelBinder); - - return new MethodBodySemanticModel(owner, rootBinder, syntax, parentSemanticModelOpt: parentSemanticModel, speculatedPosition: position); + return CreateSpeculativeForNode(parentSemanticModel, owner, syntax, rootBinder, snapshotManagerOpt: null, parentRemappedSymbolsOpt: null, position); } - internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out PublicSemanticModel speculativeModel) { // CONSIDER: Do we want to ensure that speculated method and the original method have identical signatures? return GetSpeculativeSemanticModelForMethodBody(parentModel, position, method.Body, out speculativeModel); } - private bool GetSpeculativeSemanticModelForMethodBody(SyntaxTreeSemanticModel parentModel, int position, BlockSyntax body, out SemanticModel speculativeModel) + private bool GetSpeculativeSemanticModelForMethodBody(SyntaxTreeSemanticModel parentModel, int position, BlockSyntax body, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -206,12 +195,12 @@ private bool GetSpeculativeSemanticModelForMethodBody(SyntaxTreeSemanticModel pa return true; } - internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out PublicSemanticModel speculativeModel) { return GetSpeculativeSemanticModelForMethodBody(parentModel, position, accessor.Body, out speculativeModel); } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -229,7 +218,7 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode return true; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -248,7 +237,7 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode return true; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out PublicSemanticModel speculativeModel) { if (MemberSymbol is MethodSymbol methodSymbol && methodSymbol.MethodKind == MethodKind.Constructor && Root.FindToken(position).Parent?.AncestorsAndSelf().OfType().FirstOrDefault()?.Parent == Root) @@ -267,7 +256,7 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out PublicSemanticModel speculativeModel) { if (MemberSymbol is SynthesizedRecordConstructor primaryCtor && primaryCtor.GetSyntax() is RecordDeclarationSyntax recordDecl) @@ -290,7 +279,7 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out PublicSemanticModel speculativeModel) { speculativeModel = null; return false; diff --git a/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs new file mode 100644 index 0000000000000..48a70ca817de0 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.CSharp +{ + /// + /// Instances of this can be exposed to external consumers. + /// + internal abstract partial class PublicSemanticModel : CSharpSemanticModel + { + } +} diff --git a/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs b/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs new file mode 100644 index 0000000000000..3f0ec4cb2d444 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs @@ -0,0 +1,471 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.CSharp +{ + + internal sealed class SpeculativeSemanticModelWithMemberModel : PublicSemanticModel + { + private readonly SyntaxTreeSemanticModel _parentSemanticModel; + private readonly int _position; + private readonly NullableWalker.SnapshotManager? _parentSnapshotManagerOpt; + private readonly MemberSemanticModel _memberModel; + + private SpeculativeSemanticModelWithMemberModel( + SyntaxTreeSemanticModel parentSemanticModel, + int position, + NullableWalker.SnapshotManager? snapshotManagerOpt) + { + Debug.Assert(parentSemanticModel is not null); + + _parentSemanticModel = parentSemanticModel; + _position = position; + _parentSnapshotManagerOpt = snapshotManagerOpt; + _memberModel = null!; + } + + public SpeculativeSemanticModelWithMemberModel( + SyntaxTreeSemanticModel parentSemanticModel, + int position, + AttributeSyntax syntax, + NamedTypeSymbol attributeType, + AliasSymbol aliasOpt, + Binder rootBinder, + ImmutableDictionary? parentRemappedSymbolsOpt) + : this(parentSemanticModel, position, snapshotManagerOpt: null) + { + Debug.Assert(syntax != null); + Debug.Assert(rootBinder != null); + Debug.Assert(rootBinder.IsSemanticModelBinder); + + _memberModel = new AttributeSemanticModel(syntax, attributeType, aliasOpt, rootBinder, containingPublicSemanticModel: this, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt); + } + + public SpeculativeSemanticModelWithMemberModel( + SyntaxTreeSemanticModel parentSemanticModel, + int position, + Symbol owner, + EqualsValueClauseSyntax syntax, + Binder rootBinder, + ImmutableDictionary? parentRemappedSymbolsOpt) + : this(parentSemanticModel, position, snapshotManagerOpt: null) + { + Debug.Assert(syntax != null); + Debug.Assert(rootBinder != null); + Debug.Assert(rootBinder.IsSemanticModelBinder); + + _memberModel = new InitializerSemanticModel(syntax, owner, rootBinder, containingPublicSemanticModel: this, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt); + } + + public SpeculativeSemanticModelWithMemberModel( + SyntaxTreeSemanticModel parentModel, + int position, + Symbol owner, + TypeSyntax type, + Binder rootBinder, + ImmutableDictionary? parentRemappedSymbolsOpt, + NullableWalker.SnapshotManager? snapshotManagerOpt) + : this(parentModel, position, snapshotManagerOpt) + { + _memberModel = new MemberSemanticModel.SpeculativeMemberSemanticModel(this, owner, type, rootBinder, parentRemappedSymbolsOpt); + } + + public SpeculativeSemanticModelWithMemberModel( + SyntaxTreeSemanticModel parentSemanticModel, + int position, + MethodSymbol owner, + CSharpSyntaxNode syntax, + Binder rootBinder, + ImmutableDictionary? parentRemappedSymbolsOpt, + NullableWalker.SnapshotManager? snapshotManagerOpt) + : this(parentSemanticModel, position, snapshotManagerOpt) + { + Debug.Assert(syntax != null); + Debug.Assert(rootBinder != null); + Debug.Assert(rootBinder.IsSemanticModelBinder); + + _memberModel = new MethodBodySemanticModel(owner, rootBinder, syntax, containingPublicSemanticModel: this, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt); + } + + internal NullableWalker.SnapshotManager? ParentSnapshotManagerOpt => _parentSnapshotManagerOpt; + + public override bool IsSpeculativeSemanticModel => true; + + public override int OriginalPositionForSpeculation => _position; + + public override CSharpSemanticModel ParentModel => _parentSemanticModel; + + public override CSharpCompilation Compilation => _parentSemanticModel.Compilation; + + internal override CSharpSyntaxNode Root => _memberModel.Root; + + public override SyntaxTree SyntaxTree => _memberModel.SyntaxTree; + + public override bool IgnoresAccessibility => _parentSemanticModel.IgnoresAccessibility; + + internal sealed override SemanticModel ContainingModelOrSelf => this; + + internal override MemberSemanticModel GetMemberModel(SyntaxNode node) + { + return _memberModel.GetMemberModel(node); + } + + public override Conversion ClassifyConversion( + ExpressionSyntax expression, + ITypeSymbol destination, + bool isExplicitInSource = false) + { + return _memberModel.ClassifyConversion(expression, destination, isExplicitInSource); + } + + internal override Conversion ClassifyConversionForCast( + ExpressionSyntax expression, + TypeSymbol destination) + { + return _memberModel.ClassifyConversionForCast(expression, destination); + } + + public override ImmutableArray GetSyntaxDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetSyntaxDiagnostics(span, cancellationToken); + } + + public override ImmutableArray GetDeclarationDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclarationDiagnostics(span, cancellationToken); + } + + public override ImmutableArray GetMethodBodyDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetMethodBodyDiagnostics(span, cancellationToken); + } + + public override ImmutableArray GetDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDiagnostics(span, cancellationToken); + } + + public override INamespaceSymbol GetDeclaredSymbol(NamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override INamespaceSymbol GetDeclaredSymbol(FileScopedNamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override INamedTypeSymbol GetDeclaredSymbol(BaseTypeDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override INamedTypeSymbol GetDeclaredSymbol(DelegateDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IFieldSymbol GetDeclaredSymbol(EnumMemberDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override ISymbol GetDeclaredSymbol(LocalFunctionStatementSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override ISymbol GetDeclaredSymbol(MemberDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IMethodSymbol GetDeclaredSymbol(CompilationUnitSyntax declarationSyntax, CancellationToken cancellationToken = default) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IMethodSymbol GetDeclaredSymbol(BaseMethodDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override ISymbol GetDeclaredSymbol(BasePropertyDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IPropertySymbol GetDeclaredSymbol(PropertyDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IPropertySymbol GetDeclaredSymbol(IndexerDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IEventSymbol GetDeclaredSymbol(EventDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IMethodSymbol GetDeclaredSymbol(AccessorDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IMethodSymbol GetDeclaredSymbol(ArrowExpressionClauseSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override ISymbol GetDeclaredSymbol(VariableDeclaratorSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override ISymbol GetDeclaredSymbol(SingleVariableDesignationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + internal override LocalSymbol GetAdjustedLocalSymbol(SourceLocalSymbol local) + { + return _memberModel.GetAdjustedLocalSymbol(local); + } + + public override ILabelSymbol GetDeclaredSymbol(LabeledStatementSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override ILabelSymbol GetDeclaredSymbol(SwitchLabelSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IAliasSymbol GetDeclaredSymbol(UsingDirectiveSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IAliasSymbol GetDeclaredSymbol(ExternAliasDirectiveSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + public override IParameterSymbol GetDeclaredSymbol(ParameterSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + } + + internal override ImmutableArray GetDeclaredSymbols(BaseFieldDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbols(declarationSyntax, cancellationToken); + } + + public override ITypeParameterSymbol GetDeclaredSymbol(TypeParameterSyntax typeParameter, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(typeParameter, cancellationToken); + } + + public override IRangeVariableSymbol GetDeclaredSymbol(JoinIntoClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(node, cancellationToken); + } + + public override IRangeVariableSymbol GetDeclaredSymbol(QueryClauseSyntax queryClause, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(queryClause, cancellationToken); + } + + public override IRangeVariableSymbol GetDeclaredSymbol(QueryContinuationSyntax node, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(node, cancellationToken); + } + + public override AwaitExpressionInfo GetAwaitExpressionInfo(AwaitExpressionSyntax node) + { + return _memberModel.GetAwaitExpressionInfo(node); + } + + public override ForEachStatementInfo GetForEachStatementInfo(ForEachStatementSyntax node) + { + return _memberModel.GetForEachStatementInfo(node); + } + + public override ForEachStatementInfo GetForEachStatementInfo(CommonForEachStatementSyntax node) + { + return _memberModel.GetForEachStatementInfo(node); + } + + public override DeconstructionInfo GetDeconstructionInfo(AssignmentExpressionSyntax node) + { + return _memberModel.GetDeconstructionInfo(node); + } + + public override DeconstructionInfo GetDeconstructionInfo(ForEachVariableStatementSyntax node) + { + return _memberModel.GetDeconstructionInfo(node); + } + + public override QueryClauseInfo GetQueryClauseInfo(QueryClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetQueryClauseInfo(node, cancellationToken); + } + + public override IPropertySymbol GetDeclaredSymbol(AnonymousObjectMemberDeclaratorSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declaratorSyntax, cancellationToken); + } + + public override INamedTypeSymbol GetDeclaredSymbol(AnonymousObjectCreationExpressionSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declaratorSyntax, cancellationToken); + } + + public override INamedTypeSymbol GetDeclaredSymbol(TupleExpressionSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declaratorSyntax, cancellationToken); + } + + public override ISymbol GetDeclaredSymbol(ArgumentSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetDeclaredSymbol(declaratorSyntax, cancellationToken); + } + + internal override IOperation? GetOperationWorker(CSharpSyntaxNode node, CancellationToken cancellationToken) + { + return _memberModel.GetOperationWorker(node, cancellationToken); + } + + internal override SymbolInfo GetSymbolInfoWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetSymbolInfoWorker(node, options, cancellationToken); + } + + internal override CSharpTypeInfo GetTypeInfoWorker(CSharpSyntaxNode node, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetTypeInfoWorker(node, cancellationToken); + } + + internal override ImmutableArray GetMemberGroupWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetMemberGroupWorker(node, options, cancellationToken); + } + + internal override ImmutableArray GetIndexerGroupWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetIndexerGroupWorker(node, options, cancellationToken); + } + + internal override Optional GetConstantValueWorker(CSharpSyntaxNode node, CancellationToken cancellationToken) + { + return _memberModel.GetConstantValueWorker(node, cancellationToken); + } + + internal override SymbolInfo GetCollectionInitializerSymbolInfoWorker(InitializerExpressionSyntax collectionInitializer, ExpressionSyntax node, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetCollectionInitializerSymbolInfoWorker(collectionInitializer, node, cancellationToken); + } + + public override SymbolInfo GetSymbolInfo(OrderingSyntax node, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetSymbolInfo(node, cancellationToken); + } + + public override SymbolInfo GetSymbolInfo(SelectOrGroupClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetSymbolInfo(node, cancellationToken); + } + + public override TypeInfo GetTypeInfo(SelectOrGroupClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken)) + { + return _memberModel.GetTypeInfo(node, cancellationToken); + } + + internal override Binder GetEnclosingBinderInternal(int position) + { + return _memberModel.GetEnclosingBinderInternal(position); + } + + internal override Symbol RemapSymbolIfNecessaryCore(Symbol symbol) + { + return _memberModel.RemapSymbolIfNecessaryCore(symbol); + } + + internal sealed override Func GetSyntaxNodesToAnalyzeFilter(SyntaxNode declaredNode, ISymbol declaredSymbol) + { + return _memberModel.GetSyntaxNodesToAnalyzeFilter(declaredNode, declaredSymbol); + } + + internal override bool ShouldSkipSyntaxNodeAnalysis(SyntaxNode node, ISymbol containingSymbol) + { + return _memberModel.ShouldSkipSyntaxNodeAnalysis(node, containingSymbol); + } + + internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, BindingDiagnosticBag diagnostics) + { + return _memberModel.Bind(binder, node, diagnostics); + } + + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out PublicSemanticModel? speculativeModel) + { + return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, constructorInitializer, out speculativeModel); + } + + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out PublicSemanticModel? speculativeModel) + { + return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, constructorInitializer, out speculativeModel); + } + + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out PublicSemanticModel? speculativeModel) + { + return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, initializer, out speculativeModel); + } + + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out PublicSemanticModel? speculativeModel) + { + return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, expressionBody, out speculativeModel); + } + + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out PublicSemanticModel? speculativeModel) + { + return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, statement, out speculativeModel); + } + + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out PublicSemanticModel? speculativeModel) + { + return _memberModel.TryGetSpeculativeSemanticModelForMethodBodyCore(parentModel, position, method, out speculativeModel); + } + + internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out PublicSemanticModel? speculativeModel) + { + return _memberModel.TryGetSpeculativeSemanticModelForMethodBodyCore(parentModel, position, accessor, out speculativeModel); + } + + internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, TypeSyntax type, SpeculativeBindingOption bindingOption, out PublicSemanticModel speculativeModel) + { + return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, type, bindingOption, out speculativeModel); + } + + internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CrefSyntax crefSyntax, out PublicSemanticModel speculativeModel) + { + return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, crefSyntax, out speculativeModel); + } + + internal override BoundExpression GetSpeculativelyBoundExpression(int position, ExpressionSyntax expression, SpeculativeBindingOption bindingOption, out Binder binder, out ImmutableArray crefSymbols) + { + return _memberModel.GetSpeculativelyBoundExpression(position, expression, bindingOption, out binder, out crefSymbols); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Compilation/SpeculativeSyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SpeculativeSyntaxTreeSemanticModel.cs index 2d436857fc1f1..b421d5132cb8c 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SpeculativeSyntaxTreeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SpeculativeSyntaxTreeSemanticModel.cs @@ -47,7 +47,7 @@ private static SpeculativeSyntaxTreeSemanticModel CreateCore(SyntaxTreeSemanticM } private SpeculativeSyntaxTreeSemanticModel(SyntaxTreeSemanticModel parentSemanticModel, CSharpSyntaxNode root, Binder rootBinder, int position, SpeculativeBindingOption bindingOption) - : base(parentSemanticModel.Compilation, parentSemanticModel.SyntaxTree, root.SyntaxTree) + : base(parentSemanticModel.Compilation, parentSemanticModel.SyntaxTree, root.SyntaxTree, parentSemanticModel.IgnoresAccessibility) { _parentSemanticModel = parentSemanticModel; _root = root; diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs index d865e71511cbc..e74c97837b61b 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.CSharp /// /// Allows asking semantic questions about any node in a SyntaxTree within a Compilation. /// - internal partial class SyntaxTreeSemanticModel : CSharpSemanticModel + internal partial class SyntaxTreeSemanticModel : PublicSemanticModel { private readonly CSharpCompilation _compilation; private readonly SyntaxTree _syntaxTree; @@ -50,11 +50,12 @@ internal SyntaxTreeSemanticModel(CSharpCompilation compilation, SyntaxTree synta _binderFactory = compilation.GetBinderFactory(SyntaxTree, ignoreAccessibility); } - internal SyntaxTreeSemanticModel(CSharpCompilation parentCompilation, SyntaxTree parentSyntaxTree, SyntaxTree speculatedSyntaxTree) + internal SyntaxTreeSemanticModel(CSharpCompilation parentCompilation, SyntaxTree parentSyntaxTree, SyntaxTree speculatedSyntaxTree, bool ignoreAccessibility) { _compilation = parentCompilation; _syntaxTree = speculatedSyntaxTree; - _binderFactory = _compilation.GetBinderFactory(parentSyntaxTree); + _binderFactory = _compilation.GetBinderFactory(parentSyntaxTree, ignoreAccessibility); + _ignoresAccessibility = ignoreAccessibility; } /// @@ -591,7 +592,7 @@ internal override SemanticModel ContainingModelOrSelf get { return this; } } - internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, TypeSyntax type, SpeculativeBindingOption bindingOption, out SemanticModel speculativeModel) + internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, TypeSyntax type, SpeculativeBindingOption bindingOption, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -612,7 +613,7 @@ internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSeman return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CrefSyntax crefSyntax, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CrefSyntax crefSyntax, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -627,7 +628,7 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode return false; } - internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out SemanticModel speculativeModel) + internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -641,7 +642,7 @@ internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSeman return false; } - internal sealed override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out SemanticModel speculativeModel) + internal sealed override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -655,7 +656,7 @@ internal sealed override bool TryGetSpeculativeSemanticModelForMethodBodyCore(Sy return false; } - internal sealed override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out SemanticModel speculativeModel) + internal sealed override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -669,7 +670,7 @@ internal sealed override bool TryGetSpeculativeSemanticModelForMethodBodyCore(Sy return false; } - internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out SemanticModel speculativeModel) + internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -683,7 +684,7 @@ internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSeman return false; } - internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out SemanticModel speculativeModel) + internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -697,7 +698,7 @@ internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticMode return false; } - internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out SemanticModel speculativeModel) + internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -716,7 +717,7 @@ internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSeman return false; } - internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out SemanticModel speculativeModel) + internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out PublicSemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); @@ -757,7 +758,7 @@ internal override BoundExpression GetSpeculativelyBoundExpression(int position, return GetSpeculativelyBoundExpressionWithoutNullability(position, expression, bindingOption, out binder, out crefSymbols); } - internal AttributeSemanticModel CreateSpeculativeAttributeSemanticModel(int position, AttributeSyntax attribute, Binder binder, AliasSymbol aliasOpt, NamedTypeSymbol attributeType) + internal PublicSemanticModel CreateSpeculativeAttributeSemanticModel(int position, AttributeSyntax attribute, Binder binder, AliasSymbol aliasOpt, NamedTypeSymbol attributeType) { var memberModel = IsNullableAnalysisEnabledAtSpeculativePosition(position, attribute) ? GetMemberModel(position) : null; return AttributeSemanticModel.CreateSpeculative(this, attribute, attributeType, aliasOpt, binder, memberModel?.GetRemappedSymbols(), position); diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel_RegionAnalysisContext.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel_RegionAnalysisContext.cs index a2e2436e2d8b0..3da52ceea31e0 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel_RegionAnalysisContext.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel_RegionAnalysisContext.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp /// /// Allows asking semantic questions about any node in a SyntaxTree within a Compilation. /// - internal partial class SyntaxTreeSemanticModel : CSharpSemanticModel + internal partial class SyntaxTreeSemanticModel { private RegionAnalysisContext RegionAnalysisContext(ExpressionSyntax expression) { diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs index 8455823a932c8..16c046c7e2e19 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs @@ -1466,6 +1466,7 @@ enum C bool success = model.TryGetSpeculativeSemanticModel(equalsValue.SpanStart, newEqualsValue, out speculativeModel); Assert.True(success); Assert.NotNull(speculativeModel); + Assert.False(speculativeModel.IgnoresAccessibility); var typeInfo = speculativeModel.GetTypeInfo(expr); Assert.NotNull(typeInfo.Type); @@ -1475,6 +1476,10 @@ enum C var constantInfo = speculativeModel.GetConstantValue(expr); Assert.True(constantInfo.HasValue, "must be a constant"); Assert.Equal((short)0, constantInfo.Value); + + model = compilation.GetSemanticModel(tree, ignoreAccessibility: true); + model.TryGetSpeculativeSemanticModel(equalsValue.SpanStart, newEqualsValue, out speculativeModel); + Assert.True(speculativeModel.IgnoresAccessibility); } [Fact] @@ -2699,6 +2704,7 @@ private static void TestGetSpeculativeSemanticModelForTypeSyntax_Common( var success = model.TryGetSpeculativeSemanticModel(position, speculatedTypeSyntax, out speculativeModel, bindingOption); Assert.True(success); Assert.NotNull(speculativeModel); + Assert.False(speculativeModel.IgnoresAccessibility); Assert.True(speculativeModel.IsSpeculativeSemanticModel); Assert.Equal(model, speculativeModel.ParentModel); @@ -2830,6 +2836,11 @@ class MyException : System.Exception var speculatedTypeExpression = SyntaxFactory.ParseName("System.ArgumentException"); TestGetSpeculativeSemanticModelForTypeSyntax_Common(model, baseList.SpanStart, speculatedTypeExpression, SpeculativeBindingOption.BindAsTypeOrNamespace, SymbolKind.NamedType, "System.ArgumentException"); + + model = compilation.GetSemanticModel(tree, ignoreAccessibility: true); + SemanticModel speculativeModel; + model.TryGetSpeculativeSemanticModel(baseList.SpanStart, speculatedTypeExpression, out speculativeModel); + Assert.True(speculativeModel.IgnoresAccessibility); } [Fact] diff --git a/src/Compilers/Core/Portable/Operations/Operation.cs b/src/Compilers/Core/Portable/Operations/Operation.cs index 0eac58b1f866a..68e833169fa88 100644 --- a/src/Compilers/Core/Portable/Operations/Operation.cs +++ b/src/Compilers/Core/Portable/Operations/Operation.cs @@ -31,7 +31,7 @@ protected Operation(SemanticModel? semanticModel, SyntaxNode syntax, bool isImpl if (semanticModel != null) { Debug.Assert(semanticModel.ContainingModelOrSelf != null); - if (semanticModel.IsSpeculativeSemanticModel) + if (semanticModel.Language != LanguageNames.CSharp && semanticModel.IsSpeculativeSemanticModel) { Debug.Assert(semanticModel.ContainingModelOrSelf == semanticModel); } From 2fd361a139856e0709be6ba55d686bb5daaa3fd8 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Tue, 11 Oct 2022 09:48:27 -0700 Subject: [PATCH 2/4] SpeculativeSemanticModelWithMemberModel - create child member models for attributes and parameter default values. Fixes #60801. Fixes #24135. --- .../Portable/Binder/Binder_Invocation.cs | 7 - .../Compilation/AttributeSemanticModel.cs | 2 +- .../Compilation/InitializerSemanticModel.cs | 2 +- .../Compilation/MemberSemanticModel.cs | 10 +- .../Compilation/PublicSemanticModel.cs | 36 +++ ...SpeculativeSemanticModelWithMemberModel.cs | 217 ++++++++++++------ .../Compilation/SyntaxTreeSemanticModel.cs | 34 --- .../Portable/Symbols/Symbol_Attributes.cs | 2 +- .../Test/Semantic/Semantics/LambdaTests.cs | 4 +- .../Semantic/Semantics/LocalFunctionTests.cs | 5 +- .../Test/Semantic/Semantics/OutVarTests.cs | 176 ++++++++++++++ .../SymbolCompletionProviderTests.cs | 30 +-- 12 files changed, 382 insertions(+), 143 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index 5e6ff69f032c5..f191d0564baaf 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -1863,13 +1863,6 @@ private bool TryBindNameofOperator(InvocationExpressionSyntax node, BindingDiagn if (node.MayBeNameofOperator()) { var binder = this.GetBinder(node); - if (binder is null) - { - // This could happen during speculation due to a bug - // Tracked by https://github.com/dotnet/roslyn/issues/60801 - result = null; - return false; - } if (binder.EnclosingNameofArgument == node.ArgumentList.Arguments[0].Expression) { result = binder.BindNameofOperatorInternal(node, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs index 7c9e25a3d0d7f..343b459bcdbb9 100644 --- a/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs @@ -33,7 +33,7 @@ internal AttributeSemanticModel( /// /// Creates an AttributeSemanticModel that allows asking semantic questions about an attribute node. /// - public static AttributeSemanticModel Create(SyntaxTreeSemanticModel containingSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Symbol? attributeTarget, Binder rootBinder, ImmutableDictionary parentRemappedSymbolsOpt) + public static AttributeSemanticModel Create(PublicSemanticModel containingSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Symbol? attributeTarget, Binder rootBinder, ImmutableDictionary? parentRemappedSymbolsOpt) { rootBinder = attributeTarget is null ? rootBinder : new ContextualAttributeBinder(rootBinder, attributeTarget); return new AttributeSemanticModel(syntax, attributeType, aliasOpt, rootBinder, containingSemanticModel, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt); diff --git a/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs index 7b4a69ca859f3..c2ceb6136b97b 100644 --- a/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs @@ -56,7 +56,7 @@ internal static InitializerSemanticModel Create(SyntaxTreeSemanticModel containi /// /// Creates a SemanticModel for a parameter default value. /// - internal static InitializerSemanticModel Create(SyntaxTreeSemanticModel containingSemanticModel, ParameterSyntax syntax, ParameterSymbol parameterSymbol, Binder rootBinder, ImmutableDictionary parentRemappedSymbolsOpt) + internal static InitializerSemanticModel Create(PublicSemanticModel containingSemanticModel, ParameterSyntax syntax, ParameterSymbol parameterSymbol, Binder rootBinder, ImmutableDictionary parentRemappedSymbolsOpt) { Debug.Assert(containingSemanticModel != null); return new InitializerSemanticModel(syntax, parameterSymbol, rootBinder, containingSemanticModel, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt); diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs index c78519ec21ecf..a0dd3bd4ab006 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs @@ -551,22 +551,22 @@ private static BoundNode GetLowerBoundNode(ImmutableArray boundNodes) return boundNodes[boundNodes.Length - 1]; } - public override ImmutableArray GetSyntaxDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) + public sealed override ImmutableArray GetSyntaxDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotSupportedException(); } - public override ImmutableArray GetDeclarationDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) + public sealed override ImmutableArray GetDeclarationDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotSupportedException(); } - public override ImmutableArray GetMethodBodyDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) + public sealed override ImmutableArray GetMethodBodyDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotSupportedException(); } - public override ImmutableArray GetDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) + public sealed override ImmutableArray GetDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotSupportedException(); } @@ -2320,7 +2320,7 @@ internal sealed override Func GetSyntaxNodesToAnalyzeFilter(Sy throw ExceptionUtilities.Unreachable(); } - internal override bool ShouldSkipSyntaxNodeAnalysis(SyntaxNode node, ISymbol containingSymbol) + internal sealed override bool ShouldSkipSyntaxNodeAnalysis(SyntaxNode node, ISymbol containingSymbol) { throw ExceptionUtilities.Unreachable(); } diff --git a/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs index 48a70ca817de0..40be8f1f51287 100644 --- a/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; + namespace Microsoft.CodeAnalysis.CSharp { /// @@ -9,5 +12,38 @@ namespace Microsoft.CodeAnalysis.CSharp /// internal abstract partial class PublicSemanticModel : CSharpSemanticModel { + protected AttributeSemanticModel CreateModelForAttribute(Binder enclosingBinder, AttributeSyntax attribute, MemberSemanticModel containingModel) + { + AliasSymbol aliasOpt; + var attributeType = (NamedTypeSymbol)enclosingBinder.BindType(attribute.Name, BindingDiagnosticBag.Discarded, out aliasOpt).Type; + + // For attributes where a nameof could introduce some type parameters, we need to track the attribute target + Symbol? attributeTarget = getAttributeTarget(attribute.Parent?.Parent); + + return AttributeSemanticModel.Create( + this, + attribute, + attributeType, + aliasOpt, + attributeTarget, + enclosingBinder.WithAdditionalFlags(BinderFlags.AttributeArgument), + containingModel?.GetRemappedSymbols()); + + Symbol? getAttributeTarget(SyntaxNode? targetSyntax) + { + return targetSyntax switch + { + BaseMethodDeclarationSyntax or + LocalFunctionStatementSyntax or + ParameterSyntax or + TypeParameterSyntax or + IndexerDeclarationSyntax or + AccessorDeclarationSyntax or + DelegateDeclarationSyntax => GetDeclaredSymbolForNode(targetSyntax).GetSymbol(), + AnonymousFunctionExpressionSyntax anonymousFunction => GetSymbolInfo(anonymousFunction).Symbol.GetSymbol(), + _ => null + }; + } + } } } diff --git a/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs b/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs index 3f0ec4cb2d444..a82bd95e1c846 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { @@ -18,6 +19,7 @@ internal sealed class SpeculativeSemanticModelWithMemberModel : PublicSemanticMo private readonly int _position; private readonly NullableWalker.SnapshotManager? _parentSnapshotManagerOpt; private readonly MemberSemanticModel _memberModel; + private ImmutableDictionary _childMemberModels = ImmutableDictionary.Empty; private SpeculativeSemanticModelWithMemberModel( SyntaxTreeSemanticModel parentSemanticModel, @@ -113,9 +115,88 @@ public SpeculativeSemanticModelWithMemberModel( internal sealed override SemanticModel ContainingModelOrSelf => this; + private MemberSemanticModel GetEnclosingMemberModel(int position) + { + AssertPositionAdjusted(position); + SyntaxNode? node = Root.FindTokenIncludingCrefAndNameAttributes(position).Parent; + return node is null ? _memberModel : GetEnclosingMemberModel(node); + } + + private MemberSemanticModel GetEnclosingMemberModel(SyntaxNode node) + { + if (node.SyntaxTree != SyntaxTree) + { + return _memberModel; + } + + var attributeOrParameter = node.FirstAncestorOrSelf(static n => n.Kind() is SyntaxKind.Attribute or SyntaxKind.Parameter); + + if (attributeOrParameter is null || + attributeOrParameter == Root || + attributeOrParameter.Parent is null || + !Root.Span.Contains(attributeOrParameter.Span)) + { + return _memberModel; + } + + MemberSemanticModel containing = GetEnclosingMemberModel(attributeOrParameter.Parent); + + switch (attributeOrParameter) + { + case AttributeSyntax attribute: + + return GetOrAddModelForAttribute(containing, attribute); + + case ParameterSyntax paramDecl: + + return GetOrAddModelForParameter(node, containing, paramDecl); + + default: + ExceptionUtilities.UnexpectedValue(attributeOrParameter); + return containing; + } + } + + private MemberSemanticModel GetOrAddModelForAttribute(MemberSemanticModel containing, AttributeSyntax attribute) + { + return ImmutableInterlocked.GetOrAdd(ref _childMemberModels, attribute, + (node, binderAndModel) => CreateModelForAttribute(binderAndModel.binder, (AttributeSyntax)node, binderAndModel.model), + (binder: containing.GetEnclosingBinder(attribute.SpanStart), model: containing)); + } + + private MemberSemanticModel GetOrAddModelForParameter(SyntaxNode node, MemberSemanticModel containing, ParameterSyntax paramDecl) + { + EqualsValueClauseSyntax? defaultValueSyntax = paramDecl.Default; + + if (defaultValueSyntax != null && defaultValueSyntax.FullSpan.Contains(node.Span)) + { + var parameterSymbol = containing.GetDeclaredSymbol(paramDecl).GetSymbol(); + if ((object)parameterSymbol != null) + { + return ImmutableInterlocked.GetOrAdd(ref _childMemberModels, defaultValueSyntax, + (equalsValue, tuple) => + InitializerSemanticModel.Create( + this, + tuple.paramDecl, + tuple.parameterSymbol, + tuple.containing.GetEnclosingBinder(tuple.paramDecl.SpanStart). + CreateBinderForParameterDefaultValue(tuple.parameterSymbol, + (EqualsValueClauseSyntax)equalsValue), + tuple.containing.GetRemappedSymbols()), + (compilation: this.Compilation, + paramDecl, + parameterSymbol, + containing) + ); + } + } + + return containing; + } + internal override MemberSemanticModel GetMemberModel(SyntaxNode node) { - return _memberModel.GetMemberModel(node); + return GetEnclosingMemberModel(node).GetMemberModel(node); } public override Conversion ClassifyConversion( @@ -123,119 +204,119 @@ public override Conversion ClassifyConversion( ITypeSymbol destination, bool isExplicitInSource = false) { - return _memberModel.ClassifyConversion(expression, destination, isExplicitInSource); + return GetEnclosingMemberModel(expression).ClassifyConversion(expression, destination, isExplicitInSource); } internal override Conversion ClassifyConversionForCast( ExpressionSyntax expression, TypeSymbol destination) { - return _memberModel.ClassifyConversionForCast(expression, destination); + return GetEnclosingMemberModel(expression).ClassifyConversionForCast(expression, destination); } public override ImmutableArray GetSyntaxDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetSyntaxDiagnostics(span, cancellationToken); + throw new NotSupportedException(); } public override ImmutableArray GetDeclarationDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclarationDiagnostics(span, cancellationToken); + throw new NotSupportedException(); } public override ImmutableArray GetMethodBodyDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetMethodBodyDiagnostics(span, cancellationToken); + throw new NotSupportedException(); } public override ImmutableArray GetDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDiagnostics(span, cancellationToken); + throw new NotSupportedException(); } public override INamespaceSymbol GetDeclaredSymbol(NamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override INamespaceSymbol GetDeclaredSymbol(FileScopedNamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override INamedTypeSymbol GetDeclaredSymbol(BaseTypeDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override INamedTypeSymbol GetDeclaredSymbol(DelegateDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IFieldSymbol GetDeclaredSymbol(EnumMemberDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override ISymbol GetDeclaredSymbol(LocalFunctionStatementSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override ISymbol GetDeclaredSymbol(MemberDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IMethodSymbol GetDeclaredSymbol(CompilationUnitSyntax declarationSyntax, CancellationToken cancellationToken = default) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IMethodSymbol GetDeclaredSymbol(BaseMethodDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override ISymbol GetDeclaredSymbol(BasePropertyDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IPropertySymbol GetDeclaredSymbol(PropertyDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IPropertySymbol GetDeclaredSymbol(IndexerDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IEventSymbol GetDeclaredSymbol(EventDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IMethodSymbol GetDeclaredSymbol(AccessorDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IMethodSymbol GetDeclaredSymbol(ArrowExpressionClauseSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override ISymbol GetDeclaredSymbol(VariableDeclaratorSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override ISymbol GetDeclaredSymbol(SingleVariableDesignationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } internal override LocalSymbol GetAdjustedLocalSymbol(SourceLocalSymbol local) @@ -245,157 +326,157 @@ internal override LocalSymbol GetAdjustedLocalSymbol(SourceLocalSymbol local) public override ILabelSymbol GetDeclaredSymbol(LabeledStatementSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override ILabelSymbol GetDeclaredSymbol(SwitchLabelSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IAliasSymbol GetDeclaredSymbol(UsingDirectiveSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IAliasSymbol GetDeclaredSymbol(ExternAliasDirectiveSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } public override IParameterSymbol GetDeclaredSymbol(ParameterSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbol(declarationSyntax, cancellationToken); } internal override ImmutableArray GetDeclaredSymbols(BaseFieldDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbols(declarationSyntax, cancellationToken); + return GetEnclosingMemberModel(declarationSyntax).GetDeclaredSymbols(declarationSyntax, cancellationToken); } public override ITypeParameterSymbol GetDeclaredSymbol(TypeParameterSyntax typeParameter, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(typeParameter, cancellationToken); + return GetEnclosingMemberModel(typeParameter).GetDeclaredSymbol(typeParameter, cancellationToken); } public override IRangeVariableSymbol GetDeclaredSymbol(JoinIntoClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(node, cancellationToken); + return GetEnclosingMemberModel(node).GetDeclaredSymbol(node, cancellationToken); } public override IRangeVariableSymbol GetDeclaredSymbol(QueryClauseSyntax queryClause, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(queryClause, cancellationToken); + return GetEnclosingMemberModel(queryClause).GetDeclaredSymbol(queryClause, cancellationToken); } public override IRangeVariableSymbol GetDeclaredSymbol(QueryContinuationSyntax node, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(node, cancellationToken); + return GetEnclosingMemberModel(node).GetDeclaredSymbol(node, cancellationToken); } public override AwaitExpressionInfo GetAwaitExpressionInfo(AwaitExpressionSyntax node) { - return _memberModel.GetAwaitExpressionInfo(node); + return GetEnclosingMemberModel(node).GetAwaitExpressionInfo(node); } public override ForEachStatementInfo GetForEachStatementInfo(ForEachStatementSyntax node) { - return _memberModel.GetForEachStatementInfo(node); + return GetEnclosingMemberModel(node).GetForEachStatementInfo(node); } public override ForEachStatementInfo GetForEachStatementInfo(CommonForEachStatementSyntax node) { - return _memberModel.GetForEachStatementInfo(node); + return GetEnclosingMemberModel(node).GetForEachStatementInfo(node); } public override DeconstructionInfo GetDeconstructionInfo(AssignmentExpressionSyntax node) { - return _memberModel.GetDeconstructionInfo(node); + return GetEnclosingMemberModel(node).GetDeconstructionInfo(node); } public override DeconstructionInfo GetDeconstructionInfo(ForEachVariableStatementSyntax node) { - return _memberModel.GetDeconstructionInfo(node); + return GetEnclosingMemberModel(node).GetDeconstructionInfo(node); } public override QueryClauseInfo GetQueryClauseInfo(QueryClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetQueryClauseInfo(node, cancellationToken); + return GetEnclosingMemberModel(node).GetQueryClauseInfo(node, cancellationToken); } public override IPropertySymbol GetDeclaredSymbol(AnonymousObjectMemberDeclaratorSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declaratorSyntax, cancellationToken); + return GetEnclosingMemberModel(declaratorSyntax).GetDeclaredSymbol(declaratorSyntax, cancellationToken); } public override INamedTypeSymbol GetDeclaredSymbol(AnonymousObjectCreationExpressionSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declaratorSyntax, cancellationToken); + return GetEnclosingMemberModel(declaratorSyntax).GetDeclaredSymbol(declaratorSyntax, cancellationToken); } public override INamedTypeSymbol GetDeclaredSymbol(TupleExpressionSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declaratorSyntax, cancellationToken); + return GetEnclosingMemberModel(declaratorSyntax).GetDeclaredSymbol(declaratorSyntax, cancellationToken); } public override ISymbol GetDeclaredSymbol(ArgumentSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetDeclaredSymbol(declaratorSyntax, cancellationToken); + return GetEnclosingMemberModel(declaratorSyntax).GetDeclaredSymbol(declaratorSyntax, cancellationToken); } internal override IOperation? GetOperationWorker(CSharpSyntaxNode node, CancellationToken cancellationToken) { - return _memberModel.GetOperationWorker(node, cancellationToken); + return GetEnclosingMemberModel(node).GetOperationWorker(node, cancellationToken); } internal override SymbolInfo GetSymbolInfoWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetSymbolInfoWorker(node, options, cancellationToken); + return GetEnclosingMemberModel(node).GetSymbolInfoWorker(node, options, cancellationToken); } internal override CSharpTypeInfo GetTypeInfoWorker(CSharpSyntaxNode node, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetTypeInfoWorker(node, cancellationToken); + return GetEnclosingMemberModel(node).GetTypeInfoWorker(node, cancellationToken); } internal override ImmutableArray GetMemberGroupWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetMemberGroupWorker(node, options, cancellationToken); + return GetEnclosingMemberModel(node).GetMemberGroupWorker(node, options, cancellationToken); } internal override ImmutableArray GetIndexerGroupWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetIndexerGroupWorker(node, options, cancellationToken); + return GetEnclosingMemberModel(node).GetIndexerGroupWorker(node, options, cancellationToken); } internal override Optional GetConstantValueWorker(CSharpSyntaxNode node, CancellationToken cancellationToken) { - return _memberModel.GetConstantValueWorker(node, cancellationToken); + return GetEnclosingMemberModel(node).GetConstantValueWorker(node, cancellationToken); } internal override SymbolInfo GetCollectionInitializerSymbolInfoWorker(InitializerExpressionSyntax collectionInitializer, ExpressionSyntax node, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetCollectionInitializerSymbolInfoWorker(collectionInitializer, node, cancellationToken); + return GetEnclosingMemberModel(collectionInitializer).GetCollectionInitializerSymbolInfoWorker(collectionInitializer, node, cancellationToken); } public override SymbolInfo GetSymbolInfo(OrderingSyntax node, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetSymbolInfo(node, cancellationToken); + return GetEnclosingMemberModel(node).GetSymbolInfo(node, cancellationToken); } public override SymbolInfo GetSymbolInfo(SelectOrGroupClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetSymbolInfo(node, cancellationToken); + return GetEnclosingMemberModel(node).GetSymbolInfo(node, cancellationToken); } public override TypeInfo GetTypeInfo(SelectOrGroupClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken)) { - return _memberModel.GetTypeInfo(node, cancellationToken); + return GetEnclosingMemberModel(node).GetTypeInfo(node, cancellationToken); } internal override Binder GetEnclosingBinderInternal(int position) { - return _memberModel.GetEnclosingBinderInternal(position); + return GetEnclosingMemberModel(position).GetEnclosingBinderInternal(position); } internal override Symbol RemapSymbolIfNecessaryCore(Symbol symbol) @@ -405,67 +486,67 @@ internal override Symbol RemapSymbolIfNecessaryCore(Symbol symbol) internal sealed override Func GetSyntaxNodesToAnalyzeFilter(SyntaxNode declaredNode, ISymbol declaredSymbol) { - return _memberModel.GetSyntaxNodesToAnalyzeFilter(declaredNode, declaredSymbol); + throw ExceptionUtilities.Unreachable(); } internal override bool ShouldSkipSyntaxNodeAnalysis(SyntaxNode node, ISymbol containingSymbol) { - return _memberModel.ShouldSkipSyntaxNodeAnalysis(node, containingSymbol); + throw ExceptionUtilities.Unreachable(); } internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, BindingDiagnosticBag diagnostics) { - return _memberModel.Bind(binder, node, diagnostics); + return GetEnclosingMemberModel(node).Bind(binder, node, diagnostics); } internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out PublicSemanticModel? speculativeModel) { - return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, constructorInitializer, out speculativeModel); + throw ExceptionUtilities.Unreachable(); } internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out PublicSemanticModel? speculativeModel) { - return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, constructorInitializer, out speculativeModel); + throw ExceptionUtilities.Unreachable(); } internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out PublicSemanticModel? speculativeModel) { - return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, initializer, out speculativeModel); + throw ExceptionUtilities.Unreachable(); } internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out PublicSemanticModel? speculativeModel) { - return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, expressionBody, out speculativeModel); + throw ExceptionUtilities.Unreachable(); } internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out PublicSemanticModel? speculativeModel) { - return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, statement, out speculativeModel); + throw ExceptionUtilities.Unreachable(); } internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out PublicSemanticModel? speculativeModel) { - return _memberModel.TryGetSpeculativeSemanticModelForMethodBodyCore(parentModel, position, method, out speculativeModel); + throw ExceptionUtilities.Unreachable(); } internal override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out PublicSemanticModel? speculativeModel) { - return _memberModel.TryGetSpeculativeSemanticModelForMethodBodyCore(parentModel, position, accessor, out speculativeModel); + throw ExceptionUtilities.Unreachable(); } internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, TypeSyntax type, SpeculativeBindingOption bindingOption, out PublicSemanticModel speculativeModel) { - return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, type, bindingOption, out speculativeModel); + throw ExceptionUtilities.Unreachable(); } internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CrefSyntax crefSyntax, out PublicSemanticModel speculativeModel) { - return _memberModel.TryGetSpeculativeSemanticModelCore(parentModel, position, crefSyntax, out speculativeModel); + throw ExceptionUtilities.Unreachable(); } internal override BoundExpression GetSpeculativelyBoundExpression(int position, ExpressionSyntax expression, SpeculativeBindingOption bindingOption, out Binder binder, out ImmutableArray crefSymbols) { - return _memberModel.GetSpeculativelyBoundExpression(position, expression, bindingOption, out binder, out crefSymbols); + return GetEnclosingMemberModel(CheckAndAdjustPosition(position)).GetSpeculativelyBoundExpression(position, expression, bindingOption, out binder, out crefSymbols); } } } diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs index e74c97837b61b..82d675320ceb9 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs @@ -1264,40 +1264,6 @@ private SynthesizedRecordConstructor TryGetSynthesizedRecordConstructor(RecordDe return symbol; } - private AttributeSemanticModel CreateModelForAttribute(Binder enclosingBinder, AttributeSyntax attribute, MemberSemanticModel containingModel) - { - AliasSymbol aliasOpt; - var attributeType = (NamedTypeSymbol)enclosingBinder.BindType(attribute.Name, BindingDiagnosticBag.Discarded, out aliasOpt).Type; - - // For attributes where a nameof could introduce some type parameters, we need to track the attribute target - Symbol attributeTarget = getAttributeTarget(attribute.Parent.Parent); - - return AttributeSemanticModel.Create( - this, - attribute, - attributeType, - aliasOpt, - attributeTarget, - enclosingBinder.WithAdditionalFlags(BinderFlags.AttributeArgument), - containingModel?.GetRemappedSymbols()); - - Symbol getAttributeTarget(SyntaxNode targetSyntax) - { - return targetSyntax switch - { - BaseMethodDeclarationSyntax or - LocalFunctionStatementSyntax or - ParameterSyntax or - TypeParameterSyntax or - IndexerDeclarationSyntax or - AccessorDeclarationSyntax or - DelegateDeclarationSyntax => GetDeclaredSymbolForNode(targetSyntax).GetSymbol(), - AnonymousFunctionExpressionSyntax anonymousFunction => GetSymbolInfo(anonymousFunction).Symbol.GetSymbol(), - _ => null - }; - } - } - private FieldSymbol GetDeclaredFieldSymbol(VariableDeclaratorSyntax variableDecl) { var declaredSymbol = GetDeclaredSymbol(variableDecl); diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs index 12e1c07526559..546fee9f6fd40 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs @@ -602,7 +602,7 @@ private ImmutableArray GetAttributesToBind( var binder = rootBinderOpt ?? compilation.GetBinderFactory(syntaxTree).GetBinder(attributeDeclarationSyntaxList.Node); binder = new ContextualAttributeBinder(binder, this); - Debug.Assert(!binder.InAttributeArgument || this is MethodSymbol { MethodKind: MethodKind.LambdaMethod }, "Possible cycle in attribute binding"); + Debug.Assert(!binder.InAttributeArgument || this is MethodSymbol { MethodKind: MethodKind.LambdaMethod or MethodKind.LocalFunction }, "Possible cycle in attribute binding"); for (int i = 0; i < attributesToBindCount - prevCount; i++) { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 8d107c0a61c3a..e58695735ae17 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -3913,10 +3913,8 @@ static void Main() a = (IdentifierNameSyntax)newTree.GetRoot().DescendantNodes().OfType().Single().Name; Assert.Equal("A", a.Identifier.Text); - // If we aren't using the right binder here, the compiler crashes going through the binder factory var info = model.GetSymbolInfo(a); - // This behavior is wrong. See https://github.com/dotnet/roslyn/issues/24135 - Assert.Equal(attrType, info.Symbol); + Assert.Equal(attrCtor, info.Symbol); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index af37149cd8be9..6056790c0a50e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -409,10 +409,8 @@ static void M() a = newTree.GetRoot().DescendantNodes().OfType().ElementAt(2); Assert.Equal("A", a.Identifier.Text); - // If we aren't using the right binder here, the compiler crashes going through the binder factory var info = model.GetSymbolInfo(a); - // This behavior is wrong. See https://github.com/dotnet/roslyn/issues/24135 - Assert.Equal(attrType, info.Symbol); + Assert.Equal(attrCtor, info.Symbol); } [Theory] @@ -8599,6 +8597,7 @@ private void VerifyParameter(CSharpCompilation comp, int index, string expectedM } [Fact] + [WorkItem(60801, "https://github.com/dotnet/roslyn/issues/60801")] public void ParameterScope_InMethodAttributeNameOf_GetSymbolInfoOnSpeculativeMethodBodySemanticModel() { var source = @" diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs index 690df32f2800d..c73229ed17116 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs @@ -36243,6 +36243,182 @@ public static void Test3(this Cls x) {} var node = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "Test3").Last(); Assert.True(model.GetSymbolInfo(node).IsEmpty); } + + [Fact] + [WorkItem(60801, "https://github.com/dotnet/roslyn/issues/60801")] + public void GetSymbolInfoOnSpeculativeMethodBodySemanticModelInAttribute_01() + { + var source = @" +class C +{ + void M() + { + [My(M2(out var x))] + void local(int parameter) { } + } + + static string M2(out int x) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,13): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [My(M2(out var x))] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "M2(out var x)").WithLocation(6, 13), + // (7,14): warning CS8321: The local function 'local' is declared but never used + // void local(int parameter) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(7, 14) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var tree2 = CSharpSyntaxTree.ParseText(source); + var method = tree2.GetRoot().DescendantNodes().OfType().First(); + Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(method.Body.SpanStart, method, out var speculativeModel)); + + var invocation = tree2.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal("M2(out var x)", invocation.ToString()); + var symbolInfo = speculativeModel.GetSymbolInfo(invocation); + Assert.Equal("System.String C.M2(out System.Int32 x)", symbolInfo.Symbol.ToTestDisplayString()); + + Assert.True(model.TryGetSpeculativeSemanticModel(method.Body.SpanStart + 1, method.DescendantNodes().OfType().Single(), out speculativeModel)); + symbolInfo = speculativeModel.GetSymbolInfo(invocation); + Assert.Equal("System.String C.M2(out System.Int32 x)", symbolInfo.Symbol.ToTestDisplayString()); + } + + + [Fact] + [WorkItem(60801, "https://github.com/dotnet/roslyn/issues/60801")] + public void GetSymbolInfoOnSpeculativeMethodBodySemanticModelInAttribute_02() + { + var source = @" +class C +{ + void M() + { + [My(() => { [My(M2(out var x))] static string M2(out int x) => throw null; })] + void local(int parameter) { } + } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,13): error CS1660: Cannot convert lambda expression to type 'string' because it is not a delegate type + // [My(() => { [My(M2(out var x))] static string M2(out int x) => throw null; })] + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => { [My(M2(out var x))] static string M2(out int x) => throw null; }").WithArguments("lambda expression", "string").WithLocation(6, 13), + // (7,14): warning CS8321: The local function 'local' is declared but never used + // void local(int parameter) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(7, 14) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var tree2 = CSharpSyntaxTree.ParseText(source); + var method = tree2.GetRoot().DescendantNodes().OfType().First(); + Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(method.Body.SpanStart, method, out var speculativeModel)); + + var invocation = tree2.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal("M2(out var x)", invocation.ToString()); + var symbolInfo = speculativeModel.GetSymbolInfo(invocation); + Assert.Equal("System.String M2(out System.Int32 x)", symbolInfo.Symbol.ToTestDisplayString()); + Assert.Same(symbolInfo.Symbol, speculativeModel.GetDeclaredSymbol(tree2.GetRoot().DescendantNodes().OfType().Where(l => l.Identifier.ValueText == "M2").Single())); + } + + [Fact] + [WorkItem(60801, "https://github.com/dotnet/roslyn/issues/60801")] + public void GetSymbolInfoOnSpeculativeMethodBodySemanticModelInDefaultParameterValue_01() + { + var source = @" +class C +{ + void M() + { + void local(string parameter = M2(out var x)) { } + } + + static string M2(out int x) => throw null; +} +"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,14): warning CS8321: The local function 'local' is declared but never used + // void local(string parameter = M2(out var x)) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(6, 14), + // (6,39): error CS1736: Default parameter value for 'parameter' must be a compile-time constant + // void local(string parameter = M2(out var x)) { } + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "M2(out var x)").WithArguments("parameter").WithLocation(6, 39) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var tree2 = CSharpSyntaxTree.ParseText(source); + var method = tree2.GetRoot().DescendantNodes().OfType().First(); + Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(method.Body.SpanStart, method, out var speculativeModel)); + + var invocation = tree2.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal("M2(out var x)", invocation.ToString()); + var symbolInfo = speculativeModel.GetSymbolInfo(invocation); + Assert.Equal("System.String C.M2(out System.Int32 x)", symbolInfo.Symbol.ToTestDisplayString()); + + var equalsValue = method.DescendantNodes().OfType().Single(); + Assert.True(model.TryGetSpeculativeSemanticModel(equalsValue.Value.SpanStart, equalsValue, out speculativeModel)); + symbolInfo = speculativeModel.GetSymbolInfo(invocation); + Assert.Equal("System.String C.M2(out System.Int32 x)", symbolInfo.Symbol.ToTestDisplayString()); + } + + [Fact] + [WorkItem(60801, "https://github.com/dotnet/roslyn/issues/60801")] + public void GetSymbolInfoOnSpeculativeMethodBodySemanticModelInDefaultParameterValue_02() + { + var source = @" +class C +{ + void M() + { + void local(string parameter = () => { static string M2(out int x, string y = M2(out var a, ""b"")) => throw null; }) { } + } +} +"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,14): warning CS8321: The local function 'local' is declared but never used + // void local(string parameter = M2(out var x)) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(6, 14), + // (6,39): error CS1736: Default parameter value for 'parameter' must be a compile-time constant + // void local(string parameter = () => { static string M2(out int x, string y = M2(out var a, "b")) => throw null; }) { } + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, @"() => { static string M2(out int x, string y = M2(out var a, ""b"")) => throw null; }").WithArguments("parameter").WithLocation(6, 39) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var tree2 = CSharpSyntaxTree.ParseText(source); + var method = tree2.GetRoot().DescendantNodes().OfType().First(); + Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(method.Body.SpanStart, method, out var speculativeModel)); + + var invocation = tree2.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal(@"M2(out var a, ""b"")", invocation.ToString()); + var symbolInfo = speculativeModel.GetSymbolInfo(invocation); + Assert.Equal("System.String M2(out System.Int32 x, [System.String y = null])", symbolInfo.Symbol.ToTestDisplayString()); + Assert.Same(symbolInfo.Symbol, speculativeModel.GetDeclaredSymbol(tree2.GetRoot().DescendantNodes().OfType().Where(l => l.Identifier.ValueText == "M2").Single())); + } } internal static class OutVarTestsExtensions diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs index bee35e1ae54c6..03b8ebcd22c45 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs @@ -11804,11 +11804,9 @@ void local(int parameter) { } } } "; - // Speculation within attributes on local functions is broken - // Tracked by https://github.com/dotnet/roslyn/issues/60801 - await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); + await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); - await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter", skipSpeculation: true); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); } [Fact] @@ -11823,11 +11821,9 @@ void local([Some(nameof(p$$))] int parameter) { } } } "; - // Speculation within attributes on local functions is broken - // Tracked by https://github.com/dotnet/roslyn/issues/60801 - await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); + await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); - await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter", skipSpeculation: true); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); } [Fact] @@ -11842,11 +11838,9 @@ void M() } } "; - // Speculation within attributes on local functions is broken - // Tracked by https://github.com/dotnet/roslyn/issues/60801 - await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); + await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); - await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter", skipSpeculation: true); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); } [Fact] @@ -11861,11 +11855,9 @@ void M() } } "; - // Speculation within attributes on local functions is broken - // Tracked by https://github.com/dotnet/roslyn/issues/60801 - await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); + await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); - await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter", skipSpeculation: true); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); } [Fact] @@ -11886,11 +11878,9 @@ public async Task ParameterAvailableInDelegateParameterAttributeNameof() var source = @" delegate void MyDelegate([Some(nameof(p$$))] int parameter); "; - // Speculation within attributes on local functions is broken - // Tracked by https://github.com/dotnet/roslyn/issues/60801 - await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); + await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); - await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter", skipSpeculation: true); + await VerifyItemExistsAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); } private static string MakeMarkup(string source, string languageVersion = "Preview") From 3b01a499807ae7d35a165e6a2c3247be20b9d190 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Wed, 12 Oct 2022 17:58:19 -0700 Subject: [PATCH 3/4] Follow up on merge from main --- .../Compilation/AttributeSemanticModel.cs | 22 ------------------- ...SpeculativeSemanticModelWithMemberModel.cs | 15 ++++++++++++- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs index a09498f1cf1da..83583bdb01dd3 100644 --- a/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs @@ -47,29 +47,7 @@ public static AttributeSemanticModel Create(PublicSemanticModel containingSemant /// public static SpeculativeSemanticModelWithMemberModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Binder rootBinder, ImmutableDictionary parentRemappedSymbolsOpt, int position) { -<<<<<<< HEAD return new SpeculativeSemanticModelWithMemberModel(parentSemanticModel, position, syntax, attributeType, aliasOpt, rootBinder, parentRemappedSymbolsOpt); -======= - Debug.Assert(parentSemanticModel != null); - Debug.Assert(rootBinder != null); - Debug.Assert(rootBinder.IsSemanticModelBinder); - - var attributeTarget = GetAttributeTargetFromPosition(position, parentSemanticModel); - return new AttributeSemanticModel(syntax, attributeType, attributeTarget, aliasOpt, rootBinder, parentSemanticModelOpt: parentSemanticModel, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt, speculatedPosition: position); - } - - private static Symbol? GetAttributeTargetFromPosition(int position, SemanticModel model) - { - var attributedNode = model.SyntaxTree.GetRoot().FindToken(position).Parent; - attributedNode = attributedNode?.FirstAncestorOrSelf()?.Parent; - - if (attributedNode is not null) - { - return model.GetDeclaredSymbolForNode(attributedNode).GetSymbol(); - } - - return null; ->>>>>>> dotnet/main } private NamedTypeSymbol AttributeType diff --git a/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs b/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs index a82bd95e1c846..b21250ffe787a 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs @@ -48,7 +48,20 @@ public SpeculativeSemanticModelWithMemberModel( Debug.Assert(rootBinder != null); Debug.Assert(rootBinder.IsSemanticModelBinder); - _memberModel = new AttributeSemanticModel(syntax, attributeType, aliasOpt, rootBinder, containingPublicSemanticModel: this, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt); + _memberModel = new AttributeSemanticModel(syntax, attributeType, getAttributeTargetFromPosition(position, parentSemanticModel), aliasOpt, rootBinder, containingPublicSemanticModel: this, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt); + + static Symbol? getAttributeTargetFromPosition(int position, SyntaxTreeSemanticModel model) + { + var attributedNode = model.SyntaxTree.GetRoot().FindToken(position).Parent; + attributedNode = attributedNode?.FirstAncestorOrSelf()?.Parent; + + if (attributedNode is not null) + { + return model.GetDeclaredSymbolForNode(attributedNode).GetSymbol(); + } + + return null; + } } public SpeculativeSemanticModelWithMemberModel( From 239fa2c4c6bc8fb01a5500eb36c66355ec2ccf6f Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Fri, 14 Oct 2022 07:56:47 -0700 Subject: [PATCH 4/4] PR feedback --- .../CSharp/Portable/Compilation/PublicSemanticModel.cs | 2 ++ .../Compilation/SpeculativeSemanticModelWithMemberModel.cs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs index 40be8f1f51287..97d55376026f3 100644 --- a/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs @@ -9,6 +9,8 @@ namespace Microsoft.CodeAnalysis.CSharp { /// /// Instances of this can be exposed to external consumers. + /// Other types of are not designed for direct exposure + /// and their implementation might not be able to handle external requests properly. /// internal abstract partial class PublicSemanticModel : CSharpSemanticModel { diff --git a/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs b/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs index b21250ffe787a..d2144644ae53a 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SpeculativeSemanticModelWithMemberModel.cs @@ -12,7 +12,10 @@ namespace Microsoft.CodeAnalysis.CSharp { - + /// + /// Instances of this type represent user-facing speculative semantic models that are backed by + /// internal . + /// internal sealed class SpeculativeSemanticModelWithMemberModel : PublicSemanticModel { private readonly SyntaxTreeSemanticModel _parentSemanticModel;