Skip to content

Commit

Permalink
https://github.com/manifold-systems/manifold/issues/449
Browse files Browse the repository at this point in the history
- handle shadowing where an instance field shadows an inner class of the same name. This is particularly useful in code gen where both a property and an inner type are derived from the same element. Otherwise, use-cases such as: Person.address.builder(), don't work because address resolves as the field and not the inner class.
- json type manifold code gen, maintain a single file field at the top-level and reference that with fully qualified name, avoids naming collision with manifold-props
  • Loading branch information
rsmckinney committed May 16, 2023
1 parent 305f3c7 commit 6720775
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.Tag;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.util.*;

import java.util.*;
import java.util.function.BiPredicate;
import java.util.function.Predicate;

import com.sun.tools.javac.util.Names;
import manifold.api.util.IssueMsg;
import manifold.internal.javac.AbstractBinder.Node;
import manifold.util.JreUtil;
import manifold.util.ReflectUtil;

import static com.sun.tools.javac.code.Flags.INTERFACE;
Expand All @@ -43,6 +44,13 @@ public interface ManAttr
{
String AUTO_TYPE = "manifold.ext.rt.api.auto";

Object Kind_TYP = JreUtil.isJava8()
? ReflectUtil.field( Kinds.class, "TYP" ).getStatic()
: ReflectUtil.field( Kinds.class.getTypeName() + "$Kind", "TYP" ).getStatic();
Object KindSelector_TYP = JreUtil.isJava8()
? ReflectUtil.field( Kinds.class, "TYP" ).getStatic()
: ReflectUtil.field( Kinds.class.getTypeName() + "$KindSelector", "TYP" ).getStatic();

boolean JAILBREAK_PRIVATE_FROM_SUPERS = true;

String COMPARE_TO = "compareTo";
Expand Down Expand Up @@ -76,6 +84,11 @@ default Log getLogger()
return (Log)ReflectUtil.field( this, "log" ).get();
}

default Object resultInfo()
{
return ReflectUtil.field( this, "resultInfo" ).get();
}

default Check chk()
{
return (Check)ReflectUtil.field( this, "chk" ).get();
Expand Down Expand Up @@ -396,6 +409,128 @@ default boolean isAutoType( Type type )
return type != null && type.tsym != null && type.tsym.getQualifiedName().toString().equals( AUTO_TYPE );
}

/**
* Facilitates handling shadowing where an instance field shadows an inner class of the same name.
* This is particularly useful in code gen where both a property and an inner type are derived from the same element.
* Otherwise, use-cases such as: Person.address.builder(), don't work because address resolves as the field and not
* the inner class.
*/
default void restoreDiagnostics( JCTree.JCFieldAccess tree, DeferredAttrDiagHandler deferredAttrDiagHandler )
{
Queue<JCDiagnostic> diagnostics = deferredAttrDiagHandler.getDiagnostics();
if( !diagnostics.isEmpty() )
{
if( ((tree.selected instanceof JCTree.JCIdent && isType( ((JCTree.JCIdent)tree.selected).sym )) ||
(tree.selected instanceof JCTree.JCFieldAccess) && isType( ((JCTree.JCFieldAccess)tree.selected).sym )) &&
tree.sym instanceof Symbol.VarSymbol )
{
getLogger().popDiagnosticHandler( deferredAttrDiagHandler );
tree.sym = null;
if( tree.selected instanceof JCTree.JCIdent )
{
((JCTree.JCIdent)tree.selected).sym = null;
}
else
{
((JCTree.JCFieldAccess)tree.selected).sym = null;
}
ReflectUtil.field( resultInfo(), "pkind" ).set( KindSelector_TYP );

ReflectUtil.method( this, "visitSelect", JCTree.JCFieldAccess.class ).invokeSuper( tree );
// super.visitSelect( tree );

return;
}

deferredAttrDiagHandler.reportDeferredDiagnostics();
}
getLogger().popDiagnosticHandler( deferredAttrDiagHandler );
}
static boolean isType( Symbol sym )
{
return sym != null && Objects.equals( ReflectUtil.field( sym, "kind" ).get(), Kind_TYP );
}
default DeferredAttrDiagHandler suppressDiagnositics( JCTree.JCFieldAccess tree )
{
return new DeferredAttrDiagHandler( getLogger(), tree );
}

