profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/JakeWharton/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.
Jake Wharton JakeWharton Square Pittsburgh, PA, USA https://jakewharton.com

JakeWharton/butterknife 25625

Bind Android views and callbacks to fields and methods.

JakeWharton/ActionBarSherlock 7183

[DEPRECATED] Action bar implementation which uses the native action bar on Android 4.0+ and a custom implementation on pre-4.0 through a single API and theme.

cashapp/sqldelight 3797

SQLDelight - Generates typesafe Kotlin APIs from SQL

androidx/androidx 2496

Development environment for Android Jetpack extension libraries under the androidx namespace. Synchronized with Android Jetpack's primary development branch on AOSP.

JakeWharton/Android-DirectionalViewPager 1040

[DEPRECATED] Implementation of the compatibility library ViewPager class that supports paging both vertically and horizontally.

cashapp/duktape-android 807

The Duktape embeddable Javascript engine packaged for Android.

JakeWharton/adb-event-mirror 800

Mirror the touch/key/button events of one device onto one or more other devices in real-time

JakeWharton/dagger-reflect 631

A reflection-based implementation of the Dagger dependency injection library for fast IDE builds.

JakeWharton/dependency-tree-diff 552

An intelligent diff tool for the output of Gradle's dependencies task

JakeWharton/confundus 230

Kotlin compiler plugin which brings Kotlin/JS's unsafeCast to Kotlin/JVM

startedJakeWharton/NineOldAndroids

started time in 2 minutes

push eventoznu/docker-cloudflare-ddns

Tomás Warynyca

commit sha da678bf65978a0e3f516aa5890389e2ed2235e53

Upgrade to Alpine 3.13

view details

oznu

commit sha ee6dde2793f0fc17b4917bb4caa9ac32dfcc2635

Merge pull request #61 from tomaswarynyca/patch-1 Upgrade to Alpine 3.13

view details

push time in 32 minutes

issue commentjordanpotter/docker-wireguard

Local dns server

It seems I cannot add custom iptables rules because they are followed in order. I would need to remove the default reject rule to add custom ones and then re-add the default reject rule again.

This means the image need to be adjusted and I haven't dug into that part of Docker yet. 😛

Add allow LAN rules with an environment variable maybe? 🤔

Yrlish

comment created time in 35 minutes

issue commentKotlin/kotlinx.serialization

Default serializer for sealed types if input has no explicit type

Is it possible to use this for a sealed type without creating a serializers module?

For an open type, creating a serializers module is already required, but it seems that in order to use this with a sealed type, you need to create a module (when you would otherwise not need to).

charleskorn

comment created time in an hour

push eventJetBrains/kotlin

Nikolay Krasko

commit sha 3022fb396b4f117f0f4837939aab11921a8e4541

Add fasutil to the list of package to relocate (KT-44758) #KT-44758 Fixed

view details

push time in an hour

push eventUweTrottmann/SeriesGuide

Uwe Trottmann

commit sha 9be6ef0682f4272d0dc1f59904d7778d98fd62ec

Allow removal of legacy show if connected to Cloud.

view details

push time in 2 hours

startedJakeWharton/pidcat

started time in 2 hours

issue commentoznu/docker-cloudflare-ddns

Add Support for Multiple Sub Domains

SUBDOMAIN=subdomain,secondsubdomain,third,etc

that would be wonderful

cfitzw

comment created time in 2 hours

issue commentsquare/okhttp

IllegalArgumentException for the url in the Cache Entry

Thanks @yschimke for improving the logging in #6495 for the next release. In the meantime what could we do to progress on this issue? If the issue is detected on the reading side, maybe we could try to detect it even earlier, meaning at the writing side ? Maybe HttpUrl.url is invalid...

brunoescalona

comment created time in 2 hours

PR opened square/okhttp

Add test for empty scheme with delimiter

Test case related to cache corruption found in #6453

+1 -0

0 comment

1 changed file

pr created time in 3 hours

issue commentjordanpotter/docker-wireguard

Unable to access WebUIs of containers routed through this container

As this docker's iptables only blocks outgoing traffic. This means setting up a reverse proxy into this container will work fine. I have a few containers running behind this wireguard all configured with a docker-compose file.

Here is an example:

---
version: "2.1"
services:
  swag:
    image: ghcr.io/linuxserver/swag
    container_name: swag
    cap_add:
      - NET_ADMIN
    environment:
      - ...
    volumes:
      - ./data/swag:/config
    ports:
      - 443:443
      - 80:80
    restart: unless-stopped

  wireguard:
    image: jordanpotter/wireguard:2.0.1
    container_name: wireguard
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    volumes:
      - ./data/vpn.conf:/etc/wireguard/wg0.conf
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped

  whatever: # e.g. runs a service on port 8123
    image: ...
    container_name: whatever
    depends_on:
      - "wireguard"
    network_mode: "service:wireguard"
    environment:
      - ...
    restart: unless-stopped

Lets say the container whatever have a service running on port 8123 inside it. As whatever is configured with network_mode: "service:wireguard" we need to access it through the container wireguard, as in http://wireguard:8123/. Either you map the port on the wireguard container with -p 8123:8123 or you use a separate container for reverse proxying, in which do not need to map the port.

I am using linuxserver/docker-swag for reverse proxying, it has a bunch of nice stuff in it out of the box. Swag has a bunch of reverse proxy configurations bundled with it sourced from linuxserver/reverse-proxy-confs. What you need to remember to do, is to change the nginx site configuration from whatever hostname is in it to wireguard, e.g. set $upstream_app whatever; to set $upstream_app wireguard;

In easier terms, basically change proxy_pass http://whatever:8123; to proxy_pass http://wireguard:8123;.

rafajrichard

comment created time in 3 hours

push eventgoogle/desugar_jdk_libs

Donald Duo Zhao

commit sha e9a22c9d90121b4ef9402806aca6ecf8c5a8ea0f

Move `DesugarUnsafe` to `sun/misc/` package #desugar_jdk_libs #java11 - Keep `Desugar<X>` classes in the same package as its origin `<X>`. This is to easy track desugar-specific `Desugar<X>` classes, as well as keeping `Desugar<X>` with the same class and member visibility as its origin `<X>`, and maintaining package-level dependency graph the same as the OpenJDK version. - Starter-example CL as including non `java/`-prefixed classes in `desugar_jdk_libs` PiperOrigin-RevId: 359904867

view details

push time in 4 hours

push eventJetBrains/kotlin

Steven Schäfer

commit sha 482e217b5e96fbb7422f96e02202eb0ff35c6999

JVM IR: Fix inline class mangling for calls to internal functions ...in a different module, e.g., using -Xfriend-paths.

view details

Mikhael Bogdanov

commit sha be9ef8f3c84dbdc0ef706a9cacae405a8812a479

Remove obsolete DxChecker

view details

Mikhael Bogdanov

commit sha 6a29097a8caa8c7299bc43f6441b3026bbaa5493

Remove obsolete dependency for dx

view details

Sergey Igushkin

commit sha 021a63827d40b1ecfd1b0ded8e9f38d64d2732d8

Add API version 1.5 to accepted values in MPP language settings

view details

Dmitriy Novozhilov

commit sha 21f022dec295686ba31f93136c26dd73e58c1cd8

Add :kotlin-scripting-compiler.test to modules with disabled -Werror flag

view details

Mikhael Bogdanov

commit sha 9f9c8e3d778bcdfff6b1d41a1cc5509818da130c

Mute stream api test on Android

view details

Alexander Udalov

commit sha 2bbe3db0411d51f0cbd79e4d622f525e46cab03b

Update copyrights in CLI scripts

view details

Alexander Udalov

commit sha 2ef4ca4e6e743e3e787a74de5f02cebd66e8e123

CLI: do not pass -noverify to java process starting from JDK 13 #KT-44232 Fixed

view details

Alexander Udalov

commit sha f08733eb7530526cc3f37e099aebee8ee1e9c484

CLI: suppress warning on JDK 9+ with illegal access to ResourceBundle The underlying issue is tracked in IDEA-248785. #KT-43704 Fixed

view details

Alexander Udalov

commit sha e7cf34a2a97a3070876e8f4ed40d9e85409be938

Workaround illegal access problem in daemon for JDK 17-ea Otherwise Kotlin cannot be used in Gradle since https://github.com/openjdk/jdk/commit/ed4c4ee7 where JDK internals started to be encapsulated by default. For some reason, using listOf("--add-opens", "java.base/java.util=ALL-UNNAMED") doesn't help, so use the more general `--illegal-access=permit`. #KT-43704

view details

Alexander Gorshenev

commit sha 16b3fedcd4f363c1afdc5810a4dd8beb6ff4e46a

Created AbstractKlibBinaryCompatibilityTest and AbstractJsKlibBinaryCompatibilityTest A common test runner for klib binary compatibility tests and its js counterpart

view details

Alexander Gorshenev

commit sha 6265ac8c198a39aa536b4f976b95833098cd03bf

Re-enabled disabled test

view details

Dmitriy Novozhilov

