private static void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
        {
            var invocation = context.Node as InvocationExpressionSyntax;
            var info       = context.SemanticModel.GetSymbolInfo(invocation);
            var method     = info.Symbol as IMethodSymbol;

            if (method == null)
            {
                return;
            }

            // is serilog even present in the compilation?
            var messageTemplateAttribute = context.SemanticModel.Compilation.GetTypeByMetadataName("Serilog.Core.MessageTemplateFormatMethodAttribute");

            if (messageTemplateAttribute == null)
            {
                return;
            }

            // is it a serilog logging method?
            var attributes    = method.GetAttributes();
            var attributeData = attributes.FirstOrDefault(x => x.AttributeClass == messageTemplateAttribute);

            if (attributeData == null)
            {
                return;
            }

            string messageTemplateName = attributeData.ConstructorArguments.First().Value as string;

            // check for errors in the MessageTemplate
            var arguments      = new List <SourceArgument>();
            var properties     = new List <PropertyToken>();
            var hasErrors      = false;
            var literalSpan    = default(TextSpan);
            var exactPositions = true;
            var stringText     = default(string);

            foreach (var argument in invocation.ArgumentList.Arguments)
            {
                var paramter = RoslynHelper.DetermineParameter(argument, context.SemanticModel, true, context.CancellationToken);
                if (paramter.Name == messageTemplateName)
                {
                    string messageTemplate;

                    // is it a simple string literal?
                    var literal = argument.Expression as LiteralExpressionSyntax;
                    if (literal == null)
                    {
                        // can we at least get a computed constant value for it?
                        var constantValue = context.SemanticModel.GetConstantValue(argument.Expression, context.CancellationToken);
                        if (!constantValue.HasValue || !(constantValue.Value is string))
                        {
                            context.ReportDiagnostic(Diagnostic.Create(ConstantMessageTemplateRule, argument.Expression.GetLocation(), argument.Expression.ToString()));
                            continue;
                        }

                        // we can't map positions back from the computed string into the real positions
                        exactPositions  = false;
                        messageTemplate = constantValue.Value as string;
                    }
                    else
                    {
                        stringText     = literal.Token.Text;
                        exactPositions = true;

                        messageTemplate = literal.Token.ValueText;
                    }

                    literalSpan = argument.Expression.GetLocation().SourceSpan;

                    var messageTemplateDiagnostics = AnalyzingMessageTemplateParser.Analyze(messageTemplate);
                    foreach (var templateDiagnostic in messageTemplateDiagnostics)
                    {
                        var property = templateDiagnostic as PropertyToken;
                        if (property != null)
                        {
                            properties.Add(property);
                            continue;
                        }

                        var diagnostic = templateDiagnostic as MessageTemplateDiagnostic;
                        if (diagnostic != null)
                        {
                            hasErrors = true;
                            ReportDiagnostic(ref context, ref literalSpan, stringText, exactPositions, TemplateRule, diagnostic);
                        }
                    }
                }
                else if (paramter.Name.StartsWith("propertyValue", StringComparison.Ordinal))
                {
                    var location = argument.GetLocation().SourceSpan;
                    arguments.Add(new SourceArgument {
                        StartIndex = location.Start, Length = location.Length
                    });
                }
            }

            // do properties match up?
            if (!hasErrors && literalSpan != default(TextSpan) && (arguments.Count > 0 || properties.Count > 0))
            {
                var diagnostics = PropertyBindingAnalyzer.AnalyzeProperties(properties, arguments);
                foreach (var diagnostic in diagnostics)
                {
                    ReportDiagnostic(ref context, ref literalSpan, stringText, exactPositions, PropertyBindingRule, diagnostic);
                }

                // are there duplicate property names?
                var usedNames = new HashSet <string>();
                foreach (var property in properties)
                {
                    if (!property.IsPositional && !usedNames.Add(property.PropertyName))
                    {
                        ReportDiagnostic(ref context, ref literalSpan, stringText, exactPositions, UniquePropertyNameRule, new MessageTemplateDiagnostic(property.StartIndex, property.Length, property.PropertyName));
                    }
                }
            }

            // is this an overload where the exception argument is used?
            var exception = context.SemanticModel.Compilation.GetTypeByMetadataName("System.Exception");

            if (method.Parameters.First().Type == exception)
            {
                return;
            }

            // is there an overload with the exception argument?
            if (!method.ContainingType.GetMembers().OfType <IMethodSymbol>().Any(x => x.Name == method.Name && x.Parameters.FirstOrDefault()?.Type == exception))
            {
                return;
            }

            // check wether any of the format arguments is an exception
            foreach (var argument in invocation.ArgumentList.Arguments)
            {
                var arginfo = context.SemanticModel.GetTypeInfo(argument.Expression);
                if (IsException(exception, arginfo.Type))
                {
                    context.ReportDiagnostic(Diagnostic.Create(ExceptionRule, argument.GetLocation(), argument.Expression.ToFullString()));
                }
            }
        }
        private static void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
        {
            var invocation = context.Node as InvocationExpressionSyntax;
            var info       = context.SemanticModel.GetSymbolInfo(invocation, context.CancellationToken);
            var method     = info.Symbol as IMethodSymbol;

            if (method == null)
            {
                return;
            }

            // is serilog even present in the compilation?
            var messageTemplateAttribute = context.SemanticModel.Compilation.GetTypeByMetadataName("Serilog.Core.MessageTemplateFormatMethodAttribute");

            if (messageTemplateAttribute == null)
            {
                return;
            }

            // check if ForContext<T> / ForContext(typeof(T)) calls use the containing type as T
            if (method.Name == ForContext && method.ReturnType.ToString() == ILogger)
            {
                CheckForContextCorrectness(ref context, invocation, method);
            }

            // is it a serilog logging method?
            var attributes    = method.GetAttributes();
            var attributeData = attributes.FirstOrDefault(x => x.AttributeClass == messageTemplateAttribute);

            if (attributeData == null)
            {
                return;
            }

            string messageTemplateName = attributeData.ConstructorArguments.First().Value as string;

            // check for errors in the MessageTemplate
            var arguments           = default(List <SourceArgument>);
            var properties          = new List <PropertyToken>();
            var hasErrors           = false;
            var literalSpan         = default(TextSpan);
            var exactPositions      = true;
            var stringText          = default(string);
            var invocationArguments = invocation.ArgumentList.Arguments;

            foreach (var argument in invocationArguments)
            {
                var parameter = RoslynHelper.DetermineParameter(argument, context.SemanticModel, true, context.CancellationToken);
                if (parameter.Name == messageTemplateName)
                {
                    string messageTemplate;

                    // is it a simple string literal?
                    if (argument.Expression is LiteralExpressionSyntax literal)
                    {
                        stringText     = literal.Token.Text;
                        exactPositions = true;

                        messageTemplate = literal.Token.ValueText;
                    }
                    else
                    {
                        // can we at least get a computed constant value for it?
                        var constantValue = context.SemanticModel.GetConstantValue(argument.Expression, context.CancellationToken);
                        if (!constantValue.HasValue || !(constantValue.Value is string constString))
                        {
                            INamedTypeSymbol StringType() => context.SemanticModel.Compilation.GetTypeByMetadataName("System.String");

                            if (context.SemanticModel.GetSymbolInfo(argument.Expression, context.CancellationToken).Symbol is IFieldSymbol field && field.Name == "Empty" && field.Type == StringType())
                            {
                                constString = "";
                            }
                            else
                            {
                                context.ReportDiagnostic(Diagnostic.Create(ConstantMessageTemplateRule, argument.Expression.GetLocation(), argument.Expression.ToString()));
                                continue;
                            }
                        }

                        // we can't map positions back from the computed string into the real positions
                        exactPositions  = false;
                        messageTemplate = constString;
                    }

                    literalSpan = argument.Expression.GetLocation().SourceSpan;

                    var messageTemplateDiagnostics = AnalyzingMessageTemplateParser.Analyze(messageTemplate);
                    foreach (var templateDiagnostic in messageTemplateDiagnostics)
                    {
                        if (templateDiagnostic is PropertyToken property)
                        {
                            properties.Add(property);
                            continue;
                        }

                        if (templateDiagnostic is MessageTemplateDiagnostic diagnostic)
                        {
                            hasErrors = true;
                            ReportDiagnostic(ref context, ref literalSpan, stringText, exactPositions, TemplateRule, diagnostic);
                        }
                    }

                    var messageTemplateArgumentIndex = invocationArguments.IndexOf(argument);
                    arguments = invocationArguments.Skip(messageTemplateArgumentIndex + 1).Select(x =>
                    {
                        var location = x.GetLocation().SourceSpan;
                        return(new SourceArgument {
                            Argument = x, StartIndex = location.Start, Length = location.Length
                        });
                    }).ToList();

                    break;
                }
            }