From 19907a74d92ba5c8382908a02e8fd5b91702baaa Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 10 Feb 2024 20:54:53 +0100 Subject: [PATCH] [apex] Finish ASTReferenceExpression - removed method getContext() - always returned null Fixes TODO(b/243906211) - Verify that getReferenceType() returns the correct values Fixes TODO(b/239648780) --- docs/pages/release_notes.md | 2 + .../lang/apex/ast/ASTReferenceExpression.java | 10 +--- .../pmd/lang/apex/ast/ApexTreeBuilder.kt | 2 +- .../apex/ast/ASTReferenceExpressionTest.java | 49 +++++++++++++++++++ .../lang/apex/ast/SafeNavigationOperator.txt | 26 +++++----- 5 files changed, 66 insertions(+), 23 deletions(-) create mode 100644 pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpressionTest.java diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index b80dbce011..de480debb6 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -256,6 +256,8 @@ The following previously deprecated classes have been removed: * The constant `STATIC_INITIALIZER_METHOD_NAME` in {%jdoc apex::lang.apex.rule.codestyle.FieldDeclarationsShouldBeAtStartRule %} has been removed. It was used to filter out synthetic methods, but these are not generated anymore with the new parser. + * The method `getContext()` in {%jdoc apex::lang.apex.ast.ASTReferenceExpression %} has been removed. + It was not used and always returned `null`. * pmd-java * The interface `FinalizableNode` (introduced in 7.0.0-rc1) has been removed. Its method `isFinal()` has been moved down to the 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 1e4c2f7edd..dbf9e887ec 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 @@ -26,15 +26,7 @@ public final class ASTReferenceExpression extends AbstractApexNode.Many { val (receiver, components, isSafe) = flattenExpression(node.receiver) ASTMethodCallExpression(node, components).apply { - buildReferenceExpression(components, receiver, ReferenceType.METHOD, isSafe).also { + buildReferenceExpression(components, receiver, ReferenceType.METHOD, isSafe || node.isSafe).also { it.setParent(this) } buildChildren(node, parent = this, exclude = { it == node.receiver }) diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpressionTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpressionTest.java new file mode 100644 index 0000000000..64c766de41 --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpressionTest.java @@ -0,0 +1,49 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class ASTReferenceExpressionTest extends ApexParserTestBase { + @Test + void referenceTypeMethodWithSafeNav() { + ASTReferenceExpression reference = parse("class Foo { static void bar() { Foo?.staticMethod(); } }") + .descendants(ASTReferenceExpression.class) + .first(); + assertEquals(ReferenceType.METHOD, reference.getReferenceType()); + assertTrue(reference.isSafeNav()); + } + + @Test + void referenceTypeMethodWithoutSafeNav() { + ASTReferenceExpression reference = parse("class Foo { static void bar() { Foo.staticMethod(); } }") + .descendants(ASTReferenceExpression.class) + .first(); + assertEquals(ReferenceType.METHOD, reference.getReferenceType()); + assertFalse(reference.isSafeNav()); + } + + @Test + void referenceTypeLoad() { + ASTReferenceExpression reference = parse("class Foo { static void bar() { Foo x = Foo?.INSTANCE; } }") + .descendants(ASTReferenceExpression.class) + .first(); + assertEquals(ReferenceType.LOAD, reference.getReferenceType()); + assertTrue(reference.isSafeNav()); + } + + @Test + void referenceTypeStore() { + ASTReferenceExpression reference = parse("class Foo { static void bar() { Foo.INSTANCE = x; } }") + .descendants(ASTReferenceExpression.class) + .first(); + assertEquals(ReferenceType.STORE, reference.getReferenceType()); + assertFalse(reference.isSafeNav()); + } +} 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 index 3b98ec9ffe..7a511f5556 100644 --- 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 @@ -9,7 +9,7 @@ | +- ModifierNode[@Abstract = false, @DefiningType = "c__Foo", @DeprecatedTestMethod = false, @Final = false, @Global = false, @InheritedSharing = false, @Modifiers = 0, @Namespace = null, @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @Virtual = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] | +- FieldDeclaration[@DefiningType = "c__Foo", @Image = "x", @Name = "x", @Namespace = null, @RealLoc = true] | +- VariableExpression[@DefiningType = "c__Foo", @Image = "anIntegerField", @Namespace = null, @RealLoc = true] - | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = true] + | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SObjectType = false, @SafeNav = true] | | +- VariableExpression[@DefiningType = "c__Foo", @Image = "anObject", @Namespace = null, @RealLoc = true] | | +- EmptyReferenceExpression[@DefiningType = null, @Namespace = null, @RealLoc = false] | +- VariableExpression[@DefiningType = "c__Foo", @Image = "x", @Namespace = null, @RealLoc = true] @@ -18,9 +18,9 @@ | +- ModifierNode[@Abstract = false, @DefiningType = "c__Foo", @DeprecatedTestMethod = false, @Final = false, @Global = false, @InheritedSharing = false, @Modifiers = 0, @Namespace = null, @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @Virtual = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] | +- FieldDeclaration[@DefiningType = "c__Foo", @Image = "profileUrl", @Name = "profileUrl", @Namespace = null, @RealLoc = true] | +- MethodCallExpression[@DefiningType = "c__Foo", @FullMethodName = "toExternalForm", @InputParametersSize = 0, @MethodName = "toExternalForm", @Namespace = null, @RealLoc = true] - | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = false] + | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.METHOD, @SObjectType = false, @SafeNav = true] | | +- MethodCallExpression[@DefiningType = "c__Foo", @FullMethodName = "user.getProfileUrl", @InputParametersSize = 0, @MethodName = "getProfileUrl", @Namespace = null, @RealLoc = true] - | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "user", @Namespace = null, @RealLoc = true, @SObjectType = false, @SafeNav = false] + | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "user", @Namespace = null, @RealLoc = true, @ReferenceType = ReferenceType.METHOD, @SObjectType = false, @SafeNav = false] | +- VariableExpression[@DefiningType = "c__Foo", @Image = "profileUrl", @Namespace = null, @RealLoc = true] | +- EmptyReferenceExpression[@DefiningType = null, @Namespace = null, @RealLoc = false] +- Method[@Arity = 1, @CanonicalName = "bar1", @Constructor = false, @DefiningType = "c__Foo", @Image = "bar1", @Namespace = null, @RealLoc = true, @ReturnType = "void", @StaticInitializer = false] @@ -30,15 +30,15 @@ | +- BlockStatement[@CurlyBrace = true, @DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] | +- ExpressionStatement[@DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] | | +- VariableExpression[@DefiningType = "c__Foo", @Image = "b", @Namespace = null, @RealLoc = true] - | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = true] + | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SObjectType = false, @SafeNav = true] | | +- VariableExpression[@DefiningType = "c__Foo", @Image = "a", @Namespace = null, @RealLoc = true] | | +- EmptyReferenceExpression[@DefiningType = null, @Namespace = null, @RealLoc = false] | +- ExpressionStatement[@DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] | +- MethodCallExpression[@DefiningType = "c__Foo", @FullMethodName = "c1", @InputParametersSize = 0, @MethodName = "c1", @Namespace = null, @RealLoc = true] - | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = false] + | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.METHOD, @SObjectType = false, @SafeNav = true] | +- CastExpression[@DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] | +- VariableExpression[@DefiningType = "c__Foo", @Image = "b1", @Namespace = null, @RealLoc = true] - | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = true] + | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SObjectType = false, @SafeNav = true] | +- VariableExpression[@DefiningType = "c__Foo", @Image = "a1", @Namespace = null, @RealLoc = true] | +- EmptyReferenceExpression[@DefiningType = null, @Namespace = null, @RealLoc = false] +- Method[@Arity = 2, @CanonicalName = "bar2", @Constructor = false, @DefiningType = "c__Foo", @Image = "bar2", @Namespace = null, @RealLoc = true, @ReturnType = "void", @StaticInitializer = false] @@ -50,9 +50,9 @@ | +- BlockStatement[@CurlyBrace = true, @DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] | +- ExpressionStatement[@DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] | | +- VariableExpression[@DefiningType = "c__Foo", @Image = "aField", @Namespace = null, @RealLoc = true] - | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = false] + | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SObjectType = false, @SafeNav = false] | | +- MethodCallExpression[@DefiningType = "c__Foo", @FullMethodName = "aMethod", @InputParametersSize = 0, @MethodName = "aMethod", @Namespace = null, @RealLoc = true] - | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = false] + | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.METHOD, @SObjectType = false, @SafeNav = true] | | +- ArrayLoadExpression[@DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] | | +- VariableExpression[@DefiningType = "c__Foo", @Image = "a", @Namespace = null, @RealLoc = true] | | | +- EmptyReferenceExpression[@DefiningType = null, @Namespace = null, @RealLoc = false] @@ -60,9 +60,9 @@ | | +- EmptyReferenceExpression[@DefiningType = null, @Namespace = null, @RealLoc = false] | +- ExpressionStatement[@DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] | +- VariableExpression[@DefiningType = "c__Foo", @Image = "aField", @Namespace = null, @RealLoc = true] - | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = true] + | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SObjectType = false, @SafeNav = true] | +- MethodCallExpression[@DefiningType = "c__Foo", @FullMethodName = "aMethod", @InputParametersSize = 0, @MethodName = "aMethod", @Namespace = null, @RealLoc = true] - | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = false] + | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.METHOD, @SObjectType = false, @SafeNav = false] | +- ArrayLoadExpression[@DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] | +- VariableExpression[@DefiningType = "c__Foo", @Image = "a", @Namespace = null, @RealLoc = true] | | +- EmptyReferenceExpression[@DefiningType = null, @Namespace = null, @RealLoc = false] @@ -77,14 +77,14 @@ | +- ModifierNode[@Abstract = false, @DefiningType = "c__Foo", @DeprecatedTestMethod = false, @Final = false, @Global = false, @InheritedSharing = false, @Modifiers = 0, @Namespace = null, @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @Virtual = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] | +- VariableDeclaration[@DefiningType = "c__Foo", @Image = "s", @Namespace = null, @RealLoc = true, @Type = "String"] | +- VariableExpression[@DefiningType = "c__Foo", @Image = "BillingCity", @Namespace = null, @RealLoc = true] - | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = true] + | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SObjectType = false, @SafeNav = true] | | +- VariableExpression[@DefiningType = "c__Foo", @Image = "Account", @Namespace = null, @RealLoc = true] - | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "contact", @Namespace = null, @RealLoc = true, @SObjectType = false, @SafeNav = false] + | | +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "contact", @Namespace = null, @RealLoc = true, @ReferenceType = ReferenceType.LOAD, @SObjectType = false, @SafeNav = false] | +- VariableExpression[@DefiningType = "c__Foo", @Image = "s", @Namespace = null, @RealLoc = true] | +- EmptyReferenceExpression[@DefiningType = null, @Namespace = null, @RealLoc = false] +- ReturnStatement[@DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] +- VariableExpression[@DefiningType = "c__Foo", @Image = "Name", @Namespace = null, @RealLoc = true] - +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @SObjectType = false, @SafeNav = true] + +- ReferenceExpression[@DefiningType = "c__Foo", @Image = "", @Namespace = null, @RealLoc = false, @ReferenceType = ReferenceType.LOAD, @SObjectType = false, @SafeNav = true] +- SoqlExpression[@CanonicalQuery = "SELECT Name FROM Account WHERE Id = :accId", @DefiningType = "c__Foo", @Namespace = null, @Query = "SELECT Name FROM Account WHERE Id = :accId", @RealLoc = true] +- BindExpressions[@DefiningType = "c__Foo", @Namespace = null, @RealLoc = true] +- VariableExpression[@DefiningType = "c__Foo", @Image = "accId", @Namespace = null, @RealLoc = true]