Пример #1
0
        /// <summary>
        /// Inspects the property values of the <paramref name="node"/> object using Reflection and
        /// creates API call descriptions for the property values recursively. Properties that are not
        /// essential to the shape of the syntax tree (such as Span) are ignored.
        /// </summary>
        private APIList QuotePropertyValues(SyntaxNode node)
        {
            var result     = APIList.Create();
            var properties = node.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

            // Filter out non-essential properties listed in nonStructuralProperties
            result.Add(properties.Where(propertyInfo => !nonStructuralProperties.Contains(propertyInfo.Name))
                       .Select(propertyInfo => QuotePropertyValue(node, propertyInfo))
                       .Where(apiCall => apiCall != null).ToArray( ));

            // HACK: factory methods for the following node types accept back the first "kind" parameter
            // that we filter out above. Add an artificial "property value" that can be later used to
            // satisfy the first parameter of type SyntaxKind.
            if (node is AccessorDeclarationSyntax || node is BinaryExpressionSyntax ||
                node is ClassOrStructConstraintSyntax || node is CheckedExpressionSyntax ||
                node is CheckedStatementSyntax || node is ConstructorInitializerSyntax ||
                node is GotoStatementSyntax || node is InitializerExpressionSyntax ||
                node is LiteralExpressionSyntax || node is MemberAccessExpressionSyntax ||
                node is OrderingSyntax || node is PostfixUnaryExpressionSyntax ||
                node is PrefixUnaryExpressionSyntax || node is DocumentationCommentTriviaSyntax ||
                node is SwitchLabelSyntax || node is YieldStatementSyntax)
            {
                result.Add(new ApiCall("Kind", "SyntaxKind." + node.CSharpKind( ).ToString( )));
            }

            return(result);
        }
Пример #2
0
        /// <summary>
        /// The main recursive method that given a SyntaxNode recursively quotes the entire subtree.
        /// </summary>
        private ApiCall QuoteNode(SyntaxNode node, string name)
        {
            APIList    quotedPropertyValues = QuotePropertyValues(node);
            MethodInfo factoryMethod        = PickFactoryMethodToCreateNode(node);
            var        factoryMethodCall    = new MethodCall(factoryMethod.DeclaringType.Name + "." + factoryMethod.Name);
            var        codeBlock            = new ApiCall(name, factoryMethodCall);

            APIList.AddFactoryMethodArguments(factoryMethod, factoryMethodCall, quotedPropertyValues);
            ApiCall.AddModifyingCalls(node, codeBlock, quotedPropertyValues);
            return(codeBlock);
        }
Пример #3
0
        /// <summary>
        /// Adds information about subsequent modifying fluent interface style calls on an object (like
        /// foo.With(...).With(...))
        /// </summary>
        public static void AddModifyingCalls(object treeElement, ApiCall apiCall, APIList values)
        {
            var methods = treeElement.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance);

            foreach (var value in values)
            {
                var methodName = "With" + value.Name.ProperCase();
                if (!methods.Any(m => m.Name == methodName))
                {
                    throw new NotSupportedException( );
                }
                methodName = "." + methodName;
                apiCall.AddModifyingCall(new MethodCall(methodName, ArgList.Create(value)));
            }
        }
Пример #4
0
        public static void AddFactoryMethodArguments(MethodInfo factory, MethodCall factoryMethodCall, APIList quotedValues)
        {
            foreach (var FMP in factory.GetParameters( ))
            {
                var pName = FMP.Name;
                var pType = FMP.ParameterType;

                ApiCall quotedCodeBlock = quotedValues.FindValue(pName);

                // special case to prefer Syntax.IdentifierName("C") to
                // Syntax.IdentifierName(Syntax.Identifier("C"))
                if (pName == "name" && pType == typeof(string))
                {
                    quotedCodeBlock = quotedValues.First(a => a.Name == "Identifier");
                    var methodCall = quotedCodeBlock.FactoryMethodCall as MethodCall;
                    if (methodCall != null && methodCall.Name == "SyntaxFactory.Identifier")
                    {
                        if (methodCall.Arguments.Count == 1)
                        {
                            factoryMethodCall.Arguments.Add(methodCall.Arguments [0]);
                        }
                        else
                        {
                            factoryMethodCall.Arguments.Add(quotedCodeBlock);
                        }
                        quotedValues.Remove(quotedCodeBlock);
                        continue;
                    }
                }
                // special case to prefer Syntax.ClassDeclarationSyntax(string) instead of
                // Syntax.ClassDeclarationSyntax(SyntaxToken)
                if (pName == "identifier" && pType == typeof(string))
                {
                    var methodCall = quotedCodeBlock.FactoryMethodCall as MethodCall;
                    if (methodCall != null && methodCall.Name == "SyntaxFactory.Identifier" && methodCall.Arguments.Count == 1)
                    {
                        factoryMethodCall.Arguments.Add(methodCall.Arguments [0]);
                        quotedValues.Remove(quotedCodeBlock);
                        continue;
                    }
                }

                if (quotedCodeBlock != null)
                {
                    factoryMethodCall.Arguments.Add(quotedCodeBlock); quotedValues.Remove(quotedCodeBlock);
                }
                else if (!FMP.IsOptional)
                {
                    throw new InvalidOperationException(
                              string.Format(
                                  "Couldn't find value for parameter '{0}' of method '{1}'. Go to QuotePropertyValues and add your node type to the exception list.",
                                  pName,
                                  factory));
                }
            }
        }