using System; using System.IO; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Entities.Expressions; using Semmle.Extraction.Kinds; using Semmle.Extraction.CSharp.Util; namespace Semmle.Extraction.CSharp.Entities { internal class Property : CachedSymbol, IExpressionParentEntity { protected Property(Context cx, IPropertySymbol init) : base(cx, init) { type = new Lazy(() => Type.Create(base.Context, Symbol.Type)); } private readonly Lazy type; private Type Type => type.Value; protected override IPropertySymbol BodyDeclaringSymbol => Symbol.PartialImplementationPart ?? Symbol; public override Microsoft.CodeAnalysis.Location? ReportingLocation => BodyDeclaringSymbol.Locations.BestOrDefault(); public override void WriteId(EscapingTextWriter trapFile) { trapFile.WriteSubId(Type); trapFile.Write(" "); trapFile.WriteSubId(ContainingType!); trapFile.Write('.'); Method.AddExplicitInterfaceQualifierToId(Context, trapFile, Symbol.ExplicitInterfaceImplementations); trapFile.Write(Symbol.Name); trapFile.Write(";property"); } public override void Populate(TextWriter trapFile) { PopulateAttributes(); PopulateModifiers(trapFile); BindComments(); PopulateNullability(trapFile, Symbol.GetAnnotatedType()); PopulateRefKind(trapFile, Symbol.RefKind); var type = Type; trapFile.properties(this, Symbol.GetName(), ContainingType!, type.TypeRef, Create(Context, Symbol.OriginalDefinition)); var getter = BodyDeclaringSymbol.GetMethod; var setter = BodyDeclaringSymbol.SetMethod; if (getter is not null) Method.Create(Context, getter); if (setter is not null) Method.Create(Context, setter); var declSyntaxReferences = IsSourceDeclaration ? Symbol.DeclaringSyntaxReferences. Select(d => d.GetSyntax()).OfType().ToArray() : Enumerable.Empty(); foreach (var explicitInterface in Symbol.ExplicitInterfaceImplementations.Select(impl => Type.Create(Context, impl.ContainingType))) { trapFile.explicitly_implements(this, explicitInterface.TypeRef); foreach (var syntax in declSyntaxReferences) TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier!.Name, this, explicitInterface); } if (Context.ExtractLocation(Symbol)) { WriteLocationsToTrap(trapFile.property_location, this, Locations); } if (IsSourceDeclaration && Symbol.FromSource()) { var expressionBody = ExpressionBody; if (expressionBody is not null) { Context.PopulateLater(() => Expression.Create(Context, expressionBody, this, 0)); } var child = 1; foreach (var initializer in declSyntaxReferences .Select(n => n.Initializer) .Where(i => i is not null)) { Context.PopulateLater(() => { var loc = Context.CreateLocation(initializer!.GetLocation()); var annotatedType = AnnotatedTypeSymbol.CreateNotAnnotated(Symbol.Type); var simpleAssignExpr = new Expression(new ExpressionInfo(Context, annotatedType, loc, ExprKind.SIMPLE_ASSIGN, this, child++, isCompilerGenerated: true, null)); Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer.Value, simpleAssignExpr, 0)); var access = new Expression(new ExpressionInfo(Context, annotatedType, Location, ExprKind.PROPERTY_ACCESS, simpleAssignExpr, 1, isCompilerGenerated: true, null)); trapFile.expr_access(access, this); if (!Symbol.IsStatic) { This.CreateImplicit(Context, Symbol.ContainingType, Location, access, -1); } }); } foreach (var syntax in declSyntaxReferences) TypeMention.Create(Context, syntax.Type, this, type); } } public override Microsoft.CodeAnalysis.Location FullLocation { get { return Symbol.DeclaringSyntaxReferences .Select(r => r.GetSyntax()) .OfType() .Select(s => s.GetLocation()) .Concat(Symbol.Locations) .Best(); } } bool IExpressionParentEntity.IsTopLevelParent => true; public static Property Create(Context cx, IPropertySymbol prop) { var isIndexer = prop.IsIndexer || prop.Parameters.Any(); return isIndexer ? Indexer.Create(cx, prop) : PropertyFactory.Instance.CreateEntityFromSymbol(cx, prop); } private class PropertyFactory : CachedEntityFactory { public static PropertyFactory Instance { get; } = new PropertyFactory(); public override Property Create(Context cx, IPropertySymbol init) => new Property(cx, init); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.PushesLabel; } }