Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Security.Cryptography;
using System.Runtime.Serialization;
using System.Text;
using Microsoft.CodeAnalysis.Diagnostics;
Expand Down Expand Up @@ -49,23 +50,40 @@ public static SourceGeneratedDocumentIdentity Generate(ProjectId projectId, stri
// dynamic assembly they produced at runtime and passed us that via a custom AnalyzerReference.
var assemblyNameToHash = generatorIdentity.AssemblyPath ?? generatorIdentity.AssemblyName;

using var _ = ArrayBuilder<byte>.GetInstance(capacity: (assemblyNameToHash.Length + 1 + generatorIdentity.TypeName.Length + 1 + hintName.Length) * 2 + projectIdBytes.Length, out var hashInput);
hashInput.AddRange(projectIdBytes);
var hashInputLength = projectIdBytes.Length
+ Encoding.Unicode.GetByteCount(assemblyNameToHash)
+ 2
+ Encoding.Unicode.GetByteCount(generatorIdentity.TypeName)
+ 2
+ Encoding.Unicode.GetByteCount(hintName);

var hashInput = new byte[hashInputLength];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there no streaming version that can avoid this alloc in the first place?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I could find (at least on the Encoding class)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about IncrementalHash.Create(Sha256), and then just append the data, instead of needing the initial array to copy into?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we also have the Checksum type. Which, TBH, feels pretty appropriate for this use case :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, reworked with using Checksums instead. It does seem easier this way.


Array.Copy(projectIdBytes, 0, hashInput, 0, projectIdBytes.Length);
var byteIndex = projectIdBytes.Length;

// Add a null to separate the generator name and hint name; since this is effectively a joining of UTF-16 bytes
// we'll use a UTF-16 null just to make sure there's absolutely no risk of collision.
hashInput.AddRange(Encoding.Unicode.GetBytes(assemblyNameToHash));
hashInput.AddRange(0, 0);
hashInput.AddRange(Encoding.Unicode.GetBytes(generatorIdentity.TypeName));
hashInput.AddRange(0, 0);
hashInput.AddRange(Encoding.Unicode.GetBytes(hintName));
byteIndex += Encoding.Unicode.GetBytes(assemblyNameToHash, 0, assemblyNameToHash.Length, hashInput, byteIndex);
byteIndex += 2;
byteIndex += Encoding.Unicode.GetBytes(generatorIdentity.TypeName, 0, generatorIdentity.TypeName.Length, hashInput, byteIndex);
byteIndex += 2;
byteIndex += Encoding.Unicode.GetBytes(hintName, 0, hintName.Length, hashInput, byteIndex);

// The particular choice of crypto algorithm here is arbitrary and can be always changed as necessary. The only requirement
// is it must be collision resistant, and provide enough bits to fill a GUID.
using var crytpoAlgorithm = System.Security.Cryptography.SHA256.Create();
var hash = crytpoAlgorithm.ComputeHash(hashInput.ToArray());
#if NET
Span<byte> hash = stackalloc byte[SHA256.HashSizeInBytes];
SHA256.HashData(hashInput, hash);

var guid = new Guid(hash[..16]);
#else
using var crytpoAlgorithm = SHA256.Create();
var hash = crytpoAlgorithm.ComputeHash(hashInput);

Array.Resize(ref hash, 16);
var guid = new Guid(hash);
#endif

var documentId = DocumentId.CreateFromSerialized(projectId, guid, isSourceGenerated: true, hintName);

Expand Down
Loading