You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

823 lines
24 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using Microsoft.CodeAnalysis;
  8. using Microsoft.CodeAnalysis.CSharp;
  9. using Microsoft.CodeAnalysis.CSharp.Syntax;
  10. using Microsoft.CodeAnalysis.Shared.Extensions;
  11. using Microsoft.CodeAnalysis.Text;
  12. using Roslyn.Utilities;
  13. namespace ICSharpCode.ILSpy.AddIn
  14. {
  15. static class SyntaxNodeExtensions
  16. {
  17. public static IEnumerable<SyntaxNode> GetAncestors(this SyntaxNode node)
  18. {
  19. var current = node.Parent;
  20. while (current != null)
  21. {
  22. yield return current;
  23. current = current is IStructuredTriviaSyntax
  24. ? ((IStructuredTriviaSyntax)current).ParentTrivia.Token.Parent
  25. : current.Parent;
  26. }
  27. }
  28. public static IEnumerable<TNode> GetAncestors<TNode>(this SyntaxNode node)
  29. where TNode : SyntaxNode
  30. {
  31. var current = node.Parent;
  32. while (current != null)
  33. {
  34. if (current is TNode)
  35. {
  36. yield return (TNode)current;
  37. }
  38. current = current is IStructuredTriviaSyntax
  39. ? ((IStructuredTriviaSyntax)current).ParentTrivia.Token.Parent
  40. : current.Parent;
  41. }
  42. }
  43. public static TNode GetAncestor<TNode>(this SyntaxNode node)
  44. where TNode : SyntaxNode
  45. {
  46. if (node == null)
  47. {
  48. return default(TNode);
  49. }
  50. return node.GetAncestors<TNode>().FirstOrDefault();
  51. }
  52. public static TNode GetAncestorOrThis<TNode>(this SyntaxNode node)
  53. where TNode : SyntaxNode
  54. {
  55. if (node == null)
  56. {
  57. return default(TNode);
  58. }
  59. return node.GetAncestorsOrThis<TNode>().FirstOrDefault();
  60. }
  61. public static IEnumerable<TNode> GetAncestorsOrThis<TNode>(this SyntaxNode node)
  62. where TNode : SyntaxNode
  63. {
  64. var current = node;
  65. while (current != null)
  66. {
  67. if (current is TNode)
  68. {
  69. yield return (TNode)current;
  70. }
  71. current = current is IStructuredTriviaSyntax
  72. ? ((IStructuredTriviaSyntax)current).ParentTrivia.Token.Parent
  73. : current.Parent;
  74. }
  75. }
  76. public static bool HasAncestor<TNode>(this SyntaxNode node)
  77. where TNode : SyntaxNode
  78. {
  79. return node.GetAncestors<TNode>().Any();
  80. }
  81. public static bool CheckParent<T>(this SyntaxNode node, Func<T, bool> valueChecker) where T : SyntaxNode
  82. {
  83. if (node == null)
  84. {
  85. return false;
  86. }
  87. var parentNode = node.Parent as T;
  88. if (parentNode == null)
  89. {
  90. return false;
  91. }
  92. return valueChecker(parentNode);
  93. }
  94. /// <summary>
  95. /// Returns true if is a given token is a child token of of a certain type of parent node.
  96. /// </summary>
  97. /// <typeparam name="TParent">The type of the parent node.</typeparam>
  98. /// <param name="node">The node that we are testing.</param>
  99. /// <param name="childGetter">A function that, when given the parent node, returns the child token we are interested in.</param>
  100. public static bool IsChildNode<TParent>(this SyntaxNode node, Func<TParent, SyntaxNode> childGetter)
  101. where TParent : SyntaxNode
  102. {
  103. var ancestor = node.GetAncestor<TParent>();
  104. if (ancestor == null)
  105. {
  106. return false;
  107. }
  108. var ancestorNode = childGetter(ancestor);
  109. return node == ancestorNode;
  110. }
  111. /// <summary>
  112. /// Returns true if this node is found underneath the specified child in the given parent.
  113. /// </summary>
  114. public static bool IsFoundUnder<TParent>(this SyntaxNode node, Func<TParent, SyntaxNode> childGetter)
  115. where TParent : SyntaxNode
  116. {
  117. var ancestor = node.GetAncestor<TParent>();
  118. if (ancestor == null)
  119. {
  120. return false;
  121. }
  122. var child = childGetter(ancestor);
  123. // See if node passes through child on the way up to ancestor.
  124. return node.GetAncestorsOrThis<SyntaxNode>().Contains(child);
  125. }
  126. public static SyntaxNode GetCommonRoot(this SyntaxNode node1, SyntaxNode node2)
  127. {
  128. //Contract.ThrowIfTrue(node1.RawKind == 0 || node2.RawKind == 0);
  129. // find common starting node from two nodes.
  130. // as long as two nodes belong to same tree, there must be at least one common root (Ex, compilation unit)
  131. var ancestors = node1.GetAncestorsOrThis<SyntaxNode>();
  132. var set = new HashSet<SyntaxNode>(node2.GetAncestorsOrThis<SyntaxNode>());
  133. return ancestors.First(set.Contains);
  134. }
  135. public static int Width(this SyntaxNode node)
  136. {
  137. return node.Span.Length;
  138. }
  139. public static int FullWidth(this SyntaxNode node)
  140. {
  141. return node.FullSpan.Length;
  142. }
  143. public static SyntaxNode FindInnermostCommonNode(
  144. this IEnumerable<SyntaxNode> nodes,
  145. Func<SyntaxNode, bool> predicate)
  146. {
  147. IEnumerable<SyntaxNode> blocks = null;
  148. foreach (var node in nodes)
  149. {
  150. blocks = blocks == null
  151. ? node.AncestorsAndSelf().Where(predicate)
  152. : blocks.Intersect(node.AncestorsAndSelf().Where(predicate));
  153. }
  154. return blocks == null ? null : blocks.First();
  155. }
  156. public static TSyntaxNode FindInnermostCommonNode<TSyntaxNode>(this IEnumerable<SyntaxNode> nodes)
  157. where TSyntaxNode : SyntaxNode
  158. {
  159. return (TSyntaxNode)nodes.FindInnermostCommonNode(n => n is TSyntaxNode);
  160. }
  161. /// <summary>
  162. /// create a new root node from the given root after adding annotations to the tokens
  163. ///
  164. /// tokens should belong to the given root
  165. /// </summary>
  166. public static SyntaxNode AddAnnotations(this SyntaxNode root, IEnumerable<Tuple<SyntaxToken, SyntaxAnnotation>> pairs)
  167. {
  168. // Contract.ThrowIfNull(root);
  169. // Contract.ThrowIfNull(pairs);
  170. var tokenMap = pairs.GroupBy(p => p.Item1, p => p.Item2).ToDictionary(g => g.Key, g => g.ToArray());
  171. return root.ReplaceTokens(tokenMap.Keys, (o, n) => o.WithAdditionalAnnotations(tokenMap[o]));
  172. }
  173. /// <summary>
  174. /// create a new root node from the given root after adding annotations to the nodes
  175. ///
  176. /// nodes should belong to the given root
  177. /// </summary>
  178. public static SyntaxNode AddAnnotations(this SyntaxNode root, IEnumerable<Tuple<SyntaxNode, SyntaxAnnotation>> pairs)
  179. {
  180. // Contract.ThrowIfNull(root);
  181. // Contract.ThrowIfNull(pairs);
  182. var tokenMap = pairs.GroupBy(p => p.Item1, p => p.Item2).ToDictionary(g => g.Key, g => g.ToArray());
  183. return root.ReplaceNodes(tokenMap.Keys, (o, n) => o.WithAdditionalAnnotations(tokenMap[o]));
  184. }
  185. public static TextSpan GetContainedSpan(this IEnumerable<SyntaxNode> nodes)
  186. {
  187. // Contract.ThrowIfNull(nodes);
  188. // Contract.ThrowIfFalse(nodes.Any());
  189. TextSpan fullSpan = nodes.First().Span;
  190. foreach (var node in nodes)
  191. {
  192. fullSpan = TextSpan.FromBounds(
  193. Math.Min(fullSpan.Start, node.SpanStart),
  194. Math.Max(fullSpan.End, node.Span.End));
  195. }
  196. return fullSpan;
  197. }
  198. public static IEnumerable<TextSpan> GetContiguousSpans(
  199. this IEnumerable<SyntaxNode> nodes, Func<SyntaxNode, SyntaxToken> getLastToken = null)
  200. {
  201. SyntaxNode lastNode = null;
  202. TextSpan? textSpan = null;
  203. foreach (var node in nodes)
  204. {
  205. if (lastNode == null)
  206. {
  207. textSpan = node.Span;
  208. }
  209. else
  210. {
  211. var lastToken = getLastToken == null
  212. ? lastNode.GetLastToken()
  213. : getLastToken(lastNode);
  214. if (lastToken.GetNextToken(includeDirectives: true) == node.GetFirstToken())
  215. {
  216. // Expand the span
  217. textSpan = TextSpan.FromBounds(textSpan.Value.Start, node.Span.End);
  218. }
  219. else
  220. {
  221. // Return the last span, and start a new one
  222. yield return textSpan.Value;
  223. textSpan = node.Span;
  224. }
  225. }
  226. lastNode = node;
  227. }
  228. if (textSpan.HasValue)
  229. {
  230. yield return textSpan.Value;
  231. }
  232. }
  233. //public static bool OverlapsHiddenPosition(this SyntaxNode node, CancellationToken cancellationToken)
  234. //{
  235. // return node.OverlapsHiddenPosition(node.Span, cancellationToken);
  236. //}
  237. //public static bool OverlapsHiddenPosition(this SyntaxNode node, TextSpan span, CancellationToken cancellationToken)
  238. //{
  239. // return node.SyntaxTree.OverlapsHiddenPosition(span, cancellationToken);
  240. //}
  241. //public static bool OverlapsHiddenPosition(this SyntaxNode declaration, SyntaxNode startNode, SyntaxNode endNode, CancellationToken cancellationToken)
  242. //{
  243. // var start = startNode.Span.End;
  244. // var end = endNode.SpanStart;
  245. // var textSpan = TextSpan.FromBounds(start, end);
  246. // return declaration.OverlapsHiddenPosition(textSpan, cancellationToken);
  247. //}
  248. public static IEnumerable<T> GetAnnotatedNodes<T>(this SyntaxNode node, SyntaxAnnotation syntaxAnnotation) where T : SyntaxNode
  249. {
  250. return node.GetAnnotatedNodesAndTokens(syntaxAnnotation).Select(n => n.AsNode()).OfType<T>();
  251. }
  252. public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2)
  253. {
  254. if (node == null)
  255. {
  256. return false;
  257. }
  258. var csharpKind = node.Kind();
  259. return csharpKind == kind1 || csharpKind == kind2;
  260. }
  261. public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3)
  262. {
  263. if (node == null)
  264. {
  265. return false;
  266. }
  267. var csharpKind = node.Kind();
  268. return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3;
  269. }
  270. public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4)
  271. {
  272. if (node == null)
  273. {
  274. return false;
  275. }
  276. var csharpKind = node.Kind();
  277. return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3 || csharpKind == kind4;
  278. }
  279. public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5)
  280. {
  281. if (node == null)
  282. {
  283. return false;
  284. }
  285. var csharpKind = node.Kind();
  286. return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3 || csharpKind == kind4 || csharpKind == kind5;
  287. }
  288. /// <summary>
  289. /// Returns the list of using directives that affect <paramref name="node"/>. The list will be returned in
  290. /// top down order.
  291. /// </summary>
  292. public static IEnumerable<UsingDirectiveSyntax> GetEnclosingUsingDirectives(this SyntaxNode node)
  293. {
  294. return node.GetAncestorOrThis<CompilationUnitSyntax>().Usings
  295. .Concat(node.GetAncestorsOrThis<NamespaceDeclarationSyntax>()
  296. .Reverse()
  297. .SelectMany(n => n.Usings));
  298. }
  299. public static bool IsUnsafeContext(this SyntaxNode node)
  300. {
  301. if (node.GetAncestor<UnsafeStatementSyntax>() != null)
  302. {
  303. return true;
  304. }
  305. return node.GetAncestors<MemberDeclarationSyntax>().Any(
  306. m => m.GetModifiers().Any(SyntaxKind.UnsafeKeyword));
  307. }
  308. public static bool IsInStaticContext(this SyntaxNode node)
  309. {
  310. // this/base calls are always static.
  311. if (node.FirstAncestorOrSelf<ConstructorInitializerSyntax>() != null)
  312. {
  313. return true;
  314. }
  315. var memberDeclaration = node.FirstAncestorOrSelf<MemberDeclarationSyntax>();
  316. if (memberDeclaration == null)
  317. {
  318. return false;
  319. }
  320. switch (memberDeclaration.Kind())
  321. {
  322. case SyntaxKind.MethodDeclaration:
  323. case SyntaxKind.ConstructorDeclaration:
  324. case SyntaxKind.PropertyDeclaration:
  325. case SyntaxKind.EventDeclaration:
  326. case SyntaxKind.IndexerDeclaration:
  327. return memberDeclaration.GetModifiers().Any(SyntaxKind.StaticKeyword);
  328. case SyntaxKind.FieldDeclaration:
  329. // Inside a field one can only access static members of a type.
  330. return true;
  331. case SyntaxKind.DestructorDeclaration:
  332. return false;
  333. }
  334. // Global statements are not a static context.
  335. if (node.FirstAncestorOrSelf<GlobalStatementSyntax>() != null)
  336. {
  337. return false;
  338. }
  339. // any other location is considered static
  340. return true;
  341. }
  342. public static NamespaceDeclarationSyntax GetInnermostNamespaceDeclarationWithUsings(this SyntaxNode contextNode)
  343. {
  344. var usingDirectiveAncestor = contextNode.GetAncestor<UsingDirectiveSyntax>();
  345. if (usingDirectiveAncestor == null)
  346. {
  347. return contextNode.GetAncestorsOrThis<NamespaceDeclarationSyntax>().FirstOrDefault(n => n.Usings.Count > 0);
  348. }
  349. else
  350. {
  351. // We are inside a using directive. In this case, we should find and return the first 'parent' namespace with usings.
  352. var containingNamespace = usingDirectiveAncestor.GetAncestor<NamespaceDeclarationSyntax>();
  353. if (containingNamespace == null)
  354. {
  355. // We are inside a top level using directive (i.e. one that's directly in the compilation unit).
  356. return null;
  357. }
  358. else
  359. {
  360. return containingNamespace.GetAncestors<NamespaceDeclarationSyntax>().FirstOrDefault(n => n.Usings.Count > 0);
  361. }
  362. }
  363. }
  364. /// <summary>
  365. /// Returns all of the trivia to the left of this token up to the previous token (concatenates
  366. /// the previous token's trailing trivia and this token's leading trivia).
  367. /// </summary>
  368. public static IEnumerable<SyntaxTrivia> GetAllPrecedingTriviaToPreviousToken(this SyntaxToken token)
  369. {
  370. var prevToken = token.GetPreviousToken(includeSkipped: true);
  371. if (prevToken.Kind() == SyntaxKind.None)
  372. {
  373. return token.LeadingTrivia;
  374. }
  375. return prevToken.TrailingTrivia.Concat(token.LeadingTrivia);
  376. }
  377. public static bool IsBreakableConstruct(this SyntaxNode node)
  378. {
  379. switch (node.Kind())
  380. {
  381. case SyntaxKind.DoStatement:
  382. case SyntaxKind.WhileStatement:
  383. case SyntaxKind.SwitchStatement:
  384. case SyntaxKind.ForStatement:
  385. case SyntaxKind.ForEachStatement:
  386. return true;
  387. }
  388. return false;
  389. }
  390. public static bool IsContinuableConstruct(this SyntaxNode node)
  391. {
  392. switch (node.Kind())
  393. {
  394. case SyntaxKind.DoStatement:
  395. case SyntaxKind.WhileStatement:
  396. case SyntaxKind.ForStatement:
  397. case SyntaxKind.ForEachStatement:
  398. return true;
  399. }
  400. return false;
  401. }
  402. public static bool IsReturnableConstruct(this SyntaxNode node)
  403. {
  404. switch (node.Kind())
  405. {
  406. case SyntaxKind.AnonymousMethodExpression:
  407. case SyntaxKind.SimpleLambdaExpression:
  408. case SyntaxKind.ParenthesizedLambdaExpression:
  409. case SyntaxKind.MethodDeclaration:
  410. case SyntaxKind.ConstructorDeclaration:
  411. case SyntaxKind.DestructorDeclaration:
  412. case SyntaxKind.GetAccessorDeclaration:
  413. case SyntaxKind.SetAccessorDeclaration:
  414. case SyntaxKind.OperatorDeclaration:
  415. case SyntaxKind.AddAccessorDeclaration:
  416. case SyntaxKind.RemoveAccessorDeclaration:
  417. return true;
  418. }
  419. return false;
  420. }
  421. public static bool IsAnyArgumentList(this SyntaxNode node)
  422. {
  423. return node.IsKind(SyntaxKind.ArgumentList) ||
  424. node.IsKind(SyntaxKind.AttributeArgumentList) ||
  425. node.IsKind(SyntaxKind.BracketedArgumentList) ||
  426. node.IsKind(SyntaxKind.TypeArgumentList);
  427. }
  428. public static bool IsAnyLambda(this SyntaxNode node)
  429. {
  430. return
  431. node.IsKind(SyntaxKind.ParenthesizedLambdaExpression) ||
  432. node.IsKind(SyntaxKind.SimpleLambdaExpression);
  433. }
  434. public static bool IsAnyLambdaOrAnonymousMethod(this SyntaxNode node)
  435. {
  436. return node.IsAnyLambda() || node.IsKind(SyntaxKind.AnonymousMethodExpression);
  437. }
  438. public static bool IsAnyAssignExpression(this SyntaxNode node)
  439. {
  440. return SyntaxFacts.IsAssignmentExpression(node.Kind());
  441. }
  442. public static bool IsParentKind(this SyntaxNode node, SyntaxKind kind)
  443. {
  444. return node != null && node.Parent.IsKind(kind);
  445. }
  446. public static bool IsParentKind(this SyntaxToken node, SyntaxKind kind)
  447. {
  448. return node.Parent != null && node.Parent.IsKind(kind);
  449. }
  450. public static bool IsCompoundAssignExpression(this SyntaxNode node)
  451. {
  452. switch (node.Kind())
  453. {
  454. case SyntaxKind.AddAssignmentExpression:
  455. case SyntaxKind.SubtractAssignmentExpression:
  456. case SyntaxKind.MultiplyAssignmentExpression:
  457. case SyntaxKind.DivideAssignmentExpression:
  458. case SyntaxKind.ModuloAssignmentExpression:
  459. case SyntaxKind.AndAssignmentExpression:
  460. case SyntaxKind.ExclusiveOrAssignmentExpression:
  461. case SyntaxKind.OrAssignmentExpression:
  462. case SyntaxKind.LeftShiftAssignmentExpression:
  463. case SyntaxKind.RightShiftAssignmentExpression:
  464. return true;
  465. }
  466. return false;
  467. }
  468. public static bool IsLeftSideOfAssignExpression(this SyntaxNode node)
  469. {
  470. return node.IsParentKind(SyntaxKind.SimpleAssignmentExpression) &&
  471. ((AssignmentExpressionSyntax)node.Parent).Left == node;
  472. }
  473. public static bool IsLeftSideOfAnyAssignExpression(this SyntaxNode node)
  474. {
  475. return node.Parent.IsAnyAssignExpression() &&
  476. ((AssignmentExpressionSyntax)node.Parent).Left == node;
  477. }
  478. public static bool IsRightSideOfAnyAssignExpression(this SyntaxNode node)
  479. {
  480. return node.Parent.IsAnyAssignExpression() &&
  481. ((AssignmentExpressionSyntax)node.Parent).Right == node;
  482. }
  483. public static bool IsVariableDeclaratorValue(this SyntaxNode node)
  484. {
  485. return
  486. node.IsParentKind(SyntaxKind.EqualsValueClause) &&
  487. node.Parent.IsParentKind(SyntaxKind.VariableDeclarator) &&
  488. ((EqualsValueClauseSyntax)node.Parent).Value == node;
  489. }
  490. public static BlockSyntax FindInnermostCommonBlock(this IEnumerable<SyntaxNode> nodes)
  491. {
  492. return nodes.FindInnermostCommonNode<BlockSyntax>();
  493. }
  494. public static IEnumerable<SyntaxNode> GetAncestorsOrThis(this SyntaxNode node, Func<SyntaxNode, bool> predicate)
  495. {
  496. var current = node;
  497. while (current != null)
  498. {
  499. if (predicate(current))
  500. {
  501. yield return current;
  502. }
  503. current = current.Parent;
  504. }
  505. }
  506. public static SyntaxNode GetParent(this SyntaxNode node)
  507. {
  508. return node != null ? node.Parent : null;
  509. }
  510. public static ValueTuple<SyntaxToken, SyntaxToken> GetBraces(this SyntaxNode node)
  511. {
  512. var namespaceNode = node as NamespaceDeclarationSyntax;
  513. if (namespaceNode != null)
  514. {
  515. return ValueTuple.Create(namespaceNode.OpenBraceToken, namespaceNode.CloseBraceToken);
  516. }
  517. var baseTypeNode = node as BaseTypeDeclarationSyntax;
  518. if (baseTypeNode != null)
  519. {
  520. return ValueTuple.Create(baseTypeNode.OpenBraceToken, baseTypeNode.CloseBraceToken);
  521. }
  522. var accessorListNode = node as AccessorListSyntax;
  523. if (accessorListNode != null)
  524. {
  525. return ValueTuple.Create(accessorListNode.OpenBraceToken, accessorListNode.CloseBraceToken);
  526. }
  527. var blockNode = node as BlockSyntax;
  528. if (blockNode != null)
  529. {
  530. return ValueTuple.Create(blockNode.OpenBraceToken, blockNode.CloseBraceToken);
  531. }
  532. var switchStatementNode = node as SwitchStatementSyntax;
  533. if (switchStatementNode != null)
  534. {
  535. return ValueTuple.Create(switchStatementNode.OpenBraceToken, switchStatementNode.CloseBraceToken);
  536. }
  537. var anonymousObjectCreationExpression = node as AnonymousObjectCreationExpressionSyntax;
  538. if (anonymousObjectCreationExpression != null)
  539. {
  540. return ValueTuple.Create(anonymousObjectCreationExpression.OpenBraceToken, anonymousObjectCreationExpression.CloseBraceToken);
  541. }
  542. var initializeExpressionNode = node as InitializerExpressionSyntax;
  543. if (initializeExpressionNode != null)
  544. {
  545. return ValueTuple.Create(initializeExpressionNode.OpenBraceToken, initializeExpressionNode.CloseBraceToken);
  546. }
  547. return new ValueTuple<SyntaxToken, SyntaxToken>();
  548. }
  549. public static SyntaxTokenList GetModifiers(this SyntaxNode member)
  550. {
  551. if (member != null)
  552. {
  553. switch (member.Kind())
  554. {
  555. case SyntaxKind.EnumDeclaration:
  556. return ((EnumDeclarationSyntax)member).Modifiers;
  557. case SyntaxKind.ClassDeclaration:
  558. case SyntaxKind.InterfaceDeclaration:
  559. case SyntaxKind.StructDeclaration:
  560. return ((TypeDeclarationSyntax)member).Modifiers;
  561. case SyntaxKind.DelegateDeclaration:
  562. return ((DelegateDeclarationSyntax)member).Modifiers;
  563. case SyntaxKind.FieldDeclaration:
  564. return ((FieldDeclarationSyntax)member).Modifiers;
  565. case SyntaxKind.EventFieldDeclaration:
  566. return ((EventFieldDeclarationSyntax)member).Modifiers;
  567. case SyntaxKind.ConstructorDeclaration:
  568. return ((ConstructorDeclarationSyntax)member).Modifiers;
  569. case SyntaxKind.DestructorDeclaration:
  570. return ((DestructorDeclarationSyntax)member).Modifiers;
  571. case SyntaxKind.PropertyDeclaration:
  572. return ((PropertyDeclarationSyntax)member).Modifiers;
  573. case SyntaxKind.EventDeclaration:
  574. return ((EventDeclarationSyntax)member).Modifiers;
  575. case SyntaxKind.IndexerDeclaration:
  576. return ((IndexerDeclarationSyntax)member).Modifiers;
  577. case SyntaxKind.OperatorDeclaration:
  578. return ((OperatorDeclarationSyntax)member).Modifiers;
  579. case SyntaxKind.ConversionOperatorDeclaration:
  580. return ((ConversionOperatorDeclarationSyntax)member).Modifiers;
  581. case SyntaxKind.MethodDeclaration:
  582. return ((MethodDeclarationSyntax)member).Modifiers;
  583. case SyntaxKind.GetAccessorDeclaration:
  584. case SyntaxKind.SetAccessorDeclaration:
  585. case SyntaxKind.AddAccessorDeclaration:
  586. case SyntaxKind.RemoveAccessorDeclaration:
  587. return ((AccessorDeclarationSyntax)member).Modifiers;
  588. }
  589. }
  590. return default(SyntaxTokenList);
  591. }
  592. public static SyntaxNode WithModifiers(this SyntaxNode member, SyntaxTokenList modifiers)
  593. {
  594. if (member != null)
  595. {
  596. switch (member.Kind())
  597. {
  598. case SyntaxKind.EnumDeclaration:
  599. return ((EnumDeclarationSyntax)member).WithModifiers(modifiers);
  600. case SyntaxKind.ClassDeclaration:
  601. case SyntaxKind.InterfaceDeclaration:
  602. case SyntaxKind.StructDeclaration:
  603. return ((TypeDeclarationSyntax)member).WithModifiers(modifiers);
  604. case SyntaxKind.DelegateDeclaration:
  605. return ((DelegateDeclarationSyntax)member).WithModifiers(modifiers);
  606. case SyntaxKind.FieldDeclaration:
  607. return ((FieldDeclarationSyntax)member).WithModifiers(modifiers);
  608. case SyntaxKind.EventFieldDeclaration:
  609. return ((EventFieldDeclarationSyntax)member).WithModifiers(modifiers);
  610. case SyntaxKind.ConstructorDeclaration:
  611. return ((ConstructorDeclarationSyntax)member).WithModifiers(modifiers);
  612. case SyntaxKind.DestructorDeclaration:
  613. return ((DestructorDeclarationSyntax)member).WithModifiers(modifiers);
  614. case SyntaxKind.PropertyDeclaration:
  615. return ((PropertyDeclarationSyntax)member).WithModifiers(modifiers);
  616. case SyntaxKind.EventDeclaration:
  617. return ((EventDeclarationSyntax)member).WithModifiers(modifiers);
  618. case SyntaxKind.IndexerDeclaration:
  619. return ((IndexerDeclarationSyntax)member).WithModifiers(modifiers);
  620. case SyntaxKind.OperatorDeclaration:
  621. return ((OperatorDeclarationSyntax)member).WithModifiers(modifiers);
  622. case SyntaxKind.ConversionOperatorDeclaration:
  623. return ((ConversionOperatorDeclarationSyntax)member).WithModifiers(modifiers);
  624. case SyntaxKind.MethodDeclaration:
  625. return ((MethodDeclarationSyntax)member).WithModifiers(modifiers);
  626. case SyntaxKind.GetAccessorDeclaration:
  627. case SyntaxKind.SetAccessorDeclaration:
  628. case SyntaxKind.AddAccessorDeclaration:
  629. case SyntaxKind.RemoveAccessorDeclaration:
  630. return ((AccessorDeclarationSyntax)member).WithModifiers(modifiers);
  631. }
  632. }
  633. return null;
  634. }
  635. public static TypeDeclarationSyntax WithModifiers(
  636. this TypeDeclarationSyntax node, SyntaxTokenList modifiers)
  637. {
  638. switch (node.Kind())
  639. {
  640. case SyntaxKind.ClassDeclaration:
  641. return ((ClassDeclarationSyntax)node).WithModifiers(modifiers);
  642. case SyntaxKind.InterfaceDeclaration:
  643. return ((InterfaceDeclarationSyntax)node).WithModifiers(modifiers);
  644. case SyntaxKind.StructDeclaration:
  645. return ((StructDeclarationSyntax)node).WithModifiers(modifiers);
  646. }
  647. throw new InvalidOperationException();
  648. }
  649. public static bool CheckTopLevel(this SyntaxNode node, TextSpan span)
  650. {
  651. var block = node as BlockSyntax;
  652. if (block != null)
  653. {
  654. return block.ContainsInBlockBody(span);
  655. }
  656. var field = node as FieldDeclarationSyntax;
  657. if (field != null)
  658. {
  659. foreach (var variable in field.Declaration.Variables)
  660. {
  661. if (variable.Initializer != null && variable.Initializer.Span.Contains(span))
  662. {
  663. return true;
  664. }
  665. }
  666. }
  667. var global = node as GlobalStatementSyntax;
  668. if (global != null)
  669. {
  670. return true;
  671. }
  672. var constructorInitializer = node as ConstructorInitializerSyntax;
  673. if (constructorInitializer != null)
  674. {
  675. return constructorInitializer.ContainsInArgument(span);
  676. }
  677. return false;
  678. }
  679. public static bool ContainsInArgument(this ConstructorInitializerSyntax initializer, TextSpan textSpan)
  680. {
  681. if (initializer == null)
  682. {
  683. return false;
  684. }
  685. return initializer.ArgumentList.Arguments.Any(a => a.Span.Contains(textSpan));
  686. }
  687. public static bool ContainsInBlockBody(this BlockSyntax block, TextSpan textSpan)
  688. {
  689. if (block == null)
  690. {
  691. return false;
  692. }
  693. var blockSpan = TextSpan.FromBounds(block.OpenBraceToken.Span.End, block.CloseBraceToken.SpanStart);
  694. return blockSpan.Contains(textSpan);
  695. }
  696. public static bool IsDelegateOrConstructorOrMethodParameterList(this SyntaxNode node)
  697. {
  698. if (!node.IsKind(SyntaxKind.ParameterList))
  699. {
  700. return false;
  701. }
  702. return
  703. node.IsParentKind(SyntaxKind.MethodDeclaration) ||
  704. node.IsParentKind(SyntaxKind.ConstructorDeclaration) ||
  705. node.IsParentKind(SyntaxKind.DelegateDeclaration);
  706. }
  707. }
  708. }