diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a231e5267c74e..a9da3ca0a1c68 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -7,9 +7,9 @@ https://github.com/dotnet/arcade ed69753a3ffbdaa08365252c710d57a64d17f859 - + https://github.com/dotnet/roslyn - 09f75b83754732a74e0815976b80ecffd94c0dde + f24d2c5c98211908ab90d6f1f42e7592411d6058 diff --git a/eng/Versions.props b/eng/Versions.props index 24807bc01d808..2c7f6622ae35e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -23,7 +23,7 @@ - 3.8.0-1.20353.1 + 3.8.0-1.20361.1 diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index 31f2c14b3ddad..42f0663819b97 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -185,12 +185,12 @@ "vsBranch": "master", "vsMajorVersion": 16 }, - "features/dotnetFormat": { + "features/UsedAssemblyReferences": { "nugetKind": [ "Shipping", "NonShipping" ], - "version": "3.3.*", + "version": "3.8.*", "nuget": [ "https://dotnet.myget.org/F/roslyn/api/v2/package" ], "vsix": [ "https://dotnet.myget.org/F/roslyn/vsix/upload" ], - "channels": [ "dotnetFormat" ], + "channels": [ "UsedAssemblyReferences" ], "vsBranch": "master", "vsMajorVersion": 16 }, diff --git a/src/Compilers/Core/CommandLine/BuildProtocol.cs b/src/Compilers/Core/CommandLine/BuildProtocol.cs index 0a20e7f6db16b..f0389f538128d 100644 --- a/src/Compilers/Core/CommandLine/BuildProtocol.cs +++ b/src/Compilers/Core/CommandLine/BuildProtocol.cs @@ -82,11 +82,12 @@ public static BuildRequest Create(RequestLanguage language, { Debug.Assert(!string.IsNullOrWhiteSpace(compilerHash), "CompilerHash is required to send request to the build server"); - Log("Creating BuildRequest"); - Log($"Working directory: {workingDirectory}"); - Log($"Temp directory: {tempDirectory}"); - Log($"Lib directory: {libDirectory ?? "null"}"); - Log($"Compiler hash: {compilerHash}"); + Log($@" +Creating BuildRequest + Working directory: {workingDirectory} + Temp directory: {tempDirectory} + Lib directory: {libDirectory ?? null} + Compiler hash: {compilerHash}"); var requestLength = args.Count + 1 + (libDirectory == null ? 0 : 1); var requestArgs = new List(requestLength); @@ -108,7 +109,6 @@ public static BuildRequest Create(RequestLanguage language, for (int i = 0; i < args.Count; ++i) { var arg = args[i]; - Log($"argument[{i}] = {arg}"); requestArgs.Add(new Argument(ArgumentId.CommandLineArgument, i, arg)); } @@ -118,7 +118,7 @@ public static BuildRequest Create(RequestLanguage language, public static BuildRequest CreateShutdown() { var requestArgs = new[] { new Argument(ArgumentId.Shutdown, argumentIndex: 0, value: "") }; - return new BuildRequest(BuildProtocolConstants.ProtocolVersion, RequestLanguage.CSharpCompile, GetCommitHash(), requestArgs); + return new BuildRequest(BuildProtocolConstants.ProtocolVersion, RequestLanguage.CSharpCompile, GetCommitHash() ?? "", requestArgs); } /// @@ -127,19 +127,17 @@ public static BuildRequest CreateShutdown() /// The total request size must be less than 1MB. /// /// null if the Request was too large, the Request otherwise. - public static async Task ReadAsync(Stream inStream, CancellationToken cancellationToken) + public static async Task ReadAsync(Stream inStream, CancellationToken cancellationToken) { // Read the length of the request var lengthBuffer = new byte[4]; - Log("Reading length of request"); await ReadAllAsync(inStream, lengthBuffer, 4, cancellationToken).ConfigureAwait(false); var length = BitConverter.ToInt32(lengthBuffer, 0); // Back out if the request is > 1MB if (length > 0x100000) { - Log("Request is over 1MB in length, cancelling read."); - return null; + throw new ArgumentException("Request is over 1MB in length"); } cancellationToken.ThrowIfCancellationRequested(); @@ -150,7 +148,6 @@ public static BuildRequest CreateShutdown() cancellationToken.ThrowIfCancellationRequested(); - Log("Parsing request"); // Parse the request into the Request data structure. using (var reader = new BinaryReader(new MemoryStream(requestBuffer), Encoding.Unicode)) { @@ -182,8 +179,6 @@ public static BuildRequest CreateShutdown() using (var memoryStream = new MemoryStream()) using (var writer = new BinaryWriter(memoryStream, Encoding.Unicode)) { - // Format the request. - Log("Formatting request"); writer.Write(ProtocolVersion); writer.Write((uint)Language); writer.Write(CompilerHash); @@ -203,17 +198,12 @@ public static BuildRequest CreateShutdown() // Back out if the request is > 1 MB if (memoryStream.Length > 0x100000) { - Log("Request is over 1MB in length, cancelling write"); - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException("Request is over 1MB in length"); } - // Send the request to the server - Log("Writing length of request."); await outStream.WriteAsync(BitConverter.GetBytes(length), 0, 4, cancellationToken).ConfigureAwait(false); - Log("Writing request of size {0}", length); - // Write the request memoryStream.Position = 0; await memoryStream.CopyToAsync(outStream, bufferSize: length, cancellationToken: cancellationToken).ConfigureAwait(false); } @@ -311,8 +301,6 @@ public async Task WriteAsync(Stream outStream, using (var memoryStream = new MemoryStream()) using (var writer = new BinaryWriter(memoryStream, Encoding.Unicode)) { - // Format the response - Log("Formatting Response"); writer.Write((int)Type); AddResponseBody(writer); @@ -325,7 +313,6 @@ public async Task WriteAsync(Stream outStream, // Write the length of the response int length = checked((int)memoryStream.Length); - Log("Writing response length"); // There is no way to know the number of bytes written to // the pipe stream. We just have to assume all of them are written. await outStream.WriteAsync(BitConverter.GetBytes(length), @@ -333,8 +320,6 @@ await outStream.WriteAsync(BitConverter.GetBytes(length), 4, cancellationToken).ConfigureAwait(false); - // Write the response - Log("Writing response of size {0}", length); memoryStream.Position = 0; await memoryStream.CopyToAsync(outStream, bufferSize: length, cancellationToken: cancellationToken).ConfigureAwait(false); } @@ -350,14 +335,12 @@ await outStream.WriteAsync(BitConverter.GetBytes(length), /// public static async Task ReadAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken)) { - Log("Reading response length"); // Read the response length var lengthBuffer = new byte[4]; await ReadAllAsync(stream, lengthBuffer, 4, cancellationToken).ConfigureAwait(false); var length = BitConverter.ToUInt32(lengthBuffer, 0); // Read the response - Log("Reading response of length {0}", length); var responseBuffer = new byte[length]; await ReadAllAsync(stream, responseBuffer, @@ -381,7 +364,7 @@ await ReadAllAsync(stream, case ResponseType.Shutdown: return ShutdownBuildResponse.Create(reader); case ResponseType.Rejected: - return new RejectedBuildResponse(); + return RejectedBuildResponse.Create(reader); default: throw new InvalidOperationException("Received invalid response type from server."); } @@ -505,13 +488,30 @@ protected override void AddResponseBody(BinaryWriter writer) { } internal sealed class RejectedBuildResponse : BuildResponse { + public string Reason; + public override ResponseType Type => ResponseType.Rejected; + public RejectedBuildResponse(string reason) + { + Reason = reason; + } + /// /// AnalyzerInconsistency has no body. /// /// - protected override void AddResponseBody(BinaryWriter writer) { } + protected override void AddResponseBody(BinaryWriter writer) + { + WriteLengthPrefixedString(writer, Reason); + } + + public static RejectedBuildResponse Create(BinaryReader reader) + { + var reason = ReadLengthPrefixedString(reader); + Debug.Assert(reason is object); + return new RejectedBuildResponse(reason); + } } // The id numbers below are just random. It's useful to use id numbers @@ -592,14 +592,13 @@ public static void WriteLengthPrefixedString(BinaryWriter writer, string? value) /// Reads the value of of the assembly is defined in /// /// The hash value of the current assembly or an empty string - public static string GetCommitHash() + public static string? GetCommitHash() { var hashAttributes = typeof(BuildRequest).Assembly.GetCustomAttributes(); var hashAttributeCount = hashAttributes.Count(); if (hashAttributeCount != 1) { - Log($"Error reading CommitHashAttribute. Exactly 1 attribute is required, found {hashAttributeCount}"); - return string.Empty; + return null; } return hashAttributes.Single().Hash; } @@ -616,21 +615,16 @@ internal static async Task ReadAllAsync( int totalBytesRead = 0; do { - Log("Attempting to read {0} bytes from the stream", - count - totalBytesRead); int bytesRead = await stream.ReadAsync(buffer, totalBytesRead, count - totalBytesRead, cancellationToken).ConfigureAwait(false); if (bytesRead == 0) { - Log("Unexpected -- read 0 bytes from the stream."); throw new EndOfStreamException("Reached end of stream before end of read."); } - Log("Read {0} bytes", bytesRead); totalBytesRead += bytesRead; } while (totalBytesRead < count); - Log("Finished read"); } } } diff --git a/src/Compilers/Server/VBCSCompiler/CompilerRequestHandler.cs b/src/Compilers/Server/VBCSCompiler/CompilerRequestHandler.cs index 559c97032114d..c8865427d463f 100644 --- a/src/Compilers/Server/VBCSCompiler/CompilerRequestHandler.cs +++ b/src/Compilers/Server/VBCSCompiler/CompilerRequestHandler.cs @@ -96,27 +96,22 @@ public bool TryCreateCompiler(RunRequest request, out CommonCompiler compiler) public BuildResponse RunCompilation(RunRequest request, CancellationToken cancellationToken) { - Log($"CurrentDirectory = '{request.CurrentDirectory}'"); - Log($"LIB = '{request.LibDirectory}'"); - for (int i = 0; i < request.Arguments.Length; ++i) - { - Log($"Argument[{i}] = '{request.Arguments[i]}'"); - } + Log($@" +Run Compilation + CurrentDirectory = '{request.CurrentDirectory} + LIB = '{request.LibDirectory}'"); // Compiler server must be provided with a valid temporary directory in order to correctly // isolate signing between compilations. if (string.IsNullOrEmpty(request.TempDirectory)) { - Log($"Rejecting build due to missing temp directory"); - return new RejectedBuildResponse(); + return new RejectedBuildResponse("Missing temp directory"); } CommonCompiler compiler; if (!TryCreateCompiler(request, out compiler)) { - // We can't do anything with a request we don't know about. - Log($"Got request with id '{request.Language}'"); - return new RejectedBuildResponse(); + return new RejectedBuildResponse($"Cannot create compiler for language id {request.Language}"); } bool utf8output = compiler.Arguments.Utf8Output; @@ -125,11 +120,16 @@ public BuildResponse RunCompilation(RunRequest request, CancellationToken cancel return new AnalyzerInconsistencyBuildResponse(); } - Log($"****Running {request.Language} compiler..."); + Log($"Begin {request.Language} compiler run"); TextWriter output = new StringWriter(CultureInfo.InvariantCulture); int returnCode = compiler.Run(output, cancellationToken); - Log($"****{request.Language} Compilation complete.\r\n****Return code: {returnCode}\r\n****Output:\r\n{output.ToString()}\r\n"); - return new CompletedBuildResponse(returnCode, utf8output, output.ToString()); + var outputString = output.ToString(); + Log(@$" +End {request.Language} Compilation complete. +Return code: {returnCode} +Output: +{outputString}"); + return new CompletedBuildResponse(returnCode, utf8output, outputString); } } } diff --git a/src/Compilers/Server/VBCSCompiler/NamedPipeClientConnection.cs b/src/Compilers/Server/VBCSCompiler/NamedPipeClientConnection.cs index 35e1a5597e1b6..1605bf4624905 100644 --- a/src/Compilers/Server/VBCSCompiler/NamedPipeClientConnection.cs +++ b/src/Compilers/Server/VBCSCompiler/NamedPipeClientConnection.cs @@ -112,8 +112,7 @@ public void Close() // The client connection failing to close isn't fatal to the server process. It is simply a client // for which we can no longer communicate and that's okay because the Close method indicates we are // done with the client already. - var msg = string.Format($"Pipe {LoggingIdentifier}: Error closing pipe."); - CompilerServerLogger.LogException(e, msg); + CompilerServerLogger.LogException(e, $"Pipe {LoggingIdentifier}: Error closing pipe."); } } @@ -124,14 +123,12 @@ public void Close() BuildRequest request; try { - Log("Begin reading request."); request = await BuildRequest.ReadAsync(_stream, cancellationToken).ConfigureAwait(false); ValidateBuildRequest(request); - Log("End reading request."); } catch (Exception e) { - LogException(e, "Error reading build request."); + CompilerServerLogger.LogException(e, "Error reading build request."); return new ConnectionData(CompletionReason.CompilationNotStarted); } @@ -149,7 +146,7 @@ public void Close() } else if (!allowCompilationRequests) { - return await HandleRejectedRequestAsync(cancellationToken).ConfigureAwait(false); + return await HandleRejectedRequestAsync("Compilation requests not allowed at this time", cancellationToken).ConfigureAwait(false); } else { @@ -181,10 +178,8 @@ private async Task HandleCompilationRequestAsync(BuildRequest re try { - Log("Begin writing response."); await response.WriteAsync(_stream, cancellationToken).ConfigureAwait(false); reason = CompletionReason.CompilationCompleted; - Log("End writing response."); } catch { @@ -216,9 +211,9 @@ private async Task HandleIncorrectHashRequestAsync(CancellationT return new ConnectionData(CompletionReason.CompilationNotStarted); } - private async Task HandleRejectedRequestAsync(CancellationToken cancellationToken) + private async Task HandleRejectedRequestAsync(string reason, CancellationToken cancellationToken) { - var response = new RejectedBuildResponse(); + var response = new RejectedBuildResponse(reason); await response.WriteAsync(_stream, cancellationToken).ConfigureAwait(false); return new ConnectionData(CompletionReason.CompilationNotStarted); } @@ -266,13 +261,8 @@ private Task ServeBuildRequestAsync(BuildRequest buildRequest, Ca { Func func = () => { - // Do the compilation - Log("Begin compilation"); - var request = BuildProtocolUtil.GetRunRequest(buildRequest); var response = _compilerServerHost.RunCompilation(request, cancellationToken); - - Log("End compilation"); return response; }; @@ -280,15 +270,5 @@ private Task ServeBuildRequestAsync(BuildRequest buildRequest, Ca task.Start(); return task; } - - private void Log(string message) - { - CompilerServerLogger.Log("Client {0}: {1}", _loggingIdentifier, message); - } - - private void LogException(Exception e, string message) - { - CompilerServerLogger.LogException(e, string.Format("Client {0}: {1}", _loggingIdentifier, message)); - } } } diff --git a/src/Compilers/Server/VBCSCompiler/ServerDispatcher.cs b/src/Compilers/Server/VBCSCompiler/ServerDispatcher.cs index 762a7457559fa..4a7039c97e69d 100644 --- a/src/Compilers/Server/VBCSCompiler/ServerDispatcher.cs +++ b/src/Compilers/Server/VBCSCompiler/ServerDispatcher.cs @@ -229,6 +229,7 @@ private void HandleCompletedListenTask(CancellationToken cancellationToken) private void HandleCompletedTimeoutTask() { + CompilerServerLogger.Log("Timeout triggered. Shutting down server."); _diagnosticListener.KeepAliveReached(); _listenCancellationTokenSource.Cancel(); _timeoutTask = null; @@ -298,10 +299,12 @@ private void HandleCompletedConnections() case CompletionReason.ClientDisconnect: // Have to assume the worst here which is user pressing Ctrl+C at the command line and // hence wanting all compilation to end. + CompilerServerLogger.Log("Unexpected client disconnect. Shutting down server"); shutdown = true; break; case CompletionReason.ClientException: case CompletionReason.ClientShutdownRequest: + CompilerServerLogger.Log($"Unexpected client completion: {connectionData.CompletionReason}. Shutting down server"); shutdown = true; break; default: diff --git a/src/Compilers/Server/VBCSCompilerTests/CompilerServerApiTest.cs b/src/Compilers/Server/VBCSCompilerTests/CompilerServerApiTest.cs index 1299275b4c5a7..e101d9bdd63ea 100644 --- a/src/Compilers/Server/VBCSCompilerTests/CompilerServerApiTest.cs +++ b/src/Compilers/Server/VBCSCompilerTests/CompilerServerApiTest.cs @@ -512,7 +512,7 @@ public async Task CancelWillCancelCompilation() } cancellationToken.WaitHandle.WaitOne(); - return new RejectedBuildResponse(); + return new RejectedBuildResponse(""); }; var list = new List>(); diff --git a/src/Compilers/Shared/BuildServerConnection.cs b/src/Compilers/Shared/BuildServerConnection.cs index a6081eb936bd6..17d308b92b369 100644 --- a/src/Compilers/Shared/BuildServerConnection.cs +++ b/src/Compilers/Shared/BuildServerConnection.cs @@ -113,14 +113,14 @@ internal static async Task RunServerCompilationCoreAsync( CreateServerFunc createServerFunc, CancellationToken cancellationToken) { - if (pipeName == null) + if (pipeName is null) { - return new RejectedBuildResponse(); + throw new ArgumentException(nameof(pipeName)); } if (buildPaths.TempDirectory == null) { - return new RejectedBuildResponse(); + throw new ArgumentException(nameof(buildPaths)); } // early check for the build hash. If we can't find it something is wrong; no point even trying to go to the server @@ -132,21 +132,21 @@ internal static async Task RunServerCompilationCoreAsync( var pipeTask = tryConnectToServer(pipeName, buildPaths, timeoutOverride, createServerFunc, cancellationToken); if (pipeTask is null) { - return new RejectedBuildResponse(); + return new RejectedBuildResponse("Failed to connect to server"); } else { var pipe = await pipeTask.ConfigureAwait(false); if (pipe is null) { - return new RejectedBuildResponse(); + return new RejectedBuildResponse("Failed to connect to server"); } else { var request = BuildRequest.Create(language, buildPaths.WorkingDirectory, buildPaths.TempDirectory, - BuildProtocolConstants.GetCommitHash(), + BuildProtocolConstants.GetCommitHash() ?? "", arguments, keepAlive, libEnvVariable); @@ -259,7 +259,7 @@ private static async Task TryCompileAsync(NamedPipeClientStream p catch (Exception e) { LogException(e, "Error writing build request."); - return new RejectedBuildResponse(); + return new RejectedBuildResponse($"Error writing build request: {e.Message}"); } // Wait for the compilation and a monitor to detect if the server disconnects @@ -283,13 +283,13 @@ private static async Task TryCompileAsync(NamedPipeClientStream p catch (Exception e) { LogException(e, "Error reading response"); - response = new RejectedBuildResponse(); + response = new RejectedBuildResponse($"Error reading response: {e.Message}"); } } else { - Log("Server disconnect"); - response = new RejectedBuildResponse(); + Log("Client disconnect"); + response = new RejectedBuildResponse($"Client disconnected"); } // Cancel whatever task is still around diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpReplIdeFeatures.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpReplIdeFeatures.cs index 64d7d33446a7e..a31eb5206ddfe 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpReplIdeFeatures.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpReplIdeFeatures.cs @@ -88,7 +88,7 @@ public void HighlightRefsSingleSubmissionVerifyRenameTagsGoAway() VisualStudio.InteractiveWindow.VerifyTags(WellKnownTagNames.MarkerFormatDefinition_HighlightedWrittenReference, 0); } - [WpfFact] + [WpfFact(Skip = "https://github.com/dotnet/roslyn/issues/46027")] public void HighlightRefsMultipleSubmisionsVerifyRenameTagsShowUpWhenInvokedOnSubmittedText() { VisualStudio.InteractiveWindow.SubmitText("class Goo { }"); @@ -100,7 +100,7 @@ public void HighlightRefsMultipleSubmisionsVerifyRenameTagsShowUpWhenInvokedOnSu VisualStudio.InteractiveWindow.VerifyTags(WellKnownTagNames.MarkerFormatDefinition_HighlightedReference, 1); } - [WpfFact] + [WpfFact(Skip = "https://github.com/dotnet/roslyn/issues/46027")] public void HighlightRefsMultipleSubmisionsVerifyRenameTagsShowUpOnUnsubmittedText() { VisualStudio.InteractiveWindow.SubmitText("class Goo { }"); @@ -112,7 +112,7 @@ public void HighlightRefsMultipleSubmisionsVerifyRenameTagsShowUpOnUnsubmittedTe VisualStudio.InteractiveWindow.VerifyTags(WellKnownTagNames.MarkerFormatDefinition_HighlightedReference, 1); } - [WpfFact] + [WpfFact(Skip = "https://github.com/dotnet/roslyn/issues/46027")] public void HighlightRefsMultipleSubmisionsVerifyRenameTagsShowUpOnTypesWhenInvokedOnSubmittedText() { VisualStudio.InteractiveWindow.SubmitText("class Goo { }"); @@ -124,7 +124,7 @@ public void HighlightRefsMultipleSubmisionsVerifyRenameTagsShowUpOnTypesWhenInvo VisualStudio.InteractiveWindow.VerifyTags(WellKnownTagNames.MarkerFormatDefinition_HighlightedReference, 2); } - [WpfFact] + [WpfFact(Skip = "https://github.com/dotnet/roslyn/issues/46027")] public void HighlightRefsMultipleSubmisionsVerifyRenameTagsShowUpOnTypesWhenInvokedOnUnsubmittedText() { VisualStudio.InteractiveWindow.SubmitText("class Goo { }"); diff --git a/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs b/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs index 7ca3ced163be6..f6c6378b82147 100644 --- a/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs +++ b/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs @@ -107,14 +107,14 @@ public async Task TryRehydrateAsync( // The server and client should both be talking about the same compilation. As such // locations in symbols are save to resolve as we rehydrate the SymbolKey. var symbol = SymbolKey.ResolveString( - SymbolKeyData, compilation, cancellationToken: cancellationToken).GetAnySymbol(); + SymbolKeyData, compilation, out var failureReason, cancellationToken).GetAnySymbol(); if (symbol == null) { try { throw new InvalidOperationException( - $"We should always be able to resolve a symbol back on the host side:\r\n{SymbolKeyData}"); + $"We should always be able to resolve a symbol back on the host side:\r\n{SymbolKeyData}\r\n{failureReason}"); } catch (Exception ex) when (FatalError.ReportWithoutCrash(ex)) { diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AliasSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AliasSymbolKey.cs index 16c62ad938634..d4b6bd9caa68a 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AliasSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AliasSymbolKey.cs @@ -18,12 +18,18 @@ public static void Create(IAliasSymbol symbol, SymbolKeyWriter visitor) visitor.WriteString(FirstOrDefault(symbol.DeclaringSyntaxReferences)?.SyntaxTree.FilePath ?? ""); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var name = reader.ReadString(); - var targetResolution = reader.ReadSymbolKey(); + var targetResolution = reader.ReadSymbolKey(out var targetFailureReason); var filePath = reader.ReadString(); + if (targetFailureReason != null) + { + failureReason = $"({nameof(AliasSymbolKey)} {nameof(targetResolution)} failed -> {targetFailureReason})"; + return default; + } + var syntaxTree = reader.GetSyntaxTree(filePath); if (syntaxTree != null) { @@ -34,11 +40,13 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) var result = Resolve(semanticModel, syntaxTree.GetRoot(reader.CancellationToken), name, target, reader.CancellationToken); if (result.HasValue) { + failureReason = null; return result.Value; } } } + failureReason = $"({nameof(AliasSymbolKey)} '{name}' not found)"; return default; } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AnonymousFunctionOrDelegateSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AnonymousFunctionOrDelegateSymbolKey.cs index 9e37a9aad8a6c..f2fdae2dbaf9f 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AnonymousFunctionOrDelegateSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AnonymousFunctionOrDelegateSymbolKey.cs @@ -31,14 +31,21 @@ public static void Create(ISymbol symbol, SymbolKeyWriter visitor) visitor.WriteLocation(FirstOrDefault(symbol.Locations)); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var isAnonymousDelegateType = reader.ReadBoolean(); - var location = reader.ReadLocation(); + var location = reader.ReadLocation(out var locationFailureReason); + + if (locationFailureReason != null) + { + failureReason = $"({nameof(AnonymousFunctionOrDelegateSymbolKey)} {nameof(location)} failed -> {locationFailureReason})"; + return default; + } var syntaxTree = location.SourceTree; if (syntaxTree == null) { + failureReason = $"({nameof(AnonymousFunctionOrDelegateSymbolKey)} {nameof(SyntaxTree)} failed)"; return default; } @@ -58,6 +65,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) symbol = anonymousDelegate; } + failureReason = null; return new SymbolKeyResolution(symbol); } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AnonymousTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AnonymousTypeSymbolKey.cs index 1482acb3cd495..b9408cc4565a1 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AnonymousTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AnonymousTypeSymbolKey.cs @@ -28,12 +28,24 @@ public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor) visitor.WriteLocationArray(propertyLocations); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { - using var propertyTypes = reader.ReadSymbolKeyArray(); + using var propertyTypes = reader.ReadSymbolKeyArray(out var propertyTypesFailureReason); using var propertyNames = reader.ReadStringArray(); using var propertyIsReadOnly = reader.ReadBooleanArray(); - using var propertyLocations = reader.ReadLocationArray(); + using var propertyLocations = reader.ReadLocationArray(out var propertyLocationsFailureReason); + + if (propertyTypesFailureReason != null) + { + failureReason = $"({nameof(AnonymousTypeSymbolKey)} {nameof(propertyTypes)} failed -> {propertyTypesFailureReason})"; + return default; + } + + if (propertyLocationsFailureReason != null) + { + failureReason = $"({nameof(AnonymousTypeSymbolKey)} {nameof(propertyLocations)} failed -> {propertyLocationsFailureReason})"; + return default; + } if (!propertyTypes.IsDefault) { @@ -42,6 +54,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) var anonymousType = reader.Compilation.CreateAnonymousTypeSymbol( propertyTypes.ToImmutable(), propertyNames.ToImmutable(), propertyIsReadOnly.ToImmutable(), propertyLocations.ToImmutable()); + failureReason = null; return new SymbolKeyResolution(anonymousType); } catch (ArgumentException) @@ -49,6 +62,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) } } + failureReason = null; return new SymbolKeyResolution(reader.Compilation.ObjectType); } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ArrayTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ArrayTypeSymbolKey.cs index 2cbbfa3dccbe3..28a9eab15747d 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ArrayTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ArrayTypeSymbolKey.cs @@ -14,18 +14,22 @@ public static void Create(IArrayTypeSymbol symbol, SymbolKeyWriter visitor) visitor.WriteInteger(symbol.Rank); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { - var elementTypeResolution = reader.ReadSymbolKey(); + var elementTypeResolution = reader.ReadSymbolKey(out var elementTypeFailureReason); var rank = reader.ReadInteger(); + if (elementTypeFailureReason != null) + { + failureReason = $"({nameof(ArrayTypeSymbolKey)} {nameof(elementTypeResolution)} failed -> {elementTypeFailureReason})"; + return default; + } + using var result = PooledArrayBuilder.GetInstance(elementTypeResolution.SymbolCount); foreach (var typeSymbol in elementTypeResolution.OfType()) - { result.AddIfNotNull(reader.Compilation.CreateArrayTypeSymbol(typeSymbol, rank)); - } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(ArrayTypeSymbolKey)})", out failureReason); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AssemblySymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AssemblySymbolKey.cs index 972480399850c..c86d0720bc2c7 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AssemblySymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.AssemblySymbolKey.cs @@ -17,7 +17,7 @@ public static void Create(IAssemblySymbol symbol, SymbolKeyWriter visitor) visitor.WriteString(symbol.Identity.Name); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var assemblyName = reader.ReadString(); var compilation = reader.Compilation; @@ -38,7 +38,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) } } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(AssemblySymbolKey)} '{assemblyName}' not found)", out failureReason); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.BodyLevelSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.BodyLevelSymbolKey.cs index 4be5bdc419dda..1b662ffb0fdd4 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.BodyLevelSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.BodyLevelSymbolKey.cs @@ -116,15 +116,21 @@ private static bool TryGetSemanticModel( return false; } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason) { var cancellationToken = reader.CancellationToken; var name = reader.ReadString(); var kind = (SymbolKind)reader.ReadInteger(); - var locations = reader.ReadLocationArray(); + var locations = reader.ReadLocationArray(out var locationsFailureReason); var ordinal = reader.ReadInteger(); + if (locationsFailureReason != null) + { + failureReason = $"({nameof(BodyLevelSymbolKey)} {nameof(locations)} failed -> {locationsFailureReason})"; + return default; + } + // First check if we can recover the symbol just through the original location. foreach (var loc in locations) { @@ -136,6 +142,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) if (symbol?.Kind == kind && SymbolKey.Equals(reader.Compilation, name, symbol.Name)) { + failureReason = null; return resolution; } } @@ -148,10 +155,14 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) foreach (var symbol in EnumerateSymbols(semanticModel, kind, name, cancellationToken)) { if (symbol.ordinal == ordinal) + { + failureReason = null; return new SymbolKeyResolution(symbol.symbol); + } } } + failureReason = $"({nameof(BodyLevelSymbolKey)} '{name}' not found)"; return default; } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.DynamicTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.DynamicTypeSymbolKey.cs index 8423b72ae372b..90a12bac68ff1 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.DynamicTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.DynamicTypeSymbolKey.cs @@ -14,8 +14,11 @@ public static void Create(SymbolKeyWriter _) // per compilation. } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) - => new SymbolKeyResolution(reader.Compilation.DynamicType); + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) + { + failureReason = null; + return new SymbolKeyResolution(reader.Compilation.DynamicType); + } } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ErrorTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ErrorTypeSymbolKey.cs index 387fe6987b81d..7db7c6f7b48a0 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ErrorTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ErrorTypeSymbolKey.cs @@ -57,15 +57,30 @@ private static ImmutableArray GetContainingNamespaceNamesInReverse(IName return builder.ToImmutable(); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var name = reader.ReadString(); - var containingSymbolResolution = ResolveContainer(reader); + + var containingSymbolResolution = ResolveContainer(reader, out var containingSymbolFailureReason); var arity = reader.ReadInteger(); - using var typeArguments = reader.ReadSymbolKeyArray(); + using var typeArguments = reader.ReadSymbolKeyArray(out var typeArgumentsFailureReason); + + if (containingSymbolFailureReason != null) + { + failureReason = $"({nameof(ErrorTypeSymbolKey)} {nameof(containingSymbolResolution)} failed -> {containingSymbolFailureReason})"; + return default; + } + + if (typeArgumentsFailureReason != null) + { + failureReason = $"({nameof(ErrorTypeSymbolKey)} {nameof(typeArguments)} failed -> {typeArgumentsFailureReason})"; + return default; + } + if (typeArguments.IsDefault) { + failureReason = $"({nameof(ErrorTypeSymbolKey)} {nameof(typeArguments)} failed)"; return default; } @@ -85,15 +100,15 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) reader, container: null, name, arity, typeArgumentsArray)); } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(ErrorTypeSymbolKey)} failed)", out failureReason); } - private static SymbolKeyResolution ResolveContainer(SymbolKeyReader reader) + private static SymbolKeyResolution ResolveContainer(SymbolKeyReader reader, out string failureReason) { var type = reader.ReadInteger(); if (type == 0) - return reader.ReadSymbolKey(); + return reader.ReadSymbolKey(out failureReason); if (type == 1) { @@ -104,11 +119,15 @@ private static SymbolKeyResolution ResolveContainer(SymbolKeyReader reader) for (var i = namespaceNames.Count - 1; i >= 0; i--) currentNamespace = reader.Compilation.CreateErrorNamespaceSymbol(currentNamespace, namespaceNames[i]); + failureReason = null; return new SymbolKeyResolution(currentNamespace); } if (type == 2) + { + failureReason = null; return default; + } throw ExceptionUtilities.UnexpectedValue(type); } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.EventSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.EventSymbolKey.cs index c7c9bbdf8a5e2..efffd875b6a1d 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.EventSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.EventSymbolKey.cs @@ -14,13 +14,19 @@ public static void Create(IEventSymbol symbol, SymbolKeyWriter visitor) visitor.WriteSymbolKey(symbol.ContainingType); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var metadataName = reader.ReadString(); - var containingTypeResolution = reader.ReadSymbolKey(); + var containingTypeResolution = reader.ReadSymbolKey(out var containingTypeFailureReason); + + if (containingTypeFailureReason != null) + { + failureReason = $"({nameof(EventSymbolKey)} {nameof(containingTypeResolution)} failed -> {containingTypeFailureReason})"; + return default; + } using var result = GetMembersOfNamedType(containingTypeResolution, metadataName); - return CreateResolution(result); + return CreateResolution(result, $"({nameof(EventSymbolKey)} '{metadataName}' not found)", out failureReason); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FieldSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FieldSymbolKey.cs index 4e389d647b018..220e987cc90bb 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FieldSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FieldSymbolKey.cs @@ -14,13 +14,19 @@ public static void Create(IFieldSymbol symbol, SymbolKeyWriter visitor) visitor.WriteSymbolKey(symbol.ContainingType); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var metadataName = reader.ReadString(); - var containingTypeResolution = reader.ReadSymbolKey(); + var containingTypeResolution = reader.ReadSymbolKey(out var containingTypeFailureReason); + + if (containingTypeFailureReason != null) + { + failureReason = $"({nameof(FieldSymbolKey)} {nameof(containingTypeResolution)} failed -> {containingTypeFailureReason})"; + return default; + } using var result = GetMembersOfNamedType(containingTypeResolution, metadataName); - return CreateResolution(result); + return CreateResolution(result, $"({nameof(FieldSymbolKey)} '{metadataName}' not found)", out failureReason); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs index 31e9b64f12fc3..68d5eaa611535 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs @@ -16,20 +16,40 @@ public static void Create(IFunctionPointerTypeSymbol symbol, SymbolKeyWriter vis visitor.WriteParameterTypesArray(symbol.Signature.Parameters); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var returnRefKind = reader.ReadRefKind(); - var returnType = reader.ReadSymbolKey(); + var returnType = reader.ReadSymbolKey(out var returnTypeFailureReason); using var paramRefKinds = reader.ReadRefKindArray(); - using var paramTypes = reader.ReadSymbolKeyArray(); + using var parameterTypes = reader.ReadSymbolKeyArray(out var parameterTypesFailureReason); - if (paramTypes.IsDefault || !(returnType.GetAnySymbol() is ITypeSymbol returnTypeSymbol)) + if (returnTypeFailureReason != null) { + failureReason = $"({nameof(FunctionPointerTypeSymbolKey)} {nameof(returnType)} failed -> {returnTypeFailureReason})"; return default; } + if (parameterTypesFailureReason != null) + { + failureReason = $"({nameof(FunctionPointerTypeSymbolKey)} {nameof(parameterTypes)} failed -> {parameterTypesFailureReason})"; + return default; + } + + if (parameterTypes.IsDefault) + { + failureReason = $"({nameof(FunctionPointerTypeSymbolKey)} no parameter types)"; + return default; + } + + if (!(returnType.GetAnySymbol() is ITypeSymbol returnTypeSymbol)) + { + failureReason = $"({nameof(FunctionPointerTypeSymbolKey)} no return type)"; + return default; + } + + failureReason = null; return new SymbolKeyResolution(reader.Compilation.CreateFunctionPointerTypeSymbol( - returnTypeSymbol, returnRefKind, paramTypes.ToImmutable(), paramRefKinds.ToImmutable())); + returnTypeSymbol, returnRefKind, parameterTypes.ToImmutable(), paramRefKinds.ToImmutable())); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.MethodSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.MethodSymbolKey.cs index a8d1fc0906bc6..27446a85cea4c 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.MethodSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.MethodSymbolKey.cs @@ -18,10 +18,21 @@ public static void Create(IMethodSymbol symbol, SymbolKeyWriter visitor) visitor.WriteSymbolKey(symbol.ReceiverType); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { - var reducedFromResolution = reader.ReadSymbolKey(); - var receiverTypeResolution = reader.ReadSymbolKey(); + var reducedFromResolution = reader.ReadSymbolKey(out var reducedFromFailureReason); + if (reducedFromFailureReason != null) + { + failureReason = $"({nameof(ReducedExtensionMethodSymbolKey)} {nameof(reducedFromResolution)} failed -> {reducedFromFailureReason})"; + return default; + } + + var receiverTypeResolution = reader.ReadSymbolKey(out var receiverTypeFailureReason); + if (receiverTypeFailureReason != null) + { + failureReason = $"({nameof(ReducedExtensionMethodSymbolKey)} {nameof(receiverTypeResolution)} failed -> {receiverTypeFailureReason})"; + return default; + } using var result = PooledArrayBuilder.GetInstance(); foreach (var reducedFrom in reducedFromResolution.OfType()) @@ -32,7 +43,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) } } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(ReducedExtensionMethodSymbolKey)} failed)", out failureReason); } } } @@ -47,14 +58,25 @@ public static void Create(IMethodSymbol symbol, SymbolKeyWriter visitor) visitor.WriteSymbolKeyArray(symbol.TypeArguments); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { - var constructedFrom = reader.ReadSymbolKey(); - using var typeArguments = reader.ReadSymbolKeyArray(); + var constructedFrom = reader.ReadSymbolKey(out var constructedFromFailureReason); + if (constructedFromFailureReason != null) + { + failureReason = $"({nameof(ConstructedMethodSymbolKey)} {nameof(constructedFrom)} failed -> {constructedFromFailureReason})"; + return default; + } - if (constructedFrom.SymbolCount == 0 || - typeArguments.IsDefault) + using var typeArguments = reader.ReadSymbolKeyArray(out var typeArgumentsFailureReason); + if (typeArgumentsFailureReason != null) { + failureReason = $"({nameof(ConstructedMethodSymbolKey)} {nameof(typeArguments)} failed -> {typeArgumentsFailureReason})"; + return default; + } + + if (constructedFrom.SymbolCount == 0 || typeArguments.IsDefault) + { + failureReason = $"({nameof(ConstructedMethodSymbolKey)} {nameof(typeArguments)} failed -> 'constructedFrom.SymbolCount == 0 || typeArguments.IsDefault')"; return default; } @@ -69,7 +91,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) } } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(ConstructedMethodSymbolKey)} could not successfully construct)", out failureReason); } } } @@ -110,10 +132,11 @@ public static void Create(IMethodSymbol symbol, SymbolKeyWriter visitor) visitor.PopMethod(symbol); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var metadataName = reader.ReadString(); - var containingType = reader.ReadSymbolKey(); + + var containingType = reader.ReadSymbolKey(out var containingTypeFailureReason); var arity = reader.ReadInteger(); var isPartialMethodImplementationPart = reader.ReadBoolean(); using var parameterRefKinds = reader.ReadRefKindArray(); @@ -158,15 +181,21 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) // read out the values. We don't actually need to use them, but we have // to effectively read past them in the string. - using (reader.ReadSymbolKeyArray()) + using (reader.ReadSymbolKeyArray(out _)) { - _ = reader.ReadSymbolKey(); + _ = reader.ReadSymbolKey(out _); } reader.PopMethod(methodOpt: null); } - return CreateResolution(result); + if (containingTypeFailureReason != null) + { + failureReason = $"({nameof(MethodSymbolKey)} {nameof(containingType)} failed -> {containingTypeFailureReason})"; + return default; + } + + return CreateResolution(result, $"({nameof(MethodSymbolKey)} '{metadataName}' not found)", out failureReason); } private static IMethodSymbol Resolve( @@ -207,8 +236,8 @@ private static IMethodSymbol Resolve( private static IMethodSymbol Resolve( SymbolKeyReader reader, bool isPartialMethodImplementationPart, IMethodSymbol method) { - using var originalParameterTypes = reader.ReadSymbolKeyArray(); - var returnType = (ITypeSymbol)reader.ReadSymbolKey().GetAnySymbol(); + using var originalParameterTypes = reader.ReadSymbolKeyArray(out _); + var returnType = (ITypeSymbol)reader.ReadSymbolKey(out _).GetAnySymbol(); if (reader.ParameterTypesMatch(method.OriginalDefinition.Parameters, originalParameterTypes)) { diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ModuleSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ModuleSymbolKey.cs index 74275d638e13e..5bd01ebb70a3f 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ModuleSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ModuleSymbolKey.cs @@ -11,9 +11,15 @@ private static class ModuleSymbolKey public static void Create(IModuleSymbol symbol, SymbolKeyWriter visitor) => visitor.WriteSymbolKey(symbol.ContainingSymbol); - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { - var containingSymbolResolution = reader.ReadSymbolKey(); + var containingSymbolResolution = reader.ReadSymbolKey(out var containingSymbolFailureReason); + + if (containingSymbolFailureReason != null) + { + failureReason = $"({nameof(ModuleSymbolKey)} {nameof(containingSymbolResolution)} failed -> {containingSymbolFailureReason})"; + return default; + } using var result = PooledArrayBuilder.GetInstance(); foreach (var assembly in containingSymbolResolution.OfType()) @@ -23,7 +29,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) result.AddValuesIfNotNull(assembly.Modules); } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(ModuleSymbolKey)} failed)", out failureReason); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs index 75cbf7dfdc12c..4b94ebe15abc1 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs @@ -28,16 +28,29 @@ public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor) } } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var metadataName = reader.ReadString(); - var containingSymbolResolution = reader.ReadSymbolKey(); + var containingSymbolResolution = reader.ReadSymbolKey(out var containingSymbolFailureReason); var arity = reader.ReadInteger(); var isUnboundGenericType = reader.ReadBoolean(); - using var typeArguments = reader.ReadSymbolKeyArray(); + using var typeArguments = reader.ReadSymbolKeyArray(out var typeArgumentsFailureReason); + + if (containingSymbolFailureReason != null) + { + failureReason = $"({nameof(NamedTypeSymbolKey)} {nameof(containingSymbolFailureReason)} failed -> {containingSymbolFailureReason})"; + return default; + } + + if (typeArgumentsFailureReason != null) + { + failureReason = $"({nameof(NamedTypeSymbolKey)} {nameof(typeArguments)} failed -> {typeArgumentsFailureReason})"; + return default; + } if (typeArguments.IsDefault) { + failureReason = $"({nameof(NamedTypeSymbolKey)} {nameof(typeArguments)} failed)"; return default; } @@ -52,7 +65,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) isUnboundGenericType, typeArgumentArray); } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(NamedTypeSymbolKey)} failed)", out failureReason); } private static void Resolve( diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.NamespaceSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.NamespaceSymbolKey.cs index 22298b8835924..b3e0fbfc437f2 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.NamespaceSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.NamespaceSymbolKey.cs @@ -52,14 +52,21 @@ public static void Create(INamespaceSymbol symbol, SymbolKeyWriter visitor) } } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var metadataName = reader.ReadString(); var isCompilationGlobalNamespace = reader.ReadBoolean(); - var containingSymbolResolution = reader.ReadSymbolKey(); + var containingSymbolResolution = reader.ReadSymbolKey(out var containingSymbolFailureReason); + + if (containingSymbolFailureReason != null) + { + failureReason = $"({nameof(EventSymbolKey)} {nameof(containingSymbolResolution)} failed -> {containingSymbolFailureReason})"; + return default; + } if (isCompilationGlobalNamespace) { + failureReason = null; return new SymbolKeyResolution(reader.Compilation.GlobalNamespace); } @@ -88,7 +95,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) } } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(NamespaceSymbolKey)} '{metadataName}' not found)", out failureReason); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ParameterSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ParameterSymbolKey.cs index 58cbb56dc7e04..bca5b85438580 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ParameterSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.ParameterSymbolKey.cs @@ -16,10 +16,16 @@ public static void Create(IParameterSymbol symbol, SymbolKeyWriter visitor) visitor.WriteSymbolKey(symbol.ContainingSymbol); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var metadataName = reader.ReadString(); - var containingSymbolResolution = reader.ReadSymbolKey(); + var containingSymbolResolution = reader.ReadSymbolKey(out var containingSymbolFailureReason); + + if (containingSymbolFailureReason != null) + { + failureReason = $"({nameof(ParameterSymbolKey)} {nameof(containingSymbolResolution)} failed -> {containingSymbolFailureReason})"; + return default; + } using var result = PooledArrayBuilder.GetInstance(); foreach (var container in containingSymbolResolution) @@ -55,7 +61,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) } } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(ParameterSymbolKey)} '{metadataName}' not found)", out failureReason); } private static void Resolve( diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.PointerTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.PointerTypeSymbolKey.cs index 28cbc7980e3b3..37a6e0339bce7 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.PointerTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.PointerTypeSymbolKey.cs @@ -11,9 +11,15 @@ private static class PointerTypeSymbolKey public static void Create(IPointerTypeSymbol symbol, SymbolKeyWriter visitor) => visitor.WriteSymbolKey(symbol.PointedAtType); - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { - var pointedAtTypeResolution = reader.ReadSymbolKey(); + var pointedAtTypeResolution = reader.ReadSymbolKey(out var pointedAtTypeFailureReason); + + if (pointedAtTypeFailureReason != null) + { + failureReason = $"({nameof(PointerTypeSymbolKey)} {nameof(pointedAtTypeResolution)} failed -> {pointedAtTypeFailureReason})"; + return default; + } using var result = PooledArrayBuilder.GetInstance(pointedAtTypeResolution.SymbolCount); foreach (var typeSymbol in pointedAtTypeResolution.OfType()) @@ -21,7 +27,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) result.AddIfNotNull(reader.Compilation.CreatePointerTypeSymbol(typeSymbol)); } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(PointerTypeSymbolKey)} could not resolve)", out failureReason); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.PropertySymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.PropertySymbolKey.cs index a9e0306209664..757418e0d3f6a 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.PropertySymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.PropertySymbolKey.cs @@ -17,17 +17,29 @@ public static void Create(IPropertySymbol symbol, SymbolKeyWriter visitor) visitor.WriteParameterTypesArray(symbol.OriginalDefinition.Parameters); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var metadataName = reader.ReadString(); - var containingTypeResolution = reader.ReadSymbolKey(); + var containingTypeResolution = reader.ReadSymbolKey(out var containingTypeFailureReason); var isIndexer = reader.ReadBoolean(); - using var refKinds = reader.ReadRefKindArray(); - using var parameterTypes = reader.ReadSymbolKeyArray(); + using var parameterTypes = reader.ReadSymbolKeyArray(out var parameterTypesFailureReason); + + if (containingTypeFailureReason != null) + { + failureReason = $"({nameof(PropertySymbolKey)} {nameof(containingTypeResolution)} failed -> {containingTypeFailureReason})"; + return default; + } + + if (parameterTypesFailureReason != null) + { + failureReason = $"({nameof(PropertySymbolKey)} {nameof(parameterTypes)} failed -> {parameterTypesFailureReason})"; + return default; + } if (parameterTypes.IsDefault) { + failureReason = $"({nameof(PropertySymbolKey)} no parameter types)"; return default; } @@ -45,7 +57,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) } } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(PropertySymbolKey)} '{metadataName}' not found)", out failureReason); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyReader.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyReader.cs index 8459282621be1..41ebbdf20795f 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyReader.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyReader.cs @@ -25,9 +25,9 @@ private abstract class Reader : IDisposable protected const char SpaceChar = ' '; protected const char DoubleQuoteChar = '"'; - private readonly Func _readString; - private readonly Func _readBoolean; - private readonly Func _readRefKind; + private readonly ReadFunction _readString; + private readonly ReadFunction _readBoolean; + private readonly ReadFunction _readRefKind; protected string Data { get; private set; } public CancellationToken CancellationToken { get; private set; } @@ -104,14 +104,22 @@ protected char EatSpace() => Eat(SpaceChar); public bool ReadBoolean() + => ReadBoolean(out _); + + public bool ReadBoolean(out string failureReason) { + failureReason = null; var val = ReadInteger(); Debug.Assert(val == 0 || val == 1); return val == 1; } public TStringResult ReadString() + => ReadString(out _); + + public TStringResult ReadString(out string failureReason) { + failureReason = null; EatSpace(); return ReadStringNoSpace(); } @@ -164,15 +172,15 @@ private void EatDoubleQuote() => Eat(DoubleQuoteChar); public PooledArrayBuilder ReadStringArray() - => ReadArray(_readString); + => ReadArray(_readString, out _); public PooledArrayBuilder ReadBooleanArray() - => ReadArray(_readBoolean); + => ReadArray(_readBoolean, out _); public PooledArrayBuilder ReadRefKindArray() - => ReadArray(_readRefKind); + => ReadArray(_readRefKind, out _); - public PooledArrayBuilder ReadArray(Func readFunction) + public PooledArrayBuilder ReadArray(ReadFunction readFunction, out string failureReason) { var builder = PooledArrayBuilder.GetInstance(); EatSpace(); @@ -182,19 +190,33 @@ public PooledArrayBuilder ReadArray(Func readFunction) EatOpenParen(); Eat(SymbolKeyType.Array); + string totalFailureReason = null; var length = ReadInteger(); for (var i = 0; i < length; i++) { CancellationToken.ThrowIfCancellationRequested(); - builder.Builder.Add(readFunction()); + builder.Builder.Add(readFunction(out var elementFailureReason)); + + if (elementFailureReason != null) + { + var reason = $"element {i} failed {elementFailureReason}"; + totalFailureReason = totalFailureReason == null + ? $"({reason})" + : $"(totalFailureReason -> {reason})"; + } } EatCloseParen(); + failureReason = totalFailureReason; return builder; } public RefKind ReadRefKind() + => ReadRefKind(out _); + + public RefKind ReadRefKind(out string failureReason) { + failureReason = null; return (RefKind)ReadInteger(); } } @@ -267,13 +289,15 @@ protected override object CreateNullForString() => null; } + private delegate T ReadFunction(out string failureReason); + private class SymbolKeyReader : Reader { private static readonly ObjectPool s_readerPool = SharedPools.Default(); private readonly Dictionary _idToResult = new Dictionary(); - private readonly Func _readSymbolKey; - private readonly Func _readLocation; + private readonly ReadFunction _readSymbolKey; + private readonly ReadFunction _readLocation; public Compilation Compilation { get; private set; } public bool IgnoreAssemblyKey { get; private set; } @@ -379,7 +403,7 @@ internal SyntaxTree GetSyntaxTree(string filePath) #region Symbols - public SymbolKeyResolution ReadSymbolKey() + public SymbolKeyResolution ReadSymbolKey(out string failureReason) { CancellationToken.ThrowIfCancellationRequested(); EatSpace(); @@ -388,6 +412,7 @@ public SymbolKeyResolution ReadSymbolKey() if (type == SymbolKeyType.Null) { Eat(type); + failureReason = null; return default; } @@ -401,10 +426,11 @@ public SymbolKeyResolution ReadSymbolKey() { var id = ReadInteger(); result = _idToResult[id]; + failureReason = null; } else { - result = ReadWorker(type); + result = ReadWorker(type, out failureReason); var id = ReadInteger(); _idToResult[id] = result; } @@ -414,32 +440,32 @@ public SymbolKeyResolution ReadSymbolKey() return result; } - private SymbolKeyResolution ReadWorker(SymbolKeyType type) + private SymbolKeyResolution ReadWorker(SymbolKeyType type, out string failureReason) => type switch { - SymbolKeyType.Alias => AliasSymbolKey.Resolve(this), - SymbolKeyType.BodyLevel => BodyLevelSymbolKey.Resolve(this), - SymbolKeyType.ConstructedMethod => ConstructedMethodSymbolKey.Resolve(this), - SymbolKeyType.NamedType => NamedTypeSymbolKey.Resolve(this), - SymbolKeyType.ErrorType => ErrorTypeSymbolKey.Resolve(this), - SymbolKeyType.Field => FieldSymbolKey.Resolve(this), - SymbolKeyType.FunctionPointer => FunctionPointerTypeSymbolKey.Resolve(this), - SymbolKeyType.DynamicType => DynamicTypeSymbolKey.Resolve(this), - SymbolKeyType.Method => MethodSymbolKey.Resolve(this), - SymbolKeyType.Namespace => NamespaceSymbolKey.Resolve(this), - SymbolKeyType.PointerType => PointerTypeSymbolKey.Resolve(this), - SymbolKeyType.Parameter => ParameterSymbolKey.Resolve(this), - SymbolKeyType.Property => PropertySymbolKey.Resolve(this), - SymbolKeyType.ArrayType => ArrayTypeSymbolKey.Resolve(this), - SymbolKeyType.Assembly => AssemblySymbolKey.Resolve(this), - SymbolKeyType.TupleType => TupleTypeSymbolKey.Resolve(this), - SymbolKeyType.Module => ModuleSymbolKey.Resolve(this), - SymbolKeyType.Event => EventSymbolKey.Resolve(this), - SymbolKeyType.ReducedExtensionMethod => ReducedExtensionMethodSymbolKey.Resolve(this), - SymbolKeyType.TypeParameter => TypeParameterSymbolKey.Resolve(this), - SymbolKeyType.AnonymousType => AnonymousTypeSymbolKey.Resolve(this), - SymbolKeyType.AnonymousFunctionOrDelegate => AnonymousFunctionOrDelegateSymbolKey.Resolve(this), - SymbolKeyType.TypeParameterOrdinal => TypeParameterOrdinalSymbolKey.Resolve(this), + SymbolKeyType.Alias => AliasSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.BodyLevel => BodyLevelSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.ConstructedMethod => ConstructedMethodSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.NamedType => NamedTypeSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.ErrorType => ErrorTypeSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.Field => FieldSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.FunctionPointer => FunctionPointerTypeSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.DynamicType => DynamicTypeSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.Method => MethodSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.Namespace => NamespaceSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.PointerType => PointerTypeSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.Parameter => ParameterSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.Property => PropertySymbolKey.Resolve(this, out failureReason), + SymbolKeyType.ArrayType => ArrayTypeSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.Assembly => AssemblySymbolKey.Resolve(this, out failureReason), + SymbolKeyType.TupleType => TupleTypeSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.Module => ModuleSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.Event => EventSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.ReducedExtensionMethod => ReducedExtensionMethodSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.TypeParameter => TypeParameterSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.AnonymousType => AnonymousTypeSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.AnonymousFunctionOrDelegate => AnonymousFunctionOrDelegateSymbolKey.Resolve(this, out failureReason), + SymbolKeyType.TypeParameterOrdinal => TypeParameterOrdinalSymbolKey.Resolve(this, out failureReason), _ => throw new NotImplementedException(), }; @@ -453,9 +479,14 @@ private SymbolKeyResolution ReadWorker(SymbolKeyType type) /// Callers should the instance returned. No check is /// necessary if default was returned before calling /// - public PooledArrayBuilder ReadSymbolKeyArray() where TSymbol : ISymbol + public PooledArrayBuilder ReadSymbolKeyArray(out string failureReason) where TSymbol : ISymbol { - using var resolutions = ReadArray(_readSymbolKey); + using var resolutions = ReadArray(_readSymbolKey, out var elementsFailureReason); + if (elementsFailureReason != null) + { + failureReason = elementsFailureReason; + return default; + } var result = PooledArrayBuilder.GetInstance(); foreach (var resolution in resolutions) @@ -467,10 +498,12 @@ public PooledArrayBuilder ReadSymbolKeyArray() where TSymbol : else { result.Dispose(); + failureReason = $"({nameof(ReadSymbolKeyArray)} incorrect type for element)"; return default; } } + failureReason = null; return result; } @@ -494,12 +527,13 @@ protected override string CreateNullForString() #region Locations - public Location ReadLocation() + public Location ReadLocation(out string failureReason) { EatSpace(); if ((SymbolKeyType)Data[Position] == SymbolKeyType.Null) { Eat(SymbolKeyType.Null); + failureReason = null; return null; } @@ -515,14 +549,21 @@ public Location ReadLocation() var syntaxTree = GetSyntaxTree(filePath); if (syntaxTree != null) { + failureReason = null; return Location.Create(syntaxTree, new TextSpan(start, length)); } } else if (kind == LocationKind.MetadataFile) { - var assemblyResolution = ReadSymbolKey(); + var assemblyResolution = ReadSymbolKey(out var assemblyFailureReason); var moduleName = ReadString(); + if (assemblyFailureReason != null) + { + failureReason = $"{nameof(ReadLocation)} {nameof(assemblyResolution)} failed -> " + assemblyFailureReason; + return Location.None; + } + // We may be resolving in a compilation where we don't have a module // with this name. In that case, just map this location to none. if (assemblyResolution.GetAnySymbol() is IAssemblySymbol assembly) @@ -533,12 +574,14 @@ public Location ReadLocation() var location = FirstOrDefault(module.Locations); if (location != null) { + failureReason = null; return location; } } } } + failureReason = null; return Location.None; } @@ -576,8 +619,8 @@ private static IModuleSymbol GetModule(IEnumerable modules, strin return null; } - public PooledArrayBuilder ReadLocationArray() - => ReadArray(_readLocation); + public PooledArrayBuilder ReadLocationArray(out string failureReason) + => ReadArray(_readLocation, out failureReason); #endregion } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TupleTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TupleTypeSymbolKey.cs index cb2557af71a76..66089b79ec865 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TupleTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TupleTypeSymbolKey.cs @@ -17,11 +17,20 @@ public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor) { Debug.Assert(symbol.IsTupleType); + var isError = symbol.TupleUnderlyingType.TypeKind == TypeKind.Error; + var friendlyNames = ArrayBuilder.GetInstance(); var locations = ArrayBuilder.GetInstance(); - var isError = symbol.TupleUnderlyingType.TypeKind == TypeKind.Error; + foreach (var element in symbol.TupleElements) + { + friendlyNames.Add(element.IsImplicitlyDeclared ? null : element.Name); + locations.Add(FirstOrDefault(element.Locations) ?? Location.None); + } + visitor.WriteBoolean(isError); + visitor.WriteStringArray(friendlyNames.ToImmutableAndFree()); + visitor.WriteLocationArray(locations.ToImmutableAndFree()); if (isError) { @@ -38,76 +47,79 @@ public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteSymbolKey(symbol.TupleUnderlyingType); } + } - foreach (var element in symbol.TupleElements) - { - friendlyNames.Add(element.IsImplicitlyDeclared ? null : element.Name); - locations.Add(FirstOrDefault(element.Locations) ?? Location.None); - } + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) + { + var isError = reader.ReadBoolean(); - visitor.WriteStringArray(friendlyNames.ToImmutableAndFree()); - visitor.WriteLocationArray(locations.ToImmutableAndFree()); + return isError ? ResolveErrorTuple(reader, out failureReason) : ResolveNormalTuple(reader, out failureReason); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + private static SymbolKeyResolution ResolveNormalTuple(SymbolKeyReader reader, out string failureReason) { - var isError = reader.ReadBoolean(); - if (isError) - { - using var elementTypes = reader.ReadSymbolKeyArray(); - using var elementNames = reader.ReadStringArray(); - var elementLocations = ReadElementLocations(reader); + using var elementNames = reader.ReadStringArray(); + var elementLocations = ReadElementLocations(reader, out var elementLocationsFailureReason); + var underlyingTypeResolution = reader.ReadSymbolKey(out var underlyingTypeFailureReason); - if (!elementTypes.IsDefault) - { - try - { - var result = reader.Compilation.CreateTupleTypeSymbol( - elementTypes.ToImmutable(), elementNames.ToImmutable(), elementLocations); - return new SymbolKeyResolution(result); - } - catch (ArgumentException) - { - } - } + if (underlyingTypeFailureReason != null) + { + failureReason = $"({nameof(TupleTypeSymbolKey)} {nameof(underlyingTypeResolution)} failed -> {underlyingTypeFailureReason})"; + return default; } - else + + using var result = PooledArrayBuilder.GetInstance(); + + var elementNamesArray = elementNames.ToImmutable(); + foreach (var namedType in underlyingTypeResolution.OfType()) { - var underlyingTypeResolution = reader.ReadSymbolKey(); - using var elementNamesBuilder = reader.ReadStringArray(); - var elementLocations = ReadElementLocations(reader); + result.AddIfNotNull(reader.Compilation.CreateTupleTypeSymbol( + namedType, elementNamesArray, elementLocations)); + } - try - { - using var result = PooledArrayBuilder.GetInstance(); + return CreateResolution(result, $"({nameof(TupleTypeSymbolKey)} failed)", out failureReason); + } - var elementNames = elementNamesBuilder.ToImmutable(); - foreach (var namedType in underlyingTypeResolution.OfType()) - { - result.AddIfNotNull(reader.Compilation.CreateTupleTypeSymbol( - namedType, elementNames, elementLocations)); - } + private static SymbolKeyResolution ResolveErrorTuple(SymbolKeyReader reader, out string failureReason) + { + using var elementNames = reader.ReadStringArray(); + var elementLocations = ReadElementLocations(reader, out var elementLocationsFailureReason); + using var elementTypes = reader.ReadSymbolKeyArray(out var elementTypesFailureReason); - return CreateResolution(result); - } - catch (ArgumentException) - { - } + if (elementLocationsFailureReason != null) + { + failureReason = $"({nameof(TupleTypeSymbolKey)} {nameof(elementLocations)} failed -> {elementLocationsFailureReason})"; + return default; + } + + if (elementTypesFailureReason != null) + { + failureReason = $"({nameof(TupleTypeSymbolKey)} {nameof(elementTypes)} failed -> {elementTypesFailureReason})"; + return default; + } + + if (elementTypes.IsDefault) + { + failureReason = $"({nameof(TupleTypeSymbolKey)} {nameof(elementTypes)} failed)"; + return default; } - return new SymbolKeyResolution(reader.Compilation.ObjectType); + var result = reader.Compilation.CreateTupleTypeSymbol( + elementTypes.ToImmutable(), elementNames.ToImmutable(), elementLocations); + failureReason = null; + return new SymbolKeyResolution(result); } - private static ImmutableArray ReadElementLocations(SymbolKeyReader reader) + private static ImmutableArray ReadElementLocations(SymbolKeyReader reader, out string failureReason) { - using var elementLocations = reader.ReadLocationArray(); + using var elementLocations = reader.ReadLocationArray(out failureReason); + if (failureReason != null) + return default; // Compiler API requires that all the locations are non-null, or that there is a default // immutable array passed in. if (elementLocations.Builder.All(loc => loc == null)) - { return default; - } return elementLocations.ToImmutable(); } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TypeParameterOrdinalSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TypeParameterOrdinalSymbolKey.cs index cd422fb78d0c6..f1d5c470ec03c 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TypeParameterOrdinalSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TypeParameterOrdinalSymbolKey.cs @@ -17,15 +17,21 @@ public static void Create(ITypeParameterSymbol symbol, int methodIndex, SymbolKe visitor.WriteInteger(symbol.Ordinal); } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var methodIndex = reader.ReadInteger(); var ordinal = reader.ReadInteger(); var method = reader.ResolveMethod(methodIndex); + var typeParameter = method?.TypeParameters[ordinal]; - return typeParameter == null - ? default - : new SymbolKeyResolution(typeParameter); + if (typeParameter == null) + { + failureReason = $"({nameof(TypeParameterOrdinalSymbolKey)} failed)"; + return default; + } + + failureReason = null; + return new SymbolKeyResolution(typeParameter); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TypeParameterSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TypeParameterSymbolKey.cs index ef2cf73383080..fcafa1134af87 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TypeParameterSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.TypeParameterSymbolKey.cs @@ -25,20 +25,34 @@ public static void Create(ITypeParameterSymbol symbol, SymbolKeyWriter visitor) } } - public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string failureReason) { var isCref = reader.ReadBoolean(); if (isCref) { - var location = reader.ReadLocation(); + var location = reader.ReadLocation(out var locationFailureReason); + if (locationFailureReason != null) + { + failureReason = $"({nameof(TypeParameterSymbolKey)} {nameof(location)} failed -> {locationFailureReason})"; + return default; + } + var resolution = reader.ResolveLocation(location); + + failureReason = null; return resolution.GetValueOrDefault(); } else { var metadataName = reader.ReadString(); - var containingSymbolResolution = reader.ReadSymbolKey(); + var containingSymbolResolution = reader.ReadSymbolKey(out var containingSymbolFailureReason); + + if (containingSymbolFailureReason != null) + { + failureReason = $"({nameof(TypeParameterSymbolKey)} {nameof(containingSymbolResolution)} failed -> {containingSymbolFailureReason})"; + return default; + } using var result = PooledArrayBuilder.GetInstance(); foreach (var containingSymbol in containingSymbolResolution) @@ -52,7 +66,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) } } - return CreateResolution(result); + return CreateResolution(result, $"({nameof(TypeParameterSymbolKey)} '{metadataName}' not found)", out failureReason); } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.cs index b558e880cc728..af4bca827b1ba 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.cs @@ -160,16 +160,31 @@ public static bool CanCreate(ISymbol symbol, CancellationToken cancellationToken public static SymbolKeyResolution ResolveString( string symbolKey, Compilation compilation, bool ignoreAssemblyKey = false, CancellationToken cancellationToken = default) + { + return ResolveString(symbolKey, compilation, ignoreAssemblyKey, out _, cancellationToken); + } + + public static SymbolKeyResolution ResolveString( + string symbolKey, Compilation compilation, + out string failureReason, CancellationToken cancellationToken) + { + return ResolveString(symbolKey, compilation, ignoreAssemblyKey: false, out failureReason, cancellationToken); + } + + public static SymbolKeyResolution ResolveString( + string symbolKey, Compilation compilation, bool ignoreAssemblyKey, + out string failureReason, CancellationToken cancellationToken) { using var reader = SymbolKeyReader.GetReader( symbolKey, compilation, ignoreAssemblyKey, cancellationToken); var version = reader.ReadFormatVersion(); if (version != FormatVersion) { + failureReason = $"({nameof(SymbolKey)} invalid format '${version}')"; return default; } - var result = reader.ReadSymbolKey(); + var result = reader.ReadSymbolKey(out failureReason); Debug.Assert(reader.Position == symbolKey.Length); return result; } @@ -208,7 +223,8 @@ public SymbolKeyResolution Resolve( public override string ToString() => _symbolKeyData; - private static SymbolKeyResolution CreateResolution(PooledArrayBuilder symbols) + private static SymbolKeyResolution CreateResolution( + PooledArrayBuilder symbols, string reasonIfFailed, out string failureReason) where TSymbol : class, ISymbol { #if DEBUG @@ -220,14 +236,17 @@ private static SymbolKeyResolution CreateResolution(PooledArrayBuilder< if (symbols.Builder.Count == 0) { + failureReason = reasonIfFailed; return default; } else if (symbols.Builder.Count == 1) { + failureReason = null; return new SymbolKeyResolution(symbols.Builder[0]); } else { + failureReason = null; return new SymbolKeyResolution( ImmutableArray.CastUp(symbols.Builder.ToImmutable()), CandidateReason.Ambiguous);