// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { /// /// A class that represents all the arguments necessary to create a new project instance. /// [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] public sealed class ProjectInfo { internal ProjectAttributes Attributes { get; } /// /// The unique Id of the project. /// public ProjectId Id => Attributes.Id; /// /// The version of the project. /// public VersionStamp Version => Attributes.Version; /// /// The name of the project. This may differ from the project's filename. /// public string Name => Attributes.Name; /// /// The name of the assembly that this project will create, without file extension. /// , public string AssemblyName => Attributes.AssemblyName; /// /// The language of the project. /// public string Language => Attributes.Language; /// /// The path to the project file or null if there is no project file. /// public string FilePath => Attributes.FilePath; /// /// The path to the output file (module or assembly). /// public string OutputFilePath => Attributes.OutputFilePath; /// /// True if this is a submission project for interactive sessions. /// public bool IsSubmission => Attributes.IsSubmission; /// /// True if project information is complete. In some workspace hosts, it is possible /// a project only has partial information. In such cases, a project might not have all /// information on its files or references. /// internal bool HasAllInformation => Attributes.HasAllInformation; /// /// The initial compilation options for the project, or null if the default options should be used. /// public CompilationOptions CompilationOptions { get; } /// /// The initial parse options for the source code documents in this project, or null if the default options should be used. /// public ParseOptions ParseOptions { get; } /// /// The list of source documents initially associated with the project. /// public IReadOnlyList Documents { get; } /// /// The project references initially defined for the project. /// public IReadOnlyList ProjectReferences { get; } /// /// The metadata references initially defined for the project. /// public IReadOnlyList MetadataReferences { get; } /// /// The analyzers initially associated with this project. /// public IReadOnlyList AnalyzerReferences { get; } /// /// The list of non-source documents associated with this project. /// public IReadOnlyList AdditionalDocuments { get; } /// /// Type of the host object. /// public Type HostObjectType { get; } private ProjectInfo( ProjectAttributes attributes, CompilationOptions compilationOptions, ParseOptions parseOptions, IEnumerable documents, IEnumerable projectReferences, IEnumerable metadataReferences, IEnumerable analyzerReferences, IEnumerable additionalDocuments, Type hostObjectType) { Attributes = attributes; CompilationOptions = compilationOptions; ParseOptions = parseOptions; Documents = documents.ToImmutableReadOnlyListOrEmpty(); ProjectReferences = projectReferences.ToImmutableReadOnlyListOrEmpty(); MetadataReferences = metadataReferences.ToImmutableReadOnlyListOrEmpty(); AnalyzerReferences = analyzerReferences.ToImmutableReadOnlyListOrEmpty(); AdditionalDocuments = additionalDocuments.ToImmutableReadOnlyListOrEmpty(); HostObjectType = hostObjectType; } /// /// Create a new instance of a ProjectInfo. /// internal static ProjectInfo Create( ProjectId id, VersionStamp version, string name, string assemblyName, string language, string filePath, string outputFilePath, CompilationOptions compilationOptions, ParseOptions parseOptions, IEnumerable documents, IEnumerable projectReferences, IEnumerable metadataReferences, IEnumerable analyzerReferences, IEnumerable additionalDocuments, bool isSubmission, Type hostObjectType, bool hasAllInformation) { return new ProjectInfo( new ProjectAttributes( id, version, name, assemblyName, language, filePath, outputFilePath, isSubmission, hasAllInformation), compilationOptions, parseOptions, documents, projectReferences, metadataReferences, analyzerReferences, additionalDocuments, hostObjectType); } /// /// Create a new instance of a ProjectInfo. /// public static ProjectInfo Create( ProjectId id, VersionStamp version, string name, string assemblyName, string language, string filePath = null, string outputFilePath = null, CompilationOptions compilationOptions = null, ParseOptions parseOptions = null, IEnumerable documents = null, IEnumerable projectReferences = null, IEnumerable metadataReferences = null, IEnumerable analyzerReferences = null, IEnumerable additionalDocuments = null, bool isSubmission = false, Type hostObjectType = null) { return Create( id, version, name, assemblyName, language, filePath, outputFilePath, compilationOptions, parseOptions, documents, projectReferences, metadataReferences, analyzerReferences, additionalDocuments, isSubmission, hostObjectType, hasAllInformation: true); } private ProjectInfo With( ProjectAttributes attributes = null, CompilationOptions compilationOptions = null, ParseOptions parseOptions = null, IEnumerable documents = null, IEnumerable projectReferences = null, IEnumerable metadataReferences = null, IEnumerable analyzerReferences = null, IEnumerable additionalDocuments = null, Optional hostObjectType = default(Optional)) { var newAttributes = attributes ?? Attributes; var newCompilationOptions = compilationOptions ?? CompilationOptions; var newParseOptions = parseOptions ?? ParseOptions; var newDocuments = documents ?? Documents; var newProjectReferences = projectReferences ?? ProjectReferences; var newMetadataReferences = metadataReferences ?? MetadataReferences; var newAnalyzerReferences = analyzerReferences ?? AnalyzerReferences; var newAdditionalDocuments = additionalDocuments ?? AdditionalDocuments; var newHostObjectType = hostObjectType.HasValue ? hostObjectType.Value : HostObjectType; if (newAttributes == Attributes && newCompilationOptions == CompilationOptions && newParseOptions == ParseOptions && newDocuments == Documents && newProjectReferences == ProjectReferences && newMetadataReferences == MetadataReferences && newAnalyzerReferences == AnalyzerReferences && newAdditionalDocuments == AdditionalDocuments && newHostObjectType == HostObjectType) { return this; } return new ProjectInfo( newAttributes, newCompilationOptions, newParseOptions, newDocuments, newProjectReferences, newMetadataReferences, newAnalyzerReferences, newAdditionalDocuments, newHostObjectType); } public ProjectInfo WithDocuments(IEnumerable documents) { return With(documents: documents.ToImmutableReadOnlyListOrEmpty()); } public ProjectInfo WithAdditionalDocuments(IEnumerable additionalDocuments) { return With(additionalDocuments: additionalDocuments.ToImmutableReadOnlyListOrEmpty()); } public ProjectInfo WithVersion(VersionStamp version) { return 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)); } public ProjectInfo WithAssemblyName(string assemblyName) { return With(attributes: Attributes.With(assemblyName: assemblyName)); } public ProjectInfo WithOutputFilePath(string outputFilePath) { return With(attributes: Attributes.With(outputPath: outputFilePath)); } public ProjectInfo WithCompilationOptions(CompilationOptions compilationOptions) { return With(compilationOptions: compilationOptions); } public ProjectInfo WithParseOptions(ParseOptions parseOptions) { return With(parseOptions: parseOptions); } public ProjectInfo WithProjectReferences(IEnumerable projectReferences) { return With(projectReferences: projectReferences.ToImmutableReadOnlyListOrEmpty()); } public ProjectInfo WithMetadataReferences(IEnumerable metadataReferences) { return With(metadataReferences: metadataReferences.ToImmutableReadOnlyListOrEmpty()); } public ProjectInfo WithAnalyzerReferences(IEnumerable analyzerReferences) { return With(analyzerReferences: analyzerReferences.ToImmutableReadOnlyListOrEmpty()); } internal ProjectInfo WithHasAllInformation(bool hasAllInformation) { return With(attributes: Attributes.With(hasAllInformation: hasAllInformation)); } internal string GetDebuggerDisplay() { return nameof(ProjectInfo) + " " + Name + (!string.IsNullOrWhiteSpace(FilePath) ? " " + FilePath : ""); } /// /// type that contains information regarding this project itself but /// no tree information such as document info /// internal class ProjectAttributes : IChecksummedObject, IObjectWritable { /// /// The unique Id of the project. /// public ProjectId Id { get; } /// /// The version of the project. /// public VersionStamp Version { get; } /// /// The name of the project. This may differ from the project's filename. /// public string Name { get; } /// /// The name of the assembly that this project will create, without file extension. /// , public string AssemblyName { get; } /// /// The language of the project. /// public string Language { get; } /// /// The path to the project file or null if there is no project file. /// public string FilePath { get; } /// /// The path to the output file (module or assembly). /// public string OutputFilePath { get; } /// /// True if this is a submission project for interactive sessions. /// public bool IsSubmission { get; } /// /// True if project information is complete. In some workspace hosts, it is possible /// a project only has partial information. In such cases, a project might not have all /// information on its files or references. /// public bool HasAllInformation { get; } public ProjectAttributes( ProjectId id, VersionStamp version, string name, string assemblyName, string language, string filePath, string outputFilePath, bool isSubmission, bool hasAllInformation) { if (id == null) { throw new ArgumentNullException(nameof(id)); } if (name == null) { throw new ArgumentNullException(nameof(name)); } if (language == null) { throw new ArgumentNullException(nameof(language)); } if (assemblyName == null) { throw new ArgumentNullException(nameof(assemblyName)); } Id = id; Name = name; Language = language; AssemblyName = assemblyName; Version = version; FilePath = filePath; OutputFilePath = outputFilePath; IsSubmission = isSubmission; HasAllInformation = hasAllInformation; } public ProjectAttributes With( VersionStamp? version = default(VersionStamp?), string name = null, string assemblyName = null, string language = null, Optional filePath = default(Optional), Optional outputPath = default(Optional), Optional isSubmission = default(Optional), Optional hasAllInformation = default(Optional)) { var newVersion = version.HasValue ? version.Value : Version; var newName = name ?? Name; var newAssemblyName = assemblyName ?? AssemblyName; var newLanguage = language ?? Language; var newFilepath = filePath.HasValue ? filePath.Value : FilePath; var newOutputPath = outputPath.HasValue ? outputPath.Value : OutputFilePath; var newIsSubmission = isSubmission.HasValue ? isSubmission.Value : IsSubmission; var newHasAllInformation = hasAllInformation.HasValue ? hasAllInformation.Value : HasAllInformation; if (newVersion == Version && newName == Name && newAssemblyName == AssemblyName && newLanguage == Language && newFilepath == FilePath && newOutputPath == OutputFilePath && newIsSubmission == IsSubmission && newHasAllInformation == HasAllInformation) { return this; } return new ProjectAttributes( Id, newVersion, newName, newAssemblyName, newLanguage, newFilepath, newOutputPath, newIsSubmission, newHasAllInformation); } public void WriteTo(ObjectWriter writer) { Id.WriteTo(writer); // TODO: figure out a way to send version info over as well // info.Version.WriteTo(writer); writer.WriteString(Name); writer.WriteString(AssemblyName); writer.WriteString(Language); writer.WriteString(FilePath); writer.WriteString(OutputFilePath); writer.WriteBoolean(IsSubmission); writer.WriteBoolean(HasAllInformation); // TODO: once CompilationOptions, ParseOptions, ProjectReference, MetadataReference, AnalyzerReference supports // serialization, we should include those here as well. } public static ProjectAttributes ReadFrom(ObjectReader reader) { var projectId = ProjectId.ReadFrom(reader); // var version = VersionStamp.ReadFrom(reader); var name = reader.ReadString(); var assemblyName = reader.ReadString(); var language = reader.ReadString(); var filePath = reader.ReadString(); var outputFilePath = reader.ReadString(); var isSubmission = reader.ReadBoolean(); var hasAllInformation = reader.ReadBoolean(); return new ProjectAttributes(projectId, VersionStamp.Create(), name, assemblyName, language, filePath, outputFilePath, isSubmission, hasAllInformation); } private Checksum _lazyChecksum; Checksum IChecksummedObject.Checksum { get { if (_lazyChecksum == null) { _lazyChecksum = Checksum.Create(this, nameof(ProjectAttributes)); } return _lazyChecksum; } } } } }