On Thu, 12 Jan 2023 16:20:12 GMT, Archie L. Cobbs <[email protected]> wrote:
>> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java
>> line 218:
>>
>>> 216: new TreeScanner() {
>>> 217:
>>> 218: private Lint lint = ThisEscapeAnalyzer.this.lint;
>>
>> On a first look I'm not sure about the granularity of suppression here. I
>> believe that suppressing at the class level, or at the constructor level is
>> enough. Allowing to further annotate var declarations and non-constructor
>> methods, while doable, might actually be counter productive - in the sense
>> that the annotation does not occur in the constructor (where you'd want to
>> see it) but in some other method. I think the fact that a constructor is
>> escaping (willingly) should be a visible thing. Something to consider.
>
> Two things...
>
> We need to support annotations on field declarations because their
> initializers are effectively mini-constructors. But we don't need it on local
> variables, parameters, etc. - too confusing.
>
> For annotations on methods, yes it's debatable. It can be handy if you have
> e.g. an `init()` method that all of your constructors invoke. However, I
> agree it's also confusing, so I will remove.
>
> But we should keep the notion that if a constructor invokes `this()`, and the
> invoked constructor has annotations suppressed, then we skip over the
> constructor invocation.
>
> I will make these updates.
Yep - I guess there's a general theme of "where do we want the warnings to be
reported". My general feeling is that reporting a warning on the constructor
might be enough - but I see that you try to generate a warning in the exact
spot where the leakage happens - which I'm not sure if it's ok, or too clever.
>> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java
>> line 270:
>>
>>> 268: final boolean analyzable =
>>> this.currentClassIsExternallyExtendable() &&
>>> 269: TreeInfo.isConstructor(tree) &&
>>> 270: !tree.sym.isPrivate() &&
>>
>> Why aren't private constructors analyzed? If we have a class with a private
>> constructor and public static factory invoking said constructor, and the
>> constructor makes `this` escape, isn't that an issue we should detect?
>
>> If we have a class with a private constructor and public static factory
>> invoking said constructor, and the constructor makes this escape, isn't that
>> an issue we should detect?
>
> A static factory method will not create a subclassed instance, so there's no
> 'this' escape problem.
>
> But I admit I completely missed factory methods as a potential thing to worry
> about.
>
> Is it possible for a leak to be missed due to the use of a factory method?
>
> Hmm. I can't immediately think of how, but if you can come up with an example
> please share.
I guess what I'm thinking about:
class Foo {
private Foo() {
m(this);
}
public void m() { ... } // overridable
static Foo makeFoo() { return new Foo(); }
}
>> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java
>> line 294:
>>
>>> 292: !(this.currentClass.sym.isSealed() &&
>>> this.currentClass.permitting.isEmpty()) &&
>>> 293: !(this.currentClass.sym.owner.kind == MTH) &&
>>> 294: !this.privateOuter;
>>
>> Here, note that is the owner of the current class symbol is a method, that
>> covers anonymous classes too, which is a part of `privateOuter`. So the only
>> think we need to check here is whether "currentClass" is private, which is a
>> simple predicate. No need to carry `privateOuter` I believe
>
> Unless you explicitly declare a nested class `private`, it won't have the
> `ACC_PRIVATE` flag, even though it is "implicitly private" because it has a
> `private` enclosing class.
>
> Example:
>
> $ cat PrivateOuter.java
> public class PrivateOuter {
> private static class Inner1 {
> static class Inner2 {
> }
> }
> }
> $ javap -v PrivateOuter$Inner1$Inner2
> Classfile
> /Users/archie/proj/jdk/flex-test/classes/PrivateOuter$Inner1$Inner2.class
> Last modified Jan 12, 2023; size 408 bytes
> SHA-256 checksum
> 51ba6d39a5e66df2a078761d6424acbea7a8e32b8451f6ca7d2af49889673b2c
> Compiled from "PrivateOuter.java"
> class PrivateOuter$Inner1$Inner2
> minor version: 0
> major version: 63
> flags: (0x0020) ACC_SUPER
> this_class: #7 // PrivateOuter$Inner1$Inner2
> super_class: #2 // java/lang/Object
> ...
>
>
> So we have to keep track of this "implicit privateness" manually, which is
> what the `privateOuter` flag is for.
D'oh - missed the `|=` - so this keeps updating...
-------------
PR: https://git.openjdk.org/jdk/pull/11874