public override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node) { node = (FieldDeclarationSyntax)base.VisitFieldDeclaration(node); if (AttributeMatchUtil.HasAttributeSimple(node.AttributeLists, CountAttributeName)) { node = node.WithDeclaration(node.Declaration.WithType(NarrowIntegerType(node.Declaration.Type))); } return node; }
// this one does both proper and pseudo attributes public override SyntaxNode VisitParameter(ParameterSyntax node) { // Normal parameter lists use a proper attribute: [Widen] // Anonymous delegate parameter lists do not permit attributes, so must use trivia: /*[Widen]*/ // Therefore, check for both if (AttributeMatchUtil.HasAttributeSimple(node.AttributeLists, WidenAttributeName) || AttributeMatchUtil.HasTriviaAnnotationSimple(node.GetLeadingTrivia(), WidenAttributeName)) { node = node.WithType(WidenType(node.Type)); } node = (ParameterSyntax)base.VisitParameter(node); return(node); }
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) { if (AttributeMatchUtil.HasAttributeSimple(node.AttributeLists, WidenAttributeName)) { node = node.WithReturnType(WidenType(node.ReturnType)); } if (node.ExplicitInterfaceSpecifier != null) { // reassociate trivia from return type expression to interface type node = node .WithReturnType( node.ReturnType.WithTrailingTrivia(SyntaxTriviaList.Empty)) .WithExplicitInterfaceSpecifier( node.ExplicitInterfaceSpecifier.WithLeadingTrivia( node.ReturnType.GetTrailingTrivia().AddRange(node.ExplicitInterfaceSpecifier.GetLeadingTrivia()))); } node = (MethodDeclarationSyntax)base.VisitMethodDeclaration(node); return(node); }
public static SyntaxNode Do(Compilation compilation, Compilation interfacesCompilation, SyntaxNode root, SyntaxNode targetTypeDeclaration) { // Couldn't get SymbolFinder.FindImplementedInterfaceMembersAsync or .FindImplementations working, so doing it the hard hacky way. if (targetTypeDeclaration is StructDeclarationSyntax) { return(root); // not propagating documentation into the structs (used for enumeration entry definitions) } // collect all interfaces and the methods/properties they declare Dictionary <InterfaceDeclarationSyntax, List <MemberDeclarationSyntax> > interfaces = new Dictionary <InterfaceDeclarationSyntax, List <MemberDeclarationSyntax> >(); foreach (Compilation compilation1 in new Compilation[] { interfacesCompilation, compilation }) { foreach (SyntaxTree interfaceTree in compilation1.SyntaxTrees) { foreach (SyntaxNode node in interfaceTree.GetRoot().DescendantNodesAndSelf().Where( delegate(SyntaxNode candidate) { return(candidate.IsKind(SyntaxKind.InterfaceDeclaration)); })) { if (AttributeMatchUtil.HasAttributeSimple(((InterfaceDeclarationSyntax)node).AttributeLists, DocSourceAttributeName)) { List <MemberDeclarationSyntax> members = new List <MemberDeclarationSyntax>(); foreach (SyntaxNode decl in node.DescendantNodesAndSelf().Where(delegate(SyntaxNode candidate) { return(candidate.IsKind(SyntaxKind.MethodDeclaration) || candidate.IsKind(SyntaxKind.PropertyDeclaration)); })) { members.Add((MemberDeclarationSyntax)decl); } InterfaceDeclarationSyntax ifaceDecl = (InterfaceDeclarationSyntax)node; interfaces.Add(ifaceDecl, members); } } } } // enumrate base types of generated class List <BaseTypeSyntax> baseTypes = new List <BaseTypeSyntax>(); { IEnumerable <BaseTypeSyntax> baseTypeList = ((ClassDeclarationSyntax)targetTypeDeclaration).BaseList.Types; foreach (BaseTypeSyntax baseType in baseTypeList) { baseTypes.Add(baseType); } } Dictionary <SyntaxNode, SyntaxNode> replacements = new Dictionary <SyntaxNode, SyntaxNode>(); foreach (BaseTypeSyntax baseType in baseTypes) { // can we find an interface that matches this? foreach (KeyValuePair <InterfaceDeclarationSyntax, List <MemberDeclarationSyntax> > interfaceItem in interfaces) { InterfaceDeclarationSyntax interfaceDeclaration = interfaceItem.Key; // hack string baseTypeString = GetStringForBaseTypeComparison(baseType); string patternString = GetStringForInterfaceComparison(interfaceDeclaration); //Console.WriteLine("{2} {0} ? {1}", baseTypeString, patternString, String.Equals(baseTypeString, patternString) ? "*" : " "); if (String.Equals(baseTypeString, patternString)) { // can we find any members we implemented that are in the interface? foreach (SyntaxNode node in targetTypeDeclaration.DescendantNodes(delegate(SyntaxNode descendInto) { return((descendInto == targetTypeDeclaration) || descendInto.IsKind(SyntaxKind.MethodDeclaration) || descendInto.IsKind(SyntaxKind.PropertyDeclaration)); }) .Where(delegate(SyntaxNode candidate) { return(candidate.IsKind(SyntaxKind.MethodDeclaration) || candidate.IsKind(SyntaxKind.PropertyDeclaration)); })) { if (node.IsKind(SyntaxKind.MethodDeclaration)) { MethodDeclarationSyntax implementation = (MethodDeclarationSyntax)node; if (default(SyntaxToken) == implementation.Modifiers.FirstOrDefault(delegate(SyntaxToken candidate) { return(candidate.IsKind(SyntaxKind.PublicKeyword)); })) { continue; // non-public can't be from an interface } foreach (MemberDeclarationSyntax prototype1 in interfaceItem.Value) { if (prototype1.IsKind(SyntaxKind.MethodDeclaration)) { MethodDeclarationSyntax prototype = (MethodDeclarationSyntax)prototype1; // HACK: should check argument and return types if (SyntaxFactory.AreEquivalent(implementation.Identifier, prototype.Identifier) && (implementation.ParameterList.Parameters.Count == prototype.ParameterList.Parameters.Count)) { // copy documentation SyntaxNode replacement = node.WithLeadingTrivia( node.GetLeadingTrivia() .Add(SyntaxFactory.EndOfLine(Environment.NewLine)) .AddRange(CookDocumentationTrivia(prototype.GetLeadingTrivia()))); if (!replacements.ContainsKey(node)) // in case exposed by multiple interfaces { replacements.Add(node, replacement); } break; } } } } else if (node.IsKind(SyntaxKind.PropertyDeclaration)) { PropertyDeclarationSyntax implementation = (PropertyDeclarationSyntax)node; if (default(SyntaxToken) == implementation.Modifiers.FirstOrDefault(delegate(SyntaxToken candidate) { return(candidate.IsKind(SyntaxKind.PublicKeyword)); })) { continue; // non-public can't be from an interface } foreach (MemberDeclarationSyntax prototype1 in interfaceItem.Value) { if (prototype1.IsKind(SyntaxKind.PropertyDeclaration)) { PropertyDeclarationSyntax prototype = (PropertyDeclarationSyntax)prototype1; // HACK if (SyntaxFactory.AreEquivalent(implementation.Identifier, prototype.Identifier)) { // copy documentation SyntaxNode replacement = node.WithLeadingTrivia( node.GetLeadingTrivia() .Add(SyntaxFactory.EndOfLine(Environment.NewLine)) .AddRange(CookDocumentationTrivia(prototype.GetLeadingTrivia()))); if (!replacements.ContainsKey(node)) // in case exposed by multiple interfaces { replacements.Add(node, replacement); } break; } } } } else { throw new ArgumentException(); } } break; } } } SyntaxNodeReplacementRewriter syntaxNodeReplacementRewriter = new SyntaxNodeReplacementRewriter(replacements); root = syntaxNodeReplacementRewriter.Visit(root); // This is probably really slow - but we can use AreEquivalent() since we've only changed trivia targetTypeDeclaration = root.DescendantNodes().First(delegate(SyntaxNode candidate) { return(SyntaxFactory.AreEquivalent(targetTypeDeclaration, candidate)); }); replacements.Clear(); foreach (BaseTypeSyntax baseType in baseTypes) { // can we find an interface that matches this? foreach (KeyValuePair <InterfaceDeclarationSyntax, List <MemberDeclarationSyntax> > interfaceItem in interfaces) { InterfaceDeclarationSyntax interfaceDeclaration = interfaceItem.Key; // hack if (String.Equals(baseType.Type.ToString(), String.Concat(interfaceDeclaration.Identifier.Text, interfaceDeclaration.TypeParameterList != null ? interfaceDeclaration.TypeParameterList.ToString() : null))) { // propagate interface comment to class if (!replacements.ContainsKey(targetTypeDeclaration)) { replacements.Add( targetTypeDeclaration, targetTypeDeclaration.WithLeadingTrivia( targetTypeDeclaration.GetLeadingTrivia() .Add(SyntaxFactory.EndOfLine(Environment.NewLine)) .AddRange(CookDocumentationTrivia(interfaceDeclaration.GetLeadingTrivia())))); } break; } } } syntaxNodeReplacementRewriter = new SyntaxNodeReplacementRewriter(replacements); root = syntaxNodeReplacementRewriter.Visit(root); return(root); }