class DeferredDiagnosticHandler extends Log.DiagnosticHandler
{
private Queue<JCDiagnostic> deferred = new ListBuffer<>();
private final Predicate<JCDiagnostic> filter;

public DeferredDiagnosticHandler(Log log) {
this(log, null);
}

public DeferredDiagnosticHandler(Log log, Predicate<JCDiagnostic> filter) {
this.filter = filter;
install(log);
}

@Override
public void report(JCDiagnostic diag) {
if (!diag.isFlagSet(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE) &&
(filter == null || filter.test(diag))) {
deferred.add(diag);
} else {
prev.report(diag);
}
}

public Queue<JCDiagnostic> getDiagnostics() {
return deferred;
}

/** Report all deferred diagnostics. */
public void reportDeferredDiagnostics() {
reportDeferredDiagnostics(EnumSet.allOf(JCDiagnostic.Kind.class));
}

/** Report selected deferred diagnostics. */
public void reportDeferredDiagnostics(Set<JCDiagnostic.Kind> kinds) {
JCDiagnostic d;
while ((d = deferred.poll()) != null) {
if (kinds.contains(d.getKind()))
prev.report(d);
}
deferred = null; // prevent accidental ongoing use
}
}
class DeferredAttrDiagHandler extends DeferredDiagnosticHandler
{
static class PosScanner extends TreeScanner
{
JCDiagnostic.DiagnosticPosition pos;
boolean found = false;

PosScanner( JCDiagnostic.DiagnosticPosition pos )
{
this.pos = pos;
}

@Override
public void scan( JCTree tree )
{
if( tree != null &&
tree.pos() == pos )
{
found = true;
}
super.scan( tree );
}
}
DeferredAttrDiagHandler( Log log, JCTree newTree )
{
super( log, d -> {
DeferredAttrDiagHandler.PosScanner posScanner = new DeferredAttrDiagHandler.PosScanner( d.getDiagnosticPosition() );
posScanner.scan( newTree );
return posScanner.found;
} );
}
}

