diff --git a/src/Uno.SourceGeneration.Engine.Shared/Workspace/CSharpCommandLineArgumentReader.cs b/src/Uno.SourceGeneration.Engine.Shared/Workspace/CSharpCommandLineArgumentReader.cs index 1ec96ee..7445b97 100644 --- a/src/Uno.SourceGeneration.Engine.Shared/Workspace/CSharpCommandLineArgumentReader.cs +++ b/src/Uno.SourceGeneration.Engine.Shared/Workspace/CSharpCommandLineArgumentReader.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// https://github.com/dotnet/roslyn/blob/3e39dd3535962bf9e30bd650e4ff34b610b8349a/src/Workspaces/Core/MSBuild/MSBuild/CSharp/CSharpCommandLineArgumentReader.cs + using System.Collections.Immutable; using Uno.SourceGeneration.Engine.Workspace.Constants; using MSB = Microsoft.Build; @@ -31,7 +33,6 @@ namespace Uno.SourceGeneration.Engine.Workspace ReadPlatform(); ReadReferences(); ReadSigning(); - ReadAnalyzerConfig(); AddIfNotNullOrWhiteSpace("appconfig", Project.ReadPropertyString(PropertyNames.AppConfigForCompiler)); AddIfNotNullOrWhiteSpace("baseaddress", Project.ReadPropertyString(PropertyNames.BaseAddress)); diff --git a/src/Uno.SourceGeneration.Engine.Shared/Workspace/CommandLineArgumentReader.cs b/src/Uno.SourceGeneration.Engine.Shared/Workspace/CommandLineArgumentReader.cs index 85f4528..c574ad5 100644 --- a/src/Uno.SourceGeneration.Engine.Shared/Workspace/CommandLineArgumentReader.cs +++ b/src/Uno.SourceGeneration.Engine.Shared/Workspace/CommandLineArgumentReader.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// https://github.com/dotnet/roslyn/blob/3e39dd3535962bf9e30bd650e4ff34b610b8349a/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/CommandLineArgumentReader.cs + using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -40,11 +42,11 @@ namespace Uno.SourceGeneration.Engine.Workspace _builder.Add($"/{name}"); } - protected void Add(string name, string value) + protected void Add(string name, string value, bool addQuoteIfValueContainsWhitespace = true) { ValidateName(name); - if (string.IsNullOrEmpty(value) || value.Any(char.IsWhiteSpace)) + if (string.IsNullOrEmpty(value) || (addQuoteIfValueContainsWhitespace && value.Any(char.IsWhiteSpace))) { _builder.Add($"/{name}:\"{value}\""); } @@ -59,11 +61,11 @@ namespace Uno.SourceGeneration.Engine.Workspace Add(name, value.ToString()); } - protected void AddIfNotNullOrWhiteSpace(string name, string value) + protected void AddIfNotNullOrWhiteSpace(string name, string? value, bool addQuoteIfValueContainsWhitespace = true) { if (!string.IsNullOrWhiteSpace(value)) { - Add(name, value); + Add(name, value, addQuoteIfValueContainsWhitespace); } } @@ -120,8 +122,9 @@ namespace Uno.SourceGeneration.Engine.Workspace protected string GetAbsolutePath(string path) { - var directoryPath = PathUtilities.GetDirectoryName(Project.FullPath); - return Path.GetFullPath(FileUtilities.ResolveRelativePath(path, directoryPath) ?? path); + var baseDirectory = PathUtilities.GetDirectoryName(Project.FullPath); + var absolutePath = FileUtilities.ResolveRelativePath(path, baseDirectory) ?? path; + return FileUtilities.TryNormalizeAbsolutePath(absolutePath) ?? absolutePath; } protected void ReadAdditionalFiles() @@ -169,8 +172,7 @@ namespace Uno.SourceGeneration.Engine.Workspace if (emitDebugInfo) { var debugType = Project.ReadPropertyString(PropertyNames.DebugType); - - if (s_debugTypeValues.TryGetValue(debugType, out var value)) + if (debugType != null && s_debugTypeValues.TryGetValue(debugType, out var value)) { Add("debug", value); } @@ -210,9 +212,17 @@ namespace Uno.SourceGeneration.Engine.Workspace protected void ReadImports() { var imports = Project.GetTaskItems(ItemNames.Import); - if (imports != null) + if (imports == null) + return; + + // In case of import alias clause in the form of `aliasname = namespace`, + // we want to add quotes to that single clause only instead of the entire imports. + AddIfNotNullOrWhiteSpace("imports", string.Join(",", imports.Select(ReadImportItem)), addQuoteIfValueContainsWhitespace: false); + + static string ReadImportItem(MSB.Framework.ITaskItem item) { - AddIfNotNullOrWhiteSpace("imports", string.Join(",", imports.Select(item => item.ItemSpec.Trim()))); + var trimmed = item.ItemSpec.Trim(); + return trimmed.Contains(' ') ? $"\"{trimmed}\"" : trimmed; } } @@ -283,15 +293,6 @@ namespace Uno.SourceGeneration.Engine.Workspace } } - protected void ReadAnalyzerConfig() - { - var editorConfigFiles = Project.GetItems("EditorConfigFiles"); - foreach (var editorConfigFile in editorConfigFiles) - { - Add("analyzerconfig", editorConfigFile.EvaluatedInclude); - } - } - protected ImmutableArray Read() { ReadCore(); diff --git a/src/Uno.SourceGeneration.Engine.Shared/Workspace/Constants/ItemNames.cs b/src/Uno.SourceGeneration.Engine.Shared/Workspace/Constants/ItemNames.cs index 89b7d8b..190210c 100644 --- a/src/Uno.SourceGeneration.Engine.Shared/Workspace/Constants/ItemNames.cs +++ b/src/Uno.SourceGeneration.Engine.Shared/Workspace/Constants/ItemNames.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// https://github.com/dotnet/roslyn/blob/3e39dd3535962bf9e30bd650e4ff34b610b8349a/src/Workspaces/Core/MSBuild/MSBuild/Constants/ItemNames.cs + namespace Uno.SourceGeneration.Engine.Workspace.Constants { internal static class ItemNames @@ -9,6 +11,7 @@ namespace Uno.SourceGeneration.Engine.Workspace.Constants public const string Compile = nameof(Compile); public const string CscCommandLineArgs = nameof(CscCommandLineArgs); public const string DocFileItem = nameof(DocFileItem); + public const string EditorConfigFiles = nameof(EditorConfigFiles); public const string Import = nameof(Import); public const string ProjectReference = nameof(ProjectReference); public const string Reference = nameof(Reference); diff --git a/src/Uno.SourceGeneration.Engine.Shared/Workspace/Extensions.cs b/src/Uno.SourceGeneration.Engine.Shared/Workspace/Extensions.cs index f94a3cc..2277cb9 100644 --- a/src/Uno.SourceGeneration.Engine.Shared/Workspace/Extensions.cs +++ b/src/Uno.SourceGeneration.Engine.Shared/Workspace/Extensions.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// https://github.com/dotnet/roslyn/blob/3e39dd3535962bf9e30bd650e4ff34b610b8349a/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/Extensions.cs + using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -21,6 +23,9 @@ namespace Uno.SourceGeneration.Engine.Workspace public static IEnumerable GetDocuments(this MSB.Execution.ProjectInstance executedProject) => executedProject.GetItems(ItemNames.Compile); + public static IEnumerable GetEditorConfigFiles(this MSB.Execution.ProjectInstance executedProject) + => executedProject.GetItems(ItemNames.EditorConfigFiles); + public static IEnumerable GetMetadataReferences(this MSB.Execution.ProjectInstance executedProject) => executedProject.GetItems(ItemNames.ReferencePath); diff --git a/src/Uno.SourceGeneration.Engine.Shared/Workspace/ProjectFileInfo.cs b/src/Uno.SourceGeneration.Engine.Shared/Workspace/ProjectFileInfo.cs index c8fbf7d..1101c34 100644 --- a/src/Uno.SourceGeneration.Engine.Shared/Workspace/ProjectFileInfo.cs +++ b/src/Uno.SourceGeneration.Engine.Shared/Workspace/ProjectFileInfo.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// https://github.com/dotnet/roslyn/blob/main/src/Workspaces/Core/MSBuild/MSBuild/ProjectFile/ProjectFileInfo.cs + using Microsoft.Build.Evaluation; using Microsoft.Build.Execution; using Microsoft.Build.Framework; @@ -44,6 +46,21 @@ namespace Uno.SourceGeneration.Engine.Workspace /// public string OutputRefFilePath { get; } +#if false + /// + /// The default namespace of the project ("" if not defined, which means global namespace), + /// or null if it is unknown or not applicable. + /// + /// + /// Right now VB doesn't have the concept of "default namespace". But we conjure one in workspace + /// by assigning the value of the project's root namespace to it. So various feature can choose to + /// use it for their own purpose. + /// In the future, we might consider officially exposing "default namespace" for VB project + /// (e.g. through a "defaultnamespace" msbuild property) + /// + public string DefaultNamespace { get; } +#endif + /// /// The target framework of this project. /// This takes the form of the 'short name' form used by NuGet (e.g. net46, netcoreapp2.0, etc.) @@ -65,14 +82,27 @@ namespace Uno.SourceGeneration.Engine.Workspace /// public ImmutableArray AdditionalDocuments { get; } + /// + /// The analyzer config documents. + /// + public ImmutableArray AnalyzerConfigDocuments { get; } + /// /// References to other projects. /// public ImmutableArray ProjectReferences { get; } +#if false + /// + /// The error message produced when a failure occurred attempting to get the info. + /// If a failure occurred some or all of the information may be inaccurate or incomplete. + /// + public DiagnosticLog Log { get; } +#endif + public override string ToString() => string.IsNullOrWhiteSpace(TargetFramework) - ? FilePath + ? FilePath ?? string.Empty : $"{FilePath} ({TargetFramework})"; private ProjectFileInfo( @@ -81,11 +111,15 @@ namespace Uno.SourceGeneration.Engine.Workspace string filePath, string outputFilePath, string outputRefFilePath, + //string defaultNamespace, string targetFramework, ImmutableArray commandLineArgs, ImmutableArray documents, ImmutableArray additionalDocuments, - ImmutableArray projectReferences) + ImmutableArray analyzerConfigDocuments, + ImmutableArray projectReferences + //DiagnosticLog log + ) { Debug.Assert(filePath != null); @@ -94,11 +128,14 @@ namespace Uno.SourceGeneration.Engine.Workspace this.FilePath = filePath; this.OutputFilePath = outputFilePath; this.OutputRefFilePath = outputRefFilePath; + //this.DefaultNamespace = defaultNamespace; this.TargetFramework = targetFramework; this.CommandLineArgs = commandLineArgs; this.Documents = documents; this.AdditionalDocuments = additionalDocuments; + this.AnalyzerConfigDocuments = analyzerConfigDocuments; this.ProjectReferences = projectReferences; + //this.Log = log; } public static ProjectFileInfo Create( @@ -106,36 +143,47 @@ namespace Uno.SourceGeneration.Engine.Workspace string filePath, string outputFilePath, string outputRefFilePath, + //string defaultNamespace, string targetFramework, ImmutableArray commandLineArgs, ImmutableArray documents, ImmutableArray additionalDocuments, - ImmutableArray projectReferences) - => new ProjectFileInfo( + ImmutableArray analyzerConfigDocuments, + ImmutableArray projectReferences + //DiagnosticLog log) + ) + => new( isEmpty: false, language, filePath, outputFilePath, outputRefFilePath, + //defaultNamespace, targetFramework, commandLineArgs, documents, additionalDocuments, - projectReferences); + analyzerConfigDocuments, + projectReferences + //log + ); - public static ProjectFileInfo CreateEmpty(string language, string filePath) - => new ProjectFileInfo( + public static ProjectFileInfo CreateEmpty(string language, string filePath) // , DiagnosticLog log + => new( isEmpty: true, language, filePath, outputFilePath: null, outputRefFilePath: null, + //defaultNamespace: null, targetFramework: null, commandLineArgs: ImmutableArray.Empty, documents: ImmutableArray.Empty, additionalDocuments: ImmutableArray.Empty, - projectReferences: ImmutableArray.Empty); - + analyzerConfigDocuments: ImmutableArray.Empty, + projectReferences: ImmutableArray.Empty + //log + ); public static ProjectFileInfo FromMSBuildProjectInstance(string language, Microsoft.Build.Evaluation.Project loadedProject, ProjectInstance project) => new Builder(loadedProject, project).Build(language); @@ -180,9 +228,14 @@ namespace Uno.SourceGeneration.Engine.Workspace .ToImmutableArray(); var additionalDocs = _project.GetAdditionalFiles() - .Select(MakeAdditionalDocumentFileInfo) + .Select(MakeNonSourceFileDocumentFileInfo) .ToImmutableArray(); + var analyzerConfigDocs = _project.GetEditorConfigFiles() + .Select(MakeNonSourceFileDocumentFileInfo) + .ToImmutableArray(); + + return ProjectFileInfo.Create( language, _loadedProject.FullPath, @@ -192,17 +245,17 @@ namespace Uno.SourceGeneration.Engine.Workspace commandLineArgs, docs, additionalDocs, + analyzerConfigDocs, _project.GetProjectReferences().ToImmutableArray() ); } - private DocumentFileInfo MakeAdditionalDocumentFileInfo(ITaskItem documentItem) + private DocumentFileInfo MakeNonSourceFileDocumentFileInfo(ITaskItem documentItem) { var filePath = GetDocumentFilePath(documentItem); var logicalPath = GetDocumentLogicalPath(documentItem, _project.Directory); var isLinked = IsDocumentLinked(documentItem); var isGenerated = IsDocumentGenerated(documentItem); - return new DocumentFileInfo(filePath, logicalPath, isLinked, isGenerated, SourceCodeKind.Regular); } @@ -314,5 +367,5 @@ namespace Uno.SourceGeneration.Engine.Workspace private ImmutableArray ReadCommandLineArgs(ProjectInstance project) => CSharpCommandLineArgumentReader.Read(project); } - } + } } diff --git a/src/Uno.SourceGeneration.Engine.Shared/Workspace/ProjectInfoBuilder.cs b/src/Uno.SourceGeneration.Engine.Shared/Workspace/ProjectInfoBuilder.cs index ad38b71..856cf9d 100644 --- a/src/Uno.SourceGeneration.Engine.Shared/Workspace/ProjectInfoBuilder.cs +++ b/src/Uno.SourceGeneration.Engine.Shared/Workspace/ProjectInfoBuilder.cs @@ -12,6 +12,9 @@ using Uno.SourceGeneration.Engine.Workspace.Utilities; using Uno.SourceGeneration.Host; using Uno.SourceGeneration.Host.Helpers; +// Almost taken from https://github.com/dotnet/roslyn/blob/3e39dd3535962bf9e30bd650e4ff34b610b8349a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker.cs +// But not an exact copy. + namespace Uno.SourceGeneration.Engine.Workspace { internal class ProjectInfoBuilder @@ -60,6 +63,7 @@ namespace Uno.SourceGeneration.Engine.Workspace var documents = CreateDocumentInfos(projectFileInfo.Documents, projectId, commandLineArgs.Encoding); var additionalDocuments = CreateDocumentInfos(projectFileInfo.AdditionalDocuments, projectId, commandLineArgs.Encoding); + var analyzerConfigDocuments = CreateDocumentInfos(projectFileInfo.AnalyzerConfigDocuments, projectId, commandLineArgs.Encoding); // CheckForDuplicateDocuments(documents, additionalDocuments, projectPath, projectId); var resolvedReferences = ResolveReferencesAsync(projectId, projectFileInfo, commandLineArgs); @@ -79,16 +83,8 @@ namespace Uno.SourceGeneration.Engine.Workspace analyzerReferences: Enumerable.Empty(), additionalDocuments: additionalDocuments, isSubmission: false, - hostObjectType: null).WithAnalyzerConfigDocuments(commandLineArgs.AnalyzerConfigPaths.Select(CreateDocumentInfo)); - - DocumentInfo CreateDocumentInfo(string path) - { - return DocumentInfo.Create( - DocumentId.CreateNewId(projectId, path), - name: path, - filePath: path, - loader: new FileTextLoader(path, commandLineArgs.Encoding)); - } + hostObjectType: null) + .WithAnalyzerConfigDocuments(analyzerConfigDocuments); } private readonly struct ResolvedReferences diff --git a/src/Uno.SourceGeneration.Host/Uno.SourceGeneration.Host.csproj b/src/Uno.SourceGeneration.Host/Uno.SourceGeneration.Host.csproj index 3dea596..01ea28b 100644 --- a/src/Uno.SourceGeneration.Host/Uno.SourceGeneration.Host.csproj +++ b/src/Uno.SourceGeneration.Host/Uno.SourceGeneration.Host.csproj @@ -7,7 +7,7 @@ true true true - 7.2 + 9 $(MSBuildThisFileDirectory)app.$(TargetFramework).config LatestMajor