File: MSBuild\ProjectFile\CommandLineArgumentReader.cs
Web Access
Project: src\src\Workspaces\Core\MSBuild.BuildHost\Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj (Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost)
// 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 Roslyn.Utilities;
using MSB = Microsoft.Build;
 
namespace Microsoft.CodeAnalysis.MSBuild
{
    internal abstract class CommandLineArgumentReader
    {
        protected readonly MSB.Execution.ProjectInstance Project;
        private readonly ImmutableArray<string>.Builder _builder;
 
        protected CommandLineArgumentReader(MSB.Execution.ProjectInstance project)
        {
            Project = project;
            _builder = ImmutableArray.CreateBuilder<string>();
        }
 
        protected abstract void ReadCore();
 
        private static void ValidateName(string name)
        {
            if (string.IsNullOrEmpty(name) || name.Any(char.IsWhiteSpace))
            {
                throw new ArgumentException(WorkspaceMSBuildBuildHostResources.Parameter_cannot_be_null_empty_or_contain_whitespace, nameof(name));
            }
        }
 
        protected void Add(string name)
        {
            ValidateName(name);
 
            _builder.Add($"/{name}");
        }
 
        protected void Add(string name, string? value, bool addQuoteIfValueContainsWhitespace = true)
        {
            ValidateName(name);
 
            if (string.IsNullOrEmpty(value) || (addQuoteIfValueContainsWhitespace && value.Any(char.IsWhiteSpace)))
            {
                _builder.Add($"/{name}:\"{value}\"");
            }
            else
            {
                _builder.Add($"/{name}:{value}");
            }
        }
 
        protected void Add(string name, int value)
        {
            Add(name, value.ToString());
        }
 
        protected void AddIfNotNullOrWhiteSpace(string name, string? value, bool addQuoteIfValueContainsWhitespace = true)
        {
            if (!RoslynString.IsNullOrWhiteSpace(value))
            {
                Add(name, value, addQuoteIfValueContainsWhitespace);
            }
        }
 
        protected void AddIfTrue(string name, bool condition)
        {
            if (condition)
            {
                Add(name);
            }
        }
 
        protected void AddIfTrue(string name, string value, bool condition)
        {
            if (condition)
            {
                Add(name, value);
            }
        }
 
        protected void AddIfFalse(string name, bool condition)
        {
            if (!condition)
            {
                Add(name);
            }
        }
 
        protected void AddWithPlus(string name)
        {
            Add($"{name}+");
        }
 
        protected void AddWithMinus(string name)
        {
            Add($"{name}-");
        }
 
        protected void AddWithPlusOrMinus(string name, bool condition)
        {
            if (condition)
            {
                AddWithPlus(name);
            }
            else
            {
                AddWithMinus(name);
            }
        }
 
        protected string GetDocumentFilePath(MSB.Framework.ITaskItem documentItem)
        {
            return GetAbsolutePath(documentItem.ItemSpec);
        }
 
        protected string GetAbsolutePath(string path)
        {
            var baseDirectory = PathUtilities.GetDirectoryName(Project.FullPath);
            var absolutePath = FileUtilities.ResolveRelativePath(path, baseDirectory) ?? path;
            return FileUtilities.TryNormalizeAbsolutePath(absolutePath) ?? absolutePath;
        }
 
        protected void ReadAdditionalFiles()
        {
            var additionalFiles = Project.GetAdditionalFiles();
            if (additionalFiles != null)
            {
                foreach (var additionalFile in additionalFiles)
                {
                    Add("additionalfile", GetDocumentFilePath(additionalFile));
                }
            }
        }
 
        protected void ReadAnalyzers()
        {
            var analyzers = Project.GetAnalyzers();
            if (analyzers != null)
            {
                foreach (var analyzer in analyzers)
                {
                    Add("analyzer", GetDocumentFilePath(analyzer));
                }
            }
        }
 
        protected void ReadCodePage()
        {
            var codePage = Project.ReadPropertyInt(PropertyNames.CodePage);
            AddIfTrue("codepage", codePage.ToString(), codePage != 0);
        }
 