commit sha 772ca2715c74fddeee95e5a9fddd10251c71bb7f

[Test] Don't change testdata in FirIdenticalChecker in teamcity mode

view details

Dmitriy Novozhilov

commit sha 297288e98484ddf21a7a1444ad17d7268bb026bd

[Test] Don't generate new files in GeneratorsFileUtil in teamcity mode

view details

Dmitriy Novozhilov

commit sha 771600077cadad50bc9a32e53f322944fbf358b6

[Test] Fail if there are changes in generated fir tree files in teamcity build

view details

Ivan Gavrilovic

commit sha 509ed64917a72f562047458c4fd13dce3407d440

KT-43686: Make kapt Gradle task cacheable across machines Use `@Classpath` for kotlin stdlib input property. This is to allow cache hits when builds are running on different machines and path to kotlin stdlib differs. Test: BuildCacheRelocationIT

view details

Alexander Udalov

commit sha d022bb0248a3f199ea0bc671b93dc30c5052c292

Switch default JVM target to 1.8 #KT-29405 Fixed

view details

Alexander Udalov

commit sha 64e97225b8aefb2156b08a8af22e047a2d7379d8

Light classes: map annotation targets depending on JVM target Since the default JVM target (`JvmTarget.DEFAULT`) is now 1.8, the changed test started to fail. This change fixes it.

view details

Alexander Udalov

commit sha adfa8c788ca97e4ba173fc51a10853171ff0f62b

Light classes: use JVM target from the module Using "JVM_1_8" always resulted in incorrect mapping of Kotlin annotation targets to Java element types. The change in AbstractKotlinRenderLogTest is needed because while CliTraceHolder.module is technically a descriptor leak, it was never detected by this test accidentally, because of the depth cutoff equal to 10, which started to not be enough after the minor refactoring of replacing `Delegates.notNull` with `lateinit`.

view details

Alexander Udalov

commit sha e9436da858e0b49f7d3a34b397c5b705fd71347e

Change logic of applying JVM target from AGP options Now that the default JVM target is 1.8, we have to add the JVM target 1.6 explicitly if the Android project is configured with source/target 1.6, and not do anything if it's configured with 1.8. #KT-31027

view details

push time in 5 hours

push eventandroidx/androidx

Yigit Boyar

commit sha fc9df1181ed75a213c28b917d96adc4076163aa7

Incremental processing for KSP This CL adds incremental compilation for the KSP backend. We do not respect the `room.incremental` flag since it was added to initially enable incremental java annotation processing and KSP is a new backend hence we should always be incremental. (developer can still turn it off for all of KSP). The way we collect these files is a bit hacky because it requires us to wrap a KSFile into a javax.model.Element because the only API available in JavaPoet receives javax.model.Element. An alternative implementation could abstract JavaPoet but it would be a more complicated change. There is a KI in KSP: https://github.com/google/ksp/issues/332 * KSP does not delete previous outputs if originating files are deleted. That test is disabled for now until there is a new KSP release with the fix. This does not easily reproduce in a sample app but does reproduce in our testing setup. Bug: 176453350 Test: RoomIncrementalAnnotationProcessingTest RelNote: Added incremental compilation support for KSP. Change-Id: I031c1f94890ebe2a382c26f7f0745edb790a5a7b

view details

Treehugger Robot

commit sha bdcb2e8cda94281d314eec3c18bb7a4d2581aa2a

Merge "Incremental processing for KSP" into androidx-main

view details

push time in 5 hours

pull request commentJetBrains/kotlin

FIR checker: introduce *_NOT_IMPLEMENTED override checker

I measured performance, and looks like this checker takes about 2.5-3 seconds, where ~60 seconds is the time of the whole FIR FE work = Raw FIR building + all resolve stages. May be it should be so, but we at least should think can we optimize it or not.

