using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Populators; using Semmle.Util; using System.Linq; using Microsoft.CodeAnalysis.CSharp; using Semmle.Extraction.Entities; namespace Semmle.Extraction.CSharp.Entities { public class Constructor : Method { Constructor(Context cx, IMethodSymbol init) : base(cx, init) { } public override void Populate() { PopulateMethod(); ExtractModifiers(); ContainingType.ExtractGenerics(); Context.Emit(Tuples.constructors(this, symbol.ContainingType.Name, ContainingType, (Constructor)OriginalDefinition)); Context.Emit(Tuples.constructor_location(this, Location)); if (symbol.IsImplicitlyDeclared) { var lineCounts = new LineCounts() { Total = 2, Code = 1, Comment = 0 }; Context.Emit(Tuples.numlines(this, lineCounts)); } ExtractCompilerGenerated(); } protected override void ExtractInitializers() { // Do not extract initializers for constructed types. if (!IsSourceDeclaration) return; var syntax = Syntax; var initializer = syntax == null ? null : syntax.Initializer; if (initializer == null) return; Type initializerType; var symbolInfo = Context.GetSymbolInfo(initializer); switch (initializer.Kind()) { case SyntaxKind.BaseConstructorInitializer: initializerType = Type.Create(Context, symbol.ContainingType.BaseType); break; case SyntaxKind.ThisConstructorInitializer: initializerType = ContainingType; break; default: Context.ModelError(initializer, "Unknown initializer"); return; } var initInfo = new ExpressionInfo(Context, initializerType, Context.Create(initializer.ThisOrBaseKeyword.GetLocation()), Kinds.ExprKind.CONSTRUCTOR_INIT, this, -1, false, null); var init = new Expression(initInfo); var target = Constructor.Create(Context, (IMethodSymbol)symbolInfo.Symbol); if (target == null) { Context.ModelError(symbol, "Unable to resolve call"); return; } Context.Emit(Tuples.expr_call(init, target)); int child = 0; foreach (var arg in initializer.ArgumentList.Arguments) { Expression.Create(Context, arg.Expression, init, child++); } } ConstructorDeclarationSyntax Syntax { get { return symbol.DeclaringSyntaxReferences. Select(r => r.GetSyntax()). OfType(). FirstOrDefault(); } } public new static Constructor Create(Context cx, IMethodSymbol constructor) { if (constructor == null) return null; switch (constructor.MethodKind) { case MethodKind.StaticConstructor: case MethodKind.Constructor: return ConstructorFactory.Instance.CreateEntity(cx, constructor); default: throw new InternalError(constructor, "Attempt to create a Constructor from a symbol that isn't a constructor"); } } public override IId Id { get { return new Key(tb => { if (symbol.IsStatic) tb.Append("static"); tb.Append(ContainingType); AddParametersToId(Context, tb, symbol); tb.Append(";constructor"); }); } } ConstructorDeclarationSyntax GetSyntax() => symbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax()).OfType().FirstOrDefault(); public override Microsoft.CodeAnalysis.Location FullLocation => ReportingLocation; public override Microsoft.CodeAnalysis.Location ReportingLocation { get { var syn = GetSyntax(); if (syn != null) { return syn.Identifier.GetLocation(); } else if (symbol.IsImplicitlyDeclared) { return ContainingType.ReportingLocation; } else { return symbol.ContainingType.Locations.FirstOrDefault(); } } } class ConstructorFactory : ICachedEntityFactory { public static readonly ConstructorFactory Instance = new ConstructorFactory(); public Constructor Create(Context cx, IMethodSymbol init) => new Constructor(cx, init); } } }