|
// 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.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// Allows asking semantic questions about a tree of syntax nodes in a Compilation. Typically,
/// an instance is obtained by a call to <see cref="Compilation.GetSemanticModel(SyntaxTree, SemanticModelOptions)"/>.
/// </summary>
/// <remarks>
/// <para>An instance of SemanticModel caches local symbols and semantic information. Thus, it
/// is much more efficient to use a single instance of SemanticModel when asking multiple
/// questions about a syntax tree, because information from the first question may be reused.
/// This also means that holding onto an instance of SemanticModel for a long time may keep a
/// significant amount of memory from being garbage collected.
/// </para>
/// <para>
/// When an answer is a named symbol that is reachable by traversing from the root of the symbol
/// table, (that is, from an AssemblySymbol of the Compilation), that symbol will be returned
/// (i.e. the returned value will be reference-equal to one reachable from the root of the
/// symbol table). Symbols representing entities without names (e.g. array-of-int) may or may
/// not exhibit reference equality. However, some named symbols (such as local variables) are
/// not reachable from the root. These symbols are visible as answers to semantic questions.
/// When the same SemanticModel object is used, the answers exhibit reference-equality.
/// </para>
/// </remarks>
public abstract class SemanticModel
{
/// <summary>
/// Gets the source language ("C#" or "Visual Basic").
/// </summary>
public abstract string Language { get; }
/// <summary>
/// The compilation this model was obtained from.
/// </summary>
public Compilation Compilation
{
get { return CompilationCore; }
}
/// <summary>
/// The compilation this model was obtained from.
/// </summary>
protected abstract Compilation CompilationCore { get; }
/// <summary>
/// The syntax tree this model was obtained from.
/// </summary>
public SyntaxTree SyntaxTree
{
get { return SyntaxTreeCore; }
}
/// <summary>
/// The syntax tree this model was obtained from.
/// </summary>
protected abstract SyntaxTree SyntaxTreeCore { get; }
/// <summary>
/// Gets the operation corresponding to the expression or statement syntax node.
/// </summary>
/// <param name="node">The expression or statement syntax node.</param>
/// <param name="cancellationToken">An optional cancellation token.</param>
/// <returns></returns>
public IOperation? GetOperation(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken))
{
return GetOperationCore(node, cancellationToken);
}
protected abstract IOperation? GetOperationCore(SyntaxNode node, CancellationToken cancellationToken);
/// <summary>
/// Returns true if this is a SemanticModel that ignores accessibility rules when answering semantic questions.
/// </summary>
public virtual bool IgnoresAccessibility
{
get { return false; }
}
[Experimental(RoslynExperiments.NullableDisabledSemanticModel, UrlFormat = RoslynExperiments.NullableDisabledSemanticModel_Url)]
public abstract bool NullableAnalysisIsDisabled { get; }
/// <summary>
/// Gets symbol information about a syntax node.
/// </summary>
/// <param name="node">The syntax node to get semantic information for.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the
/// process of obtaining the semantic info.</param>
internal SymbolInfo GetSymbolInfo(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken))
{
return GetSymbolInfoCore(node, cancellationToken);
}
/// <summary>
/// Gets symbol information about a syntax node.
/// </summary>
/// <param name="node">The syntax node to get semantic information for.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the
/// process of obtaining the semantic info.</param>
protected abstract SymbolInfo GetSymbolInfoCore(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Binds the node in the context of the specified location and get semantic information
/// such as type, symbols and diagnostics. This method is used to get semantic information
/// about an expression that did not actually appear in the source code.
/// </summary>
/// <param name="position">A character position used to identify a declaration scope and
/// accessibility. This character position must be within the FullSpan of the Root syntax
/// node in this SemanticModel.
/// </param>
/// <param name="expression">A syntax node that represents a parsed expression. This syntax
/// node need not and typically does not appear in the source code referred to SemanticModel
/// instance.</param>
/// <param name="bindingOption">Indicates whether to binding the expression as a full expressions,
/// or as a type or namespace. If SpeculativeBindingOption.BindAsTypeOrNamespace is supplied, then
/// expression should derive from TypeSyntax.</param>
/// <returns>The semantic information for the topmost node of the expression.</returns>
/// <remarks>The passed in expression is interpreted as a stand-alone expression, as if it
/// appeared by itself somewhere within the scope that encloses "position".</remarks>
internal SymbolInfo GetSpeculativeSymbolInfo(int position, SyntaxNode expression, SpeculativeBindingOption bindingOption)
{
return GetSpeculativeSymbolInfoCore(position, expression, bindingOption);
}
/// <summary>
/// Binds the node in the context of the specified location and get semantic information
/// such as type, symbols and diagnostics. This method is used to get semantic information
/// about an expression that did not actually appear in the source code.
/// </summary>
/// <param name="position">A character position used to identify a declaration scope and
/// accessibility. This character position must be within the FullSpan of the Root syntax
/// node in this SemanticModel.
/// </param>
/// <param name="expression">A syntax node that represents a parsed expression. This syntax
/// node need not and typically does not appear in the source code referred to SemanticModel
/// instance.</param>
/// <param name="bindingOption">Indicates whether to binding the expression as a full expressions,
/// or as a type or namespace. If SpeculativeBindingOption.BindAsTypeOrNamespace is supplied, then
/// expression should derive from TypeSyntax.</param>
/// <returns>The semantic information for the topmost node of the expression.</returns>
/// <remarks>The passed in expression is interpreted as a stand-alone expression, as if it
/// appeared by itself somewhere within the scope that encloses "position".</remarks>
protected abstract SymbolInfo GetSpeculativeSymbolInfoCore(int position, SyntaxNode expression, SpeculativeBindingOption bindingOption);
/// <summary>
/// Binds the node in the context of the specified location and get semantic information
/// such as type, symbols and diagnostics. This method is used to get semantic information
/// about an expression that did not actually appear in the source code.
/// </summary>
/// <param name="position">A character position used to identify a declaration scope and
/// accessibility. This character position must be within the FullSpan of the Root syntax
/// node in this SemanticModel.
/// </param>
/// <param name="expression">A syntax node that represents a parsed expression. This syntax
/// node need not and typically does not appear in the source code referred to SemanticModel
/// instance.</param>
/// <param name="bindingOption">Indicates whether to binding the expression as a full expressions,
/// or as a type or namespace. If SpeculativeBindingOption.BindAsTypeOrNamespace is supplied, then
/// expression should derive from TypeSyntax.</param>
/// <returns>The semantic information for the topmost node of the expression.</returns>
/// <remarks>The passed in expression is interpreted as a stand-alone expression, as if it
/// appeared by itself somewhere within the scope that encloses "position".</remarks>
internal TypeInfo GetSpeculativeTypeInfo(int position, SyntaxNode expression, SpeculativeBindingOption bindingOption)
{
return GetSpeculativeTypeInfoCore(position, expression, bindingOption);
}
/// <summary>
/// Binds the node in the context of the specified location and get semantic information
/// such as type, symbols and diagnostics. This method is used to get semantic information
/// about an expression that did not actually appear in the source code.
/// </summary>
/// <param name="position">A character position used to identify a declaration scope and
/// accessibility. This character position must be within the FullSpan of the Root syntax
/// node in this SemanticModel.
/// </param>
/// <param name="expression">A syntax node that represents a parsed expression. This syntax
/// node need not and typically does not appear in the source code referred to SemanticModel
/// instance.</param>
/// <param name="bindingOption">Indicates whether to binding the expression as a full expressions,
/// or as a type or namespace. If SpeculativeBindingOption.BindAsTypeOrNamespace is supplied, then
/// expression should derive from TypeSyntax.</param>
/// <returns>The semantic information for the topmost node of the expression.</returns>
/// <remarks>The passed in expression is interpreted as a stand-alone expression, as if it
/// appeared by itself somewhere within the scope that encloses "position".</remarks>
protected abstract TypeInfo GetSpeculativeTypeInfoCore(int position, SyntaxNode expression, SpeculativeBindingOption bindingOption);
/// <summary>
/// Gets type information about a syntax node.
/// </summary>
/// <param name="node">The syntax node to get semantic information for.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the
/// process of obtaining the semantic info.</param>
internal TypeInfo GetTypeInfo(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken))
{
return GetTypeInfoCore(node, cancellationToken);
}
/// <summary>
/// Gets type information about a syntax node.
/// </summary>
/// <param name="node">The syntax node to get semantic information for.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the
/// process of obtaining the semantic info.</param>
protected abstract TypeInfo GetTypeInfoCore(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// If "nameSyntax" resolves to an alias name, return the IAliasSymbol corresponding
/// to A. Otherwise return null.
/// </summary>
/// <param name="nameSyntax">Name to get alias info for.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the
/// process of obtaining the alias information.</param>
internal IAliasSymbol? GetAliasInfo(SyntaxNode nameSyntax, CancellationToken cancellationToken = default(CancellationToken))
{
return GetAliasInfoCore(nameSyntax, cancellationToken);
}
/// <summary>
/// If "nameSyntax" resolves to an alias name, return the IAliasSymbol corresponding
/// to A. Otherwise return null.
/// </summary>
/// <param name="nameSyntax">Name to get alias info for.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the
/// process of obtaining the alias information.</param>
protected abstract IAliasSymbol? GetAliasInfoCore(SyntaxNode nameSyntax, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Returns true if this is a speculative semantic model created with any of the TryGetSpeculativeSemanticModel methods.
/// </summary>
[MemberNotNullWhen(true, nameof(ParentModel))]
public abstract bool IsSpeculativeSemanticModel
{
get;
}
/// <summary>
/// If this is a speculative semantic model, returns the original position at which the speculative model was created.
/// Otherwise, returns 0.
/// </summary>
public abstract int OriginalPositionForSpeculation
{
get;
}
/// <summary>
/// If this is a speculative semantic model, then returns its parent semantic model.
/// Otherwise, returns null.
/// </summary>
public SemanticModel? ParentModel
{
get { return this.ParentModelCore; }
}
/// <summary>
/// If this is a speculative semantic model, then returns its parent semantic model.
/// Otherwise, returns null.
/// </summary>
protected abstract SemanticModel? ParentModelCore
{
get;
}
/// <summary>
/// If this is an instance of semantic model that cannot be exposed to external consumers, then returns the containing public semantic model.
/// Otherwise, returns this instance of the semantic model.
/// </summary>
internal abstract SemanticModel ContainingPublicModelOrSelf
{
get;
}
/// <summary>
/// Binds the name in the context of the specified location and sees if it resolves to an
/// alias name. If it does, return the AliasSymbol corresponding to it. Otherwise, return null.
/// </summary>
/// <param name="position">A character position used to identify a declaration scope and
/// accessibility. This character position must be within the FullSpan of the Root syntax
/// node in this SemanticModel.
/// </param>
/// <param name="nameSyntax">A syntax node that represents a name. This syntax
/// node need not and typically does not appear in the source code referred to by the
/// SemanticModel instance.</param>
/// <param name="bindingOption">Indicates whether to binding the name as a full expression,
/// or as a type or namespace. If SpeculativeBindingOption.BindAsTypeOrNamespace is supplied, then
/// expression should derive from TypeSyntax.</param>
/// <remarks>The passed in name is interpreted as a stand-alone name, as if it
/// appeared by itself somewhere within the scope that encloses "position".</remarks>
internal IAliasSymbol? GetSpeculativeAliasInfo(int position, SyntaxNode nameSyntax, SpeculativeBindingOption bindingOption)
{
return GetSpeculativeAliasInfoCore(position, nameSyntax, bindingOption);
}
/// <summary>
/// Binds the name in the context of the specified location and sees if it resolves to an
/// alias name. If it does, return the AliasSymbol corresponding to it. Otherwise, return null.
/// </summary>
/// <param name="position">A character position used to identify a declaration scope and
/// accessibility. This character position must be within the FullSpan of the Root syntax
/// node in this SemanticModel.
/// </param>
/// <param name="nameSyntax">A syntax node that represents a name. This syntax
/// node need not and typically does not appear in the source code referred to by the
/// SemanticModel instance.</param>
/// <param name="bindingOption">Indicates whether to binding the name as a full expression,
/// or as a type or namespace. If SpeculativeBindingOption.BindAsTypeOrNamespace is supplied, then
/// expression should derive from TypeSyntax.</param>
/// <remarks>The passed in name is interpreted as a stand-alone name, as if it
/// appeared by itself somewhere within the scope that encloses "position".</remarks>
protected abstract IAliasSymbol? GetSpeculativeAliasInfoCore(int position, SyntaxNode nameSyntax, SpeculativeBindingOption bindingOption);
/// <summary>
/// Get all of the syntax errors within the syntax tree associated with this
/// object. Does not get errors involving declarations or compiling method bodies or initializers.
/// </summary>
/// <param name="span">Optional span within the syntax tree for which to get diagnostics.
/// If no argument is specified, then diagnostics for the entire tree are returned.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the
/// process of obtaining the diagnostics.</param>
public abstract ImmutableArray<Diagnostic> GetSyntaxDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Get all of the declaration errors within the syntax tree associated with this
/// object. Does not get errors involving incorrect syntax, compiling method bodies or initializers.
/// </summary>
/// <param name="span">Optional span within the syntax tree for which to get diagnostics.
/// If no argument is specified, then diagnostics for the entire tree are returned.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the
/// process of obtaining the diagnostics.</param>
/// <remarks>The declaration errors for a syntax tree are cached. The first time this method
/// is called, all declarations are analyzed for diagnostics. Calling this a second time
/// will return the cached diagnostics.
/// </remarks>
public abstract ImmutableArray<Diagnostic> GetDeclarationDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Get all of the method body and initializer errors within the syntax tree associated with this
/// object. Does not get errors involving incorrect syntax or declarations.
/// </summary>
/// <param name="span">Optional span within the syntax tree for which to get diagnostics.
/// If no argument is specified, then diagnostics for the entire tree are returned.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the
/// process of obtaining the diagnostics.</param>
/// <remarks>The method body errors for a syntax tree are not cached. The first time this method
/// is called, all method bodies are analyzed for diagnostics. Calling this a second time
/// will repeat this work.
/// </remarks>
public abstract ImmutableArray<Diagnostic> GetMethodBodyDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Get all the errors within the syntax tree associated with this object. Includes errors
/// involving compiling method bodies or initializers, in addition to the errors returned by
/// GetDeclarationDiagnostics.
/// </summary>
/// <param name="span">Optional span within the syntax tree for which to get diagnostics.
/// If no argument is specified, then diagnostics for the entire tree are returned.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the
/// process of obtaining the diagnostics.</param>
/// <remarks>
/// Because this method must semantically bind all method bodies and initializers to check
/// for diagnostics, it may take a significant amount of time. Unlike
/// GetDeclarationDiagnostics, diagnostics for method bodies and initializers are not
/// cached, any semantic information used to obtain the diagnostics is discarded.
/// </remarks>
public abstract ImmutableArray<Diagnostic> GetDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Gets the symbol associated with a declaration syntax node.
/// </summary>
/// <param name="declaration">A syntax node that is a declaration. This can be any type
/// derived from MemberDeclarationSyntax, TypeDeclarationSyntax, EnumDeclarationSyntax,
/// NamespaceDeclarationSyntax, ParameterSyntax, TypeParameterSyntax, or the alias part of a
/// UsingDirectiveSyntax</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The symbol declared by the node or null if the node is not a declaration.</returns>
internal ISymbol? GetDeclaredSymbolForNode(SyntaxNode declaration, CancellationToken cancellationToken = default(CancellationToken))
{
return GetDeclaredSymbolCore(declaration, cancellationToken);
}
/// <summary>
/// Gets the symbol associated with a declaration syntax node.
/// </summary>
/// <param name="declaration">A syntax node that is a declaration. This can be any type
/// derived from MemberDeclarationSyntax, TypeDeclarationSyntax, EnumDeclarationSyntax,
/// NamespaceDeclarationSyntax, ParameterSyntax, TypeParameterSyntax, or the alias part of a
/// UsingDirectiveSyntax</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The symbol declared by the node or null if the node is not a declaration.</returns>
protected abstract ISymbol? GetDeclaredSymbolCore(SyntaxNode declaration, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Gets the symbols associated with a declaration syntax node. Unlike <see cref="GetDeclaredSymbolForNode(SyntaxNode, CancellationToken)"/>,
/// this method returns all symbols declared by a given declaration syntax node. Specifically:
/// <list type="number">
/// <item>in the case of field declaration syntax nodes, which can declare multiple symbols, this method returns
/// all declared symbols.</item>
/// <item>in the case of type declarations with a primary constructor, both the <see cref="INamedTypeSymbol"/>
/// for the type, and the <see cref="IMethodSymbol"/> for the primary constructor will be returned.</item>
/// </list>
/// </summary>
/// <param name="declaration">A syntax node that is a declaration. This can be any type
/// derived from MemberDeclarationSyntax, TypeDeclarationSyntax, EnumDeclarationSyntax,
/// NamespaceDeclarationSyntax, ParameterSyntax, TypeParameterSyntax, or the alias part of a
/// UsingDirectiveSyntax</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The symbols declared by the node.</returns>
internal ImmutableArray<ISymbol> GetDeclaredSymbolsForNode(SyntaxNode declaration, CancellationToken cancellationToken = default(CancellationToken))
{
return GetDeclaredSymbolsCore(declaration, cancellationToken);
}
/// <summary>
/// Gets the symbols associated with a declaration syntax node. Unlike <see cref="GetDeclaredSymbolForNode(SyntaxNode, CancellationToken)"/>,
/// this method returns all symbols declared by a given declaration syntax node. Specifically:
/// <list type="number">
/// <item>in the case of field declaration syntax nodes, which can declare multiple symbols, this method returns
/// all declared symbols.</item>
/// <item>in the case of type declarations with a primary constructor, both the <see cref="INamedTypeSymbol"/>
/// for the type, and the <see cref="IMethodSymbol"/> for the primary constructor will be returned.</item>
/// </list>
/// </summary>
/// <param name="declaration">A syntax node that is a declaration. This can be any type
/// derived from MemberDeclarationSyntax, TypeDeclarationSyntax, EnumDeclarationSyntax,
/// NamespaceDeclarationSyntax, ParameterSyntax, TypeParameterSyntax, or the alias part of a
/// UsingDirectiveSyntax</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The symbols declared by the node.</returns>
protected abstract ImmutableArray<ISymbol> GetDeclaredSymbolsCore(SyntaxNode declaration, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Gets the available named symbols in the context of the specified location and optional container. Only
/// symbols that are accessible and visible from the given location are returned.
/// </summary>
/// <param name="position">The character position for determining the enclosing declaration scope and
/// accessibility.</param>
/// <param name="container">The container to search for symbols within. If null then the enclosing declaration
/// scope around position is used.</param>
/// <param name="name">The name of the symbol to find. If null is specified then symbols
/// with any names are returned.</param>
/// <param name="includeReducedExtensionMethods">Consider (reduced) extension methods.</param>
/// <returns>A list of symbols that were found. If no symbols were found, an empty list is returned.</returns>
/// <remarks>
/// The "position" is used to determine what variables are visible and accessible. Even if "container" is
/// specified, the "position" location is significant for determining which members of "containing" are
/// accessible.
///
/// Labels are not considered (see <see cref="LookupLabels"/>).
///
/// Non-reduced extension methods are considered regardless of the value of <paramref name="includeReducedExtensionMethods"/>.
/// </remarks>
public ImmutableArray<ISymbol> LookupSymbols(
int position,
INamespaceOrTypeSymbol? container = null,
string? name = null,
bool includeReducedExtensionMethods = false)
{
return LookupSymbolsCore(position, container, name, includeReducedExtensionMethods);
}
/// <summary>
/// Backing implementation of <see cref="LookupSymbols"/>.
/// </summary>
protected abstract ImmutableArray<ISymbol> LookupSymbolsCore(
int position,
INamespaceOrTypeSymbol? container,
string? name,
bool includeReducedExtensionMethods);
/// <summary>
/// Gets the available base type members in the context of the specified location. Akin to
/// calling <see cref="LookupSymbols"/> with the container set to the immediate base type of
/// the type in which <paramref name="position"/> occurs. However, the accessibility rules
/// are different: protected members of the base type will be visible.
///
/// Consider the following example:
///
/// public class Base
/// {
/// protected void M() { }
/// }
///
/// public class Derived : Base
/// {
/// void Test(Base b)
/// {
/// b.M(); // Error - cannot access protected member.
/// base.M();
/// }
/// }
///
/// Protected members of an instance of another type are only accessible if the instance is known
/// to be "this" instance (as indicated by the "base" keyword).
/// </summary>
/// <param name="position">The character position for determining the enclosing declaration scope and
/// accessibility.</param>
/// <param name="name">The name of the symbol to find. If null is specified then symbols
/// with any names are returned.</param>
/// <returns>A list of symbols that were found. If no symbols were found, an empty list is returned.</returns>
/// <remarks>
/// The "position" is used to determine what variables are visible and accessible.
///
/// Non-reduced extension methods are considered, but reduced extension methods are not.
/// </remarks>
public ImmutableArray<ISymbol> LookupBaseMembers(
int position,
string? name = null)
{
return LookupBaseMembersCore(position, name);
}
/// <summary>
/// Backing implementation of <see cref="LookupBaseMembers"/>.
/// </summary>
protected abstract ImmutableArray<ISymbol> LookupBaseMembersCore(
int position,
string? name);
/// <summary>
/// Gets the available named static member symbols in the context of the specified location and optional container.
/// Only members that are accessible and visible from the given location are returned.
///
/// Non-reduced extension methods are considered, since they are static methods.
/// </summary>
/// <param name="position">The character position for determining the enclosing declaration scope and
/// accessibility.</param>
/// <param name="container">The container to search for symbols within. If null then the enclosing declaration
/// scope around position is used.</param>
/// <param name="name">The name of the symbol to find. If null is specified then symbols
/// with any names are returned.</param>
/// <returns>A list of symbols that were found. If no symbols were found, an empty list is returned.</returns>
/// <remarks>
/// The "position" is used to determine what variables are visible and accessible. Even if "container" is
/// specified, the "position" location is significant for determining which members of "containing" are
/// accessible.
///
/// Essentially the same as filtering instance members out of the results of an analogous <see cref="LookupSymbols"/> call.
/// </remarks>
public ImmutableArray<ISymbol> LookupStaticMembers(
int position,
INamespaceOrTypeSymbol? container = null,
string? name = null)
{
return LookupStaticMembersCore(position, container, name);
}
/// <summary>
/// Backing implementation of <see cref="LookupStaticMembers"/>.
/// </summary>
protected abstract ImmutableArray<ISymbol> LookupStaticMembersCore(
int position,
INamespaceOrTypeSymbol? container,
string? name);
/// <summary>
/// Gets the available named namespace and type symbols in the context of the specified location and optional container.
/// Only members that are accessible and visible from the given location are returned.
/// </summary>
/// <param name="position">The character position for determining the enclosing declaration scope and
/// accessibility.</param>
/// <param name="container">The container to search for symbols within. If null then the enclosing declaration
/// scope around position is used.</param>
/// <param name="name">The name of the symbol to find. If null is specified then symbols
/// with any names are returned.</param>
/// <returns>A list of symbols that were found. If no symbols were found, an empty list is returned.</returns>
/// <remarks>
/// The "position" is used to determine what variables are visible and accessible. Even if "container" is
/// specified, the "position" location is significant for determining which members of "containing" are
/// accessible.
///
/// Does not return INamespaceOrTypeSymbol, because there could be aliases.
/// </remarks>
public ImmutableArray<ISymbol> LookupNamespacesAndTypes(
int position,
INamespaceOrTypeSymbol? container = null,
string? name = null)
{
return LookupNamespacesAndTypesCore(position, container, name);
}
/// <summary>
/// Backing implementation of <see cref="LookupNamespacesAndTypes"/>.
/// </summary>
protected abstract ImmutableArray<ISymbol> LookupNamespacesAndTypesCore(
int position,
INamespaceOrTypeSymbol? container,
string? name);
/// <summary>
/// Gets the available named label symbols in the context of the specified location and optional container.
/// Only members that are accessible and visible from the given location are returned.
/// </summary>
/// <param name="position">The character position for determining the enclosing declaration scope and
/// accessibility.</param>
/// <param name="name">The name of the symbol to find. If null is specified then symbols
/// with any names are returned.</param>
/// <returns>A list of symbols that were found. If no symbols were found, an empty list is returned.</returns>
/// <remarks>
/// The "position" is used to determine what variables are visible and accessible. Even if "container" is
/// specified, the "position" location is significant for determining which members of "containing" are
/// accessible.
/// </remarks>
public ImmutableArray<ISymbol> LookupLabels(
int position,
string? name = null)
{
return LookupLabelsCore(position, name);
}
/// <summary>
/// Backing implementation of <see cref="LookupLabels"/>.
/// </summary>
protected abstract ImmutableArray<ISymbol> LookupLabelsCore(
int position,
string? name);
/// <summary>
/// Analyze control-flow within a part of a method body.
/// </summary>
/// <param name="firstStatement">The first node to be included within the analysis.</param>
/// <param name="lastStatement">The last node to be included within the analysis.</param>
/// <returns>An object that can be used to obtain the result of the control flow analysis.</returns>
/// <exception cref="System.ArgumentException">The span is not with a method
/// body.</exception>
/// <remarks>
/// The first and last nodes must be fully inside the same method body.
/// </remarks>
internal ControlFlowAnalysis AnalyzeControlFlow(SyntaxNode firstStatement, SyntaxNode lastStatement)
{
return AnalyzeControlFlowCore(firstStatement, lastStatement);
}
/// <summary>
/// Analyze control-flow within a part of a method body.
/// </summary>
/// <param name="firstStatement">The first node to be included within the analysis.</param>
/// <param name="lastStatement">The last node to be included within the analysis.</param>
/// <returns>An object that can be used to obtain the result of the control flow analysis.</returns>
/// <exception cref="System.ArgumentException">The span is not with a method
/// body.</exception>
/// <remarks>
/// The first and last nodes must be fully inside the same method body.
/// </remarks>
protected abstract ControlFlowAnalysis AnalyzeControlFlowCore(SyntaxNode firstStatement, SyntaxNode lastStatement);
/// <summary>
/// Analyze control-flow within a part of a method body.
/// </summary>
/// <param name="statement">The statement to be analyzed.</param>
/// <returns>An object that can be used to obtain the result of the control flow analysis.</returns>
/// <exception cref="System.ArgumentException">The span is not with a method
/// body.</exception>
/// <remarks>
/// The statement must be fully inside the same method body.
/// </remarks>
internal ControlFlowAnalysis AnalyzeControlFlow(SyntaxNode statement)
{
return AnalyzeControlFlowCore(statement);
}
/// <summary>
/// Analyze control-flow within a part of a method body.
/// </summary>
/// <param name="statement">The statement to be analyzed.</param>
/// <returns>An object that can be used to obtain the result of the control flow analysis.</returns>
/// <exception cref="System.ArgumentException">The span is not with a method
/// body.</exception>
/// <remarks>
/// The statement must be fully inside the same method body.
/// </remarks>
protected abstract ControlFlowAnalysis AnalyzeControlFlowCore(SyntaxNode statement);
/// <summary>
/// Analyze data-flow within a part of a method body.
/// </summary>
/// <param name="firstStatement">The first node to be included within the analysis.</param>
/// <param name="lastStatement">The last node to be included within the analysis.</param>
/// <returns>An object that can be used to obtain the result of the data flow analysis.</returns>
/// <exception cref="System.ArgumentException">The span is not with a method
/// body.</exception>
/// <remarks>
/// The first and last nodes must be fully inside the same method body.
/// </remarks>
internal DataFlowAnalysis AnalyzeDataFlow(SyntaxNode firstStatement, SyntaxNode lastStatement)
{
return AnalyzeDataFlowCore(firstStatement, lastStatement);
}
/// <summary>
/// Analyze data-flow within a part of a method body.
/// </summary>
/// <param name="firstStatement">The first node to be included within the analysis.</param>
/// <param name="lastStatement">The last node to be included within the analysis.</param>
/// <returns>An object that can be used to obtain the result of the data flow analysis.</returns>
/// <exception cref="System.ArgumentException">The span is not with a method
/// body.</exception>
/// <remarks>
/// The first and last nodes must be fully inside the same method body.
/// </remarks>
protected abstract DataFlowAnalysis AnalyzeDataFlowCore(SyntaxNode firstStatement, SyntaxNode lastStatement);
/// <summary>
/// Analyze data-flow within a part of a method body.
/// </summary>
/// <param name="statementOrExpression">The statement or expression to be analyzed. A ConstructorInitializerSyntax / PrimaryConstructorBaseTypeSyntax is treated here as a regular statement.</param>
/// <returns>An object that can be used to obtain the result of the data flow analysis.</returns>
/// <exception cref="System.ArgumentException">The statement or expression is not with a method
/// body or field or property initializer.</exception>
/// <remarks>
/// The statement or expression must be fully inside a method body.
/// </remarks>
internal DataFlowAnalysis AnalyzeDataFlow(SyntaxNode statementOrExpression)
{
return AnalyzeDataFlowCore(statementOrExpression);
}
/// <summary>
/// Analyze data-flow within a part of a method body.
/// </summary>
/// <param name="statementOrExpression">The statement or expression to be analyzed.</param>
/// <returns>An object that can be used to obtain the result of the data flow analysis.</returns>
/// <exception cref="System.ArgumentException">The statement or expression is not with a method
/// body or field or property initializer.</exception>
/// <remarks>
/// The statement or expression must be fully inside a method body.
/// </remarks>
protected abstract DataFlowAnalysis AnalyzeDataFlowCore(SyntaxNode statementOrExpression);
/// <summary>
/// If the node provided has a constant value an Optional value will be returned with
/// HasValue set to true and with Value set to the constant. If the node does not have an
/// constant value, an Optional will be returned with HasValue set to false.
/// </summary>
public Optional<object?> GetConstantValue(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken))
{
return GetConstantValueCore(node, cancellationToken);
}
/// <summary>
/// If the node provided has a constant value an Optional value will be returned with
/// HasValue set to true and with Value set to the constant. If the node does not have an
/// constant value, an Optional will be returned with HasValue set to false.
/// </summary>
protected abstract Optional<object?> GetConstantValueCore(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// When getting information for a symbol that resolves to a method group or property group,
/// from which a method is then chosen; the chosen method or property is present in Symbol;
/// all methods in the group that was consulted are placed in this property.
/// </summary>
internal ImmutableArray<ISymbol> GetMemberGroup(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken))
{
return GetMemberGroupCore(node, cancellationToken);
}
/// <summary>
/// When getting information for a symbol that resolves to a method group or property group,
/// from which a method is then chosen; the chosen method or property is present in Symbol;
/// all methods in the group that was consulted are placed in this property.
/// </summary>
protected abstract ImmutableArray<ISymbol> GetMemberGroupCore(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Given a position in the SyntaxTree for this SemanticModel returns the innermost Symbol
/// that the position is considered inside of.
/// </summary>
public ISymbol? GetEnclosingSymbol(int position, CancellationToken cancellationToken = default(CancellationToken))
{
return GetEnclosingSymbolCore(position, cancellationToken);
}
/// <summary>
/// Given a position in the SyntaxTree for this SemanticModel returns the innermost Symbol
/// that the position is considered inside of.
/// </summary>
protected abstract ISymbol? GetEnclosingSymbolCore(int position, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Given a position in the SyntaxTree for this SemanticModel returns the <see cref="IImportScope"/>s at that
/// point. Scopes are ordered from closest to the passed in <paramref name="position"/> to the furthest. See
/// <see cref="IImportScope"/> for a deeper description of what information is available for each scope.
/// </summary>
public ImmutableArray<IImportScope> GetImportScopes(int position, CancellationToken cancellationToken = default)
=> GetImportScopesCore(position, cancellationToken);
private protected abstract ImmutableArray<IImportScope> GetImportScopesCore(int position, CancellationToken cancellationToken);
/// <summary>
/// Determines if the symbol is accessible from the specified location.
/// </summary>
/// <param name="position">A character position used to identify a declaration scope and
/// accessibility. This character position must be within the FullSpan of the Root syntax
/// node in this SemanticModel.
/// </param>
/// <param name="symbol">The symbol that we are checking to see if it accessible.</param>
/// <returns>
/// True if "symbol is accessible, false otherwise.</returns>
/// <remarks>
/// This method only checks accessibility from the point of view of the accessibility
/// modifiers on symbol and its containing types. Even if true is returned, the given symbol
/// may not be able to be referenced for other reasons, such as name hiding.
/// </remarks>
public bool IsAccessible(int position, ISymbol symbol)
{
return IsAccessibleCore(position, symbol);
}
/// <summary>
/// Determines if the symbol is accessible from the specified location.
/// </summary>
/// <param name="position">A character position used to identify a declaration scope and
/// accessibility. This character position must be within the FullSpan of the Root syntax
/// node in this SemanticModel.
/// </param>
/// <param name="symbol">The symbol that we are checking to see if it accessible.</param>
/// <returns>
/// True if "symbol is accessible, false otherwise.</returns>
/// <remarks>
/// This method only checks accessibility from the point of view of the accessibility
/// modifiers on symbol and its containing types. Even if true is returned, the given symbol
/// may not be able to be referenced for other reasons, such as name hiding.
/// </remarks>
protected abstract bool IsAccessibleCore(int position, ISymbol symbol);
/// <summary>
/// Field-like events can be used as fields in types that can access private
/// members of the declaring type of the event.
/// </summary>
/// <remarks>
/// Always false for VB events.
/// </remarks>
public bool IsEventUsableAsField(int position, IEventSymbol eventSymbol)
{
return IsEventUsableAsFieldCore(position, eventSymbol);
}
/// <summary>
/// Field-like events can be used as fields in types that can access private
/// members of the declaring type of the event.
/// </summary>
/// <remarks>
/// Always false for VB events.
/// </remarks>
protected abstract bool IsEventUsableAsFieldCore(int position, IEventSymbol eventSymbol);
/// <summary>
/// If <paramref name="nameSyntax"/> is an identifier name syntax node, return the <see cref="PreprocessingSymbolInfo"/> corresponding
/// to it.
/// </summary>
/// <param name="nameSyntax">The nameSyntax node to get semantic information for.</param>
public PreprocessingSymbolInfo GetPreprocessingSymbolInfo(SyntaxNode nameSyntax)
{
return GetPreprocessingSymbolInfoCore(nameSyntax);
}
/// <summary>
/// If <paramref name="nameSyntax"/> is an identifier name syntax node, return the <see cref="PreprocessingSymbolInfo"/> corresponding
/// to it.
/// </summary>
/// <param name="nameSyntax">The nameSyntax node to get semantic information for.</param>
protected abstract PreprocessingSymbolInfo GetPreprocessingSymbolInfoCore(SyntaxNode nameSyntax);
/// <summary>
/// Gets the <see cref="DeclarationInfo"/> for all the declarations whose span overlaps with the given <paramref name="span"/>.
/// </summary>
/// <param name="span">Span to get declarations.</param>
/// <param name="getSymbol">Flag indicating whether <see cref="DeclarationInfo.DeclaredSymbol"/> should be computed for the returned declaration infos.
/// If false, then <see cref="DeclarationInfo.DeclaredSymbol"/> is always null.</param>
/// <param name="builder">Builder to add declarations.</param>
/// <param name="cancellationToken">Cancellation token.</param>
internal abstract void ComputeDeclarationsInSpan(TextSpan span, bool getSymbol, ArrayBuilder<DeclarationInfo> builder, CancellationToken cancellationToken);
/// <summary>
/// Takes a node and returns a set of declarations that overlap the node's span.
/// </summary>
internal abstract void ComputeDeclarationsInNode(SyntaxNode node, ISymbol associatedSymbol, bool getSymbol, ArrayBuilder<DeclarationInfo> builder, CancellationToken cancellationToken, int? levelsToCompute = null);
/// <summary>
/// Gets a filter that determines whether or not a given syntax node and its descendants should be analyzed for the given
/// declared node and declared symbol. We have scenarios where certain syntax nodes declare multiple symbols,
/// for example record declarations, and we want to avoid duplicate syntax node callbacks for such nodes.
/// Note that the predicate returned by this method filters out both the node and all its descendants from analysis.
/// If you wish to skip analysis just for a specific node, but not its descendants, then add the required logic in
/// <see cref="ShouldSkipSyntaxNodeAnalysis(SyntaxNode, ISymbol)"/>.
/// </summary>
internal virtual Func<SyntaxNode, bool>? GetSyntaxNodesToAnalyzeFilter(SyntaxNode declaredNode, ISymbol declaredSymbol) => null;
/// <summary>
/// Determines if the given syntax node with the given containing symbol should be analyzed or not.
/// Note that only the given syntax node will be filtered out from analysis, this API will be invoked separately
/// for each of its descendants. If you wish to skip analysis of the node and all its descendants, then add the required
/// logic to <see cref="GetSyntaxNodesToAnalyzeFilter(SyntaxNode, ISymbol)"/>.
/// </summary>
internal virtual bool ShouldSkipSyntaxNodeAnalysis(SyntaxNode node, ISymbol containingSymbol) => false;
/// <summary>
/// Takes a Symbol and syntax for one of its declaring syntax reference and returns the topmost syntax node to be used by syntax analyzer.
/// </summary>
protected internal virtual SyntaxNode GetTopmostNodeForDiagnosticAnalysis(ISymbol symbol, SyntaxNode declaringSyntax)
{
return declaringSyntax;
}
/// <summary>
/// Root of this semantic model
/// </summary>
internal SyntaxNode Root => RootCore;
/// <summary>
/// Root of this semantic model
/// </summary>
protected abstract SyntaxNode RootCore { get; }
/// <summary>
/// Gets the <see cref="NullableContext"/> at a position in the file.
/// </summary>
/// <param name="position">The position to get the context for.</param>
public abstract NullableContext GetNullableContext(int position);
}
}
|