Browse Source

Add support for FormattableString patterns.

pull/1243/head
Siegfried Pammer 7 years ago
parent
commit
0fc5c8b988
  1. 59
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS6_StringInterpolation.cs
  2. 673
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS6_StringInterpolation.opt.roslyn.il
  3. 705
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS6_StringInterpolation.roslyn.il
  4. 160
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  5. 5
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs
  6. 4
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
  7. 139
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  8. 18
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
  9. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  10. 17
      ICSharpCode.Decompiler/Semantics/Conversion.cs
  11. 42
      ICSharpCode.Decompiler/Semantics/InterpolatedStringResolveResult.cs
  12. 10
      ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs

59
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS6_StringInterpolation.cs

@ -16,12 +16,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -16,12 +16,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine($"\ta{args.Length}b");
Console.WriteLine($"\ta{args.Length}ba{args[0]}a{args[args.Length]}a{args.Length}");
Console.WriteLine($"\ta{((args.Length != 0) ? 5 : 0)}");
Console.WriteLine($"\ta{(object)(args ?? args)}");
Console.WriteLine($"\ta{args ?? args}");
Console.WriteLine($"\ta{args[0][0] == 'a'}");
// This is legal, but we cannot create a pretty test for it, as it would require us
// to convert string literals to string interpolation literals even without a string.Format call.
// I do not think, this is worth the effort.
//Console.WriteLine($"\ta{$"a" == args[0]}");
Console.WriteLine($"\ta{$"a{args.Length}" == args[0]}");
}
public static void InvalidFormatString(string[] args)
@ -51,5 +48,57 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -51,5 +48,57 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine(string.Format("{0{a}0}", args.Length));
Console.WriteLine(string.Format("test: {0}", string.Join(",", args)));
}
public void FormattableStrings(FormattableString s, string[] args)
{
s = $"{args.Length}";
s = $"a{{0{args.Length}";
s = $"{args.Length:x}";
s = $"\ta{args.Length}b";
s = $"\ta{args.Length}ba{args[0]}a{args[args.Length]}a{args.Length}";
s = $"\ta{((args.Length != 0) ? 5 : 0)}";
s = $"\ta{args ?? args}";
s = $"\ta{args[0][0] == 'a'}";
s = $"\ta{$"a{args.Length}" == args[0]}";
RequiresCast($"{args.Length}");
RequiresCast($"a{{0{args.Length}");
RequiresCast($"{args.Length:x}");
RequiresCast($"\ta{args.Length}b");
RequiresCast($"\ta{args.Length}ba{args[0]}a{args[args.Length]}a{args.Length}");
RequiresCast($"\ta{((args.Length != 0) ? 5 : 0)}");
RequiresCast($"\ta{args ?? args}");
RequiresCast($"\ta{args[0][0] == 'a'}");
RequiresCast($"\ta{$"a{args.Length}" == args[0]}");
RequiresCast((FormattableString)$"{args.Length}");
RequiresCast((FormattableString)$"a{{0{args.Length}");
RequiresCast((FormattableString)$"{args.Length:x}");
RequiresCast((FormattableString)$"\ta{args.Length}b");
RequiresCast((FormattableString)$"\ta{args.Length}ba{args[0]}a{args[args.Length]}a{args.Length}");
RequiresCast((FormattableString)$"\ta{((args.Length != 0) ? 5 : 0)}");
RequiresCast((FormattableString)$"\ta{args ?? args}");
RequiresCast((FormattableString)$"\ta{args[0][0] == 'a'}");
RequiresCast((FormattableString)$"\ta{$"a{args.Length}" == args[0]}");
RequiresCast((IFormattable)$"{args.Length}");
RequiresCast((IFormattable)$"a{{0{args.Length}");
RequiresCast((IFormattable)$"{args.Length:x}");
RequiresCast((IFormattable)$"\ta{args.Length}b");
RequiresCast((IFormattable)$"\ta{args.Length}ba{args[0]}a{args[args.Length]}a{args.Length}");
RequiresCast((IFormattable)$"\ta{((args.Length != 0) ? 5 : 0)}");
RequiresCast((IFormattable)$"\ta{args ?? args}");
RequiresCast((IFormattable)$"\ta{args[0][0] == 'a'}");
RequiresCast((IFormattable)$"\ta{$"a{args.Length}" == args[0]}");
}
public void RequiresCast(string value)
{
}
public void RequiresCast(FormattableString value)
{
}
public void RequiresCast(IFormattable value)
{
}
}
}

673
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS6_StringInterpolation.opt.roslyn.il

