Skip to content

Commit

Permalink
Speculative semantic model - create child member models for attribute…
Browse files Browse the repository at this point in the history
…s and parameter default values. (#64634)

Part 1. 
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.
Now we expose ```SpeculativeSemanticModelWithMemberModel``` instead 

Part 2.
SpeculativeSemanticModelWithMemberModel - create child member models for attributes and parameter default values.

Fixes #60801.
Fixes #24135.
  • Loading branch information
AlekseyTs authored Oct 14, 2022
1 parent 87ececb commit c12de00
Show file tree
Hide file tree
Showing 19 changed files with 976 additions and 253 deletions.
7 changes: 0 additions & 7 deletions src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
48 changes: 14 additions & 34 deletions src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,15 @@ internal sealed class AttributeSemanticModel : MemberSemanticModel
private readonly AliasSymbol _aliasOpt;
private readonly Symbol? _attributeTarget;

private AttributeSemanticModel(
internal AttributeSemanticModel(
AttributeSyntax syntax,
NamedTypeSymbol attributeType,
Symbol? attributeTarget,
AliasSymbol aliasOpt,
Binder rootBinder,
SyntaxTreeSemanticModel? containingSemanticModelOpt = null,
SyntaxTreeSemanticModel? parentSemanticModelOpt = null,
ImmutableDictionary<Symbol, Symbol>? parentRemappedSymbolsOpt = null,
int speculatedPosition = 0)
: base(syntax, attributeType, new ExecutableCodeBinder(syntax, rootBinder.ContainingMember(), rootBinder), containingSemanticModelOpt, parentSemanticModelOpt, snapshotManagerOpt: null, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt, speculatedPosition)
PublicSemanticModel containingPublicSemanticModel,
ImmutableDictionary<Symbol, Symbol>? parentRemappedSymbolsOpt = null)
: base(syntax, attributeType, new ExecutableCodeBinder(syntax, rootBinder.ContainingMember(), rootBinder), containingPublicSemanticModel, parentRemappedSymbolsOpt)
{
Debug.Assert(syntax != null);
_aliasOpt = aliasOpt;
Expand All @@ -38,7 +36,7 @@ private AttributeSemanticModel(
/// <summary>
/// Creates an AttributeSemanticModel that allows asking semantic questions about an attribute node.
/// </summary>
public static AttributeSemanticModel Create(SyntaxTreeSemanticModel containingSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Symbol? attributeTarget, Binder rootBinder, ImmutableDictionary<Symbol, Symbol> parentRemappedSymbolsOpt)
public static AttributeSemanticModel Create(PublicSemanticModel containingSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Symbol? attributeTarget, Binder rootBinder, ImmutableDictionary<Symbol, Symbol>? parentRemappedSymbolsOpt)
{
rootBinder = attributeTarget is null ? rootBinder : new ContextualAttributeBinder(rootBinder, attributeTarget);
return new AttributeSemanticModel(syntax, attributeType, attributeTarget, aliasOpt, rootBinder, containingSemanticModel, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt);
Expand All @@ -47,27 +45,9 @@ public static AttributeSemanticModel Create(SyntaxTreeSemanticModel containingSe
/// <summary>
/// Creates a speculative AttributeSemanticModel that allows asking semantic questions about an attribute node that did not appear in the original source code.
/// </summary>
public static AttributeSemanticModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Binder rootBinder, ImmutableDictionary<Symbol, Symbol> parentRemappedSymbolsOpt, int position)
public static SpeculativeSemanticModelWithMemberModel CreateSpeculative(SyntaxTreeSemanticModel parentSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Binder rootBinder, ImmutableDictionary<Symbol, Symbol> parentRemappedSymbolsOpt, int position)
{
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<AttributeListSyntax>()?.Parent;

if (attributedNode is not null)
{
return model.GetDeclaredSymbolForNode(attributedNode).GetSymbol();
}

return null;
return new SpeculativeSemanticModelWithMemberModel(parentSemanticModel, position, syntax, attributeType, aliasOpt, rootBinder, parentRemappedSymbolsOpt);
}

private NamedTypeSymbol AttributeType
Expand Down Expand Up @@ -145,43 +125,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;
Expand Down
54 changes: 36 additions & 18 deletions src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/// <summary>
/// Get a SemanticModel object that is associated with a method body that did not appear in this source code.
Expand All @@ -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);

/// <summary>
/// Get a SemanticModel object that is associated with a type syntax node that did not appear in
Expand All @@ -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);

/// <summary>
/// Get a SemanticModel object that is associated with a statement that did not appear in
Expand All @@ -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);

/// <summary>
/// Get a SemanticModel object that is associated with an initializer that did not appear in
Expand All @@ -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);

/// <summary>
/// Get a SemanticModel object that is associated with an expression body that did not appear in
Expand All @@ -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);

/// <summary>
/// Get a SemanticModel object that is associated with a constructor initializer that did not appear in
Expand All @@ -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);

/// <summary>
/// Get a SemanticModel object that is associated with a constructor initializer that did not appear in
Expand All @@ -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);

/// <summary>
/// Get a SemanticModel object that is associated with a cref that did not appear in
Expand All @@ -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);

/// <summary>
/// Get a SemanticModel object that is associated with an attribute that did not appear in
Expand Down
Loading

0 comments on commit c12de00

Please sign in to comment.