public SyntaxNodeOrTokenListItem(SyntaxNodeOrToken syntaxNodeOrToken) { _lineSpan = syntaxNodeOrToken.GetLocation().GetLineSpan(); Content = $"{_lineSpan}: {syntaxNodeOrToken.Kind()} {Truncate(syntaxNodeOrToken.ToString())}"; ToolTip = syntaxNodeOrToken.ToString(); }
private void Print(SyntaxNodeOrToken node, bool dump) { if (dump) { switch (node.Kind()) { case SyntaxKind.IdentifierToken: case SyntaxKind.NumericLiteralToken: case SyntaxKind.StringLiteralToken: case SyntaxKind.UTF8StringLiteralToken: case SyntaxKind.SingleLineRawStringLiteralToken: case SyntaxKind.UTF8SingleLineRawStringLiteralToken: case SyntaxKind.MultiLineRawStringLiteralToken: case SyntaxKind.UTF8MultiLineRawStringLiteralToken: if (node.IsMissing) { goto default; } var value = node.ToString().Replace("\"", "\\\""); _output.WriteLine(@"N(SyntaxKind.{0}, ""{1}"");", node.Kind(), value); break; default: _output.WriteLine("{0}(SyntaxKind.{1});", node.IsMissing ? "M" : "N", node.Kind()); break; } } }
private void Print(SyntaxNodeOrToken node, bool dump) { if (dump) { switch (node.Kind()) { case SyntaxKind.IdentifierToken: case SyntaxKind.NumericLiteralToken: if (node.IsMissing) { goto default; } _output.WriteLine( @"N(SyntaxKind.{0}, ""{1}"");", node.Kind(), node.ToString() ); break; default: _output.WriteLine( "{0}(SyntaxKind.{1});", node.IsMissing ? "M" : "N", node.Kind() ); break; } } }
public static Task <Document> AddNewLineBeforeInsteadOfAfterAsync( Document document, SyntaxNodeOrToken left, SyntaxNodeOrToken middle, SyntaxNodeOrToken right, CancellationToken cancellationToken = default) { StringBuilder sb = StringBuilderCache.GetInstance(); SyntaxTriviaList trailingTrivia = middle.GetTrailingTrivia(); if (IsOptionalWhitespaceThenEndOfLineTrivia(trailingTrivia)) { sb.Append(DetermineEndOfLine(middle).ToString()); } else { sb.Append(trailingTrivia.ToString()); } sb.Append(right.GetLeadingTrivia().ToString()); sb.Append(middle.ToString()); sb.Append(" "); return(document.WithTextChangeAsync( TextSpan.FromBounds(left.Span.End, right.SpanStart), StringBuilderCache.GetStringAndFree(sb), cancellationToken)); }
private void NodeToJson(JsonWriter jw, SyntaxNodeOrToken node, Dictionary <SyntaxNodeOrToken, int> nodeToIdx) { jw.WriteStartObject(); jw.WritePropertyName("id"); jw.WriteValue(nodeToIdx[node]); jw.WritePropertyName("type"); jw.WriteValue(node.Kind().ToString()); if (node.IsKind(SyntaxKind.IdentifierName) || node.IsKind(SyntaxKind.PredefinedType) || RoslynUtils.IsSimpleLiteral(node) || node.IsToken || node.AsNode().ChildNodes().Count() == 0) { jw.WritePropertyName("value"); jw.WriteValue(node.ToString()); } else { jw.WritePropertyName("children"); jw.WriteStartArray(); foreach (var child in node.AsNode().ChildNodesAndTokens()) { if (!nodeToIdx.TryGetValue(child, out int idx)) { idx = int.MaxValue; } jw.WriteValue(idx); } jw.WriteEndArray(); } jw.WriteEndObject(); }
public static Task <Document> AddNewLineAfterInsteadOfBeforeAsync( Document document, SyntaxNodeOrToken left, SyntaxNodeOrToken middle, SyntaxNodeOrToken right, CancellationToken cancellationToken = default) { StringBuilder sb = StringBuilderCache.GetInstance(); sb.Append(" "); sb.Append(middle.ToString()); SyntaxTriviaList trailingTrivia = left.GetTrailingTrivia(); if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(trailingTrivia)) { sb.Append(SyntaxTriviaAnalysis.GetEndOfLine(left).ToString()); } else { sb.Append(trailingTrivia.ToString()); } sb.Append(middle.GetLeadingTrivia().ToString()); string newText = StringBuilderCache.GetStringAndFree(sb); var textChange = new TextChange( TextSpan.FromBounds(left.Span.End, right.SpanStart), newText); return(document.WithTextChangeAsync(textChange, cancellationToken)); }
public SyntaxOrTokenItemViewModel(SyntaxNodeOrToken syntaxNodeOrToken, int?maxFilePathLength = null) { LineSpan = syntaxNodeOrToken.GetLocation().GetLineSpan(); Class = LineSpan.Path.Split('\\').Last(); Content = $"{LineSpan.Path.PadRight(maxFilePathLength ?? 100)} {LineSpan.Span.ToString().PadLeft(20)}{"".PadLeft(5)}{syntaxNodeOrToken.ToString().Truncate()}"; ToolTip = syntaxNodeOrToken.ToString(); }
internal VariableNode RegisterField(SyntaxNodeOrToken v, IFieldSymbol s) { VariableNode lhs; if (s.Type.TypeKind.Equals(TypeKind.Delegate)) { lhs = new DelegateVariableNode(v.ToString(), Utils.CreateTypeDescriptor(s.Type)); } else { lhs = new FieldNode(s.ContainingType.Name, v.ToString(), Utils.CreateTypeDescriptor(s.Type)); //lhs = ANode.Define(t, v); } if (lhs != null) { this.StatementProcessor.RegisterLocalVariable(lhs); } return(lhs); }
public SourceLabelSymbol( MethodSymbol containingMethod, SyntaxNodeOrToken identifierNodeOrToken, ConstantValue switchCaseLabelConstant = null) : base(identifierNodeOrToken.IsToken ? identifierNodeOrToken.AsToken().ValueText : identifierNodeOrToken.ToString()) { this.containingMethod = containingMethod; this.identifierNodeOrToken = identifierNodeOrToken; this.switchCaseLabelConstant = switchCaseLabelConstant; }
internal VariableNode RegisterVariable(SyntaxNodeOrToken v, ITypeSymbol type, ISymbol s) { VariableNode lhs; if (type.TypeKind.Equals(TypeKind.Delegate)) { lhs = new DelegateVariableNode(v.ToString(), Utils.CreateTypeDescriptor(type)); } else { lhs = new VariableNode(v.ToString(), Utils.CreateTypeDescriptor(type)); //lhs = ANode.Define(t, v); } if (lhs != null) { this.StatementProcessor.RegisterLocalVariable(lhs); } return(lhs); }
private static void Print(SyntaxNodeOrToken node) { if (node.Kind() == SyntaxKind.IdentifierToken && !node.IsMissing) { Debug.WriteLine(@"N(SyntaxKind.{0}, ""{1}"");", node.Kind(), node.ToString()); } else { Debug.WriteLine("{0}(SyntaxKind.{1});", node.IsMissing ? "M" : "N", node.Kind()); } }
public static VulnerabilityDetail Create(string filePath, SyntaxNodeOrToken codeSnippet, Enums.ScannerType category, string message = null) { string code = "OPT" + category.GetHashCode().ToString("D4"); return(new VulnerabilityDetail { FilePath = filePath, CodeSnippet = codeSnippet.ToString(), LineNumber = Mapper.Map.GetLineNumber(codeSnippet), Code = code, Description = GetResourceString(code, "Description"), Message = string.IsNullOrWhiteSpace(message) ? GetResourceString(code, "MessageFormat") : message, Type = category, Title = GetResourceString(code, "Title") }); }
private static void Print(SyntaxNodeOrToken node) { switch (node.Kind()) { case SyntaxKind.IdentifierToken: case SyntaxKind.NumericLiteralToken: if (node.IsMissing) { goto default; } Debug.WriteLine(@"N(SyntaxKind.{0}, ""{1}"");", node.Kind(), node.ToString()); break; default: Debug.WriteLine("{0}(SyntaxKind.{1});", node.IsMissing ? "M" : "N", node.Kind()); break; } }
public void CommonSyntaxToString_VisualBasic() { SyntaxNode node = VB.SyntaxFactory.IdentifierName("test"); Assert.Equal("test", node.ToString()); SyntaxNodeOrToken nodeOrToken = node; Assert.Equal("test", nodeOrToken.ToString()); SyntaxToken token = node.DescendantTokens().Single(); Assert.Equal("test", token.ToString()); SyntaxTrivia trivia = VB.SyntaxFactory.Whitespace("test"); Assert.Equal("test", trivia.ToString()); }
void UpdateWordAdornments() { SnapshotPoint currentRequest = RequestedPoint; var document = View.TextSnapshot.TextBuffer.GetRelatedDocuments().FirstOrDefault(); if (document == null) { SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(), null); return; } var syntaxTree = document.GetSyntaxTreeAsync().ConfigureAwait(false).GetAwaiter().GetResult(); var root = syntaxTree.GetRoot(); SyntaxNodeOrToken token = root.FindToken(currentRequest.Position); var line = View.TextSnapshot.GetLineFromPosition(currentRequest.Position); SyntaxNodeOrToken lineSyntax = root.FindNode(TextSpan.FromBounds(line.Start, line.End)); var nodes = lineSyntax.ChildNodesAndTokens(); var methods = new List <SyntaxNodeOrToken>(); TraversideNodes(nodes, methods); if (!methods.Any()) { SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(), null); return; } var idx = -1; TextSpan currentArgSpan = TextSpan.FromBounds(0, 0); SyntaxNodeOrToken _sqlSyntax = null; foreach (var method in methods) { var _argsSyntax = ((SyntaxNodeOrToken)method.Parent).GetNextSibling().ChildNodesAndTokens().Where(p => p.IsKind(SyntaxKind.Argument)); foreach (var _arg in _argsSyntax) { idx++; if (_arg.Span.Start <= currentRequest.Position && currentRequest.Position <= _arg.Span.End) { currentArgSpan = _arg.Span; var dot = method.GetPreviousSibling(); //如果方法名签名不是一个点(.),终止 if (!dot.IsKind(SyntaxKind.DotToken)) { SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(), null); return; } _sqlSyntax = dot.GetPreviousSibling(); break; } } } //如果没有选择参数,并且Splice方法前不是字符串 if (idx == -1 || !_sqlSyntax.IsKind(SyntaxKind.StringLiteralExpression)) { SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(), null); return; } //SyntaxNodeOrToken argsSyntax = null; //if (token.Parent.IsKind(SyntaxKind.ArgumentList)) // argsSyntax = token.Parent; //else // argsSyntax = ((SyntaxNodeOrToken)token.Parent?.Parent).GetPreviousSibling().Parent;//此情况是光标在具体某个参数上 //if (argsSyntax.RawKind == 0) // argsSyntax = ((SyntaxNodeOrToken)token.Parent?.Parent?.Parent).GetPreviousSibling().Parent; //if (argsSyntax == null || !argsSyntax.IsKind(SyntaxKind.ArgumentList)) //{ // SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(), null); // return; //} //var expression = argsSyntax.GetPreviousSibling(); //#region 判断是不是拼接sql的方法(Splice) //var syntax = expression.ChildNodesAndTokens(); //if (syntax.Count != 3) //{ // SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(), null); // return; //} //if (!syntax.First().IsKind(SyntaxKind.StringLiteralExpression) || !syntax.Last().IsKind(SyntaxKind.IdentifierName) || !syntax.Last().ToFullString().Equals("Splice", StringComparison.Ordinal)) //{ // SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(), null); // return; //} //#endregion //var args = argsSyntax.ChildNodesAndTokens().Where(p => p.IsKind(SyntaxKind.Argument)).ToList(); //var pointer = token.Span.Start; ////获取当前焦点在第几个参数 //foreach (var arg in args) //{ // idx++; // if (arg.Span.Start >= pointer && pointer <= arg.Span.End) // break; //} //var sqlSyntax = syntax.First(); var sql = _sqlSyntax.ToString(); var startIdx = -1; var endIdx = -1; var currentIdx = 0; for (var i = 0; i <= idx; i++) { startIdx = sql.IndexOf("{", currentIdx); if (startIdx == -1) { break; } endIdx = sql.IndexOf("}", startIdx); if (endIdx == -1) { break; } currentIdx = endIdx; } if (startIdx == -1 || endIdx == -1) { SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(), null); return; } List <SnapshotSpan> wordSpans = new List <SnapshotSpan>(); //添加当前选中的参数高亮 //wordSpans.Add(new SnapshotSpan(View.TextSnapshot, currentArgSpan.Start, currentArgSpan.End - currentArgSpan.Start)); //添加对应的拼接sql部分高亮 wordSpans.Add(new SnapshotSpan(View.TextSnapshot, _sqlSyntax.Span.Start + startIdx, endIdx - startIdx + 1)); //Find all words in the buffer like the one the caret is on TextExtent word = TextStructureNavigator.GetExtentOfWord(currentRequest); SnapshotSpan currentWord = word.Span; //If this is the current word, and the caret moved within a word, we're done. if (CurrentWord.HasValue && currentWord == CurrentWord) { return; } //If another change hasn't happened, do a real update if (currentRequest == RequestedPoint) { SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(wordSpans), currentWord); } }
private List<SourceLabelSymbol> FindMatchingSwitchCaseLabels(ConstantValue constantValue, SyntaxNodeOrToken labelSyntax = default(SyntaxNodeOrToken)) { // SwitchLabelsMap: Dictionary for the switch case/default labels. // Case labels with a non-null constant value are indexed on their ConstantValue. // Invalid case labels with null constant value are indexed on the labelName. object key; if (constantValue != null) { key = constantValue; } else { key = labelSyntax.ToString(); } return FindMatchingSwitchLabels(key); }
public static void AddDataFlowEdges(SourceGraph sourceGraph, SyntaxNodeOrToken tokenOfInterest, ICollection <SyntaxNodeOrToken> forbiddenNodes = null, ICollection <Edge <SyntaxNodeOrToken, SourceGraphEdge> > addedEdges = null) { //There's nothing before the declaration, so we don't need to bother: if (sourceGraph.DeclarationNodes.Contains(tokenOfInterest)) { return; } //We only ever need to visit each node once, so collect visited nodes here: var visitedNodes = new HashSet <(SyntaxNodeOrToken, bool)>(); //Start from all predecessors of the token of interest: var toVisit = new Stack <(SyntaxNodeOrToken node, bool haveFoundUse)>(); foreach (var(_, label, target) in sourceGraph.GetOutEdges(tokenOfInterest)) { if (label != SourceGraphEdge.LastUsedVariable || (forbiddenNodes?.Contains(target) ?? false)) { continue; } if (visitedNodes.Add((target, false))) { toVisit.Push((target, false)); } } string nodeLabelToLookFor = tokenOfInterest.ToString(); while (toVisit.Count > 0) { var(node, haveFoundUse) = toVisit.Pop(); if (node.ToString().Equals(nodeLabelToLookFor)) { if (!haveFoundUse) { var lastUseEdge = new Edge <SyntaxNodeOrToken, SourceGraphEdge>(tokenOfInterest, SourceGraphEdge.LastUse, node); if (sourceGraph.AddEdge(lastUseEdge)) { addedEdges?.Add(lastUseEdge); } haveFoundUse = true; } if (sourceGraph.WrittenVariableNodes.Contains(node)) { var lastWriteEdge = new Edge <SyntaxNodeOrToken, SourceGraphEdge>(tokenOfInterest, SourceGraphEdge.LastWrite, node); if (sourceGraph.AddEdge(lastWriteEdge)) { addedEdges?.Add(lastWriteEdge); } //We are done with this path -- we found a use and a write! continue; } //There's nothing before the declaration, so we don't need to bother to recurse further: if (sourceGraph.DeclarationNodes.Contains(node)) { continue; } } foreach (var(_, label, target) in sourceGraph.GetOutEdges(node)) { if (label != SourceGraphEdge.LastUsedVariable || (forbiddenNodes?.Contains(target) ?? false)) { continue; } if (visitedNodes.Add((target, haveFoundUse))) { toVisit.Push((target, haveFoundUse)); } } } }
private int GetSimilarity(SyntaxNodeOrToken node1, SyntaxNodeOrToken node2) { // count the characters in the common/identical nodes int w = 0; _nodeSimilaritySet.Clear(); _tokenTextSimilaritySet.Clear(); if (node1.IsToken && node2.IsToken) { var text1 = node1.ToString(); var text2 = node2.ToString(); if (text1 == text2) { // main text of token is the same w += text1.Length; } foreach (var tr in node1.GetLeadingTrivia()) { _nodeSimilaritySet.Add(tr.UnderlyingNode); } foreach (var tr in node1.GetTrailingTrivia()) { _nodeSimilaritySet.Add(tr.UnderlyingNode); } foreach (var tr in node2.GetLeadingTrivia()) { if (_nodeSimilaritySet.Contains(tr.UnderlyingNode)) { w += tr.FullSpan.Length; } } foreach (var tr in node2.GetTrailingTrivia()) { if (_nodeSimilaritySet.Contains(tr.UnderlyingNode)) { w += tr.FullSpan.Length; } } } else { foreach (var n1 in node1.ChildNodesAndTokens()) { _nodeSimilaritySet.Add(n1.UnderlyingNode); if (n1.IsToken) { _tokenTextSimilaritySet.Add(n1.ToString()); } } foreach (var n2 in node2.ChildNodesAndTokens()) { if (_nodeSimilaritySet.Contains(n2.UnderlyingNode)) { w += n2.FullSpan.Length; } else if (n2.IsToken) { var tokenText = n2.ToString(); if (_tokenTextSimilaritySet.Contains(tokenText)) { w += tokenText.Length; } } } } return w; }
public IEnumerable <ITagSpan <IClassificationTag> > FindBracketSpans(RoslynDocument doc, NormalizedSnapshotSpanCollection spans) { var snapshot = spans[0].Snapshot; List <ITagSpan <IClassificationTag> > _tagspans = new List <ITagSpan <IClassificationTag> >(); var nodeOrToken = (SyntaxNodeOrToken)doc.SyntaxRoot; Action <List <ITagSpan <IClassificationTag> >, SyntaxNodeOrToken, int> _walkintochild = null; int _dept = 0; _walkintochild = (List <ITagSpan <IClassificationTag> > __tagspans, SyntaxNodeOrToken nOrT, int __dept) => { foreach (var child in nOrT.ChildNodesAndTokens()) { if (child.ChildNodesAndTokens().Count > 0) { _walkintochild(__tagspans, child, ++__dept); } } List <SyntaxNodeOrToken> __brace = nOrT.ChildNodesAndTokens().Where(child => child.IsKind(SyntaxKind.OpenBraceToken) || child.IsKind(SyntaxKind.CloseBraceToken) || child.IsKind(SyntaxKind.OpenParenToken) || child.IsKind(SyntaxKind.CloseParenToken) || child.IsKind(SyntaxKind.OpenBracketToken) || child.IsKind(SyntaxKind.CloseBracketToken) ).ToList(); if (__brace.Count == 0) { return; } if (__brace.Where(s => s.ToString() == "(").ToList().Count != __brace.Where(s => s.ToString() == ")").ToList().Count) { return; } if (__brace.Where(s => s.ToString() == "{").ToList().Count != __brace.Where(s => s.ToString() == "}").ToList().Count) { return; } if (__brace.Where(s => s.ToString() == "[").ToList().Count != __brace.Where(s => s.ToString() == "]").ToList().Count) { return; } while (__brace.Count > 0) { SyntaxNodeOrToken l1 = __brace.First(); SyntaxNodeOrToken l2 = null; string _start_check = l1.ToString(); string _end_check = ")"; if (_start_check == "{") { _end_check = "}"; } if (_start_check == "[") { _end_check = "]"; } if (_start_check != "{" && _start_check != "(" && _start_check != "[") { break; } __brace.Remove(l1); int par = 1; for (int i = 0; i < __brace.Count; ++i) { SyntaxNodeOrToken _ncheck = __brace[i]; if (_ncheck.ToString() == _end_check) { par--; } else if (_ncheck.ToString() == _start_check) { par++; } if (par == 0) { l2 = _ncheck; __brace.Remove(l2); break; } } string _tp = ((__dept % 8) + 1).ToString(); IClassificationType classificationType = _classificationTypeRegistry.GetClassificationType(_tp); __tagspans.Add(l1.Span.ToTagSpan(snapshot, classificationType)); if (l2 != null) { __tagspans.Add(l2.Span.ToTagSpan(snapshot, classificationType)); } else { return; } } }; _walkintochild(_tagspans, nodeOrToken, _dept); foreach (ITagSpan <IClassificationTag> _t in _tagspans) { yield return(_t); } }
public IEnumerable <ITagSpan <IClassificationTag> > FindBracketSpans(RoslynDocument doc, NormalizedSnapshotSpanCollection spans) { var snapshot = spans[0].Snapshot; var _nodeOrToken = (SyntaxNodeOrToken)doc.SyntaxRoot; int _dept = 0; List <ITagSpan <IClassificationTag> > _tagSpans = new List <ITagSpan <IClassificationTag> >(); void nextChildNode(List <ITagSpan <IClassificationTag> > tagSpans, SyntaxNodeOrToken nodeOrToken, int dept) { foreach (var child in nodeOrToken.ChildNodesAndTokens()) { if (child.ChildNodesAndTokens().Count > 0) { nextChildNode(tagSpans, child, ++dept); } } List <SyntaxNodeOrToken> brace = nodeOrToken.ChildNodesAndTokens().Where(child => child.IsKind(SyntaxKind.OpenBraceToken) || child.IsKind(SyntaxKind.CloseBraceToken) || child.IsKind(SyntaxKind.OpenParenToken) || child.IsKind(SyntaxKind.CloseParenToken) || child.IsKind(SyntaxKind.OpenBracketToken) || child.IsKind(SyntaxKind.CloseBracketToken)) .ToList(); if (brace.Count == 0) { return; } if (brace.Where(s => s.ToString() == "(").ToList().Count != brace.Where(s => s.ToString() == ")").ToList().Count) { return; } if (brace.Where(s => s.ToString() == "{").ToList().Count != brace.Where(s => s.ToString() == "}").ToList().Count) { return; } if (brace.Where(s => s.ToString() == "[").ToList().Count != brace.Where(s => s.ToString() == "]").ToList().Count) { return; } while (brace.Count > 0) { SyntaxNodeOrToken line1 = brace.First(); SyntaxNodeOrToken line2 = null; string start = line1.ToString(); string end = ")"; if (start == "{") { end = "}"; } if (start == "[") { end = "]"; } if (start != "(" && start != "{" && start != "[") { break; } brace.Remove(line1); int par = 1; for (int i = 0; i < brace.Count; ++i) { SyntaxNodeOrToken check = brace[i]; if (check.ToString() == end) { par--; } else if (check.ToString() == start) { par++; } if (par == 0) { line2 = check; brace.Remove(line2); break; } } string _tp = ((dept % 8) + 1).ToString(); IClassificationType classificationType = _registry.GetClassificationType(_tp); tagSpans.Add(line1.Span.ToTagSpan(snapshot, classificationType)); if (line2 != null) { tagSpans.Add(line2.Span.ToTagSpan(snapshot, classificationType)); } else { return; } } } nextChildNode(_tagSpans, _nodeOrToken, _dept); foreach (ITagSpan <IClassificationTag> tag in _tagSpans) { yield return(tag); } }
public static void AddDataFlowEdges(SourceGraph sourceGraph, SyntaxNodeOrToken tokenOfInterest, ICollection <SyntaxNodeOrToken> forbiddenNodes = null, ICollection <Edge <SyntaxNodeOrToken, SourceGraphEdge> > addedEdges = null) { var semanticModel = sourceGraph.SemanticModel; //There's nothing before the declaration, so we don't need to bother: if (sourceGraph.VariableDeclarationNodes.Contains(tokenOfInterest)) { return; } //We only ever need to visit each node once, so collect visited nodes here: var visitedNodes = new HashSet <(SyntaxNodeOrToken, bool)>(); //Start from all predecessors of the token of interest: var toVisit = new Stack <(SyntaxNodeOrToken node, bool haveFoundUse)>(); foreach (var(_, label, target) in sourceGraph.GetOutEdges(tokenOfInterest)) { if (label != SourceGraphEdge.LastUsedVariable || (forbiddenNodes?.Contains(target) ?? false)) { continue; } if (visitedNodes.Add((target, false))) { toVisit.Push((target, false)); } } var nodeOfInterest = tokenOfInterest.IsToken ? tokenOfInterest.AsToken().Parent : tokenOfInterest.AsNode(); ISymbol symbolToLookFor = nodeOfInterest != null?semanticModel.GetSymbolInfo(nodeOfInterest).Symbol?.OriginalDefinition : null; string nodeLabelToLookFor = tokenOfInterest.ToString(); while (toVisit.Count > 0) { var(node, haveFoundUse) = toVisit.Pop(); var nodeSyntaxNode = node.IsToken ? node.AsToken().Parent : node.AsNode(); var nodeSymbol = nodeSyntaxNode != null?semanticModel.GetSymbolInfo(nodeSyntaxNode).Symbol?.OriginalDefinition : null; bool matches; if (symbolToLookFor == null || nodeSymbol == null) { // This may happen in cases where Roslyn doesn't have symbol info // or when one of the nodes is a dummy node (and thus doesn't belong to the SyntaxTree) matches = node.ToString().Equals(nodeLabelToLookFor); } else { matches = nodeSymbol.Equals(symbolToLookFor); } if (matches) { if (!haveFoundUse) { var lastUseEdge = new Edge <SyntaxNodeOrToken, SourceGraphEdge>(tokenOfInterest, SourceGraphEdge.LastUse, node); if (sourceGraph.AddEdge(lastUseEdge)) { addedEdges?.Add(lastUseEdge); } haveFoundUse = true; } if (sourceGraph.VariableWriteNodes.Contains(node)) { var lastWriteEdge = new Edge <SyntaxNodeOrToken, SourceGraphEdge>(tokenOfInterest, SourceGraphEdge.LastWrite, node); if (sourceGraph.AddEdge(lastWriteEdge)) { addedEdges?.Add(lastWriteEdge); } //We are done with this path -- we found a use and a write! continue; } //There's nothing before the declaration, so we don't need to bother to recurse further: if (sourceGraph.VariableDeclarationNodes.Contains(node)) { continue; } } foreach (var(_, label, target) in sourceGraph.GetOutEdges(node)) { if (label != SourceGraphEdge.LastUsedVariable || (forbiddenNodes?.Contains(target) ?? false)) { continue; } if (visitedNodes.Add((target, haveFoundUse))) { toVisit.Push((target, haveFoundUse)); } } } }