Too bad to hear that it will add 5% performance overhead. :( Nothing came to me right now, but will keep that in mind.

jsjeon

comment created time in 5 hours

Pull request review commentJetBrains/kotlin

FIR checker: introduce *_NOT_IMPLEMENTED override checker

+/*+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.+ */++package org.jetbrains.kotlin.fir.analysis.checkers.declaration++import org.jetbrains.kotlin.descriptors.Modality+import org.jetbrains.kotlin.descriptors.Visibilities+import org.jetbrains.kotlin.fir.*+import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext+import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass+import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors+import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn+import org.jetbrains.kotlin.fir.declarations.*+import org.jetbrains.kotlin.fir.scopes.*+import org.jetbrains.kotlin.fir.scopes.impl.unwrapDelegateTarget+import org.jetbrains.kotlin.fir.symbols.CallableId+import org.jetbrains.kotlin.fir.symbols.impl.*+import org.jetbrains.kotlin.fir.types.*+import org.jetbrains.kotlin.name.Name++object FirNotImplementedOverrideChecker : FirClassChecker() {+    // TODO: differentiate members with different annotations, e.g., @Api...(x) @Api...(y)+    // TODO: differentiate parameter names? e.g., foo(x : T) v.s. override foo(y : T)+    private object SignaturePresenter : FirDeclarationPresenter {+        override fun StringBuilder.appendRepresentation(it: CallableId) {+            append(it.callableName)+        }+    }++    private fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =+        this.unsubstitutedScope(context.sessionHolder.session, context.sessionHolder.scopeSession, withForcedTypeCalculator = true)++    // TODO: Collection extensions are not properly regarded as an override. Should not have a whitelist like this.+    private val COLLECTIONS = listOf("java.util", "kotlin.collections")++    override fun check(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {+        // TODO: kt4763Property: reporting on `object` literal causes invalid error in test...FirDiagnosticHandler+        if (declaration is FirAnonymousObject) return++        val source = declaration.source ?: return+        if (source.kind is FirFakeSourceElementKind) return++        val contributedMembers = collectCallableMembers(declaration, context)+        val potentialFakeOverrides = getBaseDeclarationsForFakeOverrides(declaration, contributedMembers, context)++        // TODO: consider open as overridable, and check conflicts as well+        val abstractFakeOverrides = potentialFakeOverrides.filter {+            it is FirMemberDeclaration &&+                    it.isAbstract &&+                    // TODO: FIR MPP support+                    (it.getContainingClass(context) as? FirRegularClass)?.isExpect == false+        }+        if (abstractFakeOverrides.isEmpty()) return++        // TODO: differentiate type-substituted declarations. Otherwise, they will be reported as MANY_IMPL_MEMBER_NOT_IMPLEMENTED+        val sigToDeclarations = mutableMapOf<String, MutableList<FirCallableDeclaration<*>>>()+        for (abstractFakeOverride in abstractFakeOverrides) {+            val sig = when (abstractFakeOverride) {+                is FirSimpleFunction -> SignaturePresenter.represent(abstractFakeOverride)+                is FirProperty -> SignaturePresenter.represent(abstractFakeOverride)+                else -> continue+            }+            sigToDeclarations.computeIfAbsent(sig) { mutableListOf() }.add(abstractFakeOverride)+        }++        val canHaveAbstractMembers = declaration is FirRegularClass && declaration.canHaveAbstractFakeOverride+        // var alreadyReportedManyNotImplemented = false+        var alreadyReportedAbstractNotImplemented = false+        for (fakeOverrides in sigToDeclarations.values) {+            if (fakeOverrides.size > 1) {+                // TODO: MANY_* as well as some conflict diagnostics+/*+                if (alreadyReportedManyNotImplemented) continue+                val representative = fakeOverrides.first()+                if (fakeOverrides.any { it.isFromInterface(context) }) {+                    reporter.reportOn(source, FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                } else {+                    reporter.reportOn(source, FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                }+                alreadyReportedManyNotImplemented = true+*/+            } else {+                assert(fakeOverrides.size == 1)+                val notImplemented = fakeOverrides.single()+                if ((notImplemented as? FirMemberDeclaration)?.isAbstract != true) continue+                if (canHaveAbstractMembers || alreadyReportedAbstractNotImplemented) continue++                val notImplementedFunction = notImplemented as? FirSimpleFunction+                // TODO: suspend function overridden by a Java class in the middle is not properly regarded as an override.+                if (notImplementedFunction?.isSuspend == true) continue+                // TODO: Collection extensions are not properly regarded as an override.+                val originalPackage =+                    notImplementedFunction?.originalIfFakeOverride()?.dispatchReceiverType?.classId?.packageFqName?.asString()+                if (originalPackage in COLLECTIONS) continue++                if (notImplemented.isFromInterface(context)) {+                    reporter.reportOn(source, FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)+                } else {+                    reporter.reportOn(source, FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)+                }+                alreadyReportedAbstractNotImplemented = true+            }+        }+    }++    private fun FirCallableDeclaration<*>.isFromInterface(context: CheckerContext): Boolean =+        (getContainingClass(context) as? FirRegularClass)?.isInterface == true++    private fun collectCallableMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> =+        firClass.declarations.filterIsInstance<FirCallableDeclaration<*>>() ++                dataClassMembers(firClass, context) ++                delegatedMembers(firClass, context)++    private val FirSimpleFunction.matchesEqualsSignature: Boolean+        get() = valueParameters.size == 1 && valueParameters[0].returnTypeRef.coneType.isNullableAny &&+                returnTypeRef.coneType.isBoolean++    private val FirSimpleFunction.matchesHashCodeSignature: Boolean+        get() = valueParameters.isEmpty() &&+                returnTypeRef.coneType.isInt++    private val FirSimpleFunction.matchesToStringSignature: Boolean+        get() = valueParameters.isEmpty() &&+                returnTypeRef.coneType.isString++    private val FirSimpleFunction.matchesDataClassSyntheticMemberSignatures: Boolean+        get() = (this.name == EQUALS_NAME && matchesEqualsSignature) ||+                (this.name == HASHCODE_NAME && matchesHashCodeSignature) ||+                (this.name == TOSTRING_NAME && matchesToStringSignature)++    private val SYNTHETIC_NAMES = listOf(EQUALS_NAME, HASHCODE_NAME, TOSTRING_NAME)++    // See [DataClassMembersGenerator#generate]+    // But, this one doesn't create IR counterparts. We just need what synthetic members would be generated for data/inline classes.+    private fun dataClassMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> {+        if (firClass !is FirRegularClass || (!firClass.isData && !firClass.isInline)) return emptyList()++        val contributedInThisType = firClass.declarations.mapNotNull {+            if (it is FirSimpleFunction && it.matchesDataClassSyntheticMemberSignatures) {+                it.name+            } else+                null+        }++        val contributedInSupertypes = mutableMapOf<Name, FirCallableDeclaration<*>>()+        val classScope = firClass.unsubstitutedScope(context)+        for (name in SYNTHETIC_NAMES) {+            classScope.processFunctionsByName(name) {+                val declaration = it.fir+                if (declaration.matchesDataClassSyntheticMemberSignatures && declaration.modality != Modality.FINAL) {+                    contributedInSupertypes.putIfAbsent(declaration.name, declaration)+                }+            }+        }++        val result = mutableListOf<FirCallableDeclaration<*>>()+        for (name in SYNTHETIC_NAMES) {+            if (name in contributedInThisType) continue+            contributedInSupertypes[name]?.let { result.add(it) }+        }+        return result+    }++    // See [DelegatedMemberGenerator#generate]+    // But, this one doesn't create IR counterparts. We just need what members could be delegated to avoid false fake overrides.+    private fun delegatedMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> {+        val delegations = firClass.declarations.filterIsInstance<FirField>().filter { it.isSynthetic }+        val delegation = delegations.singleOrNull() ?: return emptyList()++        val result = mutableListOf<FirCallableDeclaration<*>>()+        val classLookupTag = firClass.symbol.toLookupTag()+        val classScope = firClass.unsubstitutedScope(context)++        classScope.processAllFunctions { functionSymbol ->+            val unwrapped =+                functionSymbol.unwrapDelegateTarget(classLookupTag, classScope::getDirectOverriddenFunctions, delegation, firClass)+                    ?: return@processAllFunctions++            if (unwrapped.isJavaDefault) {+                return@processAllFunctions+            }++            result.add(functionSymbol.fir)+        }++        classScope.processAllProperties { propertySymbol ->+            if (propertySymbol !is FirPropertySymbol) return@processAllProperties++            propertySymbol.unwrapDelegateTarget(classLookupTag, classScope::getDirectOverriddenProperties, delegation, firClass)+                ?: return@processAllProperties++            result.add(propertySymbol.fir)+        }++        return result+    }++    // See [FakeOverrideGenerator#getFakeOverrides]+    // But, this one doesn't create fake overrides. We just need what _base_ declarations will be referred by fake overrides.+    private fun getBaseDeclarationsForFakeOverrides(+        firClass: FirClass<*>,+        contributedDeclarations: Collection<FirDeclaration>,+        context: CheckerContext+    ): Collection<FirCallableDeclaration<*>> {+        val result = mutableListOf<FirCallableDeclaration<*>>()+        val classScope = firClass.unsubstitutedScope(context)++        fun checkFunctionSymbolAndAddToResult(originalSymbol: FirCallableSymbol<*>) {+            if (shouldCreateFakeOverridden<FirSimpleFunction, FirNamedFunctionSymbol>(firClass, originalSymbol, contributedDeclarations)) {+                result.add(originalSymbol.fir)+            }+        }++        fun checkPropertySymbolAndAddToResult(originalSymbol: FirCallableSymbol<*>) {+            if (shouldCreateFakeOverridden<FirProperty, FirPropertySymbol>(firClass, originalSymbol, contributedDeclarations)) {+                result.add(originalSymbol.fir)+            }+        }++        val superTypesCallableNames = classScope.getCallableNames()+        for (name in superTypesCallableNames) {+            classScope.processFunctionsByName(name) { functionSymbol ->+                // TODO: MANY_* as well as some conflict diagnostics+                //if (functionSymbol is FirIntersectionOverrideFunctionSymbol)+                //    functionSymbol.intersections.forEach(::checkFunctionSymbolAndAddToResult)+                //else+                checkFunctionSymbolAndAddToResult(functionSymbol)+            }++            classScope.processPropertiesByName(name) { propertySymbol ->+                // TODO: MANY_* as well as some conflict diagnostics+                //if (propertySymbol is FirIntersectionOverridePropertySymbol)+                //    propertySymbol.intersections.forEach(::checkPropertySymbolAndAddToResult)+                //else+                checkPropertySymbolAndAddToResult(propertySymbol)+            }+        }++        return result+    }++    // See [FakeOverrideGenerator#createFakeOverriddenIfNeeded]+    private inline fun <reified D : FirCallableMemberDeclaration<D>, reified S : FirCallableSymbol<D>> shouldCreateFakeOverridden(+        firClass: FirClass<*>,+        originalSymbol: FirCallableSymbol<*>,+        contributedDeclarations: Collection<FirDeclaration>,+    ): Boolean {+        if (originalSymbol !is S || originalSymbol.fir in contributedDeclarations) return false+        val classLookupTag = firClass.symbol.toLookupTag()+        val originalDeclaration = originalSymbol.fir+        if (originalSymbol.dispatchReceiverClassOrNull() == classLookupTag && !originalDeclaration.origin.fromSupertypes) return false+        if (originalDeclaration.visibility == Visibilities.Private) return false+        return when {+            originalSymbol.fir.origin.fromSupertypes && originalSymbol.dispatchReceiverClassOrNull() == classLookupTag -> {

If this will return that boolean result, yes, that's right. I intentionally maintain this structure to align with FakeOverrideGenerator since we need more accurate base symbols for substitute/intersection cases. Noticed this https://github.com/JetBrains/kotlin/commit/cf830887ec13b4b5e0d9f7b6ce46b6c6990ca1e0 too; changed the check to use that as well; and rewrote a bit to collect base symbols for substitute/intersection cases as well.

jsjeon

comment created time in 5 hours

Pull request review commentJetBrains/kotlin

FIR checker: introduce *_NOT_IMPLEMENTED override checker

+/*+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.+ */++package org.jetbrains.kotlin.fir.analysis.checkers.declaration++import org.jetbrains.kotlin.descriptors.Modality+import org.jetbrains.kotlin.descriptors.Visibilities+import org.jetbrains.kotlin.fir.*+import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext+import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass+import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors+import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn+import org.jetbrains.kotlin.fir.declarations.*+import org.jetbrains.kotlin.fir.scopes.*+import org.jetbrains.kotlin.fir.scopes.impl.unwrapDelegateTarget+import org.jetbrains.kotlin.fir.symbols.CallableId+import org.jetbrains.kotlin.fir.symbols.impl.*+import org.jetbrains.kotlin.fir.types.*+import org.jetbrains.kotlin.name.Name++object FirNotImplementedOverrideChecker : FirClassChecker() {+    // TODO: differentiate members with different annotations, e.g., @Api...(x) @Api...(y)+    // TODO: differentiate parameter names? e.g., foo(x : T) v.s. override foo(y : T)+    private object SignaturePresenter : FirDeclarationPresenter {+        override fun StringBuilder.appendRepresentation(it: CallableId) {+            append(it.callableName)+        }+    }++    private fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =+        this.unsubstitutedScope(context.sessionHolder.session, context.sessionHolder.scopeSession, withForcedTypeCalculator = true)++    // TODO: Collection extensions are not properly regarded as an override. Should not have a whitelist like this.+    private val COLLECTIONS = listOf("java.util", "kotlin.collections")++    override fun check(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {+        // TODO: kt4763Property: reporting on `object` literal causes invalid error in test...FirDiagnosticHandler+        if (declaration is FirAnonymousObject) return++        val source = declaration.source ?: return+        if (source.kind is FirFakeSourceElementKind) return++        val contributedMembers = collectCallableMembers(declaration, context)+        val potentialFakeOverrides = getBaseDeclarationsForFakeOverrides(declaration, contributedMembers, context)++        // TODO: consider open as overridable, and check conflicts as well+        val abstractFakeOverrides = potentialFakeOverrides.filter {+            it is FirMemberDeclaration &&+                    it.isAbstract &&+                    // TODO: FIR MPP support+                    (it.getContainingClass(context) as? FirRegularClass)?.isExpect == false+        }+        if (abstractFakeOverrides.isEmpty()) return++        // TODO: differentiate type-substituted declarations. Otherwise, they will be reported as MANY_IMPL_MEMBER_NOT_IMPLEMENTED+        val sigToDeclarations = mutableMapOf<String, MutableList<FirCallableDeclaration<*>>>()+        for (abstractFakeOverride in abstractFakeOverrides) {+            val sig = when (abstractFakeOverride) {+                is FirSimpleFunction -> SignaturePresenter.represent(abstractFakeOverride)+                is FirProperty -> SignaturePresenter.represent(abstractFakeOverride)+                else -> continue+            }+            sigToDeclarations.computeIfAbsent(sig) { mutableListOf() }.add(abstractFakeOverride)+        }++        val canHaveAbstractMembers = declaration is FirRegularClass && declaration.canHaveAbstractFakeOverride+        // var alreadyReportedManyNotImplemented = false+        var alreadyReportedAbstractNotImplemented = false+        for (fakeOverrides in sigToDeclarations.values) {+            if (fakeOverrides.size > 1) {+                // TODO: MANY_* as well as some conflict diagnostics+/*+                if (alreadyReportedManyNotImplemented) continue+                val representative = fakeOverrides.first()+                if (fakeOverrides.any { it.isFromInterface(context) }) {+                    reporter.reportOn(source, FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                } else {+                    reporter.reportOn(source, FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                }+                alreadyReportedManyNotImplemented = true+*/+            } else {+                assert(fakeOverrides.size == 1)+                val notImplemented = fakeOverrides.single()+                if ((notImplemented as? FirMemberDeclaration)?.isAbstract != true) continue+                if (canHaveAbstractMembers || alreadyReportedAbstractNotImplemented) continue++                val notImplementedFunction = notImplemented as? FirSimpleFunction+                // TODO: suspend function overridden by a Java class in the middle is not properly regarded as an override.+                if (notImplementedFunction?.isSuspend == true) continue+                // TODO: Collection extensions are not properly regarded as an override.+                val originalPackage =+                    notImplementedFunction?.originalIfFakeOverride()?.dispatchReceiverType?.classId?.packageFqName?.asString()+                if (originalPackage in COLLECTIONS) continue++                if (notImplemented.isFromInterface(context)) {+                    reporter.reportOn(source, FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)+                } else {+                    reporter.reportOn(source, FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)+                }+                alreadyReportedAbstractNotImplemented = true+            }+        }+    }++    private fun FirCallableDeclaration<*>.isFromInterface(context: CheckerContext): Boolean =+        (getContainingClass(context) as? FirRegularClass)?.isInterface == true++    private fun collectCallableMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> =+        firClass.declarations.filterIsInstance<FirCallableDeclaration<*>>() ++                dataClassMembers(firClass, context) ++                delegatedMembers(firClass, context)++    private val FirSimpleFunction.matchesEqualsSignature: Boolean+        get() = valueParameters.size == 1 && valueParameters[0].returnTypeRef.coneType.isNullableAny &&+                returnTypeRef.coneType.isBoolean++    private val FirSimpleFunction.matchesHashCodeSignature: Boolean+        get() = valueParameters.isEmpty() &&+                returnTypeRef.coneType.isInt++    private val FirSimpleFunction.matchesToStringSignature: Boolean+        get() = valueParameters.isEmpty() &&+                returnTypeRef.coneType.isString++    private val FirSimpleFunction.matchesDataClassSyntheticMemberSignatures: Boolean+        get() = (this.name == EQUALS_NAME && matchesEqualsSignature) ||+                (this.name == HASHCODE_NAME && matchesHashCodeSignature) ||+                (this.name == TOSTRING_NAME && matchesToStringSignature)++    private val SYNTHETIC_NAMES = listOf(EQUALS_NAME, HASHCODE_NAME, TOSTRING_NAME)++    // See [DataClassMembersGenerator#generate]+    // But, this one doesn't create IR counterparts. We just need what synthetic members would be generated for data/inline classes.+    private fun dataClassMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> {+        if (firClass !is FirRegularClass || (!firClass.isData && !firClass.isInline)) return emptyList()++        val contributedInThisType = firClass.declarations.mapNotNull {+            if (it is FirSimpleFunction && it.matchesDataClassSyntheticMemberSignatures) {+                it.name+            } else+                null+        }++        val contributedInSupertypes = mutableMapOf<Name, FirCallableDeclaration<*>>()+        val classScope = firClass.unsubstitutedScope(context)+        for (name in SYNTHETIC_NAMES) {+            classScope.processFunctionsByName(name) {+                val declaration = it.fir+                if (declaration.matchesDataClassSyntheticMemberSignatures && declaration.modality != Modality.FINAL) {+                    contributedInSupertypes.putIfAbsent(declaration.name, declaration)+                }+            }+        }++        val result = mutableListOf<FirCallableDeclaration<*>>()+        for (name in SYNTHETIC_NAMES) {+            if (name in contributedInThisType) continue+            contributedInSupertypes[name]?.let { result.add(it) }+        }+        return result+    }++    // See [DelegatedMemberGenerator#generate]+    // But, this one doesn't create IR counterparts. We just need what members could be delegated to avoid false fake overrides.+    private fun delegatedMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> {+        val delegations = firClass.declarations.filterIsInstance<FirField>().filter { it.isSynthetic }+        val delegation = delegations.singleOrNull() ?: return emptyList()++        val result = mutableListOf<FirCallableDeclaration<*>>()+        val classLookupTag = firClass.symbol.toLookupTag()+        val classScope = firClass.unsubstitutedScope(context)++        classScope.processAllFunctions { functionSymbol ->+            val unwrapped =+                functionSymbol.unwrapDelegateTarget(classLookupTag, classScope::getDirectOverriddenFunctions, delegation, firClass)+                    ?: return@processAllFunctions++            if (unwrapped.isJavaDefault) {+                return@processAllFunctions+            }++            result.add(functionSymbol.fir)+        }++        classScope.processAllProperties { propertySymbol ->+            if (propertySymbol !is FirPropertySymbol) return@processAllProperties++            propertySymbol.unwrapDelegateTarget(classLookupTag, classScope::getDirectOverriddenProperties, delegation, firClass)+                ?: return@processAllProperties++            result.add(propertySymbol.fir)+        }++        return result+    }++    // See [FakeOverrideGenerator#getFakeOverrides]+    // But, this one doesn't create fake overrides. We just need what _base_ declarations will be referred by fake overrides.+    private fun getBaseDeclarationsForFakeOverrides(+        firClass: FirClass<*>,+        contributedDeclarations: Collection<FirDeclaration>,+        context: CheckerContext+    ): Collection<FirCallableDeclaration<*>> {+        val result = mutableListOf<FirCallableDeclaration<*>>()+        val classScope = firClass.unsubstitutedScope(context)++        fun checkFunctionSymbolAndAddToResult(originalSymbol: FirCallableSymbol<*>) {+            if (shouldCreateFakeOverridden<FirSimpleFunction, FirNamedFunctionSymbol>(firClass, originalSymbol, contributedDeclarations)) {+                result.add(originalSymbol.fir)+            }+        }++        fun checkPropertySymbolAndAddToResult(originalSymbol: FirCallableSymbol<*>) {+            if (shouldCreateFakeOverridden<FirProperty, FirPropertySymbol>(firClass, originalSymbol, contributedDeclarations)) {+                result.add(originalSymbol.fir)+            }+        }++        val superTypesCallableNames = classScope.getCallableNames()+        for (name in superTypesCallableNames) {+            classScope.processFunctionsByName(name) { functionSymbol ->+                // TODO: MANY_* as well as some conflict diagnostics+                //if (functionSymbol is FirIntersectionOverrideFunctionSymbol)+                //    functionSymbol.intersections.forEach(::checkFunctionSymbolAndAddToResult)+                //else+                checkFunctionSymbolAndAddToResult(functionSymbol)+            }++            classScope.processPropertiesByName(name) { propertySymbol ->+                // TODO: MANY_* as well as some conflict diagnostics+                //if (propertySymbol is FirIntersectionOverridePropertySymbol)+                //    propertySymbol.intersections.forEach(::checkPropertySymbolAndAddToResult)+                //else+                checkPropertySymbolAndAddToResult(propertySymbol)+            }+        }++        return result+    }++    // See [FakeOverrideGenerator#createFakeOverriddenIfNeeded]+    private inline fun <reified D : FirCallableMemberDeclaration<D>, reified S : FirCallableSymbol<D>> shouldCreateFakeOverridden(+        firClass: FirClass<*>,+        originalSymbol: FirCallableSymbol<*>,+        contributedDeclarations: Collection<FirDeclaration>,+    ): Boolean {+        if (originalSymbol !is S || originalSymbol.fir in contributedDeclarations) return false+        val classLookupTag = firClass.symbol.toLookupTag()+        val originalDeclaration = originalSymbol.fir+        if (originalSymbol.dispatchReceiverClassOrNull() == classLookupTag && !originalDeclaration.origin.fromSupertypes) return false+        if (originalDeclaration.visibility == Visibilities.Private) return false+        return when {+            originalSymbol.fir.origin.fromSupertypes && originalSymbol.dispatchReceiverClassOrNull() == classLookupTag -> {+                // Substitution case+                false+            }+            originalDeclaration.allowsToHaveFakeOverrideIn(firClass) -> {+                // Trivial fake override case+                true+            }+            else -> {+                false+            }+        }+    }++    // TODO: Need to refactor the counterpart in FakeOverrideGenerator?+    private fun FirCallableMemberDeclaration<*>.allowsToHaveFakeOverrideIn(firClass: FirClass<*>): Boolean {+        if (!allowsToHaveFakeOverride) return false+        // if (this.visibility != JavaDescriptorVisibilities.PACKAGE_VISIBILITY) return true

Looks like you do not handle multi-inheritance properly

I have to admit that's the case. I left a bunch of TODOs regarding that. This visibility check seems a different topic, though.

jsjeon

comment created time in 5 hours

Pull request review commentJetBrains/kotlin

FIR checker: introduce *_NOT_IMPLEMENTED override checker

+/*+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.+ */++package org.jetbrains.kotlin.fir.analysis.checkers.declaration++import org.jetbrains.kotlin.descriptors.Modality+import org.jetbrains.kotlin.descriptors.Visibilities+import org.jetbrains.kotlin.fir.*+import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext+import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass+import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors+import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn+import org.jetbrains.kotlin.fir.declarations.*+import org.jetbrains.kotlin.fir.scopes.*+import org.jetbrains.kotlin.fir.scopes.impl.unwrapDelegateTarget+import org.jetbrains.kotlin.fir.symbols.CallableId+import org.jetbrains.kotlin.fir.symbols.impl.*+import org.jetbrains.kotlin.fir.types.*+import org.jetbrains.kotlin.name.Name++object FirNotImplementedOverrideChecker : FirClassChecker() {+    // TODO: differentiate members with different annotations, e.g., @Api...(x) @Api...(y)+    // TODO: differentiate parameter names? e.g., foo(x : T) v.s. override foo(y : T)+    private object SignaturePresenter : FirDeclarationPresenter {+        override fun StringBuilder.appendRepresentation(it: CallableId) {+            append(it.callableName)+        }+    }++    private fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =+        this.unsubstitutedScope(context.sessionHolder.session, context.sessionHolder.scopeSession, withForcedTypeCalculator = true)++    // TODO: Collection extensions are not properly regarded as an override. Should not have a whitelist like this.+    private val COLLECTIONS = listOf("java.util", "kotlin.collections")++    override fun check(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {+        // TODO: kt4763Property: reporting on `object` literal causes invalid error in test...FirDiagnosticHandler+        if (declaration is FirAnonymousObject) return++        val source = declaration.source ?: return+        if (source.kind is FirFakeSourceElementKind) return++        val contributedMembers = collectCallableMembers(declaration, context)+        val potentialFakeOverrides = getBaseDeclarationsForFakeOverrides(declaration, contributedMembers, context)++        // TODO: consider open as overridable, and check conflicts as well+        val abstractFakeOverrides = potentialFakeOverrides.filter {+            it is FirMemberDeclaration &&+                    it.isAbstract &&+                    // TODO: FIR MPP support+                    (it.getContainingClass(context) as? FirRegularClass)?.isExpect == false+        }+        if (abstractFakeOverrides.isEmpty()) return++        // TODO: differentiate type-substituted declarations. Otherwise, they will be reported as MANY_IMPL_MEMBER_NOT_IMPLEMENTED+        val sigToDeclarations = mutableMapOf<String, MutableList<FirCallableDeclaration<*>>>()+        for (abstractFakeOverride in abstractFakeOverrides) {+            val sig = when (abstractFakeOverride) {+                is FirSimpleFunction -> SignaturePresenter.represent(abstractFakeOverride)+                is FirProperty -> SignaturePresenter.represent(abstractFakeOverride)+                else -> continue+            }+            sigToDeclarations.computeIfAbsent(sig) { mutableListOf() }.add(abstractFakeOverride)+        }++        val canHaveAbstractMembers = declaration is FirRegularClass && declaration.canHaveAbstractFakeOverride+        // var alreadyReportedManyNotImplemented = false+        var alreadyReportedAbstractNotImplemented = false+        for (fakeOverrides in sigToDeclarations.values) {+            if (fakeOverrides.size > 1) {+                // TODO: MANY_* as well as some conflict diagnostics+/*+                if (alreadyReportedManyNotImplemented) continue+                val representative = fakeOverrides.first()+                if (fakeOverrides.any { it.isFromInterface(context) }) {+                    reporter.reportOn(source, FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                } else {+                    reporter.reportOn(source, FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                }+                alreadyReportedManyNotImplemented = true+*/+            } else {+                assert(fakeOverrides.size == 1)+                val notImplemented = fakeOverrides.single()+                if ((notImplemented as? FirMemberDeclaration)?.isAbstract != true) continue+                if (canHaveAbstractMembers || alreadyReportedAbstractNotImplemented) continue++                val notImplementedFunction = notImplemented as? FirSimpleFunction+                // TODO: suspend function overridden by a Java class in the middle is not properly regarded as an override.+                if (notImplementedFunction?.isSuspend == true) continue+                // TODO: Collection extensions are not properly regarded as an override.+                val originalPackage =+                    notImplementedFunction?.originalIfFakeOverride()?.dispatchReceiverType?.classId?.packageFqName?.asString()+                if (originalPackage in COLLECTIONS) continue++                if (notImplemented.isFromInterface(context)) {+                    reporter.reportOn(source, FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)+                } else {+                    reporter.reportOn(source, FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)+                }+                alreadyReportedAbstractNotImplemented = true+            }+        }+    }++    private fun FirCallableDeclaration<*>.isFromInterface(context: CheckerContext): Boolean =+        (getContainingClass(context) as? FirRegularClass)?.isInterface == true++    private fun collectCallableMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> =+        firClass.declarations.filterIsInstance<FirCallableDeclaration<*>>() ++                dataClassMembers(firClass, context) ++                delegatedMembers(firClass, context)++    private val FirSimpleFunction.matchesEqualsSignature: Boolean+        get() = valueParameters.size == 1 && valueParameters[0].returnTypeRef.coneType.isNullableAny &&+                returnTypeRef.coneType.isBoolean++    private val FirSimpleFunction.matchesHashCodeSignature: Boolean+        get() = valueParameters.isEmpty() &&+                returnTypeRef.coneType.isInt++    private val FirSimpleFunction.matchesToStringSignature: Boolean+        get() = valueParameters.isEmpty() &&+                returnTypeRef.coneType.isString++    private val FirSimpleFunction.matchesDataClassSyntheticMemberSignatures: Boolean+        get() = (this.name == EQUALS_NAME && matchesEqualsSignature) ||+                (this.name == HASHCODE_NAME && matchesHashCodeSignature) ||+                (this.name == TOSTRING_NAME && matchesToStringSignature)++    private val SYNTHETIC_NAMES = listOf(EQUALS_NAME, HASHCODE_NAME, TOSTRING_NAME)++    // See [DataClassMembersGenerator#generate]+    // But, this one doesn't create IR counterparts. We just need what synthetic members would be generated for data/inline classes.+    private fun dataClassMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> {+        if (firClass !is FirRegularClass || (!firClass.isData && !firClass.isInline)) return emptyList()++        val contributedInThisType = firClass.declarations.mapNotNull {+            if (it is FirSimpleFunction && it.matchesDataClassSyntheticMemberSignatures) {+                it.name+            } else+                null+        }++        val contributedInSupertypes = mutableMapOf<Name, FirCallableDeclaration<*>>()+        val classScope = firClass.unsubstitutedScope(context)+        for (name in SYNTHETIC_NAMES) {+            classScope.processFunctionsByName(name) {+                val declaration = it.fir+                if (declaration.matchesDataClassSyntheticMemberSignatures && declaration.modality != Modality.FINAL) {+                    contributedInSupertypes.putIfAbsent(declaration.name, declaration)+                }+            }+        }++        val result = mutableListOf<FirCallableDeclaration<*>>()+        for (name in SYNTHETIC_NAMES) {+            if (name in contributedInThisType) continue+            contributedInSupertypes[name]?.let { result.add(it) }+        }+        return result+    }++    // See [DelegatedMemberGenerator#generate]+    // But, this one doesn't create IR counterparts. We just need what members could be delegated to avoid false fake overrides.+    private fun delegatedMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> {

Yeah... but we can't ignore delegated members. Needless to say, without this, we will see many false alarms. It starts with synthetic FirField check to make sure we have a delegation indeed. Hope that early bail-out is effective enough.

jsjeon

comment created time in 5 hours

Pull request review commentJetBrains/kotlin

FIR checker: introduce *_NOT_IMPLEMENTED override checker

+/*+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.+ */++package org.jetbrains.kotlin.fir.analysis.checkers.declaration++import org.jetbrains.kotlin.descriptors.Modality+import org.jetbrains.kotlin.descriptors.Visibilities+import org.jetbrains.kotlin.fir.*+import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext+import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass+import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors+import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn+import org.jetbrains.kotlin.fir.declarations.*+import org.jetbrains.kotlin.fir.scopes.*+import org.jetbrains.kotlin.fir.scopes.impl.unwrapDelegateTarget+import org.jetbrains.kotlin.fir.symbols.CallableId+import org.jetbrains.kotlin.fir.symbols.impl.*+import org.jetbrains.kotlin.fir.types.*+import org.jetbrains.kotlin.name.Name++object FirNotImplementedOverrideChecker : FirClassChecker() {+    // TODO: differentiate members with different annotations, e.g., @Api...(x) @Api...(y)+    // TODO: differentiate parameter names? e.g., foo(x : T) v.s. override foo(y : T)+    private object SignaturePresenter : FirDeclarationPresenter {+        override fun StringBuilder.appendRepresentation(it: CallableId) {+            append(it.callableName)+        }+    }++    private fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =+        this.unsubstitutedScope(context.sessionHolder.session, context.sessionHolder.scopeSession, withForcedTypeCalculator = true)

I do remember FirOverrideChecker did the same thing. Utilized it and used both of override checkers.

jsjeon

comment created time in 5 hours

Pull request review commentJetBrains/kotlin

FIR checker: introduce *_NOT_IMPLEMENTED override checker

+/*+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.+ */++package org.jetbrains.kotlin.fir.analysis.checkers.declaration++import org.jetbrains.kotlin.descriptors.Modality+import org.jetbrains.kotlin.descriptors.Visibilities+import org.jetbrains.kotlin.fir.*+import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext+import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass+import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors+import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn+import org.jetbrains.kotlin.fir.declarations.*+import org.jetbrains.kotlin.fir.scopes.*+import org.jetbrains.kotlin.fir.scopes.impl.unwrapDelegateTarget+import org.jetbrains.kotlin.fir.symbols.CallableId+import org.jetbrains.kotlin.fir.symbols.impl.*+import org.jetbrains.kotlin.fir.types.*+import org.jetbrains.kotlin.name.Name++object FirNotImplementedOverrideChecker : FirClassChecker() {+    // TODO: differentiate members with different annotations, e.g., @Api...(x) @Api...(y)+    // TODO: differentiate parameter names? e.g., foo(x : T) v.s. override foo(y : T)+    private object SignaturePresenter : FirDeclarationPresenter {+        override fun StringBuilder.appendRepresentation(it: CallableId) {+            append(it.callableName)+        }+    }++    private fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =+        this.unsubstitutedScope(context.sessionHolder.session, context.sessionHolder.scopeSession, withForcedTypeCalculator = true)++    // TODO: Collection extensions are not properly regarded as an override. Should not have a whitelist like this.+    private val COLLECTIONS = listOf("java.util", "kotlin.collections")++    override fun check(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {+        // TODO: kt4763Property: reporting on `object` literal causes invalid error in test...FirDiagnosticHandler+        if (declaration is FirAnonymousObject) return++        val source = declaration.source ?: return+        if (source.kind is FirFakeSourceElementKind) return++        val contributedMembers = collectCallableMembers(declaration, context)+        val potentialFakeOverrides = getBaseDeclarationsForFakeOverrides(declaration, contributedMembers, context)++        // TODO: consider open as overridable, and check conflicts as well+        val abstractFakeOverrides = potentialFakeOverrides.filter {+            it is FirMemberDeclaration &&+                    it.isAbstract &&+                    // TODO: FIR MPP support+                    (it.getContainingClass(context) as? FirRegularClass)?.isExpect == false+        }+        if (abstractFakeOverrides.isEmpty()) return++        // TODO: differentiate type-substituted declarations. Otherwise, they will be reported as MANY_IMPL_MEMBER_NOT_IMPLEMENTED+        val sigToDeclarations = mutableMapOf<String, MutableList<FirCallableDeclaration<*>>>()+        for (abstractFakeOverride in abstractFakeOverrides) {+            val sig = when (abstractFakeOverride) {+                is FirSimpleFunction -> SignaturePresenter.represent(abstractFakeOverride)+                is FirProperty -> SignaturePresenter.represent(abstractFakeOverride)+                else -> continue+            }+            sigToDeclarations.computeIfAbsent(sig) { mutableListOf() }.add(abstractFakeOverride)+        }++        val canHaveAbstractMembers = declaration is FirRegularClass && declaration.canHaveAbstractFakeOverride+        // var alreadyReportedManyNotImplemented = false+        var alreadyReportedAbstractNotImplemented = false+        for (fakeOverrides in sigToDeclarations.values) {+            if (fakeOverrides.size > 1) {+                // TODO: MANY_* as well as some conflict diagnostics+/*+                if (alreadyReportedManyNotImplemented) continue+                val representative = fakeOverrides.first()+                if (fakeOverrides.any { it.isFromInterface(context) }) {+                    reporter.reportOn(source, FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                } else {+                    reporter.reportOn(source, FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                }+                alreadyReportedManyNotImplemented = true+*/+            } else {+                assert(fakeOverrides.size == 1)+                val notImplemented = fakeOverrides.single()+                if ((notImplemented as? FirMemberDeclaration)?.isAbstract != true) continue+                if (canHaveAbstractMembers || alreadyReportedAbstractNotImplemented) continue++                val notImplementedFunction = notImplemented as? FirSimpleFunction+                // TODO: suspend function overridden by a Java class in the middle is not properly regarded as an override.+                if (notImplementedFunction?.isSuspend == true) continue+                // TODO: Collection extensions are not properly regarded as an override.+                val originalPackage =+                    notImplementedFunction?.originalIfFakeOverride()?.dispatchReceiverType?.classId?.packageFqName?.asString()+                if (originalPackage in COLLECTIONS) continue++                if (notImplemented.isFromInterface(context)) {+                    reporter.reportOn(source, FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)+                } else {+                    reporter.reportOn(source, FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)+                }+                alreadyReportedAbstractNotImplemented = true+            }+        }+    }++    private fun FirCallableDeclaration<*>.isFromInterface(context: CheckerContext): Boolean =+        (getContainingClass(context) as? FirRegularClass)?.isInterface == true++    private fun collectCallableMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> =+        firClass.declarations.filterIsInstance<FirCallableDeclaration<*>>() ++                dataClassMembers(firClass, context) ++                delegatedMembers(firClass, context)++    private val FirSimpleFunction.matchesEqualsSignature: Boolean+        get() = valueParameters.size == 1 && valueParameters[0].returnTypeRef.coneType.isNullableAny &&+                returnTypeRef.coneType.isBoolean++    private val FirSimpleFunction.matchesHashCodeSignature: Boolean+        get() = valueParameters.isEmpty() &&+                returnTypeRef.coneType.isInt++    private val FirSimpleFunction.matchesToStringSignature: Boolean+        get() = valueParameters.isEmpty() &&+                returnTypeRef.coneType.isString++    private val FirSimpleFunction.matchesDataClassSyntheticMemberSignatures: Boolean+        get() = (this.name == EQUALS_NAME && matchesEqualsSignature) ||

Yes, noticed this: https://github.com/JetBrains/kotlin/commit/b138b166e3d5ffba8205d24f238491d912af4a21 Thanks.

jsjeon

comment created time in 5 hours

Pull request review commentJetBrains/kotlin

FIR checker: introduce *_NOT_IMPLEMENTED override checker

+/*+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.+ */++package org.jetbrains.kotlin.fir.analysis.checkers.declaration++import org.jetbrains.kotlin.descriptors.Modality+import org.jetbrains.kotlin.descriptors.Visibilities+import org.jetbrains.kotlin.fir.*+import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext+import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass+import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors+import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn+import org.jetbrains.kotlin.fir.declarations.*+import org.jetbrains.kotlin.fir.scopes.*+import org.jetbrains.kotlin.fir.scopes.impl.unwrapDelegateTarget+import org.jetbrains.kotlin.fir.symbols.CallableId+import org.jetbrains.kotlin.fir.symbols.impl.*+import org.jetbrains.kotlin.fir.types.*+import org.jetbrains.kotlin.name.Name++object FirNotImplementedOverrideChecker : FirClassChecker() {+    // TODO: differentiate members with different annotations, e.g., @Api...(x) @Api...(y)+    // TODO: differentiate parameter names? e.g., foo(x : T) v.s. override foo(y : T)+    private object SignaturePresenter : FirDeclarationPresenter {+        override fun StringBuilder.appendRepresentation(it: CallableId) {+            append(it.callableName)+        }+    }++    private fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =+        this.unsubstitutedScope(context.sessionHolder.session, context.sessionHolder.scopeSession, withForcedTypeCalculator = true)++    // TODO: Collection extensions are not properly regarded as an override. Should not have a whitelist like this.+    private val COLLECTIONS = listOf("java.util", "kotlin.collections")++    override fun check(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {+        // TODO: kt4763Property: reporting on `object` literal causes invalid error in test...FirDiagnosticHandler+        if (declaration is FirAnonymousObject) return++        val source = declaration.source ?: return+        if (source.kind is FirFakeSourceElementKind) return++        val contributedMembers = collectCallableMembers(declaration, context)+        val potentialFakeOverrides = getBaseDeclarationsForFakeOverrides(declaration, contributedMembers, context)++        // TODO: consider open as overridable, and check conflicts as well+        val abstractFakeOverrides = potentialFakeOverrides.filter {+            it is FirMemberDeclaration &&+                    it.isAbstract &&+                    // TODO: FIR MPP support+                    (it.getContainingClass(context) as? FirRegularClass)?.isExpect == false+        }+        if (abstractFakeOverrides.isEmpty()) return++        // TODO: differentiate type-substituted declarations. Otherwise, they will be reported as MANY_IMPL_MEMBER_NOT_IMPLEMENTED+        val sigToDeclarations = mutableMapOf<String, MutableList<FirCallableDeclaration<*>>>()+        for (abstractFakeOverride in abstractFakeOverrides) {+            val sig = when (abstractFakeOverride) {+                is FirSimpleFunction -> SignaturePresenter.represent(abstractFakeOverride)+                is FirProperty -> SignaturePresenter.represent(abstractFakeOverride)+                else -> continue+            }+            sigToDeclarations.computeIfAbsent(sig) { mutableListOf() }.add(abstractFakeOverride)+        }++        val canHaveAbstractMembers = declaration is FirRegularClass && declaration.canHaveAbstractFakeOverride+        // var alreadyReportedManyNotImplemented = false+        var alreadyReportedAbstractNotImplemented = false+        for (fakeOverrides in sigToDeclarations.values) {+            if (fakeOverrides.size > 1) {+                // TODO: MANY_* as well as some conflict diagnostics+/*+                if (alreadyReportedManyNotImplemented) continue+                val representative = fakeOverrides.first()+                if (fakeOverrides.any { it.isFromInterface(context) }) {+                    reporter.reportOn(source, FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                } else {+                    reporter.reportOn(source, FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                }+                alreadyReportedManyNotImplemented = true+*/+            } else {+                assert(fakeOverrides.size == 1)+                val notImplemented = fakeOverrides.single()+                if ((notImplemented as? FirMemberDeclaration)?.isAbstract != true) continue+                if (canHaveAbstractMembers || alreadyReportedAbstractNotImplemented) continue++                val notImplementedFunction = notImplemented as? FirSimpleFunction+                // TODO: suspend function overridden by a Java class in the middle is not properly regarded as an override.+                if (notImplementedFunction?.isSuspend == true) continue+                // TODO: Collection extensions are not properly regarded as an override.+                val originalPackage =+                    notImplementedFunction?.originalIfFakeOverride()?.dispatchReceiverType?.classId?.packageFqName?.asString()+                if (originalPackage in COLLECTIONS) continue++                if (notImplemented.isFromInterface(context)) {+                    reporter.reportOn(source, FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)+                } else {+                    reporter.reportOn(source, FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, declaration, notImplemented, context)+                }+                alreadyReportedAbstractNotImplemented = true+            }+        }+    }++    private fun FirCallableDeclaration<*>.isFromInterface(context: CheckerContext): Boolean =+        (getContainingClass(context) as? FirRegularClass)?.isInterface == true++    private fun collectCallableMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> =+        firClass.declarations.filterIsInstance<FirCallableDeclaration<*>>() ++                dataClassMembers(firClass, context) ++                delegatedMembers(firClass, context)++    private val FirSimpleFunction.matchesEqualsSignature: Boolean+        get() = valueParameters.size == 1 && valueParameters[0].returnTypeRef.coneType.isNullableAny &&+                returnTypeRef.coneType.isBoolean++    private val FirSimpleFunction.matchesHashCodeSignature: Boolean+        get() = valueParameters.isEmpty() &&+                returnTypeRef.coneType.isInt++    private val FirSimpleFunction.matchesToStringSignature: Boolean+        get() = valueParameters.isEmpty() &&+                returnTypeRef.coneType.isString++    private val FirSimpleFunction.matchesDataClassSyntheticMemberSignatures: Boolean+        get() = (this.name == EQUALS_NAME && matchesEqualsSignature) ||+                (this.name == HASHCODE_NAME && matchesHashCodeSignature) ||+                (this.name == TOSTRING_NAME && matchesToStringSignature)++    private val SYNTHETIC_NAMES = listOf(EQUALS_NAME, HASHCODE_NAME, TOSTRING_NAME)++    // See [DataClassMembersGenerator#generate]+    // But, this one doesn't create IR counterparts. We just need what synthetic members would be generated for data/inline classes.+    private fun dataClassMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> {+        if (firClass !is FirRegularClass || (!firClass.isData && !firClass.isInline)) return emptyList()++        val contributedInThisType = firClass.declarations.mapNotNull {+            if (it is FirSimpleFunction && it.matchesDataClassSyntheticMemberSignatures) {+                it.name+            } else+                null+        }++        val contributedInSupertypes = mutableMapOf<Name, FirCallableDeclaration<*>>()+        val classScope = firClass.unsubstitutedScope(context)+        for (name in SYNTHETIC_NAMES) {+            classScope.processFunctionsByName(name) {+                val declaration = it.fir+                if (declaration.matchesDataClassSyntheticMemberSignatures && declaration.modality != Modality.FINAL) {+                    contributedInSupertypes.putIfAbsent(declaration.name, declaration)+                }+            }+        }++        val result = mutableListOf<FirCallableDeclaration<*>>()+        for (name in SYNTHETIC_NAMES) {+            if (name in contributedInThisType) continue+            contributedInSupertypes[name]?.let { result.add(it) }+        }+        return result+    }++    // See [DelegatedMemberGenerator#generate]+    // But, this one doesn't create IR counterparts. We just need what members could be delegated to avoid false fake overrides.+    private fun delegatedMembers(firClass: FirClass<*>, context: CheckerContext): Collection<FirCallableDeclaration<*>> {+        val delegations = firClass.declarations.filterIsInstance<FirField>().filter { it.isSynthetic }+        val delegation = delegations.singleOrNull() ?: return emptyList()++        val result = mutableListOf<FirCallableDeclaration<*>>()+        val classLookupTag = firClass.symbol.toLookupTag()+        val classScope = firClass.unsubstitutedScope(context)++        classScope.processAllFunctions { functionSymbol ->+            val unwrapped =+                functionSymbol.unwrapDelegateTarget(classLookupTag, classScope::getDirectOverriddenFunctions, delegation, firClass)+                    ?: return@processAllFunctions++            if (unwrapped.isJavaDefault) {+                return@processAllFunctions+            }++            result.add(functionSymbol.fir)+        }++        classScope.processAllProperties { propertySymbol ->+            if (propertySymbol !is FirPropertySymbol) return@processAllProperties++            propertySymbol.unwrapDelegateTarget(classLookupTag, classScope::getDirectOverriddenProperties, delegation, firClass)+                ?: return@processAllProperties++            result.add(propertySymbol.fir)+        }++        return result+    }++    // See [FakeOverrideGenerator#getFakeOverrides]+    // But, this one doesn't create fake overrides. We just need what _base_ declarations will be referred by fake overrides.+    private fun getBaseDeclarationsForFakeOverrides(+        firClass: FirClass<*>,+        contributedDeclarations: Collection<FirDeclaration>,+        context: CheckerContext+    ): Collection<FirCallableDeclaration<*>> {+        val result = mutableListOf<FirCallableDeclaration<*>>()+        val classScope = firClass.unsubstitutedScope(context)++        fun checkFunctionSymbolAndAddToResult(originalSymbol: FirCallableSymbol<*>) {+            if (shouldCreateFakeOverridden<FirSimpleFunction, FirNamedFunctionSymbol>(firClass, originalSymbol, contributedDeclarations)) {+                result.add(originalSymbol.fir)+            }+        }++        fun checkPropertySymbolAndAddToResult(originalSymbol: FirCallableSymbol<*>) {+            if (shouldCreateFakeOverridden<FirProperty, FirPropertySymbol>(firClass, originalSymbol, contributedDeclarations)) {+                result.add(originalSymbol.fir)+            }+        }++        val superTypesCallableNames = classScope.getCallableNames()+        for (name in superTypesCallableNames) {+            classScope.processFunctionsByName(name) { functionSymbol ->+                // TODO: MANY_* as well as some conflict diagnostics+                //if (functionSymbol is FirIntersectionOverrideFunctionSymbol)+                //    functionSymbol.intersections.forEach(::checkFunctionSymbolAndAddToResult)+                //else+                checkFunctionSymbolAndAddToResult(functionSymbol)+            }++            classScope.processPropertiesByName(name) { propertySymbol ->+                // TODO: MANY_* as well as some conflict diagnostics+                //if (propertySymbol is FirIntersectionOverridePropertySymbol)+                //    propertySymbol.intersections.forEach(::checkPropertySymbolAndAddToResult)+                //else+                checkPropertySymbolAndAddToResult(propertySymbol)+            }+        }++        return result+    }++    // See [FakeOverrideGenerator#createFakeOverriddenIfNeeded]+    private inline fun <reified D : FirCallableMemberDeclaration<D>, reified S : FirCallableSymbol<D>> shouldCreateFakeOverridden(+        firClass: FirClass<*>,+        originalSymbol: FirCallableSymbol<*>,+        contributedDeclarations: Collection<FirDeclaration>,+    ): Boolean {+        if (originalSymbol !is S || originalSymbol.fir in contributedDeclarations) return false+        val classLookupTag = firClass.symbol.toLookupTag()+        val originalDeclaration = originalSymbol.fir+        if (originalSymbol.dispatchReceiverClassOrNull() == classLookupTag && !originalDeclaration.origin.fromSupertypes) return false+        if (originalDeclaration.visibility == Visibilities.Private) return false+        return when {+            originalSymbol.fir.origin.fromSupertypes && originalSymbol.dispatchReceiverClassOrNull() == classLookupTag -> {+                // Substitution case+                false+            }+            originalDeclaration.allowsToHaveFakeOverrideIn(firClass) -> {+                // Trivial fake override case+                true+            }+            else -> {+                false+            }+        }+    }++    // TODO: Need to refactor the counterpart in FakeOverrideGenerator?+    private fun FirCallableMemberDeclaration<*>.allowsToHaveFakeOverrideIn(firClass: FirClass<*>): Boolean {+        if (!allowsToHaveFakeOverride) return false+        // if (this.visibility != JavaDescriptorVisibilities.PACKAGE_VISIBILITY) return true

I think I found a nicer way: using FirVisibilityChecker's isVisible. No behavior changes!

jsjeon

comment created time in 5 hours

Pull request review commentJetBrains/kotlin

FIR checker: introduce *_NOT_IMPLEMENTED override checker

+/*+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.+ */++package org.jetbrains.kotlin.fir.analysis.checkers.declaration++import org.jetbrains.kotlin.descriptors.Modality+import org.jetbrains.kotlin.descriptors.Visibilities+import org.jetbrains.kotlin.fir.*+import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext+import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass+import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors+import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn+import org.jetbrains.kotlin.fir.declarations.*+import org.jetbrains.kotlin.fir.scopes.*+import org.jetbrains.kotlin.fir.scopes.impl.unwrapDelegateTarget+import org.jetbrains.kotlin.fir.symbols.CallableId+import org.jetbrains.kotlin.fir.symbols.impl.*+import org.jetbrains.kotlin.fir.types.*+import org.jetbrains.kotlin.name.Name++object FirNotImplementedOverrideChecker : FirClassChecker() {+    // TODO: differentiate members with different annotations, e.g., @Api...(x) @Api...(y)+    // TODO: differentiate parameter names? e.g., foo(x : T) v.s. override foo(y : T)+    private object SignaturePresenter : FirDeclarationPresenter {+        override fun StringBuilder.appendRepresentation(it: CallableId) {+            append(it.callableName)+        }+    }++    private fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =+        this.unsubstitutedScope(context.sessionHolder.session, context.sessionHolder.scopeSession, withForcedTypeCalculator = true)++    // TODO: Collection extensions are not properly regarded as an override. Should not have a whitelist like this.+    private val COLLECTIONS = listOf("java.util", "kotlin.collections")++    override fun check(declaration: FirClass<*>, context: CheckerContext, reporter: DiagnosticReporter) {+        // TODO: kt4763Property: reporting on `object` literal causes invalid error in test...FirDiagnosticHandler+        if (declaration is FirAnonymousObject) return++        val source = declaration.source ?: return+        if (source.kind is FirFakeSourceElementKind) return++        val contributedMembers = collectCallableMembers(declaration, context)+        val potentialFakeOverrides = getBaseDeclarationsForFakeOverrides(declaration, contributedMembers, context)++        // TODO: consider open as overridable, and check conflicts as well+        val abstractFakeOverrides = potentialFakeOverrides.filter {+            it is FirMemberDeclaration &&+                    it.isAbstract &&+                    // TODO: FIR MPP support+                    (it.getContainingClass(context) as? FirRegularClass)?.isExpect == false+        }+        if (abstractFakeOverrides.isEmpty()) return++        // TODO: differentiate type-substituted declarations. Otherwise, they will be reported as MANY_IMPL_MEMBER_NOT_IMPLEMENTED+        val sigToDeclarations = mutableMapOf<String, MutableList<FirCallableDeclaration<*>>>()+        for (abstractFakeOverride in abstractFakeOverrides) {+            val sig = when (abstractFakeOverride) {+                is FirSimpleFunction -> SignaturePresenter.represent(abstractFakeOverride)+                is FirProperty -> SignaturePresenter.represent(abstractFakeOverride)+                else -> continue+            }+            sigToDeclarations.computeIfAbsent(sig) { mutableListOf() }.add(abstractFakeOverride)+        }++        val canHaveAbstractMembers = declaration is FirRegularClass && declaration.canHaveAbstractFakeOverride+        // var alreadyReportedManyNotImplemented = false+        var alreadyReportedAbstractNotImplemented = false+        for (fakeOverrides in sigToDeclarations.values) {+            if (fakeOverrides.size > 1) {+                // TODO: MANY_* as well as some conflict diagnostics+/*+                if (alreadyReportedManyNotImplemented) continue+                val representative = fakeOverrides.first()+                if (fakeOverrides.any { it.isFromInterface(context) }) {+                    reporter.reportOn(source, FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                } else {+                    reporter.reportOn(source, FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED, declaration, representative, context)+                }+                alreadyReportedManyNotImplemented = true+*/+            } else {+                assert(fakeOverrides.size == 1)+                val notImplemented = fakeOverrides.single()+                if ((notImplemented as? FirMemberDeclaration)?.isAbstract != true) continue+                if (canHaveAbstractMembers || alreadyReportedAbstractNotImplemented) continue++                val notImplementedFunction = notImplemented as? FirSimpleFunction+                // TODO: suspend function overridden by a Java class in the middle is not properly regarded as an override.+                if (notImplementedFunction?.isSuspend == true) continue+                // TODO: Collection extensions are not properly regarded as an override.+                val originalPackage =+                    notImplementedFunction?.originalIfFakeOverride()?.dispatchReceiverType?.classId?.packageFqName?.asString()+                if (originalPackage in COLLECTIONS) continue

There weren't that many cases IIRC, so I removed that, and got 2 more correct reports and 3 suspicious cases. Two (out of 3) are kinda expected (?), as described at https://github.com/JetBrains/kotlin/commit/45018ea4685e73040f25d1237b153f882fe22cb3

incorrect Corner cases like having both contains(Object) and contains(String) within implementation of Collection<String> is not supported

I added TODOs to those test files to not forget. The last one is actually a real issue I think. Collection#removeAt, which is a built-in rename (to remove(index) I think?) is still detected as a fake override with abstract base symbol. Surprised to see that having that fake override in IR doesn't matter (I saw a couple BB tests that will be impacted with that false alarm). Anyway, since it bothers BB tests, I added another kind of ugly whitelist. Not sure we need a generalization for built-in renames or I'm missing something.

jsjeon

comment created time in 5 hours

startedJakeWharton/timber

started time in 6 hours

push eventandroidx/androidx

Jim Sproch

commit sha d0aa428244246132d1df645be34ab3e601ab5976

Fix typo in ktdoc for mutableStateMapOf Change-Id: I2c3fba07830d703426948fa3a007b592db07c376

view details

Jim Sproch

commit sha 54d99af63343b05a5d8b678e75340824a043b9b6

Merge "Fix typo in ktdoc for mutableStateMapOf" into androidx-main

view details

push time in 6 hours

startedJakeWharton/docker-mbsync

started time in 6 hours

push eventmarchof/java-almanac

GitHub Action

commit sha b8a5e919530fba0fe8cdfc33cea416308eee9c1a

Update API diffs to 17-ea+11-835-open

view details

push time in 7 hours

push eventcashapp/paparazzi

John Rodriguez

commit sha 6b80ca99651624f9c3fe9740e51652d0a4689ca8

Update sample to latest Paparazzi version

view details

John Rodriguez

commit sha 1cec99a4f53a14b65495ad8e2b453d0f80b7d3b8

Update build.gradle Co-authored-by: Jake Wharton <github@jakewharton.com>

view details

John Rodriguez

commit sha 18212c6ce981cde1946652c157cf135eff5a0051

Merge pull request #210 from cashapp/jrod/2021-02-26/update-sample Update sample to latest Paparazzi version

view details

push time in 7 hours

delete branch cashapp/paparazzi

delete branch : jrod/2021-02-26/update-sample

delete time in 7 hours