Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Private Java field with public accessors has private keyword in Kotlin signature #2439

Closed
flyingfish162 opened this issue Apr 14, 2022 · 6 comments · Fixed by #2532
Closed
Labels
bug good first issue A beginner-friendly issue for which some assistance is expected

Comments

@flyingfish162
Copy link

Describe the bug
I have a module mixed with java/kotlin classes in Android project. Generating docs with includeNonPublic set to false still adds Java non-public properties (that have public getter/setter specifically) to the output while their getter and setter not outputted.

Expected behaviour
Non-public properties not visible in the html output while their public getter and setter are visible.

Screenshots
Current generated doc page:
Screen Shot 2022-04-14 at 17 27 55
Screen Shot 2022-04-14 at 17 30 22

To Reproduce

  1. Create TestClass.java:
package com.example.test;

public class TestClass {
    private int a;
    int b;

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }
}
  1. Run ./gradlew app:dokkaHtml
  2. Output should not contain a and b but public getter and setter

Dokka configuration
Configuration of dokka used to reproduce the bug

Module build.gradle:

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

apply from: 'kdoc.gradle'

kdoc.gradle:

apply plugin: "org.jetbrains.dokka"

dokkaHtml {
    outputDirectory.set(file("build/kdoc"))
    dokkaSourceSets {
        configureEach {
            includeNonPublic.set(false)
            skipEmptyPackages.set(true)
            jdkVersion.set(8)
            noAndroidSdkLink.set(true)
            noStdlibLink.set(true)
            noJdkLink.set(true)
        }
    }
}

Project build.gradle:

buildscript {
    dependencies {
        classpath 'com.android.tools.build:gradle:7.1.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.20"
        classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.6.10")
    }
}

Installation

  • Operating system: macOS
  • Build tool: Gradle v7.2
  • Dokka version: 1.6.10

Additional context
I see this issue since Dokka version 1.4.32

@IgnatBeresnev
Copy link
Member

IgnatBeresnev commented Apr 25, 2022

Hi!

I believe this is how kotlin-java interop works:

  • From Kotlin's perspective, if a java field has both a getter and a setter - it's a var property. If it only has the getter, it's a val.
  • From Java's perspective, if the kotlin property is var, it contains both the getter and the setter, while a val only contains the getter.

2022-04-25_23-48-59

Non-public properties not visible in the html output while their public getter and setter are visible.

So I don't think your expected behaviour is correct, it would simply be wrong even compared to the Intellij IDEA. In Kotlin, there's no concept of getters and setters

However, it is indeed wrong that the word private is present in there. It should not be there, then everything will make sense and be correct.

@IgnatBeresnev IgnatBeresnev added the good first issue A beginner-friendly issue for which some assistance is expected label Apr 25, 2022
@IgnatBeresnev
Copy link
Member

IgnatBeresnev commented Apr 25, 2022

For anyone looking to fix this, here's the expected behaviour. For the java class

public class TestClass {
    private int a;

    public int getA() {
        return a;
    }

    public void setA(int a) {

    }
}

it should generate the following signature:

It seems to be a relatively easy fix for in terms of writing code, here's where the problem is: KotlinSignatureProvider#propertySignature.

It should throw away private (and possibly other non-public) visibility keyword if this property has publicly available accessors. For instance - private properties with public getters and setters, like in the example above.

The fix should be roughly something like this (should be cleaned up of course):

p.visibility[sourceSet].takeIf {
    val isPrivateJavaPropertyWithPublicAccessors =
        (it == JavaVisibility.Private)
                && (p.getter?.visibility?.get(sourceSet) == JavaVisibility.Public)
                && (p.setter?.visibility?.get(sourceSet) == JavaVisibility.Public)

    it !in ignoredVisibilities && !isPrivateJavaPropertyWithPublicAccessors
}?.name?.let { keyword("$it ") }

However, fixing this will involve some thinking and testing for corner cases:

  1. Can setting documentedVisibilities (and legacy includeNonPublic) introduce more bugs after the fix?
  2. What to do with other modifiers, such as protected/package-private.
  3. What to do if accessors are not public, or only one accessor is public and the other is private. This should probably be compared to how Intellij IDEA behaves.
  4. Do we need to take into account the value set in documentedVisibilities?

And more tests with corner cases will need to be added. SignatureTest is for Kotlin sources only, so a class nearby, something like JavaToKotlinSignatureTest would do the job.

@IgnatBeresnev IgnatBeresnev changed the title includeNonPublic.set(false) doesn't omit Java non-public fields that have public getter and setter Private Java field with public accessors has private keyword in Kotlin signature Apr 25, 2022
@IgnatBeresnev IgnatBeresnev linked a pull request Jun 15, 2022 that will close this issue
@IgnatBeresnev
Copy link
Member

Will be fixed in #2532, thanks for the report!

@EvgeniyMish
Copy link

Hi! I still experience this issue in 1.8.20.

@IgnatBeresnev
Copy link
Member

@EvgeniyMish could you please share the use case? A number of unit tests were written in #2439, so it's unlikely to be a regression - most likely it's a different bug or yet another corner case

@anmolsingla2323
Copy link

anmolsingla2323 commented Nov 8, 2023

Can some one please provide an example on how to use documentedVisibilities to generate documentation for public accessors (get and set) with private field.

I already tried
documentedVisibilities.set([DokkaConfiguration.Visibility.PUBLIC])

No errors where produced but documentation for get set functions were also not produced

I am using groovy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug good first issue A beginner-friendly issue for which some assistance is expected
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants