Isolate access to ElementFilters

This CL attempts to isolate access to ElementFilters into extension
methods.
As part of it, I've also removed all access to ElementUtils except for
the extension files.

Unfortunately, the difference between declared methods / methods
including supers / instance methods is not super clear in our codebase.
I tried a best effort to group them in 3 sections but I'm not 100% sure
if this is correct.

Added an additional test for element extensions (probably needs to be
further extended).

Bug: 160323720
Test: existing test suite, ElementExtTest
Change-Id: I962758128d3123b4c120fe48630ad54202047833
diff --git a/room/compiler/build.gradle b/room/compiler/build.gradle
index 59634ee..22d60b8 100644
--- a/room/compiler/build.gradle
+++ b/room/compiler/build.gradle
@@ -15,6 +15,8 @@
  */
 
 
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
 import static androidx.build.dependencies.DependenciesKt.*
 import androidx.build.BuildOnServerKt
 import androidx.build.CompilationTarget
@@ -240,6 +242,13 @@
 tasks.findByName("compileKotlin").dependsOn(":room:room-runtime:jarDebug")
 tasks.findByName("compileKotlin").dependsOn(":sqlite:sqlite:jarDebug")
 
+tasks.withType(KotlinCompile).configureEach {
+    kotlinOptions {
+        freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn",
+                             "-Xopt-in=kotlin.contracts.ExperimentalContracts"]
+    }
+}
+
 androidx {
     name = "Android Room Compiler"
     publish = Publish.SNAPSHOT_AND_RELEASE
diff --git a/room/compiler/src/main/kotlin/androidx/room/ext/element_ext.kt b/room/compiler/src/main/kotlin/androidx/room/ext/element_ext.kt
index fdd7a8d..53fdaa8 100644
--- a/room/compiler/src/main/kotlin/androidx/room/ext/element_ext.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/ext/element_ext.kt
@@ -44,6 +44,7 @@
 import javax.lang.model.util.SimpleAnnotationValueVisitor6
 import javax.lang.model.util.SimpleTypeVisitor7
 import javax.lang.model.util.Types
+import kotlin.contracts.contract
 import kotlin.reflect.KClass
 
 fun Element.hasAnyOf(vararg modifiers: Modifier): Boolean {
@@ -69,6 +70,10 @@
 
 fun Element.isEntityElement() = this.hasAnnotation(androidx.room.Entity::class)
 
+fun TypeElement.getConstructors(): List<ExecutableElement> {
+    return ElementFilter.constructorsIn(enclosedElements)
+}
+
 /**
  * gets all members including super privates. does not handle duplicate field names!!!
  */
@@ -89,7 +94,7 @@
 }
 
 fun TypeElement.getAllMethodsIncludingSupers(): Set<ExecutableElement> {
-    val myMethods = ElementFilter.methodsIn(this.enclosedElements).toSet()
+    val myMethods = getDeclaredMethods().toSet()
     val interfaceMethods = interfaces.flatMap {
         it.asTypeElement().getAllMethodsIncludingSupers()
     }
@@ -387,10 +392,10 @@
     }
 
     val parent = this.enclosingElement as TypeElement
-    val innerClass = parent.enclosedElements.find {
-        it.kind == ElementKind.CLASS && it.simpleName.contentEquals(DEFAULT_IMPLS_CLASS_NAME)
-    } ?: return null
-    return ElementFilter.methodsIn(innerClass.enclosedElements).find {
+    val innerClass: TypeElement = parent.enclosedElements.find {
+        it.isType() && it.simpleName.contentEquals(DEFAULT_IMPLS_CLASS_NAME)
+    } as? TypeElement ?: return null
+    return innerClass.getDeclaredMethods().find {
         it.simpleName == this.simpleName && paramsMatch(this.parameters, it.parameters)
     }
 }
@@ -415,11 +420,42 @@
 
 fun Element.asExecutableElement() = MoreElements.asExecutable(this)
 
-fun Element.isType() = MoreElements.isType(this)
+fun Element.isType(): Boolean {
+    contract {
+        returns(true) implies (this@isType is TypeElement)
+    }
+    return MoreElements.isType(this)
+}
 
 fun Element.asDeclaredType() = asType().asDeclaredType()
 
-fun TypeElement.getLocalAndInheritedMethods(
+/**
+ * methods declared in this type
+ *  includes all instance/static methods in this
+ */
+fun TypeElement.getDeclaredMethods() = ElementFilter.methodsIn(
+    enclosedElements
+)
+
+/**
+ * Methods declared in this type and its parents
+ *  includes all instance/static methods in this
+ *  includes all instance/static methods in parent CLASS if they are accessible from this (e.g. not
+ *  private).
+ *  does not include static methods in parent interfaces
+ */
+fun TypeElement.getAllMethods(
+    processingEnv: ProcessingEnvironment
+) = ElementFilter.methodsIn(
+    processingEnv.elementUtils.getAllMembers(this)
+)
+
+/**
+ * Instance methods declared in this and supers
+ *  include non private instance methods
+ *  also includes non-private instance methods from supers
+ */
+fun TypeElement.getAllNonPrivateInstanceMethods(
     processingEnvironment: ProcessingEnvironment
 ) = MoreElements.getLocalAndInheritedMethods(
     this,
diff --git a/room/compiler/src/main/kotlin/androidx/room/ext/processing_env_ext.kt b/room/compiler/src/main/kotlin/androidx/room/ext/processing_env_ext.kt
index 101bdcd..4ab6d2b 100644
--- a/room/compiler/src/main/kotlin/androidx/room/ext/processing_env_ext.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/ext/processing_env_ext.kt
@@ -15,6 +15,7 @@
  */
 package androidx.room.ext
 
+import com.google.auto.common.GeneratedAnnotations
 import com.squareup.javapoet.TypeName
 import javax.annotation.processing.ProcessingEnvironment
 import javax.lang.model.element.TypeElement
@@ -108,3 +109,12 @@
 fun ProcessingEnvironment.findTypeMirror(
     qName: String
 ): TypeMirror? = findTypeElement(qName)?.asType()
+
+fun ProcessingEnvironment.getGeneratedAnnotation(): TypeElement? {
+    val element = GeneratedAnnotations.generatedAnnotation(elementUtils, sourceVersion)
+    return if (element.isPresent) {
+        element.get()
+    } else {
+        null
+    }
+}
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/androidx/room/ext/type_mirror_ext.kt b/room/compiler/src/main/kotlin/androidx/room/ext/type_mirror_ext.kt
index 6829d3a..ff2e46c 100644
--- a/room/compiler/src/main/kotlin/androidx/room/ext/type_mirror_ext.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/ext/type_mirror_ext.kt
@@ -109,7 +109,6 @@
     this
 )
 
-@OptIn(ExperimentalContracts::class)
 fun TypeMirror.isArray(): Boolean {
     contract {
         returns(true) implies (this@isArray is ArrayType)
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt
index 7f2aeaf..0e1cdc0 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt
@@ -20,6 +20,8 @@
 import androidx.room.TypeConverters
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.asMemberOf
+import androidx.room.ext.getAllMethods
+import androidx.room.ext.getConstructors
 import androidx.room.ext.hasAnnotation
 import androidx.room.ext.hasAnyOf
 import androidx.room.ext.toAnnotationBox
@@ -46,7 +48,6 @@
 import javax.lang.model.element.TypeElement
 import javax.lang.model.type.DeclaredType
 import javax.lang.model.type.TypeMirror
-import javax.lang.model.util.ElementFilter
 
 /**
  * Processes classes that are referenced in TypeConverters annotations.
@@ -87,17 +88,14 @@
 
     fun process(): List<CustomTypeConverter> {
         // using element utils instead of MoreElements to include statics.
-        val methods = ElementFilter
-            .methodsIn(context.processingEnv.elementUtils.getAllMembers(element))
+        val methods = element.getAllMethods(context.processingEnv)
         val declaredType = element.asDeclaredType()
         val converterMethods = methods.filter {
             it.hasAnnotation(TypeConverter::class)
         }
         context.checker.check(converterMethods.isNotEmpty(), element, TYPE_CONVERTER_EMPTY_CLASS)
         val allStatic = converterMethods.all { it.modifiers.contains(Modifier.STATIC) }
-        val constructors = ElementFilter.constructorsIn(
-            context.processingEnv.elementUtils.getAllMembers(element)
-        )
+        val constructors = element.getConstructors()
         val kotlinMetadata = KotlinMetadataElement.createFor(context, element)
         val isKotlinObjectDeclaration = kotlinMetadata?.isObject() == true
         context.checker.check(
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
index a15359f..ffadc85 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/DaoProcessor.kt
@@ -25,6 +25,8 @@
 import androidx.room.Update
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.findKotlinDefaultImpl
+import androidx.room.ext.getAllMethods
+import androidx.room.ext.getConstructors
 import androidx.room.ext.hasAnnotation
 import androidx.room.ext.hasAnyOf
 import androidx.room.ext.typeName
@@ -38,7 +40,6 @@
 import javax.lang.model.element.Modifier.ABSTRACT
 import javax.lang.model.element.TypeElement
 import javax.lang.model.type.DeclaredType
-import javax.lang.model.util.ElementFilter
 
 class DaoProcessor(
     baseContext: Context,
@@ -60,8 +61,8 @@
                 element, ProcessorErrors.DAO_MUST_BE_AN_ABSTRACT_CLASS_OR_AN_INTERFACE)
 
         val declaredType = element.asDeclaredType()
-        val allMembers = context.processingEnv.elementUtils.getAllMembers(element)
-        val methods = ElementFilter.methodsIn(allMembers)
+        val allMethods = element.getAllMethods(context.processingEnv)
+        val methods = allMethods
             .filter {
                 it.hasAnyOf(ABSTRACT) &&
                         it.findKotlinDefaultImpl(context.processingEnv.typeUtils) == null
@@ -128,7 +129,7 @@
                     executableElement = it).process()
         } ?: emptyList()
 
-        val transactionMethods = ElementFilter.methodsIn(allMembers).filter { member ->
+        val transactionMethods = allMethods.filter { member ->
             member.hasAnnotation(Transaction::class) &&
                     PROCESSED_ANNOTATIONS.none { member.hasAnnotation(it) }
         }.map {
@@ -141,7 +142,7 @@
         val kotlinDefaultMethodDelegates = if (element.kind == ElementKind.INTERFACE) {
             val allProcessedMethods =
                 methods.values.flatten() + transactionMethods.map { it.element }
-            ElementFilter.methodsIn(allMembers).filterNot {
+            allMethods.filterNot {
                 allProcessedMethods.contains(it)
             }.mapNotNull { method ->
                 method.findKotlinDefaultImpl(context.processingEnv.typeUtils)?.let { delegate ->
@@ -155,7 +156,7 @@
             emptyList()
         }
 
-        val constructors = ElementFilter.constructorsIn(allMembers)
+        val constructors = element.getConstructors()
         val typeUtils = context.processingEnv.typeUtils
         val goodConstructor = constructors.firstOrNull {
             it.parameters.size == 1 &&
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
index 3684df7..9bceb2a 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
@@ -22,6 +22,7 @@
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.asExecutableElement
 import androidx.room.ext.asTypeElement
+import androidx.room.ext.getAllMethods
 import androidx.room.ext.hasAnnotation
 import androidx.room.ext.hasAnyOf
 import androidx.room.ext.isType
@@ -42,7 +43,6 @@
 import isAssignableFrom
 import java.util.Locale
 import javax.lang.model.element.Element
-import javax.lang.model.element.ElementKind
 import javax.lang.model.element.Modifier
 import javax.lang.model.element.TypeElement
 import javax.lang.model.type.TypeMirror
@@ -78,8 +78,6 @@
         )
         context.checker.check(extendsRoomDb, element, ProcessorErrors.DB_MUST_EXTEND_ROOM_DB)
 
-        val allMembers = context.processingEnv.elementUtils.getAllMembers(element)
-
         val views = resolveDatabaseViews(viewsMap.values.toList())
         val dbVerifier = if (element.hasAnnotation(SkipQueryVerification::class)) {
             null
@@ -94,8 +92,8 @@
         validateUniqueTableAndViewNames(element, entities, views)
 
         val declaredType = element.asDeclaredType()
-        val daoMethods = allMembers.filter {
-            it.hasAnyOf(Modifier.ABSTRACT) && it.kind == ElementKind.METHOD
+        val daoMethods = element.getAllMethods(context.processingEnv).filter {
+            it.hasAnyOf(Modifier.ABSTRACT)
         }.filterNot {
             // remove methods that belong to room
             val containing = it.enclosingElement
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
index ed0c696..60e3d76 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
@@ -28,7 +28,8 @@
 import androidx.room.ext.findTypeElement
 import androidx.room.ext.getAllFieldsIncludingPrivateSupers
 import androidx.room.ext.getAllMethodsIncludingSupers
-import androidx.room.ext.getLocalAndInheritedMethods
+import androidx.room.ext.getConstructors
+import androidx.room.ext.getAllNonPrivateInstanceMethods
 import androidx.room.ext.hasAnnotation
 import androidx.room.ext.hasAnyOf
 import androidx.room.ext.isAssignableFromWithoutVariance
@@ -74,7 +75,6 @@
 import javax.lang.model.element.VariableElement
 import javax.lang.model.type.DeclaredType
 import javax.lang.model.type.TypeMirror
-import javax.lang.model.util.ElementFilter
 
 /**
  * Processes any class as if it is a Pojo.
@@ -228,17 +228,17 @@
                     }
                 }
 
-        val methods = element.getLocalAndInheritedMethods(context.processingEnv)
-                .filter {
-                    !it.hasAnyOf(PRIVATE, ABSTRACT, STATIC) &&
-                            !it.hasAnnotation(Ignore::class)
-                }.map {
-                    PojoMethodProcessor(
-                            context = context,
-                            element = it,
-                            owner = declaredType
-                    ).process()
-                }
+        val methods = element.getAllNonPrivateInstanceMethods(context.processingEnv)
+            .asSequence()
+            .filter {
+                !it.hasAnyOf(ABSTRACT) && !it.hasAnnotation(Ignore::class)
+            }.map {
+                PojoMethodProcessor(
+                    context = context,
+                    element = it,
+                    owner = declaredType
+                ).process()
+            }.toList()
 
         val getterCandidates = methods.filter {
             it.element.parameters.size == 0 && it.resolvedType.returnType.isNotVoid()
@@ -904,8 +904,7 @@
                 }
         }
 
-        override fun findConstructors(element: TypeElement) = ElementFilter.constructorsIn(
-                element.enclosedElements).filterNot {
+        override fun findConstructors(element: TypeElement) = element.getConstructors().filterNot {
             it.hasAnnotation(Ignore::class) || it.hasAnyOf(PRIVATE)
         }
 
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/ShortcutParameterProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/ShortcutParameterProcessor.kt
index 5b0da19..d41dfdf 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/ShortcutParameterProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/ShortcutParameterProcessor.kt
@@ -18,17 +18,17 @@
 
 import androidx.room.ext.asMemberOf
 import androidx.room.ext.extendsBound
+import androidx.room.ext.getAllNonPrivateInstanceMethods
 import androidx.room.ext.requireTypeMirror
 import androidx.room.vo.ShortcutQueryParameter
 import asDeclaredType
+import asTypeElement
 import isAssignableFrom
 import isType
-import javax.lang.model.element.TypeElement
 import javax.lang.model.element.VariableElement
 import javax.lang.model.type.ArrayType
 import javax.lang.model.type.DeclaredType
 import javax.lang.model.type.TypeMirror
-import javax.lang.model.util.ElementFilter
 
 /**
  * Processes parameters of methods that are annotated with Insert, Update or Delete.
@@ -62,7 +62,6 @@
     private fun extractPojoType(typeMirror: TypeMirror): Pair<TypeMirror?, Boolean> {
 
         val processingEnv = context.processingEnv
-        val elementUtils = context.processingEnv.elementUtils
         val typeUtils = context.processingEnv.typeUtils
 
         fun verifyAndPair(pojoType: TypeMirror, isMultiple: Boolean): Pair<TypeMirror?, Boolean> {
@@ -77,8 +76,7 @@
         }
 
         fun extractPojoTypeFromIterator(iterableType: DeclaredType): TypeMirror {
-            ElementFilter.methodsIn(elementUtils
-                    .getAllMembers(typeUtils.asElement(iterableType) as TypeElement)).forEach {
+            iterableType.asTypeElement().getAllNonPrivateInstanceMethods(processingEnv).forEach {
                 if (it.simpleName.toString() == "iterator") {
                     return it.asMemberOf(typeUtils, iterableType)
                         .returnType
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/autovalue/AutoValuePojoProcessorDelegate.kt b/room/compiler/src/main/kotlin/androidx/room/processor/autovalue/AutoValuePojoProcessorDelegate.kt
index 6c5cca9..a20c5e5 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/autovalue/AutoValuePojoProcessorDelegate.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/autovalue/AutoValuePojoProcessorDelegate.kt
@@ -19,6 +19,7 @@
 import androidx.room.Ignore
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.getAllMethodsIncludingSupers
+import androidx.room.ext.getDeclaredMethods
 import androidx.room.ext.getPackage
 import androidx.room.ext.hasAnnotation
 import androidx.room.ext.hasAnyOf
@@ -37,7 +38,6 @@
 import javax.lang.model.element.Modifier
 import javax.lang.model.element.TypeElement
 import javax.lang.model.type.DeclaredType
-import javax.lang.model.util.ElementFilter
 
 /**
  * Delegate to process generated AutoValue class as a Pojo.
@@ -81,7 +81,7 @@
 
     override fun findConstructors(element: TypeElement): List<ExecutableElement> {
         val typeUtils = context.processingEnv.typeUtils
-        return ElementFilter.methodsIn(autoValueElement.enclosedElements).filter {
+        return autoValueElement.getDeclaredMethods().filter {
             it.hasAnyOf(Modifier.STATIC) &&
                     !it.hasAnnotation(Ignore::class) &&
                     !it.hasAnyOf(Modifier.PRIVATE) &&
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt
index c22f108..0fdcd22 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt
@@ -18,9 +18,9 @@
 
 import androidx.room.RoomProcessor
 import androidx.room.ext.S
+import androidx.room.ext.getGeneratedAnnotation
 import androidx.room.ext.typeName
 import androidx.room.solver.CodeGenScope.Companion.CLASS_PROPERTY_PREFIX
-import com.google.auto.common.GeneratedAnnotations
 import com.squareup.javapoet.AnnotationSpec
 import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.FieldSpec
@@ -66,9 +66,7 @@
         adapterTypeSpecBuilder: TypeSpec.Builder,
         processingEnv: ProcessingEnvironment
     ) {
-        GeneratedAnnotations.generatedAnnotation(
-            processingEnv.elementUtils, processingEnv.sourceVersion
-        ).ifPresent {
+        processingEnv.getGeneratedAnnotation()?.let {
             val generatedAnnotationSpec =
                 AnnotationSpec.builder(ClassName.get(it))
                     .addMember("value", S, RoomProcessor::class.java.canonicalName)
diff --git a/room/compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt b/room/compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
new file mode 100644
index 0000000..b61b312
--- /dev/null
+++ b/room/compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 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 androidx.room.ext
+
+import com.google.common.truth.Truth.assertThat
+import com.google.testing.compile.JavaFileObjects
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import simpleRun
+import javax.lang.model.element.ExecutableElement
+
+@RunWith(JUnit4::class)
+class ElementExtTest {
+    @Test
+    fun methodsInClass() {
+        val parentCode = JavaFileObjects.forSourceLines(
+            "foo.bar.Parent", """
+            package foo.bar;
+
+            public class Parent {
+                public Parent() {}
+                private void parentPrivate() {}
+                public void parentPublic() {}
+                public void overridden() {}
+                private static void parentStaticPrivate() {}
+                public static void parentStaticPublic() {}
+            }
+        """.trimIndent()
+        )
+        val childCode = JavaFileObjects.forSourceLines(
+            "foo.bar.Child", """
+            package foo.bar;
+
+            public class Child extends Parent {
+                public Child() {}
+                private void childPrivate() {}
+                public void childPublic() {}
+                public void overridden() {}
+                private static void childStaticPrivate() {}
+                public static void childStaticPublic() {}
+            }
+        """.trimIndent()
+        )
+        simpleRun(
+            jfos = *arrayOf(parentCode, childCode)
+        ) {
+            val parent = it.processingEnv.requireTypeElement("foo.bar.Parent")
+            val child = it.processingEnv.requireTypeElement("foo.bar.Child")
+            val objectMethods = it.processingEnv.requireTypeElement("java.lang.Object")
+                .getAllMethods(it.processingEnv).map {
+                    it.simpleName.toString()
+                } - "registerNatives"
+            val parentMethods = listOf(
+                "parentPrivate", "parentPublic", "parentStaticPrivate",
+                "parentStaticPublic", "overridden"
+            )
+            val childMethods = listOf(
+                "childPrivate", "childPublic", "childStaticPrivate",
+                "childStaticPublic", "overridden"
+            )
+            assertThat(parent.getDeclaredMethods()).containsExactlyElementsIn(parentMethods)
+            assertThat(parent.getAllMethods(it.processingEnv))
+                .containsExactlyElementsIn(parentMethods + objectMethods)
+            assertThat(parent.getAllNonPrivateInstanceMethods(it.processingEnv))
+                .containsExactlyElementsIn(
+                    parentMethods + objectMethods -
+                            listOf("parentPrivate", "parentStaticPrivate", "parentStaticPublic")
+                )
+
+            assertThat(child.getDeclaredMethods()).containsExactlyElementsIn(
+                childMethods
+            )
+            assertThat(child.getAllMethods(it.processingEnv)).containsExactlyElementsIn(
+                childMethods + parentMethods + objectMethods -
+                        listOf("parentPrivate", "parentStaticPrivate", "overridden") +
+                        "overridden" // add 1 overridden back
+            )
+            assertThat(child.getAllNonPrivateInstanceMethods(it.processingEnv))
+                .containsExactlyElementsIn(
+                    childMethods + parentMethods + objectMethods -
+                            listOf(
+                                "parentPrivate", "parentStaticPrivate", "parentStaticPublic",
+                                "childPrivate", "childStaticPrivate", "childStaticPublic",
+                                "overridden"
+                            ) + "overridden" // add 1 overridden back
+                )
+
+            assertThat(child.getConstructors()).containsExactly("<init>")
+            assertThat(parent.getConstructors()).containsExactly("<init>")
+        }.compilesWithoutError()
+    }
+
+    @Test
+    fun methodsInInterface() {
+        val parentCode = JavaFileObjects.forSourceLines(
+            "foo.bar.Parent", """
+            package foo.bar;
+
+            public interface Parent {
+                public void parentPublic();
+                public void overridden();
+                private static void parentStaticPrivate() {}
+                public static void parentStaticPublic() {}
+            }
+        """.trimIndent()
+        )
+        val childCode = JavaFileObjects.forSourceLines(
+            "foo.bar.Child", """
+            package foo.bar;
+
+            public interface Child extends Parent {
+                public void childPublic();
+                public void overridden();
+                private static void childStaticPrivate() {}
+                public static void childStaticPublic() {}
+            }
+        """.trimIndent()
+        )
+        simpleRun(
+            jfos = *arrayOf(parentCode, childCode)
+        ) {
+            val parent = it.processingEnv.requireTypeElement("foo.bar.Parent")
+            val child = it.processingEnv.requireTypeElement("foo.bar.Child")
+            val objectMethods = it.processingEnv.requireTypeElement("java.lang.Object")
+                .getAllMethods(it.processingEnv).map {
+                    it.simpleName.toString()
+                } - listOf("registerNatives", "clone", "finalize")
+            val parentMethods = listOf(
+                "parentPublic", "parentStaticPrivate", "parentStaticPublic", "overridden"
+            )
+            val childMethods = listOf(
+                "childPublic", "childStaticPrivate", "childStaticPublic", "overridden"
+            )
+            assertThat(parent.getDeclaredMethods())
+                .containsExactlyElementsIn(parentMethods)
+            assertThat(parent.getAllMethods(it.processingEnv))
+                .containsExactlyElementsIn(parentMethods + objectMethods)
+            assertThat(parent.getAllNonPrivateInstanceMethods(it.processingEnv))
+                .containsExactly("parentPublic", "overridden")
+
+            assertThat(child.getDeclaredMethods())
+                .containsExactlyElementsIn(childMethods)
+            assertThat(child.getAllMethods(it.processingEnv)).containsExactlyElementsIn(
+                childMethods + parentMethods + objectMethods -
+                        listOf("parentStaticPrivate", "parentStaticPublic", "overridden") +
+                        "overridden" // add 1 overridden back
+            )
+            assertThat(child.getAllNonPrivateInstanceMethods(it.processingEnv))
+                .containsExactly(
+                    "childPublic", "parentPublic", "overridden"
+                )
+
+            assertThat(child.getConstructors()).isEmpty()
+            assertThat(parent.getConstructors()).isEmpty()
+        }.compilesWithoutError()
+    }
+
+    private fun assertThat(executables: Iterable<ExecutableElement>) = assertThat(
+        executables.map { it.simpleName.toString() }
+    )
+}
\ No newline at end of file
diff --git a/room/compiler/src/test/kotlin/androidx/room/kotlin/KotlinMetadataElementTest.kt b/room/compiler/src/test/kotlin/androidx/room/kotlin/KotlinMetadataElementTest.kt
index bf1fb1c..c99a86d 100644
--- a/room/compiler/src/test/kotlin/androidx/room/kotlin/KotlinMetadataElementTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/kotlin/KotlinMetadataElementTest.kt
@@ -16,8 +16,10 @@
 
 package androidx.room.kotlin
 
-import androidx.room.ext.requireTypeElement
 import androidx.room.ext.asExecutableElement
+import androidx.room.ext.getConstructors
+import androidx.room.ext.getDeclaredMethods
+import androidx.room.ext.requireTypeElement
 import androidx.room.processor.Context
 import androidx.room.testing.TestInvocation
 import com.google.common.truth.Truth.assertThat
@@ -25,7 +27,6 @@
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 import simpleRun
-import javax.lang.model.util.ElementFilter
 import kotlin.reflect.KClass
 
 @RunWith(JUnit4::class)
@@ -38,7 +39,7 @@
                 invocation,
                 TestData::class
             )
-            assertThat(ElementFilter.methodsIn(testClassElement.enclosedElements)
+            assertThat(testClassElement.getDeclaredMethods()
                 .first { it.simpleName.toString() == "functionWithParams" }
                 .let { metadataElement.getParameterNames(it.asExecutableElement()) }
             ).isEqualTo(
@@ -55,7 +56,7 @@
                 TestData::class
             )
             assertThat(
-                ElementFilter.constructorsIn(testClassElement.enclosedElements).map {
+                testClassElement.getConstructors().map {
                     val desc = it.asExecutableElement().descriptor()
                     desc to (desc == metadataElement.findPrimaryConstructorSignature())
                 }
@@ -73,7 +74,7 @@
                 invocation,
                 TestData::class
             )
-            assertThat(ElementFilter.methodsIn(testClassElement.enclosedElements).map {
+            assertThat(testClassElement.getDeclaredMethods().map {
                 val executableElement = it.asExecutableElement()
                 executableElement.simpleName.toString() to metadataElement.isSuspendFunction(
                     executableElement
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/CustomConverterProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/CustomConverterProcessorTest.kt
index c2e98ff..5fef51b 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/CustomConverterProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/CustomConverterProcessorTest.kt
@@ -20,8 +20,7 @@
 import androidx.room.ext.requireTypeElement
 import androidx.room.ext.typeName
 import androidx.room.processor.ProcessorErrors.TYPE_CONVERTER_EMPTY_CLASS
-import androidx.room.processor.ProcessorErrors
-        .TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR
+import androidx.room.processor.ProcessorErrors.TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR
 import androidx.room.processor.ProcessorErrors.TYPE_CONVERTER_MUST_BE_PUBLIC
 import androidx.room.processor.ProcessorErrors.TYPE_CONVERTER_UNBOUND_GENERIC
 import androidx.room.testing.TestInvocation
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt
index 8f186bc..f35bdf5 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt
@@ -20,6 +20,7 @@
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.asTypeElement
 import androidx.room.ext.asVariableElement
+import androidx.room.ext.getAllFieldsIncludingPrivateSupers
 import androidx.room.ext.requireTypeMirror
 import androidx.room.parser.Collate
 import androidx.room.parser.SQLTypeAffinity
@@ -41,7 +42,6 @@
 import org.mockito.Mockito.mock
 import simpleRun
 import javax.lang.model.element.Element
-import javax.lang.model.element.ElementKind
 import javax.lang.model.type.TypeKind
 import javax.lang.model.type.TypeMirror
 
@@ -440,9 +440,10 @@
                             val (owner, fieldElement) = invocation.roundEnv
                                     .getElementsAnnotatedWith(Entity::class.java)
                                     .map {
-                                        Pair(it, invocation.processingEnv.elementUtils
-                                                .getAllMembers(it.asTypeElement())
-                                                .firstOrNull { it.kind == ElementKind.FIELD })
+                                        Pair(it, it.asTypeElement()
+                                            .getAllFieldsIncludingPrivateSupers(
+                                                invocation.processingEnv
+                                            ).firstOrNull())
                                     }
                                     .first { it.second != null }
                             val entityContext =
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/InsertionMethodProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/InsertionMethodProcessorTest.kt
index ea9d973..e146b71 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/InsertionMethodProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/InsertionMethodProcessorTest.kt
@@ -26,6 +26,7 @@
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.asExecutableElement
 import androidx.room.ext.asTypeElement
+import androidx.room.ext.getAllMethods
 import androidx.room.ext.hasAnnotation
 import androidx.room.ext.typeName
 import androidx.room.solver.shortcut.result.InsertMethodAdapter
@@ -761,16 +762,16 @@
                         .forAnnotations(Insert::class, Dao::class)
                         .nextRunHandler { invocation ->
                             val (owner, methods) = invocation.roundEnv
-                                    .getElementsAnnotatedWith(Dao::class.java)
-                                    .map {
-                                        Pair(it,
-                                                invocation.processingEnv.elementUtils
-                                                        .getAllMembers(it.asTypeElement())
-                                                        .filter {
-                                                            it.hasAnnotation(Insert::class.java)
-                                                        }
-                                        )
-                                    }.first { it.second.isNotEmpty() }
+                                .getElementsAnnotatedWith(Dao::class.java)
+                                .map {
+                                    Pair(it,
+                                        it.asTypeElement().getAllMethods(
+                                            invocation.processingEnv
+                                        ).filter {
+                                            it.hasAnnotation(Insert::class.java)
+                                        }
+                                    )
+                                }.first { it.second.isNotEmpty() }
                             val processor = InsertionMethodProcessor(
                                     baseContext = invocation.context,
                                     containing = owner.asDeclaredType(),
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
index c884e24..711e36a 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
@@ -26,6 +26,7 @@
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.asExecutableElement
 import androidx.room.ext.asTypeElement
+import androidx.room.ext.getAllMethods
 import androidx.room.ext.hasAnnotation
 import androidx.room.ext.requireTypeMirror
 import androidx.room.ext.typeName
@@ -984,11 +985,11 @@
                         .getElementsAnnotatedWith(Dao::class.java)
                         .map {
                             Pair(it,
-                                invocation.processingEnv.elementUtils
-                                    .getAllMembers(it.asTypeElement())
-                                    .filter {
-                                        it.hasAnnotation(Query::class)
-                                    }
+                                it.asTypeElement().getAllMethods(
+                                    invocation.processingEnv
+                                ).filter {
+                                    it.hasAnnotation(Query::class)
+                                }
                             )
                         }.first { it.second.isNotEmpty() }
                     val verifier = if (enableVerification) {
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
index 77765ac..60f2877 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
@@ -28,6 +28,8 @@
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.asExecutableElement
 import androidx.room.ext.asTypeElement
+import androidx.room.ext.getAllMethods
+import androidx.room.ext.getDeclaredMethods
 import androidx.room.ext.hasAnnotation
 import androidx.room.ext.requireTypeElement
 import androidx.room.ext.typeName
@@ -47,7 +49,6 @@
 import org.hamcrest.MatcherAssert.assertThat
 import org.junit.Test
 import simpleRun
-import javax.lang.model.util.ElementFilter
 
 class RawQueryMethodProcessorTest {
     @Test
@@ -200,7 +201,7 @@
         simpleRun { invocation ->
             val daoElement =
                 invocation.processingEnv.requireTypeElement(RawQuerySuspendUnitDao::class)
-            val daoFunctionElement = ElementFilter.methodsIn(daoElement.enclosedElements).first()
+            val daoFunctionElement = daoElement.getDeclaredMethods().first()
             RawQueryMethodProcessor(
                 baseContext = invocation.context,
                 containing = daoElement.asDeclaredType(),
@@ -315,11 +316,11 @@
                                     .getElementsAnnotatedWith(Dao::class.java)
                                     .map {
                                         Pair(it,
-                                                invocation.processingEnv.elementUtils
-                                                        .getAllMembers(it.asTypeElement())
-                                                        .filter {
-                                                            it.hasAnnotation(RawQuery::class)
-                                                        }
+                                                it.asTypeElement().getAllMethods(
+                                                    invocation.processingEnv
+                                                ).filter {
+                                                    it.hasAnnotation(RawQuery::class)
+                                                }
                                         )
                                     }.first { it.second.isNotEmpty() }
                             val parser = RawQueryMethodProcessor(
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/ShortcutMethodProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/ShortcutMethodProcessorTest.kt
index 8a7fe70..c534f7a 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/ShortcutMethodProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/ShortcutMethodProcessorTest.kt
@@ -25,6 +25,7 @@
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.asExecutableElement
 import androidx.room.ext.asTypeElement
+import androidx.room.ext.getAllMethods
 import androidx.room.ext.hasAnnotation
 import androidx.room.ext.typeName
 import androidx.room.testing.TestInvocation
@@ -473,11 +474,11 @@
                                     .getElementsAnnotatedWith(Dao::class.java)
                                     .map {
                                         Pair(it,
-                                                invocation.processingEnv.elementUtils
-                                                        .getAllMembers(it.asTypeElement())
-                                                        .filter {
-                                                            it.hasAnnotation(annotation)
-                                                        }
+                                            it.asTypeElement().getAllMethods(
+                                                invocation.processingEnv
+                                            ).filter {
+                                                it.hasAnnotation(annotation)
+                                            }
                                         )
                                     }.first { it.second.isNotEmpty() }
                             val processed = process(
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/TransactionMethodProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/TransactionMethodProcessorTest.kt
index 67c7a61..1e46eb3 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/TransactionMethodProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/TransactionMethodProcessorTest.kt
@@ -22,6 +22,7 @@
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.asExecutableElement
 import androidx.room.ext.asTypeElement
+import androidx.room.ext.getAllMethods
 import androidx.room.ext.hasAnnotation
 import androidx.room.testing.TestInvocation
 import androidx.room.testing.TestProcessor
@@ -240,11 +241,11 @@
                                     .getElementsAnnotatedWith(Dao::class.java)
                                     .map {
                                         Pair(it,
-                                                invocation.processingEnv.elementUtils
-                                                        .getAllMembers(it.asTypeElement())
-                                                        .filter {
-                                                            it.hasAnnotation(Transaction::class)
-                                                        }
+                                            it.asTypeElement().getAllMethods(
+                                                invocation.processingEnv
+                                            ).filter {
+                                                it.hasAnnotation(Transaction::class)
+                                            }
                                         )
                                     }.first { it.second.isNotEmpty() }
                             val processor = TransactionMethodProcessor(
diff --git a/room/compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt b/room/compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt
index 68754ec..793b2de 100644
--- a/room/compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt
@@ -23,6 +23,7 @@
 import androidx.room.ext.asDeclaredType
 import androidx.room.ext.asExecutableElement
 import androidx.room.ext.asTypeElement
+import androidx.room.ext.getAllMethods
 import androidx.room.ext.hasAnnotation
 import androidx.room.processor.QueryMethodProcessor
 import androidx.room.testing.TestProcessor
@@ -305,11 +306,11 @@
                                     .getElementsAnnotatedWith(Dao::class.java)
                                     .map {
                                         Pair(it,
-                                                invocation.processingEnv.elementUtils
-                                                        .getAllMembers(it.asTypeElement())
-                                                        .filter {
-                                                            it.hasAnnotation(Query::class)
-                                                        }
+                                            it.asTypeElement().getAllMethods(
+                                                invocation.processingEnv
+                                            ).filter {
+                                                it.hasAnnotation(Query::class)
+                                            }
                                         )
                                     }.first { it.second.isNotEmpty() }
                             val parser = QueryMethodProcessor(