<div dir="ltr"><div dir="ltr">On Fri, Nov 4, 2022 at 1:08 PM Brian Goetz <<a href="mailto:brian.goetz@oracle.com" target="_blank">brian.goetz@oracle.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div>
<font size="4"><font face="monospace">We should check each file
locally, without regard to whether superclasses or subclasses
are problematic.</font></font></div></blockquote><div><br></div><div>That definitely keeps things simpler.<br></div><div><br></div><div>So it sounds like we have boiled this down to the following:</div><div><ol><li>Add one new warning, which applies to one class at a time</li><li>The warning looks for constructors with a possible 'this' escape<br></li></ol></div><div>Obviously this is a "best effort" thing, false positives will happen. The warning would say something like "possible early access before instance is fully initialized".</div></div><div class="gmail_quote"><br></div><div class="gmail_quote">Now we just need a definition of "possible 'this' escape".</div><div class="gmail_quote"><br></div><div class="gmail_quote">The goal is to close off all routes by which 'this' could end up being passed to code in any subclass. In other words we are not trying to save the class from itself.<br><div><br></div><div>Attempt #1...</div><div><br></div><div>A 'this' escape is when, in a non-final class <span style="font-family:monospace">MyClass</span> constructor, after a <span style="font-family:monospace">super()</span> call, a reference to the 'this' instance is used, explicitly or implicitly, in any expression that (as far as the compiler can tell) might possibly:<br></div><div><ol><li>Invoke a non-static method declared in any strict supertype of <span style="font-family:monospace">MyClass</span></li><li><span style="font-family:monospace"></span>Invoke a non-static, non-private, non-final method declared in <span style="font-family:monospace">MyClass</span></li><li>Invoke a non-static, private or final method declared in <span style="font-family:monospace">MyClass</span> that has a possible 'this' escape (recursive definition)<br></li><li>Otherwise access a field <span style="font-family:monospace"><span style="font-family:arial,sans-serif">or i<span style="font-family:monospace"><span style="font-family:arial,sans-serif">nvoke a non-static method </span></span>declared in</span></span> any subclass of <span style="font-family:monospace">MyClass</span></li></ol></div><div>Any expression caught by #4 would necessarily involve a downcast, so the compiler might choose to simply check for any expression that could possibly downcast 'this'.<br></div><br><div>Test case 1: <span style="font-family:monospace">HashSet</span> should generate a warning. It does because of case #1.<br></div><div><br></div><div>Test case 2: the class below should not generate a warning. It doesn't because <span style="font-family:monospace">resetBoard()</span> is private and contains no 'this' escapes.<br></div><div><br><div style="margin-left:40px"><span style="font-family:monospace">public class TicTacToe {</span></div><div style="margin-left:40px"><span style="font-family:monospace"><br></span></div><div style="margin-left:40px"><span style="font-family:monospace"> private final char[][] board = new char[3][3];<br></span></div><div style="margin-left:40px"><span style="font-family:monospace"><br></span></div><div style="margin-left:40px"><span style="font-family:monospace"> public TicTacToe() {</span></div><div style="margin-left:40px"><span style="font-family:monospace"> this.<span style="font-family:monospace">resetBoard</span>();<br></span></div><div style="margin-left:40px"><span style="font-family:monospace"> }<br></span></div><div style="margin-left:40px"><span style="font-family:monospace"><br></span></div><div style="margin-left:40px"><span style="font-family:monospace"> private void resetBoard() {</span></div><div style="margin-left:40px"><span style="font-family:monospace"> Stream.of(this.board).forEach(row -> Arrays.fill(row, ' '));<br></span></div><div style="margin-left:40px"><span style="font-family:monospace"> }</span></div><div style="margin-left:40px"><span style="font-family:monospace"><br></span></div><div style="margin-left:40px"><span style="font-family:monospace"> // more stuff here...<br></span></div><div style="margin-left:40px"><span style="font-family:monospace">}<br></span></div></div><div><br></div><div>Test case 3: <span style="font-family:monospace">FilteredSet</span> does not generate a warning. Instead, we are putting the "blame" on <span style="font-family:monospace">HashSet</span>.<br></div><div><br></div><div> -Archie<br clear="all"></div></div><br>-- <br><div dir="ltr">Archie L. Cobbs<br></div></div>