private async Task<Document> HandleDeclarationAsync(Document document, SyntaxNode root, SyntaxNode node, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var declarationContext = node.Parent; TypeSyntax typeSyntax = null; if (declarationContext is VariableDeclarationSyntax) { typeSyntax = ((VariableDeclarationSyntax)declarationContext).Type; } else if (declarationContext is ForEachStatementSyntax) { typeSyntax = ((ForEachStatementSyntax)declarationContext).Type; } else { Contract.Fail($"unhandled kind {declarationContext.Kind().ToString()}"); } var typeSymbol = semanticModel.GetTypeInfo(typeSyntax).ConvertedType; var typeName = typeSymbol.GenerateTypeSyntax() .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(node.GetTrailingTrivia()); Debug.Assert(!typeName.ContainsDiagnostics, "Explicit type replacement likely introduced an error in code"); var newRoot = root.ReplaceNode(node, typeName); return document.WithSyntaxRoot(newRoot); }
private static Task<Document> ReplaceTypeWithVarAsync(Document document, SyntaxNode root, SyntaxNode node) { var implicitType = SyntaxFactory.IdentifierName("var") .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(node.GetTrailingTrivia()); var newRoot = root.ReplaceNode(node, implicitType); return Task.FromResult(document.WithSyntaxRoot(newRoot)); }
private static bool CheckSuppressionCommentOnNode(Diagnostic diagnostic, string diagnosticShortName, SyntaxNode node, CancellationToken cancellation) { cancellation.ThrowIfCancellationRequested(); var successfulMatch = node?.GetLeadingTrivia() .Where(x => x.IsKind(SyntaxKind.SingleLineCommentTrivia)) .Select(trivia => _suppressPattern.Match(trivia.ToString())) .FirstOrDefault(match => match.Success && diagnostic.Id == match.Groups[1].Value && diagnosticShortName == match.Groups[2].Value); return(successfulMatch != null); }
internal override Task<Document> GetUpdatedDocumentAsync( Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, string diagnosticId, CancellationToken cancellationToken) { ArrayTypeSyntax arrayType = GetArrayType(nodeToFix); if (arrayType != null) { TypeSyntax elementType = arrayType.ElementType.WithoutLeadingTrivia().WithoutTrailingTrivia(); if (arrayType.RankSpecifiers.Count > 1) { elementType = SyntaxFactory.ArrayType(elementType, SyntaxFactory.List(arrayType.RankSpecifiers.Skip(1))); } InvocationExpressionSyntax syntax = InvokeStaticGenericParameterlessMethod( model.Compilation.GetTypeByMetadataName("System.Array"), EmptyArrayDiagnosticAnalyzer.ArrayEmptyMethodName, elementType.WithoutLeadingTrivia().WithoutTrailingTrivia()); if (nodeToFix.HasLeadingTrivia) { syntax = syntax.WithLeadingTrivia(nodeToFix.GetLeadingTrivia()); } if (nodeToFix.HasTrailingTrivia) { syntax = syntax.WithTrailingTrivia(nodeToFix.GetTrailingTrivia()); } if (syntax != null) { root = root.ReplaceNode(nodeToFix, syntax); document = document.WithSyntaxRoot(root); } } return Task.FromResult(document); }
private static int GetLeadingWhitespaceLength(SyntaxNode node) { if (!(node is IXmlElement)) { return 0; } var leadingTrivia = node.GetLeadingTrivia(); if (leadingTrivia == null) { return 0; } int totalLength = 0; foreach (var child in leadingTrivia.ChildNodes) { if (child.Kind == SyntaxKind.WhitespaceTrivia) { totalLength += child.FullWidth; } } return totalLength; }
private IEnumerable <ExpressionStatementSyntax> CreateStubInitializerDeclarations(SyntaxNode node, string variableName, INamedTypeSymbol symbol) { var objectCreationExpression = node.DescendantNodes(s => !(s is ObjectCreationExpressionSyntax)).OfType <ObjectCreationExpressionSyntax>().FirstOrDefault(); IEnumerable <ExpressionStatementSyntax> initializerExpressions = new ExpressionStatementSyntax[0]; if (objectCreationExpression?.Initializer != null && symbol != null) { initializerExpressions = InitializersToExpressions.Expand(objectCreationExpression.Initializer, SyntaxFactory.IdentifierName(variableName)) .Select(expressionStatementSyntax => { var statementSyntax = expressionStatementSyntax.WithLeadingTrivia(node.GetLeadingTrivia()); var newAssignment = TryReplaceAssignmentExpressionWithMethodCall(statementSyntax, symbol); if (newAssignment == null) { return(statementSyntax); } return(newAssignment .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed)); }); } return(initializerExpressions); }
internal static SyntaxNode WithLeadingTriviaFrom(this SyntaxNode node, SyntaxNode other) { return(other.HasLeadingTrivia ? node.WithLeadingTrivia(other.GetLeadingTrivia()) : node); }
private static bool HasLeadingBlankLines(SyntaxNode node) { var firstTriviaIgnoringWhitespace = node.GetLeadingTrivia().FirstOrDefault(x => !x.IsKind(SyntaxKind.WhitespaceTrivia)); return(firstTriviaIgnoringWhitespace.IsKind(SyntaxKind.EndOfLineTrivia)); }
/// <summary> /// Determines if the node should be json serialized based on the precedence of /// a //json single line comment /// </summary> public static bool ShouldBeConvertedToJson(this SyntaxNode node) => node.HasLeadingTrivia && ShouldBeConvertedToJson(node, node.GetLeadingTrivia());
/// <summary> /// Determines if the node should be hidden i.e. not included in the documentation, /// based on the precedence of a //hide single line comment /// </summary> public static bool ShouldBeHidden(this SyntaxNode node) => node.HasLeadingTrivia && ShouldBeHidden(node, node.GetLeadingTrivia());
private static SyntaxNode ReplaceWellFormedMultiLineCommentHeader(Document document, SyntaxNode root, StyleCopSettings settings, int commentIndex, XmlFileHeader header) { SyntaxTriviaList trivia = root.GetLeadingTrivia(); var commentTrivia = trivia[commentIndex]; // Is the comment pushed in by a prefix? var commentIndentation = string.Empty; if (commentIndex > 0) { var prefixTrivia = trivia[commentIndex - 1]; if (prefixTrivia.IsKind(SyntaxKind.WhitespaceTrivia)) { commentIndentation = prefixTrivia.ToFullString(); } } var triviaString = commentTrivia.ToFullString(); var startIndex = triviaString.IndexOf("/*", StringComparison.Ordinal) + 2; var endIndex = triviaString.LastIndexOf("*/", StringComparison.Ordinal); var commentContext = triviaString.Substring(startIndex, endIndex - startIndex).Trim(' ', '\t').TrimEnd(); var triviaStringParts = commentContext.Replace("\r\n", "\n").Split('\n'); // Assume we have comments that have a leading * string interlinePadding = " *"; int minExpectedLength = (commentIndentation + interlinePadding).Length; string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); // Examine second line to see if we should have stars or not if it's blank // set the interline padding to be blank also. if ((triviaStringParts.Length > 2) && (triviaStringParts[1].Length > minExpectedLength) && string.IsNullOrWhiteSpace(triviaStringParts[1].Substring(0, minExpectedLength))) { interlinePadding = " "; } // Pad line that used to be next to a /* triviaStringParts[0] = commentIndentation + interlinePadding + " " + triviaStringParts[0]; StringBuilder sb = StringBuilderPool.Allocate(); string fileName = Path.GetFileName(document.FilePath); var copyrightText = GetCopyrightText(commentIndentation + interlinePadding, settings.DocumentationRules.GetCopyrightText(fileName), newLineText); var newHeader = WrapInXmlComment(commentIndentation + interlinePadding, copyrightText, document.Name, settings, newLineText); sb.Append(commentIndentation); sb.Append("/*"); if (header.GetElement("copyright") == null) { // No copyright element at the moment so add us. sb.Append(newHeader.Substring(minExpectedLength)); sb.Append(newLineText); // Append the original stuff foreach (var oldLine in triviaStringParts) { sb.Append(oldLine.TrimEnd()); sb.Append(newLineText); } } else { bool firstLine = true; bool inCopyright = false; foreach (var oldLine in triviaStringParts) { var openingTag = oldLine.Contains("<copyright "); var closingTag = oldLine.Contains("</copyright>") || (openingTag && oldLine.Trim().EndsWith("/>")); if (openingTag) { inCopyright = !closingTag; sb.Append(newHeader.Substring(firstLine ? minExpectedLength : 0)); sb.Append(newLineText); } if (inCopyright) { inCopyright = !closingTag; } else { sb.Append(oldLine.Substring(firstLine ? minExpectedLength : 0)); sb.Append(newLineText); } firstLine = false; } } sb.Append(commentIndentation); sb.Append(" */"); // Get rid of any trailing spaces. var lines = sb.ToString().Split(new string[] { newLineText }, StringSplitOptions.None); sb.Clear(); for (int i = 0; i < lines.Length; i++) { sb.Append((i == 0 ? string.Empty : newLineText) + lines[i].TrimEnd()); } var newTrivia = SyntaxFactory.SyntaxTrivia(SyntaxKind.MultiLineCommentTrivia, StringBuilderPool.ReturnAndFree(sb)); return(root.WithLeadingTrivia(trivia.Replace(commentTrivia, newTrivia))); }
public static T WithTrivia <T>([NotNull] this T syntaxNode, [NotNull] SyntaxNode templateNode) where T : SyntaxNode { Requires.NotNull(syntaxNode, nameof(syntaxNode)); Requires.NotNull(templateNode, nameof(templateNode)); return(syntaxNode.WithTrailingTrivia(templateNode.GetTrailingTrivia()).WithLeadingTrivia(templateNode.GetLeadingTrivia())); }
/// <summary> /// Visits the specified syntax node. /// </summary> /// <param name="node">The syntax node to visit.</param> public void Visit(SyntaxNode node) { if (node == null) { return; } if (node is SyntaxToken) { Visit(node.GetLeadingTrivia()); } switch (node.Kind) { case SyntaxKind.SingleLineCommentTrivia: case SyntaxKind.MultiLineCommentTrivia: VisitCommentTrivia((StructurelessSyntaxTrivia)node); break; case SyntaxKind.NumberToken: VisitNumber((SyntaxToken)node); break; case SyntaxKind.AnimationKeyword: case SyntaxKind.AsKeyword: case SyntaxKind.EventKeyword: case SyntaxKind.HandledKeyword: case SyntaxKind.ImportantKeyword: case SyntaxKind.KeyframeKeyword: case SyntaxKind.PlaySfxKeyword: case SyntaxKind.PlayStoryboardKeyword: case SyntaxKind.PropertyKeyword: case SyntaxKind.SetHandledKeyword: case SyntaxKind.SetKeyword: case SyntaxKind.TargetKeyword: case SyntaxKind.TransitionKeyword: case SyntaxKind.TriggerKeyword: VisitKeyword((SyntaxToken)node); break; case SyntaxKind.Selector: VisitSelector((UvssSelectorSyntax)node); break; case SyntaxKind.SelectorPart: case SyntaxKind.InvalidSelectorPart: VisitSelectorPart((UvssSelectorPartBaseSyntax)node); break; case SyntaxKind.PseudoClass: VisitPseudoClass((UvssPseudoClassSyntax)node); break; case SyntaxKind.Rule: VisitRule((UvssRuleSyntax)node); break; case SyntaxKind.EventName: VisitEventName((UvssEventNameSyntax)node); break; case SyntaxKind.PropertyName: VisitPropertyName((UvssPropertyNameSyntax)node); break; case SyntaxKind.PropertyValueToken: VisitPropertyValueToken((SyntaxToken)node); break; case SyntaxKind.Storyboard: VisitStoryboard((UvssStoryboardSyntax)node); break; case SyntaxKind.StoryboardTarget: VisitStoryboardTarget((UvssStoryboardTargetSyntax)node); break; case SyntaxKind.AnimationKeyframe: VisitAnimationKeyframe((UvssAnimationKeyframeSyntax)node); break; case SyntaxKind.NavigationExpression: VisitNavigationExpression((UvssNavigationExpressionSyntax)node); break; case SyntaxKind.UnknownDirective: VisitUnknownDirective((UvssUnknownDirectiveSyntax)node); break; case SyntaxKind.CultureDirective: VisitCultureDirective((UvssCultureDirectiveSyntax)node); break; } for (int i = 0; i < node.SlotCount; i++) { var child = node.GetSlot(i); if (child != null) { Visit(child); } } if (node is SyntaxToken) { Visit(node.GetTrailingTrivia()); } }
private static SyntaxNode ReplaceHeader(ISyntaxFacts syntaxFacts, AbstractFileHeaderHelper fileHeaderHelper, SyntaxTrivia newLineTrivia, SyntaxNode root, string expectedFileHeader) { // Skip single line comments, whitespace, and end of line trivia until a blank line is encountered. var triviaList = root.GetLeadingTrivia(); // True if the current line is blank so far (empty or whitespace); otherwise, false. The first line is // assumed to not be blank, which allows the analysis to detect a file header which follows a blank line at // the top of the file. var onBlankLine = false; // The set of indexes to remove from 'triviaList'. After removing these indexes, the remaining trivia (if // any) will be preserved in the document along with the replacement header. var removalList = new List <int>(); // The number of spaces to indent the new header. This is expected to match the indentation of the header // which is being replaced. var leadingSpaces = string.Empty; // The number of spaces found so far on the current line. This will become 'leadingSpaces' if the spaces are // followed by a comment which is considered a header comment. var possibleLeadingSpaces = string.Empty; // Need to do this with index so we get the line endings correct. for (var i = 0; i < triviaList.Count; i++) { var triviaLine = triviaList[i]; if (triviaLine.RawKind == syntaxFacts.SyntaxKinds.SingleLineCommentTrivia) { if (possibleLeadingSpaces != string.Empty) { // One or more spaces precedes the comment. Keep track of these spaces so we can indent the new // header by the same amount. leadingSpaces = possibleLeadingSpaces; } removalList.Add(i); onBlankLine = false; } else if (triviaLine.RawKind == syntaxFacts.SyntaxKinds.WhitespaceTrivia) { if (leadingSpaces == string.Empty) { possibleLeadingSpaces = triviaLine.ToFullString(); } removalList.Add(i); } else if (triviaLine.RawKind == syntaxFacts.SyntaxKinds.EndOfLineTrivia) { possibleLeadingSpaces = string.Empty; removalList.Add(i); if (onBlankLine) { break; } else { onBlankLine = true; } } else { break; } } // Remove copyright lines in reverse order. for (var i = removalList.Count - 1; i >= 0; i--) { triviaList = triviaList.RemoveAt(removalList[i]); } var newHeaderTrivia = CreateNewHeader(syntaxFacts, leadingSpaces + fileHeaderHelper.CommentPrefix, expectedFileHeader, newLineTrivia.ToFullString()); // Add a blank line and any remaining preserved trivia after the header. newHeaderTrivia = newHeaderTrivia.Add(newLineTrivia).Add(newLineTrivia).AddRange(triviaList); // Insert header at top of the file. return(root.WithLeadingTrivia(newHeaderTrivia)); }
/// <summary> /// Returns the updated solution and a flag indicating if all references were fixed or not. /// </summary> private async Task <(Solution newSolution, bool allReferencesFixed)> UpdateReferencesAsync(ISymbol symbol, Solution solution, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var references = await SymbolFinder.FindReferencesAsync(symbol, solution, cancellationToken).ConfigureAwait(false); // Filter out cascaded symbol references. For example, accessor references for property symbol. references = references.Where(r => symbol.Equals(r.Definition)); if (!references.HasExactly(1)) { return(newSolution : solution, allReferencesFixed : !references.Any()); } var allReferencesFixed = true; // Group references by document and fix references in each document. foreach (var referenceLocationGroup in references.Single().Locations.GroupBy(r => r.Document)) { // Get document in current solution var document = solution.GetDocument(referenceLocationGroup.Key.Id); // Skip references in projects with different language. // https://github.com/dotnet/roslyn-analyzers/issues/1986 tracks handling them. if (!document.Project.Language.Equals(symbol.Language, StringComparison.Ordinal)) { allReferencesFixed = false; continue; } var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); // Compute replacements var editor = new SyntaxEditor(root, solution.Workspace); foreach (var referenceLocation in referenceLocationGroup) { cancellationToken.ThrowIfCancellationRequested(); var referenceNode = root.FindNode(referenceLocation.Location.SourceSpan, getInnermostNodeForTie: true); if (referenceNode == null) { allReferencesFixed = false; continue; } var operation = semanticModel.GetOperationWalkingUpParentChain(referenceNode, cancellationToken); SyntaxNode nodeToReplaceOpt = null; switch (operation) { case IMemberReferenceOperation memberReference: if (IsReplacableOperation(memberReference.Instance)) { nodeToReplaceOpt = GetSyntaxNodeToReplace(memberReference); } break; case IInvocationOperation invocation: if (IsReplacableOperation(invocation.Instance)) { nodeToReplaceOpt = GetExpressionOfInvocation(invocation.Syntax); } break; } if (nodeToReplaceOpt == null) { allReferencesFixed = false; continue; } // Fetch the symbol for the node to replace - note that this might be // different from the original symbol due to generic type arguments. var symbolForNodeToReplace = GetSymbolForNodeToReplace(nodeToReplaceOpt, semanticModel); if (symbolForNodeToReplace == null) { allReferencesFixed = false; continue; } SyntaxNode memberName; var typeArgumentsOpt = GetTypeArguments(referenceNode); memberName = typeArgumentsOpt != null? editor.Generator.GenericName(symbolForNodeToReplace.Name, typeArgumentsOpt) : editor.Generator.IdentifierName(symbolForNodeToReplace.Name); var newNode = editor.Generator.MemberAccessExpression( expression: editor.Generator.TypeExpression(symbolForNodeToReplace.ContainingType), memberName: memberName) .WithLeadingTrivia(nodeToReplaceOpt.GetLeadingTrivia()) .WithTrailingTrivia(nodeToReplaceOpt.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); editor.ReplaceNode(nodeToReplaceOpt, newNode); } document = document.WithSyntaxRoot(editor.GetChangedRoot()); solution = document.Project.Solution; } return(solution, allReferencesFixed); // Local functions. bool IsReplacableOperation(IOperation operation) { // We only replace reference operations whose removal cannot change semantics. if (operation != null) { switch (operation.Kind) { case OperationKind.InstanceReference: case OperationKind.ParameterReference: case OperationKind.LocalReference: return(true); case OperationKind.FieldReference: case OperationKind.PropertyReference: return(IsReplacableOperation(((IMemberReferenceOperation)operation).Instance)); } } return(false); } ISymbol GetSymbolForNodeToReplace(SyntaxNode nodeToReplace, SemanticModel semanticModel) { var symbolInfo = semanticModel.GetSymbolInfo(nodeToReplace, cancellationToken); var symbolForNodeToReplace = symbolInfo.Symbol; if (symbolForNodeToReplace == null && symbolInfo.CandidateReason == CandidateReason.StaticInstanceMismatch && symbolInfo.CandidateSymbols.Length == 1) { return(symbolInfo.CandidateSymbols[0]); } return(symbolForNodeToReplace); } }
public static SyntaxToken WithLeadingTrivia(this SyntaxToken token, [NotNull] SyntaxNode node) { Requires.NotNull(node, nameof(node)); return(token.WithLeadingTrivia(node.GetLeadingTrivia())); }
void CheckXmlDocForErrors(SyntaxNode node, ISymbol member) { context.CancellationToken.ThrowIfCancellationRequested(); foreach (var triva in node.GetLeadingTrivia()) { if (triva.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia)) { storedXmlComment.Add((DocumentationCommentTriviaSyntax)triva.GetStructure()); new CRefVisistor(this).Visit(triva.GetStructure()); } } if (storedXmlComment.Count == 0) { return; } xml.Clear(); xml.Append(firstline); var OffsetTable = new List <int>(); foreach (var cmt in storedXmlComment) { OffsetTable.Add(xml.Length - firstline.Length); xml.Append(cmt.Content + "\n"); } xml.Append("</root>\n"); var doc = new AXmlParser().Parse(SourceText.From(xml.ToString())); var stack = new Stack <AXmlObject>(); stack.Push(doc); foreach (var err in doc.SyntaxErrors) { AddXmlIssue(CalculateRealStartOffset(OffsetTable, err.StartOffset), err.EndOffset - err.StartOffset, err.Description); } while (stack.Count > 0) { var cur = stack.Pop(); var el = cur as AXmlElement; if (el != null) { switch (el.Name) { case "typeparam": case "typeparamref": var name = el.Attributes.FirstOrDefault(attr => attr.Name == "name"); if (name == null || name.ValueSegment.Length < 2) { break; } if (member != null && member.IsKind(SymbolKind.NamedType)) { var type = (INamedTypeSymbol)member; if (!type.TypeArguments.Any(arg => arg.Name == name.Value)) { AddXmlIssue(CalculateRealStartOffset(OffsetTable, name.ValueSegment.Start + 1), name.ValueSegment.Length - 2, string.Format(GettextCatalog.GetString("Type parameter '{0}' not found"), name.Value)); } } break; case "param": case "paramref": name = el.Attributes.FirstOrDefault(attr => attr.Name == "name"); if (name == null || name.ValueSegment.Length < 2) { break; } var m = member as IMethodSymbol; if (m != null) { if (m.Parameters.Any(p => p.Name == name.Value)) { break; } AddXmlIssue(CalculateRealStartOffset(OffsetTable, name.ValueSegment.Start + 1), name.ValueSegment.Length - 2, string.Format(GettextCatalog.GetString("Parameter '{0}' not found"), name.Value)); break; } var prop = member as IPropertySymbol; if (prop != null) { if (prop.Parameters.Any(p => p.Name == name.Value)) { break; } if (name.Value == "value") { break; } AddXmlIssue(CalculateRealStartOffset(OffsetTable, name.ValueSegment.Start + 1), name.ValueSegment.Length - 2, string.Format(GettextCatalog.GetString("Parameter '{0}' not found"), name.Value)); break; } var evt = member as IEventSymbol; if (evt != null) { if (name.Value == "value") { break; } AddXmlIssue(CalculateRealStartOffset(OffsetTable, name.ValueSegment.Start + 1), name.ValueSegment.Length - 2, string.Format(GettextCatalog.GetString("Parameter '{0}' not found"), name.Value)); break; } var named = member as INamedTypeSymbol; if (named != null) { if (named.DelegateInvokeMethod == null) { break; } if (named.DelegateInvokeMethod.Parameters.Any(p => p.Name == name.Value)) { break; } AddXmlIssue(CalculateRealStartOffset(OffsetTable, name.ValueSegment.Start + 1), name.ValueSegment.Length - 2, string.Format(GettextCatalog.GetString("Parameter '{0}' not found"), name.Value)); break; } AddXmlIssue(CalculateRealStartOffset(OffsetTable, name.ValueSegment.Start + 1), name.ValueSegment.Length - 2, string.Format(GettextCatalog.GetString("Parameter '{0}' not found"), name.Value)); break; } } foreach (var child in cur.Children) { stack.Push(child); } } storedXmlComment.Clear(); }
/// <summary> /// Adds the <c>auto-generated</c> file header to the document. /// </summary> public SyntaxNode Process(SyntaxNode syntax, ProcessorContext context) => syntax.WithLeadingTrivia(syntax.GetLeadingTrivia().Add(Comment(header)));
public static bool IsExteriorTriviaEmptyOrWhitespace(SyntaxNode node) { return(node.GetLeadingTrivia().IsEmptyOrWhitespace() && node.GetTrailingTrivia().IsEmptyOrWhitespace()); }
public static SyntaxTrivia GetIndentation(this SyntaxNode node) { IEnumerable <SyntaxTrivia> leadingTrivia = node.GetLeadingTrivia(); return(leadingTrivia.GetIndentation()); }
public DocumentationComment?GetSingleLineComment(SyntaxNode method) { var trivia = method.GetLeadingTrivia().FirstOrDefault(t => t.Kind() == SyntaxKind.SingleLineDocumentationCommentTrivia); return(trivia == default ? null : Translate(trivia)); }
internal static async Task HandleDeclarationAsync( Document document, SyntaxEditor editor, SyntaxNode node, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var declarationContext = node.Parent; TypeSyntax typeSyntax = null; ParenthesizedVariableDesignationSyntax parensDesignation = null; if (declarationContext is RefTypeSyntax refType) { declarationContext = declarationContext.Parent; } if (declarationContext is VariableDeclarationSyntax varDecl) { typeSyntax = varDecl.Type; } else if (declarationContext is ForEachStatementSyntax forEach) { typeSyntax = forEach.Type; } else if (declarationContext is DeclarationExpressionSyntax declarationExpression) { typeSyntax = declarationExpression.Type; if (declarationExpression.Designation.IsKind(SyntaxKind.ParenthesizedVariableDesignation)) { parensDesignation = (ParenthesizedVariableDesignationSyntax)declarationExpression.Designation; } } else { Contract.Fail($"unhandled kind {declarationContext.Kind().ToString()}"); } if (parensDesignation is null) { var typeSymbol = semanticModel.GetTypeInfo(typeSyntax.StripRefIfNeeded()).ConvertedType; // We're going to be passed through the simplifier. Tell it to not just convert // this back to var (as that would defeat the purpose of this refactoring entirely). var typeName = typeSymbol.GenerateTypeSyntax(allowVar: false) .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(node.GetTrailingTrivia()); Debug.Assert(!typeName.ContainsDiagnostics, "Explicit type replacement likely introduced an error in code"); editor.ReplaceNode(node, typeName); } else { var tupleTypeSymbol = semanticModel.GetTypeInfo(typeSyntax.Parent).ConvertedType; var leadingTrivia = node.GetLeadingTrivia() .Concat(parensDesignation.GetAllPrecedingTriviaToPreviousToken().Where(t => !t.IsWhitespace()).Select(t => t.WithoutAnnotations(SyntaxAnnotation.ElasticAnnotation))); var tupleDeclaration = GenerateTupleDeclaration(tupleTypeSymbol, parensDesignation).WithLeadingTrivia(leadingTrivia); editor.ReplaceNode(declarationContext, tupleDeclaration); } }
private static SyntaxNode RemoveComments(SyntaxNode ele) { if (ele.HasLeadingTrivia) { var oldCommentsTrivias = from trivia in ele.GetLeadingTrivia().Where( x => (x.Kind == SyntaxKind.MultiLineCommentTrivia || x.Kind == SyntaxKind.SingleLineCommentTrivia)) select trivia; foreach (var comment in oldCommentsTrivias) { ele = ele.ReplaceTrivia(comment, SyntaxTriviaList.Empty); } } if (ele.DescendantTrivia() != null && ele.DescendantTrivia().Count() > 0) { var containingComments = from trivia in ele.DescendantTrivia().Where( x => (x.Kind == SyntaxKind.MultiLineCommentTrivia || x.Kind == SyntaxKind.SingleLineCommentTrivia)) select trivia; foreach (var comment in containingComments) { ele = ele.ReplaceTrivia(comment, SyntaxTriviaList.Empty); } } return ele; }
private static SyntaxNode ReplaceHeader(Document document, SyntaxNode root, StyleCopSettings settings, bool isMalformedHeader) { // If the header is well formed Xml then we parse out the copyright otherwise // Skip single line comments, whitespace, and end of line trivia until a blank line is encountered. SyntaxTriviaList trivia = root.GetLeadingTrivia(); bool onBlankLine = false; bool inCopyright = isMalformedHeader; int? copyrightTriviaIndex = null; var removalList = new List <int>(); var leadingSpaces = string.Empty; string possibleLeadingSpaces = string.Empty; // remove header decoration lines, they will be re-generated trivia = RemoveHeaderDecorationLines(trivia, settings); // Need to do this with index so we get the line endings correct. for (int i = 0; i < trivia.Count; i++) { var triviaLine = trivia[i]; bool done = false; switch (triviaLine.Kind()) { case SyntaxKind.SingleLineCommentTrivia: if (possibleLeadingSpaces != string.Empty) { leadingSpaces = possibleLeadingSpaces; } if (!isMalformedHeader) { var openingTag = triviaLine.ToFullString().Contains("<copyright "); var closingTag = triviaLine.ToFullString().Contains("</copyright>") || (openingTag && triviaLine.ToFullString().Trim().EndsWith("/>")); if (openingTag) { inCopyright = !closingTag; copyrightTriviaIndex = i; } else if (inCopyright) { removalList.Add(i); inCopyright = !closingTag; } } else { removalList.Add(i); } onBlankLine = false; break; case SyntaxKind.WhitespaceTrivia: if (leadingSpaces == string.Empty) { possibleLeadingSpaces = triviaLine.ToFullString(); } if (inCopyright) { removalList.Add(i); } break; case SyntaxKind.EndOfLineTrivia: if (inCopyright) { removalList.Add(i); } if (onBlankLine) { done = true; } else { onBlankLine = true; } break; default: done = true; break; } if (done) { break; } } // Remove copyright lines in reverse order. for (int i = removalList.Count - 1; i >= 0; i--) { trivia = trivia.RemoveAt(removalList[i]); } string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); var newLineTrivia = SyntaxFactory.EndOfLine(newLineText); var newHeaderTrivia = CreateNewHeader(leadingSpaces + "//", document.Name, settings, newLineText); if (!isMalformedHeader && copyrightTriviaIndex.HasValue) { // Does the copyright element have leading whitespace? If so remove it. if ((copyrightTriviaIndex.Value > 0) && trivia[copyrightTriviaIndex.Value - 1].IsKind(SyntaxKind.WhitespaceTrivia)) { copyrightTriviaIndex = copyrightTriviaIndex - 1; trivia = trivia.RemoveAt(copyrightTriviaIndex.Value); } // Replace copyright element in place. return(root.WithLeadingTrivia(trivia.ReplaceRange(trivia[copyrightTriviaIndex.Value], newHeaderTrivia))); } else { // Add blank line if we don't already have comments at top of file. if (!FirstLineIsComment(trivia)) { newHeaderTrivia = newHeaderTrivia.Add(newLineTrivia); } // Insert header at top of the file. return(root.WithLeadingTrivia(newHeaderTrivia.Add(newLineTrivia).AddRange(trivia))); } }
protected static void ComputePositionAndTriviaForRemoveAttributeFromAttributeList( SyntaxNode attributeToRemove, Func <SyntaxToken, bool> isComma, out int positionOfRemovedNode, out IEnumerable <SyntaxTrivia> triviaOfRemovedNode) { positionOfRemovedNode = attributeToRemove.FullSpan.Start; var root = attributeToRemove.SyntaxTree.GetRoot(); var previousToken = root.FindToken(attributeToRemove.FullSpan.Start - 1); var leading = isComma(previousToken) ? previousToken.LeadingTrivia : attributeToRemove.GetLeadingTrivia(); var nextToken = root.FindToken(attributeToRemove.FullSpan.End + 1); var trailing = isComma(nextToken) ? nextToken.TrailingTrivia : attributeToRemove.GetTrailingTrivia(); triviaOfRemovedNode = leading.Concat(trailing); }
public static bool ShouldBeHidden(this SyntaxNode node, SyntaxTriviaList leadingTrivia) => leadingTrivia != default(SyntaxTriviaList) && SingleLineHideComment.IsMatch(node.GetLeadingTrivia().ToFullString());
private bool HasCopyrightHeader(SyntaxNode syntaxNode) { var existingHeader = GetExistingHeader(syntaxNode.GetLeadingTrivia()); return(SequnceStartsWith(_header, existingHeader)); }
/// <summary> /// Determines if the node is preceded by any multiline documentation. /// </summary> /// <param name="node">The node.</param> public static bool HasMultiLineDocumentationCommentTrivia(this SyntaxNode node) => node.HasLeadingTrivia && node.GetLeadingTrivia().Any(c => c.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia));
public override SyntaxNode Visit(SyntaxNode node) { _cancellationToken.ThrowIfCancellationRequested(); if (node == null) { return node; } // Process children first node = base.Visit(node); // Check the leading trivia for doc comments. if (node.GetLeadingTrivia().Any(SyntaxKind.SingleLineDocumentationCommentTrivia)) { var newLeadingTrivia = new List<SyntaxTrivia>(); foreach (var trivia in node.GetLeadingTrivia()) { if (trivia.Kind() == SyntaxKind.SingleLineDocumentationCommentTrivia) { newLeadingTrivia.Add(SyntaxFactory.Comment("//")); newLeadingTrivia.Add(SyntaxFactory.ElasticCarriageReturnLineFeed); var structuredTrivia = (DocumentationCommentTriviaSyntax)trivia.GetStructure(); newLeadingTrivia.AddRange(ConvertDocCommentToRegularComment(structuredTrivia)); } else { newLeadingTrivia.Add(trivia); } } node = node.WithLeadingTrivia(newLeadingTrivia); } return node; }
public SyntaxNode TraverseAndConvert(SyntaxNode node, SyntaxNode newNode) { // Step 1: Handle current node // Find out if this node is a documentable API declaration // If not, skip to go to the child nodes. string docCommentId = GetAPIForNode(node); if (docCommentId != null) { // Look up the comment text string docCommentText = GetDocCommentForId(docCommentId); // Get the SyntaxTrivia for the comment SyntaxTree newTree = (CSharpSyntaxTree)CSharpSyntaxTree.ParseText(docCommentText); var newTrivia = newTree.GetRoot().GetLeadingTrivia(); // Read a doc comment from a syntax tree. //var classNode = (ClassDeclarationSyntax)newTree.GetRoot().ChildNodes().First(); //var newTrivia = classNode.GetLeadingTrivia(); //var docCommentTrivia = newTrivia.Single(t => t.Kind() == SyntaxKind.SingleLineDocumentationCommentTrivia || // t.Kind() == SyntaxKind.MultiLineDocumentationCommentTrivia); // Find out if there is an existing comment or doc comment if (node.HasLeadingTrivia) { SyntaxTriviaList triviaList = node.GetLeadingTrivia(); SyntaxTrivia firstComment = triviaList.Last(); foreach (var trivia in triviaList.Reverse()) { SyntaxKind kind = trivia.Kind(); switch (kind) { case SyntaxKind.SingleLineCommentTrivia: case SyntaxKind.MultiLineCommentTrivia: // Found existing comment firstComment = trivia; break; case SyntaxKind.MultiLineDocumentationCommentTrivia: case SyntaxKind.SingleLineDocumentationCommentTrivia: // Found existing XML doc comment firstComment = trivia; break; default: break; } } // Append the doc comment newNode = node.InsertTriviaBefore(firstComment, newTrivia); } else // no leading trivia { newNode = node.WithLeadingTrivia(newTrivia); } } else // not an API node { newNode = node; } if (node.ChildNodes().Count() > 0) { newNode = newNode.ReplaceNodes(newNode.ChildNodes(), TraverseAndConvert); } return(newNode); }
public static void CollectCommentBlockSpans( SyntaxNode node, ArrayBuilder<BlockSpan> spans) { if (node == null) { throw new ArgumentNullException(nameof(node)); } var triviaList = node.GetLeadingTrivia(); CollectCommentBlockSpans(triviaList, spans); }
private static SyntaxNode TrimLeadingNewLines(SyntaxNode node) => node.WithLeadingTrivia(node.GetLeadingTrivia().SkipWhile(t => t.Kind() == SyntaxKind.EndOfLineTrivia));
private async Task <Document> ReplaceDateTimeWithDateTimeOffsetAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) { SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken); IdentifierNameSyntax convertedNode = (IdentifierNameSyntax)node; IdentifierNameSyntax newNode = convertedNode?.WithIdentifier(SyntaxFactory.ParseToken("DateTimeOffset")).WithLeadingTrivia(node.GetLeadingTrivia()).WithTrailingTrivia(node.GetTrailingTrivia()); SyntaxNode newRoot = root.ReplaceNode(node, newNode); Document newDocument = document.WithSyntaxRoot(newRoot); return(newDocument); }
/// <summary> /// Gets the number of steps that the given node is indented. /// </summary> /// <param name="indentationOptions">The indentation options to use.</param> /// <param name="node">The node to inspect.</param> /// <returns>The number of steps that the node is indented.</returns> public static int GetIndentationSteps(IndentationOptions indentationOptions, SyntaxNode node) { return(GetIndentationSteps(indentationOptions, node.SyntaxTree, node.GetLeadingTrivia())); }
public static string ConvertTo(this SyntaxNode source, string middle) { return($"{source.GetLeadingTrivia().ToFullString()}{middle}{source.GetTrailingTrivia().ToFullString()}"); }
public static bool IsAutogenerated(SyntaxNode contents) { return contents.GetLeadingTrivia().Any(x => x.ToFullString().Contains("<auto-generated")); }
// VB can't override virtual events :\ // See https://github.com/dotnet/vblang/issues/63 protected override SyntaxNode AddEvent(SyntaxGenerator generator, SyntaxNode syntax, IEventSymbol symbol, SyntaxNode @event) => syntax.WithLeadingTrivia(syntax.GetLeadingTrivia().Add( CommentTrivia($@"' NOTE: overriding virtual events is not supported by VB.NET. Skipping {generator.GetName(@event)}. See https://github.com/dotnet/vblang/issues/63 ")));
public static void CollectCommentRegions(SyntaxNode node, List<OutliningSpan> spans) { if (node == null) { throw new ArgumentNullException("node"); } var triviaList = node.GetLeadingTrivia(); CollectCommentRegions(triviaList, spans); }
private static bool NoCommentsBefore(SyntaxNode node) => !node.GetLeadingTrivia().Any(t => t.IsComment());