@ -46,7 +46,7 @@ @@ -46,7 +46,7 @@
.method public hidebysig static void General(string[] args) cil managed
{
// Code size 232 (0xe8)
// Code size 278 (0x116)
.maxstack 6
IL_0000: ldstr "{0}"
IL_0005: ldarg.0
@ -149,7 +149,24 @@ @@ -149,7 +149,24 @@
IL_00dd: call string [mscorlib]System.String::Format(string,
object)
IL_00e2: call void [mscorlib]System.Console::WriteLine(string)
IL_00e7: ret
IL_00e7: ldstr "\ta{0}"
IL_00ec: ldstr "a{0}"
IL_00f1: ldarg.0
IL_00f2: ldlen
IL_00f3: conv.i4
IL_00f4: box [mscorlib]System.Int32
IL_00f9: call string [mscorlib]System.String::Format(string,
object)
IL_00fe: ldarg.0
IL_00ff: ldc.i4.0
IL_0100: ldelem.ref
IL_0101: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0106: box [mscorlib]System.Boolean
IL_010b: call string [mscorlib]System.String::Format(string,
object)
IL_0110: call void [mscorlib]System.Console::WriteLine(string)
IL_0115: ret
} // end of method CS6_StringInterpolation::General
.method public hidebysig static void InvalidFormatString(string[] args) cil managed
@ -351,6 +368,658 @@ @@ -351,6 +368,658 @@
IL_022b: ret
} // end of method CS6_StringInterpolation::InvalidFormatString
.method public hidebysig instance void
FormattableStrings(class [mscorlib]System.FormattableString s,
string[] args) cil managed
{
// Code size 1325 (0x52d)
.maxstack 8
IL_0000: ldstr "{0}"
IL_0005: ldc.i4.1
IL_0006: newarr [mscorlib]System.Object
IL_000b: dup
IL_000c: ldc.i4.0
IL_000d: ldarg.2
IL_000e: ldlen
IL_000f: conv.i4
IL_0010: box [mscorlib]System.Int32
IL_0015: stelem.ref
IL_0016: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_001b: starg.s s
IL_001d: ldstr "a{{0{0}"
IL_0022: ldc.i4.1
IL_0023: newarr [mscorlib]System.Object
IL_0028: dup
IL_0029: ldc.i4.0
IL_002a: ldarg.2
IL_002b: ldlen
IL_002c: conv.i4
IL_002d: box [mscorlib]System.Int32
IL_0032: stelem.ref
IL_0033: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0038: starg.s s
IL_003a: ldstr "{0:x}"
IL_003f: ldc.i4.1
IL_0040: newarr [mscorlib]System.Object
IL_0045: dup
IL_0046: ldc.i4.0
IL_0047: ldarg.2
IL_0048: ldlen
IL_0049: conv.i4
IL_004a: box [mscorlib]System.Int32
IL_004f: stelem.ref
IL_0050: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0055: starg.s s
IL_0057: ldstr "\ta{0}b"
IL_005c: ldc.i4.1
IL_005d: newarr [mscorlib]System.Object
IL_0062: dup
IL_0063: ldc.i4.0
IL_0064: ldarg.2
IL_0065: ldlen
IL_0066: conv.i4
IL_0067: box [mscorlib]System.Int32
IL_006c: stelem.ref
IL_006d: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0072: starg.s s
IL_0074: ldstr "\ta{0}ba{1}a{2}a{3}"
IL_0079: ldc.i4.4
IL_007a: newarr [mscorlib]System.Object
IL_007f: dup
IL_0080: ldc.i4.0
IL_0081: ldarg.2
IL_0082: ldlen
IL_0083: conv.i4
IL_0084: box [mscorlib]System.Int32
IL_0089: stelem.ref
IL_008a: dup
IL_008b: ldc.i4.1
IL_008c: ldarg.2
IL_008d: ldc.i4.0
IL_008e: ldelem.ref
IL_008f: stelem.ref
IL_0090: dup
IL_0091: ldc.i4.2
IL_0092: ldarg.2
IL_0093: ldarg.2
IL_0094: ldlen
IL_0095: conv.i4
IL_0096: ldelem.ref
IL_0097: stelem.ref
IL_0098: dup
IL_0099: ldc.i4.3
IL_009a: ldarg.2
IL_009b: ldlen
IL_009c: conv.i4
IL_009d: box [mscorlib]System.Int32
IL_00a2: stelem.ref
IL_00a3: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_00a8: starg.s s
IL_00aa: ldstr "\ta{0}"
IL_00af: ldc.i4.1
IL_00b0: newarr [mscorlib]System.Object
IL_00b5: dup
IL_00b6: ldc.i4.0
IL_00b7: ldarg.2
IL_00b8: ldlen
IL_00b9: brtrue.s IL_00be
IL_00bb: ldc.i4.0
IL_00bc: br.s IL_00bf
IL_00be: ldc.i4.5
IL_00bf: box [mscorlib]System.Int32
IL_00c4: stelem.ref
IL_00c5: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_00ca: starg.s s
IL_00cc: ldstr "\ta{0}"
IL_00d1: ldc.i4.1
IL_00d2: newarr [mscorlib]System.Object
IL_00d7: dup
IL_00d8: ldc.i4.0
IL_00d9: ldarg.2
IL_00da: dup
IL_00db: brtrue.s IL_00df
IL_00dd: pop
IL_00de: ldarg.2
IL_00df: stelem.ref
IL_00e0: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_00e5: starg.s s
IL_00e7: ldstr "\ta{0}"
IL_00ec: ldc.i4.1
IL_00ed: newarr [mscorlib]System.Object
IL_00f2: dup
IL_00f3: ldc.i4.0
IL_00f4: ldarg.2
IL_00f5: ldc.i4.0
IL_00f6: ldelem.ref
IL_00f7: ldc.i4.0
IL_00f8: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_00fd: ldc.i4.s 97
IL_00ff: ceq
IL_0101: box [mscorlib]System.Boolean
IL_0106: stelem.ref
IL_0107: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_010c: starg.s s
IL_010e: ldstr "\ta{0}"
IL_0113: ldc.i4.1
IL_0114: newarr [mscorlib]System.Object
IL_0119: dup
IL_011a: ldc.i4.0
IL_011b: ldstr "a{0}"
IL_0120: ldarg.2
IL_0121: ldlen
IL_0122: conv.i4
IL_0123: box [mscorlib]System.Int32
IL_0128: call string [mscorlib]System.String::Format(string,
object)
IL_012d: ldarg.2
IL_012e: ldc.i4.0
IL_012f: ldelem.ref
IL_0130: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0135: box [mscorlib]System.Boolean
IL_013a: stelem.ref
IL_013b: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0140: starg.s s
IL_0142: ldarg.0
IL_0143: ldstr "{0}"
IL_0148: ldarg.2
IL_0149: ldlen
IL_014a: conv.i4
IL_014b: box [mscorlib]System.Int32
IL_0150: call string [mscorlib]System.String::Format(string,
object)
IL_0155: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_015a: ldarg.0
IL_015b: ldstr "a{{0{0}"
IL_0160: ldarg.2
IL_0161: ldlen
IL_0162: conv.i4
IL_0163: box [mscorlib]System.Int32
IL_0168: call string [mscorlib]System.String::Format(string,
object)
IL_016d: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_0172: ldarg.0
IL_0173: ldstr "{0:x}"
IL_0178: ldarg.2
IL_0179: ldlen
IL_017a: conv.i4
IL_017b: box [mscorlib]System.Int32
IL_0180: call string [mscorlib]System.String::Format(string,
object)
IL_0185: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_018a: ldarg.0
IL_018b: ldstr "\ta{0}b"
IL_0190: ldarg.2
IL_0191: ldlen
IL_0192: conv.i4
IL_0193: box [mscorlib]System.Int32
IL_0198: call string [mscorlib]System.String::Format(string,
object)
IL_019d: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_01a2: ldarg.0
IL_01a3: ldstr "\ta{0}ba{1}a{2}a{3}"
IL_01a8: ldc.i4.4
IL_01a9: newarr [mscorlib]System.Object
IL_01ae: dup
IL_01af: ldc.i4.0
IL_01b0: ldarg.2
IL_01b1: ldlen
IL_01b2: conv.i4
IL_01b3: box [mscorlib]System.Int32
IL_01b8: stelem.ref
IL_01b9: dup
IL_01ba: ldc.i4.1
IL_01bb: ldarg.2
IL_01bc: ldc.i4.0
IL_01bd: ldelem.ref
IL_01be: stelem.ref
IL_01bf: dup
IL_01c0: ldc.i4.2
IL_01c1: ldarg.2
IL_01c2: ldarg.2
IL_01c3: ldlen
IL_01c4: conv.i4
IL_01c5: ldelem.ref
IL_01c6: stelem.ref
IL_01c7: dup
IL_01c8: ldc.i4.3
IL_01c9: ldarg.2
IL_01ca: ldlen
IL_01cb: conv.i4
IL_01cc: box [mscorlib]System.Int32
IL_01d1: stelem.ref
IL_01d2: call string [mscorlib]System.String::Format(string,
object[])
IL_01d7: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_01dc: ldarg.0
IL_01dd: ldstr "\ta{0}"
IL_01e2: ldarg.2
IL_01e3: ldlen
IL_01e4: brtrue.s IL_01e9
IL_01e6: ldc.i4.0
IL_01e7: br.s IL_01ea
IL_01e9: ldc.i4.5
IL_01ea: box [mscorlib]System.Int32
IL_01ef: call string [mscorlib]System.String::Format(string,
object)
IL_01f4: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_01f9: ldarg.0
IL_01fa: ldstr "\ta{0}"
IL_01ff: ldarg.2
IL_0200: dup
IL_0201: brtrue.s IL_0205
IL_0203: pop
IL_0204: ldarg.2
IL_0205: call string [mscorlib]System.String::Format(string,
object)
IL_020a: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_020f: ldarg.0
IL_0210: ldstr "\ta{0}"
IL_0215: ldarg.2
IL_0216: ldc.i4.0
IL_0217: ldelem.ref
IL_0218: ldc.i4.0
IL_0219: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_021e: ldc.i4.s 97
IL_0220: ceq
IL_0222: box [mscorlib]System.Boolean
IL_0227: call string [mscorlib]System.String::Format(string,
object)
IL_022c: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_0231: ldarg.0
IL_0232: ldstr "\ta{0}"
IL_0237: ldstr "a{0}"
IL_023c: ldarg.2
IL_023d: ldlen
IL_023e: conv.i4
IL_023f: box [mscorlib]System.Int32
IL_0244: call string [mscorlib]System.String::Format(string,
object)
IL_0249: ldarg.2
IL_024a: ldc.i4.0
IL_024b: ldelem.ref
IL_024c: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0251: box [mscorlib]System.Boolean
IL_0256: call string [mscorlib]System.String::Format(string,
object)
IL_025b: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_0260: ldarg.0
IL_0261: ldstr "{0}"
IL_0266: ldc.i4.1
IL_0267: newarr [mscorlib]System.Object
IL_026c: dup
IL_026d: ldc.i4.0
IL_026e: ldarg.2
IL_026f: ldlen
IL_0270: conv.i4
IL_0271: box [mscorlib]System.Int32
IL_0276: stelem.ref
IL_0277: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_027c: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_0281: ldarg.0
IL_0282: ldstr "a{{0{0}"
IL_0287: ldc.i4.1
IL_0288: newarr [mscorlib]System.Object
IL_028d: dup
IL_028e: ldc.i4.0
IL_028f: ldarg.2
IL_0290: ldlen
IL_0291: conv.i4
IL_0292: box [mscorlib]System.Int32
IL_0297: stelem.ref
IL_0298: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_029d: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_02a2: ldarg.0
IL_02a3: ldstr "{0:x}"
IL_02a8: ldc.i4.1
IL_02a9: newarr [mscorlib]System.Object
IL_02ae: dup
IL_02af: ldc.i4.0
IL_02b0: ldarg.2
IL_02b1: ldlen
IL_02b2: conv.i4
IL_02b3: box [mscorlib]System.Int32
IL_02b8: stelem.ref
IL_02b9: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_02be: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_02c3: ldarg.0
IL_02c4: ldstr "\ta{0}b"
IL_02c9: ldc.i4.1
IL_02ca: newarr [mscorlib]System.Object
IL_02cf: dup
IL_02d0: ldc.i4.0
IL_02d1: ldarg.2
IL_02d2: ldlen
IL_02d3: conv.i4
IL_02d4: box [mscorlib]System.Int32
IL_02d9: stelem.ref
IL_02da: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_02df: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_02e4: ldarg.0
IL_02e5: ldstr "\ta{0}ba{1}a{2}a{3}"
IL_02ea: ldc.i4.4
IL_02eb: newarr [mscorlib]System.Object
IL_02f0: dup
IL_02f1: ldc.i4.0
IL_02f2: ldarg.2
IL_02f3: ldlen
IL_02f4: conv.i4
IL_02f5: box [mscorlib]System.Int32
IL_02fa: stelem.ref
IL_02fb: dup
IL_02fc: ldc.i4.1
IL_02fd: ldarg.2
IL_02fe: ldc.i4.0
IL_02ff: ldelem.ref
IL_0300: stelem.ref
IL_0301: dup
IL_0302: ldc.i4.2
IL_0303: ldarg.2
IL_0304: ldarg.2
IL_0305: ldlen
IL_0306: conv.i4
IL_0307: ldelem.ref
IL_0308: stelem.ref
IL_0309: dup
IL_030a: ldc.i4.3
IL_030b: ldarg.2
IL_030c: ldlen
IL_030d: conv.i4
IL_030e: box [mscorlib]System.Int32
IL_0313: stelem.ref
IL_0314: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0319: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_031e: ldarg.0
IL_031f: ldstr "\ta{0}"
IL_0324: ldc.i4.1
IL_0325: newarr [mscorlib]System.Object
IL_032a: dup
IL_032b: ldc.i4.0
IL_032c: ldarg.2
IL_032d: ldlen
IL_032e: brtrue.s IL_0333
IL_0330: ldc.i4.0
IL_0331: br.s IL_0334
IL_0333: ldc.i4.5
IL_0334: box [mscorlib]System.Int32
IL_0339: stelem.ref
IL_033a: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_033f: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_0344: ldarg.0
IL_0345: ldstr "\ta{0}"
IL_034a: ldc.i4.1
IL_034b: newarr [mscorlib]System.Object
IL_0350: dup
IL_0351: ldc.i4.0
IL_0352: ldarg.2
IL_0353: dup
IL_0354: brtrue.s IL_0358
IL_0356: pop
IL_0357: ldarg.2
IL_0358: stelem.ref
IL_0359: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_035e: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_0363: ldarg.0
IL_0364: ldstr "\ta{0}"
IL_0369: ldc.i4.1
IL_036a: newarr [mscorlib]System.Object
IL_036f: dup
IL_0370: ldc.i4.0
IL_0371: ldarg.2
IL_0372: ldc.i4.0
IL_0373: ldelem.ref
IL_0374: ldc.i4.0
IL_0375: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_037a: ldc.i4.s 97
IL_037c: ceq
IL_037e: box [mscorlib]System.Boolean
IL_0383: stelem.ref
IL_0384: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0389: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_038e: ldarg.0
IL_038f: ldstr "\ta{0}"
IL_0394: ldc.i4.1
IL_0395: newarr [mscorlib]System.Object
IL_039a: dup
IL_039b: ldc.i4.0
IL_039c: ldstr "a{0}"
IL_03a1: ldarg.2
IL_03a2: ldlen
IL_03a3: conv.i4
IL_03a4: box [mscorlib]System.Int32
IL_03a9: call string [mscorlib]System.String::Format(string,
object)
IL_03ae: ldarg.2
IL_03af: ldc.i4.0
IL_03b0: ldelem.ref
IL_03b1: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_03b6: box [mscorlib]System.Boolean
IL_03bb: stelem.ref
IL_03bc: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_03c1: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_03c6: ldarg.0
IL_03c7: ldstr "{0}"
IL_03cc: ldc.i4.1
IL_03cd: newarr [mscorlib]System.Object
IL_03d2: dup
IL_03d3: ldc.i4.0
IL_03d4: ldarg.2
IL_03d5: ldlen
IL_03d6: conv.i4
IL_03d7: box [mscorlib]System.Int32
IL_03dc: stelem.ref
IL_03dd: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_03e2: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_03e7: ldarg.0
IL_03e8: ldstr "a{{0{0}"
IL_03ed: ldc.i4.1
IL_03ee: newarr [mscorlib]System.Object
IL_03f3: dup
IL_03f4: ldc.i4.0
IL_03f5: ldarg.2
IL_03f6: ldlen
IL_03f7: conv.i4
IL_03f8: box [mscorlib]System.Int32
IL_03fd: stelem.ref
IL_03fe: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0403: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_0408: ldarg.0
IL_0409: ldstr "{0:x}"
IL_040e: ldc.i4.1
IL_040f: newarr [mscorlib]System.Object
IL_0414: dup
IL_0415: ldc.i4.0
IL_0416: ldarg.2
IL_0417: ldlen
IL_0418: conv.i4
IL_0419: box [mscorlib]System.Int32
IL_041e: stelem.ref
IL_041f: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0424: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_0429: ldarg.0
IL_042a: ldstr "\ta{0}b"
IL_042f: ldc.i4.1
IL_0430: newarr [mscorlib]System.Object
IL_0435: dup
IL_0436: ldc.i4.0
IL_0437: ldarg.2
IL_0438: ldlen
IL_0439: conv.i4
IL_043a: box [mscorlib]System.Int32
IL_043f: stelem.ref
IL_0440: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0445: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_044a: ldarg.0
IL_044b: ldstr "\ta{0}ba{1}a{2}a{3}"
IL_0450: ldc.i4.4
IL_0451: newarr [mscorlib]System.Object
IL_0456: dup
IL_0457: ldc.i4.0
IL_0458: ldarg.2
IL_0459: ldlen
IL_045a: conv.i4
IL_045b: box [mscorlib]System.Int32
IL_0460: stelem.ref
IL_0461: dup
IL_0462: ldc.i4.1
IL_0463: ldarg.2
IL_0464: ldc.i4.0
IL_0465: ldelem.ref
IL_0466: stelem.ref
IL_0467: dup
IL_0468: ldc.i4.2
IL_0469: ldarg.2
IL_046a: ldarg.2
IL_046b: ldlen
IL_046c: conv.i4
IL_046d: ldelem.ref
IL_046e: stelem.ref
IL_046f: dup
IL_0470: ldc.i4.3
IL_0471: ldarg.2
IL_0472: ldlen
IL_0473: conv.i4
IL_0474: box [mscorlib]System.Int32
IL_0479: stelem.ref
IL_047a: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_047f: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_0484: ldarg.0
IL_0485: ldstr "\ta{0}"
IL_048a: ldc.i4.1
IL_048b: newarr [mscorlib]System.Object
IL_0490: dup
IL_0491: ldc.i4.0
IL_0492: ldarg.2
IL_0493: ldlen
IL_0494: brtrue.s IL_0499
IL_0496: ldc.i4.0
IL_0497: br.s IL_049a
IL_0499: ldc.i4.5
IL_049a: box [mscorlib]System.Int32
IL_049f: stelem.ref
IL_04a0: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_04a5: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_04aa: ldarg.0
IL_04ab: ldstr "\ta{0}"
IL_04b0: ldc.i4.1
IL_04b1: newarr [mscorlib]System.Object
IL_04b6: dup
IL_04b7: ldc.i4.0
IL_04b8: ldarg.2
IL_04b9: dup
IL_04ba: brtrue.s IL_04be
IL_04bc: pop
IL_04bd: ldarg.2
IL_04be: stelem.ref
IL_04bf: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_04c4: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_04c9: ldarg.0
IL_04ca: ldstr "\ta{0}"
IL_04cf: ldc.i4.1
IL_04d0: newarr [mscorlib]System.Object
IL_04d5: dup
IL_04d6: ldc.i4.0
IL_04d7: ldarg.2
IL_04d8: ldc.i4.0
IL_04d9: ldelem.ref
IL_04da: ldc.i4.0
IL_04db: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_04e0: ldc.i4.s 97
IL_04e2: ceq
IL_04e4: box [mscorlib]System.Boolean
IL_04e9: stelem.ref
IL_04ea: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_04ef: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_04f4: ldarg.0
IL_04f5: ldstr "\ta{0}"
IL_04fa: ldc.i4.1
IL_04fb: newarr [mscorlib]System.Object
IL_0500: dup
IL_0501: ldc.i4.0
IL_0502: ldstr "a{0}"
IL_0507: ldarg.2
IL_0508: ldlen
IL_0509: conv.i4
IL_050a: box [mscorlib]System.Int32
IL_050f: call string [mscorlib]System.String::Format(string,
object)
IL_0514: ldarg.2
IL_0515: ldc.i4.0
IL_0516: ldelem.ref
IL_0517: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_051c: box [mscorlib]System.Boolean
IL_0521: stelem.ref
IL_0522: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0527: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_052c: ret
} // end of method CS6_StringInterpolation::FormattableStrings
.method public hidebysig instance void
RequiresCast(string 'value') cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method CS6_StringInterpolation::RequiresCast
.method public hidebysig instance void
RequiresCast(class [mscorlib]System.FormattableString 'value') cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method CS6_StringInterpolation::RequiresCast
.method public hidebysig instance void
RequiresCast(class [mscorlib]System.IFormattable 'value') cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method CS6_StringInterpolation::RequiresCast
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

