1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
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:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
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.
20
using System.Collections.Generic;
21
using System.Diagnostics;
24
using System.Threading;
25
using ICSharpCode.NRefactory.Utils;
27
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
30
/// Represents a specialized IMethod (e.g. after type substitution).
32
public class SpecializedMethod : SpecializedParameterizedMember, IMethod
34
readonly IMethod methodDefinition;
35
readonly ITypeParameter[] specializedTypeParameters;
36
readonly bool isParameterized;
37
readonly TypeParameterSubstitution substitutionWithoutSpecializedTypeParameters;
39
public SpecializedMethod(IMethod methodDefinition, TypeParameterSubstitution substitution)
40
: base(methodDefinition)
42
if (substitution == null)
43
throw new ArgumentNullException("substitution");
44
this.methodDefinition = methodDefinition;
45
this.isParameterized = substitution.MethodTypeArguments != null;
46
if (methodDefinition.TypeParameters.Count > 0) {
47
// The method is generic, so we need to specialize the type parameters
48
// (for specializing the constraints, and also to set the correct Owner)
49
specializedTypeParameters = new ITypeParameter[methodDefinition.TypeParameters.Count];
50
for (int i = 0; i < specializedTypeParameters.Length; i++) {
51
specializedTypeParameters[i] = new SpecializedTypeParameter(methodDefinition.TypeParameters[i], this);
53
if (!isParameterized) {
54
// Add substitution that replaces the base method's type parameters with our specialized version
55
// but do this only if the type parameters on the baseMember have not already been substituted
56
substitutionWithoutSpecializedTypeParameters = this.Substitution;
57
AddSubstitution(new TypeParameterSubstitution(null, specializedTypeParameters));
60
// Add the main substitution after the method type parameter specialization.
61
AddSubstitution(substitution);
62
if (substitutionWithoutSpecializedTypeParameters != null) {
63
// If we already have a substitution without specialized type parameters, update that:
64
substitutionWithoutSpecializedTypeParameters = TypeParameterSubstitution.Compose(substitution, substitutionWithoutSpecializedTypeParameters);
66
// Otherwise just use the whole substitution, as that doesn't contain specialized type parameters
68
substitutionWithoutSpecializedTypeParameters = this.Substitution;
70
if (specializedTypeParameters != null) {
71
// Set the substitution on the type parameters to the final composed substitution
72
foreach (var tp in specializedTypeParameters.OfType<SpecializedTypeParameter>()) {
74
tp.substitution = base.Substitution;
79
public IList<IType> TypeArguments {
80
get { return this.Substitution.MethodTypeArguments ?? EmptyList<IType>.Instance; }
83
public bool IsParameterized {
84
get { return isParameterized; }
87
public IList<IUnresolvedMethod> Parts {
88
get { return methodDefinition.Parts; }
91
public IList<IAttribute> ReturnTypeAttributes {
92
get { return methodDefinition.ReturnTypeAttributes; }
95
public IList<ITypeParameter> TypeParameters {
97
return specializedTypeParameters ?? methodDefinition.TypeParameters;
101
public bool IsExtensionMethod {
102
get { return methodDefinition.IsExtensionMethod; }
105
public bool IsConstructor {
106
get { return methodDefinition.IsConstructor; }
109
public bool IsDestructor {
110
get { return methodDefinition.IsDestructor; }
113
public bool IsOperator {
114
get { return methodDefinition.IsOperator; }
117
public bool IsPartial {
118
get { return methodDefinition.IsPartial; }
121
public bool IsAsync {
122
get { return methodDefinition.IsAsync; }
125
public bool HasBody {
126
get { return methodDefinition.HasBody; }
129
public bool IsAccessor {
130
get { return methodDefinition.IsAccessor; }
133
public IMethod ReducedFrom {
137
IMember accessorOwner;
139
public IMember AccessorOwner {
141
var result = LazyInit.VolatileRead(ref accessorOwner);
142
if (result != null) {
145
var ownerDefinition = methodDefinition.AccessorOwner;
146
if (ownerDefinition == null)
148
result = ownerDefinition.Specialize(this.Substitution);
149
return LazyInit.GetOrSet(ref accessorOwner, result);
153
accessorOwner = value;
157
public override IMemberReference ToMemberReference()
159
// Pass the MethodTypeArguments to the SpecializingMemberReference only if
160
// the generic method itself is parameterized, not if the generic method is only
161
// specialized with class type arguments.
163
// This is necessary due to this part of the ToMemberReference() contract:
164
// If this member is specialized using open generic types, the resulting member reference will need to be looked up in an appropriate generic context.
165
// Otherwise, the main resolve context of a compilation is sufficient.
167
// This means that if the method itself isn't specialized,
168
// we must not include TypeParameterReferences for the specialized type parameters
169
// in the resulting member reference.
170
if (isParameterized) {
171
return new SpecializingMemberReference(
172
baseMember.ToMemberReference(),
173
ToTypeReference(base.Substitution.ClassTypeArguments),
174
ToTypeReference(base.Substitution.MethodTypeArguments));
176
return base.ToMemberReference();
180
public override bool Equals(object obj)
182
SpecializedMethod other = obj as SpecializedMethod;
185
return this.baseMember.Equals(other.baseMember) && this.substitutionWithoutSpecializedTypeParameters.Equals(other.substitutionWithoutSpecializedTypeParameters);
188
public override int GetHashCode()
191
return 1000000013 * baseMember.GetHashCode() + 1000000009 * substitutionWithoutSpecializedTypeParameters.GetHashCode();
195
public override IMember Specialize(TypeParameterSubstitution newSubstitution)
197
return methodDefinition.Specialize(TypeParameterSubstitution.Compose(newSubstitution, substitutionWithoutSpecializedTypeParameters));
200
IMethod IMethod.Specialize(TypeParameterSubstitution newSubstitution)
202
return methodDefinition.Specialize(TypeParameterSubstitution.Compose(newSubstitution, substitutionWithoutSpecializedTypeParameters));
205
public override string ToString()
207
StringBuilder b = new StringBuilder("[");
208
b.Append(GetType().Name);
210
b.Append(this.DeclaringType.ReflectionName);
213
if (this.TypeArguments.Count > 0) {
215
for (int i = 0; i < this.TypeArguments.Count; i++) {
216
if (i > 0) b.Append(", ");
217
b.Append(this.TypeArguments[i].ReflectionName);
220
} else if (this.TypeParameters.Count > 0) {
222
b.Append(this.TypeParameters.Count);
225
for (int i = 0; i < this.Parameters.Count; i++) {
226
if (i > 0) b.Append(", ");
227
b.Append(this.Parameters[i].ToString());
230
b.Append(this.ReturnType.ReflectionName);
235
sealed class SpecializedTypeParameter : AbstractTypeParameter
237
readonly ITypeParameter baseTp;
239
// The substition is set at the end of SpecializedMethod constructor
240
internal TypeVisitor substitution;
242
public SpecializedTypeParameter(ITypeParameter baseTp, IMethod specializedOwner)
243
: base(specializedOwner, baseTp.Index, baseTp.Name, baseTp.Variance, baseTp.Attributes, baseTp.Region)
245
// We don't have to consider already-specialized baseTps because
246
// we read the baseTp directly from the unpacked memberDefinition.
247
this.baseTp = baseTp;
250
public override int GetHashCode()
252
return baseTp.GetHashCode() ^ this.Owner.GetHashCode();
255
public override bool Equals(IType other)
257
// Compare the owner, not the substitution, because the substitution may contain this specialized type parameter recursively
258
SpecializedTypeParameter o = other as SpecializedTypeParameter;
259
return o != null && baseTp.Equals(o.baseTp) && this.Owner.Equals(o.Owner);
262
public override bool HasValueTypeConstraint {
263
get { return baseTp.HasValueTypeConstraint; }
266
public override bool HasReferenceTypeConstraint {
267
get { return baseTp.HasReferenceTypeConstraint; }
270
public override bool HasDefaultConstructorConstraint {
271
get { return baseTp.HasDefaultConstructorConstraint; }
274
public override IEnumerable<IType> DirectBaseTypes {
276
return baseTp.DirectBaseTypes.Select(t => t.AcceptVisitor(substitution));