Ruby: Fix bad join

Before
```
Evaluated relational algebra for predicate Filters::Filters::FilterCall.getAnAction/0#dispred#9c0da667@85a4cbtp with tuple counts:
           394650       ~2%    {2} r1 = `__#Module::ModuleBase.getAMethod/0#dispred#56626ed3Merge_Module::ModuleBase.getModule/0#dispred#4f2c__#shared` AND NOT `_Filters::Filters::FilterCall.getExceptArgument/0#dispred#515c95c0__#Method::Method.getName/0#dispre__#antijoin_rhs`(FIRST 2)
                               {2}    | AND NOT `project#Filters::Filters::FilterCall.getOnlyArgument/0#dispred#f337e70f`(FIRST 1)
           380366       ~0%    {2}    | SCAN OUTPUT In.1, In.0

            29453       ~0%    {2} r2 = JOIN `_#Module::ModuleBase.getAMethod/0#dispred#56626ed3Merge__#AST::AstNode.getEnclosingModule/0#dispred#__#shared` WITH project#ActionController::ActionControllerActionMethod#6db6f5e0 ON FIRST 1 OUTPUT Lhs.0, Lhs.1

           366017       ~0%    {2} r3 = JOIN `_#Module::ModuleBase.getAMethod/0#dispred#56626ed3Merge_Module::ModuleBase.getModule/0#dispred#4f2ca__#shared` WITH project#ActionController::ActionControllerActionMethod#6db6f5e0 ON FIRST 1 OUTPUT Lhs.0, Lhs.1

           395470       ~0%    {2} r4 = r2 UNION r3
           395470       ~0%    {3}    | JOIN WITH `Method::Method.getName/0#dispred#2acbf239` ON FIRST 1 OUTPUT Lhs.1, Rhs.1, Lhs.0
             2227       ~0%    {2}    | JOIN WITH `Filters::Filters::FilterCall.getOnlyArgument/0#dispred#f337e70f` ON FIRST 2 OUTPUT Lhs.2, Lhs.0

           382593       ~0%    {2} r5 = r1 UNION r4
           133735       ~4%    {2}    | JOIN WITH `project#ActionController::ActionControllerActionMethod.getARoute/0#dispred#9eb85e56` ON FIRST 1 OUTPUT Lhs.1, Lhs.0
        540556870       ~2%    {3}    | JOIN WITH Filters::Filters::Filter#a42c5138 CARTESIAN PRODUCT OUTPUT Rhs.0, Lhs.0, Lhs.1
        525979755     ~127%    {3}    | JOIN WITH `Filters::Filters::FilterImpl.getFilterCallable/0#dispred#451bf7d7` ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Rhs.1
                               {3}    | REWRITE WITH TEST InOut.1 != InOut.2
        525979755  ~407036%    {2}    | SCAN OUTPUT In.0, In.1
                               return r5
```

After
```
Evaluated relational algebra for predicate Filters::Filters::FilterCall.getAnAction/0#91dba45c@74dfcepp with tuple counts:
          1363   ~4%    {2} r1 = JOIN `Filters::Filters::FilterCall.getAnActionCand/1#f053150d` WITH `Filters::Filters::FilterCall.getOnlyArgument/0#dispred#f337e70f` ON FIRST 2 OUTPUT Lhs.0, Lhs.2

        140978   ~0%    {3} r2 = `Filters::Filters::FilterCall.getAnActionCand/1#f053150d` AND NOT `Filters::Filters::FilterCall.getExceptArgument/0#dispred#515c95c0#fb`(FIRST 2)
                        {3}    | AND NOT `project#Filters::Filters::FilterCall.getOnlyArgument/0#dispred#f337e70f`(FIRST 1)
        132372   ~3%    {2}    | SCAN OUTPUT In.0, In.2

        133735   ~4%    {2} r3 = r1 UNION r2
                        return r3
```
This commit is contained in:
Tom Hvitved
2026-01-06 11:42:49 +01:00
parent 19179d5005
commit 358339427b

View File

@@ -55,6 +55,7 @@ module Filters {
private class FilterCall extends MethodCallCfgNode {
private FilterKind kind;
pragma[nomagic]
FilterCall() {
this.getExpr().getEnclosingModule() = any(ActionControllerClass c).getADeclaration() and
this.getMethodName() = ["", "prepend_", "append_", "skip_"] + kind + "_action"
@@ -62,21 +63,27 @@ module Filters {
FilterKind getKind() { result = kind }
pragma[nomagic]
private ActionControllerActionMethod getAnActionCand(string name) {
result = getADescendentAction(this) and
name = result.getName() and
// A filter cannot apply to another filter
not result = any(Filter f).getFilterCallable() and
// Only include routable actions. This can exclude valid actions if we can't parse the `routes.rb` file fully.
exists(result.getARoute())
}
/**
* Gets an action which this filter is applied to.
*/
pragma[nomagic]
ActionControllerActionMethod getAnAction() {
// A filter cannot apply to another filter
result != any(Filter f).getFilterCallable() and
// Only include routable actions. This can exclude valid actions if we can't parse the `routes.rb` file fully.
exists(result.getARoute()) and
(
result.getName() = this.getOnlyArgument()
exists(string name | result = this.getAnActionCand(name) |
name = this.getOnlyArgument()
or
not exists(this.getOnlyArgument()) and
forall(string except | except = this.getExceptArgument() | result.getName() != except)
) and
result = getADescendentAction(this)
forall(string except | except = this.getExceptArgument() | name != except)
)
}
private string getOnlyArgument() {