705
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS6_StringInterpolation.roslyn.il

@ -47,7 +47,7 @@ @@ -47,7 +47,7 @@
.method public hidebysig static void General(string[] args) cil managed
{
// Code size 241 (0xf1)
// Code size 288 (0x120)
.maxstack 6
IL_0000: nop
IL_0001: ldstr "{0}"
@ -159,7 +159,25 @@ @@ -159,7 +159,25 @@
object)
IL_00ea: call void [mscorlib]System.Console::WriteLine(string)
IL_00ef: nop
IL_00f0: ret
IL_00f0: ldstr "\ta{0}"
IL_00f5: ldstr "a{0}"
IL_00fa: ldarg.0
IL_00fb: ldlen
IL_00fc: conv.i4
IL_00fd: box [mscorlib]System.Int32
IL_0102: call string [mscorlib]System.String::Format(string,
object)
IL_0107: ldarg.0
IL_0108: ldc.i4.0
IL_0109: ldelem.ref
IL_010a: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_010f: box [mscorlib]System.Boolean
IL_0114: call string [mscorlib]System.String::Format(string,
object)
IL_0119: call void [mscorlib]System.Console::WriteLine(string)
IL_011e: nop
IL_011f: ret
} // end of method CS6_StringInterpolation::General
.method public hidebysig static void InvalidFormatString(string[] args) cil managed
@ -386,6 +404,689 @@ @@ -386,6 +404,689 @@
IL_0244: ret
} // end of method CS6_StringInterpolation::InvalidFormatString
.method public hidebysig instance void
FormattableStrings(class [mscorlib]System.FormattableString s,
string[] args) cil managed
{
// Code size 1353 (0x549)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "{0}"
IL_0006: ldc.i4.1
IL_0007: newarr [mscorlib]System.Object
IL_000c: dup
IL_000d: ldc.i4.0
IL_000e: ldarg.2
IL_000f: ldlen
IL_0010: conv.i4
IL_0011: box [mscorlib]System.Int32
IL_0016: stelem.ref
IL_0017: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_001c: starg.s s
IL_001e: ldstr "a{{0{0}"
IL_0023: ldc.i4.1
IL_0024: newarr [mscorlib]System.Object
IL_0029: dup
IL_002a: ldc.i4.0
IL_002b: ldarg.2
IL_002c: ldlen
IL_002d: conv.i4
IL_002e: box [mscorlib]System.Int32
IL_0033: stelem.ref
IL_0034: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0039: starg.s s
IL_003b: ldstr "{0:x}"
IL_0040: ldc.i4.1
IL_0041: newarr [mscorlib]System.Object
IL_0046: dup
IL_0047: ldc.i4.0
IL_0048: ldarg.2
IL_0049: ldlen
IL_004a: conv.i4
IL_004b: box [mscorlib]System.Int32
IL_0050: stelem.ref
IL_0051: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0056: starg.s s
IL_0058: ldstr "\ta{0}b"
IL_005d: ldc.i4.1
IL_005e: newarr [mscorlib]System.Object
IL_0063: dup
IL_0064: ldc.i4.0
IL_0065: ldarg.2
IL_0066: ldlen
IL_0067: conv.i4
IL_0068: box [mscorlib]System.Int32
IL_006d: stelem.ref
IL_006e: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0073: starg.s s
IL_0075: ldstr "\ta{0}ba{1}a{2}a{3}"
IL_007a: ldc.i4.4
IL_007b: newarr [mscorlib]System.Object
IL_0080: dup
IL_0081: ldc.i4.0
IL_0082: ldarg.2
IL_0083: ldlen
IL_0084: conv.i4
IL_0085: box [mscorlib]System.Int32
IL_008a: stelem.ref
IL_008b: dup
IL_008c: ldc.i4.1
IL_008d: ldarg.2
IL_008e: ldc.i4.0
IL_008f: ldelem.ref
IL_0090: stelem.ref
IL_0091: dup
IL_0092: ldc.i4.2
IL_0093: ldarg.2
IL_0094: ldarg.2
IL_0095: ldlen
IL_0096: conv.i4
IL_0097: ldelem.ref
IL_0098: stelem.ref
IL_0099: dup
IL_009a: ldc.i4.3
IL_009b: ldarg.2
IL_009c: ldlen
IL_009d: conv.i4
IL_009e: box [mscorlib]System.Int32
IL_00a3: stelem.ref
IL_00a4: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_00a9: starg.s s
IL_00ab: ldstr "\ta{0}"
IL_00b0: ldc.i4.1
IL_00b1: newarr [mscorlib]System.Object
IL_00b6: dup
IL_00b7: ldc.i4.0
IL_00b8: ldarg.2
IL_00b9: ldlen
IL_00ba: brtrue.s IL_00bf
IL_00bc: ldc.i4.0
IL_00bd: br.s IL_00c0
IL_00bf: ldc.i4.5
IL_00c0: box [mscorlib]System.Int32
IL_00c5: stelem.ref
IL_00c6: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_00cb: starg.s s
IL_00cd: ldstr "\ta{0}"
IL_00d2: ldc.i4.1
IL_00d3: newarr [mscorlib]System.Object
IL_00d8: dup
IL_00d9: ldc.i4.0
IL_00da: ldarg.2
IL_00db: dup
IL_00dc: brtrue.s IL_00e0
IL_00de: pop
IL_00df: ldarg.2
IL_00e0: stelem.ref
IL_00e1: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_00e6: starg.s s
IL_00e8: ldstr "\ta{0}"
IL_00ed: ldc.i4.1
IL_00ee: newarr [mscorlib]System.Object
IL_00f3: dup
IL_00f4: ldc.i4.0
IL_00f5: ldarg.2
IL_00f6: ldc.i4.0
IL_00f7: ldelem.ref
IL_00f8: ldc.i4.0
IL_00f9: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_00fe: ldc.i4.s 97
IL_0100: ceq
IL_0102: box [mscorlib]System.Boolean
IL_0107: stelem.ref
IL_0108: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_010d: starg.s s
IL_010f: ldstr "\ta{0}"
IL_0114: ldc.i4.1
IL_0115: newarr [mscorlib]System.Object
IL_011a: dup
IL_011b: ldc.i4.0
IL_011c: ldstr "a{0}"
IL_0121: ldarg.2
IL_0122: ldlen
IL_0123: conv.i4
IL_0124: box [mscorlib]System.Int32
IL_0129: call string [mscorlib]System.String::Format(string,
object)
IL_012e: ldarg.2
IL_012f: ldc.i4.0
IL_0130: ldelem.ref
IL_0131: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0136: box [mscorlib]System.Boolean
IL_013b: stelem.ref
IL_013c: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0141: starg.s s
IL_0143: ldarg.0
IL_0144: ldstr "{0}"
IL_0149: ldarg.2
IL_014a: ldlen
IL_014b: conv.i4
IL_014c: box [mscorlib]System.Int32
IL_0151: call string [mscorlib]System.String::Format(string,
object)
IL_0156: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_015b: nop
IL_015c: ldarg.0
IL_015d: ldstr "a{{0{0}"
IL_0162: ldarg.2
IL_0163: ldlen
IL_0164: conv.i4
IL_0165: box [mscorlib]System.Int32
IL_016a: call string [mscorlib]System.String::Format(string,
object)
IL_016f: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_0174: nop
IL_0175: ldarg.0
IL_0176: ldstr "{0:x}"
IL_017b: ldarg.2
IL_017c: ldlen
IL_017d: conv.i4
IL_017e: box [mscorlib]System.Int32
IL_0183: call string [mscorlib]System.String::Format(string,
object)
IL_0188: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_018d: nop
IL_018e: ldarg.0
IL_018f: ldstr "\ta{0}b"
IL_0194: ldarg.2
IL_0195: ldlen
IL_0196: conv.i4
IL_0197: box [mscorlib]System.Int32
IL_019c: call string [mscorlib]System.String::Format(string,
object)
IL_01a1: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_01a6: nop
IL_01a7: ldarg.0
IL_01a8: ldstr "\ta{0}ba{1}a{2}a{3}"
IL_01ad: ldc.i4.4
IL_01ae: newarr [mscorlib]System.Object
IL_01b3: dup
IL_01b4: ldc.i4.0
IL_01b5: ldarg.2
IL_01b6: ldlen
IL_01b7: conv.i4
IL_01b8: box [mscorlib]System.Int32
IL_01bd: stelem.ref
IL_01be: dup
IL_01bf: ldc.i4.1
IL_01c0: ldarg.2
IL_01c1: ldc.i4.0
IL_01c2: ldelem.ref
IL_01c3: stelem.ref
IL_01c4: dup
IL_01c5: ldc.i4.2
IL_01c6: ldarg.2
IL_01c7: ldarg.2
IL_01c8: ldlen
IL_01c9: conv.i4
IL_01ca: ldelem.ref
IL_01cb: stelem.ref
IL_01cc: dup
IL_01cd: ldc.i4.3
IL_01ce: ldarg.2
IL_01cf: ldlen
IL_01d0: conv.i4
IL_01d1: box [mscorlib]System.Int32
IL_01d6: stelem.ref
IL_01d7: call string [mscorlib]System.String::Format(string,
object[])
IL_01dc: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_01e1: nop
IL_01e2: ldarg.0
IL_01e3: ldstr "\ta{0}"
IL_01e8: ldarg.2
IL_01e9: ldlen
IL_01ea: brtrue.s IL_01ef
IL_01ec: ldc.i4.0
IL_01ed: br.s IL_01f0
IL_01ef: ldc.i4.5
IL_01f0: box [mscorlib]System.Int32
IL_01f5: call string [mscorlib]System.String::Format(string,
object)
IL_01fa: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_01ff: nop
IL_0200: ldarg.0
IL_0201: ldstr "\ta{0}"
IL_0206: ldarg.2
IL_0207: dup
IL_0208: brtrue.s IL_020c
IL_020a: pop
IL_020b: ldarg.2
IL_020c: call string [mscorlib]System.String::Format(string,
object)
IL_0211: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_0216: nop
IL_0217: ldarg.0
IL_0218: ldstr "\ta{0}"
IL_021d: ldarg.2
IL_021e: ldc.i4.0
IL_021f: ldelem.ref
IL_0220: ldc.i4.0
IL_0221: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_0226: ldc.i4.s 97
IL_0228: ceq
IL_022a: box [mscorlib]System.Boolean
IL_022f: call string [mscorlib]System.String::Format(string,
object)
IL_0234: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_0239: nop
IL_023a: ldarg.0
IL_023b: ldstr "\ta{0}"
IL_0240: ldstr "a{0}"
IL_0245: ldarg.2
IL_0246: ldlen
IL_0247: conv.i4
IL_0248: box [mscorlib]System.Int32
IL_024d: call string [mscorlib]System.String::Format(string,
object)
IL_0252: ldarg.2
IL_0253: ldc.i4.0
IL_0254: ldelem.ref
IL_0255: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_025a: box [mscorlib]System.Boolean
IL_025f: call string [mscorlib]System.String::Format(string,
object)
IL_0264: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(string)
IL_0269: nop
IL_026a: ldarg.0
IL_026b: ldstr "{0}"
IL_0270: ldc.i4.1
IL_0271: newarr [mscorlib]System.Object
IL_0276: dup
IL_0277: ldc.i4.0
IL_0278: ldarg.2
IL_0279: ldlen
IL_027a: conv.i4
IL_027b: box [mscorlib]System.Int32
IL_0280: stelem.ref
IL_0281: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0286: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_028b: nop
IL_028c: ldarg.0
IL_028d: ldstr "a{{0{0}"
IL_0292: ldc.i4.1
IL_0293: newarr [mscorlib]System.Object
IL_0298: dup
IL_0299: ldc.i4.0
IL_029a: ldarg.2
IL_029b: ldlen
IL_029c: conv.i4
IL_029d: box [mscorlib]System.Int32
IL_02a2: stelem.ref
IL_02a3: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_02a8: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_02ad: nop
IL_02ae: ldarg.0
IL_02af: ldstr "{0:x}"
IL_02b4: ldc.i4.1
IL_02b5: newarr [mscorlib]System.Object
IL_02ba: dup
IL_02bb: ldc.i4.0
IL_02bc: ldarg.2
IL_02bd: ldlen
IL_02be: conv.i4
IL_02bf: box [mscorlib]System.Int32
IL_02c4: stelem.ref
IL_02c5: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_02ca: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_02cf: nop
IL_02d0: ldarg.0
IL_02d1: ldstr "\ta{0}b"
IL_02d6: ldc.i4.1
IL_02d7: newarr [mscorlib]System.Object
IL_02dc: dup
IL_02dd: ldc.i4.0
IL_02de: ldarg.2
IL_02df: ldlen
IL_02e0: conv.i4
IL_02e1: box [mscorlib]System.Int32
IL_02e6: stelem.ref
IL_02e7: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_02ec: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_02f1: nop
IL_02f2: ldarg.0
IL_02f3: ldstr "\ta{0}ba{1}a{2}a{3}"
IL_02f8: ldc.i4.4
IL_02f9: newarr [mscorlib]System.Object
IL_02fe: dup
IL_02ff: ldc.i4.0
IL_0300: ldarg.2
IL_0301: ldlen
IL_0302: conv.i4
IL_0303: box [mscorlib]System.Int32
IL_0308: stelem.ref
IL_0309: dup
IL_030a: ldc.i4.1
IL_030b: ldarg.2
IL_030c: ldc.i4.0
IL_030d: ldelem.ref
IL_030e: stelem.ref
IL_030f: dup
IL_0310: ldc.i4.2
IL_0311: ldarg.2
IL_0312: ldarg.2
IL_0313: ldlen
IL_0314: conv.i4
IL_0315: ldelem.ref
IL_0316: stelem.ref
IL_0317: dup
IL_0318: ldc.i4.3
IL_0319: ldarg.2
IL_031a: ldlen
IL_031b: conv.i4
IL_031c: box [mscorlib]System.Int32
IL_0321: stelem.ref
IL_0322: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0327: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_032c: nop
IL_032d: ldarg.0
IL_032e: ldstr "\ta{0}"
IL_0333: ldc.i4.1
IL_0334: newarr [mscorlib]System.Object
IL_0339: dup
IL_033a: ldc.i4.0
IL_033b: ldarg.2
IL_033c: ldlen
IL_033d: brtrue.s IL_0342
IL_033f: ldc.i4.0
IL_0340: br.s IL_0343
IL_0342: ldc.i4.5
IL_0343: box [mscorlib]System.Int32
IL_0348: stelem.ref
IL_0349: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_034e: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_0353: nop
IL_0354: ldarg.0
IL_0355: ldstr "\ta{0}"
IL_035a: ldc.i4.1
IL_035b: newarr [mscorlib]System.Object
IL_0360: dup
IL_0361: ldc.i4.0
IL_0362: ldarg.2
IL_0363: dup
IL_0364: brtrue.s IL_0368
IL_0366: pop
IL_0367: ldarg.2
IL_0368: stelem.ref
IL_0369: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_036e: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_0373: nop
IL_0374: ldarg.0
IL_0375: ldstr "\ta{0}"
IL_037a: ldc.i4.1
IL_037b: newarr [mscorlib]System.Object
IL_0380: dup
IL_0381: ldc.i4.0
IL_0382: ldarg.2
IL_0383: ldc.i4.0
IL_0384: ldelem.ref
IL_0385: ldc.i4.0
IL_0386: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_038b: ldc.i4.s 97
IL_038d: ceq
IL_038f: box [mscorlib]System.Boolean
IL_0394: stelem.ref
IL_0395: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_039a: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_039f: nop
IL_03a0: ldarg.0
IL_03a1: ldstr "\ta{0}"
IL_03a6: ldc.i4.1
IL_03a7: newarr [mscorlib]System.Object
IL_03ac: dup
IL_03ad: ldc.i4.0
IL_03ae: ldstr "a{0}"
IL_03b3: ldarg.2
IL_03b4: ldlen
IL_03b5: conv.i4
IL_03b6: box [mscorlib]System.Int32
IL_03bb: call string [mscorlib]System.String::Format(string,
object)
IL_03c0: ldarg.2
IL_03c1: ldc.i4.0
IL_03c2: ldelem.ref
IL_03c3: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_03c8: box [mscorlib]System.Boolean
IL_03cd: stelem.ref
IL_03ce: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_03d3: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.FormattableString)
IL_03d8: nop
IL_03d9: ldarg.0
IL_03da: ldstr "{0}"
IL_03df: ldc.i4.1
IL_03e0: newarr [mscorlib]System.Object
IL_03e5: dup
IL_03e6: ldc.i4.0
IL_03e7: ldarg.2
IL_03e8: ldlen
IL_03e9: conv.i4
IL_03ea: box [mscorlib]System.Int32
IL_03ef: stelem.ref
IL_03f0: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_03f5: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_03fa: nop
IL_03fb: ldarg.0
IL_03fc: ldstr "a{{0{0}"
IL_0401: ldc.i4.1
IL_0402: newarr [mscorlib]System.Object
IL_0407: dup
IL_0408: ldc.i4.0
IL_0409: ldarg.2
IL_040a: ldlen
IL_040b: conv.i4
IL_040c: box [mscorlib]System.Int32
IL_0411: stelem.ref
IL_0412: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0417: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_041c: nop
IL_041d: ldarg.0
IL_041e: ldstr "{0:x}"
IL_0423: ldc.i4.1
IL_0424: newarr [mscorlib]System.Object
IL_0429: dup
IL_042a: ldc.i4.0
IL_042b: ldarg.2
IL_042c: ldlen
IL_042d: conv.i4
IL_042e: box [mscorlib]System.Int32
IL_0433: stelem.ref
IL_0434: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0439: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_043e: nop
IL_043f: ldarg.0
IL_0440: ldstr "\ta{0}b"
IL_0445: ldc.i4.1
IL_0446: newarr [mscorlib]System.Object
IL_044b: dup
IL_044c: ldc.i4.0
IL_044d: ldarg.2
IL_044e: ldlen
IL_044f: conv.i4
IL_0450: box [mscorlib]System.Int32
IL_0455: stelem.ref
IL_0456: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_045b: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_0460: nop
IL_0461: ldarg.0
IL_0462: ldstr "\ta{0}ba{1}a{2}a{3}"
IL_0467: ldc.i4.4
IL_0468: newarr [mscorlib]System.Object
IL_046d: dup
IL_046e: ldc.i4.0
IL_046f: ldarg.2
IL_0470: ldlen
IL_0471: conv.i4
IL_0472: box [mscorlib]System.Int32
IL_0477: stelem.ref
IL_0478: dup
IL_0479: ldc.i4.1
IL_047a: ldarg.2
IL_047b: ldc.i4.0
IL_047c: ldelem.ref
IL_047d: stelem.ref
IL_047e: dup
IL_047f: ldc.i4.2
IL_0480: ldarg.2
IL_0481: ldarg.2
IL_0482: ldlen
IL_0483: conv.i4
IL_0484: ldelem.ref
IL_0485: stelem.ref
IL_0486: dup
IL_0487: ldc.i4.3
IL_0488: ldarg.2
IL_0489: ldlen
IL_048a: conv.i4
IL_048b: box [mscorlib]System.Int32
IL_0490: stelem.ref
IL_0491: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0496: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_049b: nop
IL_049c: ldarg.0
IL_049d: ldstr "\ta{0}"
IL_04a2: ldc.i4.1
IL_04a3: newarr [mscorlib]System.Object
IL_04a8: dup
IL_04a9: ldc.i4.0
IL_04aa: ldarg.2
IL_04ab: ldlen
IL_04ac: brtrue.s IL_04b1
IL_04ae: ldc.i4.0
IL_04af: br.s IL_04b2
IL_04b1: ldc.i4.5
IL_04b2: box [mscorlib]System.Int32
IL_04b7: stelem.ref
IL_04b8: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_04bd: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_04c2: nop
IL_04c3: ldarg.0
IL_04c4: ldstr "\ta{0}"
IL_04c9: ldc.i4.1
IL_04ca: newarr [mscorlib]System.Object
IL_04cf: dup
IL_04d0: ldc.i4.0
IL_04d1: ldarg.2
IL_04d2: dup
IL_04d3: brtrue.s IL_04d7
IL_04d5: pop
IL_04d6: ldarg.2
IL_04d7: stelem.ref
IL_04d8: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_04dd: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_04e2: nop
IL_04e3: ldarg.0
IL_04e4: ldstr "\ta{0}"
IL_04e9: ldc.i4.1
IL_04ea: newarr [mscorlib]System.Object
IL_04ef: dup
IL_04f0: ldc.i4.0
IL_04f1: ldarg.2
IL_04f2: ldc.i4.0
IL_04f3: ldelem.ref
IL_04f4: ldc.i4.0
IL_04f5: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_04fa: ldc.i4.s 97
IL_04fc: ceq
IL_04fe: box [mscorlib]System.Boolean
IL_0503: stelem.ref
IL_0504: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0509: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_050e: nop
IL_050f: ldarg.0
IL_0510: ldstr "\ta{0}"
IL_0515: ldc.i4.1
IL_0516: newarr [mscorlib]System.Object
IL_051b: dup
IL_051c: ldc.i4.0
IL_051d: ldstr "a{0}"
IL_0522: ldarg.2
IL_0523: ldlen
IL_0524: conv.i4
IL_0525: box [mscorlib]System.Int32
IL_052a: call string [mscorlib]System.String::Format(string,
object)
IL_052f: ldarg.2
IL_0530: ldc.i4.0
IL_0531: ldelem.ref
IL_0532: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0537: box [mscorlib]System.Boolean
IL_053c: stelem.ref
IL_053d: call class [mscorlib]System.FormattableString [mscorlib]System.Runtime.CompilerServices.FormattableStringFactory::Create(string,
object[])
IL_0542: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CS6_StringInterpolation::RequiresCast(class [mscorlib]System.IFormattable)
IL_0547: nop
IL_0548: ret
} // end of method CS6_StringInterpolation::FormattableStrings
.method public hidebysig instance void
RequiresCast(string 'value') cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method CS6_StringInterpolation::RequiresCast
.method public hidebysig instance void
RequiresCast(class [mscorlib]System.FormattableString 'value') cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method CS6_StringInterpolation::RequiresCast
.method public hidebysig instance void
RequiresCast(class [mscorlib]System.IFormattable 'value') cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method CS6_StringInterpolation::RequiresCast
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

