mirror of https://github.com/icsharpcode/ILSpy.git
8 changed files with 333 additions and 36 deletions
@ -0,0 +1,228 @@ |
|||||||
|
// Copyright (c) 2018 Daniel Grunwald
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.Linq; |
||||||
|
using System.Reflection; |
||||||
|
using System.Reflection.Metadata; |
||||||
|
using System.Reflection.Metadata.Ecma335; |
||||||
|
using System.Runtime.CompilerServices; |
||||||
|
using System.Runtime.InteropServices; |
||||||
|
using ICSharpCode.Decompiler.Semantics; |
||||||
|
using ICSharpCode.Decompiler.Util; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.TypeSystem.Implementation |
||||||
|
{ |
||||||
|
sealed class MetadataProperty : IProperty |
||||||
|
{ |
||||||
|
const Accessibility InvalidAccessibility = (Accessibility)0xff; |
||||||
|
|
||||||
|
readonly MetadataAssembly assembly; |
||||||
|
readonly PropertyDefinitionHandle propertyHandle; |
||||||
|
readonly MethodDefinitionHandle getterHandle; |
||||||
|
readonly MethodDefinitionHandle setterHandle; |
||||||
|
|
||||||
|
// lazy-loaded:
|
||||||
|
string name; |
||||||
|
IAttribute[] customAttributes; |
||||||
|
volatile Accessibility cachedAccessiblity = InvalidAccessibility; |
||||||
|
IParameter[] parameters; |
||||||
|
IType returnType; |
||||||
|
|
||||||
|
internal MetadataProperty(MetadataAssembly assembly, PropertyDefinitionHandle handle) |
||||||
|
{ |
||||||
|
Debug.Assert(assembly != null); |
||||||
|
Debug.Assert(!handle.IsNil); |
||||||
|
this.assembly = assembly; |
||||||
|
this.propertyHandle = handle; |
||||||
|
|
||||||
|
var metadata = assembly.metadata; |
||||||
|
var prop = metadata.GetPropertyDefinition(handle); |
||||||
|
var accessors = prop.GetAccessors(); |
||||||
|
getterHandle = accessors.Getter; |
||||||
|
setterHandle = accessors.Setter; |
||||||
|
} |
||||||
|
|
||||||
|
public EntityHandle MetadataToken => propertyHandle; |
||||||
|
|
||||||
|
public string Name { |
||||||
|
get { |
||||||
|
string name = LazyInit.VolatileRead(ref this.name); |
||||||
|
if (name != null) |
||||||
|
return name; |
||||||
|
var metadata = assembly.metadata; |
||||||
|
var propertyDef = metadata.GetPropertyDefinition(propertyHandle); |
||||||
|
return LazyInit.GetOrSet(ref this.name, metadata.GetString(propertyDef.Name)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public bool CanGet => !getterHandle.IsNil; |
||||||
|
public bool CanSet => !setterHandle.IsNil; |
||||||
|
|
||||||
|
public IMethod Getter => assembly.GetDefinition(getterHandle); |
||||||
|
public IMethod Setter => assembly.GetDefinition(setterHandle); |
||||||
|
|
||||||
|
public bool IsIndexer => SymbolKind == SymbolKind.Indexer; |
||||||
|
public SymbolKind SymbolKind => throw new NotImplementedException(); |
||||||
|
|
||||||
|
#region Signature (ReturnType + Parameters)
|
||||||
|
public IReadOnlyList<IParameter> Parameters { |
||||||
|
get { |
||||||
|
var parameters = LazyInit.VolatileRead(ref this.parameters); |
||||||
|
if (parameters != null) |
||||||
|
return parameters; |
||||||
|
DecodeSignature(); |
||||||
|
return this.parameters; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public IType ReturnType { |
||||||
|
get { |
||||||
|
var returnType = LazyInit.VolatileRead(ref this.returnType); |
||||||
|
if (returnType != null) |
||||||
|
return returnType; |
||||||
|
DecodeSignature(); |
||||||
|
return this.returnType; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void DecodeSignature() |
||||||
|
{ |
||||||
|
var propertyDef = assembly.metadata.GetPropertyDefinition(propertyHandle); |
||||||
|
var genericContext = new GenericContext(DeclaringType.TypeParameters); |
||||||
|
var signature = propertyDef.DecodeSignature(assembly.TypeProvider, genericContext); |
||||||
|
ParameterHandleCollection? parameterHandles; |
||||||
|
if (!getterHandle.IsNil) |
||||||
|
parameterHandles = assembly.metadata.GetMethodDefinition(getterHandle).GetParameters(); |
||||||
|
else if (!setterHandle.IsNil) |
||||||
|
parameterHandles = assembly.metadata.GetMethodDefinition(setterHandle).GetParameters(); |
||||||
|
else |
||||||
|
parameterHandles = null; |
||||||
|
var (returnType, parameters) = MetadataMethod.DecodeSignature(assembly, this, signature, parameterHandles); |
||||||
|
LazyInit.GetOrSet(ref this.returnType, returnType); |
||||||
|
LazyInit.GetOrSet(ref this.parameters, parameters); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
public IReadOnlyList<IMember> ImplementedInterfaceMembers => throw new NotImplementedException(); |
||||||
|
|
||||||
|
public bool IsExplicitInterfaceImplementation => throw new NotImplementedException(); |
||||||
|
|
||||||
|
public ITypeDefinition DeclaringTypeDefinition => (Getter ?? Setter)?.DeclaringTypeDefinition; |
||||||
|
public IType DeclaringType => (Getter ?? Setter)?.DeclaringType; |
||||||
|
IMember IMember.MemberDefinition => this; |
||||||
|
TypeParameterSubstitution IMember.Substitution => TypeParameterSubstitution.Identity; |
||||||
|
|
||||||
|
#region Attributes
|
||||||
|
public IReadOnlyList<IAttribute> Attributes { |
||||||
|
get { |
||||||
|
var attr = LazyInit.VolatileRead(ref this.customAttributes); |
||||||
|
if (attr != null) |
||||||
|
return attr; |
||||||
|
return LazyInit.GetOrSet(ref this.customAttributes, DecodeAttributes()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
IAttribute[] DecodeAttributes() |
||||||
|
{ |
||||||
|
var b = new AttributeListBuilder(assembly); |
||||||
|
var metadata = assembly.metadata; |
||||||
|
var propertyDef = metadata.GetPropertyDefinition(propertyHandle); |
||||||
|
b.Add(propertyDef.GetCustomAttributes()); |
||||||
|
return b.Build(); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Accessibility
|
||||||
|
public Accessibility Accessibility { |
||||||
|
get { |
||||||
|
var acc = cachedAccessiblity; |
||||||
|
if (acc == InvalidAccessibility) |
||||||
|
return cachedAccessiblity = ComputeAccessibility(); |
||||||
|
else |
||||||
|
return acc; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Accessibility ComputeAccessibility() |
||||||
|
{ |
||||||
|
if (IsOverride && (getterHandle.IsNil || setterHandle.IsNil)) { |
||||||
|
foreach (var baseMember in InheritanceHelper.GetBaseMembers(this, includeImplementedInterfaces: false)) { |
||||||
|
if (!baseMember.IsOverride) |
||||||
|
return baseMember.Accessibility; |
||||||
|
} |
||||||
|
} |
||||||
|
return MergePropertyAccessibility( |
||||||
|
this.Getter?.Accessibility ?? Accessibility.None, |
||||||
|
this.Setter?.Accessibility ?? Accessibility.None); |
||||||
|
} |
||||||
|
|
||||||
|
static internal Accessibility MergePropertyAccessibility(Accessibility left, Accessibility right) |
||||||
|
{ |
||||||
|
if (left == Accessibility.Public || right == Accessibility.Public) |
||||||
|
return Accessibility.Public; |
||||||
|
|
||||||
|
if (left == Accessibility.ProtectedOrInternal || right == Accessibility.ProtectedOrInternal) |
||||||
|
return Accessibility.ProtectedOrInternal; |
||||||
|
|
||||||
|
if (left == Accessibility.Protected && right == Accessibility.Internal || |
||||||
|
left == Accessibility.Internal && right == Accessibility.Protected) |
||||||
|
return Accessibility.ProtectedOrInternal; |
||||||
|
|
||||||
|
if (left == Accessibility.Protected || right == Accessibility.Protected) |
||||||
|
return Accessibility.Protected; |
||||||
|
|
||||||
|
if (left == Accessibility.Internal || right == Accessibility.Internal) |
||||||
|
return Accessibility.Internal; |
||||||
|
|
||||||
|
if (left == Accessibility.ProtectedAndInternal || right == Accessibility.ProtectedAndInternal) |
||||||
|
return Accessibility.ProtectedAndInternal; |
||||||
|
|
||||||
|
return left; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
public bool IsStatic => (Getter ?? Setter)?.IsStatic ?? false; |
||||||
|
public bool IsAbstract => (Getter ?? Setter)?.IsAbstract ?? false; |
||||||
|
public bool IsSealed => (Getter ?? Setter)?.IsSealed ?? false; |
||||||
|
public bool IsVirtual => (Getter ?? Setter)?.IsVirtual ?? false; |
||||||
|
public bool IsOverride => (Getter ?? Setter)?.IsOverride ?? false; |
||||||
|
public bool IsOverridable => (Getter ?? Setter)?.IsOverridable ?? false; |
||||||
|
|
||||||
|
bool IEntity.IsShadowing => (Getter ?? Setter)?.IsShadowing ?? false; |
||||||
|
|
||||||
|
public IAssembly ParentAssembly => assembly; |
||||||
|
public ICompilation Compilation => assembly.Compilation; |
||||||
|
|
||||||
|
public string FullName => $"{DeclaringType?.FullName}.{Name}"; |
||||||
|
public string ReflectionName => $"{DeclaringType?.ReflectionName}.{Name}"; |
||||||
|
public string Namespace => DeclaringType?.Namespace ?? string.Empty; |
||||||
|
|
||||||
|
bool IMember.Equals(IMember obj, TypeVisitor typeNormalization) |
||||||
|
{ |
||||||
|
return this == obj; |
||||||
|
} |
||||||
|
|
||||||
|
public IMember Specialize(TypeParameterSubstitution substitution) |
||||||
|
{ |
||||||
|
return SpecializedProperty.Create(this, substitution); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,51 @@ |
|||||||
|
// Copyright (c) 2018 Daniel Grunwald
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Diagnostics; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.TypeSystem.Implementation |
||||||
|
{ |
||||||
|
sealed class SpecializedParameter : IParameter |
||||||
|
{ |
||||||
|
readonly IParameter baseParameter; |
||||||
|
readonly IType newType; |
||||||
|
readonly IParameterizedMember newOwner; |
||||||
|
|
||||||
|
public SpecializedParameter(IParameter baseParameter, IType newType, IParameterizedMember newOwner) |
||||||
|
{ |
||||||
|
Debug.Assert(baseParameter != null && newType != null); |
||||||
|
this.baseParameter = baseParameter; |
||||||
|
this.newType = newType; |
||||||
|
this.newOwner = newOwner; |
||||||
|
} |
||||||
|
|
||||||
|
IReadOnlyList<IAttribute> IParameter.Attributes => baseParameter.Attributes; |
||||||
|
bool IParameter.IsRef => baseParameter.IsRef; |
||||||
|
bool IParameter.IsOut => baseParameter.IsOptional; |
||||||
|
bool IParameter.IsParams => baseParameter.IsParams; |
||||||
|
bool IParameter.IsOptional => baseParameter.IsOptional; |
||||||
|
IParameterizedMember IParameter.Owner => newOwner; |
||||||
|
string IVariable.Name => baseParameter.Name; |
||||||
|
string ISymbol.Name => baseParameter.Name; |
||||||
|
IType IVariable.Type => newType; |
||||||
|
bool IVariable.IsConst => baseParameter.IsConst; |
||||||
|
object IVariable.ConstantValue => baseParameter.ConstantValue; |
||||||
|
SymbolKind ISymbol.SymbolKind => SymbolKind.Parameter; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue