Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/GuOrg/Gu.Roslyn.Extensions
Extensions for analyzers & code fixes.
https://github.com/GuOrg/Gu.Roslyn.Extensions
Last synced: 5 days ago
JSON representation
Extensions for analyzers & code fixes.
- Host: GitHub
- URL: https://github.com/GuOrg/Gu.Roslyn.Extensions
- Owner: GuOrg
- License: mit
- Created: 2018-01-04T15:48:28.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2024-05-18T08:37:45.000Z (6 months ago)
- Last Synced: 2024-05-29T06:11:16.083Z (6 months ago)
- Language: C#
- Size: 2.33 MB
- Stars: 18
- Watchers: 3
- Forks: 6
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Gu.Roslyn.Extensions
Extensions for analyzers & code fixes.[![Build status](https://ci.appveyor.com/api/projects/status/ipk8pqx4n4m7y8u8/branch/master?svg=true)](https://ci.appveyor.com/project/JohanLarsson/gu-roslyn-extensions/branch/master)
[![Build Status](https://dev.azure.com/guorg/Gu.Roslyn.Extensions/_apis/build/status/GuOrg.Gu.Roslyn.Extensions?branchName=master)](https://dev.azure.com/guorg/Gu.Roslyn.Extensions/_build/latest?definitionId=9&branchName=master)
[![NuGet](https://img.shields.io/nuget/v/Gu.Roslyn.Extensions.Source.svg)](https://www.nuget.org/packages/Gu.Roslyn.Extensions.Source/)Reason there are three packages is if analyzer author writes analyzers and fixes in separate projetcs. In that case the separate `Gu.Roslyn.AnalyzerExtensions` and `Gu.Roslyn.CodeFixExtensions` should be used.
The `Gu.Roslyn.Extensions` package is a merge of `Gu.Roslyn.AnalyzerExtensions` and `Gu.Roslyn.CodeFixExtensions`.
- [Pooled](#pooled)
- [PooledSet](#pooledset-t)
- [StringBuilderPool](#stringbuilderpool)
- [StyleCopComparers](#stylecopcomparers)
- [Symbols](#symbols)
- [QualifiedType](#qualifiedtype)
- [QualifiedMember](#qualifiedmember)
- [SymbolExt](#symbolext)
- [TrySingleDeclaration](#trysingledeclaration)
- [TypeSymbolExt](#typesymbolext)
- [IsAssignableTo](#isassignableto)
- [TryFindMember](#tryfindmember)
- [TryFindMemberRecursive](#tryfindmemberrecursive)
- [Syntax](#syntax)
- [ArgumentListSyntaxExt](#argumentlistsyntaxext)
- [TryFind](#tryfind)
- [ArgumentSyntaxExt](#argumentsyntaxext)
- [TryGetStringValue](#trygetstringvalue)
- [TryFindParameter](#tryfindparameter)
- [BasePropertyDeclarationSyntaxExt](#basepropertydeclarationsyntaxext)
- [TryGetGetter and TryGetSetter](#trygetgetter-and-trygetsetter)
- [IsGetOnly](#isgetonly)
- [IsAutoProperty](#isautoproperty)
- [SyntaxNodeExt](#syntaxnodeext)
- [IsExecutedBefore](#isexecutedbefore)
- [TypeSyntaxExt](#typesyntaxext)
- [TryFindMember](#tryfindmember)
- [Doc comments](#doc-comments)
- [MemberDeclarationSyntaxExtensions.TryGetDocumentationComment](#memberdeclarationsyntaxextensionstrygetdocumentationcomment)
- [DocumentationCommentTriviaSyntaxExtensions.TryGetX](#documentationcommenttriviasyntaxextensionstrygetx)
- [DocumentationCommentTriviaSyntaxExtensions.WithX](#documentationcommenttriviasyntaxextensionswithx)
- [DocumentationCommentTriviaSyntaxExtensions.WithX](#documentationcommenttriviasyntaxextensionswithx)
- [Walkers](#walkers)
- [ExecutionWalker : PooledWalker](#executionwalker-t--pooledwalker-t)
- [PooledWalker](#pooledwalker-t)
- [Cache](#cache-tkey--tvalue)
- [EnumarebleExt](#enumarebleext)
- [FixAll](#fixall)
- [DocumentEditorCodeFixProvider](#documenteditorcodefixprovider)
- [CodeStyle](#codestyle)
- [UnderscoreFields](#underscorefields)
- [UsingDirectivesInsideNamespace](#usingdirectivesinsidenamespace)
- [BackingFieldsAdjacent](#backingfieldsadjacent)
- [DocumentEditorExt](#documenteditorext)
- [AddUsing](#addusing)
- [AddField](#addfield)
- [AddProperty](#addproperty)
- [AddMethod](#addmethod)
- [Simplify](#simplify)
- [WithSimplifiedNames](#withsimplifiednames-t)
- [Trivia](#trivia)
- [WithTriviaFrom](#withtriviafrom)
- [WithLeadingTriviaFrom](#withleadingtriviafrom)
- [WithTrailingTriviaFrom](#withtrailingtriviafrom)# Pooled
## PooledSet
```cs
using (var set = PooledSet.Borrow())
{
}
```Or when used recursively:
```cs
// set can be null here if so a new set its returned.
using (var current = set.IncrementUsage())
{
}## StringBuilderPool
```cs
var text = StringBuilderPool.Borrow()
.AppendLine("a")
.AppendLine()
.AppendLine("b")
.Return();
```# StyleCopComparers
Comparers that compare member declarations with stylecop order.
# Symbols
## QualifiedType
For comparing with `ITypeSymbol````cs
public static readonly QualifiedType Object = new QualifiedType("System.Object", "object");
```## QualifiedMember
Same as `QualifiedType` but for members.## SymbolExt
Extension methods for `ISymbol`.
### TrySingleDeclaration
Get the declaration if it exists. If the symbol is from a binary reference the declaration will not exist.
## TypeSymbolExt
Extension methods for `ItypeSymbol`.
### IsAssignableTo
For checking if `C is Type`
### TryFindMember
Find members by name or predicate.
### TryFindMemberRecursive
Find members by name or predicate in type or base types.
# Syntax
## ArgumentListSyntaxExt
### TryFind
Find the argument that matches the parameter.
## ArgumentSyntaxExt
### TryGetStringValue
Try get the constant string value of the argument.
### TryFindParameter
Try get the matching parameter
## BasePropertyDeclarationSyntaxExt
### TryGetGetter and TryGetSetter
Get the getter or setter if exists.### IsGetOnly
Check if the property is `public int Value { get; }`
### IsAutoProperty
Check if the property is an auto property.
## SyntaxNodeExt
### IsExecutedBefore
Check if a node is executed before another node.
## TypeSyntaxExt
### TryFindMember
Helper methods for finding members by name or predicate.
# Doc comments
## MemberDeclarationSyntaxExtensions.TryGetDocumentationComment
```cs
if(member.TryGetDocumentationComment(out DocumentationCommentTriviaSyntax comment))
{
}
```## DocumentationCommentTriviaSyntaxExtensions.TryGetX
```cs
if(comment.TryGetSummary(out XmlElementSyntax comment))
{
}if(comment.TryGetTypeParam("T", out XmlElementSyntax comment))
{
}if(comment.TryGetParam("x", out XmlElementSyntax comment))
{
}if(comment.TryGetReturns(out XmlElementSyntax comment))
{
}
```## DocumentationCommentTriviaSyntaxExtensions.WithX
```cs
var updated = comment.WithSummaryText("Lorem ipsum.")
var updated = comment.WithTypeParamText("T", "Lorem ipsum.")
var updated = comment.WithParamText("x", "Lorem ipsum.")
var updated = comment.WithReturnsText("x", "Lorem ipsum.")
```## MemberDeclarationSyntax.WithDocumentationText
```cs
var method = syntaxTree.FindMethodDeclaration("Bar");
var text = "/// New summary.\r\n" +
"/// New returns.";
var updated = method.WithDocumentationText(text);
```# Walkers
## ExecutionWalker : PooledWalker
Base type for a walker that walks code in execution order. Use the `Search` enum to specify if walk should be recursive walking invoked methods etc.
Remember to clear locals in the `Clear` method.```cs
internal sealed class AssignmentExecutionWalker : ExecutionWalker
{
private readonly List assignments = new List();private AssignmentExecutionWalker()
{
}///
/// Gets a list with all in the scope.
///
public IReadOnlyList Assignments => this.assignments;public override void VisitAssignmentExpression(AssignmentExpressionSyntax node)
{
this.assignments.Add(node);
base.VisitAssignmentExpression(node);
}internal static AssignmentExecutionWalker Borrow(SyntaxNode node, Search search, SemanticModel semanticModel, CancellationToken cancellationToken)
{
var walker = Borrow(() => new AssignmentExecutionWalker());
walker.SemanticModel = semanticModel;
walker.CancellationToken = cancellationToken;
walker.Search = search;
walker.Visit(node);
return walker;
}protected override void Clear()
{
this.assignments.Clear();
base.Clear();
}
}
```### PooledWalker
A pooled walker for reuse.
Remember to clear locals in the `Clear` method.```cs
internal sealed class IdentifierNameWalker : PooledWalker
{
private readonly List identifierNames = new List();private IdentifierNameWalker()
{
}public IReadOnlyList IdentifierNames => this.identifierNames;
public static IdentifierNameWalker Borrow(SyntaxNode node) => BorrowAndVisit(node, () => new IdentifierNameWalker());
public override void VisitIdentifierName(IdentifierNameSyntax node)
{
this.identifierNames.Add(node);
base.VisitIdentifierName(node);
}protected override void Clear()
{
this.identifierNames.Clear();
}
}
```### Cache
For caching expensive calls
```cs
public override void Initialize(AnalysisContext context)
{
context.CacheToCompilationEnd();
}
```### EnumarebleExt
Extension methods for enumarebls
- TrySingle
- TryLast
- TryElementAt# FixAll
## DocumentEditorCodeFixProvider
A fix all provider that use document editor for batch fixes.```cs
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseParameterCodeFixProvider))]
[Shared]
internal class UseParameterCodeFixProvider : DocumentEditorCodeFixProvider
{
///
public override ImmutableArray FixableDiagnosticIds { get; } =
ImmutableArray.Create(GU0014PreferParameter.DiagnosticId);///
protected override async Task RegisterCodeFixesAsync(DocumentEditorCodeFixContext context)
{
var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken)
.ConfigureAwait(false);foreach (var diagnostic in context.Diagnostics)
{
if (diagnostic.Properties.TryGetValue("Name", out var name))
{
if (syntaxRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is MemberAccessExpressionSyntax memberAccess)
{
context.RegisterCodeFix(
"Prefer parameter.",
(editor, _) => editor.ReplaceNode(
memberAccess,
SyntaxFactory.IdentifierName(name)
.WithLeadingTriviaFrom(memberAccess)),
"Prefer parameter.",
diagnostic);
}
else if (syntaxRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is IdentifierNameSyntax identifierName)
{
context.RegisterCodeFix(
"Prefer parameter.",
(editor, _) => editor.ReplaceNode(
identifierName,
identifierName.WithIdentifier(SyntaxFactory.Identifier(name))
.WithLeadingTriviaFrom(identifierName)),
"Prefer parameter.",
diagnostic);
}
}
}
}
}
```# CodeStyle
Helpers for determinining the code style used in the project.
## UnderscoreFields
## UsingDirectivesInsideNamespace
## BackingFieldsAdjacent
Figures out if backing field is placed like stylecop wants it or adjacent to the property.# DocumentEditorExt
Helpers for adding members sorted according to how StyleCop wants it.
## AddUsing
Adds the using sorted and figures out if it shoul add outside or insside the namespace from the current document then project.
## AddField
Adds the field at the position StyleCop wants it.
## AddProperty
Adds the property at the position StyleCop wants it.
## AddMethod
Adds the method at the position StyleCop wants it.
# Simplify
## WithSimplifiedNames
Uses a syntax rewriter that adds `Simplifier.Annotation` to all `QualifiedNameSyntax`# Trivia
Helpers for copying trivia from other nodes.
## WithTriviaFrom
Copy trivia from a node.## WithLeadingTriviaFrom
Copy leading trivia from a node.
## WithTrailingTriviaFrom
Copy trailing trivia from a node.
# Source package
Gu.Roslyn.Extensions.Source is a package containing the sources for embedding in consuming analyzer.
This is probably the best way to consume this library as Visual Studio and other tools do not work well when an analyzer has a binary dependency.
To work it requires:```xml
```