160
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -21,6 +21,7 @@ using System.Collections.Generic; @@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.IL;
@ -234,6 +235,38 @@ namespace ICSharpCode.Decompiler.CSharp @@ -234,6 +235,38 @@ namespace ICSharpCode.Decompiler.CSharp
argumentList.GetArgumentResolveResults().ToList(), isExpandedForm: argumentList.IsExpandedForm));
}
if (settings.StringInterpolation && IsInterpolatedStringCreation(method) &&
TryGetStringInterpolationTokens(argumentList, out string format, out var tokens))
{
var arguments = argumentList.Arguments;
var content = new List<InterpolatedStringContent>();
if (tokens.Count > 0) {
foreach (var (kind, index, text) in tokens) {
switch (kind) {
case TokenKind.String:
content.Add(new InterpolatedStringText(text));
break;
case TokenKind.Argument:
content.Add(new Interpolation(arguments[index + 1]));
break;
case TokenKind.ArgumentWithFormat:
content.Add(new Interpolation(arguments[index + 1], text));
break;
}
}
var formattableStringType = expressionBuilder.compilation.FindType(KnownTypeCode.FormattableString);
var isrr = new InterpolatedStringResolveResult(expressionBuilder.compilation.FindType(KnownTypeCode.String),
format, argumentList.GetArgumentResolveResults().Skip(1).ToArray());
var expr = new InterpolatedStringExpression();
expr.Content.AddRange(content);
if (method.Name == "Format")
return expr.WithRR(isrr);
return new CastExpression(expressionBuilder.ConvertType(formattableStringType),
expr.WithRR(isrr))
.WithRR(new ConversionResolveResult(formattableStringType, isrr, Conversion.ImplicitInterpolatedStringConversion));
}
}
int allowedParamCount = (method.ReturnType.IsKnownType(KnownTypeCode.Void) ? 1 : 0);
if (method.IsAccessor && (method.AccessorOwner.SymbolKind == SymbolKind.Indexer || argumentList.ExpectedParameters.Length == allowedParamCount)) {
argumentList.CheckNoNamedOrOptionalArguments();
@ -350,6 +383,133 @@ namespace ICSharpCode.Decompiler.CSharp @@ -350,6 +383,133 @@ namespace ICSharpCode.Decompiler.CSharp
isExtensionMethodInvocation: method.IsExtensionMethod, isExpandedForm: argumentList.IsExpandedForm));
}
private bool IsInterpolatedStringCreation(IMethod method)
{
return method.IsStatic && (
(method.DeclaringType.IsKnownType(KnownTypeCode.String) && method.Name == "Format") ||
(method.Name == "Create" && method.DeclaringType.Name == "FormattableStringFactory" &&
method.DeclaringType.Namespace == "System.Runtime.CompilerServices")
);
}
private bool TryGetStringInterpolationTokens(ArgumentList argumentList, out string format, out List<(TokenKind, int, string)> tokens)
{
tokens = null;
format = null;
TranslatedExpression[] arguments = argumentList.Arguments;
if (arguments.Length == 0 || argumentList.ArgumentNames != null || argumentList.ArgumentToParameterMap != null)
return false;
if (!(arguments[(int)0].ResolveResult is ConstantResolveResult crr && crr.Type.IsKnownType((KnownTypeCode)KnownTypeCode.String)))
return false;
if (!arguments.Skip(1).All(a => !a.Expression.DescendantsAndSelf.OfType<PrimitiveExpression>().Any(p => p.Value is string)))
return false;
tokens = new List<(TokenKind, int, string)>();
int i = 0;
format = (string)crr.ConstantValue;
foreach (var (kind, data) in TokenizeFormatString(format)) {
int index;
switch (kind) {
case TokenKind.Error:
return false;
case TokenKind.String:
tokens.Add((kind, -1, data));
break;
case TokenKind.Argument:
if (!int.TryParse(data, out index) || index != i)
return false;
i++;
tokens.Add((kind, index, null));
break;
case TokenKind.ArgumentWithFormat:
string[] arg = data.Split(new[] { ':' }, 2);
if (arg.Length != 2 || arg[1].Length == 0)
return false;
if (!int.TryParse(arg[0], out index) || index != i)
return false;
i++;
tokens.Add((kind, index, arg[1]));
break;
default:
return false;
}
}
return i == arguments.Length - 1;
}
private enum TokenKind
{
Error,
String,
Argument,
ArgumentWithFormat
}
private IEnumerable<(TokenKind, string)> TokenizeFormatString(string value)
{
int pos = -1;
int Peek(int steps = 1)
{
if (pos + steps < value.Length)
return value[pos + steps];
return -1;
}
int Next()
{
int val = Peek();
pos++;
return val;
}
int next;
TokenKind kind = TokenKind.String;
StringBuilder sb = new StringBuilder();
while ((next = Next()) > -1) {
switch ((char)next) {
case '{':
if (Peek() == '{') {
kind = TokenKind.String;
sb.Append("{{");
Next();
} else {
if (sb.Length > 0) {
yield return (kind, sb.ToString());
}
kind = TokenKind.Argument;
sb.Clear();
}
break;
case '}':
if (kind != TokenKind.String) {
yield return (kind, sb.ToString());
sb.Clear();
kind = TokenKind.String;
} else {
sb.Append((char)next);
}
break;
case ':':
if (kind == TokenKind.Argument) {
kind = TokenKind.ArgumentWithFormat;
}
sb.Append(':');
break;
default:
sb.Append((char)next);
break;
}
}
if (sb.Length > 0) {
if (kind == TokenKind.String)
yield return (kind, sb.ToString());
else
yield return (TokenKind.Error, null);
}
}
private ArgumentList BuildArgumentList(ExpectedTargetDetails expectedTargetDetails, ResolveResult target, IMethod method, int firstParamIndex,
IReadOnlyList<ILInstruction> callArguments, IReadOnlyList<int> argumentToParameterMap)
{

5
ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs

@ -329,6 +329,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -329,6 +329,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
// Conditional operator
public override void VisitConditionalExpression(ConditionalExpression conditionalExpression)
{
// Inside of string interpolation ?: always needs parentheses.
if (conditionalExpression.Parent is Interpolation) {
Parenthesize(conditionalExpression);
}
// Associativity here is a bit tricky:
// (a ? b : c ? d : e) == (a ? b : (c ? d : e))
// (a ? b ? c : d : e) == (a ? (b ? c : d) : e)

4
ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

@ -123,6 +123,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -123,6 +123,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
if (c != Conversion.None) return c;
}
if (resolveResult is InterpolatedStringResolveResult isrr) {
if (toType.IsKnownType(KnownTypeCode.IFormattable) || toType.IsKnownType(KnownTypeCode.FormattableString))
return Conversion.ImplicitInterpolatedStringConversion;
}
if (resolveResult.Type.Kind == TypeKind.Dynamic)
return Conversion.ImplicitDynamicConversion;
c = AnonymousFunctionConversion(resolveResult, toType);

139
ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs

@ -110,65 +110,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -110,65 +110,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
invocationExpression.ReplaceWith(new ObjectCreateExpression(context.TypeSystemAstBuilder.ConvertType(method.TypeArguments.First())));
}
break;
case "System.String.Format":
if (context.Settings.StringInterpolation && arguments.Length > 1
&& arguments[0] is PrimitiveExpression stringExpression && stringExpression.Value is string
&& arguments.Skip(1).All(a => !a.DescendantsAndSelf.OfType<PrimitiveExpression>().Any(p => p.Value is string)))
{
var tokens = new List<(TokenKind, int, string)>();
int i = 0;
foreach (var (kind, data) in TokenizeFormatString((string)stringExpression.Value)) {
int index;
switch (kind) {
case TokenKind.Error:
return;
case TokenKind.String:
tokens.Add((kind, -1, data));
break;
case TokenKind.Argument:
if (!int.TryParse(data, out index) || index != i)
return;
i++;
tokens.Add((kind, index, null));
break;
case TokenKind.ArgumentWithFormat:
string[] arg = data.Split(new[] { ':' }, 2);
if (arg.Length != 2 || arg[1].Length == 0)
return;
if (!int.TryParse(arg[0], out index) || index != i)
return;
i++;
tokens.Add((kind, index, arg[1]));
break;
default:
return;
}
}
if (i != arguments.Length - 1)
return;
List<InterpolatedStringContent> content = new List<InterpolatedStringContent>();
if (tokens.Count > 0) {
foreach (var (kind, index, text) in tokens) {
switch (kind) {
case TokenKind.String:
content.Add(new InterpolatedStringText(text));
break;
case TokenKind.Argument:
content.Add(new Interpolation(WrapInParens(arguments[index + 1].Detach())));
break;
case TokenKind.ArgumentWithFormat:
content.Add(new Interpolation(WrapInParens(arguments[index + 1].Detach()), text));
break;
}
}
var expr = new InterpolatedStringExpression();
expr.Content.AddRange(content);
expr.CopyAnnotationsFrom(invocationExpression);
invocationExpression.ReplaceWith(expr);
return;
}
}
break;
}
BinaryOperatorType? bop = GetBinaryOperatorTypeFromMetadataName(method.Name);
@ -208,86 +149,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -208,86 +149,6 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return type is ITypeParameter tp && tp.HasDefaultConstructorConstraint;
}
Expression WrapInParens(Expression expression)
{
if (expression is ConditionalExpression)
return new ParenthesizedExpression(expression);
return expression;
}
enum TokenKind
{
Error,
String,
Argument,
ArgumentWithFormat
}
private IEnumerable<(TokenKind, string)> TokenizeFormatString(string value)
{
int pos = -1;
int Peek(int steps = 1)
{
if (pos + steps < value.Length)
return value[pos + steps];
return -1;
}
int Next()
{
int val = Peek();
pos++;
return val;
}
int next;
TokenKind kind = TokenKind.String;
StringBuilder sb = new StringBuilder();
while ((next = Next()) > -1) {
switch ((char)next) {
case '{':
if (Peek() == '{') {
kind = TokenKind.String;
sb.Append("{{");
Next();
} else {
if (sb.Length > 0) {
yield return (kind, sb.ToString());
}
kind = TokenKind.Argument;
sb.Clear();
}
break;
case '}':
if (kind != TokenKind.String) {
yield return (kind, sb.ToString());
sb.Clear();
kind = TokenKind.String;
} else {
sb.Append((char)next);
}
break;
case ':':
if (kind == TokenKind.Argument) {
kind = TokenKind.ArgumentWithFormat;
}
sb.Append(':');
break;
default:
sb.Append((char)next);
break;
}
}
if (sb.Length > 0) {
if (kind == TokenKind.String)
yield return (kind, sb.ToString());
else
yield return (TokenKind.Error, null);
}
}
bool CheckArgumentsForStringConcat(Expression[] arguments)
{
if (arguments.Length < 2)

18
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -179,10 +179,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -179,10 +179,10 @@ namespace ICSharpCode.Decompiler.CSharp
switch (ResolveResult) {
case ConversionResolveResult conversion: {
if (Expression is CastExpression cast
&& (type.IsKnownType(KnownTypeCode.Object) && conversion.Conversion.IsBoxingConversion
&& ((type.IsKnownType(KnownTypeCode.Object) && conversion.Conversion.IsBoxingConversion
|| conversion.Conversion.IsAnonymousFunctionConversion
|| (conversion.Conversion.IsImplicit && (conversion.Conversion.IsUserDefined || targetType.IsKnownType(KnownTypeCode.Decimal)))
)) {
) || (conversion.Conversion.IsInterpolatedStringConversion))) {
return this.UnwrapChild(cast.Expression);
} else if (Expression is ObjectCreateExpression oce && conversion.Conversion.IsMethodGroupConversion
&& oce.Arguments.Count == 1 && expressionBuilder.settings.UseImplicitMethodGroupConversion) {
@ -220,7 +220,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -220,7 +220,9 @@ namespace ICSharpCode.Decompiler.CSharp
}
var compilation = expressionBuilder.compilation;
var conversions = Resolver.CSharpConversions.Get(compilation);
if (ResolveResult is ConversionResolveResult conv && Expression is CastExpression cast2 && conv.Conversion.IsBoxingConversion && conversions.IsBoxingConversion(conv.Input.Type, targetType)) {
if (ResolveResult is ConversionResolveResult conv && Expression is CastExpression cast2 &&
IsBoxingOrInterpolatedStringConversion(conversions, conv.Conversion, conv.Input.Type, targetType))
{
var unwrapped = this.UnwrapChild(cast2.Expression);
if (allowImplicitConversion)
return unwrapped;
@ -384,6 +386,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -384,6 +386,16 @@ namespace ICSharpCode.Decompiler.CSharp
}
return castExpr.WithoutILInstruction().WithRR(rr);
}
bool IsBoxingOrInterpolatedStringConversion(Resolver.CSharpConversions conversions, Conversion conversion, IType inputType, IType targetType)
{
if (conversion.IsBoxingConversion && conversions.IsBoxingConversion(inputType, targetType))
return true;
if (conversion.IsInterpolatedStringConversion && (targetType.IsKnownType(KnownTypeCode.FormattableString)
|| targetType.IsKnownType(KnownTypeCode.IFormattable)))
return true;
return false;
}
TranslatedExpression LdcI4(ICompilation compilation, int val)
{

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -343,6 +343,7 @@ @@ -343,6 +343,7 @@
<Compile Include="Output\TextTokenWriter.cs" />
<Compile Include="DebugInfo\IDebugInfoProvider.cs" />
<Compile Include="DebugInfo\PortablePdbWriter.cs" />
<Compile Include="Semantics\InterpolatedStringResolveResult.cs" />
<Compile Include="SRMExtensions.cs" />
<Compile Include="SRMHacks.cs" />
<Compile Include="TypeSystem\ApplyAttributeTypeVisitor.cs" />

17
ICSharpCode.Decompiler/Semantics/Conversion.cs

@ -70,12 +70,14 @@ namespace ICSharpCode.Decompiler.Semantics @@ -70,12 +70,14 @@ namespace ICSharpCode.Decompiler.Semantics
public static readonly Conversion BoxingConversion = new BuiltinConversion(true, 7);
public static readonly Conversion UnboxingConversion = new BuiltinConversion(false, 8);
/// <summary>
/// C# 'as' cast.
/// </summary>
public static readonly Conversion TryCast = new BuiltinConversion(false, 9);
public static readonly Conversion ImplicitInterpolatedStringConversion = new BuiltinConversion(true, 10);
public static Conversion UserDefinedConversion(IMethod operatorMethod, bool isImplicit, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted = false, bool isAmbiguous = false)
{
if (operatorMethod == null)
@ -227,7 +229,9 @@ namespace ICSharpCode.Decompiler.Semantics @@ -227,7 +229,9 @@ namespace ICSharpCode.Decompiler.Semantics
public override bool IsTryCast {
get { return type == 9; }
}
public override bool IsInterpolatedStringConversion => type == 10;
public override string ToString()
{
string name = null;
@ -257,6 +261,8 @@ namespace ICSharpCode.Decompiler.Semantics @@ -257,6 +261,8 @@ namespace ICSharpCode.Decompiler.Semantics
return "unboxing conversion";
case 9:
return "try cast";
case 10:
return "interpolated string";
}
return (isImplicit ? "implicit " : "explicit ") + name + " conversion";
}
@ -583,6 +589,11 @@ namespace ICSharpCode.Decompiler.Semantics @@ -583,6 +589,11 @@ namespace ICSharpCode.Decompiler.Semantics
/// </summary>
public virtual bool IsTupleConversion => false;
/// <summary>
/// Gets whether this is an interpolated string conversion to <see cref="IFormattable" /> or <see cref="FormattableString"/>.
/// </summary>
public virtual bool IsInterpolatedStringConversion => false;
/// <summary>
/// For a tuple conversion, gets the individual tuple element conversions.
/// </summary>

42
ICSharpCode.Decompiler/Semantics/InterpolatedStringResolveResult.cs

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
// Copyright (c) 2018 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.Semantics
{
public class InterpolatedStringResolveResult : ResolveResult
{
public readonly string FormatString;
public readonly ResolveResult[] Arguments;
public InterpolatedStringResolveResult(IType stringType, string formatString, params ResolveResult[] arguments)
: base(stringType)
{
FormatString = formatString;
Arguments = arguments;
}
public override IEnumerable<ResolveResult> GetChildResults()
{
return Arguments;
}
}
}

10
ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs

@ -125,6 +125,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -125,6 +125,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
ICriticalNotifyCompletion,
/// <summary><c>System.TypedReference</c></summary>
TypedReference,
/// <summary><c>System.IFormattable</c></summary>
IFormattable,
/// <summary><c>System.FormattableString</c></summary>
FormattableString,
}
/// <summary>
@ -133,7 +137,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -133,7 +137,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
[Serializable]
public sealed class KnownTypeReference : ITypeReference
{
internal const int KnownTypeCodeCount = (int)KnownTypeCode.TypedReference + 1;
internal const int KnownTypeCodeCount = (int)KnownTypeCode.FormattableString + 1;
static readonly KnownTypeReference[] knownTypeReferences = new KnownTypeReference[KnownTypeCodeCount] {
null, // None
@ -184,7 +188,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -184,7 +188,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
new KnownTypeReference(KnownTypeCode.INotifyCompletion, TypeKind.Interface, "System.Runtime.CompilerServices", "INotifyCompletion"),
new KnownTypeReference(KnownTypeCode.ICriticalNotifyCompletion, TypeKind.Interface, "System.Runtime.CompilerServices", "ICriticalNotifyCompletion"),
new KnownTypeReference(KnownTypeCode.TypedReference, TypeKind.Struct, "System", "TypedReference"),
new KnownTypeReference(KnownTypeCode.TypedReference, TypeKind.Struct, "System", "TypedReference"),
new KnownTypeReference(KnownTypeCode.IFormattable, TypeKind.Interface, "System", "IFormattable"),
new KnownTypeReference(KnownTypeCode.FormattableString, TypeKind.Class, "System", "FormattableString", baseType: KnownTypeCode.IFormattable),
};
/// <summary>

Loading…
Cancel
Save