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.
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
Kotlin compiler plugin which brings Kotlin/JS's unsafeCast to Kotlin/JVM
startedJakeWharton/NineOldAndroids
started time in 2 minutes
push eventoznu/docker-cloudflare-ddns
commit sha da678bf65978a0e3f516aa5890389e2ed2235e53
Upgrade to Alpine 3.13
commit sha ee6dde2793f0fc17b4917bb4caa9ac32dfcc2635
Merge pull request #61 from tomaswarynyca/patch-1 Upgrade to Alpine 3.13
push time in 32 minutes
PR merged oznu/docker-cloudflare-ddns
pr closed time in 32 minutes
issue commentjordanpotter/docker-wireguard
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? 🤔
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).
comment created time in an hour
push eventJetBrains/kotlin
commit sha 3022fb396b4f117f0f4837939aab11921a8e4541
Add fasutil to the list of package to relocate (KT-44758) #KT-44758 Fixed
push time in an hour
push eventUweTrottmann/SeriesGuide
commit sha 9be6ef0682f4272d0dc1f59904d7778d98fd62ec
Allow removal of legacy show if connected to Cloud.
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
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...
comment created time in 2 hours
PR opened square/okhttp
Test case related to cache corruption found in #6453
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;
.
comment created time in 3 hours
push eventgoogle/desugar_jdk_libs
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
push time in 4 hours
push eventJetBrains/kotlin
commit sha 482e217b5e96fbb7422f96e02202eb0ff35c6999
JVM IR: Fix inline class mangling for calls to internal functions ...in a different module, e.g., using -Xfriend-paths.
commit sha be9ef8f3c84dbdc0ef706a9cacae405a8812a479
Remove obsolete DxChecker
commit sha 6a29097a8caa8c7299bc43f6441b3026bbaa5493
Remove obsolete dependency for dx
commit sha 021a63827d40b1ecfd1b0ded8e9f38d64d2732d8
Add API version 1.5 to accepted values in MPP language settings
commit sha 21f022dec295686ba31f93136c26dd73e58c1cd8
Add :kotlin-scripting-compiler.test to modules with disabled -Werror flag
commit sha 9f9c8e3d778bcdfff6b1d41a1cc5509818da130c
Mute stream api test on Android
commit sha 2bbe3db0411d51f0cbd79e4d622f525e46cab03b
Update copyrights in CLI scripts
commit sha 2ef4ca4e6e743e3e787a74de5f02cebd66e8e123
CLI: do not pass -noverify to java process starting from JDK 13 #KT-44232 Fixed
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
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
commit sha 16b3fedcd4f363c1afdc5810a4dd8beb6ff4e46a
Created AbstractKlibBinaryCompatibilityTest and AbstractJsKlibBinaryCompatibilityTest A common test runner for klib binary compatibility tests and its js counterpart
commit sha 6265ac8c198a39aa536b4f976b95833098cd03bf
Re-enabled disabled test
commit sha 772ca2715c74fddeee95e5a9fddd10251c71bb7f
[Test] Don't change testdata in FirIdenticalChecker in teamcity mode
commit sha 297288e98484ddf21a7a1444ad17d7268bb026bd
[Test] Don't generate new files in GeneratorsFileUtil in teamcity mode
commit sha 771600077cadad50bc9a32e53f322944fbf358b6
[Test] Fail if there are changes in generated fir tree files in teamcity build
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
commit sha d022bb0248a3f199ea0bc671b93dc30c5052c292
Switch default JVM target to 1.8 #KT-29405 Fixed
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.
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`.
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
push time in 5 hours
push eventandroidx/androidx
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
commit sha bdcb2e8cda94281d314eec3c18bb7a4d2581aa2a
Merge "Incremental processing for KSP" into androidx-main
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.
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.
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.
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.
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.
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.
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!
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.
comment created time in 5 hours
startedJakeWharton/timber
started time in 6 hours
push eventandroidx/androidx
commit sha d0aa428244246132d1df645be34ab3e601ab5976
Fix typo in ktdoc for mutableStateMapOf Change-Id: I2c3fba07830d703426948fa3a007b592db07c376
commit sha 54d99af63343b05a5d8b678e75340824a043b9b6
Merge "Fix typo in ktdoc for mutableStateMapOf" into androidx-main
push time in 6 hours
startedJakeWharton/docker-mbsync
started time in 6 hours
push eventmarchof/java-almanac
commit sha b8a5e919530fba0fe8cdfc33cea416308eee9c1a
Update API diffs to 17-ea+11-835-open
push time in 7 hours
push eventcashapp/paparazzi
commit sha 6b80ca99651624f9c3fe9740e51652d0a4689ca8
Update sample to latest Paparazzi version
commit sha 1cec99a4f53a14b65495ad8e2b453d0f80b7d3b8
Update build.gradle Co-authored-by: Jake Wharton <github@jakewharton.com>
commit sha 18212c6ce981cde1946652c157cf135eff5a0051
Merge pull request #210 from cashapp/jrod/2021-02-26/update-sample Update sample to latest Paparazzi version
push time in 7 hours
delete branch cashapp/paparazzi
delete branch : jrod/2021-02-26/update-sample
delete time in 7 hours