/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package libcore.java.lang.reflect.annotations;

import junit.framework.TestCase;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated;

import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY;
import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation;
import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent;
import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods;

/**
 * Tests for the {@link java.lang.reflect.AnnotatedElement} methods from the {@link Parameter}
 * objects obtained from both {@link Constructor} and {@link Method}.
 */
public class AnnotatedElementParameterTest extends TestCase {

    private static class MethodClass {
        public void methodWithoutAnnotatedParameters(String parameter1, String parameter2) {}

        public void methodWithAnnotatedParameters(@AnnotationB @AnnotationD String parameter1,
                @AnnotationC @AnnotationD String parameter2) {}
    }

    public void testMethodParameterAnnotations() throws Exception {
        Class<?> c = MethodClass.class;
        {
            Parameter[] parameters = c.getDeclaredMethod(
                    "methodWithoutAnnotatedParameters", String.class, String.class).getParameters();
            Parameter parameter0 = parameters[0];
            checkAnnotatedElementPresentMethods(parameter0);

            Parameter parameter1 = parameters[1];
            checkAnnotatedElementPresentMethods(parameter1);
        }
        {
            Parameter[] parameters = c.getDeclaredMethod(
                    "methodWithAnnotatedParameters", String.class, String.class).getParameters();

            Parameter parameter0 = parameters[0];
            checkAnnotatedElementPresentMethods(parameter0, AnnotationB.class, AnnotationD.class);

            Parameter parameter1 = parameters[1];
            checkAnnotatedElementPresentMethods(parameter1, AnnotationC.class, AnnotationD.class);
        }
    }

    private static class ConstructorClass {
        // No annotations.
        public ConstructorClass(Integer parameter1, Integer parameter2) {}

        // Annotations.
        public ConstructorClass(@AnnotationB @AnnotationD String parameter1,
                @AnnotationC @AnnotationD String parameter2) {}
    }

    public void testConstructorParameterAnnotations() throws Exception {
        Class<?> c = ConstructorClass.class;
        {
            Parameter[] parameters =
                    c.getDeclaredConstructor(Integer.class, Integer.class).getParameters();
            Parameter parameter0 = parameters[0];
            checkAnnotatedElementPresentMethods(parameter0);

            Parameter parameter1 = parameters[1];
            checkAnnotatedElementPresentMethods(parameter1);
        }
        {
            Parameter[] parameters =
                    c.getDeclaredConstructor(String.class, String.class).getParameters();

            Parameter parameter0 = parameters[0];
            checkAnnotatedElementPresentMethods(parameter0, AnnotationB.class, AnnotationD.class);

            Parameter parameter1 = parameters[1];
            checkAnnotatedElementPresentMethods(parameter1, AnnotationC.class, AnnotationD.class);
        }
    }

    private static class AnnotatedMethodClass {
        void noAnnotation(String p0) {}

        void multipleAnnotationOddity(
                @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) String p0) {}

        void multipleAnnotationExplicitSingle(@Container({@Repeated(1)}) String p0) {}

        void multipleAnnotation(@Repeated(1) @Repeated(2) String p0) {}

        void singleAnnotation(@Repeated(1) String p0) {}

        static void staticSingleAnnotation(@Repeated(1) String p0) {}

        static Method getMethodWithoutAnnotations() throws Exception {
            return AnnotatedMethodClass.class.getDeclaredMethod("noAnnotation", String.class);
        }

        static Method getMethodMultipleAnnotationOddity() throws Exception {
            return AnnotatedMethodClass.class.getDeclaredMethod(
                    "multipleAnnotationOddity", String.class);
        }

        static Method getMethodMultipleAnnotationExplicitSingle() throws Exception {
            return AnnotatedMethodClass.class.getDeclaredMethod(
                    "multipleAnnotationExplicitSingle", String.class);
        }

        static Method getMethodMultipleAnnotation() throws Exception {
            return AnnotatedMethodClass.class.getDeclaredMethod("multipleAnnotation", String.class);
        }

        static Method getMethodSingleAnnotation() throws Exception {
            return AnnotatedMethodClass.class.getDeclaredMethod("singleAnnotation", String.class);
        }

