private void AnalyzeExpression(SyntaxNodeAnalysisContext context, ConcurrentDictionary <int, Diagnostic> reports)
        {
            var parentKind = context.Node.Parent.Kind();

            // will be handled at higher level
            if (parentKind == SyntaxKind.SimpleMemberAccessExpression || parentKind == SyntaxKind.QualifiedName)
            {
                return;
            }

            var target = GetTargetOfNode(context.Node, context.SemanticModel);

            if (target == null)
            {
                return;
            }

            var platform = Analyzer.GetPlatformForSymbol(target);

            // Some quick escapes
            if (platform.Kind == PlatformKind.Unchecked)
            {
                return;
            }

            if (platform.Kind == PlatformKind.Uwp && platform.Version == Analyzer.N2SDKVersion)
            {
                return;
            }

            // Is this expression inside a method/constructor/property that claims to be specific?
            var containingBlock = context.Node.FirstAncestorOrSelf <BlockSyntax>();

            // for constructors and methods
            MemberDeclarationSyntax containingMember = containingBlock?.FirstAncestorOrSelf <BaseMethodDeclarationSyntax>();

            if (containingBlock == null || containingBlock?.Parent is AccessorDeclarationSyntax)
            {
                containingMember = context.Node.FirstAncestorOrSelf <PropertyDeclarationSyntax>();
            }

            // Is this invocation properly guarded? See readme.md for explanations.
            if (IsProperlyGuarded(context.Node, context.SemanticModel))
            {
                return;
            }

            if (containingBlock != null)
            {
                foreach (var ret in containingBlock.DescendantNodes().OfType <ReturnStatementSyntax>())
                {
                    if (IsProperlyGuarded(ret, context.SemanticModel))
                    {
                        return;
                    }
                }
            }

            // We'll report only a single diagnostic per line, the first.
            var loc = context.Node.GetLocation();

            if (!loc.IsInSource)
            {
                return;
            }

            var line = loc.GetLineSpan().StartLinePosition.Line;

            if (reports.TryGetValue(line, out var diagnostic) && diagnostic.Location.SourceSpan.Start <= loc.SourceSpan.Start)
            {
                return;
            }

            diagnostic = Diagnostic.Create(platform.Kind == PlatformKind.Uwp ? Analyzer.VersionRule : Analyzer.PlatformRule, loc);

            reports[line] = diagnostic;

            context.ReportDiagnostic(diagnostic);
        }
        /// <summary>
        /// returns instance of <see cref="HowToGuard"/> for <see cref="ISymbol"/>
        /// </summary>
        /// <param name="target">instance of <see cref="ISymbol"/></param>
        /// <returns>instance of <see cref="HowToGuard"/></returns>
        public static HowToGuard GetGuardForSymbol(ISymbol target)
        {
            var plat = Analyzer.GetPlatformForSymbol(target);

            switch (plat.Kind)
            {
            case PlatformKind.ExtensionSDK:
                return(new HowToGuard()
                {
                    TypeToCheck = target.Kind == SymbolKind.NamedType ? target.ToDisplayString() : target.ContainingType.ToDisplayString(),
                    KindOfCheck = "IsTypePresent"
                });

            case PlatformKind.Uwp:
                if (target.Kind == SymbolKind.NamedType)
                {
                    return(new HowToGuard()
                    {
                        TypeToCheck = target.ToDisplayString(),
                        KindOfCheck = "IsTypePresent"
                    });
                }
                else
                {
                    var g = new HowToGuard
                    {
                        TypeToCheck = target.ContainingType.ToDisplayString()
                    };

                    var d0 = Analyzer.GetUniversalApiAdditions(Analyzer.N0DifferencesRes);
                    var d1 = Analyzer.GetUniversalApiAdditions(Analyzer.N1DifferencesRes);

                    if (!d0.TryGetValue(g.TypeToCheck, out List <NewMember> newMembers))
                    {
                        d1.TryGetValue(g.TypeToCheck, out newMembers);
                    }

                    if (newMembers == null)
                    {
                        throw new InvalidOperationException("oops! expected this UWP version API to be in the dictionary of new things");
                    }

                    g.MemberToCheck = target.Name;

                    if (target.Kind == SymbolKind.Field)
                    {
                        // the only fields in WinRT are enum fields
                        g.KindOfCheck = "IsEnumNamedValuePresent";
                    }
                    else if (target.Kind == SymbolKind.Event)
                    {
                        g.KindOfCheck = "IsEventPresent";
                    }
                    else if (target.Kind == SymbolKind.Property)
                    {
                        // TODO: if SDK starts introducing additional accessors on properties, we'll have to change this
                        g.KindOfCheck = "IsPropertyPresent";
                    }
                    else if (target.Kind == SymbolKind.Method)
                    {
                        g.KindOfCheck = "IsMethodPresent";

                        if (target.Kind == SymbolKind.Method && plat.ByParameterCount)
                        {
                            g.ParameterCountToCheck = (target as IMethodSymbol).Parameters.Length;
                        }
                    }

                    return(g);
                }

            default:
                throw new InvalidOperationException("oops! don't know why I was asked to check something that's fine");
            }
        }