diff options
author | 2018-03-05 19:02:39 +0000 | |
---|---|---|
committer | 2018-03-05 19:02:39 +0000 | |
commit | f46f46cf5bd32788d5252b7107628a66594a5e98 (patch) | |
tree | e63323329298a7cc67799324a6edc2378cfb6822 | |
parent | 4927ba0f5011b7394e52dca2c3cec52f265f8529 (diff) | |
parent | 58143d2c47734c46c1fa4855cb603c24f2d15454 (diff) |
Merge "ART: Fixes for constructor parameter annotations"
-rw-r--r-- | runtime/art_method-inl.h | 5 | ||||
-rw-r--r-- | runtime/art_method.h | 2 | ||||
-rw-r--r-- | runtime/dex/dex_file_annotations.cc | 19 | ||||
-rw-r--r-- | runtime/dex/dex_file_annotations.h | 2 | ||||
-rw-r--r-- | runtime/mirror/class.h | 5 | ||||
-rw-r--r-- | runtime/native/java_lang_reflect_Executable.cc | 70 | ||||
-rw-r--r-- | runtime/native/java_lang_reflect_Parameter.cc | 41 | ||||
-rw-r--r-- | test/715-clinit-implicit-parameter-annotations/build | 24 | ||||
-rw-r--r-- | test/715-clinit-implicit-parameter-annotations/expected.txt | 113 | ||||
-rw-r--r-- | test/715-clinit-implicit-parameter-annotations/info.txt | 5 | ||||
-rw-r--r-- | test/715-clinit-implicit-parameter-annotations/src/Main.java | 215 | ||||
-rwxr-xr-x | test/etc/default-build | 2 |
12 files changed, 497 insertions, 6 deletions
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 145eb67aa9..92769942c0 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -295,6 +295,11 @@ inline const DexFile::ClassDef& ArtMethod::GetClassDef() { return GetDexFile()->GetClassDef(GetClassDefIndex()); } +inline size_t ArtMethod::GetNumberOfParameters() { + constexpr size_t return_type_count = 1u; + return strlen(GetShorty()) - return_type_count; +} + inline const char* ArtMethod::GetReturnTypeDescriptor() { DCHECK(!IsProxyMethod()); const DexFile* dex_file = GetDexFile(); diff --git a/runtime/art_method.h b/runtime/art_method.h index 013856f3fe..5d9b729847 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -602,6 +602,8 @@ class ArtMethod FINAL { const DexFile::ClassDef& GetClassDef() REQUIRES_SHARED(Locks::mutator_lock_); + ALWAYS_INLINE size_t GetNumberOfParameters() REQUIRES_SHARED(Locks::mutator_lock_); + const char* GetReturnTypeDescriptor() REQUIRES_SHARED(Locks::mutator_lock_); ALWAYS_INLINE Primitive::Type GetReturnTypePrimitive() REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc index 3431bb7efb..6f3354b724 100644 --- a/runtime/dex/dex_file_annotations.cc +++ b/runtime/dex/dex_file_annotations.cc @@ -1121,6 +1121,21 @@ mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method) return ProcessAnnotationSetRefList(ClassData(method), set_ref_list, size); } +uint32_t GetNumberOfAnnotatedMethodParameters(ArtMethod* method) { + const DexFile* dex_file = method->GetDexFile(); + const DexFile::ParameterAnnotationsItem* parameter_annotations = + FindAnnotationsItemForMethod(method); + if (parameter_annotations == nullptr) { + return 0u; + } + const DexFile::AnnotationSetRefList* set_ref_list = + dex_file->GetParameterAnnotationSetRefList(parameter_annotations); + if (set_ref_list == nullptr) { + return 0u; + } + return set_ref_list->size_; +} + mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method, uint32_t parameter_idx, Handle<mirror::Class> annotation_class) { @@ -1141,7 +1156,9 @@ mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method, const DexFile::AnnotationSetRefItem* annotation_set_ref = &set_ref_list->list_[parameter_idx]; const DexFile::AnnotationSetItem* annotation_set = dex_file->GetSetRefItemItem(annotation_set_ref); - + if (annotation_set == nullptr) { + return nullptr; + } return GetAnnotationObjectFromAnnotationSet(ClassData(method), annotation_set, DexFile::kDexVisibilityRuntime, diff --git a/runtime/dex/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h index d7ebf84b1c..4bb0d75a57 100644 --- a/runtime/dex/dex_file_annotations.h +++ b/runtime/dex/dex_file_annotations.h @@ -55,6 +55,8 @@ mirror::ObjectArray<mirror::Class>* GetExceptionTypesForMethod(ArtMethod* method REQUIRES_SHARED(Locks::mutator_lock_); mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); +uint32_t GetNumberOfAnnotatedMethodParameters(ArtMethod* method) + REQUIRES_SHARED(Locks::mutator_lock_); mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method, uint32_t parameter_idx, Handle<mirror::Class> annotation_class) diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index a1d0ff7374..6000317c85 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -186,6 +186,11 @@ class MANAGED Class FINAL : public Object { void SetAccessFlags(uint32_t new_access_flags) REQUIRES_SHARED(Locks::mutator_lock_); + // Returns true if the class is an enum. + ALWAYS_INLINE bool IsEnum() REQUIRES_SHARED(Locks::mutator_lock_) { + return (GetAccessFlags() & kAccEnum) != 0; + } + // Returns true if the class is an interface. ALWAYS_INLINE bool IsInterface() REQUIRES_SHARED(Locks::mutator_lock_) { return (GetAccessFlags() & kAccInterface) != 0; diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc index a5e70affa5..b129c66759 100644 --- a/runtime/native/java_lang_reflect_Executable.cc +++ b/runtime/native/java_lang_reflect_Executable.cc @@ -70,7 +70,6 @@ static jobjectArray Executable_getSignatureAnnotation(JNIEnv* env, jobject javaM if (method->GetDeclaringClass()->IsProxyClass()) { return nullptr; } - StackHandleScope<1> hs(soa.Self()); return soa.AddLocalReference<jobjectArray>(annotations::GetSignatureAnnotationForMethod(method)); } @@ -80,9 +79,76 @@ static jobjectArray Executable_getParameterAnnotationsNative(JNIEnv* env, jobjec ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); if (method->IsProxyMethod()) { return nullptr; + } + + StackHandleScope<4> hs(soa.Self()); + Handle<mirror::ObjectArray<mirror::Object>> annotations = + hs.NewHandle(annotations::GetParameterAnnotations(method)); + if (annotations.IsNull()) { + return nullptr; + } + + // If the method is not a constructor, or has parameter annotations + // for each parameter, then we can return those annotations + // unmodified. Otherwise, we need to look at whether the + // constructor has implicit parameters as these may need padding + // with empty parameter annotations. + if (!method->IsConstructor() || + annotations->GetLength() == static_cast<int>(method->GetNumberOfParameters())) { + return soa.AddLocalReference<jobjectArray>(annotations.Get()); + } + + // If declaring class is a local or an enum, do not pad parameter + // annotations, as the implicit constructor parameters are an implementation + // detail rather than required by JLS. + Handle<mirror::Class> declaring_class = hs.NewHandle(method->GetDeclaringClass()); + if (annotations::GetEnclosingMethod(declaring_class) != nullptr || + declaring_class->IsEnum()) { + return soa.AddLocalReference<jobjectArray>(annotations.Get()); + } + + // Prepare to resize the annotations so there is 1:1 correspondence + // with the constructor parameters. + Handle<mirror::ObjectArray<mirror::Object>> resized_annotations = hs.NewHandle( + mirror::ObjectArray<mirror::Object>::Alloc( + soa.Self(), + annotations->GetClass(), + static_cast<int>(method->GetNumberOfParameters()))); + if (resized_annotations.IsNull()) { + DCHECK(soa.Self()->IsExceptionPending()); + return nullptr; + } + + static constexpr bool kTransactionActive = false; + const int32_t offset = resized_annotations->GetLength() - annotations->GetLength(); + if (offset > 0) { + // Workaround for dexers (d8/dx) that do not insert annotations + // for implicit parameters (b/68033708). + ObjPtr<mirror::Class> annotation_array_class = + soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array); + Handle<mirror::ObjectArray<mirror::Object>> empty_annotations = hs.NewHandle( + mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0)); + if (empty_annotations.IsNull()) { + DCHECK(soa.Self()->IsExceptionPending()); + return nullptr; + } + for (int i = 0; i < offset; ++i) { + resized_annotations->SetWithoutChecks<kTransactionActive>(i, empty_annotations.Get()); + } + for (int i = 0; i < annotations->GetLength(); ++i) { + ObjPtr<mirror::Object> annotation = annotations->GetWithoutChecks(i); + resized_annotations->SetWithoutChecks<kTransactionActive>(i + offset, annotation); + } } else { - return soa.AddLocalReference<jobjectArray>(annotations::GetParameterAnnotations(method)); + // Workaround for Jack (defunct) erroneously inserting annotations + // for local classes (b/68033708). + DCHECK_LT(offset, 0); + for (int i = 0; i < resized_annotations->GetLength(); ++i) { + ObjPtr<mirror::Object> annotation = annotations->GetWithoutChecks(i - offset); + resized_annotations->SetWithoutChecks<kTransactionActive>(i, annotation); + } } + return soa.AddLocalReference<jobjectArray>(resized_annotations.Get()); } static jobjectArray Executable_getParameters0(JNIEnv* env, jobject javaMethod) { diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc index 0b3015bda8..1ab91098d7 100644 --- a/runtime/native/java_lang_reflect_Parameter.cc +++ b/runtime/native/java_lang_reflect_Parameter.cc @@ -58,6 +58,40 @@ static jobject Parameter_getAnnotationNative(JNIEnv* env, return nullptr; } + uint32_t annotated_parameter_count = annotations::GetNumberOfAnnotatedMethodParameters(method); + if (annotated_parameter_count == 0u) { + return nullptr; + } + + // For constructors with implicit arguments, we may need to adjust + // annotation positions based on whether the implicit parameters are + // expected to known and not just a compiler implementation detail. + if (method->IsConstructor()) { + StackHandleScope<1> hs(soa.Self()); + // If declaring class is a local or an enum, do not pad parameter + // annotations, as the implicit constructor parameters are an + // implementation detail rather than required by JLS. + Handle<mirror::Class> declaring_class = hs.NewHandle(method->GetDeclaringClass()); + if (annotations::GetEnclosingMethod(declaring_class) == nullptr && !declaring_class->IsEnum()) { + // Adjust the parameter index if the number of annotations does + // not match the number of parameters. + if (annotated_parameter_count <= parameter_count) { + // Workaround for dexer not inserting annotation state for implicit parameters (b/68033708). + uint32_t skip_count = parameter_count - annotated_parameter_count; + DCHECK_GE(2u, skip_count); + if (parameterIndex < static_cast<jint>(skip_count)) { + return nullptr; + } + parameterIndex -= skip_count; + } else { + // Workaround for Jack erroneously inserting implicit parameter for local classes + // (b/68033708). + DCHECK_EQ(1u, annotated_parameter_count - parameter_count); + parameterIndex += static_cast<jint>(annotated_parameter_count - parameter_count); + } + } + } + StackHandleScope<1> hs(soa.Self()); Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType))); return soa.AddLocalReference<jobject>( @@ -65,9 +99,10 @@ static jobject Parameter_getAnnotationNative(JNIEnv* env, } static JNINativeMethod gMethods[] = { - FAST_NATIVE_METHOD(Parameter, - getAnnotationNative, - "(Ljava/lang/reflect/Executable;ILjava/lang/Class;)Ljava/lang/annotation/Annotation;"), + FAST_NATIVE_METHOD( + Parameter, + getAnnotationNative, + "(Ljava/lang/reflect/Executable;ILjava/lang/Class;)Ljava/lang/annotation/Annotation;"), }; void register_java_lang_reflect_Parameter(JNIEnv* env) { diff --git a/test/715-clinit-implicit-parameter-annotations/build b/test/715-clinit-implicit-parameter-annotations/build new file mode 100644 index 0000000000..4753c8c7dc --- /dev/null +++ b/test/715-clinit-implicit-parameter-annotations/build @@ -0,0 +1,24 @@ +#!/bin/bash +# +# Copyright 2018 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. + +# Make us exit on a failure +set -e + +# Always use D8 as DX does not support propagating parameter name and +# access_flag information. +export USE_D8=true + +./default-build "$@" --experimental parameter-annotations diff --git a/test/715-clinit-implicit-parameter-annotations/expected.txt b/test/715-clinit-implicit-parameter-annotations/expected.txt new file mode 100644 index 0000000000..357eb6253e --- /dev/null +++ b/test/715-clinit-implicit-parameter-annotations/expected.txt @@ -0,0 +1,113 @@ +Main + public Main() +Main$1LocalClassStaticContext + Main$1LocalClassStaticContext(int) + Parameter [0]: Indexed : @Main$AnnotationA() + Array : @Main$AnnotationA() + Main$AnnotationA Yes + @Main$AnnotationA() + Main$AnnotationB No +Main$1LocalClassStaticContextWithCapture + Main$1LocalClassStaticContextWithCapture(java.lang.String,long) + Parameter [0]: Indexed : @Main$AnnotationA() + Array : @Main$AnnotationA() + Main$AnnotationA Yes + @Main$AnnotationA() + Main$AnnotationB No +Main$1LocalClassStaticContextWithCaptureAlternateOrdering + Main$1LocalClassStaticContextWithCaptureAlternateOrdering(java.lang.String,long) + Parameter [0]: Indexed : @Main$AnnotationA() + Array : @Main$AnnotationA() + Main$AnnotationA Yes + @Main$AnnotationA() + Main$AnnotationB No +Main$1LocalClass + Main$1LocalClass(Main,int) + Parameter [0]: Indexed : @Main$AnnotationA() + Array : @Main$AnnotationA() + Main$AnnotationA Yes + @Main$AnnotationA() + Main$AnnotationB No +Main$1LocalClassWithCapture + Main$1LocalClassWithCapture(Main,java.lang.String,long) + Parameter [0]: Indexed : @Main$AnnotationA() + Array : @Main$AnnotationA() + Main$AnnotationA Yes + @Main$AnnotationA() + Main$AnnotationB No +Main$Inner + Main$Inner(Main,int,java.lang.String) + Parameter [0]: Main$AnnotationA No + Main$AnnotationB No + Parameter [1]: Indexed : @Main$AnnotationA() + Array : @Main$AnnotationA() + Main$AnnotationA Yes + @Main$AnnotationA() + Main$AnnotationB No + Parameter [2]: Main$AnnotationA No + Main$AnnotationB No + Main$Inner(Main,int,java.lang.String,boolean) + Parameter [0]: Main$AnnotationA No + Main$AnnotationB No + Parameter [1]: Indexed : @Main$AnnotationA() + Array : @Main$AnnotationA() + Main$AnnotationA Yes + @Main$AnnotationA() + Main$AnnotationB No + Parameter [2]: Main$AnnotationA No + Main$AnnotationB No + Parameter [3]: Indexed : @Main$AnnotationB(value=x) + Array : @Main$AnnotationB(value=x) + Main$AnnotationA No + Main$AnnotationB Yes + @Main$AnnotationB(value=x) +Main$StaticInner + Main$StaticInner(int,java.lang.String) + Parameter [0]: Indexed : @Main$AnnotationA() + Array : @Main$AnnotationA() + Main$AnnotationA Yes + @Main$AnnotationA() + Main$AnnotationB No + Parameter [1]: Main$AnnotationA No + Main$AnnotationB No + Main$StaticInner(int,java.lang.String,boolean) + Parameter [0]: Indexed : @Main$AnnotationB(value=foo) + Array : @Main$AnnotationB(value=foo) + Main$AnnotationA No + Main$AnnotationB Yes + @Main$AnnotationB(value=foo) + Parameter [1]: Main$AnnotationA No + Main$AnnotationB No + Parameter [2]: Indexed : @Main$AnnotationA() + Array : @Main$AnnotationA() + Main$AnnotationA Yes + @Main$AnnotationA() + Main$AnnotationB No +Main$ImportantNumber + private Main$ImportantNumber(java.lang.String,int,double) + Parameter [0]: Indexed : @Main$AnnotationA() + Array : @Main$AnnotationA() + Main$AnnotationA Yes + @Main$AnnotationA() + Main$AnnotationB No + private Main$ImportantNumber(java.lang.String,int,double,boolean) + Parameter [0]: Indexed : @Main$AnnotationB(value=x) + Array : @Main$AnnotationB(value=x) + Main$AnnotationA No + Main$AnnotationB Yes + @Main$AnnotationB(value=x) + Parameter [1]: Indexed : @Main$AnnotationB(value=y) + Array : @Main$AnnotationB(value=y) + Main$AnnotationA No + Main$AnnotationB Yes + @Main$AnnotationB(value=y) +Main$BinaryNumber + private Main$BinaryNumber(java.lang.String,int) + Parameter [0]: Main$AnnotationA No + Main$AnnotationB No + Parameter [1]: Main$AnnotationA No + Main$AnnotationB No +Main$1 + Main$1(java.lang.String) + Parameter [0]: Main$AnnotationA No + Main$AnnotationB No diff --git a/test/715-clinit-implicit-parameter-annotations/info.txt b/test/715-clinit-implicit-parameter-annotations/info.txt new file mode 100644 index 0000000000..31afd62f27 --- /dev/null +++ b/test/715-clinit-implicit-parameter-annotations/info.txt @@ -0,0 +1,5 @@ +Tests ART synthesizes parameter annotations for implicit parameters on +constructors. Inner class and enum constructors may have implicit +parameters. If the constructor has parameter annotations, the implicit +parameters may not have annotations in the DEX file, but code that +looks at these annotations will expect them to. diff --git a/test/715-clinit-implicit-parameter-annotations/src/Main.java b/test/715-clinit-implicit-parameter-annotations/src/Main.java new file mode 100644 index 0000000000..351e3a94b3 --- /dev/null +++ b/test/715-clinit-implicit-parameter-annotations/src/Main.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2018 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. + */ + +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Constructor; +import java.lang.reflect.Parameter; + +public class Main { + // A simple parameter annotation + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationA {} + + // A parameter annotation with additional state + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationB { + String value() default "default-value"; + } + + // An inner class whose constructors with have an implicit + // argument for the enclosing instance. + public class Inner { + private final int number; + private final String text; + boolean flag; + + Inner(@AnnotationA int number, String text) { + this.number = number; + this.text = text; + this.flag = false; + } + + Inner(@AnnotationA int number, String text, @AnnotationB("x") boolean flag) { + this.number = number; + this.text = text; + this.flag = flag; + } + } + + // An inner class whose constructors with have no implicit + // arguments for the enclosing instance. + public static class StaticInner { + private final int number; + private final String text; + boolean flag; + + StaticInner(@AnnotationA int number, String text) { + this.number = number; + this.text = text; + this.flag = false; + } + + StaticInner(@AnnotationB("foo") int number, String text, @AnnotationA boolean flag) { + this.number = number; + this.text = text; + this.flag = flag; + } + } + + public enum ImportantNumber { + ONE(1.0), + TWO(2.0), + MANY(3.0, true); + + private double doubleValue; + private boolean isLarge; + + ImportantNumber(@AnnotationA double doubleValue) { + this.doubleValue = doubleValue; + this.isLarge = false; + } + + ImportantNumber(@AnnotationB("x") double doubleValue, @AnnotationB("y") boolean isLarge) { + this.doubleValue = doubleValue; + this.isLarge = isLarge; + } + } + + public enum BinaryNumber { + ZERO, + ONE; + } + + private abstract static class AnonymousBase { + public AnonymousBase(@AnnotationA String s) {} + } + + private static String annotationToNormalizedString(Annotation annotation) { + // String.replace() to accomodate different representation across VMs. + return annotation.toString().replace("\"", ""); + } + + private static void DumpConstructorParameterAnnotations(Class<?> cls) throws Throwable { + System.out.println(cls.getName()); + for (Constructor c : cls.getDeclaredConstructors()) { + System.out.println(" " + c); + Annotation[][] annotations = c.getParameterAnnotations(); + Parameter[] parameters = c.getParameters(); + for (int i = 0; i < annotations.length; ++i) { + // Exercise java.lang.reflect.Executable.getParameterAnnotationsNative() + // which retrieves all annotations for the parameters. + System.out.print(" Parameter [" + i + "]:"); + for (Annotation annotation : parameters[i].getAnnotations()) { + System.out.println(" Indexed : " + annotationToNormalizedString(annotation)); + } + for (Annotation annotation : annotations[i]) { + System.out.println(" Array : " + annotationToNormalizedString(annotation)); + } + + // Exercise Parameter.getAnnotationNative() with + // retrieves a single parameter annotation according to type. + Object[] opaqueClasses = new Object[] {AnnotationA.class, AnnotationB.class}; + for (Object opaqueClass : opaqueClasses) { + @SuppressWarnings("unchecked") + Class<? extends Annotation> annotationClass = + (Class<? extends Annotation>) opaqueClass; + Annotation annotation = parameters[i].getDeclaredAnnotation(annotationClass); + String hasAnnotation = (annotation != null ? "Yes" : "No"); + System.out.println(" " + annotationClass.getName() + " " + hasAnnotation); + + Annotation[] parameterAnnotations = parameters[i].getDeclaredAnnotationsByType(annotationClass); + for (Annotation parameterAnnotation : parameterAnnotations) { + System.out.println(" " + annotationToNormalizedString(parameterAnnotation)); + } + } + } + } + } + + private Class<?> getLocalClassWithEnclosingInstanceCapture() { + class LocalClass { + private final int integerValue; + + LocalClass(@AnnotationA int integerValue) { + this.integerValue = integerValue; + } + } + return LocalClass.class; + } + + private Class<?> getLocalClassWithEnclosingInstanceAndLocalCapture() { + final long CAPTURED_VALUE = System.currentTimeMillis(); + class LocalClassWithCapture { + private final String value; + private final long capturedValue; + + LocalClassWithCapture(@AnnotationA String p1) { + this.value = p1; + this.capturedValue = CAPTURED_VALUE; + } + } + return LocalClassWithCapture.class; + } + + public static void main(String[] args) throws Throwable { + // A local class declared in a static context (0 implicit parameters). + class LocalClassStaticContext { + private final int value; + + LocalClassStaticContext(@AnnotationA int p0) { + this.value = p0; + } + } + + final long CAPTURED_VALUE = System.currentTimeMillis(); + // A local class declared in a static context with a capture (1 implicit parameters). + class LocalClassStaticContextWithCapture { + private final long capturedValue; + private final String argumentValue; + + LocalClassStaticContextWithCapture(@AnnotationA String p1) { + this.capturedValue = CAPTURED_VALUE; + this.argumentValue = p1; + } + } + + // Another local class declared in a static context with a capture (1 implicit parameters). + class LocalClassStaticContextWithCaptureAlternateOrdering { + private final String argumentValue; + private final long capturedValue; + + LocalClassStaticContextWithCaptureAlternateOrdering(@AnnotationA String p1) { + this.argumentValue = p1; + this.capturedValue = CAPTURED_VALUE; + } + } + + DumpConstructorParameterAnnotations(Main.class); + DumpConstructorParameterAnnotations(LocalClassStaticContext.class); + DumpConstructorParameterAnnotations(LocalClassStaticContextWithCapture.class); + DumpConstructorParameterAnnotations(LocalClassStaticContextWithCaptureAlternateOrdering.class); + Main m = new Main(); + DumpConstructorParameterAnnotations(m.getLocalClassWithEnclosingInstanceCapture()); + DumpConstructorParameterAnnotations(m.getLocalClassWithEnclosingInstanceAndLocalCapture()); + DumpConstructorParameterAnnotations(Inner.class); + DumpConstructorParameterAnnotations(StaticInner.class); + DumpConstructorParameterAnnotations(ImportantNumber.class); + DumpConstructorParameterAnnotations(BinaryNumber.class); + DumpConstructorParameterAnnotations(new AnonymousBase("") {}.getClass()); + } +} diff --git a/test/etc/default-build b/test/etc/default-build index 4ed2af6ac6..3e6577cfda 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -137,12 +137,14 @@ declare -A JAVAC_EXPERIMENTAL_ARGS JAVAC_EXPERIMENTAL_ARGS["default-methods"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["lambdas"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["method-handles"]="-source 1.8 -target 1.8" +JAVAC_EXPERIMENTAL_ARGS["parameter-annotations"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["var-handles"]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.8 -target 1.8" JAVAC_EXPERIMENTAL_ARGS["agents"]="-source 1.8 -target 1.8" declare -A DX_EXPERIMENTAL_ARGS DX_EXPERIMENTAL_ARGS["method-handles"]="--min-sdk-version=26" +DX_EXPERIMENTAL_ARGS["parameter-annotations"]="--min-sdk-version=25" DX_EXPERIMENTAL_ARGS["var-handles"]="--min-sdk-version=26" while true; do |