/**
* Handle properties in interfaces, which are non-static unless explicitly static.
* This is necessary so that a non-static property can reference type variables in its type: @var T element;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class ManAttr_11 extends Attr implements ManAttr
private final ManLog_11 _manLog;
private final Symtab _syms;
private final Stack<JCTree.JCFieldAccess> _selects;
private final Stack<JCTree.JCMethodInvocation> _applys;
private final Stack<JCTree.JCAnnotatedType> _annotatedTypes;
private final Stack<JCTree.JCMethodDecl> _methodDefs;
private final Set<JCTree.JCMethodInvocation> _visitedAutoMethodCalls = new HashSet<>();
Expand All @@ -66,6 +67,7 @@ public class ManAttr_11 extends Attr implements ManAttr
{
super( ctx );
_selects = new Stack<>();
_applys = new Stack<>();
_annotatedTypes = new Stack<>();
_methodDefs = new Stack<>();
_syms = Symtab.instance( ctx );
Expand Down Expand Up @@ -125,7 +127,23 @@ public class ManAttr_11 extends Attr implements ManAttr
_selects.push( tree );
try
{
super.visitSelect( tree );
JCTree.JCMethodInvocation parent = peekApply();
DeferredAttrDiagHandler deferredAttrDiagHandler = null;
if( parent == null || parent.meth != tree )
{
deferredAttrDiagHandler = suppressDiagnositics( tree );
}
try
{
super.visitSelect( tree );
}
finally
{
if( deferredAttrDiagHandler != null )
{
restoreDiagnostics( tree, deferredAttrDiagHandler );
}
}
patchAutoFieldType( tree );
}
finally
Expand Down Expand Up @@ -479,6 +497,11 @@ public class ManAttr_11 extends Attr implements ManAttr
return _selects.isEmpty() ? null : _selects.peek();
}

public JCTree.JCMethodInvocation peekApply()
{
return _applys.isEmpty() ? null : _applys.peek();
}

public JCTree.JCAnnotatedType peekAnnotatedType()
{
return _annotatedTypes.isEmpty() ? null : _annotatedTypes.peek();
Expand Down Expand Up @@ -512,6 +535,7 @@ public class ManAttr_11 extends Attr implements ManAttr
_manLog.pushSuspendIssues( tree ); // since method-calls can be nested, we need a tree of stacks TreeNode(JCTree.JCFieldAccess, Stack<JCDiagnostic>>)
}

_applys.push( tree );
JCTree.JCFieldAccess fieldAccess = (JCTree.JCFieldAccess)tree.meth;
try
{
Expand Down Expand Up @@ -549,6 +573,7 @@ public class ManAttr_11 extends Attr implements ManAttr
}
finally
{
_applys.pop();
if( JAILBREAK_PRIVATE_FROM_SUPERS )
{
_manLog.popSuspendIssues( tree );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class ManAttr_17 extends Attr implements ManAttr
private final ManLog_11 _manLog;
private final Symtab _syms;
private final Stack<JCTree.JCFieldAccess> _selects;
private final Stack<JCTree.JCMethodInvocation> _applys;
private final Stack<JCTree.JCAnnotatedType> _annotatedTypes;
private final Stack<JCTree.JCMethodDecl> _methodDefs;
private final Set<JCTree.JCMethodInvocation> _visitedAutoMethodCalls = new HashSet<>();
Expand All @@ -67,6 +68,7 @@ public class ManAttr_17 extends Attr implements ManAttr
{
super( ctx );
_selects = new Stack<>();
_applys = new Stack<>();
_annotatedTypes = new Stack<>();
_methodDefs = new Stack<>();
_syms = Symtab.instance( ctx );
Expand Down Expand Up @@ -128,7 +130,23 @@ public class ManAttr_17 extends Attr implements ManAttr
_selects.push( tree );
try
{
super.visitSelect( tree );
JCTree.JCMethodInvocation parent = peekApply();
DeferredAttrDiagHandler deferredAttrDiagHandler = null;
if( parent == null || parent.meth != tree )
{
deferredAttrDiagHandler = suppressDiagnositics( tree );
}
try
{
super.visitSelect( tree );
}
finally
{
if( deferredAttrDiagHandler != null )
{
restoreDiagnostics( tree, deferredAttrDiagHandler );
}
}
patchAutoFieldType( tree );
}
finally
Expand Down Expand Up @@ -499,6 +517,11 @@ public class ManAttr_17 extends Attr implements ManAttr
return _selects.isEmpty() ? null : _selects.peek();
}

public JCTree.JCMethodInvocation peekApply()
{
return _applys.isEmpty() ? null : _applys.peek();
}

public JCTree.JCAnnotatedType peekAnnotatedType()
{
return _annotatedTypes.isEmpty() ? null : _annotatedTypes.peek();
Expand Down Expand Up @@ -532,6 +555,7 @@ public class ManAttr_17 extends Attr implements ManAttr
_manLog.pushSuspendIssues( tree ); // since method-calls can be nested, we need a tree of stacks TreeNode(JCTree.JCFieldAccess, Stack<JCDiagnostic>>)
}

_applys.push( tree );
JCTree.JCFieldAccess fieldAccess = (JCTree.JCFieldAccess)tree.meth;
try
{
Expand Down Expand Up @@ -569,6 +593,7 @@ public class ManAttr_17 extends Attr implements ManAttr
}
finally
{
_applys.pop();
if( JAILBREAK_PRIVATE_FROM_SUPERS )
{
_manLog.popSuspendIssues( tree );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class ManAttr_8 extends Attr implements ManAttr
private final ManLog_8 _manLog;
private final Symtab _syms;
private final Stack<JCTree.JCFieldAccess> _selects;
private final Stack<JCTree.JCMethodInvocation> _applys;
private final Stack<JCTree.JCAnnotatedType> _annotatedTypes;
private final Stack<JCTree.JCMethodDecl> _methodDefs;
private final Set<JCTree.JCMethodInvocation> _visitedAutoMethodCalls = new HashSet<>();
Expand All @@ -80,6 +81,7 @@ private ManAttr_8( Context ctx )
{
super( ctx );
_selects = new Stack<>();
_applys = new Stack<>();
_annotatedTypes = new Stack<>();
_methodDefs = new Stack<>();
_syms = Symtab.instance( ctx );
Expand Down Expand Up @@ -135,7 +137,23 @@ public void visitSelect( JCTree.JCFieldAccess tree )
_selects.push( tree );
try
{
super.visitSelect( tree );
JCTree.JCMethodInvocation parent = peekApply();
DeferredAttrDiagHandler deferredAttrDiagHandler = null;
if( parent == null || parent.meth != tree )
{
deferredAttrDiagHandler = suppressDiagnositics( tree );
}
try
{
super.visitSelect( tree );
}
finally
{
if( deferredAttrDiagHandler != null )
{
restoreDiagnostics( tree, deferredAttrDiagHandler );
}
}
patchAutoFieldType( tree );
}
finally
Expand Down Expand Up @@ -466,6 +484,11 @@ public JCTree.JCFieldAccess peekSelect()
return _selects.isEmpty() ? null : _selects.peek();
}

public JCTree.JCMethodInvocation peekApply()
{
return _applys.isEmpty() ? null : _applys.peek();
}

public JCTree.JCAnnotatedType peekAnnotatedType()
{
return _annotatedTypes.isEmpty() ? null : _annotatedTypes.peek();
Expand Down Expand Up @@ -499,6 +522,7 @@ public void visitApply( JCTree.JCMethodInvocation tree )
_manLog.pushSuspendIssues( tree ); // since method-calls can be nested, we need a tree of stacks TreeNode(JCTree.JCFieldAccess, Stack<JCDiagnostic>>)
}

_applys.push( tree );
JCTree.JCFieldAccess fieldAccess = (JCTree.JCFieldAccess)tree.meth;
try
{
Expand Down Expand Up @@ -536,6 +560,7 @@ public void visitApply( JCTree.JCMethodInvocation tree )
}
finally
{
_applys.pop();
if( JAILBREAK_PRIVATE_FROM_SUPERS )
{
_manLog.popSuspendIssues( tree );
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 6720775

Please sign in to comment.