/// <summary> /// Visits a member. /// </summary> /// <typeparam name="T">The syntax node type to visit.</typeparam> /// <param name="node">The node to visit.</param> /// <param name="exctractName">Extract the node name.</param> /// <param name="typeParameterList">The type parameter list.</param> /// <param name="targetNode">Resolved the target node.</param> /// <param name="visit">Visit sub nodes.</param> private void Visit <T>(T node, Func <T, string> exctractName, TypeParameterListSyntax typeParameterList, Func <T, SyntaxNode> targetNode, Action <T> visit) where T : CSharpSyntaxNode { // Retrieve the accessor name string name = exctractName(node); // Compute suffix for representing generics if (null != typeParameterList) { name = string.Format( "{0}{{{1}}}", name, string.Join(",", typeParameterList.Parameters.Select(x => x.ToString()))); } // Keep track of the initial node the restore the root after the visit CSharpSyntaxMatchingNode initialNode = this.Root; // Create and add the node this.Root = this.Root.EnsureNode(name); this.Root.AddSyntaxNode(targetNode(node)); // Trigger member visiting visit(node); // Copy the class sub tree to the Trie root this.Root.CopyTo(this.internalInvariantRoot, name); // Restore the initial root this.Root = initialNode; }
/// <summary> /// Visits a namespace declaration. /// A namespace may be composed with different segment dot separated, each segment has to be represented by a different node. /// However the syntax node is attached to the last node only. /// </summary> /// <param name="node">The namespace declaration node to visit.</param> public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) { // Retrieve the namespace name and split segments string name = node.Name.ToString(); string[] namespaces = name.Split('.'); // Keep track of the initial node the restore the root after the visit CSharpSyntaxMatchingNode initialNode = this.Root; // Browse all namespaces and generate intermediate node for each segment for the copy to the root CSharpSyntaxMatchingNode firstNamespaceNode = null; foreach (string currentNamespace in namespaces) { // Create the node and keep track of the first one this.Root = this.Root.EnsureNode(currentNamespace); if (null == firstNamespaceNode) { firstNamespaceNode = this.Root; } } // Add the syntax node the last segment this.Root.AddSyntaxNode(node); // Triger member visiting base.VisitNamespaceDeclaration(node); // Copy the generated sub tree to the Trie root firstNamespaceNode.CopyTo(this.internalInvariantRoot, namespaces[0]); // Restore the initial root this.Root = initialNode; }
/// <summary> /// Copies to a given node. /// </summary> /// <param name="targetNode">The node wherer to copy.</param> /// <param name="name">The node name.</param> public void CopyTo(CSharpSyntaxMatchingNode targetNode, string name) { // Data validation Ensure.That(() => name).IsNotNullOrWhiteSpace(); Ensure.That(() => targetNode).IsNotNull(); // Ensure and retrieve a node the the copy CSharpSyntaxMatchingNode newNode = targetNode.EnsureNode(name); // Add syntax node to the created node if (null != this.matchingSyntaxNodes) { // Lazy create the syntax nodes if (null == newNode.matchingSyntaxNodes) { newNode.matchingSyntaxNodes = new List <SyntaxNode>(); } // Merge syntax nodes int[] indexes = newNode.matchingSyntaxNodes.Select(x => x.Span.Start).ToArray(); newNode.matchingSyntaxNodes.AddRange(this.matchingSyntaxNodes.Where(x => !indexes.Contains(x.Span.Start))); } // Recurse for applying copy to the children if (null != this.children && this.children.Count > 0) { string[] childrenName = this.children.Keys.ToArray(); foreach (string childName in childrenName) { this.children[childName].CopyTo(newNode, childName); } } }
/// <summary> /// Copies to a given node. /// </summary> /// <param name="targetNode">The node wherer to copy.</param> /// <param name="name">The node name.</param> public void CopyTo(CSharpSyntaxMatchingNode targetNode, string name) { // Data validation Ensure.That(() => name).IsNotNullOrWhiteSpace(); Ensure.That(() => targetNode).IsNotNull(); // Ensure and retrieve a node the the copy CSharpSyntaxMatchingNode newNode = targetNode.EnsureNode(name); // Add syntax node to the created node if (null != this.matchingSyntaxNodes) { // Lazy create the syntax nodes if (null == newNode.matchingSyntaxNodes) { newNode.matchingSyntaxNodes = new List<SyntaxNode>(); } // Merge syntax nodes int[] indexes = newNode.matchingSyntaxNodes.Select(x => x.Span.Start).ToArray(); newNode.matchingSyntaxNodes.AddRange(this.matchingSyntaxNodes.Where(x => !indexes.Contains(x.Span.Start))); } // Recurse for applying copy to the children if (null != this.children && this.children.Count > 0) { string[] childrenName = this.children.Keys.ToArray(); foreach (string childName in childrenName) { this.children[childName].CopyTo(newNode, childName); } } }
/// <summary> /// Finds a node from syntax chunk. /// </summary> /// <param name="chunks">The chunks to match.</param> /// <returns></returns> public CSharpSyntaxMatchingNode Match(string[] chunks) { // Data validation Ensure.That(() => chunks).IsNotNull(); // Browse the Trie until finding a matching CSharpSyntaxMatchingNode matchingNode = this; foreach (string fragment in chunks) { // Could not find any matching if (null == matchingNode.children || !matchingNode.children.TryGetValue(fragment, out matchingNode)) { return(null); } } // Return the matching node return(matchingNode); }
/// <summary> /// Finds a node from syntax chunk. /// </summary> /// <param name="chunks">The chunks to match.</param> /// <returns></returns> public CSharpSyntaxMatchingNode Match(string[] chunks) { if (chunks == null) { throw new ArgumentNullException(nameof(chunks)); } // Browse the Trie until finding a matching CSharpSyntaxMatchingNode matchingNode = this; foreach (string fragment in chunks) { // Could not find any matching if (null == matchingNode.children || !matchingNode.children.TryGetValue(fragment, out matchingNode)) { return(null); } } // Return the matching node return(matchingNode); }
/// <summary> /// Extracts a snippet from a given rule pattern. /// </summary> /// <param name="fullFilename">The full filename (with path) to load and to extract the snippet from.</param> /// <param name="memberPattern">The member pattern to extract.</param> /// <returns>The extracted snippet.</returns> public override string Extract(string fullFilename, string memberPattern) { // Return the entire code if no member is specified if (string.IsNullOrWhiteSpace(memberPattern)) { return(base.Extract(fullFilename, memberPattern)); } // Parse the matching rule from the pattern CSharpMatchingRule rule = CSharpMatchingRule.Parse(memberPattern); // Load the trie for pattern matching if (null == this.syntaxTrie) { // Load file content string sourceCode = this.LoadFile(fullFilename); // Build a syntax tree from the source code SyntaxTree tree = CSharpSyntaxTree.ParseText(sourceCode); SyntaxNode root = tree.GetRoot(); // Visit the syntax tree for generating a Trie for pattern matching CSharpSyntaxWalkerMatchingBuilder syntaxMatchingBuilder = new CSharpSyntaxWalkerMatchingBuilder(); syntaxMatchingBuilder.Visit(root); // Retrieve the Trie root this.syntaxTrie = syntaxMatchingBuilder.Root; } // Match the rule from the syntax matching Trie CSharpSyntaxMatchingNode matchingTrie = syntaxTrie.Match(rule.MatchingChunks); if (null == matchingTrie) { throw new SnippetExtractionException("Cannot find member", memberPattern); } // Build a snippet for extracted syntax nodes return(this.BuildSnippet(matchingTrie.MatchingSyntaxNodes, rule.ExtractionMode)); }
/// <summary> /// Extracts a snippet from a given rule pattern. /// </summary> /// <param name="fullFilename">The full filename (with path) to load and to extract the snippet from.</param> /// <param name="memberPattern">The member pattern to extract.</param> /// <returns>The extracted snippet.</returns> public override string Extract(string fullFilename, string memberPattern) { // Return the entire code if no member is specified if (string.IsNullOrWhiteSpace(memberPattern)) { return base.Extract(fullFilename, memberPattern); } // Parse the matching rule from the pattern CSharpMatchingRule rule = CSharpMatchingRule.Parse(memberPattern); // Load the trie for pattern matching if (null == this.syntaxTrie) { // Load file content string sourceCode = this.LoadFile(fullFilename); // Build a syntax tree from the source code SyntaxTree tree = CSharpSyntaxTree.ParseText(sourceCode); SyntaxNode root = tree.GetRoot(); // Visit the syntax tree for generating a Trie for pattern matching CSharpSyntaxWalkerMatchingBuilder syntaxMatchingBuilder = new CSharpSyntaxWalkerMatchingBuilder(); syntaxMatchingBuilder.Visit(root); // Retrieve the Trie root this.syntaxTrie = syntaxMatchingBuilder.Root; } // Match the rule from the syntax matching Trie CSharpSyntaxMatchingNode matchingTrie = syntaxTrie.Match(rule.MatchingChunks); if (null == matchingTrie) { throw new SnippetExtractionException("Cannot find member", memberPattern); } // Build a snippet for extracted syntax nodes return this.BuildSnippet(matchingTrie.MatchingSyntaxNodes, rule.ExtractionMode); }
/// <summary> /// Copies to a given node. /// </summary> /// <param name="targetNode">The node wherer to copy.</param> /// <param name="name">The node name.</param> public void CopyTo(CSharpSyntaxMatchingNode targetNode, string name) { if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentException($"'{nameof(name)}' is null or whitespace"); } if (targetNode == null) { throw new ArgumentNullException(nameof(targetNode)); } // Ensure and retrieve a node the the copy CSharpSyntaxMatchingNode newNode = targetNode.EnsureNode(name); // Add syntax node to the created node if (null != this.matchingSyntaxNodes) { // Lazy create the syntax nodes if (null == newNode.matchingSyntaxNodes) { newNode.matchingSyntaxNodes = new List <SyntaxNode>(); } // Merge syntax nodes int[] indexes = newNode.matchingSyntaxNodes.Select(x => x.Span.Start).ToArray(); newNode.matchingSyntaxNodes.AddRange(this.matchingSyntaxNodes.Where(x => !indexes.Contains(x.Span.Start))); } // Recurse for applying copy to the children if (null != this.children && this.children.Count > 0) { string[] childrenName = this.children.Keys.ToArray(); foreach (string childName in childrenName) { this.children[childName].CopyTo(newNode, childName); } } }
/// <summary> /// Copies to a given node. /// </summary> /// <param name="targetNode">The node wherer to copy.</param> /// <param name="name">The node name.</param> public void CopyTo(CSharpSyntaxMatchingNode targetNode, string name) { if(string.IsNullOrWhiteSpace(name)) { throw new ArgumentException($"'{nameof(name)}' is null or whitespace"); } if(targetNode == null) { throw new ArgumentNullException(nameof(targetNode)); } // Ensure and retrieve a node the the copy CSharpSyntaxMatchingNode newNode = targetNode.EnsureNode(name); // Add syntax node to the created node if (null != this.matchingSyntaxNodes) { // Lazy create the syntax nodes if (null == newNode.matchingSyntaxNodes) { newNode.matchingSyntaxNodes = new List<SyntaxNode>(); } // Merge syntax nodes int[] indexes = newNode.matchingSyntaxNodes.Select(x => x.Span.Start).ToArray(); newNode.matchingSyntaxNodes.AddRange(this.matchingSyntaxNodes.Where(x => !indexes.Contains(x.Span.Start))); } // Recurse for applying copy to the children if (null != this.children && this.children.Count > 0) { string[] childrenName = this.children.Keys.ToArray(); foreach (string childName in childrenName) { this.children[childName].CopyTo(newNode, childName); } } }
/// <summary> /// Initializes a new instance of <see cref="CSharpSyntaxWalkerMatchingBuilder"/>. /// </summary> public CSharpSyntaxWalkerMatchingBuilder() { this.internalInvariantRoot = new CSharpSyntaxMatchingNode(); this.Root = this.internalInvariantRoot; }