Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ruby: More splat flow (alternative) #14090

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft

Conversation

hmac
Copy link
Contributor

@hmac hmac commented Aug 29, 2023

No description provided.

Allow flow from a splat argument to a positional parameter in cases
where there are positional arguments left of the splat. For example:

    def foo(x, y, z); end

    foo(1, *[2, 3])
Copy link
Contributor

@hvitved hvitved left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This aligns with how I envisioned it in my comment #13974 (review). A few comments.

exists(c.asCallable()) and // exclude library callables
isParameterNode(_, c, any(ParameterPosition p | p.isSplat(_)))
exists(c.asCallable()) // exclude library callables
// and isParameterNode(_, c, any(ParameterPosition p | p.isSplat(_)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

// since that won't (probably) won't reach the parameters of the callable.
// This saves a node per call.
n >= 0 and
node1.asExpr().(Argument).isArgumentOf(call, any(ArgumentPosition p | p.isSplat(splatPos))) and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be limited to splatPos > 0?

exists(int n, int splatPos, CfgNodes::ExprNodes::CallCfgNode call |
// Don't propagate taint on the `self` element of the splat
// since that won't (probably) won't reach the parameters of the callable.
// This saves a node per call.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a misunderstanding on my part that content at index -1 represented the value of the container itself. That's why I added the n >= 0 constraint. I've now realised this isn't true and that positional content is only defined for n in [0..10] so I'll remove the constraint and this comment.

// Don't propagate taint on the `self` element of the splat
// since that won't (probably) won't reach the parameters of the callable.
// This saves a node per call.
n >= 0 and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can n ever be < 0?

node2.getPosition() = n + splatPos and
(
c = getPositionalContent(n) or
c.isSingleton(TUnknownElementContent())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

n is not bound in this case; in this case it should store into a version of SynthSplatArgumentElementNode that represents unknown content (you could abuse TSynthSplatArgumentElementNode(-1) to represent unknown).

}

class TSourceParameterNode =
TNormalParameterNode or TBlockParameterNode or TSelfParameterNode or
TSynthHashSplatParameterNode or TSynthSplatParameterNode or TSynthSplatArgParameterNode;
TSynthHashSplatParameterNode or TSynthSplatParameterNode or TSynthSplatArgParameterNode or
TSynthSplatArgumentElementNode;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

TSynthSplatArgumentNode(CfgNodes::ExprNodes::CallCfgNode c) or
TSynthSplatArgumentElementNode(CfgNodes::ExprNodes::CallCfgNode c, int n) {
n in [0 .. 10] and
exists(Argument arg, ArgumentPosition pos | pos.isSplat(_) and arg.isArgumentOf(c, pos))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be limited to pos.isSplat(any(int splatPos | splatPos > 0))?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do that, then I think it breaks cases like

def f(x, y); end
f(*[taint, 2])

because we no longer match the explicit splat arg to the synth splat parameter. If we re-add ppos.isSynthSplat() and apos.isSplat(0) to parameterMatch, then we still have a failure in cases like

def g(x, *y); end

g(*[1, taint])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants