-
Notifications
You must be signed in to change notification settings - Fork 468
/
AggregateCategorizedAnalyzerConfigOptions.cs
127 lines (106 loc) · 5.83 KB
/
AggregateCategorizedAnalyzerConfigOptions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if CODEANALYSIS_V3_OR_BETTER
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Analyzer.Utilities.PooledObjects;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Analyzer.Utilities
{
using static CategorizedAnalyzerConfigOptionsExtensions;
/// <summary>
/// Aggregate analyzer configuration options:
///
/// <list type="number">
/// <item><description>Per syntax tree options from <see cref="AnalyzerConfigOptionsProvider"/>.</description></item>
/// <item><description>Options from an <strong>.editorconfig</strong> file passed in as an additional file (back compat).</description></item>
/// </list>
///
/// <inheritdoc cref="ICategorizedAnalyzerConfigOptions"/>
/// </summary>
internal sealed class AggregateCategorizedAnalyzerConfigOptions : ICategorizedAnalyzerConfigOptions
{
public static readonly AggregateCategorizedAnalyzerConfigOptions Empty = new(
globalOptions: null,
ImmutableDictionary<SyntaxTree, Lazy<SyntaxTreeCategorizedAnalyzerConfigOptions>>.Empty,
CompilationCategorizedAnalyzerConfigOptions.Empty);
private readonly Lazy<SyntaxTreeCategorizedAnalyzerConfigOptions>? _globalOptions;
private readonly ImmutableDictionary<SyntaxTree, Lazy<SyntaxTreeCategorizedAnalyzerConfigOptions>> _perTreeOptions;
private readonly CompilationCategorizedAnalyzerConfigOptions _additionalFileBasedOptions;
private AggregateCategorizedAnalyzerConfigOptions(Lazy<SyntaxTreeCategorizedAnalyzerConfigOptions>? globalOptions, ImmutableDictionary<SyntaxTree, Lazy<SyntaxTreeCategorizedAnalyzerConfigOptions>> perTreeOptions, CompilationCategorizedAnalyzerConfigOptions additionalFileBasedOptions)
{
_globalOptions = globalOptions;
_perTreeOptions = perTreeOptions;
_additionalFileBasedOptions = additionalFileBasedOptions;
}
public bool IsEmpty
{
get
{
Debug.Assert(ReferenceEquals(this, Empty) || !_perTreeOptions.IsEmpty || !_additionalFileBasedOptions.IsEmpty);
return ReferenceEquals(this, Empty);
}
}
public static AggregateCategorizedAnalyzerConfigOptions Create(AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider, Compilation compilation, CompilationCategorizedAnalyzerConfigOptions additionalFileBasedOptions)
{
analyzerConfigOptionsProvider = analyzerConfigOptionsProvider ?? throw new ArgumentNullException(nameof(analyzerConfigOptionsProvider));
additionalFileBasedOptions = additionalFileBasedOptions ?? throw new ArgumentNullException(nameof(additionalFileBasedOptions));
if (analyzerConfigOptionsProvider.IsEmpty() && additionalFileBasedOptions.IsEmpty)
{
return Empty;
}
Lazy<SyntaxTreeCategorizedAnalyzerConfigOptions>? globalOptions;
#if CODEANALYSIS_V3_7_OR_BETTER
globalOptions = new Lazy<SyntaxTreeCategorizedAnalyzerConfigOptions>(() => SyntaxTreeCategorizedAnalyzerConfigOptions.Create(analyzerConfigOptionsProvider.GlobalOptions));
#else
globalOptions = null;
#endif
var perTreeOptionsBuilder = PooledDictionary<SyntaxTree, Lazy<SyntaxTreeCategorizedAnalyzerConfigOptions>>.GetInstance();
foreach (var tree in compilation.SyntaxTrees)
{
perTreeOptionsBuilder.Add(tree, new Lazy<SyntaxTreeCategorizedAnalyzerConfigOptions>(() => Create(tree, analyzerConfigOptionsProvider)));
}
return new AggregateCategorizedAnalyzerConfigOptions(globalOptions, perTreeOptionsBuilder.ToImmutableDictionaryAndFree(), additionalFileBasedOptions);
static SyntaxTreeCategorizedAnalyzerConfigOptions Create(SyntaxTree tree, AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider)
{
var options = analyzerConfigOptionsProvider.GetOptions(tree);
return SyntaxTreeCategorizedAnalyzerConfigOptions.Create(options);
}
}
public T GetOptionValue<T>(string optionName, SyntaxTree? tree, DiagnosticDescriptor? rule, TryParseValue<T> tryParseValue, T defaultValue, OptionKind kind = OptionKind.DotnetCodeQuality)
{
if (TryGetOptionValue(optionName, kind, tree, rule, tryParseValue, defaultValue, out var value))
{
return value;
}
return defaultValue;
}
private bool TryGetOptionValue<T>(string optionName, OptionKind kind, SyntaxTree? tree, DiagnosticDescriptor? rule, TryParseValue<T> tryParseValue, T defaultValue, [MaybeNullWhen(false)] out T value)
{
if (ReferenceEquals(this, Empty))
{
value = defaultValue;
return false;
}
// Prefer additional file based options for back compat.
if (_additionalFileBasedOptions.TryGetOptionValue(optionName, kind, rule, tryParseValue, defaultValue, out value))
{
return true;
}
if (tree is null)
{
if (_globalOptions is null)
{
value = defaultValue;
return false;
}
return _globalOptions.Value.TryGetOptionValue(optionName, kind, rule, tryParseValue, defaultValue, out value);
}
return _perTreeOptions.TryGetValue(tree, out var lazyTreeOptions) &&
lazyTreeOptions.Value.TryGetOptionValue(optionName, kind, rule, tryParseValue, defaultValue, out value);
}
}
}
#endif