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); } } }