Skip to content

Commit

Permalink
chore: suppress IDE0161 message
Browse files Browse the repository at this point in the history
  • Loading branch information
filzrev committed Sep 20, 2023
1 parent 82511bf commit e10d1d5
Show file tree
Hide file tree
Showing 4 changed files with 294 additions and 300 deletions.
33 changes: 15 additions & 18 deletions src/Docfx.Dotnet/SourceLink/PortableCustomDebugInfoKinds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,21 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable
namespace Microsoft.CodeAnalysis.Debugging;

namespace Microsoft.CodeAnalysis.Debugging
internal static class PortableCustomDebugInfoKinds
{
internal static class PortableCustomDebugInfoKinds
{
public static readonly Guid AsyncMethodSteppingInformationBlob = new("54FD2AC5-E925-401A-9C2A-F94F171072F8");
public static readonly Guid StateMachineHoistedLocalScopes = new("6DA9A61E-F8C7-4874-BE62-68BC5630DF71");
public static readonly Guid DynamicLocalVariables = new("83C563C4-B4F3-47D5-B824-BA5441477EA8");
public static readonly Guid TupleElementNames = new("ED9FDF71-8879-4747-8ED3-FE5EDE3CE710");
public static readonly Guid DefaultNamespace = new("58b2eab6-209f-4e4e-a22c-b2d0f910c782");
public static readonly Guid EncLocalSlotMap = new("755F52A8-91C5-45BE-B4B8-209571E552BD");
public static readonly Guid EncLambdaAndClosureMap = new("A643004C-0240-496F-A783-30D64F4979DE");
public static readonly Guid EncStateMachineStateMap = new("8B78CD68-2EDE-420B-980B-E15884B8AAA3");
public static readonly Guid SourceLink = new("CC110556-A091-4D38-9FEC-25AB9A351A6A");
public static readonly Guid EmbeddedSource = new("0E8A571B-6926-466E-B4AD-8AB04611F5FE");
public static readonly Guid CompilationMetadataReferences = new("7E4D4708-096E-4C5C-AEDA-CB10BA6A740D");
public static readonly Guid CompilationOptions = new("B5FEEC05-8CD0-4A83-96DA-466284BB4BD8");
public static readonly Guid TypeDefinitionDocuments = new("932E74BC-DBA9-4478-8D46-0F32A7BAB3D3");
}
public static readonly Guid AsyncMethodSteppingInformationBlob = new("54FD2AC5-E925-401A-9C2A-F94F171072F8");
public static readonly Guid StateMachineHoistedLocalScopes = new("6DA9A61E-F8C7-4874-BE62-68BC5630DF71");
public static readonly Guid DynamicLocalVariables = new("83C563C4-B4F3-47D5-B824-BA5441477EA8");
public static readonly Guid TupleElementNames = new("ED9FDF71-8879-4747-8ED3-FE5EDE3CE710");
public static readonly Guid DefaultNamespace = new("58b2eab6-209f-4e4e-a22c-b2d0f910c782");
public static readonly Guid EncLocalSlotMap = new("755F52A8-91C5-45BE-B4B8-209571E552BD");
public static readonly Guid EncLambdaAndClosureMap = new("A643004C-0240-496F-A783-30D64F4979DE");
public static readonly Guid EncStateMachineStateMap = new("8B78CD68-2EDE-420B-980B-E15884B8AAA3");
public static readonly Guid SourceLink = new("CC110556-A091-4D38-9FEC-25AB9A351A6A");
public static readonly Guid EmbeddedSource = new("0E8A571B-6926-466E-B4AD-8AB04611F5FE");
public static readonly Guid CompilationMetadataReferences = new("7E4D4708-096E-4C5C-AEDA-CB10BA6A740D");
public static readonly Guid CompilationOptions = new("B5FEEC05-8CD0-4A83-96DA-466284BB4BD8");
public static readonly Guid TypeDefinitionDocuments = new("932E74BC-DBA9-4478-8D46-0F32A7BAB3D3");
}
295 changes: 147 additions & 148 deletions src/Docfx.Dotnet/SourceLink/SourceLinkMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,210 +12,209 @@

#nullable enable

namespace Microsoft.SourceLink.Tools
namespace Microsoft.SourceLink.Tools;

