diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java index 197ba04899..02ff19ec66 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java @@ -55,4 +55,8 @@ public class ASTReferenceExpression extends AbstractApexNode extends AbstractApexNo } } + private TypeInfo getDefiningTypeOrNull() { + try { + return node.getDefiningType(); + } catch (UnsupportedOperationException e) { + return null; + } + } + @Override public String getDefiningType() { - if (node.getDefiningType() != null) { - return node.getDefiningType().getApexName(); + TypeInfo definingType = getDefiningTypeOrNull(); + if (definingType != null) { + return definingType.getApexName(); } return null; } @Override public String getNamespace() { - if (node.getDefiningType() != null) { - return node.getDefiningType().getNamespace().toString(); + TypeInfo definingType = getDefiningTypeOrNull(); + if (definingType != null) { + return definingType.getNamespace().toString(); } return null; } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java new file mode 100644 index 0000000000..dc7c66b6f1 --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java @@ -0,0 +1,29 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + + +package net.sourceforge.pmd.lang.apex.ast; + +import org.junit.Test; + +import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper; +import net.sourceforge.pmd.lang.ast.test.BaseTreeDumpTest; +import net.sourceforge.pmd.lang.ast.test.RelevantAttributePrinter; + +public class ApexTreeDumpTest extends BaseTreeDumpTest { + + public ApexTreeDumpTest() { + super(new RelevantAttributePrinter(), ".cls"); + } + + @Override + public BaseParsingHelper getParser() { + return ApexParsingHelper.DEFAULT; + } + + @Test + public void safeNavigationOperator() throws Exception { + doTest("SafeNavigationOperator"); + } +} diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/SafeNavigationOperator.cls b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/SafeNavigationOperator.cls new file mode 100644 index 0000000000..6dedbd277b --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/SafeNavigationOperator.cls @@ -0,0 +1,25 @@ +// See https://github.com/pmd/pmd/issues/2839 +// and https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_SafeNavigationOperator.htm + +public class Foo { + Integer x = anObject?.anIntegerField; // The expression is of type Integer because the field is of type Integer + + // New code using the safe navigation operator + String profileUrl = user.getProfileUrl()?.toExternalForm(); + + public void bar1(Object a) { + a?.b; // Evaluates to: a == null ? null : a.b + ((T)a1?.b1)?.c1(); + } + + public void bar2(Object[] a, int x) { + a[x]?.aMethod().aField; // Evaluates to null if a[x] == null + a[x].aMethod()?.aField; + } + + public String getName(int accId) { + String s = contact.Account?.BillingCity; + // New code using the safe navigation operator + return [SELECT Name FROM Account WHERE Id = :accId]?.Name; + } +} \ No newline at end of file diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/SafeNavigationOperator.txt b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/SafeNavigationOperator.txt new file mode 100644 index 0000000000..43aa08511b --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/SafeNavigationOperator.txt @@ -0,0 +1,98 @@ ++- UserClass[@ApexVersion = 51.0, @DefiningType = "Foo", @Image = "Foo", @InterfaceNames = null, @Location = "(4, 14, 180, 183)", @Namespace = "", @RealLoc = true, @SuperClassName = "", @TypeKind = TypeKind.CLASS] + +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(4, 14, 180, 183)", @Modifiers = 1, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = true, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + +- Field[@DefiningType = "Foo", @Image = "x", @Location = "(5, 13, 198, 199)", @Name = "x", @Namespace = "", @RealLoc = true, @Type = "Integer", @Value = null] + | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(5, 13, 198, 199)", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + +- Field[@DefiningType = "Foo", @Image = "profileUrl", @Location = "(8, 12, 365, 375)", @Name = "profileUrl", @Namespace = "", @RealLoc = true, @Type = "String", @Value = null] + | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(8, 12, 365, 375)", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + +- FieldDeclarationStatements[@DefiningType = "Foo", @Location = "(5, 5, 190, 199)", @Namespace = "", @RealLoc = true, @TypeArguments = null, @TypeName = "Integer"] + | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "no location", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- FieldDeclaration[@DefiningType = "Foo", @Image = "anIntegerField", @Location = "(5, 13, 198, 199)", @Name = "anIntegerField", @Namespace = "", @RealLoc = true] + | +- VariableExpression[@DefiningType = "Foo", @Image = "anIntegerField", @Location = "(5, 27, 212, 226)", @Namespace = "", @RealLoc = true] + | | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SafeNav = true] + | | +- VariableExpression[@DefiningType = "Foo", @Image = "anObject", @Location = "(5, 17, 202, 210)", @Namespace = "", @RealLoc = true] + | | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + | +- VariableExpression[@DefiningType = "Foo", @Image = "x", @Location = "(5, 13, 198, 199)", @Namespace = "", @RealLoc = true] + | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + +- FieldDeclarationStatements[@DefiningType = "Foo", @Location = "(8, 5, 358, 375)", @Namespace = "", @RealLoc = true, @TypeArguments = null, @TypeName = "String"] + | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "no location", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- FieldDeclaration[@DefiningType = "Foo", @Image = "profileUrl", @Location = "(8, 12, 365, 375)", @Name = "profileUrl", @Namespace = "", @RealLoc = true] + | +- MethodCallExpression[@DefiningType = "Foo", @FullMethodName = "toExternalForm", @InputParametersSize = 0, @Location = "(8, 47, 400, 414)", @MethodName = "toExternalForm", @Namespace = "", @RealLoc = true] + | | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.METHOD, @SafeNav = true] + | | +- MethodCallExpression[@DefiningType = "Foo", @FullMethodName = "user.getProfileUrl", @InputParametersSize = 0, @Location = "(8, 30, 383, 396)", @MethodName = "getProfileUrl", @Namespace = "", @RealLoc = true] + | | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Image = "user", @Location = "(8, 25, 378, 382)", @Names = null, @Namespace = "", @RealLoc = true, @ReferenceType = ReferenceType.METHOD, @SafeNav = false] + | +- VariableExpression[@DefiningType = "Foo", @Image = "profileUrl", @Location = "(8, 12, 365, 375)", @Namespace = "", @RealLoc = true] + | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + +- Method[@Arity = 1, @CanonicalName = "bar1", @Constructor = false, @DefiningType = "Foo", @Image = "bar1", @Location = "(10, 17, 435, 439)", @Namespace = "", @RealLoc = true, @ReturnType = "void"] + | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(10, 17, 435, 439)", @Modifiers = 1, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = true, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- Parameter[@DefiningType = "Foo", @Image = "a", @Location = "(10, 29, 447, 448)", @Namespace = "", @RealLoc = true, @Type = "Object"] + | | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(10, 29, 447, 448)", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- BlockStatement[@CurlyBrace = true, @DefiningType = "Foo", @Location = "(10, 32, 450, 538)", @Namespace = "", @RealLoc = true] + | +- ExpressionStatement[@DefiningType = "Foo", @Location = "(11, 12, 463, 465)", @Namespace = "", @RealLoc = true] + | | +- VariableExpression[@DefiningType = "Foo", @Image = "b", @Location = "(11, 12, 463, 464)", @Namespace = "", @RealLoc = true] + | | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SafeNav = true] + | | +- VariableExpression[@DefiningType = "Foo", @Image = "a", @Location = "(11, 9, 460, 461)", @Namespace = "", @RealLoc = true] + | | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + | +- ExpressionStatement[@DefiningType = "Foo", @Location = "(12, 22, 527, 532)", @Namespace = "", @RealLoc = true] + | +- MethodCallExpression[@DefiningType = "Foo", @FullMethodName = "c1", @InputParametersSize = 0, @Location = "(12, 22, 527, 529)", @MethodName = "c1", @Namespace = "", @RealLoc = true] + | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.METHOD, @SafeNav = true] + | +- CastExpression[@DefiningType = "Foo", @Location = "(12, 10, 515, 518)", @Namespace = "", @RealLoc = true] + | +- VariableExpression[@DefiningType = "Foo", @Image = "b1", @Location = "(12, 17, 522, 524)", @Namespace = "", @RealLoc = true] + | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SafeNav = true] + | +- VariableExpression[@DefiningType = "Foo", @Image = "a1", @Location = "(12, 13, 518, 520)", @Namespace = "", @RealLoc = true] + | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + +- Method[@Arity = 2, @CanonicalName = "bar2", @Constructor = false, @DefiningType = "Foo", @Image = "bar2", @Location = "(15, 17, 556, 560)", @Namespace = "", @RealLoc = true, @ReturnType = "void"] + | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(15, 17, 556, 560)", @Modifiers = 1, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = true, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- Parameter[@DefiningType = "Foo", @Image = "a", @Location = "(15, 31, 570, 571)", @Namespace = "", @RealLoc = true, @Type = "List"] + | | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(15, 31, 570, 571)", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- Parameter[@DefiningType = "Foo", @Image = "x", @Location = "(15, 38, 577, 578)", @Namespace = "", @RealLoc = true, @Type = "int"] + | | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(15, 38, 577, 578)", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- BlockStatement[@CurlyBrace = true, @DefiningType = "Foo", @Location = "(15, 41, 580, 688)", @Namespace = "", @RealLoc = true] + | +- ExpressionStatement[@DefiningType = "Foo", @Location = "(16, 25, 606, 613)", @Namespace = "", @RealLoc = true] + | | +- VariableExpression[@DefiningType = "Foo", @Image = "aField", @Location = "(16, 25, 606, 612)", @Namespace = "", @RealLoc = true] + | | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SafeNav = false] + | | +- MethodCallExpression[@DefiningType = "Foo", @FullMethodName = "aMethod", @InputParametersSize = 0, @Location = "(16, 15, 596, 603)", @MethodName = "aMethod", @Namespace = "", @RealLoc = true] + | | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.METHOD, @SafeNav = true] + | | +- ArrayLoadExpression[@DefiningType = "Foo", @Location = "(16, 9, 590, 591)", @Namespace = "", @RealLoc = true] + | | +- VariableExpression[@DefiningType = "Foo", @Image = "a", @Location = "(16, 9, 590, 591)", @Namespace = "", @RealLoc = true] + | | | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + | | +- VariableExpression[@DefiningType = "Foo", @Image = "x", @Location = "(16, 11, 592, 593)", @Namespace = "", @RealLoc = true] + | | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + | +- ExpressionStatement[@DefiningType = "Foo", @Location = "(17, 25, 675, 682)", @Namespace = "", @RealLoc = true] + | +- VariableExpression[@DefiningType = "Foo", @Image = "aField", @Location = "(17, 25, 675, 681)", @Namespace = "", @RealLoc = true] + | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SafeNav = true] + | +- MethodCallExpression[@DefiningType = "Foo", @FullMethodName = "aMethod", @InputParametersSize = 0, @Location = "(17, 14, 664, 671)", @MethodName = "aMethod", @Namespace = "", @RealLoc = true] + | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.METHOD, @SafeNav = false] + | +- ArrayLoadExpression[@DefiningType = "Foo", @Location = "(17, 9, 659, 660)", @Namespace = "", @RealLoc = true] + | +- VariableExpression[@DefiningType = "Foo", @Image = "a", @Location = "(17, 9, 659, 660)", @Namespace = "", @RealLoc = true] + | | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + | +- VariableExpression[@DefiningType = "Foo", @Image = "x", @Location = "(17, 11, 661, 662)", @Namespace = "", @RealLoc = true] + | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + +- Method[@Arity = 1, @CanonicalName = "getName", @Constructor = false, @DefiningType = "Foo", @Image = "getName", @Location = "(20, 19, 708, 715)", @Namespace = "", @RealLoc = true, @ReturnType = "String"] + | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(20, 19, 708, 715)", @Modifiers = 1, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = true, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- Parameter[@DefiningType = "Foo", @Image = "accId", @Location = "(20, 31, 720, 725)", @Namespace = "", @RealLoc = true, @Type = "int"] + | | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(20, 31, 720, 725)", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- BlockStatement[@CurlyBrace = true, @DefiningType = "Foo", @Location = "(20, 38, 727, 905)", @Namespace = "", @RealLoc = true] + | +- VariableDeclarationStatements[@DefiningType = "Foo", @Location = "(21, 9, 737, 745)", @Namespace = "", @RealLoc = true] + | | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "no location", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | | +- VariableDeclaration[@DefiningType = "Foo", @Image = "s", @Location = "(21, 16, 744, 745)", @Namespace = "", @RealLoc = true, @Type = "String"] + | | +- VariableExpression[@DefiningType = "Foo", @Image = "BillingCity", @Location = "(21, 37, 765, 776)", @Namespace = "", @RealLoc = true] + | | | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SafeNav = true] + | | | +- VariableExpression[@DefiningType = "Foo", @Image = "Account", @Location = "(21, 28, 756, 763)", @Namespace = "", @RealLoc = true] + | | | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Image = "contact", @Location = "(21, 20, 748, 755)", @Names = null, @Namespace = "", @RealLoc = true, @ReferenceType = ReferenceType.LOAD, @SafeNav = false] + | | +- VariableExpression[@DefiningType = "Foo", @Image = "s", @Location = "(21, 16, 744, 745)", @Namespace = "", @RealLoc = true] + | | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + | +- ReturnStatement[@DefiningType = "Foo", @Location = "(23, 9, 841, 899)", @Namespace = "", @RealLoc = true] + | +- VariableExpression[@DefiningType = "Foo", @Image = "Name", @Location = "(23, 62, 894, 898)", @Namespace = "", @RealLoc = true] + | +- ReferenceExpression[@Context = null, @DefiningType = "Foo", @Location = "no location", @Names = null, @Namespace = "", @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SafeNav = true] + | +- SoqlExpression[@CanonicalQuery = "SELECT Name FROM Account WHERE Id = :tmpVar1", @DefiningType = "Foo", @Location = "(23, 16, 848, 892)", @Namespace = "", @Query = "SELECT Name FROM Account WHERE Id = :accId", @RealLoc = true] + | +- BindExpressions[@DefiningType = "Foo", @Location = "(23, 16, 848, 892)", @Namespace = "", @RealLoc = true] + | +- VariableExpression[@DefiningType = "Foo", @Image = "accId", @Location = "(23, 54, 886, 891)", @Namespace = "", @RealLoc = true] + | +- EmptyReferenceExpression[@DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = false] + +- Method[@Arity = 0, @CanonicalName = "", @Constructor = false, @DefiningType = "Foo", @Image = "", @Location = "no location", @Namespace = "", @RealLoc = false, @ReturnType = "void"] + | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = false, @InheritedSharing = false, @Location = "(4, 14, 180, 183)", @Modifiers = 8, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = true, @Static = true, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + +- Method[@Arity = 0, @CanonicalName = "clone", @Constructor = false, @DefiningType = "Foo", @Image = "clone", @Location = "no location", @Namespace = "", @RealLoc = false, @ReturnType = "Object"] + | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = true, @InheritedSharing = false, @Location = "no location", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + +- UserClassMethods[@DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = false] + | +- Method[@Arity = 0, @CanonicalName = "", @Constructor = true, @DefiningType = "Foo", @Image = "", @Location = "no location", @Namespace = "", @RealLoc = false, @ReturnType = "void"] + | +- ModifierNode[@Abstract = false, @DefiningType = "Foo", @Final = false, @Global = true, @InheritedSharing = false, @Location = "(4, 14, 180, 183)", @Modifiers = 0, @Namespace = "", @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = true, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + +- BridgeMethodCreator[@DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = false]