-
Notifications
You must be signed in to change notification settings - Fork 222
/
KnownType.Implementation.cs
110 lines (95 loc) · 3.6 KB
/
KnownType.Implementation.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
/*
* SonarAnalyzer for .NET
* Copyright (C) 2015-2023 SonarSource SA
* mailto: contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
using System.Text;
namespace SonarAnalyzer.Helpers
{
[DebuggerDisplay("{DebuggerDisplay}")]
public sealed partial class KnownType
{
private readonly IList<string> namespaceParts;
private readonly string[] genericParameters;
public string TypeName { get; }
public string FullName { get; }
public bool IsArray { get; init; }
internal string DebuggerDisplay
{
get
{
var sb = new StringBuilder(FullName);
if (genericParameters.Length > 0)
{
sb.Append('<').Append(genericParameters.JoinStr(", ")).Append('>');
}
if (IsArray)
{
sb.Append("[]");
}
return sb.ToString();
}
}
public KnownType(string fullName, params string[] genericParameters)
{
var parts = fullName.Split('.');
namespaceParts = new ArraySegment<string>(parts, 0, parts.Length - 1);
this.genericParameters = genericParameters;
FullName = fullName;
TypeName = parts[parts.Length - 1];
}
public bool Matches(ITypeSymbol symbol) =>
IsMatch(symbol) || IsMatch(symbol.OriginalDefinition);
private bool IsMatch(ITypeSymbol symbol)
{
_ = symbol ?? throw new ArgumentNullException(nameof(symbol));
if (IsArray)
{
if (symbol is IArrayTypeSymbol array)
{
symbol = array.ElementType;
}
else
{
return false;
}
}
return symbol.Name == TypeName
&& NamespaceMatches(symbol)
&& GenericParametersMatch(symbol);
}
private bool GenericParametersMatch(ISymbol symbol) =>
symbol is INamedTypeSymbol namedType
? namedType.TypeParameters.Select(x => x.Name).SequenceEqual(genericParameters)
: genericParameters.Length == 0;
private bool NamespaceMatches(ISymbol symbol)
{
var currentNamespace = symbol.ContainingNamespace;
var index = namespaceParts.Count - 1;
while (currentNamespace != null && !string.IsNullOrEmpty(currentNamespace.Name) && index >= 0)
{
if (currentNamespace.Name != namespaceParts[index])
{
return false;
}
currentNamespace = currentNamespace.ContainingNamespace;
index--;
}
return index == -1 && string.IsNullOrEmpty(currentNamespace?.Name);
}
}
}