1 | // Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team |
---|
2 | // |
---|
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this |
---|
4 | // software and associated documentation files (the "Software"), to deal in the Software |
---|
5 | // without restriction, including without limitation the rights to use, copy, modify, merge, |
---|
6 | // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
---|
7 | // to whom the Software is furnished to do so, subject to the following conditions: |
---|
8 | // |
---|
9 | // The above copyright notice and this permission notice shall be included in all copies or |
---|
10 | // substantial portions of the Software. |
---|
11 | // |
---|
12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
---|
13 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
---|
14 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
---|
15 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
---|
16 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
---|
17 | // DEALINGS IN THE SOFTWARE. |
---|
18 | |
---|
19 | using System; |
---|
20 | using System.Collections.Generic; |
---|
21 | using ICSharpCode.NRefactory.Semantics; |
---|
22 | using ICSharpCode.NRefactory.Utils; |
---|
23 | |
---|
24 | namespace ICSharpCode.NRefactory.TypeSystem.Implementation |
---|
25 | { |
---|
26 | /// <summary> |
---|
27 | /// Default implementation of <see cref="IUnresolvedAttribute"/>. |
---|
28 | /// </summary> |
---|
29 | [Serializable] |
---|
30 | public sealed class DefaultUnresolvedAttribute : AbstractFreezable, IUnresolvedAttribute, IFreezable, ISupportsInterning |
---|
31 | { |
---|
32 | ITypeReference attributeType; |
---|
33 | DomRegion region; |
---|
34 | IList<ITypeReference> constructorParameterTypes; |
---|
35 | IList<IConstantValue> positionalArguments; |
---|
36 | IList<KeyValuePair<IMemberReference, IConstantValue>> namedArguments; |
---|
37 | |
---|
38 | public DefaultUnresolvedAttribute(ITypeReference attributeType) |
---|
39 | { |
---|
40 | if (attributeType == null) |
---|
41 | throw new ArgumentNullException("attributeType"); |
---|
42 | this.attributeType = attributeType; |
---|
43 | } |
---|
44 | |
---|
45 | public DefaultUnresolvedAttribute(ITypeReference attributeType, IEnumerable<ITypeReference> constructorParameterTypes) |
---|
46 | { |
---|
47 | if (attributeType == null) |
---|
48 | throw new ArgumentNullException("attributeType"); |
---|
49 | this.attributeType = attributeType; |
---|
50 | this.ConstructorParameterTypes.AddRange(constructorParameterTypes); |
---|
51 | } |
---|
52 | |
---|
53 | protected override void FreezeInternal() |
---|
54 | { |
---|
55 | base.FreezeInternal(); |
---|
56 | constructorParameterTypes = FreezableHelper.FreezeList(constructorParameterTypes); |
---|
57 | positionalArguments = FreezableHelper.FreezeListAndElements(positionalArguments); |
---|
58 | namedArguments = FreezableHelper.FreezeList(namedArguments); |
---|
59 | foreach (var pair in namedArguments) { |
---|
60 | FreezableHelper.Freeze(pair.Key); |
---|
61 | FreezableHelper.Freeze(pair.Value); |
---|
62 | } |
---|
63 | } |
---|
64 | |
---|
65 | public ITypeReference AttributeType { |
---|
66 | get { return attributeType; } |
---|
67 | } |
---|
68 | |
---|
69 | public DomRegion Region { |
---|
70 | get { return region; } |
---|
71 | set { |
---|
72 | FreezableHelper.ThrowIfFrozen(this); |
---|
73 | region = value; |
---|
74 | } |
---|
75 | } |
---|
76 | |
---|
77 | public IList<ITypeReference> ConstructorParameterTypes { |
---|
78 | get { |
---|
79 | if (constructorParameterTypes == null) |
---|
80 | constructorParameterTypes = new List<ITypeReference>(); |
---|
81 | return constructorParameterTypes; |
---|
82 | } |
---|
83 | } |
---|
84 | |
---|
85 | public IList<IConstantValue> PositionalArguments { |
---|
86 | get { |
---|
87 | if (positionalArguments == null) |
---|
88 | positionalArguments = new List<IConstantValue>(); |
---|
89 | return positionalArguments; |
---|
90 | } |
---|
91 | } |
---|
92 | |
---|
93 | public IList<KeyValuePair<IMemberReference, IConstantValue>> NamedArguments { |
---|
94 | get { |
---|
95 | if (namedArguments == null) |
---|
96 | namedArguments = new List<KeyValuePair<IMemberReference, IConstantValue>>(); |
---|
97 | return namedArguments; |
---|
98 | } |
---|
99 | } |
---|
100 | |
---|
101 | public void AddNamedFieldArgument(string fieldName, IConstantValue value) |
---|
102 | { |
---|
103 | this.NamedArguments.Add(new KeyValuePair<IMemberReference, IConstantValue>( |
---|
104 | new DefaultMemberReference(SymbolKind.Field, attributeType, fieldName), |
---|
105 | value |
---|
106 | )); |
---|
107 | } |
---|
108 | |
---|
109 | public void AddNamedPropertyArgument(string propertyName, IConstantValue value) |
---|
110 | { |
---|
111 | this.NamedArguments.Add(new KeyValuePair<IMemberReference, IConstantValue>( |
---|
112 | new DefaultMemberReference(SymbolKind.Property, attributeType, propertyName), |
---|
113 | value |
---|
114 | )); |
---|
115 | } |
---|
116 | |
---|
117 | public IAttribute CreateResolvedAttribute(ITypeResolveContext context) |
---|
118 | { |
---|
119 | return new DefaultResolvedAttribute(this, context); |
---|
120 | } |
---|
121 | |
---|
122 | int ISupportsInterning.GetHashCodeForInterning() |
---|
123 | { |
---|
124 | int hash = attributeType.GetHashCode() ^ constructorParameterTypes.GetHashCode(); |
---|
125 | unchecked { |
---|
126 | if (constructorParameterTypes != null) { |
---|
127 | foreach (var type in constructorParameterTypes) { |
---|
128 | hash *= 27; |
---|
129 | hash += type.GetHashCode(); |
---|
130 | } |
---|
131 | } |
---|
132 | if (positionalArguments != null) { |
---|
133 | foreach (var arg in positionalArguments) { |
---|
134 | hash *= 31; |
---|
135 | hash += arg.GetHashCode(); |
---|
136 | } |
---|
137 | } |
---|
138 | if (namedArguments != null) { |
---|
139 | foreach (var pair in namedArguments) { |
---|
140 | hash *= 71; |
---|
141 | hash += pair.Key.GetHashCode() + pair.Value.GetHashCode() * 73; |
---|
142 | } |
---|
143 | } |
---|
144 | } |
---|
145 | return hash; |
---|
146 | } |
---|
147 | |
---|
148 | bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) |
---|
149 | { |
---|
150 | DefaultUnresolvedAttribute o = other as DefaultUnresolvedAttribute; |
---|
151 | return o != null && attributeType == o.attributeType |
---|
152 | && ListEquals(constructorParameterTypes, o.constructorParameterTypes) |
---|
153 | && ListEquals(positionalArguments, o.positionalArguments) |
---|
154 | && ListEquals(namedArguments ?? EmptyList<KeyValuePair<IMemberReference, IConstantValue>>.Instance, |
---|
155 | o.namedArguments ?? EmptyList<KeyValuePair<IMemberReference, IConstantValue>>.Instance); |
---|
156 | } |
---|
157 | |
---|
158 | static bool ListEquals<T>(IList<T> list1, IList<T> list2) where T : class |
---|
159 | { |
---|
160 | if (list1 == null) |
---|
161 | list1 = EmptyList<T>.Instance; |
---|
162 | if (list2 == null) |
---|
163 | list2 = EmptyList<T>.Instance; |
---|
164 | if (list1 == list2) |
---|
165 | return true; |
---|
166 | if (list1.Count != list2.Count) |
---|
167 | return false; |
---|
168 | for (int i = 0; i < list1.Count; i++) { |
---|
169 | if (list1[i] != list2[i]) |
---|
170 | return false; |
---|
171 | } |
---|
172 | return true; |
---|
173 | } |
---|
174 | |
---|
175 | static bool ListEquals(IList<KeyValuePair<IMemberReference, IConstantValue>> list1, IList<KeyValuePair<IMemberReference, IConstantValue>> list2) |
---|
176 | { |
---|
177 | if (list1 == list2) |
---|
178 | return true; |
---|
179 | if (list1.Count != list2.Count) |
---|
180 | return false; |
---|
181 | for (int i = 0; i < list1.Count; i++) { |
---|
182 | var a = list1[i]; |
---|
183 | var b = list2[i]; |
---|
184 | if (!(a.Key == b.Key && a.Value == b.Value)) |
---|
185 | return false; |
---|
186 | } |
---|
187 | return true; |
---|
188 | } |
---|
189 | |
---|
190 | sealed class DefaultResolvedAttribute : IAttribute, ICompilationProvider |
---|
191 | { |
---|
192 | readonly DefaultUnresolvedAttribute unresolved; |
---|
193 | readonly ITypeResolveContext context; |
---|
194 | readonly IType attributeType; |
---|
195 | readonly IList<ResolveResult> positionalArguments; |
---|
196 | |
---|
197 | // cannot use ProjectedList because KeyValuePair is value type |
---|
198 | IList<KeyValuePair<IMember, ResolveResult>> namedArguments; |
---|
199 | |
---|
200 | IMethod constructor; |
---|
201 | volatile bool constructorResolved; |
---|
202 | |
---|
203 | public DefaultResolvedAttribute(DefaultUnresolvedAttribute unresolved, ITypeResolveContext context) |
---|
204 | { |
---|
205 | this.unresolved = unresolved; |
---|
206 | this.context = context; |
---|
207 | |
---|
208 | this.attributeType = unresolved.AttributeType.Resolve(context); |
---|
209 | this.positionalArguments = unresolved.PositionalArguments.Resolve(context); |
---|
210 | } |
---|
211 | |
---|
212 | public IType AttributeType { |
---|
213 | get { return attributeType; } |
---|
214 | } |
---|
215 | |
---|
216 | public DomRegion Region { |
---|
217 | get { return unresolved.Region; } |
---|
218 | } |
---|
219 | |
---|
220 | public IMethod Constructor { |
---|
221 | get { |
---|
222 | if (!constructorResolved) { |
---|
223 | constructor = ResolveConstructor(); |
---|
224 | constructorResolved = true; |
---|
225 | } |
---|
226 | return constructor; |
---|
227 | } |
---|
228 | } |
---|
229 | |
---|
230 | IMethod ResolveConstructor() |
---|
231 | { |
---|
232 | var parameterTypes = unresolved.ConstructorParameterTypes.Resolve(context); |
---|
233 | foreach (var ctor in attributeType.GetConstructors(m => m.Parameters.Count == parameterTypes.Count)) { |
---|
234 | bool ok = true; |
---|
235 | for (int i = 0; i < parameterTypes.Count; i++) { |
---|
236 | if (!ctor.Parameters[i].Type.Equals(parameterTypes[i])) { |
---|
237 | ok = false; |
---|
238 | break; |
---|
239 | } |
---|
240 | } |
---|
241 | if (ok) |
---|
242 | return ctor; |
---|
243 | } |
---|
244 | return null; |
---|
245 | } |
---|
246 | |
---|
247 | public IList<ResolveResult> PositionalArguments { |
---|
248 | get { return positionalArguments; } |
---|
249 | } |
---|
250 | |
---|
251 | public IList<KeyValuePair<IMember, ResolveResult>> NamedArguments { |
---|
252 | get { |
---|
253 | var namedArgs = LazyInit.VolatileRead(ref this.namedArguments); |
---|
254 | if (namedArgs != null) { |
---|
255 | return namedArgs; |
---|
256 | } else { |
---|
257 | namedArgs = new List<KeyValuePair<IMember, ResolveResult>>(); |
---|
258 | foreach (var pair in unresolved.NamedArguments) { |
---|
259 | IMember member = pair.Key.Resolve(context); |
---|
260 | if (member != null) { |
---|
261 | ResolveResult val = pair.Value.Resolve(context); |
---|
262 | namedArgs.Add(new KeyValuePair<IMember, ResolveResult>(member, val)); |
---|
263 | } |
---|
264 | } |
---|
265 | return LazyInit.GetOrSet(ref this.namedArguments, namedArgs); |
---|
266 | } |
---|
267 | } |
---|
268 | } |
---|
269 | |
---|
270 | public ICompilation Compilation { |
---|
271 | get { return context.Compilation; } |
---|
272 | } |
---|
273 | |
---|
274 | public override string ToString() |
---|
275 | { |
---|
276 | if (positionalArguments.Count == 0) |
---|
277 | return "[" + attributeType.ToString() + "]"; |
---|
278 | else |
---|
279 | return "[" + attributeType.ToString() + "(...)]"; |
---|
280 | } |
---|
281 | } |
---|
282 | } |
---|
283 | } |
---|