        private static readonly ImmutableDictionary<string, string> s_debugTypeValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
        {
            { "none", "none" },
            { "pdbonly", "pdbonly" },
            { "full", "full" },
            { "portable", "portable" },
            { "embedded", "embedded" }
        }.ToImmutableDictionary();
 
        protected void ReadDebugInfo()
        {
            var emitDebugInfo = Project.ReadPropertyBool(PropertyNames.DebugSymbols);
            if (emitDebugInfo)
            {
                var debugType = Project.ReadPropertyString(PropertyNames.DebugType);
                if (debugType != null && s_debugTypeValues.TryGetValue(debugType, out var value))
                {
                    Add("debug", value);
                }
            }
        }
 
        protected void ReadDelaySign()
        {
            var delaySign = Project.ReadPropertyString(PropertyNames.DelaySign);
            if (!RoslynString.IsNullOrWhiteSpace(delaySign))
            {
                AddWithPlusOrMinus("delaysign", Conversions.ToBool(delaySign));
            }
        }
 
        protected void ReadErrorReport()
        {
            var errorReport = Project.ReadPropertyString(PropertyNames.ErrorReport);
            if (!RoslynString.IsNullOrWhiteSpace(errorReport))
            {
                Add("errorreport", errorReport.ToLower());
            }
        }
 
        protected void ReadFeatures()
        {
            var features = Project.ReadPropertyString(PropertyNames.Features);
            if (!RoslynString.IsNullOrWhiteSpace(features))
            {
                foreach (var feature in CompilerOptionParseUtilities.ParseFeatureFromMSBuild(features))
                {
                    Add("features", feature);
                }
            }
        }
 
        protected void ReadImports()
        {
            var imports = Project.GetTaskItems(ItemNames.Import);
            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)
            {
                var trimmed = item.ItemSpec.Trim();
                return trimmed.Contains(' ') ? $"\"{trimmed}\"" : trimmed;
            }
        }
 
        protected void ReadPlatform()
        {
            var platform = Project.ReadPropertyString(PropertyNames.PlatformTarget);
            var prefer32bit = Project.ReadPropertyBool(PropertyNames.Prefer32Bit);
 
            if (prefer32bit && (RoslynString.IsNullOrWhiteSpace(platform) || string.Equals("anycpu", platform, StringComparison.OrdinalIgnoreCase)))
            {
                platform = "anycpu32bitpreferred";
            }
 
            AddIfNotNullOrWhiteSpace("platform", platform);
        }
 
        protected void ReadReferences()
        {
            var references = Project.GetMetadataReferences();
            if (references != null)
            {
                foreach (var reference in references)
                {
                    if (reference.ReferenceOutputAssemblyIsTrue())
                    {
                        var filePath = GetDocumentFilePath(reference);
 
                        var aliases = reference.GetAliases();
                        if (aliases.IsDefaultOrEmpty)
                        {
                            Add("reference", filePath);
                        }
                        else
                        {
                            foreach (var alias in aliases)
                            {
                                if (string.Equals(alias, "global", StringComparison.OrdinalIgnoreCase))
                                {
                                    Add("reference", filePath);
                                }
                                else
                                {
                                    Add("reference", $"{alias}=\"{filePath}\"");
                                }
                            }
                        }
                    }
                }
            }
        }
 
        protected void ReadSigning()
        {
            var signAssembly = Project.ReadPropertyBool(PropertyNames.SignAssembly);
            if (signAssembly)
            {
                var keyFile = Project.ReadPropertyString(PropertyNames.KeyOriginatorFile);
                if (!RoslynString.IsNullOrWhiteSpace(keyFile))
                {
                    Add("keyFile", keyFile);
                }
 
                var keyContainer = Project.ReadPropertyString(PropertyNames.KeyContainerName);
                if (!RoslynString.IsNullOrWhiteSpace(keyContainer))
                {
                    Add("keycontainer", keyContainer);
                }
            }
        }
 
        protected ImmutableArray<string> Read()
        {
            ReadCore();
            return _builder.ToImmutable();
        }
    }
}