/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxAnnotationTests.cs

https://github.com/dotnet/roslyn · C# · 874 lines · 863 code · 4 blank · 7 comment · 0 complexity · 3637fcef4a93ff4411c2cec300e11f4b MD5 · raw file

  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using Microsoft.CodeAnalysis.CSharp.Syntax;
  8. using Roslyn.Test.Utilities;
  9. using Xunit;
  10. namespace Microsoft.CodeAnalysis.CSharp.UnitTests
  11. {
  12. public class SyntaxAnnotationTests
  13. {
  14. #region Boundary Tests
  15. [Fact]
  16. public void TestEmpty()
  17. {
  18. var code = @"";
  19. var tree = SyntaxFactory.ParseSyntaxTree(code);
  20. TestAnnotation(tree);
  21. }
  22. [Fact]
  23. public void TestAddAnnotationToNullSyntaxToken()
  24. {
  25. SyntaxAnnotation annotation = new SyntaxAnnotation();
  26. var oldToken = default(SyntaxToken);
  27. var newToken = oldToken.WithAdditionalAnnotations(annotation);
  28. Assert.False(newToken.ContainsAnnotations);
  29. }
  30. [Fact]
  31. public void TestAddAnnotationToNullSyntaxTrivia()
  32. {
  33. SyntaxAnnotation annotation = new SyntaxAnnotation();
  34. var oldTrivia = default(SyntaxTrivia);
  35. var newTrivia = oldTrivia.WithAdditionalAnnotations(annotation);
  36. Assert.False(newTrivia.ContainsAnnotations);
  37. }
  38. [Fact]
  39. public void TestCopyAnnotationToNullSyntaxNode()
  40. {
  41. var fromNode = SyntaxFactory.ParseSyntaxTree(_helloWorldCode).GetCompilationUnitRoot();
  42. var toNode = (SyntaxNode)null;
  43. var annotatedNode = fromNode.CopyAnnotationsTo(toNode);
  44. Assert.Null(annotatedNode);
  45. }
  46. [Fact]
  47. public void TestCopyAnnotationOfZeroLengthToSyntaxNode()
  48. {
  49. var fromNode = SyntaxFactory.ParseSyntaxTree(_helloWorldCode).GetCompilationUnitRoot();
  50. var toNode = SyntaxFactory.ParseSyntaxTree(_helloWorldCode).GetCompilationUnitRoot();
  51. var annotatedNode = fromNode.CopyAnnotationsTo(toNode);
  52. Assert.Equal(annotatedNode, toNode); // Reference Equal
  53. }
  54. [Fact]
  55. public void TestCopyAnnotationFromNullSyntaxToken()
  56. {
  57. var fromToken = default(SyntaxToken);
  58. var toToken = SyntaxFactory.ParseSyntaxTree(_helloWorldCode).GetCompilationUnitRoot().DescendantTokens().First();
  59. var annotatedToken = fromToken.CopyAnnotationsTo(toToken);
  60. Assert.True(annotatedToken.IsEquivalentTo(toToken));
  61. }
  62. [Fact]
  63. public void TestCopyAnnotationToNullSyntaxToken()
  64. {
  65. var fromToken = SyntaxFactory.ParseSyntaxTree(_helloWorldCode).GetCompilationUnitRoot().DescendantTokens().First();
  66. var toToken = default(SyntaxToken);
  67. var annotatedToken = fromToken.CopyAnnotationsTo(toToken);
  68. Assert.True(annotatedToken.IsEquivalentTo(default(SyntaxToken)));
  69. }
  70. [Fact]
  71. public void TestCopyAnnotationOfZeroLengthToSyntaxToken()
  72. {
  73. var fromToken = SyntaxFactory.ParseSyntaxTree(_helloWorldCode).GetCompilationUnitRoot().DescendantTokens().First();
  74. var toToken = SyntaxFactory.ParseSyntaxTree(_helloWorldCode).GetCompilationUnitRoot().DescendantTokens().First();
  75. var annotatedToken = fromToken.CopyAnnotationsTo(toToken);
  76. Assert.Equal(annotatedToken, toToken); // Reference Equal
  77. }
  78. [Fact]
  79. public void TestCopyAnnotationFromNullSyntaxTrivia()
  80. {
  81. var fromTrivia = default(SyntaxTrivia);
  82. var tree = SyntaxFactory.ParseSyntaxTree(_helloWorldCode);
  83. var toTrivia = GetAllTrivia(tree.GetCompilationUnitRoot()).FirstOrDefault();
  84. var annotatedTrivia = fromTrivia.CopyAnnotationsTo(toTrivia);
  85. Assert.True(toTrivia.IsEquivalentTo(annotatedTrivia));
  86. }
  87. [Fact]
  88. public void TestCopyAnnotationToNullSyntaxTrivia()
  89. {
  90. var toTrivia = default(SyntaxTrivia);
  91. var tree = SyntaxFactory.ParseSyntaxTree(_helloWorldCode);
  92. var fromTrivia = GetAllTrivia(tree.GetCompilationUnitRoot()).FirstOrDefault();
  93. var annotatedTrivia = fromTrivia.CopyAnnotationsTo(toTrivia);
  94. Assert.True(default(SyntaxTrivia).IsEquivalentTo(annotatedTrivia));
  95. }
  96. [Fact]
  97. public void TestCopyAnnotationOfZeroLengthToSyntaxTrivia()
  98. {
  99. var tree = SyntaxFactory.ParseSyntaxTree(_helloWorldCode);
  100. var fromTrivia = GetAllTrivia(tree.GetCompilationUnitRoot()).FirstOrDefault();
  101. var toTrivia = GetAllTrivia(tree.GetCompilationUnitRoot()).FirstOrDefault();
  102. var annotatedTrivia = fromTrivia.CopyAnnotationsTo(toTrivia);
  103. Assert.Equal(annotatedTrivia, toTrivia); // Reference Equal
  104. }
  105. #endregion
  106. #region Negative Tests
  107. [Fact]
  108. public void TestMissingAnnotationsOnNodesOrTokens()
  109. {
  110. SyntaxAnnotation annotation = new SyntaxAnnotation();
  111. var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
  112. var matchingNodesOrTokens = tree.GetCompilationUnitRoot().GetAnnotatedNodesAndTokens(annotation);
  113. Assert.Empty(matchingNodesOrTokens);
  114. }
  115. [Fact]
  116. public void TestMissingAnnotationsOnTrivia()
  117. {
  118. SyntaxAnnotation annotation = new SyntaxAnnotation();
  119. var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
  120. var matchingTrivia = tree.GetCompilationUnitRoot().GetAnnotatedTrivia(annotation);
  121. Assert.Empty(matchingTrivia);
  122. }
  123. #endregion
  124. #region Other Functional Tests
  125. [Fact]
  126. public void TestSimpleMultipleAnnotationsOnNode()
  127. {
  128. var tree = SyntaxFactory.ParseSyntaxTree(_helloWorldCode);
  129. SyntaxAnnotation annotation1 = new SyntaxAnnotation();
  130. SyntaxAnnotation annotation2 = new SyntaxAnnotation();
  131. // Pick the first node from tree
  132. var node = GetAllNodesAndTokens(tree.GetCompilationUnitRoot()).First(t => t.IsNode).AsNode();
  133. // Annotate it
  134. var annotatedNode = node.WithAdditionalAnnotations(annotation1);
  135. var newRoot = tree.GetCompilationUnitRoot().ReplaceNode(node, annotatedNode);
  136. // Verify if annotation Exists
  137. TestAnnotation(annotation1, newRoot, node);
  138. // Pick the annotated node from the new tree
  139. var node2 = newRoot.GetAnnotatedNodesAndTokens(annotation1).Single().AsNode();
  140. // Annotate it again
  141. var twiceAnnotatedNode = node2.WithAdditionalAnnotations(annotation2);
  142. var twiceAnnotatedRoot = newRoot.ReplaceNode(node2, twiceAnnotatedNode);
  143. // Verify the recent annotation
  144. TestAnnotation(annotation2, twiceAnnotatedRoot, node2);
  145. // Verify both annotations exist in the newTree
  146. TestAnnotation(annotation1, twiceAnnotatedRoot, node);
  147. TestAnnotation(annotation2, twiceAnnotatedRoot, node);
  148. }
  149. [Fact]
  150. public void TestSimpleMultipleAnnotationsOnToken()
  151. {
  152. var tree = SyntaxFactory.ParseSyntaxTree(_helloWorldCode);
  153. SyntaxAnnotation annotation1 = new SyntaxAnnotation();
  154. SyntaxAnnotation annotation2 = new SyntaxAnnotation();
  155. // Pick the first node from tree
  156. var token = GetAllNodesAndTokens(tree.GetCompilationUnitRoot()).First(t => t.IsToken).AsToken();
  157. // Annotate it
  158. var annotatedToken = token.WithAdditionalAnnotations(annotation1);
  159. var newRoot = tree.GetCompilationUnitRoot().ReplaceToken(token, annotatedToken);
  160. // Verify if annotation Exists
  161. TestAnnotation(annotation1, newRoot, token);
  162. // Pick the annotated node from the new tree
  163. var token2 = newRoot.GetAnnotatedNodesAndTokens(annotation1).Single().AsToken();
  164. // Annotate it again
  165. var twiceAnnotatedToken = token2.WithAdditionalAnnotations(annotation2);
  166. var twiceAnnotatedRoot = newRoot.ReplaceToken(token2, twiceAnnotatedToken);
  167. // Verify the recent annotation
  168. TestAnnotation(annotation2, twiceAnnotatedRoot, token2);
  169. // Verify both annotations exist in the newTree
  170. TestAnnotation(annotation1, twiceAnnotatedRoot, token);
  171. TestAnnotation(annotation2, twiceAnnotatedRoot, token);
  172. }
  173. [Fact]
  174. public void TestSimpleMultipleAnnotationsOnTrivia()
  175. {
  176. var tree = SyntaxFactory.ParseSyntaxTree(_helloWorldCode);
  177. SyntaxAnnotation annotation1 = new SyntaxAnnotation();
  178. SyntaxAnnotation annotation2 = new SyntaxAnnotation();
  179. // Pick the first node from tree
  180. var trivia = GetAllTrivia(tree.GetCompilationUnitRoot()).First();
  181. // Annotate it
  182. var annotatedTrivia = trivia.WithAdditionalAnnotations(annotation1);
  183. var newRoot = tree.GetCompilationUnitRoot().ReplaceTrivia(trivia, annotatedTrivia);
  184. // Verify if annotation Exists
  185. TestAnnotation(annotation1, newRoot, trivia);
  186. // Pick the annotated node from the new tree
  187. var trivia2 = newRoot.GetAnnotatedTrivia(annotation1).Single();
  188. // Annotate it again
  189. var twiceAnnotatedTrivia = trivia2.WithAdditionalAnnotations(annotation2);
  190. var twiceAnnotatedRoot = newRoot.ReplaceTrivia(trivia2, twiceAnnotatedTrivia);
  191. // Verify the recent annotation
  192. TestAnnotation(annotation2, twiceAnnotatedRoot, trivia2);
  193. // Verify both annotations exist in the newTree
  194. TestAnnotation(annotation1, twiceAnnotatedRoot, trivia);
  195. TestAnnotation(annotation2, twiceAnnotatedRoot, trivia);
  196. }
  197. [Fact]
  198. public void TestMultipleAnnotationsOnAllNodesTokensAndTrivia()
  199. {
  200. var tree = SyntaxFactory.ParseSyntaxTree(_helloWorldCode);
  201. SyntaxNode newRoot = tree.GetCompilationUnitRoot();
  202. var annotations = new List<SyntaxAnnotation>(Enumerable.Range(0, 3).Select(_ => new SyntaxAnnotation()));
  203. // add annotation one by one to every single node, token, trivia
  204. foreach (var annotation in annotations)
  205. {
  206. var rewriter = new InjectAnnotationRewriter(annotation);
  207. newRoot = rewriter.Visit(newRoot);
  208. }
  209. // Verify that all annotations are present in whichever places they were added
  210. TestMultipleAnnotationsInTree(tree.GetCompilationUnitRoot(), newRoot, annotations);
  211. }
  212. [Fact]
  213. public void TestAnnotationOnEveryNodeTokenTriviaOfHelloWorld()
  214. {
  215. var tree = SyntaxFactory.ParseSyntaxTree(_helloWorldCode);
  216. TestAnnotation(tree);
  217. TestTriviaAnnotation(tree);
  218. }
  219. [Fact]
  220. public void TestIfNodeHasAnnotations()
  221. {
  222. var tree = SyntaxFactory.ParseSyntaxTree(_helloWorldCode);
  223. SyntaxAnnotation annotation1 = new SyntaxAnnotation();
  224. // Pick the first node from tree
  225. var firstNode = GetAllNodesAndTokens(tree.GetCompilationUnitRoot()).First(t => t.IsNode).AsNode();
  226. var children = firstNode.ChildNodesAndTokens();
  227. var lastChildOfFirstNode = children.Last(t => t.IsNode).AsNode();
  228. var annotatedNode = lastChildOfFirstNode.WithAdditionalAnnotations(annotation1);
  229. var newRoot = tree.GetCompilationUnitRoot().ReplaceNode(lastChildOfFirstNode, annotatedNode);
  230. // Verify if annotation Exists
  231. TestAnnotation(annotation1, newRoot, lastChildOfFirstNode);
  232. // Pick the first node from new tree and see if any of its children is annotated
  233. var firstNodeInNewTree = GetAllNodesAndTokens(newRoot).First(t => t.IsNode).AsNode();
  234. Assert.True(firstNodeInNewTree.ContainsAnnotations);
  235. // Pick the node which was annotated and see if it has the annotation
  236. var rightNode = firstNodeInNewTree.ChildNodesAndTokens().Last(t => t.IsNode).AsNode();
  237. Assert.NotNull(rightNode.GetAnnotations().Single());
  238. }
  239. [Fact]
  240. public void TestCSharpAllInOne()
  241. {
  242. var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
  243. TestAnnotation(tree);
  244. }
  245. [Fact]
  246. public void TestCSharpAllInOneRandom()
  247. {
  248. var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
  249. TestRandomAnnotations(tree);
  250. }
  251. [Fact]
  252. public void TestCSharpAllInOneManyRandom()
  253. {
  254. var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
  255. TestManyRandomAnnotations(tree);
  256. }
  257. [Fact]
  258. public void TestCSharpAllInOneTrivia()
  259. {
  260. var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
  261. TestTriviaAnnotation(tree);
  262. }
  263. [Fact]
  264. public void TestCopyAnnotations1()
  265. {
  266. var tree1 = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
  267. var tree2 = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
  268. TestCopyAnnotations(tree1, tree2);
  269. }
  270. #endregion
  271. private void TestMultipleAnnotationsInTree(SyntaxNode oldRoot, SyntaxNode newRoot, List<SyntaxAnnotation> annotations)
  272. {
  273. foreach (var annotation in annotations)
  274. {
  275. // Verify annotations in Nodes or Tokens
  276. var annotatedNodesOrTokens = newRoot.GetAnnotatedNodesAndTokens(annotation).OrderBy(t => t.SpanStart).ToList();
  277. var actualNodesOrTokens = GetAllNodesAndTokens(oldRoot).OrderBy(t => t.SpanStart).ToList();
  278. Assert.Equal(actualNodesOrTokens.Count, annotatedNodesOrTokens.Count);
  279. for (int i = 0; i < actualNodesOrTokens.Count(); i++)
  280. {
  281. var oldNode = actualNodesOrTokens.ElementAt(i);
  282. var annotatedNode = annotatedNodesOrTokens.ElementAt(i);
  283. Assert.Equal(oldNode.FullSpan, annotatedNode.FullSpan);
  284. Assert.Equal(oldNode.Span, annotatedNode.Span);
  285. Assert.True(oldNode.IsEquivalentTo(annotatedNode));
  286. }
  287. // Verify annotations in Trivia
  288. var annotatedTrivia = newRoot.GetAnnotatedTrivia(annotation).OrderBy(t => t.SpanStart);
  289. var actualTrivia = GetAllTrivia(oldRoot).OrderBy(t => t.SpanStart);
  290. Assert.Equal(annotatedTrivia.Count(), actualTrivia.Count());
  291. for (int i = 0; i < actualTrivia.Count(); i++)
  292. {
  293. var oldTrivia = actualTrivia.ElementAt(i);
  294. var newTrivia = annotatedTrivia.ElementAt(i);
  295. Assert.Equal(oldTrivia.FullSpan, newTrivia.FullSpan);
  296. Assert.Equal(oldTrivia.Span, newTrivia.Span);
  297. Assert.True(oldTrivia.IsEquivalentTo(newTrivia));
  298. }
  299. }
  300. }
  301. private void TestCopyAnnotations(SyntaxTree tree1, SyntaxTree tree2)
  302. {
  303. // create 10 annotations
  304. var annotations = new List<SyntaxAnnotation>(Enumerable.Range(0, 10).Select(_ => new SyntaxAnnotation()));
  305. // add a random annotation to every single node, token, trivia
  306. var rewriter = new InjectRandomAnnotationsRewriter(annotations);
  307. var sourceTreeRoot = rewriter.Visit(tree1.GetCompilationUnitRoot());
  308. var destTreeRoot = CopyAnnotationsTo(sourceTreeRoot, tree2.GetCompilationUnitRoot());
  309. // now we have two tree with same annotation everywhere
  310. // verify that
  311. foreach (var annotation in annotations)
  312. {
  313. // verify annotation at nodes and tokens
  314. var sourceNodeOrTokens = sourceTreeRoot.GetAnnotatedNodesAndTokens(annotation);
  315. var sourceNodeOrTokenEnumerator = sourceNodeOrTokens.GetEnumerator();
  316. var destNodeOrTokens = destTreeRoot.GetAnnotatedNodesAndTokens(annotation);
  317. var destNodeOrTokenEnumerator = destNodeOrTokens.GetEnumerator();
  318. Assert.Equal(sourceNodeOrTokens.Count(), destNodeOrTokens.Count());
  319. while (sourceNodeOrTokenEnumerator.MoveNext() && destNodeOrTokenEnumerator.MoveNext())
  320. {
  321. Assert.True(sourceNodeOrTokenEnumerator.Current.IsEquivalentTo(destNodeOrTokenEnumerator.Current));
  322. }
  323. // verify annotation at trivia
  324. var sourceTrivia = sourceTreeRoot.GetAnnotatedTrivia(annotation);
  325. var destTrivia = destTreeRoot.GetAnnotatedTrivia(annotation);
  326. var sourceTriviaEnumerator = sourceTrivia.GetEnumerator();
  327. var destTriviaEnumerator = destTrivia.GetEnumerator();
  328. Assert.Equal(sourceTrivia.Count(), destTrivia.Count());
  329. while (sourceTriviaEnumerator.MoveNext() && destTriviaEnumerator.MoveNext())
  330. {
  331. Assert.True(sourceTriviaEnumerator.Current.IsEquivalentTo(destTriviaEnumerator.Current));
  332. }
  333. }
  334. }
  335. private SyntaxNode CopyAnnotationsTo(SyntaxNode sourceTreeRoot, SyntaxNode destTreeRoot)
  336. {
  337. // now I have a tree that has annotation at every node/token/trivia
  338. // copy all those annotation to tree2 and create map from old one to new one
  339. var sourceTreeNodeOrTokenEnumerator = GetAllNodesAndTokens(sourceTreeRoot).GetEnumerator();
  340. var destTreeNodeOrTokenEnumerator = GetAllNodesAndTokens(destTreeRoot).GetEnumerator();
  341. var nodeOrTokenMap = new Dictionary<SyntaxNodeOrToken, SyntaxNodeOrToken>();
  342. while (sourceTreeNodeOrTokenEnumerator.MoveNext() && destTreeNodeOrTokenEnumerator.MoveNext())
  343. {
  344. if (sourceTreeNodeOrTokenEnumerator.Current.IsNode)
  345. {
  346. var oldNode = destTreeNodeOrTokenEnumerator.Current.AsNode();
  347. var newNode = sourceTreeNodeOrTokenEnumerator.Current.AsNode().CopyAnnotationsTo(oldNode);
  348. nodeOrTokenMap.Add(oldNode, newNode);
  349. }
  350. else if (sourceTreeNodeOrTokenEnumerator.Current.IsToken)
  351. {
  352. var oldToken = destTreeNodeOrTokenEnumerator.Current.AsToken();
  353. var newToken = sourceTreeNodeOrTokenEnumerator.Current.AsToken().CopyAnnotationsTo(oldToken);
  354. nodeOrTokenMap.Add(oldToken, newToken);
  355. }
  356. }
  357. // copy annotations at trivia
  358. var sourceTreeTriviaEnumerator = GetAllTrivia(sourceTreeRoot).GetEnumerator();
  359. var destTreeTriviaEnumerator = GetAllTrivia(destTreeRoot).GetEnumerator();
  360. var triviaMap = new Dictionary<SyntaxTrivia, SyntaxTrivia>();
  361. while (sourceTreeTriviaEnumerator.MoveNext() && destTreeTriviaEnumerator.MoveNext())
  362. {
  363. var oldTrivia = destTreeTriviaEnumerator.Current;
  364. var newTrivia = sourceTreeTriviaEnumerator.Current.CopyAnnotationsTo(oldTrivia);
  365. triviaMap.Add(oldTrivia, newTrivia);
  366. }
  367. var copier = new CopyAnnotationRewriter(nodeOrTokenMap, triviaMap);
  368. return copier.Visit(destTreeRoot);
  369. }
  370. private void TestManyRandomAnnotations(SyntaxTree syntaxTree)
  371. {
  372. // inject annotations in random places and see whether it is preserved after tree transformation
  373. var annotations = new List<Tuple<SyntaxAnnotation, SyntaxNodeOrToken>>();
  374. // we give constant seed so that we get exact same sequence every time.
  375. var randomGenerator = new Random(0);
  376. var currentRoot = syntaxTree.GetCompilationUnitRoot();
  377. var count = GetAllNodesAndTokens(currentRoot).Count;
  378. // add one in root
  379. var rootAnnotation = new SyntaxAnnotation();
  380. annotations.Add(Tuple.Create(rootAnnotation, new SyntaxNodeOrToken(currentRoot)));
  381. var rootAnnotated = AddAnnotationTo(rootAnnotation, currentRoot);
  382. currentRoot = Replace(currentRoot, currentRoot, rootAnnotated);
  383. for (int i = 0; i < 20; i++)
  384. {
  385. var annotation = new SyntaxAnnotation();
  386. var item = GetAllNodesAndTokens(currentRoot)[randomGenerator.Next(count - 1)];
  387. // save it
  388. annotations.Add(Tuple.Create(annotation, item));
  389. var annotated = AddAnnotationTo(annotation, item);
  390. currentRoot = Replace(currentRoot, item, annotated);
  391. TestAnnotations(annotations, currentRoot);
  392. }
  393. }
  394. private void TestRandomAnnotations(SyntaxTree syntaxTree)
  395. {
  396. // inject annotations in random places and see whether it is preserved after tree transformation
  397. var firstAnnotation = new SyntaxAnnotation();
  398. var secondAnnotation = new SyntaxAnnotation();
  399. var candidatePool = GetAllNodesAndTokens(syntaxTree.GetCompilationUnitRoot());
  400. var numberOfCandidates = candidatePool.Count;
  401. // we give constant seed so that we get exact same sequence every time.
  402. var randomGenerator = new Random(100);
  403. for (int i = 0; i < 20; i++)
  404. {
  405. var firstItem = candidatePool[randomGenerator.Next(numberOfCandidates - 1)];
  406. var firstAnnotated = AddAnnotationTo(firstAnnotation, firstItem);
  407. var newRoot = Replace(syntaxTree.GetCompilationUnitRoot(), firstItem, firstAnnotated);
  408. // check the first annotation
  409. TestAnnotation(firstAnnotation, newRoot, firstItem);
  410. var secondItem = GetAllNodesAndTokens(newRoot)[randomGenerator.Next(numberOfCandidates - 1)];
  411. var secondAnnotated = AddAnnotationTo(secondAnnotation, secondItem);
  412. // transform the tree again
  413. newRoot = Replace(newRoot, secondItem, secondAnnotated);
  414. // make sure both annotation are in the tree
  415. TestAnnotation(firstAnnotation, newRoot, firstItem);
  416. TestAnnotation(secondAnnotation, newRoot, secondItem);
  417. }
  418. }
  419. public TRoot Replace<TRoot>(TRoot root, SyntaxNodeOrToken oldNodeOrToken, SyntaxNodeOrToken newNodeOrToken) where TRoot : SyntaxNode
  420. {
  421. if (oldNodeOrToken.IsToken)
  422. {
  423. return root.ReplaceToken(oldNodeOrToken.AsToken(), newNodeOrToken.AsToken());
  424. }
  425. return root.ReplaceNode(oldNodeOrToken.AsNode(), newNodeOrToken.AsNode());
  426. }
  427. public SyntaxNodeOrToken AddAnnotationTo(SyntaxAnnotation annotation, SyntaxNodeOrToken nodeOrToken)
  428. {
  429. return nodeOrToken.WithAdditionalAnnotations(annotation);
  430. }
  431. private void TestAnnotations(List<Tuple<SyntaxAnnotation, SyntaxNodeOrToken>> annotations, SyntaxNode currentRoot)
  432. {
  433. // check every annotations
  434. foreach (var pair in annotations)
  435. {
  436. var annotation = pair.Item1;
  437. var nodeOrToken = pair.Item2;
  438. TestAnnotation(annotation, currentRoot, nodeOrToken);
  439. }
  440. }
  441. private void TestTriviaAnnotation(SyntaxTree syntaxTree)
  442. {
  443. var annotation = new SyntaxAnnotation();
  444. foreach (var trivia in GetAllTrivia(syntaxTree.GetCompilationUnitRoot()))
  445. {
  446. // add one annotation and test its existence
  447. var newTrivia = trivia.WithAdditionalAnnotations(annotation);
  448. var newRoot = syntaxTree.GetCompilationUnitRoot().ReplaceTrivia(trivia, newTrivia);
  449. TestAnnotation(annotation, newRoot, trivia);
  450. }
  451. }
  452. private void TestAnnotation(SyntaxTree syntaxTree)
  453. {
  454. var annotation = new SyntaxAnnotation();
  455. var allNodesAndTokens = GetAllNodesAndTokens(syntaxTree.GetCompilationUnitRoot());
  456. for (int i = 0; i < allNodesAndTokens.Count; i++)
  457. {
  458. var nodeOrToken = allNodesAndTokens[i];
  459. SyntaxNode newRoot;
  460. // add one annotation and test its existence
  461. if (nodeOrToken.IsToken)
  462. {
  463. var newToken = nodeOrToken.AsToken().WithAdditionalAnnotations(annotation);
  464. newRoot = syntaxTree.GetCompilationUnitRoot().ReplaceToken(nodeOrToken.AsToken(), newToken);
  465. }
  466. else
  467. {
  468. var newNode = nodeOrToken.AsNode().WithAdditionalAnnotations(annotation);
  469. newRoot = syntaxTree.GetCompilationUnitRoot().ReplaceNode(nodeOrToken.AsNode(), newNode);
  470. }
  471. TestAnnotation(annotation, newRoot, nodeOrToken);
  472. }
  473. }
  474. private void TestAnnotation(SyntaxAnnotation annotation, SyntaxNode root, SyntaxNodeOrToken oldNodeOrToken)
  475. {
  476. // Test for existence of exactly one annotation
  477. if (oldNodeOrToken.IsToken)
  478. {
  479. TestAnnotation(annotation, root, oldNodeOrToken.AsToken());
  480. return;
  481. }
  482. TestAnnotation(annotation, root, oldNodeOrToken.AsNode());
  483. }
  484. private void TestAnnotation(SyntaxAnnotation annotation, SyntaxNode root, SyntaxNode oldNode)
  485. {
  486. var results = root.GetAnnotatedNodesAndTokens(annotation);
  487. Assert.Equal(1, results.Count());
  488. var annotatedNode = results.Single().AsNode();
  489. // try to check whether it is same node as old node.
  490. Assert.Equal(oldNode.FullSpan, annotatedNode.FullSpan);
  491. Assert.Equal(oldNode.Span, annotatedNode.Span);
  492. Assert.True(oldNode.IsEquivalentTo(annotatedNode));
  493. }
  494. private void TestAnnotation(SyntaxAnnotation annotation, SyntaxNode root, SyntaxToken oldToken)
  495. {
  496. var results = root.GetAnnotatedNodesAndTokens(annotation);
  497. Assert.Equal(1, results.Count());
  498. var annotatedToken = results.Single().AsToken();
  499. // try to check whether it is same token as old token.
  500. Assert.Equal(oldToken.FullSpan, annotatedToken.FullSpan);
  501. Assert.Equal(oldToken.Span, annotatedToken.Span);
  502. Assert.True(oldToken.IsEquivalentTo(annotatedToken));
  503. }
  504. private void TestAnnotation(SyntaxAnnotation annotation, SyntaxNode root, SyntaxTrivia oldTrivia)
  505. {
  506. var results = root.GetAnnotatedTrivia(annotation);
  507. Assert.Equal(1, results.Count());
  508. var annotatedTrivia = results.Single();
  509. // try to check whether it is same token as old token.
  510. Assert.Equal(oldTrivia.FullSpan, annotatedTrivia.FullSpan);
  511. Assert.Equal(oldTrivia.Span, annotatedTrivia.Span);
  512. Assert.True(oldTrivia.IsEquivalentTo(annotatedTrivia));
  513. }
  514. private List<SyntaxTrivia> GetAllTrivia(SyntaxNode root)
  515. {
  516. var collector = new Collector();
  517. collector.Visit(root);
  518. return collector.Trivia;
  519. }
  520. private List<SyntaxNodeOrToken> GetAllNodesAndTokens(SyntaxNode root)
  521. {
  522. return root.DescendantNodesAndTokensAndSelf(descendIntoTrivia: true).Select(n => (SyntaxNodeOrToken)n).ToList();
  523. }
  524. private class Collector : CSharpSyntaxWalker
  525. {
  526. public List<SyntaxNodeOrToken> NodeOrTokens { get; }
  527. public List<SyntaxTrivia> Trivia { get; }
  528. public Collector()
  529. : base(SyntaxWalkerDepth.StructuredTrivia)
  530. {
  531. this.NodeOrTokens = new List<SyntaxNodeOrToken>();
  532. this.Trivia = new List<SyntaxTrivia>();
  533. }
  534. public override void Visit(SyntaxNode node)
  535. {
  536. if (node != null)
  537. {
  538. this.NodeOrTokens.Add(node);
  539. }
  540. base.Visit(node);
  541. }
  542. public override void VisitToken(SyntaxToken token)
  543. {
  544. if (!token.IsKind(SyntaxKind.None))
  545. {
  546. this.NodeOrTokens.Add(token);
  547. }
  548. base.VisitToken(token);
  549. }
  550. public override void VisitTrivia(SyntaxTrivia trivia)
  551. {
  552. if (!trivia.IsKind(SyntaxKind.None))
  553. {
  554. this.Trivia.Add(trivia);
  555. }
  556. base.VisitTrivia(trivia);
  557. }
  558. }
  559. private class InjectAnnotationRewriter : CSharpSyntaxRewriter
  560. {
  561. private readonly SyntaxAnnotation _annotation;
  562. public InjectAnnotationRewriter(SyntaxAnnotation annotation) :
  563. base(visitIntoStructuredTrivia: true)
  564. {
  565. _annotation = annotation;
  566. }
  567. public override SyntaxNode Visit(SyntaxNode node)
  568. {
  569. if (node == null)
  570. {
  571. return node;
  572. }
  573. return base.Visit(node).WithAdditionalAnnotations(_annotation);
  574. }
  575. public override SyntaxToken VisitToken(SyntaxToken token)
  576. {
  577. if (token.IsKind(SyntaxKind.None))
  578. {
  579. return token;
  580. }
  581. return base.VisitToken(token).WithAdditionalAnnotations(_annotation);
  582. }
  583. public override SyntaxTrivia VisitTrivia(SyntaxTrivia trivia)
  584. {
  585. if (trivia.IsKind(SyntaxKind.None))
  586. {
  587. return trivia;
  588. }
  589. if (trivia.HasStructure)
  590. {
  591. return base.VisitTrivia(trivia);
  592. }
  593. return base.VisitTrivia(trivia).WithAdditionalAnnotations(_annotation);
  594. }
  595. }
  596. private class InjectRandomAnnotationsRewriter : CSharpSyntaxRewriter
  597. {
  598. private readonly List<SyntaxAnnotation> _annotations;
  599. private readonly Random _random;
  600. public InjectRandomAnnotationsRewriter(List<SyntaxAnnotation> annotations) :
  601. base(visitIntoStructuredTrivia: true)
  602. {
  603. _annotations = annotations;
  604. _random = new Random(10);
  605. }
  606. public override SyntaxNode Visit(SyntaxNode node)
  607. {
  608. if (node == null)
  609. {
  610. return node;
  611. }
  612. var annotation = _annotations[_random.Next(0, _annotations.Count - 1)];
  613. return base.Visit(node).WithAdditionalAnnotations(annotation);
  614. }
  615. public override SyntaxToken VisitToken(SyntaxToken token)
  616. {
  617. if (token.Kind() == SyntaxKind.None)
  618. {
  619. return token;
  620. }
  621. var annotation = _annotations[_random.Next(0, _annotations.Count - 1)];
  622. return base.VisitToken(token).WithAdditionalAnnotations(annotation);
  623. }
  624. public override SyntaxTrivia VisitTrivia(SyntaxTrivia trivia)
  625. {
  626. if (trivia.IsKind(SyntaxKind.None))
  627. {
  628. return trivia;
  629. }
  630. // annotation will be set by actual structure trivia
  631. if (trivia.HasStructure)
  632. {
  633. return base.VisitTrivia(trivia);
  634. }
  635. var annotation = _annotations[_random.Next(0, _annotations.Count - 1)];
  636. return base.VisitTrivia(trivia).WithAdditionalAnnotations(annotation);
  637. }
  638. }
  639. private class CopyAnnotationRewriter : CSharpSyntaxRewriter
  640. {
  641. private readonly Dictionary<SyntaxNodeOrToken, SyntaxNodeOrToken> _nodeOrTokenMap;
  642. private readonly Dictionary<SyntaxTrivia, SyntaxTrivia> _triviaMap;
  643. public CopyAnnotationRewriter(Dictionary<SyntaxNodeOrToken, SyntaxNodeOrToken> nodeOrTokenMap, Dictionary<SyntaxTrivia, SyntaxTrivia> triviaMap) :
  644. base(visitIntoStructuredTrivia: true)
  645. {
  646. _nodeOrTokenMap = nodeOrTokenMap;
  647. _triviaMap = triviaMap;
  648. }
  649. public override SyntaxNode Visit(SyntaxNode node)
  650. {
  651. if (node == null)
  652. {
  653. return node;
  654. }
  655. return _nodeOrTokenMap[node].AsNode().CopyAnnotationsTo(base.Visit(node));
  656. }
  657. public override SyntaxToken VisitToken(SyntaxToken token)
  658. {
  659. if (token.IsKind(SyntaxKind.None))
  660. {
  661. return token;
  662. }
  663. return _nodeOrTokenMap[token].AsToken().CopyAnnotationsTo(base.VisitToken(token));
  664. }
  665. public override SyntaxTrivia VisitTrivia(SyntaxTrivia trivia)
  666. {
  667. if (trivia.IsKind(SyntaxKind.None))
  668. {
  669. return trivia;
  670. }
  671. // annotation will be set by actual structure trivia
  672. if (trivia.HasStructure)
  673. {
  674. return base.VisitTrivia(trivia);
  675. }
  676. return _triviaMap[trivia].CopyAnnotationsTo(base.VisitTrivia(trivia));
  677. }
  678. }
  679. private readonly string _helloWorldCode = @"using System;
  680. using System.Collections.Generic;
  681. using System.Linq;
  682. /// <summary>
  683. /// Sample Documentation
  684. /// </summary>
  685. class Program
  686. {
  687. static void Main(string[] args)
  688. {
  689. // User Comments
  690. Console.WriteLine(""Hello World!"");
  691. }
  692. }";
  693. private readonly string _allInOneCSharpCode = TestResource.AllInOneCSharpCode;
  694. }
  695. }