forked from dotmake-build/command-line
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAttributeArguments.cs
More file actions
133 lines (108 loc) · 5.32 KB
/
AttributeArguments.cs
File metadata and controls
133 lines (108 loc) · 5.32 KB
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
128
129
130
131
132
133
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace DotMake.CommandLine.SourceGeneration.Util
{
public class AttributeArguments : IEnumerable<KeyValuePair<string, TypedConstant>>
{
private readonly AttributeData attributeData;
private readonly ImmutableDictionary<string, TypedConstant> dictionary;
private readonly Dictionary<string, IPropertySymbol> resourceArguments;
public AttributeArguments(AttributeData attributeData, SemanticModel semanticModel)
{
this.attributeData = attributeData;
//Filter out arguments with null value to avoid repeated checks
//Note: IsNull should be used as Value can throw for arrays
dictionary = attributeData.NamedArguments.Where(pair => !pair.Value.IsNull)
.ToImmutableDictionary();
resourceArguments = GetResourceArguments(attributeData, semanticModel);
}
public bool ContainsKey(string argumentName)
{
return dictionary.ContainsKey(argumentName);
}
public bool TryGetValue(string argumentName, out object argumentValue)
{
if (dictionary.TryGetValue(argumentName, out var argumentTypedConstant))
{
argumentValue = argumentTypedConstant.Value;
return true;
}
argumentValue = null;
return false;
}
public bool TryGetValues(string argumentName, out object[] argumentValues)
{
//For array values
if (dictionary.TryGetValue(argumentName, out var argumentTypedConstant))
{
argumentValues = argumentTypedConstant.Values
.Where(elementTypeConstant => !elementTypeConstant.IsNull) //skip null elements
.Select(elementTypeConstant => elementTypeConstant.Value)
.ToArray();
return true;
}
argumentValues = null;
return false;
}
public bool TryGetTypedConstant(string argumentName, out TypedConstant argumentTypedConstant)
{
return dictionary.TryGetValue(argumentName, out argumentTypedConstant);
}
public bool TryGetResourceProperty(string argumentName, out IPropertySymbol resourceProperty)
{
return resourceArguments.TryGetValue(argumentName, out resourceProperty);
}
public IEnumerator<KeyValuePair<string, TypedConstant>> GetEnumerator()
{
return dictionary.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private static Dictionary<string, IPropertySymbol> GetResourceArguments(AttributeData attributeData, SemanticModel semanticModel)
{
var resourceArguments = new Dictionary<string, IPropertySymbol>();
var argumentSyntaxList = (attributeData.ApplicationSyntaxReference?.GetSyntax() as AttributeSyntax)
?.ArgumentList?.Arguments;
if (argumentSyntaxList == null || semanticModel == null)
return resourceArguments;
foreach (var argumentSyntax in argumentSyntaxList)
{
if (argumentSyntax.NameEquals != null
&& argumentSyntax.Expression is InvocationExpressionSyntax invocationExpressionSyntax
&& invocationExpressionSyntax.Expression is IdentifierNameSyntax identifierNameSyntax
&& identifierNameSyntax.Identifier.ValueText == "nameof"
&& invocationExpressionSyntax.ArgumentList.Arguments.Count == 1)
{
var nameofArgument = invocationExpressionSyntax.ArgumentList.Arguments[0].Expression;
// fix #71: Syntax node is not within syntax tree
var correctModel = semanticModel.Compilation.GetSemanticModel(nameofArgument.SyntaxTree);
SymbolInfo nameofInfo;
nameofInfo = correctModel.GetSymbolInfo(nameofArgument);
if (nameofInfo.Symbol is IPropertySymbol propertySymbol
&& propertySymbol.Type.SpecialType == SpecialType.System_String)
{
var classAttributeData = propertySymbol.ContainingType.GetAttributes()
.FirstOrDefault(a => a.AttributeClass.ToCompareString() == "System.CodeDom.Compiler.GeneratedCodeAttribute");
if (classAttributeData != null
&& classAttributeData.ConstructorArguments.Length > 0
&& !classAttributeData.ConstructorArguments[0].IsNull
&& classAttributeData.ConstructorArguments[0].Value?.ToString() == "System.Resources.Tools.StronglyTypedResourceBuilder")
{
resourceArguments.Add(
argumentSyntax.NameEquals.Name.Identifier.ValueText,
propertySymbol
);
}
}
}
}
return resourceArguments;
}
}
}