未验证 提交 7377d737 编写于 作者: T Tomáš Matoušek 提交者: GitHub

Clean up project, document and solution infos (#41901)

* ProjectInfo argument validation

* Clean up usage of ToImmutableReadOnlyListOrEmpty

* Reorder With- methods

* Clean up DocumentInfo and SolutionInfo

* Renames

* Correct nullability

* Add more tests

* Fix generator NRE

* Rmeove unnecessary checks, dead code

* Add more list tests, share test helpers
上级 7950cc42
......@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
namespace Roslyn.Utilities
{
......@@ -13,6 +14,12 @@ internal partial class SpecializedCollections
{
private partial class Empty
{
internal static class BoxedImmutableArray<T>
{
// empty boxed immutable array
public static readonly IReadOnlyList<T> Instance = ImmutableArray<T>.Empty;
}
internal class List<T> : Collection<T>, IList<T>, IReadOnlyList<T>
{
public static readonly new List<T> Instance = new List<T>();
......
......@@ -30,6 +30,11 @@ public static IList<T> EmptyList<T>()
return Empty.List<T>.Instance;
}
public static IReadOnlyList<T> EmptyBoxedImmutableArray<T>()
{
return Empty.BoxedImmutableArray<T>.Instance;
}
public static IReadOnlyList<T> EmptyReadOnlyList<T>()
{
return Empty.List<T>.Instance;
......
......@@ -344,28 +344,24 @@ internal HostLanguageServices LanguageServiceProvider
public ProjectInfo ToProjectInfo()
{
return ProjectInfo.Create(
this.Id,
this.Version,
this.Name,
this.AssemblyName,
this.Language,
this.FilePath,
this.OutputFilePath,
outputRefFilePath: null,
defaultNamespace: null,
this.CompilationOptions,
this.ParseOptions,
this.Documents.Select(d => d.ToDocumentInfo()),
this.ProjectReferences,
this.MetadataReferences,
this.AnalyzerReferences,
this.AdditionalDocuments.Select(d => d.ToDocumentInfo()),
this.AnalyzerConfigDocuments.Select(d => d.ToDocumentInfo()),
this.IsSubmission,
this.HostObjectType,
hasAllInformation: true,
runAnalyzers: true)
.WithDefaultNamespace(this.DefaultNamespace);
Id,
Version,
Name,
AssemblyName,
Language,
FilePath,
OutputFilePath,
CompilationOptions,
ParseOptions,
Documents.Select(d => d.ToDocumentInfo()),
ProjectReferences,
MetadataReferences,
AnalyzerReferences,
AdditionalDocuments.Select(d => d.ToDocumentInfo()),
IsSubmission,
HostObjectType)
.WithAnalyzerConfigDocuments(AnalyzerConfigDocuments.Select(d => d.ToDocumentInfo()))
.WithDefaultNamespace(DefaultNamespace);
}
// It is identical with the internal extension method 'GetDefaultExtension' defined in OutputKind.cs.
......
// 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
using System;
using System.Collections.Immutable;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Roslyn.Test.Utilities
{
internal class TestAnalyzerReference : AnalyzerReference
{
public override string FullPath => throw new NotImplementedException();
public override object Id => throw new NotImplementedException();
public override ImmutableArray<DiagnosticAnalyzer> GetAnalyzers(string language) => throw new NotImplementedException();
public override ImmutableArray<DiagnosticAnalyzer> GetAnalyzersForAllLanguages() => throw new NotImplementedException();
}
}
......@@ -1201,7 +1201,7 @@ public DocumentId AddTextContainer(SourceTextContainer textContainer, string ful
var documentInfo = DocumentInfo.Create(
documentId,
FileNameUtilities.GetFileName(fullPath),
folders: folders.IsDefault ? null : (IEnumerable<string>)folders,
folders: folders.NullToEmpty(),
sourceCodeKind: sourceCodeKind,
loader: textLoader,
filePath: fullPath,
......@@ -1590,8 +1590,10 @@ public void ReorderFiles(ImmutableArray<string> filePaths)
}
}
private DocumentInfo CreateDocumentInfoFromFileInfo(DynamicFileInfo fileInfo, IEnumerable<string> folders)
private DocumentInfo CreateDocumentInfoFromFileInfo(DynamicFileInfo fileInfo, ImmutableArray<string> folders)
{
Contract.ThrowIfTrue(folders.IsDefault);
// we use this file path for editorconfig.
var filePath = fileInfo.FilePath;
......
......@@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
using Roslyn.Utilities;
......@@ -932,8 +933,8 @@ public override IReadOnlyList<SyntaxNode> GetAttributes(SyntaxNode declaration)
{
if (!s_declAttributes.TryGetValue(declaration, out var attrs))
{
var tmp = Flatten(declaration.GetAttributeLists().Where(al => !IsReturnAttribute(al)).ToImmutableReadOnlyListOrEmpty());
attrs = s_declAttributes.GetValue(declaration, _d => tmp);
attrs = s_declAttributes.GetValue(declaration, declaration =>
Flatten(declaration.GetAttributeLists().Where(al => !IsReturnAttribute(al))));
}
return attrs;
......@@ -946,8 +947,8 @@ public override IReadOnlyList<SyntaxNode> GetReturnAttributes(SyntaxNode declara
{
if (!s_declReturnAttributes.TryGetValue(declaration, out var attrs))
{
var tmp = Flatten(declaration.GetAttributeLists().Where(al => IsReturnAttribute(al)).ToImmutableReadOnlyListOrEmpty());
attrs = s_declReturnAttributes.GetValue(declaration, _d => tmp);
attrs = s_declReturnAttributes.GetValue(declaration, declaration =>
Flatten(declaration.GetAttributeLists().Where(al => IsReturnAttribute(al))));
}
return attrs;
......@@ -1176,11 +1177,7 @@ private SyntaxNode InsertNamespaceImportsInternal(SyntaxNode declaration, int in
public override IReadOnlyList<SyntaxNode> GetMembers(SyntaxNode declaration)
{
return Flatten(GetUnflattenedMembers(declaration));
}
private static IReadOnlyList<SyntaxNode> GetUnflattenedMembers(SyntaxNode declaration)
=> declaration.Kind() switch
return Flatten(declaration.Kind() switch
{
SyntaxKind.ClassDeclaration => ((ClassDeclarationSyntax)declaration).Members,
SyntaxKind.StructDeclaration => ((StructDeclarationSyntax)declaration).Members,
......@@ -1189,51 +1186,64 @@ private static IReadOnlyList<SyntaxNode> GetUnflattenedMembers(SyntaxNode declar
SyntaxKind.NamespaceDeclaration => ((NamespaceDeclarationSyntax)declaration).Members,
SyntaxKind.CompilationUnit => ((CompilationUnitSyntax)declaration).Members,
_ => SpecializedCollections.EmptyReadOnlyList<SyntaxNode>(),
};
});
}
private static IReadOnlyList<SyntaxNode> Flatten(IReadOnlyList<SyntaxNode> members)
private static ImmutableArray<SyntaxNode> Flatten(IEnumerable<SyntaxNode> declarations)
{
if (members.Count == 0 || !members.Any(m => GetDeclarationCount(m) > 1))
{
return members;
}
var list = new List<SyntaxNode>();
var builder = ArrayBuilder<SyntaxNode>.GetInstance();
foreach (var declaration in members)
foreach (var declaration in declarations)
{
switch (declaration.Kind())
{
case SyntaxKind.FieldDeclaration:
Flatten(declaration, ((FieldDeclarationSyntax)declaration).Declaration, list);
FlattenDeclaration(builder, declaration, ((FieldDeclarationSyntax)declaration).Declaration);
break;
case SyntaxKind.EventFieldDeclaration:
Flatten(declaration, ((EventFieldDeclarationSyntax)declaration).Declaration, list);
FlattenDeclaration(builder, declaration, ((EventFieldDeclarationSyntax)declaration).Declaration);
break;
case SyntaxKind.LocalDeclarationStatement:
Flatten(declaration, ((LocalDeclarationStatementSyntax)declaration).Declaration, list);
FlattenDeclaration(builder, declaration, ((LocalDeclarationStatementSyntax)declaration).Declaration);
break;
case SyntaxKind.VariableDeclaration:
Flatten(declaration, (VariableDeclarationSyntax)declaration, list);
FlattenDeclaration(builder, declaration, (VariableDeclarationSyntax)declaration);
break;
case SyntaxKind.AttributeList:
var attrList = (AttributeListSyntax)declaration;
if (attrList.Attributes.Count > 1)
{
list.AddRange(attrList.Attributes);
builder.AddRange(attrList.Attributes);
}
else
{
list.Add(attrList);
builder.Add(attrList);
}
break;
default:
list.Add(declaration);
builder.Add(declaration);
break;
}
}
return list.ToImmutableReadOnlyListOrEmpty();
return builder.ToImmutableAndFree();
static void FlattenDeclaration(ArrayBuilder<SyntaxNode> builder, SyntaxNode declaration, VariableDeclarationSyntax variableDeclaration)
{
if (variableDeclaration.Variables.Count > 1)
{
builder.AddRange(variableDeclaration.Variables);
}
else
{
builder.Add(declaration);
}
}
}
private static int GetDeclarationCount(SyntaxNode declaration)
......@@ -1247,18 +1257,6 @@ private static int GetDeclarationCount(SyntaxNode declaration)
_ => 1,
};
private static void Flatten(SyntaxNode declaration, VariableDeclarationSyntax vd, List<SyntaxNode> flat)
{
if (vd.Variables.Count > 1)
{
flat.AddRange(vd.Variables);
}
else
{
flat.Add(declaration);
}
}
public override SyntaxNode InsertMembers(SyntaxNode declaration, int index, IEnumerable<SyntaxNode> members)
{
var newMembers = this.AsMembersOf(declaration, members);
......@@ -2402,14 +2400,14 @@ private static SyntaxNode WithParameterList(SyntaxNode declaration, BaseParamete
return ((ParenthesizedLambdaExpressionSyntax)declaration).WithParameterList((ParameterListSyntax)list);
case SyntaxKind.SimpleLambdaExpression:
var lambda = (SimpleLambdaExpressionSyntax)declaration;
var roList = AsReadOnlyList(list.Parameters);
if (roList.Count == 1 && IsSimpleLambdaParameter(roList[0]))
var parameters = list.Parameters;
if (parameters.Count == 1 && IsSimpleLambdaParameter(parameters[0]))
{
return lambda.WithParameter(roList[0]);
return lambda.WithParameter(parameters[0]);
}
else
{
return SyntaxFactory.ParenthesizedLambdaExpression(AsParameterList(roList), lambda.Body)
return SyntaxFactory.ParenthesizedLambdaExpression(AsParameterList(parameters), lambda.Body)
.WithLeadingTrivia(lambda.GetLeadingTrivia())
.WithTrailingTrivia(lambda.GetTrailingTrivia());
}
......@@ -3255,7 +3253,7 @@ public override SyntaxNode IfStatement(SyntaxNode condition, IEnumerable<SyntaxN
}
else
{
var falseArray = AsReadOnlyList(falseStatements);
var falseArray = falseStatements.ToList();
// make else-if chain if false-statements contain only an if-statement
return SyntaxFactory.IfStatement(
......@@ -3844,15 +3842,15 @@ internal override SyntaxNode ScopeBlock(IEnumerable<SyntaxNode> statements)
public override SyntaxNode ValueReturningLambdaExpression(IEnumerable<SyntaxNode> parameterDeclarations, SyntaxNode expression)
{
var prms = AsReadOnlyList(parameterDeclarations?.Cast<ParameterSyntax>());
var parameters = parameterDeclarations?.Cast<ParameterSyntax>().ToList();
if (prms.Count == 1 && IsSimpleLambdaParameter(prms[0]))
if (parameters != null && parameters.Count == 1 && IsSimpleLambdaParameter(parameters[0]))
{
return SyntaxFactory.SimpleLambdaExpression(prms[0], (CSharpSyntaxNode)expression);
return SyntaxFactory.SimpleLambdaExpression(parameters[0], (CSharpSyntaxNode)expression);
}
else
{
return SyntaxFactory.ParenthesizedLambdaExpression(AsParameterList(prms), (CSharpSyntaxNode)expression);
return SyntaxFactory.ParenthesizedLambdaExpression(AsParameterList(parameters), (CSharpSyntaxNode)expression);
}
}
......@@ -3879,11 +3877,6 @@ public override SyntaxNode LambdaParameter(string identifier, SyntaxNode type =
return this.ParameterDeclaration(identifier, type, null, RefKind.None);
}
private static IReadOnlyList<T> AsReadOnlyList<T>(IEnumerable<T> sequence)
{
return sequence as IReadOnlyList<T> ?? sequence.ToImmutableReadOnlyListOrEmpty();
}
internal override SyntaxNode IdentifierName(SyntaxToken identifier)
=> SyntaxFactory.IdentifierName(identifier);
......
......@@ -21,21 +21,18 @@ public class SyntaxGeneratorTests
private readonly CSharpCompilation _emptyCompilation = CSharpCompilation.Create("empty",
references: new[] { TestReferences.NetFx.v4_0_30319.mscorlib, TestReferences.NetFx.v4_0_30319.System });
private readonly INamedTypeSymbol _ienumerableInt;
private Workspace _ws;
private SyntaxGenerator _g;
private Workspace _workspace;
private SyntaxGenerator _generator;
public SyntaxGeneratorTests()
{
_ienumerableInt = _emptyCompilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T).Construct(_emptyCompilation.GetSpecialType(SpecialType.System_Int32));
}
private Workspace Workspace
=> _ws ?? (_ws = new AdhocWorkspace());
=> _workspace ??= new AdhocWorkspace();
private SyntaxGenerator Generator
=> _g ?? (_g = SyntaxGenerator.GetGenerator(Workspace, LanguageNames.CSharp));
=> _generator ??= SyntaxGenerator.GetGenerator(Workspace, LanguageNames.CSharp);
public Compilation Compile(string code)
{
......@@ -3404,7 +3401,7 @@ public class C : IDisposable
var newDecl = Generator.AddInterfaceType(decl, Generator.IdentifierName("IDisposable"));
var newRoot = root.ReplaceNode(decl, newDecl);
var elasticOnlyFormatted = Formatter.Format(newRoot, SyntaxAnnotation.ElasticAnnotation, _ws).ToFullString();
var elasticOnlyFormatted = Formatter.Format(newRoot, SyntaxAnnotation.ElasticAnnotation, _workspace).ToFullString();
Assert.Equal(expected, elasticOnlyFormatted);
}
......
......@@ -182,7 +182,7 @@ private async Task<ISymbol> GetSymbolAsync(Solution solution, ProjectId projectI
public async Task<IReadOnlyList<SyntaxNode>> GetCurrentDeclarationsAsync(ISymbol symbol, CancellationToken cancellationToken = default)
{
var currentSymbol = await this.GetCurrentSymbolAsync(symbol, cancellationToken).ConfigureAwait(false);
return this.GetDeclarations(currentSymbol).ToImmutableReadOnlyListOrEmpty();
return this.GetDeclarations(currentSymbol).ToBoxedImmutableArray();
}
/// <summary>
......
......@@ -836,7 +836,7 @@ public SyntaxNode Attribute(AttributeData attribute)
{
var args = attribute.ConstructorArguments.Select(a => this.AttributeArgument(this.TypedConstantExpression(a)))
.Concat(attribute.NamedArguments.Select(n => this.AttributeArgument(n.Key, this.TypedConstantExpression(n.Value))))
.ToImmutableReadOnlyListOrEmpty();
.ToBoxedImmutableArray();
return Attribute(
name: this.TypeExpression(attribute.AttributeClass),
......
......@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Host;
......@@ -82,13 +83,21 @@ internal DocumentInfo(DocumentAttributes attributes, TextLoader? loader, IDocume
string? filePath = null,
bool isGenerated = false)
{
return Create(id, name, folders, sourceCodeKind, loader, filePath, isGenerated, documentServiceProvider: null);
return Create(
id ?? throw new ArgumentNullException(nameof(id)),
name ?? throw new ArgumentNullException(nameof(name)),
folders.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(folders)),
sourceCodeKind,
loader,
filePath,
isGenerated,
documentServiceProvider: null);
}
internal static DocumentInfo Create(
DocumentId id,
string name,
IEnumerable<string>? folders,
IReadOnlyList<string> folders,
SourceCodeKind sourceCodeKind,
TextLoader? loader,
string? filePath,
......@@ -118,46 +127,34 @@ internal DocumentInfo(DocumentAttributes attributes, TextLoader? loader, IDocume
}
public DocumentInfo WithId(DocumentId id)
{
return With(attributes: Attributes.With(id: id));
}
=> With(attributes: Attributes.With(id: id ?? throw new ArgumentNullException(nameof(id))));
public DocumentInfo WithName(string name)
{
return this.With(attributes: Attributes.With(name: name));
}
=> With(attributes: Attributes.With(name: name ?? throw new ArgumentNullException(nameof(name))));
public DocumentInfo WithFolders(IEnumerable<string>? folders)
{
return this.With(attributes: Attributes.With(folders: folders.ToImmutableReadOnlyListOrEmpty()));
}
=> With(attributes: Attributes.With(folders: folders.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(folders))));
public DocumentInfo WithSourceCodeKind(SourceCodeKind kind)
{
return this.With(attributes: Attributes.With(sourceCodeKind: kind));
}
public DocumentInfo WithTextLoader(TextLoader? loader)
{
return With(loader: loader);
}
=> With(attributes: Attributes.With(sourceCodeKind: kind));
public DocumentInfo WithFilePath(string? filePath)
{
return this.With(attributes: Attributes.With(filePath: filePath));
}
=> With(attributes: Attributes.With(filePath: filePath));
public DocumentInfo WithTextLoader(TextLoader? loader)
=> With(loader: loader);
private string GetDebuggerDisplay()
{
return (FilePath == null) ? (nameof(Name) + " = " + Name) : (nameof(FilePath) + " = " + FilePath);
}
=> (FilePath == null) ? (nameof(Name) + " = " + Name) : (nameof(FilePath) + " = " + FilePath);
/// <summary>
/// type that contains information regarding this document itself but
/// no tree information such as document info
/// </summary>
internal class DocumentAttributes : IChecksummedObject, IObjectWritable
internal sealed class DocumentAttributes : IChecksummedObject, IObjectWritable
{
private Checksum? _lazyChecksum;
/// <summary>
/// The Id of the document.
/// </summary>
......@@ -191,14 +188,14 @@ internal class DocumentAttributes : IChecksummedObject, IObjectWritable
public DocumentAttributes(
DocumentId id,
string name,
IEnumerable<string>? folders,
IReadOnlyList<string> folders,
SourceCodeKind sourceCodeKind,
string? filePath,
bool isGenerated)
{
Id = id ?? throw new ArgumentNullException(nameof(id));
Name = name ?? throw new ArgumentNullException(nameof(name));
Folders = folders.ToImmutableReadOnlyListOrEmpty();
Id = id;
Name = name;
Folders = folders;
SourceCodeKind = sourceCodeKind;
FilePath = filePath;
IsGenerated = isGenerated;
......@@ -207,14 +204,14 @@ internal class DocumentAttributes : IChecksummedObject, IObjectWritable
public DocumentAttributes With(
DocumentId? id = null,
string? name = null,
IEnumerable<string>? folders = null,
IReadOnlyList<string>? folders = null,
Optional<SourceCodeKind> sourceCodeKind = default,
Optional<string?> filePath = default,
Optional<bool> isGenerated = default)
{
var newId = id ?? Id;
var newName = name ?? Name;
var newFolders = folders?.ToImmutableReadOnlyListOrEmpty() ?? Folders;
var newFolders = folders ?? Folders;
var newSourceCodeKind = sourceCodeKind.HasValue ? sourceCodeKind.Value : SourceCodeKind;
var newFilePath = filePath.HasValue ? filePath.Value : FilePath;
var newIsGenerated = isGenerated.HasValue ? isGenerated.Value : IsGenerated;
......@@ -258,19 +255,8 @@ public static DocumentAttributes ReadFrom(ObjectReader reader)
return new DocumentAttributes(documentId, name, folders, (SourceCodeKind)sourceCodeKind, filePath, isGenerated);
}
private Checksum? _lazyChecksum;
Checksum IChecksummedObject.Checksum
{
get
{
if (_lazyChecksum == null)
{
_lazyChecksum = Checksum.Create(WellKnownSynchronizationKind.DocumentAttributes, this);
}
return _lazyChecksum;
}
}
=> _lazyChecksum ??= Checksum.Create(WellKnownSynchronizationKind.DocumentAttributes, this);
}
}
}
......@@ -391,7 +391,7 @@ public DocumentState UpdateName(string name)
_treeSource);
}
public DocumentState UpdateFolders(IList<string> folders)
public DocumentState UpdateFolders(ImmutableArray<string> folders)
{
return new DocumentState(
_languageServices,
......
......@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Serialization;
......@@ -141,80 +142,29 @@ public sealed class ProjectInfo
ProjectAttributes attributes,
CompilationOptions? compilationOptions,
ParseOptions? parseOptions,
IEnumerable<DocumentInfo>? documents,
IEnumerable<ProjectReference>? projectReferences,
IEnumerable<MetadataReference>? metadataReferences,
IEnumerable<AnalyzerReference>? analyzerReferences,
IEnumerable<DocumentInfo>? additionalDocuments,
IEnumerable<DocumentInfo>? analyzerConfigDocuments,
IReadOnlyList<DocumentInfo> documents,
IReadOnlyList<ProjectReference> projectReferences,
IReadOnlyList<MetadataReference> metadataReferences,
IReadOnlyList<AnalyzerReference> analyzerReferences,
IReadOnlyList<DocumentInfo> additionalDocuments,
IReadOnlyList<DocumentInfo> analyzerConfigDocuments,
Type? hostObjectType)
{
Attributes = attributes;
CompilationOptions = compilationOptions;
ParseOptions = parseOptions;
Documents = documents.ToImmutableReadOnlyListOrEmpty();
ProjectReferences = projectReferences.ToImmutableReadOnlyListOrEmpty();
MetadataReferences = metadataReferences.ToImmutableReadOnlyListOrEmpty();
AnalyzerReferences = analyzerReferences.ToImmutableReadOnlyListOrEmpty();
AdditionalDocuments = additionalDocuments.ToImmutableReadOnlyListOrEmpty();
AnalyzerConfigDocuments = analyzerConfigDocuments.ToImmutableReadOnlyListOrEmpty();
Documents = documents;
ProjectReferences = projectReferences;
MetadataReferences = metadataReferences;
AnalyzerReferences = analyzerReferences;
AdditionalDocuments = additionalDocuments;
AnalyzerConfigDocuments = analyzerConfigDocuments;
HostObjectType = hostObjectType;
}
/// <summary>
/// Create a new instance of a ProjectInfo.
/// </summary>
internal static ProjectInfo Create(
ProjectId id,
VersionStamp version,
string name,
string assemblyName,
string language,
string? filePath,
string? outputFilePath,
string? outputRefFilePath,
string? defaultNamespace,
CompilationOptions? compilationOptions,
ParseOptions? parseOptions,
IEnumerable<DocumentInfo>? documents,
IEnumerable<ProjectReference>? projectReferences,
IEnumerable<MetadataReference>? metadataReferences,
IEnumerable<AnalyzerReference>? analyzerReferences,
IEnumerable<DocumentInfo>? additionalDocuments,
IEnumerable<DocumentInfo>? analyzerConfigDocuments,
bool isSubmission,
Type? hostObjectType,
bool hasAllInformation,
bool runAnalyzers)
{
return new ProjectInfo(
new ProjectAttributes(
id,
version,
name,
assemblyName,
language,
filePath,
outputFilePath,
outputRefFilePath,
defaultNamespace,
isSubmission,
hasAllInformation,
runAnalyzers),
compilationOptions,
parseOptions,
documents,
projectReferences,
metadataReferences,
analyzerReferences,
additionalDocuments,
analyzerConfigDocuments,
hostObjectType);
}
// 2.7.0 BACKCOMPAT OVERLOAD -- DO NOT TOUCH
/// <summary>
/// Create a new instance of a ProjectInfo.
/// Create a new instance of a <see cref="ProjectInfo"/>.
/// </summary>
public static ProjectInfo Create(
ProjectId id,
......@@ -236,13 +186,13 @@ public sealed class ProjectInfo
{
return Create(
id, version, name, assemblyName, language,
filePath, outputFilePath, outputRefFilePath: null, defaultNamespace: null, compilationOptions, parseOptions,
documents, projectReferences, metadataReferences, analyzerReferences, additionalDocuments, analyzerConfigDocuments: null,
isSubmission, hostObjectType, hasAllInformation: true, runAnalyzers: true);
filePath, outputFilePath, compilationOptions, parseOptions,
documents, projectReferences, metadataReferences, analyzerReferences, additionalDocuments,
isSubmission, hostObjectType, outputRefFilePath: null);
}
/// <summary>
/// Create a new instance of a ProjectInfo.
/// Create a new instance of a <see cref="ProjectInfo"/>.
/// </summary>
public static ProjectInfo Create(
ProjectId id,
......@@ -263,28 +213,46 @@ public sealed class ProjectInfo
Type? hostObjectType = null,
string? outputRefFilePath = null)
{
return Create(
id, version, name, assemblyName, language,
filePath, outputFilePath, outputRefFilePath, defaultNamespace: null, compilationOptions, parseOptions,
documents, projectReferences, metadataReferences, analyzerReferences, additionalDocuments, analyzerConfigDocuments: null,
isSubmission, hostObjectType, hasAllInformation: true, runAnalyzers: true);
return new ProjectInfo(
new ProjectAttributes(
id ?? throw new ArgumentNullException(nameof(id)),
version,
name ?? throw new ArgumentNullException(nameof(name)),
assemblyName ?? throw new ArgumentNullException(nameof(assemblyName)),
language ?? throw new ArgumentNullException(nameof(language)),
filePath,
outputFilePath,
outputRefFilePath,
defaultNamespace: null,
isSubmission,
hasAllInformation: true,
runAnalyzers: true),
compilationOptions,
parseOptions,
documents.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(documents)),
projectReferences.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(projectReferences)),
metadataReferences.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(metadataReferences)),
analyzerReferences.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(analyzerReferences)),
additionalDocuments.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(additionalDocuments)),
analyzerConfigDocuments: SpecializedCollections.EmptyBoxedImmutableArray<DocumentInfo>(),
hostObjectType);
}
private ProjectInfo With(
ProjectAttributes? attributes = null,
CompilationOptions? compilationOptions = null,
ParseOptions? parseOptions = null,
IEnumerable<DocumentInfo>? documents = null,
IEnumerable<ProjectReference>? projectReferences = null,
IEnumerable<MetadataReference>? metadataReferences = null,
IEnumerable<AnalyzerReference>? analyzerReferences = null,
IEnumerable<DocumentInfo>? additionalDocuments = null,
IEnumerable<DocumentInfo>? analyzerConfigDocuments = null,
Optional<CompilationOptions?> compilationOptions = default,
Optional<ParseOptions?> parseOptions = default,
IReadOnlyList<DocumentInfo>? documents = null,
IReadOnlyList<ProjectReference>? projectReferences = null,
IReadOnlyList<MetadataReference>? metadataReferences = null,
IReadOnlyList<AnalyzerReference>? analyzerReferences = null,
IReadOnlyList<DocumentInfo>? additionalDocuments = null,
IReadOnlyList<DocumentInfo>? analyzerConfigDocuments = null,
Optional<Type?> hostObjectType = default)
{
var newAttributes = attributes ?? Attributes;
var newCompilationOptions = compilationOptions ?? CompilationOptions;
var newParseOptions = parseOptions ?? ParseOptions;
var newCompilationOptions = compilationOptions.HasValue ? compilationOptions.Value : CompilationOptions;
var newParseOptions = parseOptions.HasValue ? parseOptions.Value : ParseOptions;
var newDocuments = documents ?? Documents;
var newProjectReferences = projectReferences ?? ProjectReferences;
var newMetadataReferences = metadataReferences ?? MetadataReferences;
......@@ -320,104 +288,68 @@ public sealed class ProjectInfo
newHostObjectType);
}
public ProjectInfo WithDocuments(IEnumerable<DocumentInfo>? documents)
{
return With(documents: documents.ToImmutableReadOnlyListOrEmpty());
}
public ProjectInfo WithAdditionalDocuments(IEnumerable<DocumentInfo>? additionalDocuments)
{
return With(additionalDocuments: additionalDocuments.ToImmutableReadOnlyListOrEmpty());
}
public ProjectInfo WithAnalyzerConfigDocuments(IEnumerable<DocumentInfo>? analyzerConfigDocuments)
{
return With(analyzerConfigDocuments: analyzerConfigDocuments.ToImmutableReadOnlyListOrEmpty());
}
public ProjectInfo WithVersion(VersionStamp version)
{
return With(attributes: Attributes.With(version: version));
}
=> With(attributes: Attributes.With(version: version));
public ProjectInfo WithName(string name)
{
return With(attributes: Attributes.With(name: name));
}
public ProjectInfo WithFilePath(string? filePath)
{
return With(attributes: Attributes.With(filePath: filePath));
}
=> With(attributes: Attributes.With(name: name ?? throw new ArgumentNullException(nameof(name))));
public ProjectInfo WithAssemblyName(string assemblyName)
{
return With(attributes: Attributes.With(assemblyName: assemblyName));
}
=> With(attributes: Attributes.With(assemblyName: assemblyName ?? throw new ArgumentNullException(nameof(assemblyName))));
public ProjectInfo WithFilePath(string? filePath)
=> With(attributes: Attributes.With(filePath: filePath));
public ProjectInfo WithOutputFilePath(string? outputFilePath)
{
return With(attributes: Attributes.With(outputPath: outputFilePath));
}
=> With(attributes: Attributes.With(outputPath: outputFilePath));
public ProjectInfo WithOutputRefFilePath(string? outputRefFilePath)
{
return With(attributes: Attributes.With(outputRefPath: outputRefFilePath));
}
=> With(attributes: Attributes.With(outputRefPath: outputRefFilePath));
public ProjectInfo WithDefaultNamespace(string? defaultNamespace)
{
return With(attributes: Attributes.With(defaultNamespace: defaultNamespace));
}
=> With(attributes: Attributes.With(defaultNamespace: defaultNamespace));
internal ProjectInfo WithHasAllInformation(bool hasAllInformation)
=> With(attributes: Attributes.With(hasAllInformation: hasAllInformation));
internal ProjectInfo WithRunAnalyzers(bool runAnalyzers)
=> With(attributes: Attributes.With(runAnalyzers: runAnalyzers));
public ProjectInfo WithCompilationOptions(CompilationOptions? compilationOptions)
{
// The With method here doesn't correctly handle the null value, tracked by https://github.com/dotnet/roslyn/issues/37880
return With(compilationOptions: compilationOptions);
}
=> With(compilationOptions: compilationOptions);
public ProjectInfo WithParseOptions(ParseOptions? parseOptions)
{
// The With method here doesn't correctly handle the null value, tracked by https://github.com/dotnet/roslyn/issues/37880
return With(parseOptions: parseOptions);
}
=> With(parseOptions: parseOptions);
public ProjectInfo WithDocuments(IEnumerable<DocumentInfo>? documents)
=> With(documents: documents.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(documents)));
public ProjectInfo WithAdditionalDocuments(IEnumerable<DocumentInfo>? additionalDocuments)
=> With(additionalDocuments: additionalDocuments.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(additionalDocuments)));
public ProjectInfo WithAnalyzerConfigDocuments(IEnumerable<DocumentInfo>? analyzerConfigDocuments)
=> With(analyzerConfigDocuments: analyzerConfigDocuments.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(analyzerConfigDocuments)));
public ProjectInfo WithProjectReferences(IEnumerable<ProjectReference>? projectReferences)
{
return With(projectReferences: projectReferences.ToImmutableReadOnlyListOrEmpty());
}
=> With(projectReferences: projectReferences.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(projectReferences)));
public ProjectInfo WithMetadataReferences(IEnumerable<MetadataReference>? metadataReferences)
{
return With(metadataReferences: metadataReferences.ToImmutableReadOnlyListOrEmpty());
}
=> With(metadataReferences: metadataReferences.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(metadataReferences)));
public ProjectInfo WithAnalyzerReferences(IEnumerable<AnalyzerReference>? analyzerReferences)
{
return With(analyzerReferences: analyzerReferences.ToImmutableReadOnlyListOrEmpty());
}
internal ProjectInfo WithHasAllInformation(bool hasAllInformation)
{
return With(attributes: Attributes.With(hasAllInformation: hasAllInformation));
}
internal ProjectInfo WithRunAnalyzers(bool runAnalyzers)
{
return With(attributes: Attributes.With(runAnalyzers: runAnalyzers));
}
=> With(analyzerReferences: analyzerReferences.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(analyzerReferences)));
internal string GetDebuggerDisplay()
{
return nameof(ProjectInfo) + " " + Name + (!string.IsNullOrWhiteSpace(FilePath) ? " " + FilePath : "");
}
=> nameof(ProjectInfo) + " " + Name + (!string.IsNullOrWhiteSpace(FilePath) ? " " + FilePath : "");
/// <summary>
/// type that contains information regarding this project itself but
/// no tree information such as document info
/// </summary>
internal class ProjectAttributes : IChecksummedObject, IObjectWritable
internal sealed class ProjectAttributes : IChecksummedObject, IObjectWritable
{
private Checksum? _lazyChecksum;
/// <summary>
/// The unique Id of the project.
/// </summary>
......@@ -494,10 +426,10 @@ internal class ProjectAttributes : IChecksummedObject, IObjectWritable
bool hasAllInformation,
bool runAnalyzers)
{
Id = id ?? throw new ArgumentNullException(nameof(id));
Name = name ?? throw new ArgumentNullException(nameof(name));
Language = language ?? throw new ArgumentNullException(nameof(language));
AssemblyName = assemblyName ?? throw new ArgumentNullException(nameof(assemblyName));
Id = id;
Name = name;
Language = language;
AssemblyName = assemblyName;
Version = version;
FilePath = filePath;
......@@ -522,7 +454,7 @@ internal class ProjectAttributes : IChecksummedObject, IObjectWritable
Optional<bool> hasAllInformation = default,
Optional<bool> runAnalyzers = default)
{
var newVersion = version.HasValue ? version.Value : Version;
var newVersion = version ?? Version;
var newName = name ?? Name;
var newAssemblyName = assemblyName ?? AssemblyName;
var newLanguage = language ?? Language;
......@@ -607,19 +539,8 @@ public static ProjectAttributes ReadFrom(ObjectReader reader)
return new ProjectAttributes(projectId, VersionStamp.Create(), name, assemblyName, language, filePath, outputFilePath, outputRefFilePath, defaultNamespace, isSubmission, hasAllInformation, runAnalyzers);
}
private Checksum? _lazyChecksum;
Checksum IChecksummedObject.Checksum
{
get
{
if (_lazyChecksum == null)
{
_lazyChecksum = Checksum.Create(WellKnownSynchronizationKind.ProjectAttributes, this);
}
return _lazyChecksum;
}
}
=> _lazyChecksum ??= Checksum.Create(WellKnownSynchronizationKind.ProjectAttributes, this);
}
}
}
......@@ -985,7 +985,9 @@ public Solution WithDocumentName(DocumentId documentId, string name)
/// Creates a new solution instance with the document specified updated to be contained in
/// the sequence of logical folders.
/// </summary>
public Solution WithDocumentFolders(DocumentId documentId, IEnumerable<string> folders)
/// <param name="documentId">Document id.</param>
/// <param name="folders">Sequence of folders. <see langword="null"/> values are ignored.</param>
public Solution WithDocumentFolders(DocumentId documentId, IEnumerable<string?> folders)
{
var newState = _state.WithDocumentFolders(documentId, folders);
if (newState == _state)
......
......@@ -42,10 +42,10 @@ public sealed class SolutionInfo
/// </summary>
public IReadOnlyList<ProjectInfo> Projects { get; }
private SolutionInfo(SolutionAttributes attributes, IEnumerable<ProjectInfo>? projects)
private SolutionInfo(SolutionAttributes attributes, IReadOnlyList<ProjectInfo> projects)
{
Attributes = attributes;
Projects = projects.ToImmutableReadOnlyListOrEmpty();
Projects = projects;
}
/// <summary>
......@@ -57,38 +57,12 @@ private SolutionInfo(SolutionAttributes attributes, IEnumerable<ProjectInfo>? pr
string? filePath = null,
IEnumerable<ProjectInfo>? projects = null)
{
return new SolutionInfo(new SolutionAttributes(id, version, filePath), projects);
}
private SolutionInfo With(
SolutionAttributes? attributes = null,
IEnumerable<ProjectInfo>? projects = null)
{
var newAttributes = attributes ?? Attributes;
var newProjects = projects ?? Projects;
if (newAttributes == Attributes &&
newProjects == Projects)
{
return this;
}
return new SolutionInfo(newAttributes, newProjects);
}
internal SolutionInfo WithVersion(VersionStamp version)
{
return With(attributes: new SolutionAttributes(Attributes.Id, version, Attributes.FilePath));
}
internal SolutionInfo WithFilePath(string? filePath)
{
return With(attributes: new SolutionAttributes(Attributes.Id, Attributes.Version, filePath));
}
internal SolutionInfo WithProjects(IEnumerable<ProjectInfo> projects)
{
return With(projects: projects);
return new SolutionInfo(
new SolutionAttributes(
id ?? throw new ArgumentNullException(nameof(id)),
version,
filePath),
projects.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(projects)));
}
internal ImmutableHashSet<string> GetProjectLanguages()
......@@ -98,8 +72,10 @@ internal ImmutableHashSet<string> GetProjectLanguages()
/// type that contains information regarding this solution itself but
/// no tree information such as project info
/// </summary>
internal class SolutionAttributes : IChecksummedObject, IObjectWritable
internal sealed class SolutionAttributes : IChecksummedObject, IObjectWritable
{
private Checksum? _lazyChecksum;
/// <summary>
/// The unique Id of the solution.
/// </summary>
......@@ -117,7 +93,7 @@ internal class SolutionAttributes : IChecksummedObject, IObjectWritable
public SolutionAttributes(SolutionId id, VersionStamp version, string? filePath)
{
Id = id ?? throw new ArgumentNullException(nameof(id));
Id = id;
Version = version;
FilePath = filePath;
}
......@@ -149,19 +125,8 @@ public static SolutionAttributes ReadFrom(ObjectReader reader)
return new SolutionAttributes(solutionId, VersionStamp.Create(), filePath);
}
private Checksum? _lazyChecksum;
Checksum IChecksummedObject.Checksum
{
get
{
if (_lazyChecksum == null)
{
_lazyChecksum = Checksum.Create(WellKnownSynchronizationKind.SolutionAttributes, this);
}
return _lazyChecksum;
}
}
=> _lazyChecksum ??= Checksum.Create(WellKnownSynchronizationKind.SolutionAttributes, this);
}
}
}
......@@ -41,7 +41,6 @@ internal partial class SolutionState
private readonly SolutionInfo.SolutionAttributes _solutionAttributes;
private readonly SolutionServices _solutionServices;
private readonly IReadOnlyList<ProjectId> _projectIds;
private readonly ImmutableDictionary<ProjectId, ProjectState> _projectIdToProjectStateMap;
private readonly ImmutableDictionary<string, ImmutableArray<DocumentId>> _filePathToDocumentIdsMap;
private readonly ProjectDependencyGraph _dependencyGraph;
......@@ -57,7 +56,7 @@ internal partial class SolutionState
int workspaceVersion,
SolutionServices solutionServices,
SolutionInfo.SolutionAttributes solutionAttributes,
IEnumerable<ProjectId> projectIds,
IReadOnlyList<ProjectId> projectIds,
SerializableOptionSet options,
ImmutableDictionary<ProjectId, ProjectState> idToProjectStateMap,
ImmutableDictionary<ProjectId, CompilationTracker> projectIdToTrackerMap,
......@@ -68,8 +67,8 @@ internal partial class SolutionState
_workspaceVersion = workspaceVersion;
_solutionAttributes = solutionAttributes;
_solutionServices = solutionServices;
_projectIds = projectIds.ToImmutableReadOnlyListOrEmpty();
Options = options ?? throw new ArgumentNullException(nameof(options));
ProjectIds = projectIds;
Options = options;
_projectIdToProjectStateMap = idToProjectStateMap;
_projectIdToTrackerMap = projectIdToTrackerMap;
_filePathToDocumentIdsMap = filePathToDocumentIdsMap;
......@@ -91,7 +90,7 @@ internal partial class SolutionState
workspaceVersion: 0,
solutionServices,
solutionAttributes,
projectIds: ImmutableArray<ProjectId>.Empty,
projectIds: SpecializedCollections.EmptyBoxedImmutableArray<ProjectId>(),
options,
idToProjectStateMap: ImmutableDictionary<ProjectId, ProjectState>.Empty,
projectIdToTrackerMap: ImmutableDictionary<ProjectId, CompilationTracker>.Empty,
......@@ -157,12 +156,12 @@ public SolutionState WithNewWorkspace(Workspace workspace, int workspaceVersion)
/// <summary>
/// A list of all the ids for all the projects contained by the solution.
/// </summary>
public IReadOnlyList<ProjectId> ProjectIds => _projectIds;
public IReadOnlyList<ProjectId> ProjectIds { get; }
// [Conditional("DEBUG")]
private void CheckInvariants()
{
Contract.ThrowIfTrue(_projectIds.Count != _projectIdToProjectStateMap.Count);
Contract.ThrowIfTrue(ProjectIds.Count != _projectIdToProjectStateMap.Count);
// An id shouldn't point at a tracker for a different project.
Contract.ThrowIfTrue(_projectIdToTrackerMap.Any(kvp => kvp.Key != kvp.Value.ProjectState.Id));
......@@ -170,7 +169,7 @@ private void CheckInvariants()
private SolutionState Branch(
SolutionInfo.SolutionAttributes? solutionAttributes = null,
IEnumerable<ProjectId>? projectIds = null,
IReadOnlyList<ProjectId>? projectIds = null,
SerializableOptionSet? options = null,
ImmutableDictionary<ProjectId, ProjectState>? idToProjectStateMap = null,
ImmutableDictionary<ProjectId, CompilationTracker>? projectIdToTrackerMap = null,
......@@ -180,7 +179,7 @@ private void CheckInvariants()
var branchId = GetBranchId();
solutionAttributes ??= _solutionAttributes;
projectIds ??= _projectIds;
projectIds ??= ProjectIds;
idToProjectStateMap ??= _projectIdToProjectStateMap;
options ??= Options.WithLanguages(GetProjectLanguages(idToProjectStateMap));
projectIdToTrackerMap ??= _projectIdToTrackerMap;
......@@ -189,7 +188,7 @@ private void CheckInvariants()
if (branchId == _branchId &&
solutionAttributes == _solutionAttributes &&
projectIds == _projectIds &&
projectIds == ProjectIds &&
options == Options &&
idToProjectStateMap == _projectIdToProjectStateMap &&
projectIdToTrackerMap == _projectIdToTrackerMap &&
......@@ -230,7 +229,7 @@ private void CheckInvariants()
workspaceVersion,
services,
_solutionAttributes,
_projectIds,
ProjectIds,
Options,
_projectIdToProjectStateMap,
_projectIdToTrackerMap,
......@@ -441,7 +440,7 @@ private SolutionState AddProject(ProjectId projectId, ProjectState projectState)
// changed project list so, increment version.
var newSolutionAttributes = _solutionAttributes.WithVersion(this.Version.GetNewerVersion());
var newProjectIds = _projectIds.ToImmutableArray().Add(projectId);
var newProjectIds = ProjectIds.ToImmutableArray().Add(projectId);
var newStateMap = _projectIdToProjectStateMap.Add(projectId, projectState);
var newDependencyGraph = _dependencyGraph
.WithAdditionalProjects(SpecializedCollections.SingletonEnumerable(projectId))
......@@ -555,7 +554,7 @@ public SolutionState RemoveProject(ProjectId projectId)
// changed project list so, increment version.
var newSolutionAttributes = _solutionAttributes.WithVersion(this.Version.GetNewerVersion());
var newProjectIds = _projectIds.ToImmutableArray().Remove(projectId);
var newProjectIds = ProjectIds.ToImmutableArray().Remove(projectId);
var newStateMap = _projectIdToProjectStateMap.Remove(projectId);
var newDependencyGraph = _dependencyGraph.WithProjectRemoved(projectId);
var newTrackerMap = CreateCompilationTrackerMap(projectId, newDependencyGraph);
......@@ -1364,7 +1363,7 @@ public SolutionState WithDocumentName(DocumentId documentId, string name)
/// Creates a new solution instance with the document specified updated to be contained in
/// the sequence of logical folders.
/// </summary>
public SolutionState WithDocumentFolders(DocumentId documentId, IEnumerable<string> folders)
public SolutionState WithDocumentFolders(DocumentId documentId, IEnumerable<string?> folders)
{
if (documentId == null)
{
......@@ -1376,12 +1375,10 @@ public SolutionState WithDocumentFolders(DocumentId documentId, IEnumerable<stri
throw new ArgumentNullException(nameof(folders));
}
var folderCollection = folders.WhereNotNull().ToReadOnlyCollection();
var oldDocument = this.GetDocumentState(documentId)!;
var newDocument = oldDocument.UpdateFolders(folderCollection);
var oldDocument = GetDocumentState(documentId)!;
var newDocument = oldDocument.UpdateFolders(folders.WhereNotNull().ToImmutableArray());
return this.WithDocumentState(newDocument);
return WithDocumentState(newDocument);
}
/// <summary>
......@@ -1663,11 +1660,6 @@ public SolutionState WithAnalyzerConfigDocumentTextLoader(DocumentId documentId,
private SolutionState WithDocumentState(DocumentState newDocument, bool textChanged = false, bool recalculateDependentVersions = false)
{
if (newDocument == null)
{
throw new ArgumentNullException(nameof(newDocument));
}
CheckContainsDocument(newDocument.Id);
if (newDocument == this.GetDocumentState(newDocument.Id))
......@@ -1700,11 +1692,6 @@ private SolutionState TouchDocument(DocumentId documentId, Func<ProjectState, Pr
private SolutionState WithAdditionalDocumentState(TextDocumentState newDocument, bool textChanged = false, bool recalculateDependentVersions = false)
{
if (newDocument == null)
{
throw new ArgumentNullException(nameof(newDocument));
}
CheckContainsAdditionalDocument(newDocument.Id);
if (newDocument == this.GetAdditionalDocumentState(newDocument.Id))
......@@ -1727,11 +1714,6 @@ private SolutionState WithAdditionalDocumentState(TextDocumentState newDocument,
private SolutionState WithAnalyzerConfigDocumentState(AnalyzerConfigDocumentState newDocument, bool textChanged = false, bool recalculateDependentVersions = false)
{
if (newDocument == null)
{
throw new ArgumentNullException(nameof(newDocument));
}
CheckContainsAnalyzerConfigDocument(newDocument.Id);
if (newDocument == this.GetAnalyzerConfigDocumentState(newDocument.Id))
......@@ -1940,7 +1922,7 @@ public SolutionState WithFrozenPartialCompilationIncludingSpecificDocument(Docum
currentPartialSolution = this.Branch(
idToProjectStateMap: newIdToProjectStateMap,
projectIdToTrackerMap: newIdToTrackerMap,
dependencyGraph: CreateDependencyGraph(_projectIds, newIdToProjectStateMap));
dependencyGraph: CreateDependencyGraph(ProjectIds, newIdToProjectStateMap));
_latestSolutionWithPartialCompilation = new WeakReference<SolutionState>(currentPartialSolution);
_timeOfLatestSolutionWithPartialCompilation = DateTime.UtcNow;
......@@ -1959,7 +1941,7 @@ public SolutionState WithFrozenPartialCompilationIncludingSpecificDocument(Docum
/// <summary>
/// Creates a new solution instance with all the documents specified updated to have the same specified text.
/// </summary>
public SolutionState WithDocumentText(IEnumerable<DocumentId> documentIds, SourceText text, PreservationMode mode = PreservationMode.PreserveValue)
public SolutionState WithDocumentText(IEnumerable<DocumentId> documentIds, SourceText text, PreservationMode mode)
{
if (documentIds == null)
{
......@@ -2234,26 +2216,6 @@ private void CheckNotSecondSubmissionReference(ProjectId projectId, ProjectId to
}
}
private void CheckNotContainsDocument(DocumentId documentId)
{
Debug.Assert(!this.ContainsDocument(documentId));
if (this.ContainsDocument(documentId))
{
throw new InvalidOperationException(WorkspacesResources.The_solution_already_contains_the_specified_document);
}
}
private void CheckNotContainsAdditionalDocument(DocumentId documentId)
{
Debug.Assert(!this.ContainsAdditionalDocument(documentId));
if (this.ContainsAdditionalDocument(documentId))
{
throw new InvalidOperationException(WorkspacesResources.The_solution_already_contains_the_specified_document);
}
}
private void CheckContainsDocument(DocumentId documentId)
{
Debug.Assert(this.ContainsDocument(documentId));
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests
{
public class DocumentInfoTests
{
[Fact]
public void Create_Errors()
{
var documentId = DocumentId.CreateNewId(ProjectId.CreateNewId());
Assert.Throws<ArgumentNullException>(() => DocumentInfo.Create(id: null, "doc"));
Assert.Throws<ArgumentNullException>(() => DocumentInfo.Create(documentId, name: null));
Assert.Throws<ArgumentNullException>(() => DocumentInfo.Create(documentId, "doc", folders: new[] { "folder", null }));
}
[Fact]
public void Create()
{
var loader = new FileTextLoader(Path.GetTempPath(), defaultEncoding: null);
var id = DocumentId.CreateNewId(ProjectId.CreateNewId());
var info = DocumentInfo.Create(
id,
name: "doc",
sourceCodeKind: SourceCodeKind.Script,
loader: loader,
isGenerated: true);
Assert.Equal(id, info.Id);
Assert.Equal("doc", info.Name);
Assert.Equal(SourceCodeKind.Script, info.SourceCodeKind);
Assert.Same(loader, info.TextLoader);
Assert.True(info.IsGenerated);
}
[Fact]
public void Create_Folders()
{
var documentId = DocumentId.CreateNewId(ProjectId.CreateNewId());
var info1 = DocumentInfo.Create(documentId, "doc", folders: new[] { "folder" });
Assert.Equal("folder", ((ImmutableArray<string>)info1.Folders).Single());
var info2 = DocumentInfo.Create(documentId, "doc");
Assert.True(((ImmutableArray<string>)info2.Folders).IsEmpty);
var info3 = DocumentInfo.Create(documentId, "doc", folders: new string[0]);
Assert.True(((ImmutableArray<string>)info3.Folders).IsEmpty);
var info4 = DocumentInfo.Create(documentId, "doc", folders: ImmutableArray<string>.Empty);
Assert.True(((ImmutableArray<string>)info4.Folders).IsEmpty);
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData("path")]
public void Create_FilePath(string path)
{
var info = DocumentInfo.Create(DocumentId.CreateNewId(ProjectId.CreateNewId()), "doc", filePath: path);
Assert.Equal(path, info.FilePath);
}
[Fact]
public void TestProperties()
{
var projectId = ProjectId.CreateNewId();
var documentId = DocumentId.CreateNewId(projectId);
var instance = DocumentInfo.Create(DocumentId.CreateNewId(ProjectId.CreateNewId()), "doc");
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithId(value), opt => opt.Id, documentId, defaultThrows: true);
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithName(value), opt => opt.Name, "New", defaultThrows: true);
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithSourceCodeKind(value), opt => opt.SourceCodeKind, SourceCodeKind.Script);
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithTextLoader(value), opt => opt.TextLoader, (TextLoader)new FileTextLoader(Path.GetTempPath(), defaultEncoding: null));
SolutionTestHelpers.TestListProperty(instance, (old, value) => old.WithFolders(value), opt => opt.Folders, "folder");
}
}
}
......@@ -3,6 +3,11 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.Diagnostics;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests
......@@ -10,13 +15,123 @@ namespace Microsoft.CodeAnalysis.UnitTests
public class ProjectInfoTests
{
[Fact]
public void Create()
public void Create_Errors()
{
var pid = ProjectId.CreateNewId();
Assert.Throws<ArgumentNullException>(() => ProjectInfo.Create(id: null, version: VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#"));
Assert.Throws<ArgumentNullException>(() => ProjectInfo.Create(pid, VersionStamp.Default, name: null, assemblyName: "Bar", language: "C#"));
Assert.Throws<ArgumentNullException>(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: null, language: "C#"));
Assert.Throws<ArgumentNullException>(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: null));
Assert.Throws<ArgumentNullException>(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#",
documents: new DocumentInfo[] { null }));
Assert.Throws<ArgumentNullException>(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#",
additionalDocuments: new DocumentInfo[] { null }));
Assert.Throws<ArgumentNullException>(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#",
projectReferences: new ProjectReference[] { null }));
Assert.Throws<ArgumentNullException>(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#",
analyzerReferences: new AnalyzerReference[] { null }));
Assert.Throws<ArgumentNullException>(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#",
metadataReferences: new MetadataReference[] { null }));
}
[Fact]
public void Create_Documents()
{
var version = VersionStamp.Default;
var documentInfo = DocumentInfo.Create(DocumentId.CreateNewId(ProjectId.CreateNewId()), "doc");
var info1 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", documents: new[] { documentInfo });
Assert.Same(documentInfo, ((ImmutableArray<DocumentInfo>)info1.Documents).Single());
var info2 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#");
Assert.True(((ImmutableArray<DocumentInfo>)info2.Documents).IsEmpty);
var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", documents: new DocumentInfo[0]);
Assert.True(((ImmutableArray<DocumentInfo>)info3.Documents).IsEmpty);
var info4 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", documents: ImmutableArray<DocumentInfo>.Empty);
Assert.True(((ImmutableArray<DocumentInfo>)info4.Documents).IsEmpty);
}
[Fact]
public void Create_AdditionalDocuments()
{
var version = VersionStamp.Default;
var documentInfo = DocumentInfo.Create(DocumentId.CreateNewId(ProjectId.CreateNewId()), "doc");
var info1 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", additionalDocuments: new[] { documentInfo });
Assert.Same(documentInfo, ((ImmutableArray<DocumentInfo>)info1.AdditionalDocuments).Single());
var info2 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#");
Assert.True(((ImmutableArray<DocumentInfo>)info2.AdditionalDocuments).IsEmpty);
var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", additionalDocuments: new DocumentInfo[0]);
Assert.True(((ImmutableArray<DocumentInfo>)info3.AdditionalDocuments).IsEmpty);
var info4 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", additionalDocuments: ImmutableArray<DocumentInfo>.Empty);
Assert.True(((ImmutableArray<DocumentInfo>)info4.AdditionalDocuments).IsEmpty);
}
[Fact]
public void Create_ProjectReferences()
{
var version = VersionStamp.Default;
var projectReference = new ProjectReference(ProjectId.CreateNewId());
var info1 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", projectReferences: new[] { projectReference });
Assert.Same(projectReference, ((ImmutableArray<ProjectReference>)info1.ProjectReferences).Single());
var info2 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#");
Assert.True(((ImmutableArray<ProjectReference>)info2.ProjectReferences).IsEmpty);
var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", projectReferences: new ProjectReference[0]);
Assert.True(((ImmutableArray<ProjectReference>)info3.ProjectReferences).IsEmpty);
var info4 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", projectReferences: ImmutableArray<ProjectReference>.Empty);
Assert.True(((ImmutableArray<ProjectReference>)info4.ProjectReferences).IsEmpty);
}
[Fact]
public void Create_MetadataReferences()
{
var version = VersionStamp.Default;
var metadataReference = new TestMetadataReference();
var info1 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", metadataReferences: new[] { metadataReference });
Assert.Same(metadataReference, ((ImmutableArray<MetadataReference>)info1.MetadataReferences).Single());
var info2 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#");
Assert.True(((ImmutableArray<MetadataReference>)info2.MetadataReferences).IsEmpty);
var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", metadataReferences: new MetadataReference[0]);
Assert.True(((ImmutableArray<MetadataReference>)info3.MetadataReferences).IsEmpty);
var info4 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", metadataReferences: ImmutableArray<MetadataReference>.Empty);
Assert.True(((ImmutableArray<MetadataReference>)info4.MetadataReferences).IsEmpty);
}
[Fact]
public void Create_AnalyzerReferences()
{
var version = VersionStamp.Default;
var analyzerReference = new TestAnalyzerReference();
var info1 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", analyzerReferences: new[] { analyzerReference });
Assert.Same(analyzerReference, ((ImmutableArray<AnalyzerReference>)info1.AnalyzerReferences).Single());
var info2 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#");
Assert.True(((ImmutableArray<AnalyzerReference>)info2.AnalyzerReferences).IsEmpty);
var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", analyzerReferences: new AnalyzerReference[0]);
Assert.True(((ImmutableArray<AnalyzerReference>)info3.AnalyzerReferences).IsEmpty);
var info4 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", analyzerReferences: ImmutableArray<AnalyzerReference>.Empty);
Assert.True(((ImmutableArray<AnalyzerReference>)info4.AnalyzerReferences).IsEmpty);
}
[Fact]
......@@ -32,5 +147,30 @@ public void DebuggerDisplayHasOnlyProjectNameWhenFilePathNotSpecified()
var projectInfo = ProjectInfo.Create(name: "Goo", id: ProjectId.CreateNewId(), version: VersionStamp.Default, assemblyName: "Bar", language: "C#");
Assert.Equal(@"ProjectInfo Goo", projectInfo.GetDebuggerDisplay());
}
[Fact]
public void TestProperties()
{
var projectId = ProjectId.CreateNewId();
var documentInfo = DocumentInfo.Create(DocumentId.CreateNewId(projectId), "doc");
var instance = ProjectInfo.Create(name: "Name", id: ProjectId.CreateNewId(), version: VersionStamp.Default, assemblyName: "AssemblyName", language: "C#");
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithVersion(value), opt => opt.Version, VersionStamp.Create());
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithName(value), opt => opt.Name, "New", defaultThrows: true);
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithAssemblyName(value), opt => opt.AssemblyName, "New", defaultThrows: true);
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithFilePath(value), opt => opt.FilePath, "New");
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithOutputFilePath(value), opt => opt.OutputFilePath, "New");
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithOutputRefFilePath(value), opt => opt.OutputRefFilePath, "New");
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithDefaultNamespace(value), opt => opt.DefaultNamespace, "New");
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithHasAllInformation(value), opt => opt.HasAllInformation, true);
SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithRunAnalyzers(value), opt => opt.RunAnalyzers, true);
SolutionTestHelpers.TestListProperty(instance, (old, value) => old.WithDocuments(value), opt => opt.Documents, documentInfo);
SolutionTestHelpers.TestListProperty(instance, (old, value) => old.WithAdditionalDocuments(value), opt => opt.AdditionalDocuments, documentInfo);
SolutionTestHelpers.TestListProperty(instance, (old, value) => old.WithAnalyzerConfigDocuments(value), opt => opt.AnalyzerConfigDocuments, documentInfo);
SolutionTestHelpers.TestListProperty(instance, (old, value) => old.WithAnalyzerReferences(value), opt => opt.AnalyzerReferences, (AnalyzerReference)new TestAnalyzerReference());
SolutionTestHelpers.TestListProperty(instance, (old, value) => old.WithMetadataReferences(value), opt => opt.MetadataReferences, (MetadataReference)new TestMetadataReference());
SolutionTestHelpers.TestListProperty(instance, (old, value) => old.WithProjectReferences(value), opt => opt.ProjectReferences, new ProjectReference(projectId));
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Immutable;
using System.Linq;
using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests
{
public class SolutionInfoTests
{
[Fact]
public void Create_Errors()
{
var solutionId = SolutionId.CreateNewId();
var version = VersionStamp.Default;
var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#");
Assert.Throws<ArgumentNullException>(() => SolutionInfo.Create(null, version));
Assert.Throws<ArgumentNullException>(() => SolutionInfo.Create(solutionId, version, projects: new[] { projectInfo, null }));
}
[Fact]
public void Create_Projects()
{
var solutionId = SolutionId.CreateNewId();
var version = VersionStamp.Default;
var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#");
var info1 = SolutionInfo.Create(solutionId, version, projects: new[] { projectInfo });
Assert.Same(projectInfo, ((ImmutableArray<ProjectInfo>)info1.Projects).Single());
var info2 = SolutionInfo.Create(solutionId, version);
Assert.True(((ImmutableArray<ProjectInfo>)info2.Projects).IsEmpty);
var info3 = SolutionInfo.Create(solutionId, version, projects: new ProjectInfo[0]);
Assert.True(((ImmutableArray<ProjectInfo>)info3.Projects).IsEmpty);
var info4 = SolutionInfo.Create(solutionId, version, projects: ImmutableArray<ProjectInfo>.Empty);
Assert.True(((ImmutableArray<ProjectInfo>)info4.Projects).IsEmpty);
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData("path")]
public void Create_FilePath(string path)
{
var info = SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Default, filePath: path);
Assert.Equal(path, info.FilePath);
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.Diagnostics;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests
{
internal static class SolutionTestHelpers
{
public static void TestProperty<T, TValue>(T instance, Func<T, TValue, T> factory, Func<T, TValue> getter, TValue validNonDefaultValue, bool defaultThrows = false)
where T : class
{
Assert.NotEqual<TValue>(default, validNonDefaultValue);
var instanceWithValue = factory(instance, validNonDefaultValue);
Assert.Equal(validNonDefaultValue, getter(instanceWithValue));
var instanceWithValue2 = factory(instanceWithValue, validNonDefaultValue);
Assert.Same(instanceWithValue2, instanceWithValue);
if (defaultThrows)
{
Assert.Throws<ArgumentNullException>(() => factory(instance, default));
}
else
{
Assert.NotNull(factory(instance, default));
}
}
public static void TestListProperty<T, TValue>(T instance, Func<T, IEnumerable<TValue>, T> factory, Func<T, IEnumerable<TValue>> getter, TValue item)
where T : class
{
var boxedItems = (IEnumerable<TValue>)ImmutableArray.Create(item);
TestProperty(instance, factory, getter, boxedItems, defaultThrows: false);
var instanceWithNoItem = factory(instance, default);
Assert.Empty(getter(instanceWithNoItem));
var instanceWithItem = factory(instanceWithNoItem, boxedItems);
// the factory preserves the identity of a boxed immutable array:
Assert.Same(boxedItems, getter(instanceWithItem));
Assert.Same(instanceWithNoItem, factory(instanceWithNoItem, default));
Assert.Same(instanceWithNoItem, factory(instanceWithNoItem, Array.Empty<TValue>()));
Assert.Same(instanceWithNoItem, factory(instanceWithNoItem, ImmutableArray<TValue>.Empty));
// the factory makes an immutable copy if given a mutable list:
var mutableItems = new[] { item };
var instanceWithMutableItems = factory(instanceWithNoItem, mutableItems);
var items = getter(instanceWithMutableItems);
Assert.NotSame(mutableItems, items);
Assert.Throws<ArgumentNullException>(() => factory(instanceWithNoItem, new TValue[] { item, default }));
}
}
}
......@@ -41,19 +41,47 @@ internal static ImmutableArray<T> ToImmutableArrayOrEmpty<T>(this IEnumerable<T>
return ImmutableArray.CreateRange<T>(items);
}
internal static ImmutableArray<T> ToImmutableArrayOrEmpty<T>(this ImmutableArray<T> items)
=> items.IsDefault ? ImmutableArray<T>.Empty : items;
internal static IReadOnlyList<T> ToImmutableReadOnlyListOrEmpty<T>(this IEnumerable<T>? items)
internal static IReadOnlyList<T> ToBoxedImmutableArray<T>(this IEnumerable<T>? items)
{
if (items is ImmutableArray<T> array && !array.IsDefault)
if (items is null)
{
return SpecializedCollections.EmptyBoxedImmutableArray<T>();
}
if (items is ImmutableArray<T> array)
{
return array.IsDefaultOrEmpty ? SpecializedCollections.EmptyBoxedImmutableArray<T>() : (IReadOnlyList<T>)items;
}
if (items is ICollection<T> collection && collection.Count == 0)
{
return (IReadOnlyList<T>)items;
return SpecializedCollections.EmptyBoxedImmutableArray<T>();
}
else
return ImmutableArray.CreateRange(items);
}
/// <summary>
/// Use to validate public API input for properties that are exposed as <see cref="IReadOnlyList{T}"/>.
///
/// Pattern:
/// <code>
/// argument.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(argument)),
/// </code>
/// </summary>
internal static IReadOnlyList<T>? AsBoxedImmutableArrayWithNonNullItems<T>(this IEnumerable<T>? sequence) where T : class
{
var list = sequence.ToBoxedImmutableArray();
foreach (var item in list)
{
return items.ToImmutableArrayOrEmpty();
if (item is null)
{
return null;
}
}
return list;
}
internal static ConcatImmutableArray<T> ConcatFast<T>(this ImmutableArray<T> first, ImmutableArray<T> second)
......
......@@ -703,15 +703,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
#End Region
#Region "Declarations"
Private Function AsReadOnlyList(Of T)(sequence As IEnumerable(Of T)) As IReadOnlyList(Of T)
Dim list = TryCast(sequence, IReadOnlyList(Of T))
If list Is Nothing Then
list = sequence.ToImmutableReadOnlyListOrEmpty()
End If
Return list
End Function
Private Shared s_fieldModifiers As DeclarationModifiers = DeclarationModifiers.Const Or DeclarationModifiers.[New] Or DeclarationModifiers.ReadOnly Or DeclarationModifiers.Static Or DeclarationModifiers.WithEvents
Private Shared s_methodModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.Async Or DeclarationModifiers.[New] Or DeclarationModifiers.Override Or DeclarationModifiers.Partial Or DeclarationModifiers.Sealed Or DeclarationModifiers.Static Or DeclarationModifiers.Virtual
......@@ -3682,7 +3673,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
End Function
Public Overrides Function GetBaseAndInterfaceTypes(declaration As SyntaxNode) As IReadOnlyList(Of SyntaxNode)
Return Me.GetInherits(declaration).SelectMany(Function(ih) ih.Types).Concat(Me.GetImplements(declaration).SelectMany(Function(imp) imp.Types)).ToImmutableReadOnlyListOrEmpty()
Return Me.GetInherits(declaration).SelectMany(Function(ih) ih.Types).Concat(Me.GetImplements(declaration).SelectMany(Function(imp) imp.Types)).ToBoxedImmutableArray()
End Function
Public Overrides Function AddBaseType(declaration As SyntaxNode, baseType As SyntaxNode) As SyntaxNode
......@@ -3947,9 +3938,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Private Function GetSubDeclarations(declaration As SyntaxNode) As IReadOnlyList(Of SyntaxNode)
Select Case declaration.Kind
Case SyntaxKind.FieldDeclaration
Return DirectCast(declaration, FieldDeclarationSyntax).Declarators.SelectMany(Function(d) d.Names).ToImmutableReadOnlyListOrEmpty()
Return DirectCast(declaration, FieldDeclarationSyntax).Declarators.SelectMany(Function(d) d.Names).ToBoxedImmutableArray()
Case SyntaxKind.LocalDeclarationStatement
Return DirectCast(declaration, LocalDeclarationStatementSyntax).Declarators.SelectMany(Function(d) d.Names).ToImmutableReadOnlyListOrEmpty()
Return DirectCast(declaration, LocalDeclarationStatementSyntax).Declarators.SelectMany(Function(d) d.Names).ToBoxedImmutableArray()
Case SyntaxKind.AttributeList
Return DirectCast(declaration, AttributeListSyntax).Attributes
Case SyntaxKind.ImportsStatement
......@@ -3960,36 +3951,32 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
End Function
Private Function Flatten(members As IReadOnlyList(Of SyntaxNode)) As IReadOnlyList(Of SyntaxNode)
If members.Count = 0 OrElse Not members.Any(Function(m) GetDeclarationCount(m) > 1) Then
Return members
End If
Dim list = New List(Of SyntaxNode)
Flatten(members, list)
Return list.ToImmutableReadOnlyListOrEmpty()
Dim builder = ArrayBuilder(Of SyntaxNode).GetInstance()
Flatten(builder, members)
Return builder.ToImmutableAndFree()
End Function
Private Sub Flatten(members As IReadOnlyList(Of SyntaxNode), list As List(Of SyntaxNode))
For Each m In members
If GetDeclarationCount(m) > 1 Then
Select Case m.Kind
Private Sub Flatten(builder As ArrayBuilder(Of SyntaxNode), members As IReadOnlyList(Of SyntaxNode))
For Each member In members
If GetDeclarationCount(member) > 1 Then
Select Case member.Kind
Case SyntaxKind.FieldDeclaration
Flatten(DirectCast(m, FieldDeclarationSyntax).Declarators, list)
Flatten(builder, DirectCast(member, FieldDeclarationSyntax).Declarators)
Case SyntaxKind.LocalDeclarationStatement
Flatten(DirectCast(m, LocalDeclarationStatementSyntax).Declarators, list)
Flatten(builder, DirectCast(member, LocalDeclarationStatementSyntax).Declarators)
Case SyntaxKind.VariableDeclarator
Flatten(DirectCast(m, VariableDeclaratorSyntax).Names, list)
Flatten(builder, DirectCast(member, VariableDeclaratorSyntax).Names)
Case SyntaxKind.AttributesStatement
Flatten(DirectCast(m, AttributesStatementSyntax).AttributeLists, list)
Flatten(builder, DirectCast(member, AttributesStatementSyntax).AttributeLists)
Case SyntaxKind.AttributeList
Flatten(DirectCast(m, AttributeListSyntax).Attributes, list)
Flatten(builder, DirectCast(member, AttributeListSyntax).Attributes)
Case SyntaxKind.ImportsStatement
Flatten(DirectCast(m, ImportsStatementSyntax).ImportsClauses, list)
Flatten(builder, DirectCast(member, ImportsStatementSyntax).ImportsClauses)
Case Else
list.Add(m)
builder.Add(member)
End Select
Else
list.Add(m)
builder.Add(member)
End If
Next
End Sub
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册