/// <summary>
/// Source Link URL map. Maps file paths matching Source Link patterns to URLs.
/// </summary>
internal readonly struct SourceLinkMap
{
/// <summary>
/// Source Link URL map. Maps file paths matching Source Link patterns to URLs.
/// </summary>
internal readonly struct SourceLinkMap
private readonly ReadOnlyCollection<Entry> _entries;

private SourceLinkMap(ReadOnlyCollection<Entry> mappings)
{
private readonly ReadOnlyCollection<Entry> _entries;
_entries = mappings;
}

private SourceLinkMap(ReadOnlyCollection<Entry> mappings)
public readonly struct Entry
{
public readonly FilePathPattern FilePath;
public readonly UriPattern Uri;

public Entry(FilePathPattern filePath, UriPattern uri)
{
_entries = mappings;
FilePath = filePath;
Uri = uri;
}

public readonly struct Entry
public void Deconstruct(out FilePathPattern filePath, out UriPattern uri)
{
public readonly FilePathPattern FilePath;
public readonly UriPattern Uri;
filePath = FilePath;
uri = Uri;
}
}

public Entry(FilePathPattern filePath, UriPattern uri)
{
FilePath = filePath;
Uri = uri;
}
public readonly struct FilePathPattern
{
public readonly string Path;
public readonly bool IsPrefix;

public void Deconstruct(out FilePathPattern filePath, out UriPattern uri)
{
filePath = FilePath;
uri = Uri;
}
public FilePathPattern(string path, bool isPrefix)
{
Path = path;
IsPrefix = isPrefix;
}
}

public readonly struct FilePathPattern
{
public readonly string Path;
public readonly bool IsPrefix;
public readonly struct UriPattern
{
public readonly string Prefix;
public readonly string Suffix;

public FilePathPattern(string path, bool isPrefix)
{
Path = path;
IsPrefix = isPrefix;
}
public UriPattern(string prefix, string suffix)
{
Prefix = prefix;
Suffix = suffix;
}
}

public readonly struct UriPattern
{
public readonly string Prefix;
public readonly string Suffix;
public IReadOnlyList<Entry> Entries => _entries;

public UriPattern(string prefix, string suffix)
{
Prefix = prefix;
Suffix = suffix;
}
}
/// <summary>
/// Parses Source Link JSON string.
/// </summary>
/// <exception cref="ArgumentNullException"><paramref name="json"/> is null.</exception>
/// <exception cref="InvalidDataException">The JSON does not follow Source Link specification.</exception>
/// <exception cref="JsonException"><paramref name="json"/> is not valid JSON string.</exception>
public static SourceLinkMap Parse(string json)
{
ArgumentNullException.ThrowIfNull(json);

public IReadOnlyList<Entry> Entries => _entries;
var list = new List<Entry>();

/// <summary>
/// Parses Source Link JSON string.
/// </summary>
/// <exception cref="ArgumentNullException"><paramref name="json"/> is null.</exception>
/// <exception cref="InvalidDataException">The JSON does not follow Source Link specification.</exception>
/// <exception cref="JsonException"><paramref name="json"/> is not valid JSON string.</exception>
public static SourceLinkMap Parse(string json)
var root = JsonDocument.Parse(json, new JsonDocumentOptions() { AllowTrailingCommas = true }).RootElement;
if (root.ValueKind != JsonValueKind.Object)
{
ArgumentNullException.ThrowIfNull(json);
throw new InvalidDataException();
}

var list = new List<Entry>();
foreach (var rootEntry in root.EnumerateObject())
{
if (!rootEntry.NameEquals("documents"))
{
// potential future extensibility
continue;
}

var root = JsonDocument.Parse(json, new JsonDocumentOptions() { AllowTrailingCommas = true }).RootElement;
if (root.ValueKind != JsonValueKind.Object)
if (rootEntry.Value.ValueKind != JsonValueKind.Object)
{
throw new InvalidDataException();
}

foreach (var rootEntry in root.EnumerateObject())
foreach (var documentsEntry in rootEntry.Value.EnumerateObject())
{
if (!rootEntry.NameEquals("documents"))
{
// potential future extensibility
continue;
}

if (rootEntry.Value.ValueKind != JsonValueKind.Object)
if (documentsEntry.Value.ValueKind != JsonValueKind.String ||
!TryParseEntry(documentsEntry.Name, documentsEntry.Value.GetString()!, out var entry))
{
throw new InvalidDataException();
}

foreach (var documentsEntry in rootEntry.Value.EnumerateObject())
{
if (documentsEntry.Value.ValueKind != JsonValueKind.String ||
!TryParseEntry(documentsEntry.Name, documentsEntry.Value.GetString()!, out var entry))
{
throw new InvalidDataException();
}

list.Add(entry);
}
list.Add(entry);
}
}

// Sort the map by decreasing file path length. This ensures that the most specific paths will checked before the least specific
// and that absolute paths will be checked before a wildcard path with a matching base
list.Sort((left, right) => -left.FilePath.Path.Length.CompareTo(right.FilePath.Path.Length));

// Sort the map by decreasing file path length. This ensures that the most specific paths will checked before the least specific
// and that absolute paths will be checked before a wildcard path with a matching base
list.Sort((left, right) => -left.FilePath.Path.Length.CompareTo(right.FilePath.Path.Length));
return new SourceLinkMap(new ReadOnlyCollection<Entry>(list));
}

return new SourceLinkMap(new ReadOnlyCollection<Entry>(list));
private static bool TryParseEntry(string key, string value, out Entry entry)
{
entry = default;

// VALIDATION RULES
// 1. The only acceptable wildcard is one and only one '*', which if present will be replaced by a relative path
// 2. If the filepath does not contain a *, the uri cannot contain a * and if the filepath contains a * the uri must contain a *
// 3. If the filepath contains a *, it must be the final character
// 4. If the uri contains a *, it may be anywhere in the uri
if (key.Length == 0)
{
return false;
}

private static bool TryParseEntry(string key, string value, out Entry entry)
var filePathStar = key.IndexOf('*');
if (filePathStar == key.Length - 1)
{
entry = default;

// VALIDATION RULES
// 1. The only acceptable wildcard is one and only one '*', which if present will be replaced by a relative path
// 2. If the filepath does not contain a *, the uri cannot contain a * and if the filepath contains a * the uri must contain a *
// 3. If the filepath contains a *, it must be the final character
// 4. If the uri contains a *, it may be anywhere in the uri
if (key.Length == 0)
{
return false;
}
key = key[..filePathStar];
}
else if (filePathStar >= 0)
{
return false;
}

var filePathStar = key.IndexOf('*');
if (filePathStar == key.Length - 1)
{
key = key[..filePathStar];
}
else if (filePathStar >= 0)
string uriPrefix, uriSuffix;
var uriStar = value.IndexOf('*');
if (uriStar >= 0)
{
if (filePathStar < 0)
{
return false;
}

string uriPrefix, uriSuffix;
var uriStar = value.IndexOf('*');
if (uriStar >= 0)
{
if (filePathStar < 0)
{
return false;
}
uriPrefix = value[..uriStar];
uriSuffix = value[(uriStar + 1)..];

uriPrefix = value[..uriStar];
uriSuffix = value[(uriStar + 1)..];

if (uriSuffix.Contains('*'))
{
return false;
}
}
else
if (uriSuffix.Contains('*'))
{
uriPrefix = value;
uriSuffix = "";
return false;
}
}
else
{
uriPrefix = value;
uriSuffix = "";
}

entry = new Entry(
new FilePathPattern(key, isPrefix: filePathStar >= 0),
new UriPattern(uriPrefix, uriSuffix));
entry = new Entry(
new FilePathPattern(key, isPrefix: filePathStar >= 0),
new UriPattern(uriPrefix, uriSuffix));

return true;
}
return true;
}

/// <summary>
/// Maps specified <paramref name="path"/> to the corresponding URL.
/// </summary>
/// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
public bool TryGetUri(
string path,
/// <summary>
/// Maps specified <paramref name="path"/> to the corresponding URL.
/// </summary>
/// <exception cref="ArgumentNullException"><paramref name="path"/> is null.</exception>
public bool TryGetUri(
string path,
#if NETCOREAPP
[NotNullWhen(true)]
[NotNullWhen(true)]
#endif
out string? uri)
{
ArgumentNullException.ThrowIfNull(path);
out string? uri)
{
ArgumentNullException.ThrowIfNull(path);

if (path.Contains('*'))
{
uri = null;
return false;
}
if (path.Contains('*'))
{
uri = null;
return false;
}

// Note: the mapping function is case-insensitive.
// Note: the mapping function is case-insensitive.

foreach (var (file, mappedUri) in _entries)
foreach (var (file, mappedUri) in _entries)
{
if (file.IsPrefix)
{
if (file.IsPrefix)
if (path.StartsWith(file.Path, StringComparison.OrdinalIgnoreCase))
{
if (path.StartsWith(file.Path, StringComparison.OrdinalIgnoreCase))
{
var escapedPath = string.Join("/", path[file.Path.Length..].Split(new[] { '/', '\\' }).Select(Uri.EscapeDataString));
uri = mappedUri.Prefix + escapedPath + mappedUri.Suffix;
return true;
}
}
else if (string.Equals(path, file.Path, StringComparison.OrdinalIgnoreCase))
{
Debug.Assert(mappedUri.Suffix.Length == 0);
uri = mappedUri.Prefix;
var escapedPath = string.Join("/", path[file.Path.Length..].Split(new[] { '/', '\\' }).Select(Uri.EscapeDataString));
uri = mappedUri.Prefix + escapedPath + mappedUri.Suffix;
return true;
}
}

uri = null;
return false;
else if (string.Equals(path, file.Path, StringComparison.OrdinalIgnoreCase))
{
Debug.Assert(mappedUri.Suffix.Length == 0);
uri = mappedUri.Prefix;
return true;
}
}

uri = null;
return false;
}
}
Loading

0 comments on commit e10d1d5

Please sign in to comment.