Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 5 additions & 5 deletions src/Testing.SourceGenerators/GeneratorTestContextBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ public GeneratorTestContextBuilder AddMarkup(string name, CodeMarkup source)
{
return this with
{
_markedLocations = _markedLocations.Add(name, new(source.Location, source.Trigger)),
_markedLocations = _markedLocations.SetItem(name, new(source.Location, source.Trigger)),
_sources = _sources.Add(new(SourceText.From(source.Code, Encoding.UTF8)) { Name = name, }),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 MEDIUM RISK

While _markedLocations was updated to SetItem to allow overriding, _sources remains additive. To fully support overriding markup, the existing source with the same name must be replaced in the _sources collection; otherwise, the compilation will contain multiple files with the same name, leading to 'Duplicate type defined' compiler errors (e.g., CS0101).

};
}
Expand Down Expand Up @@ -726,14 +726,14 @@ public GeneratorTestContextBuilder AddAdditionalTexts(params IEnumerable<Additio
public GeneratorTestContextBuilder AddOption(string path, string key, string value)
{
var rootOptions = _options;
if (rootOptions.TryGetValue(path, out var fileOptions))
if (_options.TryGetValue(path, out var fileOptions))
{
fileOptions = fileOptions.Add(key, value);
fileOptions = fileOptions.SetItem(key, value);
rootOptions = rootOptions.SetItem(path, fileOptions);
}
else
{
rootOptions = rootOptions.SetItem(path, ImmutableDictionary<string, string>.Empty.Add(key, value));
rootOptions = rootOptions.SetItem(path, ImmutableDictionary<string, string>.Empty.SetItem(key, value));
}

return this with { _options = rootOptions, };
Comment on lines 728 to 739

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚪ LOW RISK

Suggestion: This logic can be simplified to a single expression using GetValueOrDefault.

Suggested change
var rootOptions = _options;
if (rootOptions.TryGetValue(path, out var fileOptions))
if (_options.TryGetValue(path, out var fileOptions))
{
fileOptions = fileOptions.Add(key, value);
fileOptions = fileOptions.SetItem(key, value);
rootOptions = rootOptions.SetItem(path, fileOptions);
}
else
{
rootOptions = rootOptions.SetItem(path, ImmutableDictionary<string, string>.Empty.Add(key, value));
rootOptions = rootOptions.SetItem(path, ImmutableDictionary<string, string>.Empty.SetItem(key, value));
}
return this with { _options = rootOptions, };
var fileOptions = _options.GetValueOrDefault(path, ImmutableDictionary<string, string>.Empty).SetItem(key, value);
return this with { _options = _options.SetItem(path, fileOptions) };

Expand All @@ -745,7 +745,7 @@ public GeneratorTestContextBuilder AddOption(string path, string key, string val
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public GeneratorTestContextBuilder AddGlobalOption(string key, string value) => this with { _globalOptions = _globalOptions.Add(key, value), };
public GeneratorTestContextBuilder AddGlobalOption(string key, string value) => this with { _globalOptions = _globalOptions.SetItem(key, value), };

/// <summary>
/// Create the <see cref="GeneratorTestContext" /> from the builder
Expand Down
22 changes: 7 additions & 15 deletions src/Testing.SourceGenerators/OptionsProvider.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Immutable;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;

Expand All @@ -17,7 +17,7 @@
if (!options.TryGetValue(tree.FilePath, out var value)) return GlobalOptions;
foreach (var v in globalOptions.Where(v => !value.ContainsKey(v.Key)))
{
value = value.Add(v.Key, v.Value);
value = value.SetItem(v.Key, v.Value);
}

return new OptionsObject(value);
Comment on lines 17 to 23

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚪ LOW RISK

Suggestion: This merge logic can be simplified and made more efficient by using SetItems to apply local overrides to the global options.

Suggested change
if (!options.TryGetValue(tree.FilePath, out var value)) return GlobalOptions;
foreach (var v in globalOptions.Where(v => !value.ContainsKey(v.Key)))
{
value = value.Add(v.Key, v.Value);
value = value.SetItem(v.Key, v.Value);
}
return new OptionsObject(value);
if (!options.TryGetValue(tree.FilePath, out var value)) return GlobalOptions;
return new OptionsObject(globalOptions.SetItems(value));

Expand All @@ -28,24 +28,16 @@
if (!options.TryGetValue(textFile.Path, out var value)) return GlobalOptions;
foreach (var v in globalOptions.Where(v => !value.ContainsKey(v.Key)))
{
value = value.Add(v.Key, v.Value);
value = value.SetItem(v.Key, v.Value);
}

return new OptionsObject(value);
}

private sealed class OptionsObject : AnalyzerConfigOptions
private sealed class OptionsObject(ImmutableDictionary<string, string> properties) : AnalyzerConfigOptions
{
private readonly ImmutableDictionary<string, string> _properties;
private readonly ImmutableDictionary<string, string> _properties = properties;

public OptionsObject(ImmutableDictionary<string, string> properties)
{
_properties = properties;
}

public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value)
{
return _properties.TryGetValue(key, out value);
}
public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) => _properties.TryGetValue(key, out value);

Check failure on line 41 in src/Testing.SourceGenerators/OptionsProvider.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Testing.SourceGenerators/OptionsProvider.cs#L41

Potential null dereference detected.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 HIGH RISK

The _properties field is initialized from the primary constructor parameter without a null check. If properties is null, any call to TryGetValue will result in a NullReferenceException. Consider initializing with a null check: private readonly ImmutableDictionary<string, string> _properties = properties ?? ImmutableDictionary<string, string>.Empty;.

See Issue in Codacy

}
}
}
Loading