public void When_deriving_constructed_arrays_from_externally_annotated_interface_with_open_array_types_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    public interface I<T>
                    {
                        T[] P { get; }
                        T[] M(T[] p, int i);
                    }
                    public class C : I<string>
                    {
                        public string[] P { get { throw new NotImplementedException(); } }
                        public string[] M(string[] p, int i) { throw new NotImplementedException(); }
                    }
                ")
                .ExternallyAnnotated(new ExternalAnnotationsBuilder()
                    .IncludingMember(new ExternalAnnotationFragmentBuilder()
                        .Named("P:I`1.P")
                        .NotNull())
                    .IncludingMember(new ExternalAnnotationFragmentBuilder()
                        .Named("M:I`1.M(`0[],System.Int32)")
                        .NotNull()
                        .WithParameter(new ExternalAnnotationParameterBuilder()
                            .Named("p")
                            .NotNull())))
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_base_property_inherits_item_annotation_from_interface_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .Using(typeof (IEnumerable).Namespace)
                .InGlobalScope(@"
                    namespace N
                    {
                        public interface I
                        {
                            [ItemNotNull]
                            IEnumerable P { get; set; }
                        }

                        public class B : I
                        {
                            public virtual IEnumerable P { get; set; }
                        }

                        public class C : B
                        {
                            public override IEnumerable P { get; set; }
                        }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_base_parameter_inherits_annotation_from_interface_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    namespace N
                    {
                        public interface I
                        {
                            void M([NotNull] string p);
                        }

                        public class B : I
                        {
                            public virtual void M(string p) { }
                        }

                        public class C : B
                        {
                            public override void M(string p) { }
                        }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_indexer_parameter_in_base_class_is_annotated_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .Using(typeof (IEnumerable<>).Namespace)
                .InGlobalScope(@"
                    abstract class B
                    {
                        public abstract int this[[ItemNotNull] IEnumerable<string> p] { get; set; }
                    }

                    abstract class D1 : B { }

                    class D2 : D1
                    {
                        // implicitly inherits decoration from base class
                        public override int this[IEnumerable<string> p]
                        {
                            get { throw new NotImplementedException(); }
                            set { throw new NotImplementedException(); }
                        }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_field_in_nested_class_is_externally_annotated_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    namespace TestSystem
                    {
                        public class Outer
                        {
                            private class Inner
                            {
                                public int? Value;
                            }
                        }
                    }
                ")
                .ExternallyAnnotated(new ExternalAnnotationsBuilder()
                    .IncludingMember(new ExternalAnnotationFragmentBuilder()
                        .Named("F:TestSystem.Outer.Inner.Value")
                        .CanBeNull()))
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_attributes_are_internal_in_external_assembly_they_must_not_be_found()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithoutNullabilityAttributes()
                .WithReferenceToExternalAssemblyFor(@"
                    using System;

                    namespace OtherAssembly
                    {
                        internal class NotNullAttribute : Attribute { }
                        internal class CanBeNullAttribute : Attribute { }
                        internal class ItemNotNullAttribute : Attribute { }
                        internal class ItemCanBeNullAttribute : Attribute { }
                    }")
                .InGlobalScope(@"
                    class C
                    {
                        int? f;
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_base_method_inherits_annotation_from_interface_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    namespace N
                    {
                        public interface I
                        {
                            [NotNull]
                            string M();
                        }

                        public class B : I
                        {
                            public virtual string M() { throw new NotImplementedException(); }
                        }

                        public class C : B
                        {
                            public override string M() { throw new NotImplementedException(); }
                        }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_method_is_anonymous_named_by_compiler_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .Using(typeof (IEnumerable<>).Namespace)
                .InGlobalScope(@"
                    class C1
                    {
                        private void Test()
                        {
                            C2.M(delegate       // no syntax exists to decorate this anonymous method
                            {
                                throw new NotImplementedException();
                            });
                        }
                    }
                    public class C2
                    {
                        public static void M([ItemNotNull] Func<IEnumerable<int?>> callback)
                        {
                        }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_field_is_annotated_with_not_nullable_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithNullabilityAttributes(new NullabilityAttributesBuilder()
                    .InCodeNamespace("N.M"))
                .InGlobalScope(@"
                    class C
                    {
                        [N.M.NotNull] // Using fully qualified namespace
                        string f;
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_attributes_are_in_different_namespace_it_must_add_namespace_import()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithNullabilityAttributes(new NullabilityAttributesBuilder()
                    .InCodeNamespace("NA"))
                .InGlobalScope(@"
                    class C
                    {
                        <annotate/> int? [|f|];
                    }
                ")
                .ExpectingImportForNamespace("NA")
                .Build();

            // Act and assert
            VerifyNullabilityFix(source);
        }
        public void When_generic_parameters_in_generic_method_in_generic_nested_classes_are_externally_annotated_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .Using(typeof (KeyValuePair<,>).Namespace)
                .InGlobalScope(@"
                    namespace TestSystem
                    {
                        public class OuterClass<TOuter1, TOuter2>
                        {
                            public class InnerClass<TInner>
                            {
                                public TMethod1 TestMethod<TMethod1, TMethod2>(TOuter2 testOuter2,
                                    TInner testInner, TMethod2 testMethod2, KeyValuePair<TMethod1, TOuter1> pair)
                                {
                                    throw new NotImplementedException();
                                }
                            }
                        }
                    }
                ")
                .ExternallyAnnotated(new ExternalAnnotationsBuilder()
                    .IncludingMember(new ExternalAnnotationFragmentBuilder()
                        .Named(
                            "M:TestSystem.OuterClass`2.InnerClass`1.TestMethod``2(`1,`2,``1,System.Collections.Generic.KeyValuePair{``0,`0})")
                        .CanBeNull()
                        .WithParameter(new ExternalAnnotationParameterBuilder()
                            .Named("testOuter2")
                            .CanBeNull())
                        .WithParameter(new ExternalAnnotationParameterBuilder()
                            .Named("testInner")
                            .CanBeNull())
                        .WithParameter(new ExternalAnnotationParameterBuilder()
                            .Named("testMethod2")
                            .CanBeNull())
                        .WithParameter(new ExternalAnnotationParameterBuilder()
                            .Named("pair")
                            .CanBeNull())))
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_attributes_are_in_global_namespace_they_must_be_found()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithNullabilityAttributes(new NullabilityAttributesBuilder()
                    .InGlobalNamespace())
                .InGlobalScope(@"
                    namespace N
                    {
                        class C
                        {
                            <annotate/> int? [|f|];
                        }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityFix(source);
        }
        public void When_containing_type_is_decorated_with_conditional_its_members_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithReference(typeof (ConditionalAttribute).Assembly)
                .Using(typeof (ConditionalAttribute).Namespace)
                .InGlobalScope(@"
                    namespace N
                    {
                        [Conditional(""JETBRAINS_ANNOTATIONS"")]
                        class C : Attribute
                        {
                            string M() { throw new NotImplementedException(); }
                        }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_field_is_annotated_with_item_nullable_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithNullabilityAttributes(new NullabilityAttributesBuilder()
                    .InCodeNamespace("N1"))
                .Using(typeof (IEnumerable<>).Namespace)
                .InGlobalScope(@"
                    namespace N2
                    {
                        using ICBN = N1.ItemCanBeNullAttribute;

                        class C
                        {
                            [ICBN()] // Using type/namespace alias
                            IEnumerable<string> f;
                        }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_indexer_property_type_in_implicit_interface_is_not_annotated_it_must_be_reported_and_fixed()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .Using(typeof (IEnumerable<>).Namespace)
                .InGlobalScope(@"
                    namespace N
                    {
                        interface I
                        {
                            [ItemCanBeNull]
                            IEnumerable<int?> this[char p] { get; set; }
                        }

                        class C : I
                        {
                            // implicitly inherits decoration from interface
                            IEnumerable<int?> I.this[char p]
                            {
                                get { throw new NotImplementedException(); }
                                set { throw new NotImplementedException(); }
                            }

                            <annotate/> public IEnumerable<int?> [|this|][char p]
                            {
                                get { throw new NotImplementedException(); }
                                set { throw new NotImplementedException(); }
                            }
                        }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityFix(source);
        }
        public void When_attributes_are_public_nested_they_must_be_found()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithNullabilityAttributes(new NullabilityAttributesBuilder()
                    .NestedInTypes(new[]
                    {
                        "public class X",
                        "public class Nested"
                    }))
                .InGlobalScope(@"
                    class C
                    {
                        <annotate/> int? [|f|];
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityFix(source);
        }
        public void When_attributes_are_public_nested_in_private_class_they_must_not_be_found()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithNullabilityAttributes(new NullabilityAttributesBuilder()
                    .NestedInTypes(new[]
                    {
                        "public class X",
                        "private class Nested"
                    }))
                .InGlobalScope(@"
                    class C
                    {
                        int? f;
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_attributes_are_public_in_external_assembly_it_must_add_namespace_import()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithoutNullabilityAttributes()
                .WithReferenceToExternalAssemblyFor(@"
                    using System;

                    namespace OtherAssembly
                    {
                        public class NotNullAttribute : Attribute { }
                        public class CanBeNullAttribute : Attribute { }
                        public class ItemNotNullAttribute : Attribute { }
                        public class ItemCanBeNullAttribute : Attribute { }
                    }")
                .InGlobalScope(@"
                    class C
                    {
                        <annotate/> int? [|f|];
                    }
                ")
                .ExpectingImportForNamespace("OtherAssembly")
                .Build();

            // Act and assert
            VerifyNullabilityFix(source);
        }
        public void When_attributes_are_not_defined_it_must_not_report_any_diagnostics()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithoutNullabilityAttributes()
                .InGlobalScope(@"
                    class C
                    {
                        int? f;
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_return_value_type_is_generic_value_type_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    class C<T> where T : struct
                    {
                        T M() { throw new NotImplementedException(); }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_return_value_in_base_class_is_annotated_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    class B
                    {
                        [NotNull]
                        public virtual string M() { throw new NotImplementedException(); }
                    }

                    class D1 : B { }

                    class D2 : D1
                    {
                        // implicitly inherits decoration from base class
                        public override string M() { throw new NotImplementedException(); }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_return_value_is_externally_annotated_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    namespace N
                    {
                        class C
                        {
                            string M() { throw new NotImplementedException(); }
                        }
                    }
                ")
                .ExternallyAnnotated(new ExternalAnnotationsBuilder()
                    .IncludingMember(new ExternalAnnotationFragmentBuilder()
                        .Named("M:N.C.M")
                        .NotNull()))
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_return_value_is_annotated_with_nullable_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    class C
                    {
                        [CanBeNull]
                        string M() { throw new NotImplementedException(); }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_return_value_in_implicit_interface_is_annotated_with_explicit_interface_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    interface I
                    {
                        [NotNull]
                        string M();
                    }

                    class C : I
                    {
                        // implicitly inherits decoration from interface
                        string I.M() { throw new NotImplementedException(); }

                        // requires explicit decoration
                        [NotNull]
                        public string M() { throw new NotImplementedException(); }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_return_value_in_base_class_is_externally_annotated_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    namespace N
                    {
                        class B
                        {
                            public virtual string M() { throw new NotImplementedException(); }
                        }

                        class D1 : B { }

                        class D2 : D1
                        {
                            // implicitly inherits decoration from base class
                            public override string M() { throw new NotImplementedException(); }
                        }
                    }
                ")
                .ExternallyAnnotated(new ExternalAnnotationsBuilder()
                    .IncludingMember(new ExternalAnnotationFragmentBuilder()
                        .Named("M:N.B.M")
                        .NotNull()))
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_some_attributes_are_private_none_must_be_found()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithoutNullabilityAttributes()
                .InGlobalScope(@"
                    class C
                    {
                        int? f;
                    }

                    public class X
                    {
                        internal class NotNullAttribute : Attribute { }
                        private class CanBeNullAttribute : Attribute { }
                        internal class ItemNotNullAttribute : Attribute { }
                        private class ItemCanBeNullAttribute : Attribute { }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_return_value_in_implicit_interface_is_annotated_with_externally_annotated_explicit_interface_it_must_be_skipped()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    namespace N
                    {
                        interface I
                        {
                            string M();
                        }

                        class C : I
                        {
                            // implicitly inherits decoration from interface
                            string I.M() { throw new NotImplementedException(); }

                            // requires explicit decoration
                            [NotNull]
                            public string M() { throw new NotImplementedException(); }
                        }
                    }
                ")
                .ExternallyAnnotated(new ExternalAnnotationsBuilder()
                    .IncludingMember(new ExternalAnnotationFragmentBuilder()
                        .Named("M:N.I.M")
                        .CanBeNull()))
                .Build();

            // Act and assert
            VerifyNullabilityDiagnostic(source);
        }
        public void When_return_value_type_is_generic_nullable_it_must_be_reported_and_fixed()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    class C<T> where T : struct
                    {
                        <annotate/> T? [|M|]() { throw new NotImplementedException(); }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityFix(source);
        }
        public void When_attributes_are_in_JetBrains_assembly_it_must_add_namespace_import()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .WithoutNullabilityAttributes()
                .WithReference(typeof (JetBrainsNotNullAttribute).Assembly)
                .InGlobalScope(@"
                    class C
                    {
                        <annotate/> int? [|f|];
                    }
                ")
                .ExpectingImportForNamespace("JetBrains.Annotations")
                .Build();

            // Act and assert
            VerifyNullabilityFix(source);
        }
        public void When_return_value_in_implicit_interface_is_not_annotated_with_explicit_interface_it_must_be_reported_and_fixed()
        {
            // Arrange
            ParsedSourceCode source = new ClassSourceCodeBuilder()
                .InGlobalScope(@"
                    interface I
                    {
                        [NotNull]
                        string M();
                    }

                    class C : I
                    {
                        // implicitly inherits decoration from interface
                        string I.M() { throw new NotImplementedException(); }

                        <annotate/> public string [|M|]() { throw new NotImplementedException(); }
                    }
                ")
                .Build();

            // Act and assert
            VerifyNullabilityFix(source);
        }