public void Execute(GeneratorExecutionContext context) { if (context.SyntaxReceiver is not InjectSyntaxReceiver receiver) { return; } foreach (var @class in receiver.GetSymbols(context)) { MemberDeclarationSyntax?type = @class.Rewrite(); if (type is null) { continue; } var @namespace = @class.ContainingNamespace?.Rewrite() ?.WithMembers(List(new[] { type })); var sourceText = CompilationUnit() .WithUsings(List(@class.GetUsingDirectives())) .WithMembers(List(new[] { @namespace ?? type })) .WithLeadingTrivia(TriviaList(Trivia(PragmaWarningDirectiveTrivia(Token(DisableKeyword), true)))) .NormalizeWhitespace() .ToFullString(); context.AddSource($"Lightning_{@class.MetadataName}.cs", sourceText); } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { ImmutableArray <String> exceptions = ImmutableArray <String> .Empty; foreach (Diagnostic diagnostic in context.Diagnostics) { if (diagnostic.Properties.TryGetValue(AnalysisContextExtensions.ExceptionMetadataName, out String exception)) { exceptions = exceptions.Add(exception); } } SyntaxNode?root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); MemberDeclarationSyntax?declaration = root? .FindToken(context.Diagnostics.First().Location.SourceSpan.Start) .Parent.AncestorsAndSelf() .OfType <MemberDeclarationSyntax>() .FirstOrDefault(); if (!exceptions.IsDefaultOrEmpty && !(declaration is null)) { CodeAction action = CodeAction.Create( title: "Add exception documentation", createChangedDocument: cancellationToken => DocumentExceptionsAsync(context.Document, declaration, exceptions), equivalenceKey: "DocumentExceptions" ); context.RegisterCodeFix(action, context.Diagnostics); } }
public Task <SyntaxList <MemberDeclarationSyntax> > GenerateAsync(TransformationContext context, IProgress <Diagnostic> progress, CancellationToken cancellationToken) { var results = SyntaxFactory.List <MemberDeclarationSyntax>(); MemberDeclarationSyntax?copy = null; var applyToClass = context.ProcessingNode as ClassDeclarationSyntax; if (applyToClass != null) { var properties = applyToClass.Members.OfType <PropertyDeclarationSyntax>() .Select(x => { var propertySymbol = context.SemanticModel.GetDeclaredSymbol(x); var attribute = propertySymbol?.GetAttributes() .FirstOrDefault(a => a.AttributeClass.Name == nameof(TestAttribute)); string suffix = "Suff" + string.Concat(attribute?.NamedArguments.Select(a => a.Value.Value !.ToString()) ?? Enumerable.Empty <string>()); return((MemberDeclarationSyntax)MethodDeclaration(ParseTypeName("void"), x.Identifier.ValueText + suffix) .AddModifiers(Token(SyntaxKind.PublicKeyword)) .AddBodyStatements(Block())); }); copy = ClassDeclaration(applyToClass.Identifier).WithModifiers(applyToClass.Modifiers).AddMembers(properties.ToArray()); } if (copy != null) { results = results.Add(copy); } return(Task.FromResult(results)); }
private static IReadOnlyCollection <MemberDeclarationSyntax> Generate(NamespaceWrapper root, ISet <string> excludeMembersAttributes, ISet <string> excludeAttributes, Nullability currentNullability, Func <TypeWrapper, bool> excludeFunc) { var namespaces = GetAllNamespaces(root) .AsParallel() .Select(namespaceInfo => (namespaceInfo, members: namespaceInfo .Members .OrderByAndExclude(excludeMembersAttributes, excludeAttributes) .Where(x => !x.IsNested) .ToList())) .Where(x => x.members.Count > 0) .OrderBy(x => x.namespaceInfo.FullName) .ToList(); var output = new List <MemberDeclarationSyntax> [namespaces.Count]; Parallel.For( 0, namespaces.Count, namespaceIndex => { var(namespaceInfo, types) = namespaces[namespaceIndex]; if (types.Count == 0) { return; } var list = new List <MemberDeclarationSyntax>(types.Count); output[namespaceIndex] = list; var members = new MemberDeclarationSyntax?[types.Count]; Parallel.For( 0, types.Count, i => { var current = types[i]; var member = Generate(current, excludeMembersAttributes, excludeAttributes, excludeFunc, currentNullability, 1); if (member != null) { members[i] = member.AddTrialingNewLines().AddLeadingNewLines(i == 0 ? 1 : 0); } }); var namespaceName = namespaceInfo.FullName; var validMembers = members.Where(x => x != null).Select(x => x !).ToList(); if (string.IsNullOrEmpty(namespaceName)) { list.AddRange(validMembers); } else { list.Add(NamespaceDeclaration(namespaceName, validMembers, namespaceIndex != 0)); } });
public JsonType(TypeName type, Func <ImmutableDictionary <TypeName, JsonType>, string>?directReadExpression, Func <ImmutableDictionary <TypeName, JsonType>, string, string>?directWriteStatement, string?converterName, MemberDeclarationSyntax?constructionMember, MemberDeclarationSyntax?outputMember, TinyType?tinyType) { Type = type; DirectReadExpression = directReadExpression; DirectWriteStatement = directWriteStatement; ConverterName = converterName; ConstructionMember = constructionMember; TinyType = tinyType; OutputMember = outputMember; }
private static Task <Document> ChangeAccessibilityAsync( Document document, SyntaxNode root, MemberDeclarationSyntax?declaration, SyntaxKind accessibility) { if (declaration is null) { return(Task.FromResult(document)); } var firstModifier = declaration.Modifiers.FirstOrDefault(); var newModifiers = declaration.Modifiers; var isFirstModiferRemoved = false; foreach (var currentModifier in newModifiers) { if (currentModifier.Kind() is SyntaxKind.PrivateKeyword or SyntaxKind.ProtectedKeyword or SyntaxKind.InternalKeyword or SyntaxKind.PublicKeyword && !currentModifier.IsKind(accessibility)) { newModifiers = newModifiers.Remove(currentModifier); if (currentModifier == firstModifier) { isFirstModiferRemoved = true; } } } if (!isFirstModiferRemoved && firstModifier.HasLeadingTrivia) { newModifiers = newModifiers.RemoveAt(0).Insert(0, firstModifier.WithLeadingTrivia(SyntaxTriviaList.Empty)); } var publicSyntax = SyntaxFactory.Token(accessibility); if (firstModifier.HasLeadingTrivia) { publicSyntax = publicSyntax.WithLeadingTrivia(declaration.Modifiers.FirstOrDefault().LeadingTrivia); } if (firstModifier.HasTrailingTrivia) { publicSyntax = publicSyntax.WithTrailingTrivia(declaration.Modifiers.FirstOrDefault().TrailingTrivia); } newModifiers = newModifiers.Insert(0, publicSyntax); var newDeclaration = declaration.WithModifiers(newModifiers); var newRoot = root.ReplaceNode(declaration, newDeclaration); var newDoc = document.WithSyntaxRoot(newRoot); return(Task.FromResult(newDoc)); }
private bool IsPublic(MemberDeclarationSyntax?methodDecl) { if (methodDecl is null || methodDecl is NamespaceDeclarationSyntax) { return(true); } if (!methodDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword))) { return(false); } return(IsPublic(methodDecl.Parent as MemberDeclarationSyntax)); }
/// <summary>Compares two nodes and returns a value indicating whether one is less than, equal to, or greater than the other according to StyleCop.</summary> /// <returns>A signed integer that indicates if the node should be before the other according to StyleCop.</returns> /// <param name="x">The first node to compare.</param> /// <param name="y">The second node to compare.</param> public static int Compare(MemberDeclarationSyntax?x, MemberDeclarationSyntax?y) { if (TryCompare <FieldDeclarationSyntax>(x, y, FieldDeclarationComparer.Compare, out var result) || TryCompare <ConstructorDeclarationSyntax>(x, y, ConstructorDeclarationComparer.Compare, out result) || TryCompareEvent(x, y, out result) || TryCompare <EnumDeclarationSyntax>(x, y, EnumDeclarationComparer.Compare, out result) || TryCompare <PropertyDeclarationSyntax>(x, y, PropertyDeclarationComparer.Compare, out result) || TryCompare <IndexerDeclarationSyntax>(x, y, IndexerDeclarationComparer.Compare, out result) || TryCompare <MethodDeclarationSyntax>(x, y, MethodDeclarationComparer.Compare, out result) || TryCompare <StructDeclarationSyntax>(x, y, StructDeclarationComparer.Compare, out result) || TryCompare <ClassDeclarationSyntax>(x, y, ClassDeclarationComparer.Compare, out result)) { return(result); } return(0); }
private static Task <Document> AddTypeModifierAsync( Document document, SyntaxNode root, MemberDeclarationSyntax?declaration, SyntaxKind modifier) { if (declaration is null) { return(Task.FromResult(document)); } var newModifier = SyntaxFactory.Token(modifier); var indexOfPartialKeyword = declaration.Modifiers.IndexOf(SyntaxKind.PartialKeyword); var newDeclaration = indexOfPartialKeyword < 0 ? declaration.AddModifiers(newModifier) : declaration.WithModifiers(declaration.Modifiers.Insert(indexOfPartialKeyword, newModifier)); var newRoot = root.ReplaceNode(declaration, newDeclaration); var newDoc = document.WithSyntaxRoot(newRoot); return(Task.FromResult(newDoc)); }
public Task <SyntaxList <MemberDeclarationSyntax> > GenerateAsync(TransformationContext context, IProgress <Diagnostic> progress, CancellationToken cancellationToken) { var results = SyntaxFactory.List <MemberDeclarationSyntax>(); MemberDeclarationSyntax?copy = null; var applyToClass = context.ProcessingNode as ClassDeclarationSyntax; if (applyToClass != null) { copy = applyToClass .WithIdentifier(SyntaxFactory.Identifier(applyToClass.Identifier.ValueText + this.suffix)); } if (copy != null) { results = results.Add(copy); } return(Task.FromResult(results)); }
public Task <SyntaxList <MemberDeclarationSyntax> > GenerateAsync(TransformationContext context, IProgress <Diagnostic> progress, CancellationToken cancellationToken) { var results = SyntaxFactory.List <MemberDeclarationSyntax>(); MemberDeclarationSyntax?copy = null; var applyToClass = context.ProcessingNode as MethodDeclarationSyntax; if (applyToClass != null) { copy = applyToClass .WithIdentifier(SyntaxFactory.Identifier(NameGenerator.Combine(applyToClass.Identifier.ValueText, this.suffix))) .WithLeadingTrivia(SyntaxFactory.Comment($"// Bogus content: {new Bogus.Faker().Hacker.Phrase()}")); } if (copy != null) { results = results.Add(copy); } return(Task.FromResult(results)); }
private static bool TryGetBackingMember(ObjectCreationExpressionSyntax objectCreation, SyntaxNodeAnalysisContext context, out FieldOrProperty fieldOrProperty, [NotNullWhen(true)] out MemberDeclarationSyntax?memberDeclaration) { fieldOrProperty = default; memberDeclaration = null; return(objectCreation.Parent switch { EqualsValueClauseSyntax _ => objectCreation.TryFirstAncestor(out memberDeclaration) && FieldOrProperty.TryCreate(context.ContainingSymbol, out fieldOrProperty), ArrowExpressionClauseSyntax _ => objectCreation.TryFirstAncestor(out memberDeclaration) && context.ContainingSymbol is IMethodSymbol { AssociatedSymbol : { } associatedSymbol } &&
public override void VisitMethodDeclaration(MethodDeclarationSyntax node) { if (!node.AttributeLists.Any()) { base.VisitMethodDeclaration(node); return; } var attribute = node.AttributeLists .SelectMany(al => al.Attributes) .SingleOrDefault(attr => attr.Name.ToString() == "JsonParseMethod"); if (attribute is null) { base.VisitMethodDeclaration(node); return; } var semanticModel = Compilation.GetSemanticModel(node.SyntaxTree); var type = node.Ancestors().OfType <TypeDeclarationSyntax>().First(); var typeName = type.ToTypeName(semanticModel); var typeSymbol = semanticModel.GetDeclaredSymbol(type); if (node.ReturnType.ToTypeName(semanticModel) != typeName) { throw new InvalidOperationException($"Parse method {typeName}.{node.Identifier} must have a signature returning the containing type."); } if (node.ParameterList.Parameters.Count != 1) { throw new InvalidOperationException($"Parse method {typeName}.{node.Identifier} must have a single parameter"); } if (node.Modifiers.Any(m => m.ToString() == "private" || m.ToString() == "internal")) { throw new InvalidOperationException($"Parse method {typeName}.{node.Identifier} must have be public or internal"); } if (!node.Modifiers.Any(m => m.ToString() == "static")) { throw new InvalidOperationException($"Parse method {typeName}.{node.Identifier} must have be static"); } var parseType = node.ParameterList.Parameters.Single().Type !.ToTypeName(semanticModel); var writeMemberName = attribute.ArgumentList?.Arguments.SingleOrDefault(); Func <ImmutableDictionary <TypeName, JsonType>, string, string>?writeStatement = null; MemberDeclarationSyntax?outputMember = null; if (writeMemberName is not null) { if (writeMemberName.Expression is null) { throw new InvalidOperationException("JsonParseMethod declarations must have zero arguments or a single unnamed nameof parameter naming the write member"); } if (writeMemberName.Expression is not InvocationExpressionSyntax invocation || invocation.Expression.ToString() != "nameof") { throw new InvalidOperationException("JsonParseMethod declarations that specify a write member must use nameof to reference the member"); } if (invocation.ArgumentList.Arguments.Count != 1 || invocation.ArgumentList.Arguments.Single().Expression is null) { throw new InvalidOperationException("Invalid nameof operator"); } var symbolInfo = semanticModel.GetSymbolInfo(invocation.ArgumentList.Arguments.Single().Expression); var symbol = symbolInfo.Symbol ?? symbolInfo.CandidateSymbols.OfType <IMethodSymbol>().SingleOrDefault(m => m.Parameters.Length == 0 && !m.ReturnsVoid && !m.IsStatic && SymbolEqualityComparer.Default.Equals(m.ContainingType, typeSymbol)); if (symbol is IMethodSymbol method) { var writeOutputType = method.ReturnType.ToTypeName(); writeStatement = (jsonTypes, valueExpr) => jsonTypes.TryGetValue(writeOutputType, out var parseTypeJsonType) && parseTypeJsonType.CanDirectWrite(jsonTypes) ? parseTypeJsonType.DirectWriteStatement !(jsonTypes, $"({valueExpr}).{method.Name}()") : null; outputMember = method.DeclaringSyntaxReferences.First().GetSyntax() as MemberDeclarationSyntax; } else if (symbol is IPropertySymbol property) { var writeOutputType = property.Type.ToTypeName(); writeStatement = (jsonTypes, valueExpr) => jsonTypes.TryGetValue(writeOutputType, out var parseTypeJsonType) && parseTypeJsonType.CanDirectWrite(jsonTypes) ? parseTypeJsonType.DirectWriteStatement !(jsonTypes, $"({valueExpr}).{property.Name}") : null; outputMember = property.DeclaringSyntaxReferences.First().GetSyntax() as MemberDeclarationSyntax; } else { throw new InvalidOperationException($"The member {invocation.ArgumentList.Arguments.Single().Expression} is not an instance property or method with no parameters and a return value on the same type as the parse method."); } } #pragma warning disable CS8603 // Possible null reference return. JsonTypes.Add(typeName, new JsonType( type: typeName, directReadExpression: jsonTypes => jsonTypes.TryGetValue(parseType, out var parseTypeJsonType) && parseTypeJsonType.CanDirectRead(jsonTypes) ? $"{typeName}.{node.Identifier}({parseTypeJsonType.DirectReadExpression!(jsonTypes)})" : null, directWriteStatement: writeStatement, converterName: $"{typeName.ShortName}MethodConverter", constructionMember: node, outputMember: outputMember, tinyType: null )); #pragma warning restore CS8603 // Possible null reference return. }
/// <summary> /// Try to get the single declaration of a property. /// </summary> /// <param name="event">The <see cref="IEventSymbol"/>. </param> /// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param> /// <param name="declaration">The declaration.</param> /// <returns>True if one declaration was found.</returns> public static bool TrySingleDeclaration(this IEventSymbol @event, CancellationToken cancellationToken, [NotNullWhen(true)] out MemberDeclarationSyntax?declaration) { if (@event is null) { throw new System.ArgumentNullException(nameof(@event)); } declaration = @event.DeclaringSyntaxReferences.TrySingle(out var reference) ? reference.GetSyntax(cancellationToken) as MemberDeclarationSyntax : null; return(declaration != null); }
public void Generate() { bool hasChildrenProperty = false; var destinationStaticMembers = new List <MemberDeclarationSyntax>(); var destinationMembers = new List <MemberDeclarationSyntax>(); var collectionProperties = new List <PropertyDeclarationSyntax>(); foreach (MemberDeclarationSyntax modelObjectMember in _sourceInterfaceDeclaration.Members) { if (!(modelObjectMember is PropertyDeclarationSyntax modelProperty)) { continue; } string propertyName = modelProperty.Identifier.Text; string propertyDescriptorName = propertyName + "Property"; TypeSyntax destinationPropertyType = ToDestinationType(modelProperty.Type); ExpressionSyntax defaultValue = GetDefaultValue(modelProperty); bool isCollection = IsCollectionType(modelProperty.Type, out TypeSyntax collectionElementType); if (isCollection) { collectionProperties.Add(modelProperty); } else { AddPropertyDescriptor(propertyName, propertyDescriptorName, destinationPropertyType, defaultValue, destinationStaticMembers); } AddProperty(propertyName, propertyDescriptorName, destinationPropertyType, modelProperty.Type, destinationMembers); if (propertyName == "Children") { hasChildrenProperty = true; } } // Add an annotation on the last static member, so we can later add a blank line between it and the properties that follow var lastStaticMemberAnnotation = new SyntaxAnnotation(); int staticMemberCount = destinationStaticMembers.Count; if (staticMemberCount > 0) { destinationStaticMembers[staticMemberCount - 1] = destinationStaticMembers[staticMemberCount - 1].WithAdditionalAnnotations(lastStaticMemberAnnotation); } ConstructorDeclarationSyntax?constructor = CreateConstructor(collectionProperties); TypeSyntax?baseInterface = _sourceInterfaceDeclaration.BaseList?.Types.FirstOrDefault()?.Type; TypeSyntax destinationBaseClass = GetBaseClass(baseInterface); List <MemberDeclarationSyntax> classMembers = new List <MemberDeclarationSyntax>(); classMembers.AddRange(destinationStaticMembers); if (constructor != null) { classMembers.Add(constructor); } classMembers.AddRange(destinationMembers); var classDeclaration = ClassDeclaration(_destinationClassName.Identifier) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) .WithBaseList( BaseList( SeparatedList <BaseTypeSyntax>( new SyntaxNodeOrToken[] { SimpleBaseType(destinationBaseClass), Token(SyntaxKind.CommaToken), SimpleBaseType(IdentifierName(_interfaceName)) }))) .WithMembers(new SyntaxList <MemberDeclarationSyntax>(classMembers)); if (DestinationTypeHasTypeConverterAttribute) { classDeclaration = classDeclaration.WithAttributeLists( SingletonList( AttributeList( SingletonSeparatedList( Attribute( IdentifierName("TypeConverter")) .WithArgumentList( AttributeArgumentList( SingletonSeparatedList( AttributeArgument( TypeOfExpression( IdentifierName($"{_destinationClassName.Identifier}TypeConverter")))))))))); } // Add the [ContentProperty("Children")] attribute, if needed if (hasChildrenProperty) { classDeclaration = classDeclaration .WithAttributeLists( SingletonList( AttributeList( SingletonSeparatedList( Attribute( IdentifierName("ContentProperty")) .WithArgumentList( AttributeArgumentList( SingletonSeparatedList( AttributeArgument( LiteralExpression( SyntaxKind.StringLiteralExpression, Literal("Children")))))))))); } #if false var usings = new List <UsingDirectiveSyntax> { UsingDirective(_interfaceNamespaceName) .WithUsingKeyword( Token( TriviaList( Comment($"// This file is generated from {_interfaceName}.cs. Update the source file to change its contents."), CarriageReturnLineFeed), SyntaxKind.UsingKeyword, TriviaList())), UsingDirective(QualifiedName(IdentifierName("System"), IdentifierName("Windows"))) }; if (addCollectionsUsing) { usings.Add(UsingDirective(QualifiedName( QualifiedName(IdentifierName("System"), IdentifierName("Collections")), IdentifierName("Generic")))); } if (addTransformsUsing) { usings.Add(UsingDirective(QualifiedName(IdentifierName("XGraphics"), IdentifierName("Transforms")))); // This will be, for example, XGraphics.WPF.Transforms usings.Add(UsingDirective(QualifiedName(_destinationNamespaceName, IdentifierName("Transforms")))); } if (hasChildrenProperty) { usings.Add(UsingDirective(QualifiedName( QualifiedName(IdentifierName("System"), IdentifierName("Windows")), IdentifierName("Markup")))); } #endif SyntaxList <UsingDirectiveSyntax> usingDeclarations = CreateUsingDeclarations(destinationStaticMembers.Count > 0); var compilationUnit = CompilationUnit() .WithUsings(usingDeclarations) .WithMembers( SingletonList <MemberDeclarationSyntax>( NamespaceDeclaration(_destinationNamespaceName) .WithMembers(SingletonList <MemberDeclarationSyntax>(classDeclaration)))) .NormalizeWhitespace(); MemberDeclarationSyntax?lastStaticMember = compilationUnit.DescendantNodes() .OfType <MemberDeclarationSyntax>().FirstOrDefault(n => n.HasAnnotation(lastStaticMemberAnnotation)); if (lastStaticMember != null) { var newTrailingTrivia = lastStaticMember.GetTrailingTrivia().Add(CarriageReturnLineFeed); compilationUnit = compilationUnit.ReplaceNode(lastStaticMember, lastStaticMember.WithTrailingTrivia(newTrailingTrivia)); } SourceText destinationSourceText = compilationUnit.GetText(); string outputDirectory = GetOutputDirectory(_sourceNamespaceName); Directory.CreateDirectory(outputDirectory); string destinationFilePath = Path.Combine(outputDirectory, _destinationClassName + ".cs"); using (StreamWriter fileWriter = File.CreateText(destinationFilePath)) destinationSourceText.Write(fileWriter); }
/// <summary> /// Find a <see cref="EventDeclarationSyntax"/> or <see cref="EventFieldDeclarationSyntax"/> by name. /// </summary> /// <param name="type">The containing type.</param> /// <param name="name">The name.</param> /// <param name="match">The match.</param> /// <returns>True if a match was found.</returns> public static bool TryFindEvent(this TypeDeclarationSyntax type, string name, [NotNullWhen(true)] out MemberDeclarationSyntax?match) { if (type is null) { throw new ArgumentNullException(nameof(type)); } if (name is null) { throw new ArgumentNullException(nameof(name)); } foreach (var member in type.Members) { switch (member) { case EventDeclarationSyntax { Identifier: { ValueText : { } valueText } } declaration when valueText == name : match = declaration; return(true); case EventFieldDeclarationSyntax { Declaration: { Variables : { } variables } } eventField when variables.TrySingle(x => x.Identifier.ValueText == name, out _) : match = eventField; return(true); } } match = null; return(false); }