Skip to content

Ruby: assume some global constants are defined#10928

Merged
asgerf merged 6 commits intogithub:mainfrom
asgerf:rb/assumed-global-const
Oct 24, 2022
Merged

Ruby: assume some global constants are defined#10928
asgerf merged 6 commits intogithub:mainfrom
asgerf:rb/assumed-global-const

Conversation

@asgerf
Copy link
Contributor

@asgerf asgerf commented Oct 21, 2022

When classes are missing a canonical name, we end up not resolving its outgoing subclass edges. For example, we missed that Unkn::B is a subclass of Unkn::A in this example:

class Unkn::A
end

class Unkn::B < Unkn::A
end

Here is an example of a class that was affected by this issue.

This PR doesn't try to fix the problem in general, but rather aims to pick some low-hanging fruit, enough to unblock my work on migrating some models from AST to DataFlow.

We simply treat a constant C as being defined at the top-level if we've seen C referenced in a context where it can only refer to a top-level constant.

Interestingly, the API graph does contain a subclassing edge in the above example, as this isn't dependent on the classes having canonical names. API graphs of course has the luxury of not being in the same SCC as constant resolution itself, but it would be nice if we could make the two systems agree on the superclass/ancestor relationship. But that's for another PR.

I noticed some call graph changes due to the String class now being considered resolved, and this affects flow through pattern-matching in a few cases. I decided to add String to builtins() to ensure this is consistently the case, though I'm not sure if it's technically a built-in or just a class in the standard library (does it matter?).

Evaluation looks good

  • About 5000 new call edges, due to more subclassing relationships. Everything I've looked at appear to be true edges.
  • Fixes 3 spurious call edges, due to pattern-matching now properly blocking flow.
  • The lost taint sink in opal seems to be due to the call to const_get now resolved to a definition so no longer an UnknownMethodCall.

@github-actions github-actions bot added the Ruby label Oct 21, 2022
not mid instanceof ModuleBase and
not mid instanceof Block
)
private ModuleBase enclosingModuleNoBlock(Stmt node) {

Check warning

Code scanning / CodeQL

Missing QLDoc for parameter

The QLDoc has no documentation for node, but the QLDoc mentions module_eval
@asgerf asgerf marked this pull request as ready for review October 21, 2022 17:58
@asgerf asgerf requested a review from a team as a code owner October 21, 2022 17:58
@asgerf asgerf added the no-change-note-required This PR does not need a change note label Oct 21, 2022
@calumgrant calumgrant requested a review from aibaars October 24, 2022 08:26
*
* Includes `scope` itself and the final module/block.
*/
private Scope enclosingScopesNoBlock(Scope scope) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it important to stop at block scopes? I'm not sure this change is right. For example:

A = "top"
module M
  A = "M"
end

M.module_eval { puts A }

prints "top"

Copy link
Contributor Author

@asgerf asgerf Oct 24, 2022

Choose a reason for hiding this comment

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

You're right. I'm not sure what I was thinking there. The block thing is specific to include calls and such since they rely on self.

Technically there was a bug in old implementation of enclosingModule since it relies on getParent(), although it would only affect really obscure cases like,

module (include A)::B
end

where the include call would be seen as being part of the B module, not the top-level. Still, it's a footgun that might reappear later so I think it's best to keep the new formulation.

I've pushed a commit to fix the place where we incorrectly relied on this predicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-change-note-required This PR does not need a change note Ruby

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants