/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/Core/MSBuildTask/CommandLineBuilderExtension.cs
309 строк
12 KB
Jared Parsons
Properly escape ref path names that contain equals (#71038)
01 дек 2023, 23:18
Не верифицирован
01 дек 2023, 23:18
acee0d5
Код
Авторство
О чём код?
// 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.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace Microsoft.CodeAnalysis.BuildTasks { /// <summary> /// CommandLineBuilder derived class for specialized logic specific to MSBuild tasks /// </summary> public class CommandLineBuilderExtension : CommandLineBuilder { private bool _isQuotingRequired; protected override bool IsQuotingRequired(string parameter) => _isQuotingRequired || base.IsQuotingRequired(parameter); /// <summary> /// Set a boolean switch iff its value exists and its value is 'true'. /// </summary> internal void AppendWhenTrue ( string switchName, PropertyDictionary bag, string parameterName ) { object? obj = bag[parameterName]; // If the switch isn't set, don't add it to the command line. if (obj != null) { bool value = (bool)obj; if (value) { AppendSwitch(switchName); } } } /// <summary> /// Set a boolean switch only if its value exists. /// </summary> internal void AppendPlusOrMinusSwitch ( string switchName, PropertyDictionary bag, string parameterName ) { object? obj = bag[parameterName]; // If the switch isn't set, don't add it to the command line. if (obj != null) { bool value = (bool)obj; // Do not quote - or + as they are part of the switch AppendSwitchUnquotedIfNotNull(switchName, (value ? "+" : "-")); } } /// <summary> /// Set a switch if its value exists by choosing from the input choices /// </summary> internal void AppendByChoiceSwitch ( string switchName, PropertyDictionary bag, string parameterName, string choice1, string choice2 ) { object? obj = bag[parameterName]; // If the switch isn't set, don't add it to the command line. if (obj != null) { bool value = (bool)obj; AppendSwitchUnquotedIfNotNull(switchName, (value ? choice1 : choice2)); } } /// <summary> /// Set an integer switch only if its value exists. /// </summary> internal void AppendSwitchWithInteger ( string switchName, PropertyDictionary bag, string parameterName ) { object? obj = bag[parameterName]; // If the switch isn't set, don't add it to the command line. if (obj != null) { int value = (int)obj; AppendSwitchIfNotNull(switchName, value.ToString(CultureInfo.InvariantCulture)); } } /// <summary> /// Adds an aliased switch, used for ResGen: /// /reference:Goo=System.Xml.dll /// </summary> internal void AppendSwitchAliased(string switchName, string alias, string parameter) { AppendSwitchUnquotedIfNotNull(switchName, alias + "="); AppendTextWithQuoting(parameter); } /// <summary> /// Appends a switch with a value that is force quoted. This will quote as if <see cref="CommandLineBuilder.IsQuotingRequired(string)"/> /// returns true for <paramref name="parameter"/>. That means even simple values will be quoted. /// </summary> internal void AppendTextWithForceQuoting(string parameter) { Debug.Assert(!_isQuotingRequired); _isQuotingRequired = true; try { AppendTextWithQuoting(parameter); } finally { _isQuotingRequired = false; } } /// <summary> /// Appends a switch with a value that is force quoted. This will quote as if <see cref="CommandLineBuilder.IsQuotingRequired(string)"/> /// returns true for <paramref name="parameter"/>. That means even simple values will be quoted. /// </summary> internal void AppendSwitchForceQuoted(string switchName, string parameter) { AppendSwitch(switchName); AppendTextWithForceQuoting(parameter); } /// <summary> /// Adds a nested switch, used by SGen.exe. For example: /// /compiler:"/keyfile:\"c:\some folder\myfile.snk\"" /// </summary> internal void AppendNestedSwitch(string outerSwitchName, string innerSwitchName, string parameter) { string quotedParameter = GetQuotedText(parameter); AppendSwitchIfNotNull(outerSwitchName, innerSwitchName + quotedParameter); } /// <summary> /// Returns a quoted string appropriate for appending to a command line. /// </summary> /// <remarks> /// Escapes any double quotes in the string. /// </remarks> protected string GetQuotedText(string unquotedText) { StringBuilder quotedText = new StringBuilder(); AppendQuotedTextToBuffer(quotedText, unquotedText); return quotedText.ToString(); } /// <summary> /// Appends a command-line switch that takes a compound string parameter. The parameter is built up from the item-spec and /// the specified attributes. The switch is appended as many times as there are parameters given. /// </summary> internal void AppendSwitchIfNotNull ( string switchName, ITaskItem[]? parameters, string[] attributes ) { AppendSwitchIfNotNull(switchName, parameters, attributes, treatAsFlags: null); } /// <summary> /// Append a switch if 'parameter' is not null. /// Split on the characters provided. /// </summary> internal void AppendSwitchWithSplitting(string switchName, string? parameter, string delimiter, params char[] splitOn) { if (parameter != null) { string[] splits = parameter.Split(splitOn, /* omitEmptyEntries */ StringSplitOptions.RemoveEmptyEntries); string[] splitAndTrimmed = new string[splits.Length]; for (int i = 0; i < splits.Length; ++i) { splitAndTrimmed[i] = splits[i].Trim(); } AppendSwitchIfNotNull(switchName, splitAndTrimmed, delimiter); } } /// <summary> /// Returns true if the parameter is empty in spirits, /// even if it contains the separators and white space only /// Split on the characters provided. /// </summary> internal static bool IsParameterEmpty([NotNullWhen(false)] string? parameter, params char[] splitOn) { if (parameter != null) { string[] splits = parameter.Split(splitOn, /* omitEmptyEntries */ StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < splits.Length; ++i) { if (!String.IsNullOrEmpty(splits[i].Trim())) { return false; } } } return true; } /// <summary> /// Designed to handle the /link and /embed switches: /// /// /resource:<filename>[,<name>[,Private]] /// /linkresource:<filename>[,<name>[,Private]] /// /// Where the last flag--Private--is either present or not present /// depending on whether the ITaskItem has a Private="True" attribute. /// </summary> internal void AppendSwitchIfNotNull ( string switchName, ITaskItem[]? parameters, string[]? metadataNames, bool[]? treatAsFlags // May be null. In this case no metadata are treated as flags. ) { Debug.Assert(treatAsFlags == null || (metadataNames?.Length == treatAsFlags.Length), "metadataNames and treatAsFlags should have the same length."); if (parameters != null) { foreach (ITaskItem parameter in parameters) { AppendSwitchIfNotNull(switchName, parameter.ItemSpec); if (metadataNames != null) { for (int i = 0; i < metadataNames.Length; ++i) { string metadataValue = parameter.GetMetadata(metadataNames[i]); if ((metadataValue != null) && (metadataValue.Length > 0)) { // Treat attribute as a boolean flag? if (treatAsFlags == null || treatAsFlags[i] == false) { // Not a boolean flag. CommandLine.Append(','); AppendTextWithQuoting(metadataValue); } else { // A boolean flag. bool flagSet = Utilities.TryConvertItemMetadataToBool(parameter, metadataNames[i]); if (flagSet) { CommandLine.Append(','); AppendTextWithQuoting(metadataNames[i]); } } } else { if (treatAsFlags == null || treatAsFlags[i] == false) { // If the caller of this method asked us to add metadata // A, B, and C, and metadata A doesn't exist on the item, // then it doesn't make sense to check for B and C. Because // since these metadata are just being appended on the // command-line switch with comma-separation, you can't pass // in the B metadata unless you've also passed in the A // metadata. Otherwise the tool's command-line parser will // get totally confused. // This only applies to non-flag attributes. break; } } } } } } } internal void AppendArgumentIfNotNull(string argument) { if (!string.IsNullOrEmpty(argument)) { AppendSpaceIfNotEmpty(); AppendTextWithQuoting(argument); } } } }