PageRenderTime 42ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Compilers/CSharp/Test/Symbol/Symbols/AnonymousTypesSemanticsTests.cs

https://github.com/EkardNT/Roslyn
C# | 991 lines | 841 code | 132 blank | 18 comment | 15 complexity | 06a7f6fc5f26b5077e644e5aa8a8d2de MD5 | raw file
  1. // Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Microsoft.CodeAnalysis.CSharp.Symbols;
  6. using Microsoft.CodeAnalysis.CSharp.Syntax;
  7. using Microsoft.CodeAnalysis.Test.Utilities;
  8. using Microsoft.CodeAnalysis.Text;
  9. using Roslyn.Test.Utilities;
  10. using Xunit;
  11. namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols
  12. {
  13. public class AnonymousTypesSemanticsTests : CompilingTestBase
  14. {
  15. [Fact()]
  16. public void AnonymousTypeSymbols_Simple()
  17. {
  18. var source = @"
  19. public class ClassA
  20. {
  21. public struct SSS
  22. {
  23. }
  24. public static void Test1(int x)
  25. {
  26. object v1 = [# new
  27. {
  28. [# aa #] = 1,
  29. [# BB #] = """",
  30. [# CCC #] = new SSS()
  31. } #];
  32. object v2 = [# new
  33. {
  34. [# aa #] = new SSS(),
  35. [# BB #] = 123.456,
  36. [# CCC #] = [# new
  37. {
  38. (new ClassA()).[# aa #],
  39. ClassA.[# BB #],
  40. ClassA.[# CCC #]
  41. } #]
  42. } #];
  43. object v3 = [# new {} #];
  44. var v4 = [# new {} #];
  45. }
  46. public int aa
  47. {
  48. get { return 123; }
  49. }
  50. public const string BB = ""-=-=-"";
  51. public static SSS CCC = new SSS();
  52. }";
  53. var data = Compile(source, 14);
  54. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  55. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  56. 1, 2, 3);
  57. var info1 = GetAnonymousTypeInfoSummary(data, 4,
  58. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 3).Span,
  59. 5, 6, 7);
  60. var info2 = GetAnonymousTypeInfoSummary(data, 8,
  61. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 5).Span,
  62. 9, 10, 11);
  63. Assert.Equal(info0.Type, info2.Type);
  64. Assert.NotEqual(info0.Type, info1.Type);
  65. var info3 = GetAnonymousTypeInfoSummary(data, 12,
  66. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 7).Span);
  67. var info4 = GetAnonymousTypeInfoSummary(data, 13,
  68. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 8).Span);
  69. Assert.Equal(info3.Type, info4.Type);
  70. }
  71. [Fact()]
  72. public void AnonymousTypeSymbols_ContextualKeywordsInFields()
  73. {
  74. var source = @"
  75. class ClassA
  76. {
  77. static void Test1(int x)
  78. {
  79. object v1 = [# new
  80. {
  81. [# var #] = ""var"",
  82. [# get #] = new {},
  83. [# partial #] = [# new
  84. {
  85. (new ClassA()).[# select #],
  86. [# global #]
  87. } #]
  88. } #];
  89. }
  90. public int select
  91. {
  92. get { return 123; }
  93. }
  94. public const string global = ""-=-=-"";
  95. }";
  96. var data = Compile(source, 7);
  97. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  98. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  99. 1, 2, 3);
  100. var info1 = GetAnonymousTypeInfoSummary(data, 4,
  101. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 3).Span,
  102. 5, 6);
  103. Assert.Equal(
  104. "<anonymous type: System.String var, <empty anonymous type> get, <anonymous type: System.Int32 select, System.String global> partial>",
  105. info0.Type.ToTestDisplayString());
  106. Assert.Equal(
  107. "<anonymous type: System.Int32 select, System.String global>..ctor(System.Int32 select, System.String global)",
  108. info1.Symbol.ToTestDisplayString());
  109. }
  110. [Fact()]
  111. public void AnonymousTypeSymbols_DelegateMembers()
  112. {
  113. var source = @"
  114. delegate bool D1();
  115. class ClassA
  116. {
  117. void Main()
  118. {
  119. var at1 = [# new { [# module #] = (D1)(() => false)} #].module();
  120. }
  121. }";
  122. var data = Compile(source, 2);
  123. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  124. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  125. 1);
  126. Assert.Equal("<anonymous type: D1 module>", info0.Type.ToTestDisplayString());
  127. Assert.Equal("<anonymous type: D1 module>..ctor(D1 module)", info0.Symbol.ToTestDisplayString());
  128. }
  129. [Fact()]
  130. public void AnonymousTypeSymbols_BaseAccessInMembers()
  131. {
  132. var source = @"
  133. delegate bool D1();
  134. class ClassB
  135. {
  136. protected System.Func<int, int> F = x => x;
  137. }
  138. class ClassA: ClassB
  139. {
  140. void Main()
  141. {
  142. var at1 = [# [# new { base.[# F #] } #].F(1) #];
  143. }
  144. }";
  145. var data = Compile(source, 3);
  146. var info0 = GetAnonymousTypeInfoSummary(data, 1,
  147. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  148. 2);
  149. Assert.Equal("<anonymous type: System.Func<System.Int32, System.Int32> F>", info0.Type.ToTestDisplayString());
  150. var info1 = data.Model.GetSemanticInfoSummary(data.Nodes[0]);
  151. Assert.Equal("System.Int32 System.Func<System.Int32, System.Int32>.Invoke(System.Int32 arg)", info1.Symbol.ToTestDisplayString());
  152. }
  153. [Fact()]
  154. public void AnonymousTypeSymbols_InFieldInitializer()
  155. {
  156. var source = @"
  157. class ClassA
  158. {
  159. private static object F = [# new { [# F123 #] = typeof(ClassA) } #];
  160. }";
  161. var data = Compile(source, 2);
  162. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  163. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  164. 1);
  165. Assert.Equal("<anonymous type: System.Type F123>", info0.Type.ToTestDisplayString());
  166. }
  167. [Fact()]
  168. public void AnonymousTypeSymbols_Equals()
  169. {
  170. var source = @"
  171. class ClassA
  172. {
  173. static void Test1(int x)
  174. {
  175. bool result = [# new { f1 = 1, f2 = """" }.Equals(new { }) #];
  176. }
  177. }";
  178. var data = Compile(source, 1);
  179. var info = data.Model.GetSemanticInfoSummary(data.Nodes[0]);
  180. var method = info.Symbol;
  181. Assert.NotNull(method);
  182. Assert.Equal(SymbolKind.Method, method.Kind);
  183. Assert.Equal("object.Equals(object)", method.ToDisplayString());
  184. }
  185. [Fact()]
  186. public void AnonymousTypeSymbols_ToString()
  187. {
  188. var source = @"
  189. class ClassA
  190. {
  191. static void Test1(int x)
  192. {
  193. string result = [# new { f1 = 1, f2 = """" }.ToString() #];
  194. }
  195. }";
  196. var data = Compile(source, 1);
  197. var info = data.Model.GetSemanticInfoSummary(data.Nodes[0]);
  198. var method = info.Symbol;
  199. Assert.NotNull(method);
  200. Assert.Equal(SymbolKind.Method, method.Kind);
  201. Assert.Equal("object.ToString()", method.ToDisplayString());
  202. }
  203. [Fact()]
  204. public void AnonymousTypeSymbols_GetHashCode()
  205. {
  206. var source = @"
  207. class ClassA
  208. {
  209. static void Test1(int x)
  210. {
  211. int result = [# new { f1 = 1, f2 = """" }.GetHashCode() #];
  212. }
  213. }";
  214. var data = Compile(source, 1);
  215. var info = data.Model.GetSemanticInfoSummary(data.Nodes[0]);
  216. var method = info.Symbol;
  217. Assert.NotNull(method);
  218. Assert.Equal(SymbolKind.Method, method.Kind);
  219. Assert.Equal("object.GetHashCode()", method.ToDisplayString());
  220. }
  221. [Fact()]
  222. public void AnonymousTypeSymbols_Ctor()
  223. {
  224. var source = @"
  225. class ClassA
  226. {
  227. static void Test1(int x)
  228. {
  229. var result = [# new { f1 = 1, f2 = """" } #];
  230. }
  231. }";
  232. var data = Compile(source, 1);
  233. var info = data.Model.GetSemanticInfoSummary(data.Nodes[0]);
  234. var method = info.Symbol;
  235. Assert.NotNull(method);
  236. Assert.Equal(SymbolKind.Method, method.Kind);
  237. Assert.Equal("<anonymous type: int f1, string f2>..ctor(int, string)", method.ToDisplayString());
  238. Assert.Equal("<anonymous type: System.Int32 f1, System.String f2>..ctor(System.Int32 f1, System.String f2)", method.ToTestDisplayString());
  239. }
  240. [Fact()]
  241. public void AnonymousTypeTemplateCannotConstruct()
  242. {
  243. var source = @"
  244. class ClassA
  245. {
  246. object F = [# new { [# F123 #] = typeof(ClassA) } #];
  247. }";
  248. var data = Compile(source, 2);
  249. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  250. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  251. 1);
  252. var type = info0.Type;
  253. Assert.Equal("<anonymous type: System.Type F123>", type.ToTestDisplayString());
  254. Assert.True(type.IsDefinition);
  255. AssertCannotConstruct(type);
  256. }
  257. [Fact()]
  258. public void AnonymousTypeTemplateCannotConstruct_Empty()
  259. {
  260. var source = @"
  261. class ClassA
  262. {
  263. object F = [# new { } #];
  264. }";
  265. var data = Compile(source, 1);
  266. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  267. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span);
  268. var type = info0.Type;
  269. Assert.Equal("<empty anonymous type>", type.ToTestDisplayString());
  270. Assert.True(type.IsDefinition);
  271. AssertCannotConstruct(type);
  272. }
  273. [Fact()]
  274. public void AnonymousTypeFieldDeclarationIdentifier()
  275. {
  276. var source = @"
  277. class ClassA
  278. {
  279. object F = new { [# F123 #] = typeof(ClassA) };
  280. }";
  281. var data = Compile(source, 1);
  282. var info = data.Model.GetSymbolInfo((ExpressionSyntax)data.Nodes[0]);
  283. Assert.NotNull(info.Symbol);
  284. Assert.Equal(SymbolKind.Property, info.Symbol.Kind);
  285. Assert.Equal("System.Type <anonymous type: System.Type F123>.F123 { get; }", info.Symbol.ToTestDisplayString());
  286. }
  287. [Fact()]
  288. public void AnonymousTypeFieldCreatedInQuery()
  289. {
  290. var source = LINQ + @"
  291. class ClassA
  292. {
  293. void m()
  294. {
  295. var o = from x in new List1<int>(1, 2, 3) select [# new { [# x #], [# y #] = x } #];
  296. }
  297. }";
  298. var data = Compile(source, 3);
  299. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  300. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, NumberOfNewKeywords(LINQ) + 2).Span,
  301. 1, 2);
  302. var info1 = data.Model.GetSymbolInfo(((AnonymousObjectMemberDeclaratorSyntax)data.Nodes[1]).Expression);
  303. Assert.NotNull(info1.Symbol);
  304. Assert.Equal(SymbolKind.RangeVariable, info1.Symbol.Kind);
  305. Assert.Equal("x", info1.Symbol.ToDisplayString());
  306. var info2 = data.Model.GetSymbolInfo((ExpressionSyntax)data.Nodes[2]);
  307. Assert.NotNull(info2.Symbol);
  308. Assert.Equal(SymbolKind.Property, info2.Symbol.Kind);
  309. Assert.Equal("System.Int32 <anonymous type: System.Int32 x, System.Int32 y>.y { get; }", info2.Symbol.ToTestDisplayString());
  310. }
  311. [Fact()]
  312. public void AnonymousTypeFieldCreatedInQuery2()
  313. {
  314. var source = LINQ + @"
  315. class ClassA
  316. {
  317. void m()
  318. {
  319. var o = from x in new List1<int>(1, 2, 3) let y = """" select [# new { [# x #], [# y #] } #];
  320. }
  321. }";
  322. var data = Compile(source, 3);
  323. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  324. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, NumberOfNewKeywords(LINQ) + 2).Span,
  325. 1, 2);
  326. Assert.Equal("<anonymous type: System.Int32 x, System.String y>", info0.Type.ToTestDisplayString());
  327. var info1 = data.Model.GetSymbolInfo(((AnonymousObjectMemberDeclaratorSyntax)data.Nodes[1]).Expression);
  328. Assert.NotNull(info1.Symbol);
  329. Assert.Equal(SymbolKind.RangeVariable, info1.Symbol.Kind);
  330. Assert.Equal("x", info1.Symbol.ToDisplayString());
  331. var info2 = data.Model.GetSymbolInfo(((AnonymousObjectMemberDeclaratorSyntax)data.Nodes[2]).Expression);
  332. Assert.NotNull(info2.Symbol);
  333. Assert.Equal(SymbolKind.RangeVariable, info2.Symbol.Kind);
  334. Assert.Equal("y", info2.Symbol.ToDisplayString());
  335. }
  336. [Fact()]
  337. public void AnonymousTypeFieldCreatedInLambda()
  338. {
  339. var source = @"
  340. using System;
  341. class ClassA
  342. {
  343. void m()
  344. {
  345. var o = (Action)(() => ( [# new { [# x #] = 1, [# y #] = [# new { } #] } #]).ToString());;
  346. }
  347. }";
  348. var data = Compile(source, 4);
  349. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  350. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  351. 1, 2);
  352. var info1 = GetAnonymousTypeInfoSummary(data, 3,
  353. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 2).Span);
  354. Assert.Equal("<anonymous type: System.Int32 x, <empty anonymous type> y>..ctor(System.Int32 x, <empty anonymous type> y)", info0.Symbol.ToTestDisplayString());
  355. }
  356. [Fact()]
  357. public void AnonymousTypeFieldCreatedInLambda2()
  358. {
  359. var source = @"
  360. using System;
  361. class ClassA
  362. {
  363. void m()
  364. {
  365. var o = (Action)
  366. (() =>
  367. ((Func<string>) (() => ( [# new { [# x #] = 1, [# y #] = [# new { } #] } #]).ToString())
  368. ).Invoke());
  369. }
  370. }";
  371. var data = Compile(source, 4);
  372. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  373. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  374. 1, 2);
  375. var info1 = GetAnonymousTypeInfoSummary(data, 3,
  376. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 2).Span);
  377. Assert.Equal("<anonymous type: System.Int32 x, <empty anonymous type> y>..ctor(System.Int32 x, <empty anonymous type> y)", info0.Symbol.ToTestDisplayString());
  378. }
  379. [Fact()]
  380. public void AnonymousTypeSymbols_DontCrashIfNameIsQueriedBeforeEmit()
  381. {
  382. var source = @"
  383. public class ClassA
  384. {
  385. public static void Test1(int x)
  386. {
  387. object v1 = [# new { [# aa #] = 1, [# BB #] = 2 } #];
  388. object v2 = [# new { } #];
  389. }
  390. }";
  391. var data = Compile(source, 4);
  392. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  393. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  394. 1, 2);
  395. CheckAnonymousType(info0.Type, "", "");
  396. info0 = GetAnonymousTypeInfoSummary(data, 3,
  397. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 2).Span);
  398. CheckAnonymousType(info0.Type, "", "");
  399. // perform emit
  400. CompileAndVerify(
  401. data.Compilation,
  402. symbolValidator: module => CheckAnonymousTypes(module)
  403. );
  404. }
  405. #region "AnonymousTypeSymbols_DontCrashIfNameIsQueriedBeforeEmit"
  406. private void CheckAnonymousType(ITypeSymbol type, string name, string metadataName)
  407. {
  408. Assert.NotNull(type);
  409. Assert.Equal(name, type.Name);
  410. Assert.Equal(metadataName, type.MetadataName);
  411. }
  412. private void CheckAnonymousTypes(ModuleSymbol module)
  413. {
  414. var ns = module.GlobalNamespace;
  415. Assert.NotNull(ns);
  416. CheckAnonymousType(ns.GetMember<NamedTypeSymbol>("<>f__AnonymousType0"), "<>f__AnonymousType0", "<>f__AnonymousType0`2");
  417. CheckAnonymousType(ns.GetMember<NamedTypeSymbol>("<>f__AnonymousType1"), "<>f__AnonymousType1", "<>f__AnonymousType1");
  418. }
  419. #endregion
  420. [Fact()]
  421. public void AnonymousTypeSymbols_Error_Simple()
  422. {
  423. var source = @"
  424. public class ClassA
  425. {
  426. public static void Test1(int x)
  427. {
  428. object v1 = [# new
  429. {
  430. [# aa #] = xyz,
  431. [# BB #] = """",
  432. [# CCC #] = new SSS()
  433. } #];
  434. object v2 = [# new
  435. {
  436. [# aa #] = new SSS(),
  437. [# BB #] = 123.456,
  438. [# CCC #] = [# new
  439. {
  440. (new ClassA()).[# aa #],
  441. ClassA.[# BB #],
  442. ClassA.[# CCC #]
  443. } #]
  444. } #];
  445. }
  446. }";
  447. var data = Compile(source, 12,
  448. // (8,25): error CS0103: The name 'xyz' does not exist in the current context
  449. // aa = xyz,
  450. Diagnostic(ErrorCode.ERR_NameNotInContext, "xyz").WithArguments("xyz"),
  451. // (10,29): error CS0246: The type or namespace name 'SSS' could not be found (are you missing a using directive or an assembly reference?)
  452. // CCC = new SSS()
  453. Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "SSS").WithArguments("SSS"),
  454. // (15,29): error CS0246: The type or namespace name 'SSS' could not be found (are you missing a using directive or an assembly reference?)
  455. // aa = new SSS(),
  456. Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "SSS").WithArguments("SSS"),
  457. // (19,35): error CS1061: 'ClassA' does not contain a definition for 'aa' and no extension method 'aa' accepting a first argument of type 'ClassA' could be found (are you missing a using directive or an assembly reference?)
  458. // (new ClassA()). aa ,
  459. Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "aa").WithArguments("ClassA", "aa"),
  460. // (20,27): error CS0117: 'ClassA' does not contain a definition for 'BB'
  461. // ClassA. BB ,
  462. Diagnostic(ErrorCode.ERR_NoSuchMember, "BB").WithArguments("ClassA", "BB"),
  463. // (21,27): error CS0117: 'ClassA' does not contain a definition for 'CCC'
  464. // ClassA. CCC
  465. Diagnostic(ErrorCode.ERR_NoSuchMember, "CCC").WithArguments("ClassA", "CCC")
  466. );
  467. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  468. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  469. 1, 2, 3);
  470. var info1 = GetAnonymousTypeInfoSummary(data, 4,
  471. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 3).Span,
  472. 5, 6, 7);
  473. var info2 = GetAnonymousTypeInfoSummary(data, 8,
  474. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 5).Span,
  475. 9, 10, 11);
  476. Assert.Equal("<anonymous type: ? aa, System.String BB, SSS CCC>", info0.Type.ToTestDisplayString());
  477. Assert.Equal("<anonymous type: SSS aa, System.Double BB, <anonymous type: ? aa, ? BB, ? CCC> CCC>", info1.Type.ToTestDisplayString());
  478. Assert.Equal("<anonymous type: ? aa, ? BB, ? CCC>", info2.Type.ToTestDisplayString());
  479. }
  480. [Fact()]
  481. public void AnonymousTypeSymbols_Error_InUsingStatement()
  482. {
  483. var source = @"
  484. public class ClassA
  485. {
  486. public static void Test1(int x)
  487. {
  488. using (var v1 = [# new { } #])
  489. {
  490. }
  491. }
  492. }";
  493. var data = Compile(source, 1,
  494. // (6,16): error CS1674: '<empty anonymous type>': type used in a using statement must be implicitly convertible to 'System.IDisposable'
  495. // using (var v1 = new { } )
  496. Diagnostic(ErrorCode.ERR_NoConvToIDisp, "var v1 = new { }").WithArguments("<empty anonymous type>")
  497. );
  498. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  499. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span);
  500. Assert.Equal("<empty anonymous type>", info0.Type.ToTestDisplayString());
  501. }
  502. [Fact()]
  503. public void AnonymousTypeSymbols_Error_DuplicateName()
  504. {
  505. var source = @"
  506. public class ClassA
  507. {
  508. public static void Test1(int x)
  509. {
  510. object v1 = [# new
  511. {
  512. [# aa #] = 1,
  513. ClassA.[# aa #],
  514. [# bb #] = 1.2
  515. } #];
  516. }
  517. public static string aa = ""-field-aa-"";
  518. }";
  519. var data = Compile(source, 4,
  520. // (9,13): error CS0833: An anonymous type cannot have multiple properties with the same name
  521. // ClassA. aa ,
  522. Diagnostic(ErrorCode.ERR_AnonymousTypeDuplicatePropertyName, "ClassA. aa")
  523. );
  524. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  525. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  526. 1, /*2,*/ 3);
  527. Assert.Equal("<anonymous type: System.Int32 aa, System.String $1, System.Double bb>", info0.Type.ToTestDisplayString());
  528. var properties = (from m in info0.Type.GetMembers() where m.Kind == SymbolKind.Property select m).ToArray();
  529. Assert.Equal(3, properties.Length);
  530. Assert.Equal("System.Int32 <anonymous type: System.Int32 aa, System.String $1, System.Double bb>.aa { get; }", properties[0].ToTestDisplayString());
  531. Assert.Equal("System.String <anonymous type: System.Int32 aa, System.String $1, System.Double bb>.$1 { get; }", properties[1].ToTestDisplayString());
  532. Assert.Equal("System.Double <anonymous type: System.Int32 aa, System.String $1, System.Double bb>.bb { get; }", properties[2].ToTestDisplayString());
  533. }
  534. [Fact()]
  535. public void AnonymousTypeSymbols_LookupSymbols()
  536. {
  537. var source = @"
  538. public class ClassA
  539. {
  540. public static void Test1(int x)
  541. {
  542. object v1 = [# new
  543. {
  544. [# aa #] = """",
  545. [# abc #] = 123.456
  546. } #];
  547. object v2 = [# new{ } #];
  548. }
  549. }";
  550. var data = Compile(source, 4);
  551. var info0 = GetAnonymousTypeInfoSummary(data, 0,
  552. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 1).Span,
  553. 1, 2);
  554. Assert.Equal("<anonymous type: System.String aa, System.Double abc>", info0.Type.ToTestDisplayString());
  555. var pos = data.Nodes[0].Span.End;
  556. var syms = data.Model.LookupSymbols(pos, container: info0.Type).Select(x => x.ToTestDisplayString()).OrderBy(x => x).ToArray();
  557. Assert.Equal(8, syms.Length);
  558. int index = 0;
  559. Assert.Equal("System.Boolean System.Object.Equals(System.Object obj)", syms[index++]);
  560. Assert.Equal("System.Boolean System.Object.Equals(System.Object objA, System.Object objB)", syms[index++]);
  561. Assert.Equal("System.Boolean System.Object.ReferenceEquals(System.Object objA, System.Object objB)", syms[index++]);
  562. Assert.Equal("System.Double <anonymous type: System.String aa, System.Double abc>.abc { get; }", syms[index++]);
  563. Assert.Equal("System.Int32 System.Object.GetHashCode()", syms[index++]);
  564. Assert.Equal("System.String <anonymous type: System.String aa, System.Double abc>.aa { get; }", syms[index++]);
  565. Assert.Equal("System.String System.Object.ToString()", syms[index++]);
  566. Assert.Equal("System.Type System.Object.GetType()", syms[index++]);
  567. info0 = GetAnonymousTypeInfoSummary(data, 3,
  568. data.Tree.FindNodeOrTokenByKind(SyntaxKind.NewKeyword, 2).Span);
  569. Assert.Equal("<empty anonymous type>", info0.Type.ToTestDisplayString());
  570. pos = data.Nodes[3].Span.End;
  571. syms = data.Model.LookupSymbols(pos, container: info0.Type).Select(x => x.ToTestDisplayString()).OrderBy(x => x).ToArray();
  572. Assert.Equal(6, syms.Length);
  573. index = 0;
  574. Assert.Equal("System.Boolean System.Object.Equals(System.Object obj)", syms[index++]);
  575. Assert.Equal("System.Boolean System.Object.Equals(System.Object objA, System.Object objB)", syms[index++]);
  576. Assert.Equal("System.Boolean System.Object.ReferenceEquals(System.Object objA, System.Object objB)", syms[index++]);
  577. Assert.Equal("System.Int32 System.Object.GetHashCode()", syms[index++]);
  578. Assert.Equal("System.String System.Object.ToString()", syms[index++]);
  579. Assert.Equal("System.Type System.Object.GetType()", syms[index++]);
  580. }
  581. [WorkItem(543189, "DevDiv")]
  582. [Fact()]
  583. public void CheckAnonymousTypeAsConstValue()
  584. {
  585. var source = @"
  586. public class A
  587. {
  588. const int i = /*<bind>*/(new {a = 2}).a/*</bind>*/;
  589. }";
  590. var comp = CreateCompilationWithMscorlib(source);
  591. var tuple = GetBindingNodeAndModel<ExpressionSyntax>(comp);
  592. var info = tuple.Item2.GetSymbolInfo(tuple.Item1);
  593. Assert.NotNull(info.Symbol);
  594. Assert.Equal("<anonymous type: int a>.a", info.Symbol.ToDisplayString());
  595. }
  596. [WorkItem(546416, "DevDiv")]
  597. [Fact()]
  598. public void TestAnonymousTypeInsideGroupBy_Queryable()
  599. {
  600. CompileAndVerify(
  601. @"using System.Linq;
  602. public class Product
  603. {
  604. public int ProductID;
  605. public string ProductName;
  606. public int SupplierID;
  607. }
  608. public class DB
  609. {
  610. public IQueryable<Product> Products;
  611. }
  612. public class Program
  613. {
  614. public static void Main()
  615. {
  616. var db = new DB();
  617. var q0 = db.Products.GroupBy(p => new { Conditional = false ? new { p.ProductID, p.ProductName, p.SupplierID } : new { p.ProductID, p.ProductName, p.SupplierID } }).ToList();
  618. }
  619. }", additionalRefs: new[] { SystemCoreRef }).VerifyDiagnostics();
  620. }
  621. [WorkItem(546416, "DevDiv")]
  622. [Fact()]
  623. public void TestAnonymousTypeInsideGroupBy_Enumerable()
  624. {
  625. CompileAndVerify(
  626. @"using System.Linq;
  627. using System.Collections.Generic;
  628. public class Product
  629. {
  630. public int ProductID;
  631. public string ProductName;
  632. public int SupplierID;
  633. }
  634. public class DB
  635. {
  636. public IEnumerable<Product> Products;
  637. }
  638. public class Program
  639. {
  640. public static void Main()
  641. {
  642. var db = new DB();
  643. var q0 = db.Products.GroupBy(p => new { Conditional = false ? new { p.ProductID, p.ProductName, p.SupplierID } : new { p.ProductID, p.ProductName, p.SupplierID } }).ToList();
  644. }
  645. }", additionalRefs: new[] { SystemCoreRef }).VerifyDiagnostics();
  646. }
  647. [WorkItem(546416, "DevDiv")]
  648. [Fact()]
  649. public void TestAnonymousTypeInsideGroupBy_Enumerable2()
  650. {
  651. CompileAndVerify(
  652. @"using System.Linq;
  653. using System.Collections.Generic;
  654. public class Product
  655. {
  656. public int ProductID;
  657. public int SupplierID;
  658. }
  659. public class DB
  660. {
  661. public IEnumerable<Product> Products;
  662. }
  663. public class Program
  664. {
  665. public static void Main()
  666. {
  667. var db = new DB();
  668. var q0 = db.Products.GroupBy(p => new { Conditional = false ? new { p.ProductID, p.SupplierID } : new { p.ProductID, p.SupplierID } }).ToList();
  669. var q1 = db.Products.GroupBy(p => new { Conditional = false ? new { p.ProductID, p.SupplierID } : new { p.ProductID, p.SupplierID } }).ToList();
  670. }
  671. }", additionalRefs: new[] { SystemCoreRef }).VerifyDiagnostics();
  672. }
  673. #region "Utility methods"
  674. private void AssertCannotConstruct(ISymbol type)
  675. {
  676. var namedType = type as NamedTypeSymbol;
  677. Assert.NotNull(namedType);
  678. var objType = namedType.BaseType;
  679. Assert.NotNull(objType);
  680. Assert.Equal("System.Object", objType.ToTestDisplayString());
  681. TypeSymbol[] args = new TypeSymbol[namedType.Arity];
  682. for (int i = 0; i < namedType.Arity; i++)
  683. {
  684. args[i] = objType;
  685. }
  686. Assert.Throws<InvalidOperationException>(() => namedType.Construct(args));
  687. }
  688. private CompilationUtils.SemanticInfoSummary GetAnonymousTypeInfoSummary(TestData data, int node, TextSpan typeSpan, params int[] fields)
  689. {
  690. var info = data.Model.GetSemanticInfoSummary(data.Nodes[node]);
  691. var type = info.Type;
  692. Assert.True(type.IsAnonymousType);
  693. Assert.False(type.CanBeReferencedByName);
  694. Assert.Equal("System.Object", type.BaseType.ToTestDisplayString());
  695. Assert.Equal(0, type.Interfaces.Length);
  696. Assert.Equal(1, type.Locations.Length);
  697. Assert.Equal(typeSpan, type.Locations[0].SourceSpan);
  698. foreach (int field in fields)
  699. {
  700. CheckFieldNameAndLocation(data, type, data.Nodes[field]);
  701. }
  702. return info;
  703. }
  704. private void CheckFieldNameAndLocation(TestData data, ITypeSymbol type, SyntaxNode identifier)
  705. {
  706. var anonymousType = (NamedTypeSymbol)type;
  707. var current = identifier;
  708. while (current.Span == identifier.Span && !current.IsKind(SyntaxKind.IdentifierName))
  709. {
  710. current = current.ChildNodes().Single();
  711. }
  712. var node = (IdentifierNameSyntax)current;
  713. Assert.NotNull(node);
  714. var span = node.Span;
  715. var fieldName = node.ToString();
  716. var property = anonymousType.GetMember<PropertySymbol>(fieldName);
  717. Assert.NotNull(property);
  718. Assert.Equal(fieldName, property.Name);
  719. Assert.Equal(1, property.Locations.Length);
  720. Assert.Equal(span, property.Locations[0].SourceSpan);
  721. MethodSymbol getter = property.GetMethod;
  722. Assert.NotNull(getter);
  723. Assert.Equal("get_" + fieldName, getter.Name);
  724. }
  725. struct TestData
  726. {
  727. public CSharpCompilation Compilation;
  728. public SyntaxTree Tree;
  729. public List<SyntaxNode> Nodes;
  730. public SemanticModel Model;
  731. }
  732. private TestData Compile(string source, int expectedIntervals, params DiagnosticDescription[] diagnostics)
  733. {
  734. var intervals = ExtractTextIntervals(ref source);
  735. Assert.Equal(expectedIntervals, intervals.Count);
  736. var compilation = GetCompilationForEmit(
  737. new[] { source },
  738. new MetadataReference[] { },
  739. DefaultCompilationOptions.WithOutputKind(OutputKind.DynamicallyLinkedLibrary)
  740. );
  741. compilation.VerifyDiagnostics(diagnostics);
  742. var tree = compilation.SyntaxTrees[0];
  743. var nodes = new List<SyntaxNode>();
  744. foreach (var span in intervals)
  745. {
  746. var stack = new Stack<SyntaxNode>();
  747. stack.Push(tree.GetCompilationUnitRoot());
  748. while (stack.Count > 0)
  749. {
  750. var node = stack.Pop();
  751. if (span.Contains(node.Span))
  752. {
  753. nodes.Add(node);
  754. break;
  755. }
  756. foreach (var child in node.ChildNodes())
  757. {
  758. stack.Push(child);
  759. }
  760. }
  761. }
  762. Assert.Equal(expectedIntervals, nodes.Count);
  763. return new TestData()
  764. {
  765. Compilation = compilation,
  766. Tree = tree,
  767. Model = compilation.GetSemanticModel(tree),
  768. Nodes = nodes
  769. };
  770. }
  771. private CSharpCompilation Compile(string source)
  772. {
  773. return GetCompilationForEmit(
  774. new[] { source },
  775. new MetadataReference[] { },
  776. DefaultCompilationOptions.WithOutputKind(OutputKind.DynamicallyLinkedLibrary)
  777. );
  778. }
  779. private static List<TextSpan> ExtractTextIntervals(ref string source)
  780. {
  781. const string startTag = "[#";
  782. const string endTag = "#]";
  783. List<TextSpan> intervals = new List<TextSpan>();
  784. var all = (from s in FindAll(source, startTag)
  785. select new { start = true, offset = s }).Union(
  786. from s in FindAll(source, endTag)
  787. select new { start = false, offset = s }
  788. ).OrderBy(value => value.offset).ToList();
  789. while (all.Count > 0)
  790. {
  791. int i = 1;
  792. bool added = false;
  793. while (i < all.Count)
  794. {
  795. if (all[i - 1].start && !all[i].start)
  796. {
  797. intervals.Add(TextSpan.FromBounds(all[i - 1].offset, all[i].offset));
  798. all.RemoveAt(i);
  799. all.RemoveAt(i - 1);
  800. added = true;
  801. }
  802. else
  803. {
  804. i++;
  805. }
  806. }
  807. Assert.True(added);
  808. }
  809. source = source.Replace(startTag, " ").Replace(endTag, " ");
  810. intervals.Sort((x, y) => x.Start.CompareTo(y.Start));
  811. return intervals;
  812. }
  813. private static IEnumerable<int> FindAll(string source, string what)
  814. {
  815. int index = source.IndexOf(what);
  816. while (index >= 0)
  817. {
  818. yield return index;
  819. index = source.IndexOf(what, index + 1);
  820. }
  821. }
  822. private int NumberOfNewKeywords(string source)
  823. {
  824. int cnt = 0;
  825. foreach (var line in source.Split(new String[] { Environment.NewLine }, StringSplitOptions.None))
  826. {
  827. if (!string.IsNullOrWhiteSpace(line))
  828. {
  829. if (!line.Trim().StartsWith("//"))
  830. {
  831. for (int index = line.IndexOf("new "); index >= 0; )
  832. {
  833. cnt++;
  834. index = line.IndexOf("new ", index + 1);
  835. }
  836. }
  837. }
  838. }
  839. return cnt;
  840. }
  841. #endregion
  842. }
  843. }