提交 05b2ed1b 编写于 作者: C Cyrus Najmabadi

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

## API Review Notes for September 30th, 2019
### Changes reviewed
Starting commit: `38c90f8401f9e3ee5fb7c82aac36f6b85fdda979`
Ending Commit: `b8a5611e3db4f7ac3b5e1404b129304b5baf843e`
### Notes
IVariableDeclarationOperation:
- What does scripting do for using local declarations in IOperation?
......
## API Review Notes for April 15th, 2020
### Changes reviewed
Starting commit: `c827247a767c0c434dcb77496038b163b9e011da`
Ending Commit: `3375a7b209d1f590940af043e9e39f2cbb503845`
### Notes
#### Everything but Source Generators:
* `Project.RemoveDocuments`: Everything else in this type uses `IEnumerable<T>`, not `ImmutableArray<T>`. If we could start again from day 1 we might make everything that, but given that everything today uses the former, we should do so here. This applies to the overloads on `Solution` as well.
* `Solution.RemoveAdditonalDocuments/RemoveAnalyzerConfigDocuments`: We added these to `Solution`, but not to project, even though that also has the invididual `Remove` methods. We should add them to `Project` as well.
* `DocumentOptionSet.GetOption`: This API was added as a `new` on the concrete `DocumentOptionSet` to cover a change when we moved the implementation up to `OptionSet` and made the method non-virtual. This is not actually a breaking change, so we should remove this.
#### Source Generators:
As a general note, changes that we make here are _not_ considered breaking changes post 16.6.
However, we did take a broad overview of the API surface and have some notes for @chsienki.
* `GeneratorAttribute`: we should consider adding a `LanguageName` attribute to this type.
* `InitializationContext`: Rename to something like `SourceGeneratorInitialzationContext` or similar. Current name is ambiguous.
* `InitializationContext.RegisterForNotifications`:
* Naming is inconsistent with existing `Action` ending for analyzer register methods.
* `SyntaxReceiverCreator`: all other `RegisterForXAction` methods in analyzers use an `Action` or `Func`, as appropriate. We should consider doing the same here.
* `ISyntaxReceiver`: This may be redundant with existing APIs.
* `SourceGeneratorContext`: There is not currently a way to share semantic models and other binding info between source generators. We should design a way for this info to be shared so we can avoid introducing lots of binding from generators.
ErrorLogPath removed from CLO, moved to ErrorLogOptions
- We should probably maintain this API
- Just forward to the old implementation
TextDocument
- Should we not remove the constructor? This is a binary breaking change
- This empty constructor cannot be used.
- We'll keep the change.
Workspace
- CanApplyParseOptionChange going from virtual protected to virtual public is a source and binary breaking change
- We should look at having a new non-virtual public method on Workspace and forward to this API.
SyntaxFactory.AnonymousMethodExpression
- Added overload with multiple parameters
- Followup on usage
Formatter.OrganizeUsings
- Should make cancellationtoken optional?
- Need to followup with framework on what the current guidelines are
- Make this default for now
......@@ -35,9 +35,9 @@ internal CSharpCommandLineParser(bool isScriptCommandLineParser = false)
protected override string RegularFileExtension { get { return ".cs"; } }
protected override string ScriptFileExtension { get { return ".csx"; } }
internal sealed override CommandLineArguments CommonParse(IEnumerable<string> args, string baseDirectory, string? sdkDirectoryOpt, string additionalReferenceDirectories)
internal sealed override CommandLineArguments CommonParse(IEnumerable<string> args, string baseDirectory, string? sdkDirectory, string? additionalReferenceDirectories)
{
return Parse(args, baseDirectory, sdkDirectoryOpt, additionalReferenceDirectories);
return Parse(args, baseDirectory, sdkDirectory, additionalReferenceDirectories);
}
/// <summary>
......
......@@ -67,7 +67,7 @@ internal virtual IEnumerable<string> EnumerateFiles(string? directory, string fi
return Directory.EnumerateFiles(directory, fileNamePattern, searchOption);
}
internal abstract CommandLineArguments CommonParse(IEnumerable<string> args, string baseDirectory, string? sdkDirectoryOpt, string additionalReferenceDirectories);
internal abstract CommandLineArguments CommonParse(IEnumerable<string> args, string baseDirectory, string? sdkDirectory, string? additionalReferenceDirectories);
/// <summary>
/// Parses a command line.
......@@ -77,7 +77,7 @@ internal virtual IEnumerable<string> EnumerateFiles(string? directory, string fi
/// <param name="sdkDirectory">The directory to search for mscorlib, or null if not available.</param>
/// <param name="additionalReferenceDirectories">A string representing additional reference paths.</param>
/// <returns>a <see cref="CommandLineArguments"/> object representing the parsed command line.</returns>
public CommandLineArguments Parse(IEnumerable<string> args, string baseDirectory, string? sdkDirectory, string additionalReferenceDirectories)
public CommandLineArguments Parse(IEnumerable<string> args, string baseDirectory, string? sdkDirectory, string? additionalReferenceDirectories)
{
return CommonParse(args, baseDirectory, sdkDirectory, additionalReferenceDirectories);
}
......
......@@ -101,9 +101,8 @@ private async Task<DefinitionItem> GetDefinitionItemAsync(ISymbol definition)
{
if (!_definitionToItem.TryGetValue(definition, out var definitionItem))
{
var projectId = _solution.GetExactProjectId(definition);
definitionItem = await definition.ToClassifiedDefinitionItemAsync(
_solution.GetProject(projectId), includeHiddenLocations: false,
_solution.GetOriginatingProject(definition), includeHiddenLocations: false,
_options, _context.CancellationToken).ConfigureAwait(false);
_definitionToItem[definition] = definitionItem;
......
......@@ -61,18 +61,14 @@ public static async Task<(Solution solution, ISymbol symbol, ImmutableArray<ISym
var (symbol, project) = symbolAndProjectOpt.Value;
return await FindSourceImplementationsAsync(
symbol, project.Solution, cancellationToken).ConfigureAwait(false);
project.Solution, symbol, cancellationToken).ConfigureAwait(false);
}
private static async Task<(Solution solution, ISymbol symbol, ImmutableArray<ISymbol> implementations, string message)?> FindSourceImplementationsAsync(
ISymbol symbol, Solution solution, CancellationToken cancellationToken)
Solution solution, ISymbol symbol, CancellationToken cancellationToken)
{
var builder = new HashSet<ISymbol>(SymbolEquivalenceComparer.Instance);
// Find the direct implementations first.
builder.AddRange(await FindSourceImplementationsWorkerAsync(
symbol, solution, cancellationToken).ConfigureAwait(false));
// If we're in a linked file, try to find all the symbols this links to, and find all the implementations of
// each of those linked symbols. De-dupe the results so the user only gets unique results.
var linkedSymbols = await SymbolFinder.FindLinkedSymbolsAsync(
......@@ -81,25 +77,24 @@ public static async Task<(Solution solution, ISymbol symbol, ImmutableArray<ISym
foreach (var linkedSymbol in linkedSymbols)
{
builder.AddRange(await FindSourceImplementationsWorkerAsync(
linkedSymbol, solution, cancellationToken).ConfigureAwait((bool)false));
solution, linkedSymbol, cancellationToken).ConfigureAwait((bool)false));
}
var result = builder.ToImmutableArray();
var message = result.IsEmpty ? EditorFeaturesResources.The_symbol_has_no_implementations : null;
return result.Length == 0
? (solution, symbol, result, EditorFeaturesResources.The_symbol_has_no_implementations)
: (solution, symbol, result, null);
return (solution, symbol, result, message);
}
private static async Task<ImmutableArray<ISymbol>> FindSourceImplementationsWorkerAsync(
ISymbol symbol, Solution solution, CancellationToken cancellationToken)
Solution solution, ISymbol symbol, CancellationToken cancellationToken)
{
var implementations = await FindSourceAndMetadataImplementationsAsync(symbol, solution, cancellationToken).ConfigureAwait(false);
var implementations = await FindSourceAndMetadataImplementationsAsync(solution, symbol, cancellationToken).ConfigureAwait(false);
return implementations.WhereAsArray(s => s.Locations.Any(l => l.IsInSource));
}
private static async Task<ImmutableArray<ISymbol>> FindSourceAndMetadataImplementationsAsync(
ISymbol symbol, Solution solution, CancellationToken cancellationToken)
Solution solution, ISymbol symbol, CancellationToken cancellationToken)
{
if (symbol.IsInterfaceType() || symbol.IsImplementableMember())
{
......
......@@ -47,11 +47,10 @@ public async Task FindBasesAsync(Document document, int position, IFindUsagesCon
baseSymbol, solution, cancellationToken).ConfigureAwait(false);
if (sourceDefinition != null)
{
var sourceDefProjectId = solution.GetExactProjectId(sourceDefinition);
var definitionItem = await sourceDefinition.ToClassifiedDefinitionItemAsync(
solution.GetProject(sourceDefProjectId), includeHiddenLocations: false,
FindReferencesSearchOptions.Default, cancellationToken: cancellationToken)
.ConfigureAwait(false);
solution.GetOriginatingProject(sourceDefinition), includeHiddenLocations: false,
FindReferencesSearchOptions.Default, cancellationToken: cancellationToken).ConfigureAwait(false);
await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false);
found = true;
}
......
......@@ -2,18 +2,20 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
namespace Microsoft.CodeAnalysis.Interactive
{
internal partial class InteractiveHost
{
private struct InitializedRemoteService
private readonly struct InitializedRemoteService
{
public readonly RemoteService ServiceOpt;
public readonly RemoteService Service;
public readonly RemoteExecutionResult InitializationResult;
public InitializedRemoteService(RemoteService service, RemoteExecutionResult initializationResult)
{
ServiceOpt = service;
Service = service;
InitializationResult = initializationResult;
}
}
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Globalization;
using System.Threading;
......@@ -41,7 +43,7 @@ public void Dispose()
// If the value has been calculated already, dispose the service.
if (InitializedService.TryGetValue(out var initializedService))
{
initializedService.ServiceOpt?.Dispose();
initializedService.Service?.Dispose();
}
}
......@@ -101,7 +103,7 @@ private async Task<InitializedRemoteService> TryStartAndInitializeProcessAsync(C
}
}
private Task<RemoteService> TryStartProcessAsync(string hostPath, CultureInfo culture, CancellationToken cancellationToken)
private Task<RemoteService?> TryStartProcessAsync(string hostPath, CultureInfo culture, CancellationToken cancellationToken)
{
return Task.Run(() => Host.TryStartProcess(hostPath, culture, cancellationToken));
}
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Diagnostics;
using System.Runtime.Remoting;
......@@ -12,7 +14,7 @@ namespace Microsoft.CodeAnalysis.Interactive
{
internal partial class InteractiveHost
{
internal class RemoteAsyncOperation<TResult> : MarshalByRefObject
internal sealed class RemoteAsyncOperation<TResult> : MarshalByRefObject
{
private readonly RemoteService _remoteService;
private readonly TaskCompletionSource<TResult> _completion;
......@@ -20,17 +22,12 @@ internal class RemoteAsyncOperation<TResult> : MarshalByRefObject
internal RemoteAsyncOperation(RemoteService service)
{
Debug.Assert(service != null);
_remoteService = service;
_completion = new TaskCompletionSource<TResult>();
_processExitedHandler = new EventHandler((_, __) => ProcessExited());
}
public override object InitializeLifetimeService()
{
return null;
}
public override object? InitializeLifetimeService() => null;
public Task<TResult> ExecuteAsync(Action<Service, RemoteAsyncOperation<TResult>> action)
{
......@@ -67,7 +64,7 @@ public void Completed(TResult result)
private void ProcessExited()
{
Completed(result: default(TResult));
Completed(result: default!);
}
public void SetResult(TResult result)
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Diagnostics;
using System.IO;
......@@ -23,17 +25,13 @@ internal sealed class RemoteService
private readonly bool _joinOutputWritingThreadsOnDisposal;
// output pumping threads (stream output from stdout/stderr of the host process to the output/errorOutput writers)
private InteractiveHost _host; // nulled on dispose
private Thread _readOutputThread; // nulled on dispose
private Thread _readErrorOutputThread; // nulled on dispose
private InteractiveHost? _host; // nulled on dispose
private Thread? _readOutputThread; // nulled on dispose
private Thread? _readErrorOutputThread; // nulled on dispose
private volatile ProcessExitHandlerStatus _processExitHandlerStatus; // set to Handled on dispose
internal RemoteService(InteractiveHost host, Process process, int processId, Service service)
{
Debug.Assert(host != null);
Debug.Assert(process != null);
Debug.Assert(service != null);
Process = process;
Service = service;
......
......@@ -2,7 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
#nullable enable
using Microsoft.CodeAnalysis.Scripting.Hosting;
namespace Microsoft.CodeAnalysis.Interactive
......@@ -20,9 +21,6 @@ private sealed class ShadowCopyReference : PortableExecutableReference
public ShadowCopyReference(MetadataShadowCopyProvider provider, string originalPath, MetadataReferenceProperties properties)
: base(properties, originalPath)
{
Debug.Assert(originalPath != null);
Debug.Assert(provider != null);
_provider = provider;
}
......@@ -39,7 +37,7 @@ protected override Metadata GetMetadataImpl()
protected override PortableExecutableReference WithPropertiesImpl(MetadataReferenceProperties properties)
{
return new ShadowCopyReference(_provider, this.FilePath, properties);
return new ShadowCopyReference(_provider, FilePath!, properties);
}
}
}
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Diagnostics;
using System.Globalization;
......@@ -24,7 +26,7 @@ namespace Microsoft.CodeAnalysis.Interactive
/// <remarks>
/// Handles spawning of the host process and communication between the local callers and the remote session.
/// </remarks>
internal sealed partial class InteractiveHost : MarshalByRefObject
internal sealed partial class InteractiveHost
{
internal const bool DefaultIs64Bit = true;
......@@ -35,11 +37,11 @@ internal sealed partial class InteractiveHost : MarshalByRefObject
private readonly int _millisecondsTimeout;
private const int MaxAttemptsToCreateProcess = 2;
private LazyRemoteService _lazyRemoteService;
private LazyRemoteService? _lazyRemoteService;
private int _remoteServiceInstanceId;
// Remoting channel to communicate with the remote service.
private IpcServerChannel _serverChannel;
private IpcServerChannel? _serverChannel;
private TextWriter _output;
private TextWriter _errorOutput;
......@@ -55,7 +57,7 @@ internal sealed partial class InteractiveHost : MarshalByRefObject
/// </remarks>
private readonly bool _joinOutputWritingThreadsOnDisposal;
internal event Action<bool> ProcessStarting;
internal event Action<bool>? ProcessStarting;
public InteractiveHost(
Type replServiceProviderType,
......@@ -79,49 +81,39 @@ internal sealed partial class InteractiveHost : MarshalByRefObject
#region Test hooks
internal event Action<char[], int> OutputReceived;
internal event Action<char[], int> ErrorOutputReceived;
internal event Action<char[], int>? OutputReceived;
internal event Action<char[], int>? ErrorOutputReceived;
internal Process TryGetProcess()
internal Process? TryGetProcess()
{
InitializedRemoteService initializedService;
var lazyRemoteService = _lazyRemoteService;
return (lazyRemoteService?.InitializedService != null &&
lazyRemoteService.InitializedService.TryGetValue(out initializedService)) ? initializedService.ServiceOpt.Process : null;
lazyRemoteService.InitializedService.TryGetValue(out var initializedService)) ? initializedService.Service.Process : null;
}
internal Service TryGetService()
internal Service? TryGetService()
{
var initializedService = TryGetOrCreateRemoteServiceAsync().Result;
return initializedService.ServiceOpt?.Service;
return initializedService.Service?.Service;
}
// Triggered whenever we create a fresh process.
// The ProcessExited event is not hooked yet.
internal event Action<Process> InteractiveHostProcessCreated;
internal event Action<Process>? InteractiveHostProcessCreated;
internal IpcServerChannel _ServerChannel
{
get { return _serverChannel; }
}
internal IpcServerChannel? Test_ServerChannel
=> _serverChannel;
#endregion
private static string GenerateUniqueChannelLocalName()
{
return typeof(InteractiveHost).FullName + Guid.NewGuid();
}
=> typeof(InteractiveHost).FullName + Guid.NewGuid();
public override object InitializeLifetimeService()
private RemoteService? TryStartProcess(string hostPath, CultureInfo culture, CancellationToken cancellationToken)
{
return null;
}
private RemoteService TryStartProcess(string hostPath, CultureInfo culture, CancellationToken cancellationToken)
{
Process newProcess = null;
Process? newProcess = null;
int newProcessId = -1;
Semaphore semaphore = null;
Semaphore? semaphore = null;
try
{
int currentProcessId = Process.GetCurrentProcess().Id;
......@@ -309,7 +301,7 @@ internal void OnOutputReceived(bool error, char[] buffer, int count)
}
}
private void WriteOutputInBackground(bool isError, string firstLine, string secondLine = null)
private void WriteOutputInBackground(bool isError, string firstLine, string? secondLine = null)
{
var writer = isError ? _errorOutput : _output;
var guard = isError ? _errorOutputGuard : _outputGuard;
......@@ -364,7 +356,7 @@ private async Task<InitializedRemoteService> TryGetOrCreateRemoteServiceAsync()
{
try
{
LazyRemoteService currentRemoteService = _lazyRemoteService;
LazyRemoteService? currentRemoteService = _lazyRemoteService;
for (int attempt = 0; attempt < MaxAttemptsToCreateProcess; attempt++)
{
......@@ -375,7 +367,7 @@ private async Task<InitializedRemoteService> TryGetOrCreateRemoteServiceAsync()
}
var initializedService = await currentRemoteService.InitializedService.GetValueAsync(currentRemoteService.CancellationSource.Token).ConfigureAwait(false);
if (initializedService.ServiceOpt != null && initializedService.ServiceOpt.Process.IsAlive())
if (initializedService.Service != null && initializedService.Service.Process.IsAlive())
{
return initializedService;
}
......@@ -418,12 +410,12 @@ private async Task<TResult> Async<TResult>(Action<Service, RemoteAsyncOperation<
try
{
var initializedService = await TryGetOrCreateRemoteServiceAsync().ConfigureAwait(false);
if (initializedService.ServiceOpt == null)
if (initializedService.Service == null)
{
return default;
return default!;
}
return await new RemoteAsyncOperation<TResult>(initializedService.ServiceOpt).ExecuteAsync(action).ConfigureAwait(false);
return await new RemoteAsyncOperation<TResult>(initializedService.Service).ExecuteAsync(action).ConfigureAwait(false);
}
catch (Exception e) when (FatalError.Report(e))
{
......@@ -445,7 +437,7 @@ private static async Task<TResult> Async<TResult>(RemoteService remoteService, A
#region Operations
public InteractiveHostOptions OptionsOpt
public InteractiveHostOptions? OptionsOpt
=> _lazyRemoteService?.Options;
/// <summary>
......@@ -454,8 +446,6 @@ public InteractiveHostOptions OptionsOpt
/// <param name="options">The options to initialize the new process with.</param>
public async Task<RemoteExecutionResult> ResetAsync(InteractiveHostOptions options)
{
Debug.Assert(options != null);
try
{
// replace the existing service with a new one:
......@@ -468,7 +458,7 @@ public async Task<RemoteExecutionResult> ResetAsync(InteractiveHostOptions optio
}
var initializedService = await TryGetOrCreateRemoteServiceAsync().ConfigureAwait(false);
if (initializedService.ServiceOpt == null)
if (initializedService.Service == null)
{
return default;
}
......@@ -491,7 +481,7 @@ public async Task<RemoteExecutionResult> ResetAsync(InteractiveHostOptions optio
/// </remarks>
public Task<RemoteExecutionResult> ExecuteAsync(string code)
{
Debug.Assert(code != null);
Contract.ThrowIfNull(code);
return Async<RemoteExecutionResult>((service, operation) => service.Execute(operation, code));
}
......@@ -506,11 +496,7 @@ public Task<RemoteExecutionResult> ExecuteAsync(string code)
/// </remarks>
public Task<RemoteExecutionResult> ExecuteFileAsync(string path)
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
Contract.ThrowIfNull(path);
return Async<RemoteExecutionResult>((service, operation) => service.ExecuteFile(operation, path));
}
......@@ -524,7 +510,7 @@ public Task<RemoteExecutionResult> ExecuteFileAsync(string path)
/// </remarks>
public Task<bool> AddReferenceAsync(string reference)
{
Debug.Assert(reference != null);
Contract.ThrowIfNull(reference);
return Async<bool>((service, operation) => service.AddReference(operation, reference));
}
......@@ -533,9 +519,9 @@ public Task<bool> AddReferenceAsync(string reference)
/// </summary>
public Task<RemoteExecutionResult> SetPathsAsync(string[] referenceSearchPaths, string[] sourceSearchPaths, string baseDirectory)
{
Debug.Assert(referenceSearchPaths != null);
Debug.Assert(sourceSearchPaths != null);
Debug.Assert(baseDirectory != null);
Contract.ThrowIfNull(referenceSearchPaths);
Contract.ThrowIfNull(sourceSearchPaths);
Contract.ThrowIfNull(baseDirectory);
return Async<RemoteExecutionResult>((service, operation) => service.SetPaths(operation, referenceSearchPaths, sourceSearchPaths, baseDirectory));
}
......
......@@ -2,10 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Interactive
{
......@@ -17,7 +20,7 @@ internal sealed class InteractiveHostOptions
/// <summary>
/// Optional path to the .rsp file to process when initializing context of the process.
/// </summary>
public string InitializationFile { get; }
public string? InitializationFile { get; }
/// <summary>
/// Host culture used for localization of doc comments, errors.
......@@ -36,11 +39,11 @@ internal sealed class InteractiveHostOptions
public InteractiveHostOptions(
string hostDirectory,
string initializationFile = null,
CultureInfo culture = null,
string? initializationFile = null,
CultureInfo? culture = null,
bool is64Bit = false)
{
Debug.Assert(hostDirectory != null);
Contract.ThrowIfNull(hostDirectory);
HostDirectory = hostDirectory;
InitializationFile = initializationFile;
Culture = culture ?? CultureInfo.CurrentUICulture;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.Interactive
......
......@@ -2,40 +2,42 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
namespace Microsoft.CodeAnalysis.Interactive
{
[Serializable]
internal struct RemoteExecutionResult
internal readonly struct RemoteExecutionResult
{
public readonly bool Success;
/// <summary>
/// New value of source search paths after execution, or null if not changed since the last execution.
/// </summary>
public readonly string[] ChangedSourcePaths;
public readonly string[]? ChangedSourcePaths;
/// <summary>
/// New value of reference search paths after execution, or null if not changed since the last execution.
/// </summary>
public readonly string[] ChangedReferencePaths;
public readonly string[]? ChangedReferencePaths;
/// <summary>
/// New value of working directory in the remote process after execution, or null if not changed since the last execution.
/// </summary>
public readonly string ChangedWorkingDirectory;
public readonly string? ChangedWorkingDirectory;
public RemoteExecutionResult(
bool success,
string[] changedSourcePaths = null,
string[] changedReferencePaths = null,
string changedWorkingDirectory = null)
string[]? changedSourcePaths = null,
string[]? changedReferencePaths = null,
string? changedWorkingDirectory = null)
{
this.Success = success;
this.ChangedSourcePaths = changedSourcePaths;
this.ChangedReferencePaths = changedReferencePaths;
this.ChangedWorkingDirectory = changedWorkingDirectory;
Success = success;
ChangedSourcePaths = changedSourcePaths;
ChangedReferencePaths = changedReferencePaths;
ChangedWorkingDirectory = changedWorkingDirectory;
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
extern alias InteractiveHost;
using System;
......@@ -32,7 +35,7 @@ internal static string GetInteractiveHostDirectory()
internal static void DisposeInteractiveHostProcess(InteractiveHost host)
{
var serverChannel = host._ServerChannel;
var serverChannel = host.Test_ServerChannel;
host.Dispose();
var listenerThread = (Thread)s_ipcServerChannelListenerThread.GetValue(serverChannel);
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
extern alias InteractiveHost;
using System;
......@@ -34,8 +36,8 @@ public sealed class InteractiveHostTests : AbstractInteractiveHostTests
{
#region Utils
private SynchronizedStringWriter _synchronizedOutput;
private SynchronizedStringWriter _synchronizedErrorOutput;
private SynchronizedStringWriter _synchronizedOutput = null!;
private SynchronizedStringWriter _synchronizedErrorOutput = null!;
private int[] _outputReadPosition = new int[] { 0, 0 };
private readonly InteractiveHost _host;
......@@ -75,7 +77,7 @@ public override void Dispose()
{
try
{
Process process = _host.TryGetProcess();
var process = _host.TryGetProcess();
DisposeInteractiveHostProcess(_host);
......@@ -118,11 +120,6 @@ private bool Execute(string code)
return task.Result.Success;
}
private bool IsShadowCopy(string path)
{
return _host.TryGetService().IsShadowCopy(path);
}
public string ReadErrorOutputToEnd()
{
return ReadOutputToEnd(isError: true);
......@@ -135,7 +132,7 @@ private void ClearOutput()
_synchronizedErrorOutput.Clear();
}
private void RestartHost(string rspFile = null)
private void RestartHost(string? rspFile = null)
{
ClearOutput();
......@@ -150,7 +147,7 @@ public string ReadOutputToEnd(bool isError = false)
var mark = markPrefix + Guid.NewGuid().ToString();
// writes mark to the STDOUT/STDERR pipe in the remote process:
_host.TryGetService().RemoteConsoleWrite(Encoding.UTF8.GetBytes(mark), isError);
_host.TryGetService()!.RemoteConsoleWrite(Encoding.UTF8.GetBytes(mark), isError);
while (true)
{
......@@ -164,13 +161,8 @@ public string ReadOutputToEnd(bool isError = false)
}
}
private class CompiledFile
{
public string Path;
public ImmutableArray<byte> Image;
}
private static CompiledFile CompileLibrary(TempDirectory dir, string fileName, string assemblyName, string source, params MetadataReference[] references)
private static (string Path, ImmutableArray<byte> Image) CompileLibrary(
TempDirectory dir, string fileName, string assemblyName, string source, params MetadataReference[] references)
{
var file = dir.CreateFile(fileName);
var compilation = CreateEmptyCompilation(
......@@ -182,7 +174,7 @@ private static CompiledFile CompileLibrary(TempDirectory dir, string fileName, s
var image = compilation.EmitToArray();
file.WriteAllBytes(image);
return new CompiledFile { Path = file.Path, Image = image };
return (file.Path, image);
}
#endregion
......@@ -250,7 +242,7 @@ int goo(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8,
// Hosting process exited with exit code ###.
var errorOutput = ReadErrorOutputToEnd().Trim();
Assert.Equal("Process is terminated due to StackOverflowException.\n" + string.Format(InteractiveHostResources.Hosting_process_exited_with_exit_code_0, process.ExitCode), errorOutput);
Assert.Equal("Process is terminated due to StackOverflowException.\n" + string.Format(InteractiveHostResources.Hosting_process_exited_with_exit_code_0, process!.ExitCode), errorOutput);
Execute(@"1+1");
......@@ -337,10 +329,10 @@ public void AsyncExecute_HangingForegroundThreads()
var process = _host.TryGetProcess();
Assert.NotNull(process);
service.EmulateClientExit();
service!.EmulateClientExit();
// the process should terminate with exit code 0:
process.WaitForExit();
process!.WaitForExit();
Assert.Equal(0, process.ExitCode);
}
......@@ -454,7 +446,7 @@ public void UserDefinedAssemblyResolve_InfiniteLoop()
var mayTerminate = new ManualResetEvent(false);
_host.ErrorOutputReceived += (_, __) => mayTerminate.Set();
_host.TryGetService().HookMaliciousAssemblyResolve();
_host.TryGetService()!.HookMaliciousAssemblyResolve();
var executeTask = _host.AddReferenceAsync("nonexistingassembly" + Guid.NewGuid());
Assert.True(mayTerminate.WaitOne());
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
extern alias InteractiveHost;
using System;
......
......@@ -2,9 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Diagnostics;
using System.IO;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.UnitTests.Interactive
{
......@@ -44,7 +45,7 @@ public override string ToString()
}
}
public string Prefix(string mark, ref int start)
public string? Prefix(string mark, ref int start)
{
Debug.Assert(!string.IsNullOrEmpty(mark));
......
......@@ -223,8 +223,8 @@ public static IEnumerable<TSymbol> FindSimilarSymbols<TSymbol>(TSymbol symbol, C
}
/// <summary>
/// If <paramref name="symbol"/> is declared in a linked file, then this function returns all the other symbols
/// that are defined by the same symbol's syntax in the other projects that the linked file is referenced from.
/// If <paramref name="symbol"/> is declared in a linked file, then this function returns all the symbols that
/// are defined by the same symbol's syntax in the all projects that the linked file is referenced from.
/// <para/>
/// In order to be returned the other symbols must have the same <see cref="ISymbol.Name"/> and <see
/// cref="ISymbol.Kind"/> as <paramref name="symbol"/>. This matches general user intuition that these are all
......@@ -234,7 +234,8 @@ public static IEnumerable<TSymbol> FindSimilarSymbols<TSymbol>(TSymbol symbol, C
internal static async Task<ImmutableArray<ISymbol>> FindLinkedSymbolsAsync(
ISymbol symbol, Solution solution, CancellationToken cancellationToken)
{
var linkedSymbols = new HashSet<ISymbol>();
// Add the original symbol to the result set.
var linkedSymbols = new HashSet<ISymbol> { symbol };
foreach (var location in symbol.DeclaringSyntaxReferences)
{
......@@ -256,8 +257,9 @@ public static IEnumerable<TSymbol> FindSimilarSymbols<TSymbol>(TSymbol symbol, C
var semanticModel = await linkedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var linkedSymbol = semanticModel.GetDeclaredSymbol(linkedNode, cancellationToken);
if (linkedSymbol?.Kind == symbol.Kind &&
linkedSymbol?.Name == symbol.Name)
if (linkedSymbol != null &&
linkedSymbol.Kind == symbol.Kind &&
linkedSymbol.Name == symbol.Name)
{
linkedSymbols.Add(linkedSymbol);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册