-
Notifications
You must be signed in to change notification settings - Fork 64
[generator] better support for "package-private" classes #223
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
Conversation
|
I found that old binding project that ran into this issue, it was a sample from my Xamarin book. Using generator from this PR allows me to remove this: |
|
As with PR #216, this is going to have knock-on impacts of xamarin-android, particularly around In order to accept this patch, we're going to need to have the xamarin-android-side patch to allow things to continue to build. |
|
Additionally, I do not want to merge this PR or PR #216 before the d15-6 branch date. We'll merge these for d15-7. |
tools/generator/GenBaseSupport.cs
Outdated
|
|
||
| public override string Visibility { | ||
| get { return t.IsPublic || t.IsNestedPublic ? "public" : "protected internal"; } | ||
| set { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should throw InvalidOperationException so that anyone who works on generator should immediately notice that it is inappropriately used and not hiding the actual issue.
|
Yeah, I don't think we should merge this one or #216 until d15-7. Especially if I'm going to be on leave at the beginning of next year. |
81e8d7f to
44c9561
Compare
44c9561 to
d3c19ca
Compare
|
Note the It has a report of a master/master build of java.interop/xamarin-android of this PR. (More details on the private monodroid repo's wiki) The results are:
I'm still working on automating the same kind of build on some of Redth's components. |
I don't like this idea, as it creates a potential API compatibility problem. The whole point is that Meaning this is entirely plausible: // Version 1
/* package */ class Base1 {
public void foo() {}
}
public class TheFooinator extends Base1 {
/* foo() is automagically a public member */
}and then for version 2: // version 2
/* package */ class RefactoredBase {
public void foo() {}
}
public class TheFooinator extends RefactoredBase {
/* foo() is automagically a public member */
}By making |
d3c19ca to
5e09a7b
Compare
|
I've started reworking this PR to just not emit the "package private" classes in C# at all. I still need to:
|
|
@jonpryor @atsushieno I've reworked this so it's ready for review again. We basically just needed to prevent the "package private" types from being listed as base classes in C#. |
tools/generator/ClassGen.cs
Outdated
|
|
||
| public override string BaseType { | ||
| get { return nominal_base_type != null ? nominal_base_type.FullNameCorrected () : null; } | ||
| set { throw new NotImplementedException (); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not required (no need to do unless you are making further changes) but a suggested change is to use NotSupportedException instead of NIE. NIE means "we plan to implement" or "any derived classes are supposed to implement".
|
Please update the commit message/PR message to:
Additionally, please don't rely on Suggested commit message: Also note that I personally don't like backtick-backtick-backtick blocks within commit messages, as they make it harder to skim & read the content. I prefer indentation, as shown above. YMMV. |
| while (!IsAnnotation && !string.IsNullOrEmpty (BaseType)) { | ||
| var baseClass = SymbolTable.Lookup (BaseType) as ClassGen; | ||
| if (baseClass != null && RawVisibility == "public" && baseClass.RawVisibility != "public") { | ||
| BaseType = baseClass.BaseType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be "recursive"?
Consider:
public class A {
public void a() {}
}
/* package */ class B extends A {
public void b() {}
}
/* package */ class C extends B {
public void c() {}
}
public class P extends C {
public void p() {}
}$ javap -cp . P
Compiled from "P.java"
public class P extends C {
public P();
public void p();
public void c();
public void b();
}From our perspective, we can't have P inherit C, as C is package-private, but it should inherit from A, which is public:
public partial class A {
public virtual void InvokeA() {...}
}
public partial class P : A {
public virtual void B() {...}
public virtual void C() {...}
public virtual void InvokeP() {...}
}I'm not certain that this statement will support the above.
Aside: the above javap output is bonkers: it's missing A.a()!
This despite the fact that it is callable!
public class App {
public static void main (String[] args) {
P p = new P();
p.a();
}
}¯_(ツ)_/¯
Fixes dotnet#168 Java allows public classes to inherit from "package-private" classes, in which case the `public` & `protected` members of the "package-private" class are visible within the public class: // Java /* package */ abstract class SpannableStringInternal { public void getChars(int start, int end, char[] dest, int off); // ... } public class SpannableString extends SpannableStringInternal { // ... } The problem is that `generator` didn't properly support this construct, and *skips* binding of "package-private" types, resulting in generated C# code such as: // C# public partial class SpannableString : SpannableStringInternal { // CS0246: The type or namespace name `SpannableStringInternal` could not be found } This could be worked aroudn via Metadata by making the "package-private" class `public`, but this means that if (when?) the "package-private" class is *removed*, we have an ABI break. Support this construct by updating `generator` to "copy" the members from the "package-private" class into the declaring class: // C# public partial class SpannableString : Java.Lang.Object { public void GetChars(int start, int end, char[] dest, int off); // ... } This allows the generated code to compile without metadata fixup. Specifics in implementing this: - Add a `FixupAccessModifiers` method to `GenBase`, later this may need to be further extended for methods - Call `FixupAccessModifiers` in the "validation" step - Added a setter for `BaseType` so it can be modified - In `FixupAccessModifiers`, lookup the base class of the current type and check if it is non-public - Skip the package-private types, and replace them with that class's base type - Look for each method on the base type, and copy it to the public type if it does not exist - Added tests for this scenario
5e09a7b to
e9391cb
Compare
|
@jonpryor FYI this time I put the full issue URL in the commit message locally: Is the web rendering the issue number shortened? |
¯_(ツ)_/¯ I hit the "Edit comment" link/button on the PR message, and that contains: Normally that value is pre-filled with the commit-message contents... |
|
Ok next time I’ll edit the PR text after the fact, I bet that works. |

Fixes #168
Java allows public classes to inherit from "package-private" classes, in
which case the
public&protectedmembers of the "package-private"class are visible within the public class:
The problem is that
generatordidn't properly support this construct,and skips binding of "package-private" types, resulting in generated
C# code such as:
This could be worked aroudn via Metadata by making the "package-private"
class
public, but this means that if (when?) the "package-private"class is removed, we have an ABI break.
Support this construct by updating
generatorto "copy" the membersfrom the "package-private" class into the declaring class:
This allows the generated code to compile without metadata fixup.
Specifics in implementing this:
FixupAccessModifiersmethod toGenBase, later this mayneed to be further extended for methods
FixupAccessModifiersin the "validation" stepBaseTypeso it can be modifiedFixupAccessModifiers, lookup the base class of the current typeand check if it is non-public
base type
if it does not exist