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;
        }
Beispiel #2
0
        // 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);
        }
Beispiel #3
0
        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);
        }