提交 f339b8ba 编写于 作者: C CyrusNajmabadi

Merge remote-tracking branch 'upstream/master' into useExprBodyFixAll2

......@@ -3884,22 +3884,11 @@ private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter)
this.ParseAttributeDeclarations(attributes);
this.ParseParameterModifiers(modifiers);
var hasArgList = this.CurrentToken.Kind == SyntaxKind.ArgListKeyword;
TypeSyntax type = null;
if (!hasArgList)
{
type = this.ParseType(mode: ParseTypeMode.Parameter);
}
else if (this.IsPossibleType())
TypeSyntax type;
SyntaxToken name;
if (this.CurrentToken.Kind != SyntaxKind.ArgListKeyword)
{
type = this.ParseType(mode: ParseTypeMode.Parameter);
type = WithAdditionalDiagnostics(type, this.GetExpectedTokenError(SyntaxKind.CloseParenToken, SyntaxKind.IdentifierToken, 0, type.Width));
}
SyntaxToken name = null;
if (!hasArgList)
{
name = this.ParseIdentifierToken();
// When the user type "int foo[]", give them a useful error
......@@ -3911,19 +3900,11 @@ private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter)
name = AddTrailingSkippedSyntax(name, SyntaxList.List(open, close));
}
}
else if (this.IsPossibleName())
{
// Current token is an identifier token, we expected a CloseParenToken.
// Get the expected token error for the missing token with correct diagnostic
// span and then parse the identifier token.
SyntaxDiagnosticInfo diag = this.GetExpectedTokenError(SyntaxKind.CloseParenToken, SyntaxKind.IdentifierToken);
name = this.ParseIdentifierToken();
name = WithAdditionalDiagnostics(name, diag);
}
else
{
// name is not optional on ParameterSyntax
// We store an __arglist parameter as a parameter with null type and whose
// .Identifier has the kind ArgListKeyword.
type = null;
name = this.EatToken(SyntaxKind.ArgListKeyword);
}
......
......@@ -31,7 +31,7 @@ internal sealed partial class ObjectReader : IDisposable
/// this version, just change VersionByte2.
/// </summary>
internal const byte VersionByte1 = 0b10101010;
internal const byte VersionByte2 = 0b00001000;
internal const byte VersionByte2 = 0b00001001;
private readonly BinaryReader _reader;
private readonly CancellationToken _cancellationToken;
......
......@@ -157,22 +157,32 @@ private class IncrementalAnalyzer : IncrementalAnalyzerBase
_metadataPathToInfo = metadataPathToInfo;
}
public override Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, InvocationReasons reasons, CancellationToken cancellationToken)
public override async Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, InvocationReasons reasons, CancellationToken cancellationToken)
{
if (!document.SupportsSyntaxTree)
{
// Not a language we can produce indices for (i.e. TypeScript). Bail immediately.
return SpecializedTasks.EmptyTask;
return;
}
if (bodyOpt != null)
{
// This was a method level edit. This can't change the symbol tree info
// for this project. Bail immediately.
return SpecializedTasks.EmptyTask;
// This was a method body edit. We can reuse the existing SymbolTreeInfo if
// we have one. We can't just bail out here as the change in the document means
// we'll have a new checksum. We need to get that new checksum so that our
// cached information is valid.
if (_projectToInfo.TryGetValue(document.Project.Id, out var cachedInfo))
{
var checksum = await SymbolTreeInfo.GetSourceSymbolsChecksumAsync(
document.Project, cancellationToken).ConfigureAwait(false);
var newInfo = cachedInfo.WithChecksum(checksum);
_projectToInfo.AddOrUpdate(document.Project.Id, newInfo, (_1, _2) => newInfo);
return;
}
}
return UpdateSymbolTreeInfoAsync(document.Project, cancellationToken);
await UpdateSymbolTreeInfoAsync(document.Project, cancellationToken).ConfigureAwait(false);
}
public override Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken)
......@@ -194,10 +204,13 @@ private async Task UpdateSymbolTreeInfoAsync(Project project, CancellationToken
}
// Produce the indices for the source and metadata symbols in parallel.
var projectTask = UpdateSourceSymbolTreeInfoAsync(project, cancellationToken);
var referencesTask = UpdateReferencesAync(project, cancellationToken);
var tasks = new List<Task>
{
GetTask(project, () => UpdateSourceSymbolTreeInfoAsync(project, cancellationToken), cancellationToken),
GetTask(project, () => UpdateReferencesAync(project, cancellationToken), cancellationToken)
};
await Task.WhenAll(projectTask, referencesTask).ConfigureAwait(false);
await Task.WhenAll(tasks).ConfigureAwait(false);
}
private async Task UpdateSourceSymbolTreeInfoAsync(Project project, CancellationToken cancellationToken)
......@@ -218,12 +231,24 @@ private async Task UpdateSourceSymbolTreeInfoAsync(Project project, Cancellation
}
}
private Task GetTask(Project project, Func<Task> func, CancellationToken cancellationToken)
{
var isRemoteWorkspace = project.Solution.Workspace.Kind == WorkspaceKind.RemoteWorkspace;
return isRemoteWorkspace
? Task.Run(func, cancellationToken)
: func();
}
private Task UpdateReferencesAync(Project project, CancellationToken cancellationToken)
{
// Process all metadata references in parallel.
var tasks = project.MetadataReferences.OfType<PortableExecutableReference>()
.Select(r => UpdateReferenceAsync(project, r, cancellationToken))
.ToArray();
// Process all metadata references. If it remote workspace, do this in parallel.
var tasks = new List<Task>();
foreach (var reference in project.MetadataReferences.OfType<PortableExecutableReference>())
{
tasks.Add(
GetTask(project, () => UpdateReferenceAsync(project, reference, cancellationToken), cancellationToken));
}
return Task.WhenAll(tasks);
}
......
......@@ -83,7 +83,7 @@ internal partial class SymbolTreeInfo : IChecksummedObject
private SymbolTreeInfo(
Checksum checksum,
string concatenatedNames,
Node[] sortedNodes,
ImmutableArray<Node> sortedNodes,
Task<SpellChecker> spellCheckerTask,
OrderPreservingMultiDictionary<string, string> inheritanceMap)
: this(checksum, concatenatedNames, sortedNodes, spellCheckerTask)
......@@ -95,7 +95,7 @@ internal partial class SymbolTreeInfo : IChecksummedObject
private SymbolTreeInfo(
Checksum checksum,
string concatenatedNames,
Node[] sortedNodes,
ImmutableArray<Node> sortedNodes,
Task<SpellChecker> spellCheckerTask,
OrderPreservingMultiDictionary<int, int> inheritanceMap)
: this(checksum, concatenatedNames, sortedNodes, spellCheckerTask)
......@@ -106,12 +106,12 @@ internal partial class SymbolTreeInfo : IChecksummedObject
private SymbolTreeInfo(
Checksum checksum,
string concatenatedNames,
Node[] sortedNodes,
ImmutableArray<Node> sortedNodes,
Task<SpellChecker> spellCheckerTask)
{
Checksum = checksum;
_concatenatedNames = concatenatedNames;
_nodes = ImmutableArray.Create(sortedNodes);
_nodes = sortedNodes;
_spellCheckerTask = spellCheckerTask;
}
......@@ -124,6 +124,12 @@ public static SymbolTreeInfo CreateEmpty(Checksum checksum)
CreateSpellCheckerAsync(checksum, concatenatedNames, sortedNodes));
}
public SymbolTreeInfo WithChecksum(Checksum checksum)
{
return new SymbolTreeInfo(
checksum, _concatenatedNames, _nodes, _spellCheckerTask, _inheritanceMap);
}
public Task<ImmutableArray<SymbolAndProjectId>> FindAsync(
SearchQuery query, IAssemblySymbol assembly, ProjectId assemblyProjectId, SymbolFilter filter, CancellationToken cancellationToken)
{
......@@ -326,7 +332,7 @@ private int BinarySearch(string name)
private static Task<SpellChecker> GetSpellCheckerTask(
Solution solution, Checksum checksum, string filePath,
string concatenatedNames, Node[] sortedNodes)
string concatenatedNames, ImmutableArray<Node> sortedNodes)
{
// Create a new task to attempt to load or create the spell checker for this
// SymbolTreeInfo. This way the SymbolTreeInfo will be ready immediately
......@@ -336,7 +342,8 @@ private int BinarySearch(string name)
solution, checksum, filePath, concatenatedNames, sortedNodes));
}
private static Task<SpellChecker> CreateSpellCheckerAsync(Checksum checksum, string concatenatedNames, Node[] sortedNodes)
private static Task<SpellChecker> CreateSpellCheckerAsync(
Checksum checksum, string concatenatedNames, ImmutableArray<Node> sortedNodes)
{
return Task.FromResult(new SpellChecker(
checksum, sortedNodes.Select(n => new StringSlice(concatenatedNames, n.NameSpan))));
......@@ -345,7 +352,7 @@ private static Task<SpellChecker> CreateSpellCheckerAsync(Checksum checksum, str
private static void SortNodes(
ImmutableArray<BuilderNode> unsortedNodes,
out string concatenatedNames,
out Node[] sortedNodes)
out ImmutableArray<Node> sortedNodes)
{
// Generate index numbers from 0 to Count-1
var tmp = new int[unsortedNodes.Length];
......@@ -369,7 +376,9 @@ private static Task<SpellChecker> CreateSpellCheckerAsync(Checksum checksum, str
// No longer need the tmp array
tmp = null;
var result = new Node[unsortedNodes.Length];
var result = ArrayBuilder<Node>.GetInstance(unsortedNodes.Length);
result.Count = unsortedNodes.Length;
var concatenatedNamesBuilder = new StringBuilder();
string lastName = null;
......@@ -396,7 +405,7 @@ private static Task<SpellChecker> CreateSpellCheckerAsync(Checksum checksum, str
lastName = currentName;
}
sortedNodes = result;
sortedNodes = result.ToImmutableAndFree();
concatenatedNames = concatenatedNamesBuilder.ToString();
}
......
......@@ -151,9 +151,12 @@ private static Metadata GetMetadataNoThrow(PortableExecutableReference reference
{
// We can reuse the index for any given reference as long as it hasn't changed.
// So our checksum is just the checksum for the PEReference itself.
var serializer = new Serializer(solution.Workspace);
var checksum = serializer.CreateChecksum(reference, cancellationToken);
return checksum;
return ChecksumCache.GetOrCreate(reference, _ =>
{
var serializer = new Serializer(solution.Workspace);
var checksum = serializer.CreateChecksum(reference, cancellationToken);
return checksum;
});
}
private static Task<SymbolTreeInfo> TryLoadOrCreateMetadataSymbolTreeInfoAsync(
......
// 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;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Serialization;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Utilities;
......@@ -28,7 +30,7 @@ internal partial class SymbolTreeInfo : IObjectWritable
Checksum checksum,
string filePath,
string concatenatedNames,
Node[] sortedNodes)
ImmutableArray<Node> sortedNodes)
{
var result = TryLoadOrCreateAsync(
solution,
......@@ -149,7 +151,7 @@ public void WriteTo(ObjectWriter writer)
private static SymbolTreeInfo TryReadSymbolTreeInfo(
ObjectReader reader,
Func<string, Node[], Task<SpellChecker>> createSpellCheckerTask)
Func<string, ImmutableArray<Node>, Task<SpellChecker>> createSpellCheckerTask)
{
try
{
......@@ -161,14 +163,14 @@ public void WriteTo(ObjectWriter writer)
var concatenatedNames = reader.ReadString();
var nodeCount = reader.ReadInt32();
var nodes = new Node[nodeCount];
var nodes = ArrayBuilder<Node>.GetInstance(nodeCount);
for (var i = 0; i < nodeCount; i++)
{
var start = reader.ReadInt32();
var length = reader.ReadInt32();
var parentIndex = reader.ReadInt32();
nodes[i] = new Node(new TextSpan(start, length), parentIndex);
nodes.Add(new Node(new TextSpan(start, length), parentIndex));
}
var inheritanceMap = new OrderPreservingMultiDictionary<int, int>();
......@@ -185,8 +187,9 @@ public void WriteTo(ObjectWriter writer)
}
}
var spellCheckerTask = createSpellCheckerTask(concatenatedNames, nodes);
return new SymbolTreeInfo(checksum, concatenatedNames, nodes, spellCheckerTask, inheritanceMap);
var nodeArray = nodes.ToImmutableAndFree();
var spellCheckerTask = createSpellCheckerTask(concatenatedNames, nodeArray);
return new SymbolTreeInfo(checksum, concatenatedNames, nodeArray, spellCheckerTask, inheritanceMap);
}
}
catch
......
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Collections;
......@@ -42,7 +43,24 @@ private static void FreeSymbolMap(MultiDictionary<string, ISymbol> symbolMap)
return result;
}
public static async Task<Checksum> GetSourceSymbolsChecksumAsync(Project project, CancellationToken cancellationToken)
/// <summary>
/// Cache of project to the checksum for it so that we don't have to expensively recompute
/// this each time we get a project.
/// </summary>
private static ConditionalWeakTable<ProjectState, AsyncLazy<Checksum>> s_projectToSourceChecksum =
new ConditionalWeakTable<ProjectState, AsyncLazy<Checksum>>();
public static Task<Checksum> GetSourceSymbolsChecksumAsync(Project project, CancellationToken cancellationToken)
{
var workspace = project.Solution.Workspace;
var lazy = s_projectToSourceChecksum.GetValue(
project.State, p => new AsyncLazy<Checksum>(c => ComputeSourceSymbolsChecksumAsync(workspace, p, c), cacheResult: true));
return lazy.GetValueAsync(cancellationToken);
}
private static async Task<Checksum> ComputeSourceSymbolsChecksumAsync(
Workspace workspace, ProjectState projectState, CancellationToken cancellationToken)
{
// The SymbolTree for source is built from the source-symbols from the project's compilation's
// assembly. Specifically, we only get the name, kind and parent/child relationship of all the
......@@ -50,14 +68,14 @@ public static async Task<Checksum> GetSourceSymbolsChecksumAsync(Project project
// changed. The only thing that can make those source-symbols change in that manner are if
// the text of any document changes, or if options for the project change. So we build our
// checksum out of that data.
var serializer = new Serializer(project.Solution.Workspace);
var projectStateChecksums = await project.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);
var serializer = new Serializer(workspace);
var projectStateChecksums = await projectState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);
// Order the documents by FilePath. Default ordering in the RemoteWorkspace is
// to be ordered by Guid (which is not consistent across VS sessions).
var textChecksumsTasks = project.Documents.OrderBy(d => d.FilePath, StringComparer.Ordinal).Select(async d =>
var textChecksumsTasks = projectState.DocumentStates.OrderBy(d => d.Value.FilePath, StringComparer.Ordinal).Select(async d =>
{
var documentStateChecksum = await d.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);
var documentStateChecksum = await d.Value.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);
return documentStateChecksum.Text;
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册