未验证 提交 1d4cf98e 编写于 作者: J Jason Malinowski 提交者: GitHub

Merge pull request #40897 from jasonmalinowski/null-annotate-quick-info

Null annotate Quick Info
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
......@@ -7,6 +9,7 @@
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.QuickInfo;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.CodeAnalysis.CSharp.QuickInfo
{
......@@ -22,7 +25,7 @@ public CSharpSemanticQuickInfoProvider()
/// If the token is the '=>' in a lambda, or the 'delegate' in an anonymous function,
/// return the syntax for the lambda or anonymous function.
/// </summary>
protected override bool GetBindableNodeForTokenIndicatingLambda(SyntaxToken token, out SyntaxNode found)
protected override bool GetBindableNodeForTokenIndicatingLambda(SyntaxToken token, [NotNullWhen(returnValue: true)] out SyntaxNode? found)
{
if (token.IsKind(SyntaxKind.EqualsGreaterThanToken)
&& token.Parent.IsKind(SyntaxKind.ParenthesizedLambdaExpression, SyntaxKind.SimpleLambdaExpression))
......@@ -42,7 +45,7 @@ protected override bool GetBindableNodeForTokenIndicatingLambda(SyntaxToken toke
return false;
}
protected override bool GetBindableNodeForTokenIndicatingPossibleIndexerAccess(SyntaxToken token, out SyntaxNode found)
protected override bool GetBindableNodeForTokenIndicatingPossibleIndexerAccess(SyntaxToken token, [NotNullWhen(returnValue: true)] out SyntaxNode? found)
{
if (token.IsKind(SyntaxKind.CloseBracketToken, SyntaxKind.OpenBracketToken) &&
token.Parent?.Parent.IsKind(SyntaxKind.ElementAccessExpression) == true)
......@@ -63,7 +66,7 @@ protected override bool ShouldCheckPreviousToken(SyntaxToken token)
protected override ImmutableArray<TaggedText> TryGetNullabilityAnalysis(Workspace workspace, SemanticModel semanticModel, SyntaxToken token, CancellationToken cancellationToken)
{
// Anything less than C# 8 we just won't show anything, even if the compiler could theoretically give analysis
var parseOptions = (CSharpParseOptions)token.SyntaxTree.Options;
var parseOptions = (CSharpParseOptions)token.SyntaxTree!.Options;
if (parseOptions.LanguageVersion < LanguageVersion.CSharp8)
{
return default;
......@@ -119,7 +122,7 @@ protected override ImmutableArray<TaggedText> TryGetNullabilityAnalysis(Workspac
return default;
}
string messageTemplate = null;
string? messageTemplate = null;
if (typeInfo.Nullability.FlowState == NullableFlowState.NotNull)
{
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
......@@ -10,6 +12,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.QuickInfo;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.QuickInfo
{
......@@ -22,7 +25,7 @@ public CSharpSyntacticQuickInfoProvider()
{
}
protected override async Task<QuickInfoItem> BuildQuickInfoAsync(
protected override async Task<QuickInfoItem?> BuildQuickInfoAsync(
Document document,
SyntaxToken token,
CancellationToken cancellationToken)
......@@ -39,8 +42,8 @@ public CSharpSyntacticQuickInfoProvider()
return null;
}
// Now check if we can find an open brace.
var parent = token.Parent;
// Now check if we can find an open brace.
var parent = token.Parent!;
var openBrace = parent.ChildNodesAndTokens().FirstOrDefault(n => n.Kind() == SyntaxKind.OpenBraceToken).AsToken();
if (openBrace.Kind() != SyntaxKind.OpenBraceToken)
{
......@@ -56,11 +59,12 @@ public CSharpSyntacticQuickInfoProvider()
{
MarkInterestedSpanNearbyScopeBlock(parent, openBrace, ref spanStart, ref spanEnd);
}
// If the parent is a child of a property/method declaration, object/array creation, or control flow node..
// If the parent is a child of a property/method declaration, object/array creation, or control flow node,
// then walk up one higher so we can show more useful context
else if (parent.GetFirstToken() == openBrace)
{
spanStart = parent.Parent.SpanStart;
// parent.Parent must be non-null, because for GetFirstToken() to have returned something it would have had to walk up to its parent
spanStart = parent.Parent!.SpanStart;
}
// encode document spans that correspond to the text to show
......
......@@ -191,7 +191,7 @@ async Task<bool> ShouldCompleteWithFullyQualifyTypeName()
private static async Task<bool> IsInImportsDirectiveAsync(Document document, int position, CancellationToken cancellationToken)
{
var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var leftToken = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDirectives: true);
return leftToken.GetAncestor(syntaxFacts.IsUsingOrExternOrImport) != null;
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Shared.Extensions;
......@@ -8,13 +10,13 @@ namespace Microsoft.CodeAnalysis.QuickInfo
{
internal abstract class CommonQuickInfoProvider : QuickInfoProvider
{
public override async Task<QuickInfoItem> GetQuickInfoAsync(QuickInfoContext context)
public override async Task<QuickInfoItem?> GetQuickInfoAsync(QuickInfoContext context)
{
var document = context.Document;
var position = context.Position;
var cancellationToken = context.CancellationToken;
var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var token = await tree.GetTouchingTokenAsync(position, cancellationToken, findInsideTrivia: true).ConfigureAwait(false);
var info = await GetQuickInfoAsync(document, token, position, cancellationToken).ConfigureAwait(false);
......@@ -33,7 +35,7 @@ protected virtual bool ShouldCheckPreviousToken(SyntaxToken token)
return true;
}
private async Task<QuickInfoItem> GetQuickInfoAsync(
private async Task<QuickInfoItem?> GetQuickInfoAsync(
Document document,
SyntaxToken token,
int position,
......@@ -48,6 +50,6 @@ protected virtual bool ShouldCheckPreviousToken(SyntaxToken token)
return null;
}
protected abstract Task<QuickInfoItem> BuildQuickInfoAsync(Document document, SyntaxToken token, CancellationToken cancellationToken);
protected abstract Task<QuickInfoItem?> BuildQuickInfoAsync(Document document, SyntaxToken token, CancellationToken cancellationToken);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Linq;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Shared.Utilities;
namespace Microsoft.CodeAnalysis.QuickInfo
{
internal abstract partial class CommonSemanticQuickInfoProvider
{
private class SymbolComparer : IEqualityComparer<ISymbol>
{
public static readonly SymbolComparer Instance = new SymbolComparer();
private SymbolComparer()
{
}
public bool Equals(ISymbol x, ISymbol y)
{
if (x is ILabelSymbol || x is ILocalSymbol || x is IRangeVariableSymbol)
{
return object.ReferenceEquals(x, y);
}
return SymbolEquivalenceComparer.Instance.Equals(x, y);
}
public int GetHashCode(ISymbol obj)
{
if (obj is ILabelSymbol || obj is ILocalSymbol || obj is IRangeVariableSymbol)
{
return obj.GetHashCode();
}
return SymbolEquivalenceComparer.Instance.GetHashCode(obj);
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
......@@ -18,7 +22,7 @@ namespace Microsoft.CodeAnalysis.QuickInfo
{
internal abstract partial class CommonSemanticQuickInfoProvider : CommonQuickInfoProvider
{
protected override async Task<QuickInfoItem> BuildQuickInfoAsync(
protected override async Task<QuickInfoItem?> BuildQuickInfoAsync(
Document document,
SyntaxToken token,
CancellationToken cancellationToken)
......@@ -35,7 +39,7 @@ internal abstract partial class CommonSemanticQuickInfoProvider : CommonQuickInf
cancellationToken).ConfigureAwait(false);
}
private async Task<(SemanticModel model, ImmutableArray<ISymbol> symbols, SupportedPlatformData supportedPlatforms)> ComputeQuickInfoDataAsync(
private async Task<(SemanticModel model, ImmutableArray<ISymbol> symbols, SupportedPlatformData? supportedPlatforms)> ComputeQuickInfoDataAsync(
Document document,
SyntaxToken token,
CancellationToken cancellationToken)
......@@ -79,7 +83,7 @@ internal abstract partial class CommonSemanticQuickInfoProvider : CommonQuickInf
foreach (var linkedDocumentId in linkedDocumentIds)
{
var linkedDocument = document.Project.Solution.GetDocument(linkedDocumentId);
var linkedDocument = document.Project.Solution.GetRequiredDocument(linkedDocumentId);
var linkedToken = await FindTokenInLinkedDocumentAsync(token, document, linkedDocument, cancellationToken).ConfigureAwait(false);
if (linkedToken != default)
......@@ -127,13 +131,13 @@ private static bool HasNoErrors(ImmutableArray<ISymbol> symbols)
Document linkedDocument,
CancellationToken cancellationToken)
{
if (!linkedDocument.SupportsSyntaxTree)
var root = await linkedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
if (root == null)
{
return default;
}
var root = await linkedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
try
{
// Don't search trivia because we want to ignore inactive regions
......@@ -166,12 +170,12 @@ private static bool HasNoErrors(ImmutableArray<ISymbol> symbols)
SyntaxToken token,
SemanticModel semanticModel,
IEnumerable<ISymbol> symbols,
SupportedPlatformData supportedPlatforms,
SupportedPlatformData? supportedPlatforms,
CancellationToken cancellationToken)
{
var descriptionService = workspace.Services.GetLanguageServices(token.Language).GetService<ISymbolDisplayService>();
var formatter = workspace.Services.GetLanguageServices(semanticModel.Language).GetService<IDocumentationCommentFormattingService>();
var syntaxFactsService = workspace.Services.GetLanguageServices(semanticModel.Language).GetService<ISyntaxFactsService>();
var descriptionService = workspace.Services.GetLanguageServices(token.Language).GetRequiredService<ISymbolDisplayService>();
var formatter = workspace.Services.GetLanguageServices(semanticModel.Language).GetRequiredService<IDocumentationCommentFormattingService>();
var syntaxFactsService = workspace.Services.GetLanguageServices(semanticModel.Language).GetRequiredService<ISyntaxFactsService>();
var showWarningGlyph = supportedPlatforms != null && supportedPlatforms.HasValidAndInvalidProjects();
var showSymbolGlyph = true;
......@@ -302,16 +306,16 @@ void AddSection(string kind, ImmutableArray<TaggedText> taggedParts)
return default;
}
protected abstract bool GetBindableNodeForTokenIndicatingLambda(SyntaxToken token, out SyntaxNode found);
protected abstract bool GetBindableNodeForTokenIndicatingPossibleIndexerAccess(SyntaxToken token, out SyntaxNode found);
protected abstract bool GetBindableNodeForTokenIndicatingLambda(SyntaxToken token, [NotNullWhen(returnValue: true)] out SyntaxNode? found);
protected abstract bool GetBindableNodeForTokenIndicatingPossibleIndexerAccess(SyntaxToken token, [NotNullWhen(returnValue: true)] out SyntaxNode? found);
protected virtual ImmutableArray<TaggedText> TryGetNullabilityAnalysis(Workspace workspace, SemanticModel semanticModel, SyntaxToken token, CancellationToken cancellationToken) => default;
private async Task<(SemanticModel semanticModel, ImmutableArray<ISymbol> symbols)> BindTokenAsync(
Document document, SyntaxToken token, CancellationToken cancellationToken)
{
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var enclosingType = semanticModel.GetEnclosingNamedType(token.SpanStart, cancellationToken);
var symbols = GetSymbolsFromToken(token, document.Project.Solution.Workspace, semanticModel, cancellationToken);
......@@ -335,7 +339,7 @@ void AddSection(string kind, ImmutableArray<TaggedText> taggedParts)
// least bind it to a type.
if (syntaxFacts.IsOperator(token))
{
var typeInfo = semanticModel.GetTypeInfo(token.Parent, cancellationToken);
var typeInfo = semanticModel.GetTypeInfo(token.Parent!, cancellationToken);
if (IsOk(typeInfo.Type))
{
return (semanticModel, ImmutableArray.Create<ISymbol>(typeInfo.Type));
......@@ -349,7 +353,8 @@ private ImmutableArray<ISymbol> GetSymbolsFromToken(SyntaxToken token, Workspace
{
if (GetBindableNodeForTokenIndicatingLambda(token, out var lambdaSyntax))
{
return ImmutableArray.Create(semanticModel.GetSymbolInfo(lambdaSyntax, cancellationToken).Symbol);
var symbol = semanticModel.GetSymbolInfo(lambdaSyntax, cancellationToken).Symbol;
return symbol != null ? ImmutableArray.Create(symbol) : ImmutableArray<ISymbol>.Empty;
}
if (GetBindableNodeForTokenIndicatingPossibleIndexerAccess(token, out var elementAccessExpression))
......@@ -365,10 +370,10 @@ private ImmutableArray<ISymbol> GetSymbolsFromToken(SyntaxToken token, Workspace
.GetSymbols(includeType: true);
}
private static bool IsOk(ISymbol symbol)
private static bool IsOk([NotNullWhen(returnValue: true)] ISymbol? symbol)
=> symbol != null && !symbol.IsErrorType();
private static bool IsAccessible(ISymbol symbol, INamedTypeSymbol within)
private static bool IsAccessible(ISymbol symbol, INamedTypeSymbol? within)
=> within == null
|| symbol.IsAccessibleWithin(within);
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Composition;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
......@@ -32,14 +34,12 @@ internal static class IndentationHelper
// We need to figure out the shortest indentation level of the exposed lines. We'll
// then remove that indentation from all lines.
var indentationColumn = DetermineIndentationColumn(text, classifiedSpans, tabSize);
string spanClassificationType = null;
var adjustedClassifiedSpans = new List<ClassifiedSpan>();
for (var i = 0; i < classifiedSpans.Length; i++)
{
var classifiedSpan = classifiedSpans[i];
spanClassificationType = classifiedSpan.ClassificationType;
var spanClassificationType = classifiedSpan.ClassificationType;
var span = classifiedSpan.TextSpan;
var startLineNumber = text.Lines.GetLineFromPosition(span.Start).LineNumber;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
namespace Microsoft.CodeAnalysis.QuickInfo
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Threading;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Text;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.QuickInfo
......@@ -14,6 +16,6 @@ internal abstract class QuickInfoProvider
/// Gets the <see cref="QuickInfoItem"/> for the position.
/// </summary>
/// <returns>The <see cref="QuickInfoItem"/> or null if no item is available.</returns>
public abstract Task<QuickInfoItem> GetQuickInfoAsync(QuickInfoContext context);
public abstract Task<QuickInfoItem?> GetQuickInfoAsync(QuickInfoContext context);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Host.Mef;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
namespace Microsoft.CodeAnalysis.QuickInfo
{
/// <summary>
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
......@@ -21,7 +23,7 @@ public sealed class QuickInfoSection
/// </summary>
public ImmutableArray<TaggedText> TaggedParts { get; }
private QuickInfoSection(string kind, ImmutableArray<TaggedText> taggedParts)
private QuickInfoSection(string? kind, ImmutableArray<TaggedText> taggedParts)
{
Kind = kind ?? string.Empty;
TaggedParts = taggedParts.NullToEmpty();
......@@ -32,12 +34,12 @@ private QuickInfoSection(string kind, ImmutableArray<TaggedText> taggedParts)
/// </summary>
/// <param name="kind">The kind of the section. Use <see cref="QuickInfoSectionKinds"/> for the most common kinds.</param>
/// <param name="taggedParts">The individual tagged parts of the section.</param>
public static QuickInfoSection Create(string kind, ImmutableArray<TaggedText> taggedParts)
public static QuickInfoSection Create(string? kind, ImmutableArray<TaggedText> taggedParts)
{
return new QuickInfoSection(kind, taggedParts);
}
private string _text;
private string? _text;
/// <summary>
/// The text of the section without tags.
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
namespace Microsoft.CodeAnalysis.QuickInfo
{
/// <summary>
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
......@@ -16,13 +18,13 @@ public abstract class QuickInfoService : ILanguageService
/// <summary>
/// Gets the appropriate <see cref="QuickInfoService"/> for the specified document.
/// </summary>
public static QuickInfoService GetService(Document document)
public static QuickInfoService? GetService(Document? document)
=> document?.GetLanguageService<QuickInfoService>();
/// <summary>
/// Gets the <see cref="QuickInfoItem"/> associated with position in the document.
/// </summary>
public virtual Task<QuickInfoItem> GetQuickInfoAsync(
public virtual Task<QuickInfoItem?> GetQuickInfoAsync(
Document document,
int position,
CancellationToken cancellationToken = default)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Collections.Immutable;
using System.Linq;
......@@ -44,9 +46,9 @@ private ImmutableArray<QuickInfoProvider> GetProviders()
return _providers;
}
public override async Task<QuickInfoItem> GetQuickInfoAsync(Document document, int position, CancellationToken cancellationToken)
public override async Task<QuickInfoItem?> GetQuickInfoAsync(Document document, int position, CancellationToken cancellationToken)
{
var extensionManager = _workspace.Services.GetService<IExtensionManager>();
var extensionManager = _workspace.Services.GetRequiredService<IExtensionManager>();
// returns the first non-empty quick info found (based on provider order)
foreach (var provider in GetProviders())
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis.CSharp.Formatting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Extensions
{
internal static partial class SyntaxNodeExtensions
{
public static bool IsKind<TNode>(this SyntaxNode node, SyntaxKind kind, out TNode result)
public static bool IsKind<TNode>([NotNullWhen(returnValue: true)] this SyntaxNode? node, SyntaxKind kind, [NotNullWhen(returnValue: true)] out TNode? result)
where TNode : SyntaxNode
{
if (node.IsKind(kind))
{
#if !CODE_STYLE
result = (TNode)node;
#else
// The CodeStyle layer is referencing an older, unannotated version of Roslyn which doesn't know that IsKind guarantees the non-nullness
// of node. So we have to silence it here.
result = (TNode)node!;
#endif
return true;
}
......@@ -38,7 +46,7 @@ public static bool IsParentKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKi
public static bool IsParentKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4)
=> IsKind(node?.Parent, kind1, kind2, kind3, kind4);
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2)
public static bool IsKind([NotNullWhen(returnValue: true)] this SyntaxNode? node, SyntaxKind kind1, SyntaxKind kind2)
{
if (node == null)
{
......@@ -49,7 +57,7 @@ public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kin
return csharpKind == kind1 || csharpKind == kind2;
}
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3)
public static bool IsKind([NotNullWhen(returnValue: true)] this SyntaxNode? node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3)
{
if (node == null)
{
......@@ -60,7 +68,7 @@ public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kin
return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3;
}
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4)
public static bool IsKind([NotNullWhen(returnValue: true)] this SyntaxNode? node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4)
{
if (node == null)
{
......@@ -71,7 +79,7 @@ public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kin
return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3 || csharpKind == kind4;
}
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5)
public static bool IsKind([NotNullWhen(returnValue: true)] this SyntaxNode? node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5)
{
if (node == null)
{
......@@ -82,7 +90,7 @@ public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kin
return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3 || csharpKind == kind4 || csharpKind == kind5;
}
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5, SyntaxKind kind6)
public static bool IsKind([NotNullWhen(returnValue: true)] this SyntaxNode? node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5, SyntaxKind kind6)
{
if (node == null)
{
......@@ -93,7 +101,7 @@ public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kin
return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3 || csharpKind == kind4 || csharpKind == kind5 || csharpKind == kind6;
}
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5, SyntaxKind kind6, SyntaxKind kind7)
public static bool IsKind([NotNullWhen(returnValue: true)] this SyntaxNode? node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5, SyntaxKind kind6, SyntaxKind kind7)
{
if (node == null)
{
......@@ -104,7 +112,7 @@ public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kin
return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3 || csharpKind == kind4 || csharpKind == kind5 || csharpKind == kind6 || csharpKind == kind7;
}
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5, SyntaxKind kind6, SyntaxKind kind7, SyntaxKind kind8, SyntaxKind kind9, SyntaxKind kind10, SyntaxKind kind11)
public static bool IsKind([NotNullWhen(returnValue: true)] this SyntaxNode? node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5, SyntaxKind kind6, SyntaxKind kind7, SyntaxKind kind8, SyntaxKind kind9, SyntaxKind kind10, SyntaxKind kind11)
{
if (node == null)
{
......@@ -116,7 +124,7 @@ public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kin
}
public static IEnumerable<SyntaxTrivia> GetAllPrecedingTriviaToPreviousToken(
this SyntaxNode node, SourceText sourceText = null,
this SyntaxNode node, SourceText? sourceText = null,
bool includePreviousTokenTrailingTriviaOnlyIfOnSameLine = false)
=> node.GetFirstToken().GetAllPrecedingTriviaToPreviousToken(
sourceText, includePreviousTokenTrailingTriviaOnlyIfOnSameLine);
......@@ -126,7 +134,7 @@ public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kin
/// the previous token's trailing trivia and this token's leading trivia).
/// </summary>
public static IEnumerable<SyntaxTrivia> GetAllPrecedingTriviaToPreviousToken(
this SyntaxToken token, SourceText sourceText = null,
this SyntaxToken token, SourceText? sourceText = null,
bool includePreviousTokenTrailingTriviaOnlyIfOnSameLine = false)
{
var prevToken = token.GetPreviousToken(includeSkipped: true);
......@@ -135,8 +143,9 @@ public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kin
return token.LeadingTrivia;
}
Contract.ThrowIfTrue(sourceText == null && includePreviousTokenTrailingTriviaOnlyIfOnSameLine, "If we are including previous token trailing trivia, we need the text too.");
if (includePreviousTokenTrailingTriviaOnlyIfOnSameLine &&
!sourceText.AreOnSameLine(prevToken, token))
!sourceText!.AreOnSameLine(prevToken, token))
{
return token.LeadingTrivia;
}
......@@ -144,7 +153,7 @@ public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kin
return prevToken.TrailingTrivia.Concat(token.LeadingTrivia);
}
public static bool IsAnyArgumentList(this SyntaxNode node)
public static bool IsAnyArgumentList([NotNullWhen(returnValue: true)] this SyntaxNode? node)
{
return node.IsKind(SyntaxKind.ArgumentList) ||
node.IsKind(SyntaxKind.AttributeArgumentList) ||
......@@ -191,7 +200,7 @@ public static (SyntaxToken openBrace, SyntaxToken closeBrace) GetBraces(this Syn
return default;
}
public static bool IsEmbeddedStatementOwner(this SyntaxNode node)
public static bool IsEmbeddedStatementOwner([NotNullWhen(returnValue: true)] this SyntaxNode? node)
{
return node is DoStatementSyntax ||
node is ElseClauseSyntax ||
......@@ -205,7 +214,7 @@ public static bool IsEmbeddedStatementOwner(this SyntaxNode node)
node is WhileStatementSyntax;
}
public static StatementSyntax GetEmbeddedStatement(this SyntaxNode node)
public static StatementSyntax? GetEmbeddedStatement(this SyntaxNode node)
=> node switch
{
DoStatementSyntax n => n.Statement,
......
......@@ -27,5 +27,16 @@ public static Project GetRequiredProject(this Solution solution, ProjectId proje
return project;
}
public static Document GetRequiredDocument(this Solution solution, DocumentId documentId)
{
var document = solution.GetDocument(documentId);
if (document == null)
{
throw new InvalidOperationException(WorkspacesResources.The_solution_does_not_contain_the_specified_document);
}
return document;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Threading;
using System.Threading.Tasks;
......@@ -112,7 +114,6 @@ public static bool IsEntirelyHidden(this SyntaxTree tree, TextSpan span, Cancell
Contract.ThrowIfNull(syntaxTree);
var root = syntaxTree.GetRoot(cancellationToken);
var compilationUnit = root as ICompilationUnitSyntax;
var result = root.FindToken(position, findInsideTrivia: true);
if (result.RawKind != 0)
{
......@@ -124,6 +125,7 @@ public static bool IsEntirelyHidden(this SyntaxTree tree, TextSpan span, Cancell
// b) pp directive
// c) file
var compilationUnit = (ICompilationUnitSyntax)root;
var triviaList = compilationUnit.EndOfFileToken.LeadingTrivia;
foreach (var trivia in triviaList.Reverse())
{
......@@ -149,7 +151,6 @@ public static bool IsEntirelyHidden(this SyntaxTree tree, TextSpan span, Cancell
this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken, bool findInsideTrivia = false)
{
var root = syntaxTree.GetRoot(cancellationToken);
var compilationUnit = root as ICompilationUnitSyntax;
var trivia = root.FindTrivia(position, findInsideTrivia);
// If we ask right at the end of the file, we'll get back nothing.
......@@ -157,6 +158,7 @@ public static bool IsEntirelyHidden(this SyntaxTree tree, TextSpan span, Cancell
// work at the end of a file.
if (position == root.FullWidth())
{
var compilationUnit = (ICompilationUnitSyntax)root;
var endOfFileToken = compilationUnit.EndOfFileToken;
if (endOfFileToken.HasLeadingTrivia)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册