        static Method getMethodStaticSingleAnnotation() throws Exception {
            return AnnotatedMethodClass.class.getDeclaredMethod("staticSingleAnnotation",
                    String.class);
        }
    }

    private static abstract class AnnotatedMethodAbstractClass {
        abstract void abstractSingleAnnotation(@Repeated(1) String p0);

        static Method getMethodAbstractSingleAnnotation() throws Exception {
            return AnnotatedMethodAbstractClass.class.getDeclaredMethod(
                    "abstractSingleAnnotation", String.class);
        }
    }

    // Tests for isAnnotationPresent and getDeclaredAnnotation.
    public void testMethodDeclaredAnnotation_repeated() throws Exception {
        Class<? extends Annotation> repeated = Repeated.class;
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodWithoutAnnotations(),
                repeated, null);
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
                repeated, "@Repeated(1)");
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
                repeated, null);
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodMultipleAnnotation(),
                repeated, null);
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodSingleAnnotation(),
                repeated, "@Repeated(1)");
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodStaticSingleAnnotation(),
                repeated, "@Repeated(1)");
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodAbstractClass.getMethodAbstractSingleAnnotation(),
                repeated, "@Repeated(1)");

        Class<? extends Annotation> container = Container.class;
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodWithoutAnnotations(),
                container, null);
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
                container, "@Container({@Repeated(2), @Repeated(3)})");
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
                container, "@Container({@Repeated(1)})");
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodMultipleAnnotation(),
                container, "@Container({@Repeated(1), @Repeated(2)})");
        checkParameter0DeclaredAnnotation(
                AnnotatedMethodClass.getMethodSingleAnnotation(),
                container, null);
    }

    private static class AnnotatedConstructorClass {
        public AnnotatedConstructorClass(Boolean p0) {}

        public AnnotatedConstructorClass(
                @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) Long p0) {}

        public AnnotatedConstructorClass(@Container({@Repeated(1)}) Double p0) {}

        public AnnotatedConstructorClass(@Repeated(1) @Repeated(2) Integer p0) {}

        public AnnotatedConstructorClass(@Repeated(1) String p0) {}

        static Constructor<?> getConstructorWithoutAnnotations() throws Exception {
            return AnnotatedConstructorClass.class.getDeclaredConstructor(Boolean.class);
        }

        static Constructor<?> getConstructorMultipleAnnotationOddity() throws Exception {
            return AnnotatedConstructorClass.class.getDeclaredConstructor(Long.class);
        }

        static Constructor<?> getConstructorMultipleAnnotationExplicitSingle()
                throws Exception {
            return AnnotatedConstructorClass.class.getDeclaredConstructor(Double.class);
        }

        static Constructor<?> getConstructorSingleAnnotation() throws Exception {
            return AnnotatedConstructorClass.class.getDeclaredConstructor(String.class);
        }

        static Constructor<?> getConstructorMultipleAnnotation() throws Exception {
            return AnnotatedConstructorClass.class.getDeclaredConstructor(Integer.class);
        }
    }

    // Tests for isAnnotationPresent and getDeclaredAnnotation.
    public void testConstructorDeclaredAnnotation_repeated() throws Exception {
        Class<? extends Annotation> repeated = Repeated.class;
        checkParameter0DeclaredAnnotation(
                AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
                repeated, null);
        checkParameter0DeclaredAnnotation(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
                repeated, "@Repeated(1)");
        checkParameter0DeclaredAnnotation(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
                repeated, null);
        checkParameter0DeclaredAnnotation(
                AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
                repeated, null);
        checkParameter0DeclaredAnnotation(
                AnnotatedConstructorClass.getConstructorSingleAnnotation(),
                repeated, "@Repeated(1)");

        Class<? extends Annotation> container = Container.class;
        checkParameter0DeclaredAnnotation(
                AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
                container, null);
        checkParameter0DeclaredAnnotation(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
                container, "@Container({@Repeated(2), @Repeated(3)})");
        checkParameter0DeclaredAnnotation(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
                container, "@Container({@Repeated(1)})");
        checkParameter0DeclaredAnnotation(
                AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
                container, "@Container({@Repeated(1), @Repeated(2)})");
        checkParameter0DeclaredAnnotation(
                AnnotatedConstructorClass.getConstructorSingleAnnotation(),
                container, null);
    }

    private static void checkParameter0DeclaredAnnotation(
            Executable executable, Class<? extends Annotation> annotationType,
            String expectedAnnotationString) throws Exception {
        Parameter parameter = executable.getParameters()[0];

        // isAnnotationPresent
        assertIsAnnotationPresent(parameter, annotationType, expectedAnnotationString != null);

        // getDeclaredAnnotation
        assertGetDeclaredAnnotation(parameter, annotationType, expectedAnnotationString);
    }

    public void testMethodGetDeclaredAnnotationsByType_repeated() throws Exception {
        Class<? extends Annotation> repeated = Repeated.class;
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedMethodClass.getMethodWithoutAnnotations(),
                repeated, EXPECT_EMPTY);
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
                repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
                repeated, "@Repeated(1)");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotation(),
                repeated, "@Repeated(1)", "@Repeated(2)");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedMethodClass.getMethodSingleAnnotation(),
                repeated, "@Repeated(1)");

        Class<? extends Annotation> container = Container.class;
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedMethodClass.getMethodWithoutAnnotations(),
                container, EXPECT_EMPTY);
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
                container, "@Container({@Repeated(2), @Repeated(3)})");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
                container, "@Container({@Repeated(1)})");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotation(),
                container, "@Container({@Repeated(1), @Repeated(2)})");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedMethodClass.getMethodSingleAnnotation(),
                container, EXPECT_EMPTY);
    }

    public void testConstructorGetDeclaredAnnotationsByType_repeated() throws Exception {
        Class<? extends Annotation> repeated = Repeated.class;
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
                repeated, EXPECT_EMPTY);
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
                repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
                repeated, "@Repeated(1)");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
                repeated, "@Repeated(1)", "@Repeated(2)");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedConstructorClass.getConstructorSingleAnnotation(),
                repeated, "@Repeated(1)");

        Class<? extends Annotation> container = Container.class;
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
                container, EXPECT_EMPTY);
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
                container, "@Container({@Repeated(2), @Repeated(3)})");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
                container, "@Container({@Repeated(1)})");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
                container, "@Container({@Repeated(1), @Repeated(2)})");
        checkParameter0GetDeclaredAnnotationsByType(
                AnnotatedConstructorClass.getConstructorSingleAnnotation(),
                container, EXPECT_EMPTY);
    }

    private static void checkParameter0GetDeclaredAnnotationsByType(
            Executable executable, Class<? extends Annotation> annotationType,
            String... expectedAnnotationStrings) throws Exception {
        Parameter parameter = executable.getParameters()[0];
        AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
                parameter, annotationType, expectedAnnotationStrings);
    }

    public void testMethodGetAnnotationsByType_repeated() throws Exception {
        Class<? extends Annotation> repeated = Repeated.class;
        checkParameter0GetAnnotationsByType(
                AnnotatedMethodClass.getMethodWithoutAnnotations(),
                repeated, EXPECT_EMPTY);
        checkParameter0GetAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
                repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)");
        checkParameter0GetAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
                repeated, "@Repeated(1)");
        checkParameter0GetAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotation(),
                repeated, "@Repeated(1)", "@Repeated(2)");
        checkParameter0GetAnnotationsByType(
                AnnotatedMethodClass.getMethodSingleAnnotation(),
                repeated, "@Repeated(1)");

        Class<? extends Annotation> container = Container.class;
        checkParameter0GetAnnotationsByType(
                AnnotatedMethodClass.getMethodWithoutAnnotations(),
                container, EXPECT_EMPTY);
        checkParameter0GetAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
                container, "@Container({@Repeated(2), @Repeated(3)})");
        checkParameter0GetAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
                container, "@Container({@Repeated(1)})");
        checkParameter0GetAnnotationsByType(
                AnnotatedMethodClass.getMethodMultipleAnnotation(),
                container, "@Container({@Repeated(1), @Repeated(2)})");
        checkParameter0GetAnnotationsByType(
                AnnotatedMethodClass.getMethodSingleAnnotation(),
                container, EXPECT_EMPTY);
    }

    public void testConstructorGetAnnotationsByType_repeated() throws Exception {
        Class<? extends Annotation> repeated = Repeated.class;
        checkParameter0GetAnnotationsByType(
                AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
                repeated, EXPECT_EMPTY);
        checkParameter0GetAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
                repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)");
        checkParameter0GetAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
                repeated, "@Repeated(1)");
        checkParameter0GetAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
                repeated, "@Repeated(1)", "@Repeated(2)");
        checkParameter0GetAnnotationsByType(
                AnnotatedConstructorClass.getConstructorSingleAnnotation(),
                repeated, "@Repeated(1)");

        Class<? extends Annotation> container = Container.class;
        checkParameter0GetAnnotationsByType(
                AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
                container, EXPECT_EMPTY);
        checkParameter0GetAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
                container, "@Container({@Repeated(2), @Repeated(3)})");
        checkParameter0GetAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
                container, "@Container({@Repeated(1)})");
        checkParameter0GetAnnotationsByType(
                AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
                container, "@Container({@Repeated(1), @Repeated(2)})");
        checkParameter0GetAnnotationsByType(
                AnnotatedConstructorClass.getConstructorSingleAnnotation(),
                container, EXPECT_EMPTY);
    }

    private static void checkParameter0GetAnnotationsByType(
            Executable executable, Class<? extends Annotation> annotationType,
            String... expectedAnnotationStrings) throws Exception {
        Parameter parameter = executable.getParameters()[0];
        AnnotatedElementTestSupport.assertGetAnnotationsByType(
                parameter, annotationType, expectedAnnotationStrings);
    }

    /**
     * As an inner class the constructor will actually have two parameters: the first, referencing
     * the enclosing object, is inserted by the compiler.
     */
    class InnerClass {
        InnerClass(@AnnotationA String p1) {}
    }

    /** Special case testing for a compiler-generated constructor parameter. JLS 8.8.1, JLS 13.1. */
    public void testImplicitConstructorParameters_innerClass() throws Exception {
        Constructor<InnerClass> constructor =
                InnerClass.class.getDeclaredConstructor(
                        AnnotatedElementParameterTest.class, String.class);
        Parameter[] parameters = constructor.getParameters();

        // The parameter annotation code behaves as if there are two parameters.

        // The compiler-generated constructor should have no annotations.
        Parameter parameter0 = parameters[0];
        AnnotatedElementTestSupport.assertGetAnnotationsByType(
                parameter0, AnnotationA.class, new String[0]);
        AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
                parameter0, AnnotationA.class, new String[0]);
        AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
                parameter0, AnnotationA.class, null);
        AnnotatedElementTestSupport.assertIsAnnotationPresent(parameter0, AnnotationA.class, false);

        // The annotation should remain on the correct parameter.
        Parameter parameter1 = parameters[1];
        AnnotatedElementTestSupport.assertGetAnnotationsByType(
                parameter1, AnnotationA.class, new String[] {"@AnnotationA"});
        AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
                parameter1, AnnotationA.class, new String[] {"@AnnotationA"});
        AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
                parameter1, AnnotationA.class, "@AnnotationA");
        AnnotatedElementTestSupport.assertIsAnnotationPresent(
                parameter1, AnnotationA.class, true);
    }

    static abstract class AnonymousBaseClass {
        public AnonymousBaseClass(@AnnotationA String p1) {}
    }

    /** Special case testing for a compiler-generated constructor parameter. JLS 13.1 */
    public void testImplicitConstructorParameters_anonymousClass() throws Exception {
        /*
         * As an anonymous class the constructor will actually have two parameters: the first,
         * referencing the enclosing object, is inserted by the compiler.
         */
        AnonymousBaseClass anonymousClassInstance = new AnonymousBaseClass("p1") {};

        Constructor<? extends AnonymousBaseClass> constructor =
                anonymousClassInstance.getClass().getDeclaredConstructor(
                        AnnotatedElementParameterTest.class, String.class);
        Parameter[] parameters = constructor.getParameters();
        assertEquals(2, parameters.length);

        // The parameter annotation code behaves as if there are two parameters.

        // This is the synthetic parameter.
        Parameter parameter0 = parameters[0];
        AnnotatedElementTestSupport.assertGetAnnotationsByType(
                parameter0, AnnotationA.class, new String[0]);
        AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
                parameter0, AnnotationA.class, new String[0]);
        AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
                parameter0, AnnotationA.class, null);
        AnnotatedElementTestSupport.assertIsAnnotationPresent(parameter0, AnnotationA.class, false);

        // There's no annotation since we cannot annotate the parameter on the anonymous class.
        Parameter parameter1 = parameters[1];
        AnnotatedElementTestSupport.assertGetAnnotationsByType(
                parameter1, AnnotationA.class, new String[0]);
        AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
                parameter1, AnnotationA.class, new String[0]);
        AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
                parameter1, AnnotationA.class, null);
        AnnotatedElementTestSupport.assertIsAnnotationPresent(parameter1, AnnotationA.class, false);
    }

    /**
     * A static inner / nested member class will not have synthetic parameters and should behave
     * like a top-level class.
     */
    static class StaticInnerClass {
        StaticInnerClass(@AnnotationA String p1) {}
    }

    /** Special case testing for a compiler-generated constructor parameter. */
    public void testImplicitConstructorParameters_staticInnerClass() throws Exception {
        Constructor<StaticInnerClass> constructor =
                StaticInnerClass.class.getDeclaredConstructor(String.class);
        Parameter[] parameters = constructor.getParameters();
        assertEquals(1, parameters.length);

        Parameter parameter0 = parameters[0];
        AnnotatedElementTestSupport.assertGetAnnotationsByType(
                parameter0, AnnotationA.class, new String[] {"@AnnotationA"});
        AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
                parameter0, AnnotationA.class, new String[] {"@AnnotationA"});
        AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
                parameter0, AnnotationA.class, "@AnnotationA");
        AnnotatedElementTestSupport.assertIsAnnotationPresent(
                parameter0, AnnotationA.class, true);
    }
}
