public void ChainingToConstructorImplementedAsInlineCodeFromUnnamedConstructorWprks() { AssertCorrect( @"class C { static int P { get; set; } public void M() {} [System.Runtime.CompilerServices.CompilerGenerated] public C() : this(P = 42, ""X"") { M(); } public C(int x, string s) { } }", @"function() { {sm_C}.set_P(42); $ShallowCopy(_(42)._('X'), this); this.M(); }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.InlineCode("_({x})._({s})") }); }
public void ChainingToInlineCodeConstructorInNonExpandedFormUsesNonExpandedPattern() { AssertCorrect( @"class C { public static int[] a = null; public C(params int[] args) {} [System.Runtime.CompilerServices.CompilerGenerated] public C() : this(a) { } }", @"function() { $ShallowCopy(_2({sm_C}.$a), this); }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 1 ? ConstructorScriptSemantics.InlineCode("_({*args})", nonExpandedFormLiteralCode: "_2({args})") : ConstructorScriptSemantics.Unnamed() }); }
public void ConstructorChainingWithReorderedAndDefaultArgumentsWorks() { AssertCorrect( @"class C { public void M() {} static int F1() { return 0; } static int F2() { return 0; } static int F3() { return 0; } static int F4() { return 0; } public C(int a = 1, int b = 2, int c = 3, int d = 4, int e = 5, int f = 6, int g = 7) { } [System.Runtime.CompilerServices.CompilerGenerated] public C() : this(d: F1(), g: F2(), f: F3(), b: F4()) { M(); } }", @"function() { var $tmp1 = {sm_C}.F1(); var $tmp2 = {sm_C}.F2(); var $tmp3 = {sm_C}.F3(); {sm_C}.call(this, 1, {sm_C}.F4(), 3, $tmp1, 5, $tmp3, $tmp2); this.M(); }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Named("ctor1") : ConstructorScriptSemantics.Unnamed() }); }
public void InvokingBaseConstructorMarkedAsNotUsableFromScriptIsAnError() { var rpt = new MockErrorReporter(false); Compile(new[] { @"class B { public B() {} } class D : B { public D() {} }" }, errorReporter: rpt, metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.DeclaringType.Name == "D" ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.NotUsableFromScript() }); Assert.That(rpt.AllMessages.Any(msg => msg.Severity == MessageSeverity.Error && msg.FormattedMessage.IndexOf("cannot be used", StringComparison.InvariantCultureIgnoreCase) >= 0)); }
public void ChainingToStaticMethodConstructorFromAnotherTypeOfConstructorIsAnError() { var rpt = new MockErrorReporter(false); Compile(new[] { @"class C { public C() : this(0) { } public C(int x) { } }" }, errorReporter: rpt, metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.StaticMethod("ctor") }); Assert.That(rpt.AllMessagesText.Any(msg => msg.StartsWith("Error", StringComparison.InvariantCultureIgnoreCase) && msg.IndexOf("static method", StringComparison.InvariantCultureIgnoreCase) >= 0)); }
public void ChainingToJsonConstructorFromStaticMethodConstructorWorks() { AssertCorrect( @"class C { static int F1() { return 0; } static int F2() { return 0; } static int F3() { return 0; } static int F4() { return 0; } public int A, B, C, D, E, F, G; public void M() {} public C(int a = 1, int b = 2, int c = 3, int d = 4, int e = 5, int f = 6, int g = 7) { } [System.Runtime.CompilerServices.CompilerGenerated] public C() : this(d: F1(), g: F2(), f: F3(), b: F4()) { M(); } }", @"function() { var $this = { $D: {sm_C}.F1(), $G: {sm_C}.F2(), $F: {sm_C}.F3(), $B: {sm_C}.F4(), $A: 1, $C: 3, $E: 5 }; $this.M(); return $this; }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.StaticMethod("X") : ConstructorScriptSemantics.Json(c.Parameters.Select(p => c.DeclaringType.GetFields().Single(x => x.Name.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase)))) }); }
public void InvokingBaseStaticMethodConstructorFromAnotherTypeOfConstructorWorks() { AssertCorrect( @"class B { public B(int x) {} } class D : B { public static int P { get; set; } [System.Runtime.CompilerServices.CompilerGenerated] public D() : base(P = 1) {} }", @"function() { {sm_D}.set_P(1); $ShallowCopy({sm_B}.ctor(1), this); }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.DeclaringType.Name == "D" ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.StaticMethod("ctor") }); }
public JsFunctionDefinitionExpression CompileConstructor(ConstructorDeclaration ctor, IMethod constructor, List <JsStatement> instanceInitStatements, ConstructorScriptSemantics impl) { var region = _errorReporter.Region = ctor != null?ctor.GetRegion() : constructor.DeclaringTypeDefinition.Region; try { CreateCompilationContext(ctor, constructor, constructor.DeclaringTypeDefinition, (impl.Type == ConstructorScriptSemantics.ImplType.StaticMethod ? _namer.ThisAlias : null)); IList <JsStatement> body = new List <JsStatement>(); body.AddRange(PrepareParameters(constructor.Parameters, variables, expandParams: impl.ExpandParams, staticMethodWithThisAsFirstArgument: false)); if (impl.Type == ConstructorScriptSemantics.ImplType.StaticMethod) { if (ctor != null && !ctor.Initializer.IsNull) { body.AddRange(_statementCompiler.CompileConstructorInitializer(ctor.Initializer, true)); } else { body.AddRange(_statementCompiler.CompileImplicitBaseConstructorCall(constructor.DeclaringTypeDefinition, true)); } } if (ctor == null || ctor.Initializer.IsNull || ctor.Initializer.ConstructorInitializerType != ConstructorInitializerType.This) { if (impl.Type == ConstructorScriptSemantics.ImplType.StaticMethod) { // The compiler one step up has created the statements as "this.a = b;", but we need to replace that with "$this.a = b;" (or whatever name the this alias has). var replacer = new ThisReplacer(JsExpression.Identifier(_namer.ThisAlias)); instanceInitStatements = instanceInitStatements.Select(s => replacer.VisitStatement(s, null)).ToList(); } body.AddRange(instanceInitStatements); // Don't initialize fields when we are chaining, but do it when we 1) compile the default constructor, 2) don't have an initializer, or 3) when the initializer is not this(...). } if (impl.Type != ConstructorScriptSemantics.ImplType.StaticMethod) { if (ctor != null && !ctor.Initializer.IsNull) { body.AddRange(_statementCompiler.CompileConstructorInitializer(ctor.Initializer, false)); } else { body.AddRange(_statementCompiler.CompileImplicitBaseConstructorCall(constructor.DeclaringTypeDefinition, false)); } } if (ctor != null) { body.AddRange(_statementCompiler.Compile(ctor.Body).Statements); } if (impl.Type == ConstructorScriptSemantics.ImplType.StaticMethod) { if (body.Count == 0 || !(body[body.Count - 1] is JsReturnStatement)) { body.Add(JsStatement.Return()); } body = StaticMethodConstructorReturnPatcher.Process(body, _namer.ThisAlias).AsReadOnly(); } var compiled = JsExpression.FunctionDefinition(constructor.Parameters.Where((p, i) => i != constructor.Parameters.Count - 1 || !impl.ExpandParams).Select(p => variables[p].Name), JsStatement.Block(body)); return(_statementCompiler.StateMachineRewriteNormalMethod(compiled)); } catch (Exception ex) { _errorReporter.Region = region; _errorReporter.InternalError(ex); return(JsExpression.FunctionDefinition(new string[0], JsStatement.EmptyBlock)); } }
public JsFunctionDefinitionExpression CompileDefaultConstructor(IMethod constructor, List <JsStatement> instanceInitStatements, ConstructorScriptSemantics impl) { return(CompileConstructor(null, constructor, instanceInitStatements, impl)); }
public void JsonConstructorWithParameterToMemberMapWorks() { AssertCorrect( @"class C1 { public C1(int a, int b) {} public int a2, int b2; } public int F1() { return 0; } public int F2() { return 0; } public int P { get; set; } public void M() { // BEGIN var c = new C1(F1(), P = F2()); // END }", @" var $tmp2 = this.F1(); var $tmp1 = this.F2(); this.set_P($tmp1); var $c = { $a2: $tmp2, $b2: $tmp1 }; ", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.DeclaringType.Name == "C1" ? ConstructorScriptSemantics.Json(new[] { c.DeclaringType.GetFields().Single(f => f.Name == "a2"), c.DeclaringType.GetFields().Single(f => f.Name == "b2") }) : ConstructorScriptSemantics.Unnamed() }); }
public void CreatingObjectWithDynamicArgumentGivesAnErrorWhenNamesDifferBetweenApplicableMethods() { var er = new MockErrorReporter(); Compile(new[] { @"public class C1 { public C1(int x) {} public C1(string x) {} } public class C { public void M() { dynamic d = null; // BEGIN var c = new C1(d); // END } }" }, metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count > 0 ? ConstructorScriptSemantics.Named("C$" + c.Parameters[0].Type.Name) : ConstructorScriptSemantics.Unnamed() }, errorReporter: er); Assert.That(er.AllMessages.Count, Is.EqualTo(1)); Assert.That(er.AllMessages.Any(m => m.Code == 7531)); er = new MockErrorReporter(); Compile(new[] { @"public class C1 { public C1(int x) {} public C1(string x) {} } public class C { public void M() { dynamic d = null; // BEGIN var c = new C1(d); // END } }" }, metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count > 0 ? ConstructorScriptSemantics.StaticMethod("C$" + c.Parameters[0].Type.Name) : ConstructorScriptSemantics.Unnamed() }, errorReporter: er); Assert.That(er.AllMessages.Count, Is.EqualTo(1)); Assert.That(er.AllMessages.Any(m => m.Code == 7531)); }
public virtual void SetConstructorSemantics(IMethod method, ConstructorScriptSemantics semantics) { _prev.SetConstructorSemantics(method, semantics); }
public void ChainingToParamArrayConstructorThatExpandsArgumentsInNonExpandedFormIsAnError() { var er = new MockErrorReporter(false); Compile(new[] { @"class C1 { public C1(int x, int y, params int[] args) {} [System.Runtime.CompilerServices.CompilerGenerated] public C1() : this(4, 8, new[] { 59, 12, 4 }) {} }" }, metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.Named("x", expandParams: true) }, errorReporter: er); Assert.That(er.AllMessagesText.Count, Is.EqualTo(1)); Assert.That(er.AllMessagesText[0].Contains("C1") && er.AllMessagesText[0].Contains("constructor") && er.AllMessagesText[0].Contains("expanded form")); }
public void InvokingBaseStaticMethodConstructorFromAnotherTypeOfConstructorIsAnError() { var rpt = new MockErrorReporter(false); Compile(new[] { @"class B { public B() {} } class D : B { public D() {} }" }, errorReporter: rpt, metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.DeclaringType.Name == "D" ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.StaticMethod("ctor") }); Assert.That(rpt.AllMessagesText.Any(msg => msg.StartsWith("Error", StringComparison.InvariantCultureIgnoreCase) && msg.IndexOf("static method", StringComparison.InvariantCultureIgnoreCase) >= 0)); }
public void ChainingToConstructorImplementedAsJsonFromUnnamedConstructorWorks() { AssertCorrect( @"class C { public int X; public string S; static int P { get; set; } public void M() {} [System.Runtime.CompilerServices.CompilerGenerated] public C() : this(P = 42, ""X"") { M(); } public C(int x, string s) { } }", @"function() { {sm_C}.set_P(42); $ShallowCopy({ $X: 42, $S: 'X' }, this); this.M(); }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.Json(c.Parameters.Select(p => c.DeclaringType.GetFields().Single(x => x.Name.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase)))) }); }
void IMetadataImporter.SetConstructorSemantics(IMethod method, ConstructorScriptSemantics semantics) { }
public void ChainingToConstructorImplementedAsInlineCodeFromStaticMethodConstructorWorks() { AssertCorrect( @"class C { public void M() {} [System.Runtime.CompilerServices.CompilerGenerated] public C() : this(0, ""X"") { M(); } public C(int x, string s) { } }", @"function() { var $this = __Literal_(0)._X__; $this.M(); return $this; }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.StaticMethod("M") : ConstructorScriptSemantics.InlineCode("__Literal_({x})._{@s}__") }); }
public void ChainingToNamedParamArrayConstructorThatDoesNotExpandArgumentsInExpandedFormWorks() { AssertCorrect( @"class C1 { public C1(int x, int y, params int[] args) {} [System.Runtime.CompilerServices.CompilerGenerated] public C1() : this(4, 8, 59, 12, 4) {} }", @"function() { {sm_C1}.x.call(this, 4, 8, [59, 12, 4]); }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.Named("x") }); }
public void ChainingToStaticMethodConstructorFromAnotherTypeOfConstructorWorks() { AssertCorrect( @"class C { public static int P { get; set; } [System.Runtime.CompilerServices.CompilerGenerated] public C() : this(P = 0) { } public C(int x) { } }", @"function() { {sm_C}.set_P(0); $ShallowCopy({sm_C}.ctor(0), this); }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.StaticMethod("ctor") }); }
public void ChainingToNamedParamArrayConstructorThatExpandsArgumentsInNonExpandedFormWorks() { AssertCorrect( @"class C1 { static int[] args = new[] { 59, 12, 4 }; public C1(int x, int y, params int[] args) {} [System.Runtime.CompilerServices.CompilerGenerated] public C1() : this(4, 8, args) {} }", @"function() { {sm_C1}.x.apply(this, [4, 8].concat({sm_C1}.$args)); }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.Named("x", expandParams: true) }); AssertCorrect( @"class C1 { public C1(int x, int y, params int[] args) {} [System.Runtime.CompilerServices.CompilerGenerated] public C1() : this(4, 8, new[] { 59, 12, 4 }) {} }", @"function() { {sm_C1}.x.call(this, 4, 8, 59, 12, 4); }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.Named("x", expandParams: true) }); }
public void ChainingToConstructorMarkedAsNotUsableFromScriptIsAnError() { var rpt = new MockErrorReporter(false); Compile(new[] { @"class C { public C() : this(0) { } public C(int x) { } }" }, errorReporter: rpt, metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.NotUsableFromScript() }); Assert.That(rpt.AllMessages.Any(msg => msg.Severity == MessageSeverity.Error && msg.FormattedMessage.IndexOf("cannot be used", StringComparison.InvariantCultureIgnoreCase) >= 0)); }
public void ChainingToInlineCodeConstructorThatUsesExpandedParameterPlaceholderInNonExpandedFormIsAnError() { var er = new MockErrorReporter(false); Compile(new[] { @"class C1 { public static int[] a = null; public C1(params int[] args) {} [System.Runtime.CompilerServices.CompilerGenerated] public C1() : this(a) { } }" }, metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 1 ? ConstructorScriptSemantics.InlineCode("_({*args})") : ConstructorScriptSemantics.Unnamed() }, errorReporter: er); Assert.That(er.AllMessages.Any(msg => msg.Severity == MessageSeverity.Error && msg.FormattedMessage.Contains("constructor") && msg.FormattedMessage.Contains("C1") && msg.FormattedMessage.Contains("params parameter expanded"))); }
public void ChainingToAnonymousConstructorFromStaticMethodConstructorWorks() { AssertCorrect( @"class C { static int F1() { return 0; } static int F2() { return 0; } static int F3() { return 0; } static int F4() { return 0; } public void M() {} public C(int a = 1, int b = 2, int c = 3, int d = 4, int e = 5, int f = 6, int g = 7) { } [System.Runtime.CompilerServices.CompilerGenerated] public C() : this(d: F1(), g: F2(), f: F3(), b: F4()) { M(); } }", @"function() { var $tmp1 = {sm_C}.F1(); var $tmp2 = {sm_C}.F2(); var $tmp3 = {sm_C}.F3(); var $this = new {sm_C}(1, {sm_C}.F4(), 3, $tmp1, 5, $tmp3, $tmp2); $this.M(); return $this; }", metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.DeclaringType.Name == "C" && c.Parameters.Count == 0 ? ConstructorScriptSemantics.StaticMethod("ctor") : ConstructorScriptSemantics.Unnamed() }); }
public void ChainingToConstructorImplementedAsJsonFromUnnamedConstructorIsAnError() { var rpt = new MockErrorReporter(false); Compile(new[] { @"class C { public void M() {} [System.Runtime.CompilerServices.CompilerGenerated] public C() : this(0, ""X"") { M(); } public C(int x, string s) { } }" }, errorReporter: rpt, metadataImporter: new MockMetadataImporter { GetConstructorSemantics = c => c.Parameters.Count == 0 ? ConstructorScriptSemantics.Unnamed() : ConstructorScriptSemantics.Json(new IMember[0]) }); Assert.That(rpt.AllMessagesText.Any(msg => msg.StartsWith("Error", StringComparison.InvariantCultureIgnoreCase) && msg.IndexOf("not supported", StringComparison.InvariantCultureIgnoreCase) >= 0)); }