public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var nodeWithRegion = root.FindNode(context.Span, true, true); DirectiveTriviaSyntax region = nodeWithRegion as RegionDirectiveTriviaSyntax; if (region == null) { region = nodeWithRegion as EndRegionDirectiveTriviaSyntax; } if (region == null) { return; } CodeAction action = CodeAction.Create(title, CancellationToken => { var newRoot = root.RemoveNodes(region.GetRelatedDirectives(), SyntaxRemoveOptions.AddElasticMarker); var newDocument = context.Document.WithSyntaxRoot(newRoot); return(Task.FromResult(newDocument)); }); context.RegisterCodeFix(action, context.Diagnostics.First()); }
public static void Analyze(SyntaxNodeAnalysisContext context, RegionDirectiveTriviaSyntax region) { if (region.IsKind(SyntaxKind.RegionDirectiveTrivia)) { List <DirectiveTriviaSyntax> relatedDirectives = region.GetRelatedDirectives(); if (relatedDirectives.Count == 2 && relatedDirectives[1].IsKind(SyntaxKind.EndRegionDirectiveTrivia)) { DirectiveTriviaSyntax endRegion = relatedDirectives[1]; if (endRegion.IsKind(SyntaxKind.EndRegionDirectiveTrivia)) { SyntaxTrivia trivia = region.ParentTrivia; SyntaxTriviaList list = trivia.GetContainingList(); if (list.Any()) { EndRegionDirectiveTriviaSyntax endRegion2 = FindEndRegion(list, list.IndexOf(trivia)); if (endRegion == endRegion2) { context.ReportDiagnostic( DiagnosticDescriptors.RemoveEmptyRegion, region.GetLocation(), endRegion.GetLocation()); } } } } } }
private static DirectiveTriviaSyntax GetPreviousPossiblyLinkedDirective(this DirectiveTriviaSyntax directive) { DirectiveTriviaSyntax d = directive; while (d != null) { d = d.GetPreviousDirective(); if (d != null) { // Skip matched sets of directives switch (d.Kind()) { case SyntaxKind.EndIfDirectiveTrivia: while (d != null && d.Kind() != SyntaxKind.IfDirectiveTrivia) { d = d.GetPreviousLinkedDirective(); } continue; } } return(d); } return(null); }
public static void ComputeRefactorings(RefactoringContext context, DirectiveTriviaSyntax directiveTrivia) { if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveDirectiveAndRelatedDirectives) && directiveTrivia.IsKind( SyntaxKind.IfDirectiveTrivia, SyntaxKind.ElseDirectiveTrivia, SyntaxKind.ElifDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia, SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia)) { List <DirectiveTriviaSyntax> directives = directiveTrivia.GetRelatedDirectives(); if (directives.Count > 1) { string title = "Remove directive and related directive"; if (directives.Count > 2) { title += "s"; } context.RegisterRefactoring( title, cancellationToken => { return(SyntaxRemover.RemoveDirectivesAsync( context.Document, directives.ToImmutableArray(), cancellationToken)); }); } } }
public void PreprocessorDirectives() { SyntaxTree tree = SyntaxFactory.ParseSyntaxTree(@"#if true class A { } #else class B { } #endif"); SyntaxToken eof = tree.GetRoot().FindToken(tree.GetText().Length, false); Assert.AreEqual(true, eof.HasLeadingTrivia); Assert.AreEqual(false, eof.HasTrailingTrivia); Assert.AreEqual(true, eof.ContainsDirectives); SyntaxTriviaList trivia = eof.LeadingTrivia; Assert.AreEqual(3, trivia.Count); Assert.AreEqual("#else", trivia.ElementAt(0).ToString()); Assert.AreEqual(SyntaxKind.DisabledTextTrivia, trivia.ElementAt(1).CSharpKind()); Assert.AreEqual("#endif", trivia.ElementAt(2).ToString()); DirectiveTriviaSyntax directive = tree.GetRoot().GetLastDirective(); Assert.AreEqual("endif", directive.DirectiveNameToken.Value); directive = directive.GetPreviousDirective(); Assert.AreEqual("else", directive.DirectiveNameToken.Value); // List<DirectiveSyntax> relatedDirectives = directive.GetRelatedDirectives(); // Assert.AreEqual(3, relatedDirectives.Count); }
/// <summary> /// Populate the dictionary with the region name(if we are performing checks on the concerned region) along with the LocationRangeModel /// DirectiveTriviaSyntax will have both start region and end region /// Start of the region will always come RIGHT before end region in the regions list. /// Index position of start of the region will always be 0 or even. While index position of end region will always be odd and RIGHT after corresponding start /// region object. /// If the region is a start region(at index position 0 or even), add it to the dictionary. /// If the region is an end region(at index position odd), look for corresponding start region added in the previous loop and update the endLocation in LocationRangeModel object /// </summary> /// <param name="regions">Regions found in the file</param> /// <returns>Dictionary of region name and LocationRangeModel object</returns> private static Dictionary <string, LocationRangeModel> PopulateRegionLocations(List <DirectiveTriviaSyntax> regions, SyntaxNodeAnalysisContext context) { Dictionary <string, LocationRangeModel> regionLocations = new Dictionary <string, LocationRangeModel>(); string regionTag = "#region "; string regionStartName = ""; for (int i = 0; i < regions.Count; i++) { DirectiveTriviaSyntax region = regions[i]; if (i % 2 == 0) { string regionName = string.Empty; var lines = region.GetText().Lines; if (lines.Count > 0) { regionName = lines[0].ToString(); } if (regionName.StartsWith(regionTag)) { regionName = regionName.Replace(regionTag, ""); } if (regionName.Length <= 0) { continue; } if (RegionChecks.ContainsKey(regionName)) { if (regionLocations.ContainsKey(regionName)) { regionLocations.Remove(regionName); CreateDiagnostic(region.DirectiveNameToken.GetLocation(), context, regionName, EnforceNonDupliateRegion); } else { int lineNumber = GetMemberLineNumber(region.GetLocation()); regionLocations.Add(regionName, new LocationRangeModel(lineNumber, lineNumber)); regionStartName = regionName; } } } else { if (regionLocations.TryGetValue(regionStartName, out LocationRangeModel value)) { value.EndLine = GetMemberLineNumber(region.GetLocation()); regionStartName = ""; } } } return(regionLocations); }
private void HandleEndIfDirective(DirectiveTriviaSyntax directive) { if (_ifStack.IsEmpty()) { return; } FinishIf(directive); }
internal static DirectiveTriviaSyntax GetMatchingDirective(this DirectiveTriviaSyntax directive, CancellationToken cancellationToken) { try { return((DirectiveTriviaSyntax)getMatchingDirective.Invoke(null, new object[] { directive, cancellationToken })); } catch (TargetInvocationException ex) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); return(null); } }
void ShowStartRegion(DirectiveTriviaSyntax d, bool isExternal) { var item = _Menu.Add(d); item.Hint = "#region"; item.Content = SetHeader(d, false, false, false); if (isExternal) { item.Type = SymbolItemType.External; } }
private void HandleEndRegionDirective(DirectiveTriviaSyntax directive) { if (_regionStack.IsEmpty()) { return; } var previousDirective = _regionStack.Pop(); _directiveMap.Add(directive, previousDirective); _directiveMap.Add(previousDirective, directive); }
public ConditionalRegion(DirectiveTriviaSyntax startDirective, DirectiveTriviaSyntax endDirective, Tristate state) { Debug.Assert(startDirective.SyntaxTree.FilePath == endDirective.SyntaxTree.FilePath); StartDirective = startDirective; EndDirective = endDirective; SpanStart = CalculateSpanStart(startDirective); SpanEnd = endDirective.FullSpan.End; Location = Location.Create(startDirective.SyntaxTree, new TextSpan(SpanStart, SpanEnd - SpanStart)); State = state; }
private static DirectiveTriviaSyntax GetPreviousLinkedDirective(this DirectiveTriviaSyntax directive) { DirectiveTriviaSyntax d = directive.GetPreviousPossiblyLinkedDirective(); switch (directive.Kind()) { case SyntaxKind.EndIfDirectiveTrivia: while (d != null) { switch (d.Kind()) { case SyntaxKind.IfDirectiveTrivia: case SyntaxKind.ElifDirectiveTrivia: case SyntaxKind.ElseDirectiveTrivia: return(d); } d = d.GetPreviousPossiblyLinkedDirective(); } break; case SyntaxKind.ElifDirectiveTrivia: while (d != null) { switch (d.Kind()) { case SyntaxKind.IfDirectiveTrivia: case SyntaxKind.ElifDirectiveTrivia: return(d); } d = d.GetPreviousPossiblyLinkedDirective(); } break; case SyntaxKind.ElseDirectiveTrivia: while (d != null) { switch (d.Kind()) { case SyntaxKind.IfDirectiveTrivia: case SyntaxKind.ElifDirectiveTrivia: return(d); } d = d.GetPreviousPossiblyLinkedDirective(); } break; } return(null); }
private static bool IsBranchingDirective(DirectiveTriviaSyntax directive) { switch (directive.Kind()) { case SyntaxKind.IfDirectiveTrivia: case SyntaxKind.ElifDirectiveTrivia: case SyntaxKind.ElseDirectiveTrivia: return(true); default: return(false); } }
internal static DirectiveTriviaSyntax GetMatchingDirective(this DirectiveTriviaSyntax directive, CancellationToken cancellationToken) { if (directive == null) { throw new ArgumentNullException(nameof(directive)); } var directiveSyntaxMap = GetDirectiveInfo(directive, cancellationToken).DirectiveMap; directiveSyntaxMap.TryGetValue(directive, out var result); return(result); }
private static string GetBannerText(DirectiveTriviaSyntax simpleDirective) { var kw = simpleDirective.DirectiveNameToken; var prefixLength = kw.Span.End - simpleDirective.Span.Start; var text = simpleDirective.ToString().Substring(prefixLength).Trim(); if (text.Length == 0) { return(simpleDirective.HashToken.ToString() + kw.ToString()); } else { return(text); } }
public static bool TryGetDirective(string directiveName, ref DirectiveTriviaSyntax directive) { while (directive != null && directive.ToString() != directiveName && directive.GetNextDirective() != null) { directive = directive.GetNextDirective(); } if (directive?.ToString() != directiveName) { return(false); } else { return(true); } }
public static bool IsEmptyDirective(SyntaxNode rootNode, DirectiveTriviaSyntax directive) { MemberDeclarationSyntax member = rootNode .DescendantNodes() .OfType <MemberDeclarationSyntax>() .FirstOrDefault(t => t.GetLeadingTrivia().ToFullString().Contains(directive.ToString())); if (member == null) { return(true); } else { return(false); } }
private static Task <Document> AddBlankLineAfterRegionDirectiveAndBeforeEndRegionAsync( Document document, DirectiveTriviaSyntax directiveTrivia, CancellationToken cancellationToken) { switch (directiveTrivia.Kind()) { case SyntaxKind.RegionDirectiveTrivia: return(CodeFixHelpers.AddBlankLineAfterDirectiveAsync(document, directiveTrivia, cancellationToken)); case SyntaxKind.EndRegionDirectiveTrivia: return(CodeFixHelpers.AddBlankLineBeforeDirectiveAsync(document, directiveTrivia, cancellationToken)); default: throw new InvalidOperationException(); } }
public static Task <Document> AddEmptyLineAfterDirectiveAsync( Document document, DirectiveTriviaSyntax directiveTrivia, CancellationToken cancellationToken = default) { SyntaxTrivia parentTrivia = directiveTrivia.ParentTrivia; SyntaxToken token = parentTrivia.Token; SyntaxTriviaList leadingTrivia = token.LeadingTrivia; int index = leadingTrivia.IndexOf(parentTrivia); SyntaxTriviaList newLeadingTrivia = leadingTrivia.Insert(index + 1, DetermineEndOfLine(token)); SyntaxToken newToken = token.WithLeadingTrivia(newLeadingTrivia); return(document.ReplaceTokenAsync(token, newToken, cancellationToken)); }
private static bool HasSomethingInsideRegion(DirectiveTriviaSyntax regionNode) { // contains #region and #endregion directive trivia syntaxes var relatedDirectives = regionNode.GetRelatedDirectives(); if (relatedDirectives.Count != 2) { return(false); } var regionDirective = relatedDirectives[0]; var endregionDirective = relatedDirectives[1]; var regionAncestors = regionDirective.AncestorsAndSelf(); var endregionAncestors = endregionDirective.AncestorsAndSelf(); return(regionAncestors.Except(endregionAncestors).Except(relatedDirectives).Any()); }
private static int CalculateSpanStart(DirectiveTriviaSyntax startDirective) { int start = startDirective.FullSpan.Start; // Consume whitespace trivia preceding the start directive var leadingTrivia = startDirective.ParentTrivia.Token.LeadingTrivia; var triviaIndex = leadingTrivia.IndexOf(startDirective.ParentTrivia); if (triviaIndex > 0) { var previousTrivia = leadingTrivia[triviaIndex - 1]; if (previousTrivia.Kind() == SyntaxKind.WhitespaceTrivia) { start = previousTrivia.FullSpan.Start; } } return(start); }
private Tristate EvaluateDirectiveExpression(DirectiveTriviaSyntax directive, Tristate previousRegionState) { switch (directive.Kind()) { case SyntaxKind.IfDirectiveTrivia: return(EvaluateExpression(((IfDirectiveTriviaSyntax)directive).Condition)); case SyntaxKind.ElifDirectiveTrivia: Tristate result = EvaluateExpression(((ElifDirectiveTriviaSyntax)directive).Condition); return(!previousRegionState & result); case SyntaxKind.ElseDirectiveTrivia: return(!previousRegionState); default: Debug.Assert(false); return(Tristate.Varying); } }
private void ClassifyDirectiveTrivia(DirectiveTriviaSyntax node, bool allowComments = true) { var lastToken = node.EndOfDirectiveToken.GetPreviousToken(includeSkipped: false); foreach (var trivia in lastToken.TrailingTrivia) { // skip initial whitespace if (trivia.Kind() == SyntaxKind.WhitespaceTrivia) { continue; } ClassifyPreprocessorTrivia(trivia, allowComments); } foreach (var trivia in node.EndOfDirectiveToken.LeadingTrivia) { ClassifyPreprocessorTrivia(trivia, allowComments); } }
// removes unfinished if & related directives from stack and leaves active branch directives private static ConsList <Directive> CompleteIf(DirectiveTriviaSyntax branchEndSyntax, ConsList <Directive> stack, out bool include) { // if we get to the top, the default rule is to include anything that follows if (!stack.Any()) { include = true; return(stack); } // if we reach the #if directive, then we stop unwinding and start // rebuilding the stack w/o the #if/#elif/#else/#endif directives // only including content from sections that are considered included var head = stack.Head; if (head.Kind.IsIfLikeDirective()) { include = head.BranchTaken; head.BranchEnd = branchEndSyntax; return(stack.Tail); } var newStack = CompleteIf(branchEndSyntax, stack.Tail, out include); switch (stack.Head.Kind) { case SyntaxKind.ElifDirectiveTrivia: case SyntaxKind.ElseDirectiveTrivia: include = stack.Head.BranchTaken; break; default: if (include) { newStack = new ConsList <Directive>(head, newStack); } break; } return(newStack); }
private void AnalyzeRegionDirectiveTrivia(SyntaxNodeAnalysisContext context) { if (GeneratedCodeAnalyzer?.IsGeneratedCode(context) == true) { return; } var region = (RegionDirectiveTriviaSyntax)context.Node; if (region.IsKind(SyntaxKind.RegionDirectiveTrivia)) { List <DirectiveTriviaSyntax> relatedDirectives = region.GetRelatedDirectives(); if (relatedDirectives.Count == 2 && relatedDirectives[1].IsKind(SyntaxKind.EndRegionDirectiveTrivia)) { DirectiveTriviaSyntax endRegion = relatedDirectives[1]; if (endRegion.IsKind(SyntaxKind.EndRegionDirectiveTrivia)) { SyntaxTrivia trivia = region.ParentTrivia; SyntaxTriviaList list = trivia.GetContainingList(); if (list.Any()) { EndRegionDirectiveTriviaSyntax endRegion2 = FindEndRegion(list, list.IndexOf(trivia)); if (endRegion == endRegion2) { context.ReportDiagnostic( DiagnosticDescriptors.RemoveEmptyRegion, region.GetLocation(), endRegion.GetLocation()); } } } } } }
private void FinishIf(DirectiveTriviaSyntax directiveOpt) { var condDirectives = new List <DirectiveTriviaSyntax>(); if (directiveOpt != null) { condDirectives.Add(directiveOpt); } while (!_ifStack.IsEmpty()) { var poppedDirective = _ifStack.Pop(); condDirectives.Add(poppedDirective); if (poppedDirective.Kind() == SyntaxKind.IfDirectiveTrivia) { break; } } condDirectives.Sort((n1, n2) => n1.SpanStart.CompareTo(n2.SpanStart)); foreach (var cond in condDirectives) { _conditionalMap.Add(cond, condDirectives); } // #If should be the first one in sorted order var ifDirective = condDirectives.First(); Debug.Assert( ifDirective.Kind() == SyntaxKind.IfDirectiveTrivia || ifDirective.Kind() == SyntaxKind.ElifDirectiveTrivia || ifDirective.Kind() == SyntaxKind.ElseDirectiveTrivia); if (directiveOpt != null) { _directiveMap.Add(directiveOpt, ifDirective); _directiveMap.Add(ifDirective, directiveOpt); } }
private static string GetReplacementText(DirectiveTriviaSyntax startDirective, DirectiveTriviaSyntax endDirective) { if (startDirective.Kind() == SyntaxKind.IfDirectiveTrivia && endDirective.Kind() == SyntaxKind.ElifDirectiveTrivia) { var elifDirective = (ElifDirectiveTriviaSyntax)endDirective; var elifKeyword = elifDirective.ElifKeyword; var newIfDirective = SyntaxFactory.IfDirectiveTrivia( elifDirective.HashToken, SyntaxFactory.Token(elifKeyword.LeadingTrivia, SyntaxKind.IfKeyword, "if", "if", elifKeyword.TrailingTrivia), elifDirective.Condition, elifDirective.EndOfDirectiveToken, elifDirective.IsActive, elifDirective.BranchTaken, elifDirective.ConditionValue); return(newIfDirective.ToFullString()); } else { return(endDirective.ToFullString()); } }
public static EndRegionDirectiveTriviaSyntax GetEndRegion(this RegionDirectiveTriviaSyntax syntax) { DirectiveTriviaSyntax region = syntax; int c = 1; while ((region = region.GetNextDirective()) != null) { if (region.IsKind(SyntaxKind.EndRegionDirectiveTrivia)) { --c; if (c == 0) { return(region as EndRegionDirectiveTriviaSyntax); } } else if (region.IsKind(SyntaxKind.RegionDirectiveTrivia)) { ++c; } } return(null); }
private void HandleEndIfDirective(DirectiveTriviaSyntax directive) { if (_ifStack.IsEmpty()) { return; } var condDirectives = new List <DirectiveTriviaSyntax>(); condDirectives.Add(directive); while (!_ifStack.IsEmpty()) { var poppedDirective = _ifStack.Pop(); condDirectives.Add(poppedDirective); if (poppedDirective.Kind() == SyntaxKind.IfDirectiveTrivia) { break; } } condDirectives.Sort((n1, n2) => n1.SpanStart.CompareTo(n2.SpanStart)); foreach (var cond in condDirectives) { _conditionalMap.Add(cond, condDirectives); } // #If should be the first one in sorted order var ifDirective = condDirectives.First(); Contract.Assert( ifDirective.Kind() == SyntaxKind.IfDirectiveTrivia || ifDirective.Kind() == SyntaxKind.ElifDirectiveTrivia || ifDirective.Kind() == SyntaxKind.ElseDirectiveTrivia); _directiveMap.Add(directive, ifDirective); _directiveMap.Add(ifDirective, directive); }
private ImmutableArray <ConditionalRegion> ParseConditionalRegionChain(IList <DirectiveTriviaSyntax> directives, HashSet <DirectiveTriviaSyntax> visitedDirectives) { DirectiveTriviaSyntax previousDirective = null; Tristate previousRegionState = Tristate.False; bool hasEnabledRegion = false; var chain = ImmutableArray.CreateBuilder <ConditionalRegion>(); for (int i = 0; i < directives.Count; i++) { var directive = directives[i]; if (visitedDirectives.Contains(directive)) { // We've already visited this chain of linked directives return(default(ImmutableArray <ConditionalRegion>)); } if (previousDirective != null) { var regionState = EvaluateDirectiveExpression(previousDirective, previousRegionState); previousRegionState = regionState; if (regionState == Tristate.True) { // There can only be one always enabled region per chain regionState = hasEnabledRegion ? Tristate.False : Tristate.True; hasEnabledRegion = true; } var region = new ConditionalRegion(previousDirective, directive, regionState); chain.Add(region); } previousDirective = directive; visitedDirectives.Add(directive); } return(chain.ToImmutable()); }
internal Directive(DirectiveTriviaSyntax node) { Node = node; }