summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2022-07-07 18:14:15 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2022-07-07 18:14:15 +0000
commite4feb40fc359d353f2a9c61d9a53e02df30a88d8 (patch)
tree123110d1ca0cb41b1609901d155b0737f5317840
parent9ca36b31c995b24054202f8121e469392182cffa (diff)
parent385e5df0ca2a739a4bdbe2ab364ce71adfa00bff (diff)
Fix one edge case at method linking to throw at runtime. am: d88c1499ef am: 8bc8a6b5b6 am: 3c3a870149 am: ffbdfeec4c am: 385e5df0ca
Original change: https://android-review.googlesource.com/c/platform/art/+/2146626 Change-Id: I5666fdec77e93e5746722354d8bd743d379bfe46 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--runtime/art_method.cc26
-rw-r--r--runtime/art_method.h6
-rw-r--r--runtime/class_linker.cc22
-rw-r--r--runtime/common_throws.cc13
-rw-r--r--runtime/common_throws.h5
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc15
-rw-r--r--runtime/interpreter/interpreter.cc2
-rw-r--r--runtime/interpreter/interpreter_common.h25
-rw-r--r--test/182-method-linking/src/Main.java19
-rw-r--r--test/840-resolution/expected-stderr.txt0
-rw-r--r--test/840-resolution/expected-stdout.txt0
-rw-r--r--test/840-resolution/info.txt2
-rw-r--r--test/840-resolution/jasmin/SubClass2.j35
-rw-r--r--test/840-resolution/src/Main.java179
-rw-r--r--test/840-resolution/src/SuperClass.java21
-rw-r--r--test/840-resolution/src/SuperClassNoFoo.java21
-rw-r--r--test/840-resolution/src/SuperClassPrivateFoo.java21
-rw-r--r--test/840-resolution/src/SuperClassStaticFoo.java21
-rw-r--r--test/840-resolution/src/pkg/PkgSuperClass.java23
-rw-r--r--test/840-resolution/src2/SuperClass.java21
-rw-r--r--test/840-resolution/src2/SuperClassNoFoo.java18
-rw-r--r--test/840-resolution/src2/SuperClassPrivateFoo.java21
-rw-r--r--test/840-resolution/src2/SuperClassStaticFoo.java21
-rw-r--r--test/840-resolution/src2/pkg/PkgSuperClass.java23
24 files changed, 499 insertions, 61 deletions
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index cef9d7b9bd..71f08e7b4d 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -150,10 +150,34 @@ uint16_t ArtMethod::FindObsoleteDexClassDefIndex() {
return dex_file->GetIndexForClassDef(*class_def);
}
-void ArtMethod::ThrowInvocationTimeError() {
+void ArtMethod::ThrowInvocationTimeError(ObjPtr<mirror::Object> receiver) {
DCHECK(!IsInvokable());
if (IsDefaultConflicting()) {
ThrowIncompatibleClassChangeErrorForMethodConflict(this);
+ } else if (GetDeclaringClass()->IsInterface() && receiver != nullptr) {
+ // If this was an interface call, check whether there is a method in the
+ // superclass chain that isn't public. In this situation, we should throw an
+ // IllegalAccessError.
+ DCHECK(IsAbstract());
+ ObjPtr<mirror::Class> current = receiver->GetClass();
+ while (current != nullptr) {
+ for (ArtMethod& method : current->GetDeclaredMethodsSlice(kRuntimePointerSize)) {
+ ArtMethod* np_method = method.GetInterfaceMethodIfProxy(kRuntimePointerSize);
+ if (!np_method->IsStatic() &&
+ np_method->GetNameView() == GetNameView() &&
+ np_method->GetSignature() == GetSignature()) {
+ if (!np_method->IsPublic()) {
+ ThrowIllegalAccessErrorForImplementingMethod(receiver->GetClass(), np_method, this);
+ return;
+ } else if (np_method->IsAbstract()) {
+ ThrowAbstractMethodError(this);
+ return;
+ }
+ }
+ }
+ current = current->GetSuperClass();
+ }
+ ThrowAbstractMethodError(this);
} else {
DCHECK(IsAbstract());
ThrowAbstractMethodError(this);
diff --git a/runtime/art_method.h b/runtime/art_method.h
index d8bd3803fc..072dea2c4d 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -422,8 +422,10 @@ class ArtMethod final {
bool CheckIncompatibleClassChange(InvokeType type) REQUIRES_SHARED(Locks::mutator_lock_);
// Throws the error that would result from trying to invoke this method (i.e.
- // IncompatibleClassChangeError or AbstractMethodError). Only call if !IsInvokable();
- void ThrowInvocationTimeError() REQUIRES_SHARED(Locks::mutator_lock_);
+ // IncompatibleClassChangeError, AbstractMethodError, or IllegalAccessError).
+ // Only call if !IsInvokable();
+ void ThrowInvocationTimeError(ObjPtr<mirror::Object> receiver)
+ REQUIRES_SHARED(Locks::mutator_lock_);
uint16_t GetMethodIndex() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d21aecc2fa..c2ce3e2eb8 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7857,20 +7857,6 @@ bool ClassLinker::LinkMethodsHelper<kPointerSize>::FinalizeIfTable(
return true;
}
-NO_INLINE
-static void ThrowIllegalAccessErrorForImplementingMethod(ObjPtr<mirror::Class> klass,
- ArtMethod* vtable_method,
- ArtMethod* interface_method)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(!vtable_method->IsAbstract());
- DCHECK(!vtable_method->IsPublic());
- ThrowIllegalAccessError(
- klass,
- "Method '%s' implementing interface method '%s' is not public",
- vtable_method->PrettyMethod().c_str(),
- interface_method->PrettyMethod().c_str());
-}
-
template <PointerSize kPointerSize>
ObjPtr<mirror::PointerArray> ClassLinker::LinkMethodsHelper<kPointerSize>::AllocPointerArray(
Thread* self, size_t length) {
@@ -8124,15 +8110,11 @@ size_t ClassLinker::LinkMethodsHelper<kPointerSize>::AssignVTableIndexes(
found = true;
}
}
+ found = found && vtable_method->IsPublic();
+
uint32_t vtable_index = vtable_length;
if (found) {
DCHECK(vtable_method != nullptr);
- if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) {
- // FIXME: Delay the exception until we actually try to call the method. b/211854716
- sants.reset();
- ThrowIllegalAccessErrorForImplementingMethod(klass, vtable_method, interface_method);
- return 0u;
- }
vtable_index = vtable_method->GetMethodIndexDuringLinking();
if (!vtable_method->IsOverridableByDefaultMethod()) {
method_array->SetElementPtrSize(j, vtable_index, kPointerSize);
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 3a33f2a3aa..0bc913874b 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -237,6 +237,19 @@ void ThrowIllegalAccessError(ObjPtr<mirror::Class> referrer, const char* fmt, ..
va_end(args);
}
+void ThrowIllegalAccessErrorForImplementingMethod(ObjPtr<mirror::Class> klass,
+ ArtMethod* implementation_method,
+ ArtMethod* interface_method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(!implementation_method->IsAbstract());
+ DCHECK(!implementation_method->IsPublic());
+ ThrowIllegalAccessError(
+ klass,
+ "Method '%s' implementing interface method '%s' is not public",
+ implementation_method->PrettyMethod().c_str(),
+ interface_method->PrettyMethod().c_str());
+}
+
// IllegalAccessException
void ThrowIllegalAccessException(const char* msg) {
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index 843c455878..d9620df0b9 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -111,6 +111,11 @@ void ThrowIllegalAccessError(ObjPtr<mirror::Class> referrer, const char* fmt, ..
__attribute__((__format__(__printf__, 2, 3)))
REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+void ThrowIllegalAccessErrorForImplementingMethod(ObjPtr<mirror::Class> klass,
+ ArtMethod* implementation_method,
+ ArtMethod* interface_method)
+ REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+
// IllegalAccessException
void ThrowIllegalAccessException(const char* msg)
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 5995d5b0c5..7e3fdee3e1 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -224,13 +224,8 @@ class QuickArgumentVisitor {
#endif
public:
- // Special handling for proxy methods. Proxy methods are instance methods so the
- // 'this' object is the 1st argument. They also have the same frame layout as the
- // kRefAndArgs runtime method. Since 'this' is a reference, it is located in the
- // 1st GPR.
- static StackReference<mirror::Object>* GetProxyThisObjectReference(ArtMethod** sp)
+ static StackReference<mirror::Object>* GetThisObjectReference(ArtMethod** sp)
REQUIRES_SHARED(Locks::mutator_lock_) {
- CHECK((*sp)->IsProxyMethod());
CHECK_GT(kNumQuickGprArgs, 0u);
constexpr uint32_t kThisGprIndex = 0u; // 'this' is in the 1st GPR.
size_t this_arg_offset = kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset +
@@ -529,7 +524,8 @@ class QuickArgumentVisitor {
// allows to use the QuickArgumentVisitor constants without moving all the code in its own module.
extern "C" mirror::Object* artQuickGetProxyThisObject(ArtMethod** sp)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return QuickArgumentVisitor::GetProxyThisObjectReference(sp)->AsMirrorPtr();
+ DCHECK((*sp)->IsProxyMethod());
+ return QuickArgumentVisitor::GetThisObjectReference(sp)->AsMirrorPtr();
}
// Visits arguments on the stack placing them into the shadow frame.
@@ -655,7 +651,10 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self,
ScopedQuickEntrypointChecks sqec(self);
if (UNLIKELY(!method->IsInvokable())) {
- method->ThrowInvocationTimeError();
+ method->ThrowInvocationTimeError(
+ method->IsStatic()
+ ? nullptr
+ : QuickArgumentVisitor::GetThisObjectReference(sp)->AsMirrorPtr());
return 0;
}
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 311cb23510..0ffc38beeb 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -374,7 +374,7 @@ void EnterInterpreterFromInvoke(Thread* self,
num_ins = accessor.InsSize();
} else if (!method->IsInvokable()) {
self->EndAssertNoThreadSuspension(old_cause);
- method->ThrowInvocationTimeError();
+ method->ThrowInvocationTimeError(receiver);
return;
} else {
DCHECK(method->IsNative()) << method->PrettyMethod();
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 0b91120c58..fe9cf57ec5 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -259,18 +259,23 @@ static ALWAYS_INLINE bool DoInvoke(Thread* self,
}
// Null pointer check and virtual method resolution.
- ObjPtr<mirror::Object> receiver =
- (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC);
- ArtMethod* called_method;
- called_method = FindMethodToCall<type, do_access_check>(
- method_idx, resolved_method, &receiver, sf_method, self);
- if (UNLIKELY(called_method == nullptr)) {
- CHECK(self->IsExceptionPending());
- result->SetJ(0);
- return false;
+ ArtMethod* called_method = nullptr;
+ {
+ // `FindMethodToCall` might suspend, so don't keep `receiver` as a local
+ // variable after the call.
+ ObjPtr<mirror::Object> receiver =
+ (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC);
+ called_method = FindMethodToCall<type, do_access_check>(
+ method_idx, resolved_method, &receiver, sf_method, self);
+ if (UNLIKELY(called_method == nullptr)) {
+ CHECK(self->IsExceptionPending());
+ result->SetJ(0);
+ return false;
+ }
}
if (UNLIKELY(!called_method->IsInvokable())) {
- called_method->ThrowInvocationTimeError();
+ called_method->ThrowInvocationTimeError(
+ (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC));
result->SetJ(0);
return false;
}
diff --git a/test/182-method-linking/src/Main.java b/test/182-method-linking/src/Main.java
index 39029560f7..638ff654a3 100644
--- a/test/182-method-linking/src/Main.java
+++ b/test/182-method-linking/src/Main.java
@@ -33,12 +33,6 @@ import pkg2.I2;
public class Main {
public static void main(String args[]) {
- try {
- Class.forName("dalvik.system.PathClassLoader");
- } catch (ClassNotFoundException e) {
- usingRI = true;
- }
-
// A single method signature can result in multiple vtable entries
// when package-private methods from different packages are involved.
// All classes here define the method `void foo()` but classes
@@ -120,7 +114,6 @@ public class Main {
CXI1 cxi1 = new CXI1();
I1.callI1Foo(cxi1);
} catch (IllegalAccessError expected) {
- printOnDalvik("Calling pkg1.I1.foo on pkg1.CXI1");
System.out.println("Caught IllegalAccessError");
}
@@ -128,7 +121,6 @@ public class Main {
CXI2 cxi2 = new CXI2();
I2.callI2Foo(cxi2);
} catch (IllegalAccessError expected) {
- printOnDalvik("Calling pkg2.I2.foo on pkg1.CXI2");
System.out.println("Caught IllegalAccessError");
}
@@ -136,7 +128,6 @@ public class Main {
DXI1 dxi1 = new DXI1();
I1.callI1Foo(dxi1);
} catch (IllegalAccessError expected) {
- printOnDalvik("Calling pkg1.I1.foo on pkg2.DXI1");
System.out.println("Caught IllegalAccessError");
}
@@ -144,17 +135,7 @@ public class Main {
DXI2 dxi2 = new DXI2();
I2.callI2Foo(dxi2);
} catch (IllegalAccessError expected) {
- printOnDalvik("Calling pkg2.I2.foo on pkg2.DXI2");
System.out.println("Caught IllegalAccessError");
}
}
-
- private static void printOnDalvik(String line) {
- if (!usingRI) {
- // FIXME: Delay IAE until calling the method. Bug: 211854716
- System.out.println(line);
- }
- }
-
- private static boolean usingRI = false;
}
diff --git a/test/840-resolution/expected-stderr.txt b/test/840-resolution/expected-stderr.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/840-resolution/expected-stderr.txt
diff --git a/test/840-resolution/expected-stdout.txt b/test/840-resolution/expected-stdout.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/840-resolution/expected-stdout.txt
diff --git a/test/840-resolution/info.txt b/test/840-resolution/info.txt
new file mode 100644
index 0000000000..bd88f7d47d
--- /dev/null
+++ b/test/840-resolution/info.txt
@@ -0,0 +1,2 @@
+Various tests on interface method linking when not finding a public
+implementation.
diff --git a/test/840-resolution/jasmin/SubClass2.j b/test/840-resolution/jasmin/SubClass2.j
new file mode 100644
index 0000000000..8a65e1f554
--- /dev/null
+++ b/test/840-resolution/jasmin/SubClass2.j
@@ -0,0 +1,35 @@
+; Copyright (C) 2022 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.
+
+.class public SubClass2
+.super SuperClass
+.implements Interface
+
+.method public <init>()V
+ .limit stack 1
+ .limit locals 1
+ aload_0
+ invokespecial SuperClass/<init>()V
+ return
+.end method
+
+.method foo()Ljava/lang/Class;
+ .limit stack 1
+ .limit locals 1
+ ; jasmin does not support ldc with a class, so just return null for the
+ ; purpose of this test.
+ aconst_null
+ areturn
+.end method
+
diff --git a/test/840-resolution/src/Main.java b/test/840-resolution/src/Main.java
new file mode 100644
index 0000000000..23cd31d3ab
--- /dev/null
+++ b/test/840-resolution/src/Main.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+public class Main {
+
+ // Testcase 1: the superclass has a package private version in the same package.
+ static Interface s = new SubClass();
+
+ // Testcase 2: the class has a package private version.
+ static Interface s2;
+
+ // Testcase 3: the superclass has a package private version in a different package.
+ static Interface s3 = new SubClassFromPkg();
+
+ // Testcase 4: there is no implementation in the hierarchy.
+ static Interface s4 = new SubClassNoFoo();
+
+ // Testcase 5: there is a private method in the hierarchy.
+ static Interface s5 = new SubClassPrivateFoo();
+
+ // Testcase 6: there is a static method in the hierarchy.
+ static Interface s6 = new SubClassStaticFoo();
+
+ static {
+ try {
+ s2 = (Interface) Class.forName("SubClass2").newInstance();
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+
+ public static void assertEquals(Object expected, Object actual) {
+ if (expected != actual) {
+ throw new Error("Expected " + expected + ", got " + actual);
+ }
+ }
+
+ public static void assertTrue(boolean value) {
+ if (!value) {
+ throw new Error("");
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ assertEquals(SuperClass.class, ((SubClass) s).foo());
+ assertEquals(SuperClass.class, ((SuperClass) s).foo());
+
+ try {
+ s.foo();
+ throw new Error("Expected IllegalAccessError");
+ } catch (IllegalAccessError ie) {
+ // expected
+ }
+
+ assertEquals(null, ((SuperClass) s2).foo());
+ try {
+ s2.foo();
+ throw new Error("Expected IllegalAccessError");
+ } catch (IllegalAccessError ie) {
+ // expected
+ }
+
+ try {
+ ((pkg.PkgSuperClass) s3).foo();
+ throw new Error("Expected IllegalAccessError");
+ } catch (IllegalAccessError ie) {
+ // expected
+ }
+
+ try {
+ ((SubClassFromPkg) s3).foo();
+ throw new Error("Expected IllegalAccessError");
+ } catch (IllegalAccessError ie) {
+ // expected
+ }
+
+ try {
+ s3.foo();
+ throw new Error("Expected IllegalAccessError");
+ } catch (IllegalAccessError ie) {
+ // expected
+ }
+
+ try {
+ ((SuperClassNoFoo) s4).foo();
+ throw new Error("Expected NoSuchMethodError");
+ } catch (NoSuchMethodError e) {
+ // expected
+ }
+
+ try {
+ ((SubClassNoFoo) s4).foo();
+ throw new Error("Expected AbstractMethodError");
+ } catch (AbstractMethodError e) {
+ // expected
+ }
+
+ try {
+ s4.foo();
+ throw new Error("Expected AbstractMethodError");
+ } catch (AbstractMethodError e) {
+ // expected
+ }
+
+ try {
+ ((SuperClassPrivateFoo) s5).foo();
+ throw new Error("Expected IllegalAccessError");
+ } catch (IllegalAccessError e) {
+ // expected
+ }
+
+ try {
+ ((SubClassPrivateFoo) s5).foo();
+ throw new Error("Expected IllegalAccessError");
+ } catch (IllegalAccessError e) {
+ // expected
+ }
+
+ try {
+ s5.foo();
+ throw new Error("Expected AbstractMethodError on RI, IllegalAccessError on ART");
+ } catch (AbstractMethodError | IllegalAccessError e) {
+ // expected
+ }
+
+ try {
+ ((SuperClassStaticFoo) s6).foo();
+ throw new Error("Expected IncompatibleClassChangeError");
+ } catch (IncompatibleClassChangeError e) {
+ // expected
+ }
+
+ try {
+ ((SubClassStaticFoo) s6).foo();
+ throw new Error("Expected IncompatibleClassChangeError");
+ } catch (IncompatibleClassChangeError e) {
+ // expected
+ }
+
+ try {
+ s6.foo();
+ throw new Error("Expected AbstractMethodError");
+ } catch (AbstractMethodError e) {
+ // expected
+ }
+ }
+}
+
+interface Interface {
+ public Class<?> foo();
+}
+
+class SubClass extends SuperClass implements Interface {
+}
+
+class SubClassFromPkg extends pkg.PkgSuperClass implements Interface {
+}
+
+class SubClassNoFoo extends SuperClassNoFoo implements Interface {
+}
+
+class SubClassPrivateFoo extends SuperClassPrivateFoo implements Interface {
+}
+
+class SubClassStaticFoo extends SuperClassStaticFoo implements Interface {
+}
diff --git a/test/840-resolution/src/SuperClass.java b/test/840-resolution/src/SuperClass.java
new file mode 100644
index 0000000000..ece01886b7
--- /dev/null
+++ b/test/840-resolution/src/SuperClass.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+class SuperClass {
+ public Class<?> foo() {
+ return SuperClass.class;
+ }
+}
diff --git a/test/840-resolution/src/SuperClassNoFoo.java b/test/840-resolution/src/SuperClassNoFoo.java
new file mode 100644
index 0000000000..747aaefb8c
--- /dev/null
+++ b/test/840-resolution/src/SuperClassNoFoo.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+public class SuperClassNoFoo {
+ public Class<?> foo() {
+ throw new Error("Unreachable");
+ }
+}
diff --git a/test/840-resolution/src/SuperClassPrivateFoo.java b/test/840-resolution/src/SuperClassPrivateFoo.java
new file mode 100644
index 0000000000..95af4f78db
--- /dev/null
+++ b/test/840-resolution/src/SuperClassPrivateFoo.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+class SuperClassPrivateFoo {
+ public Class<?> foo() {
+ return SuperClass.class;
+ }
+}
diff --git a/test/840-resolution/src/SuperClassStaticFoo.java b/test/840-resolution/src/SuperClassStaticFoo.java
new file mode 100644
index 0000000000..490637f8dc
--- /dev/null
+++ b/test/840-resolution/src/SuperClassStaticFoo.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+public class SuperClassStaticFoo {
+ public Class<?> foo() {
+ throw new Error("Unreachable");
+ }
+}
diff --git a/test/840-resolution/src/pkg/PkgSuperClass.java b/test/840-resolution/src/pkg/PkgSuperClass.java
new file mode 100644
index 0000000000..397ae28a59
--- /dev/null
+++ b/test/840-resolution/src/pkg/PkgSuperClass.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 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 pkg;
+
+public class PkgSuperClass {
+ public Class<?> foo() {
+ return PkgSuperClass.class;
+ }
+}
diff --git a/test/840-resolution/src2/SuperClass.java b/test/840-resolution/src2/SuperClass.java
new file mode 100644
index 0000000000..fe40c0a060
--- /dev/null
+++ b/test/840-resolution/src2/SuperClass.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+class SuperClass {
+ Class<?> foo() {
+ return SuperClass.class;
+ }
+}
diff --git a/test/840-resolution/src2/SuperClassNoFoo.java b/test/840-resolution/src2/SuperClassNoFoo.java
new file mode 100644
index 0000000000..c0e8c442ed
--- /dev/null
+++ b/test/840-resolution/src2/SuperClassNoFoo.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+public class SuperClassNoFoo {
+}
diff --git a/test/840-resolution/src2/SuperClassPrivateFoo.java b/test/840-resolution/src2/SuperClassPrivateFoo.java
new file mode 100644
index 0000000000..f0c1c6853f
--- /dev/null
+++ b/test/840-resolution/src2/SuperClassPrivateFoo.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+class SuperClassPrivateFoo {
+ private Class<?> foo() {
+ return SuperClass.class;
+ }
+}
diff --git a/test/840-resolution/src2/SuperClassStaticFoo.java b/test/840-resolution/src2/SuperClassStaticFoo.java
new file mode 100644
index 0000000000..ecf8bc17a5
--- /dev/null
+++ b/test/840-resolution/src2/SuperClassStaticFoo.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+public class SuperClassStaticFoo {
+ public static Class<?> foo() {
+ return SuperClassStaticFoo.class;
+ }
+}
diff --git a/test/840-resolution/src2/pkg/PkgSuperClass.java b/test/840-resolution/src2/pkg/PkgSuperClass.java
new file mode 100644
index 0000000000..2f333eec46
--- /dev/null
+++ b/test/840-resolution/src2/pkg/PkgSuperClass.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 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 pkg;
+
+public class PkgSuperClass {
+ Class<?> foo() {
+ return PkgSuperClass.class;
+ }
+}