.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

199 lines
6.6 KiB

// Copyright (c) 2018 Siegfried Pammer
//
// 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.ComponentModel.Composition;
using System.Linq;
using System.Reflection.Metadata;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.ILSpyX.Analyzers.Builtin
{
[ExportAnalyzer(Header = "Applied To", Order = 10)]
[PartCreationPolicy(CreationPolicy.Shared)]
class AttributeAppliedToAnalyzer : IAnalyzer
{
public IEnumerable<ISymbol> Analyze(ISymbol analyzedSymbol, AnalyzerContext context)
{
if (!(analyzedSymbol is ITypeDefinition attributeType))
return Empty<ISymbol>.Array;
var scope = context.GetScopeOf(attributeType);
// TODO: DeclSecurity attributes are not supported.
if (!IsBuiltinAttribute(attributeType, out var knownAttribute))
{
return HandleCustomAttribute(attributeType, scope, context.CancellationToken).Distinct();
}
else
{
return HandleBuiltinAttribute(knownAttribute, scope, context.CancellationToken).SelectMany(s => s);
}
}
bool IsBuiltinAttribute(ITypeDefinition attributeType, out KnownAttribute knownAttribute)
{
knownAttribute = attributeType.IsBuiltinAttribute();
return !knownAttribute.IsCustomAttribute();
}
IEnumerable<IEnumerable<ISymbol>> HandleBuiltinAttribute(KnownAttribute attribute, AnalyzerScope scope, CancellationToken ct)
{
IEnumerable<ISymbol> ScanTypes(DecompilerTypeSystem ts)
{
return ts.MainModule.TypeDefinitions
.Where(t => t.HasAttribute(attribute));
}
IEnumerable<ISymbol> ScanMethods(DecompilerTypeSystem ts)
{
return ts.MainModule.TypeDefinitions
.SelectMany(t => t.Members.OfType<IMethod>())
.Where(m => m.HasAttribute(attribute))
.Select(m => m.AccessorOwner ?? m);
}
IEnumerable<ISymbol> ScanFields(DecompilerTypeSystem ts)
{
return ts.MainModule.TypeDefinitions
.SelectMany(t => t.Fields)
.Where(f => f.HasAttribute(attribute));
}
IEnumerable<ISymbol> ScanProperties(DecompilerTypeSystem ts)
{
return ts.MainModule.TypeDefinitions
.SelectMany(t => t.Properties)
.Where(p => p.HasAttribute(attribute));
}
IEnumerable<ISymbol> ScanParameters(DecompilerTypeSystem ts)
{
return ts.MainModule.TypeDefinitions
.SelectMany(t => t.Members.OfType<IMethod>())
.Where(m => m.Parameters.Any(p => p.HasAttribute(attribute)))
.Select(m => m.AccessorOwner ?? m);
}
foreach (Decompiler.Metadata.PEFile module in scope.GetModulesInScope(ct))
{
var ts = scope.ConstructTypeSystem(module);
ct.ThrowIfCancellationRequested();
switch (attribute)
{
case KnownAttribute.Serializable:
case KnownAttribute.ComImport:
case KnownAttribute.StructLayout:
yield return ScanTypes(ts);
break;
case KnownAttribute.DllImport:
case KnownAttribute.PreserveSig:
case KnownAttribute.MethodImpl:
yield return ScanMethods(ts);
break;
case KnownAttribute.FieldOffset:
case KnownAttribute.NonSerialized:
yield return ScanFields(ts);
break;
case KnownAttribute.MarshalAs:
yield return ScanFields(ts);
yield return ScanParameters(ts);
goto case KnownAttribute.Out;
case KnownAttribute.Optional:
case KnownAttribute.In:
case KnownAttribute.Out:
yield return ScanParameters(ts);
break;
case KnownAttribute.IndexerName:
yield return ScanProperties(ts);
break;
}
}
}
IEnumerable<ISymbol> HandleCustomAttribute(ITypeDefinition attributeType, AnalyzerScope scope, CancellationToken ct)
{
var genericContext = new Decompiler.TypeSystem.GenericContext(); // type arguments do not matter for this analyzer.
foreach (var module in scope.GetModulesInScope(ct))
{
var ts = scope.ConstructTypeSystem(module);
ct.ThrowIfCancellationRequested();
var decoder = new FindTypeDecoder(ts.MainModule, attributeType);
var referencedParameters = new HashSet<ParameterHandle>();
foreach (var h in module.Metadata.CustomAttributes)
{
var customAttribute = module.Metadata.GetCustomAttribute(h);
if (IsCustomAttributeOfType(customAttribute.Constructor, module.Metadata, decoder))
{
if (customAttribute.Parent.Kind == HandleKind.Parameter)
{
referencedParameters.Add((ParameterHandle)customAttribute.Parent);
}
else
{
var parent = AnalyzerHelpers.GetParentEntity(ts, customAttribute);
if (parent != null)
yield return parent;
}
}
}
if (referencedParameters.Count > 0)
{
foreach (var h in module.Metadata.MethodDefinitions)
{
var md = module.Metadata.GetMethodDefinition(h);
foreach (var p in md.GetParameters())
{
if (referencedParameters.Contains(p))
{
var method = ts.MainModule.ResolveMethod(h, genericContext);
if (method != null)
{
if (method.IsAccessor)
yield return method.AccessorOwner;
else
yield return method;
}
break;
}
}
}
}
}
}
internal static bool IsCustomAttributeOfType(EntityHandle customAttributeCtor, MetadataReader metadata, FindTypeDecoder decoder)
{
var declaringAttributeType = customAttributeCtor.GetDeclaringType(metadata);
return decoder.GetTypeFromEntity(metadata, declaringAttributeType);
}
public bool Show(ISymbol symbol)
{
return symbol is ITypeDefinition type && type.GetNonInterfaceBaseTypes()
.Any(t => t.IsKnownType(KnownTypeCode.Attribute));
}
}
}