/// <summary> /// Returns all attributes implementing the <typeparamref name="T"/> interface. /// </summary> public static IEnumerable <T> FindAttributesOfInterface <T>(this ImmutableArray <AttributeData> attributes) { Type interfType = typeof(T); if (!interfType.GetTypeInfo().IsInterface) { throw new ArgumentException("Expected an interface."); } string metadataName = interfType.IsConstructedGenericType ? interfType.GetGenericTypeDefinition().FullName : interfType.FullName; for (int i = 0; i < attributes.Length; i++) { AttributeData data = attributes[i]; ImmutableArray <INamedTypeSymbol> interfaces = data.AttributeClass.AllInterfaces; for (int o = 0; o < interfaces.Length; o++) { INamedTypeSymbol interf = interfaces[o]; if (interf.MetadataName != metadataName) { continue; } // We got this far, so we have a valid attribute; construct it. yield return(data.Construct <T>()); break; } } }
/// <summary> /// Returns all attributes of type <typeparamref name="T"/>. /// </summary> public static IEnumerable <T> FindAttributesOfType <T>(this ImmutableArray <AttributeData> attributes, bool allowInherited = true) { Type type = typeof(T); if (type.GetTypeInfo().IsInterface) { throw new ArgumentException("Expected a type."); } string metadataName = type.IsConstructedGenericType ? type.GetGenericTypeDefinition().Name : type.Name; for (int i = 0; i < attributes.Length; i++) { AttributeData data = attributes[i]; ITypeSymbol typeSymbol = data.AttributeClass; if (!allowInherited && typeSymbol.MetadataName == metadataName) { yield return(data.Construct <T>()); } else if (allowInherited) { while (typeSymbol != null) { if (typeSymbol.MetadataName == metadataName) { yield return(data.Construct <T>()); break; } typeSymbol = typeSymbol.BaseType; } } } }
/// <inheritdoc /> public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) { CancellationToken token = cancellationToken; INamedTypeSymbol symbol = semanticModel.GetDeclaredSymbol(node, token); if (symbol == null) { return(node); } int totalAttributes = 0; ImmutableArray <AttributeData> attrs = symbol.GetAttributes(); if (attrs.IsDefaultOrEmpty) { return(node); } SyntaxList <AttributeListSyntax> attributeLists = node.AttributeLists; for (int i = 0; i < attributeLists.Count; i++) { AttributeListSyntax attributeList = attributeLists[i]; SeparatedSyntaxList <AttributeSyntax> attributes = attributeList.Attributes; for (int j = 0; j < attributes.Count; j++, totalAttributes++) { AttributeSyntax attr = attributes[j]; string attrName = attr.Name.ToString(); if (attrName == "Component" || attrName == nameof(ComponentAttribute)) { // There is a 'Component' attribute: Specify its content. string contentStr = node.ToString(); // TODO: Use b64 and serialization // It works, except Roslyn <= 2.0.0 has a bug with serialization //using (MemoryStream ms = new MemoryStream()) //{ // node.SerializeTo(ms, cancellationToken); // contentStr = ms.TryGetBuffer(out ArraySegment<byte> buffer) // ? Convert.ToBase64String(buffer.Array, buffer.Offset, buffer.Count) // : Convert.ToBase64String(ms.ToArray()); //} AttributeArgumentSyntax contentArg = SyntaxFactory.AttributeArgument( SyntaxFactory.LiteralExpression( SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(contentStr) ) ); node = node.WithAttributeLists( attributeLists.Replace( attributeList, attributeList.WithAttributes( attributes.Replace(attr, attr.WithArgumentList( SyntaxFactory.AttributeArgumentList().AddArguments(contentArg) )) ) ) ); } // Maybe a component? AttributeData attrData = attrs[totalAttributes]; if (attrData.AttributeClass.MetadataName == nameof(CopyFromAttribute)) { // CopyFrom component: copy members node = CopyMembers(node, attrData, token); } else if (InheritsCompositionAttribute(attrData.AttributeClass)) { // Component: apply it CompositionAttribute builtAttr = attrData.Construct <CompositionAttribute>(); try { node = builtAttr.Component.Apply(node, symbol, token); if (node == null) { throw new NullReferenceException("A component cannot return null."); } } catch (Exception e) { throw new DiagnosticException($"Error applying the {builtAttr.Component} component.", e, attr.GetLocation()); } } } } return(node); }