using Microsoft.CodeAnalysis;
using System.Linq;
namespace Semmle.Extraction.CSharp.Entities
{
class Accessor : Method
{
protected Accessor(Context cx, IMethodSymbol init)
: base(cx, init) { }
///
/// Gets the property symbol associated with this accessor.
///
IPropertySymbol PropertySymbol
{
get
{
// Usually, the property/indexer can be fetched from the associated symbol
var prop = symbol.AssociatedSymbol as IPropertySymbol;
if (prop != null)
return prop;
// But for properties/indexers that implement explicit interfaces, Roslyn
// does not properly populate `AssociatedSymbol`
var props = symbol.ContainingType.GetMembers().OfType();
props = props.Where(p => symbol.Equals(p.GetMethod) || symbol.Equals(p.SetMethod));
return props.SingleOrDefault();
}
}
public new Accessor OriginalDefinition => Create(Context, symbol.OriginalDefinition);
public override void Populate()
{
PopulateMethod();
ExtractModifiers();
ContainingType.ExtractGenerics();
var prop = PropertySymbol;
if (prop == null)
{
Context.ModelError(symbol, "Unhandled accessor associated symbol");
return;
}
var parent = Property.Create(Context, prop);
int kind;
Accessor unboundAccessor;
if (symbol.Equals(prop.GetMethod))
{
kind = 1;
unboundAccessor = Create(Context, prop.OriginalDefinition.GetMethod);
}
else if (symbol.Equals(prop.SetMethod))
{
kind = 2;
unboundAccessor = Create(Context, prop.OriginalDefinition.SetMethod);
}
else
{
Context.ModelError(symbol, "Unhandled accessor kind");
return;
}
Context.Emit(Tuples.accessors(this, kind, symbol.Name, parent, unboundAccessor));
foreach (var l in Locations)
Context.Emit(Tuples.accessor_location(this, l));
Overrides();
if (symbol.FromSource() && Block == null)
{
Context.Emit(Tuples.compiler_generated(this));
}
}
public new static Accessor Create(Context cx, IMethodSymbol symbol) =>
AccessorFactory.Instance.CreateEntity(cx, symbol);
class AccessorFactory : ICachedEntityFactory
{
public static readonly AccessorFactory Instance = new AccessorFactory();
public Accessor Create(Context cx, IMethodSymbol init) => new Accessor(cx, init);
}
}
}