Skip to content

Conversation

RasmusWL
Copy link
Member

Instead of just adding the test example, I thought I would try to fix it. I'm totally up for discussing whether this is the right approach, but personally I think it aligns with our goals.

We don't currently allow decorators for functions, so there will be a little bit of inconsistency...

Copy link
Contributor

@yoff yoff left a comment

Choose a reason for hiding this comment

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

I agree with the heuristic in this PR; I would expect decorators to preserve the sub-class relationship often enough to make this over-approximation useful. Are the evaluation results as you expect?

The suggestion is mostly me being curious, the code might well be better as is.

Co-authored-by: yoff <lerchedahl@gmail.com>
@RasmusWL
Copy link
Member Author

Accepting this change also fixed the tests 👍 😮

The problem was this bit of modeling code (in Flask.qll)

  class FlaskMethodViewClass extends FlaskViewClass {
    FlaskMethodViewClass() {
      api_node = Views::MethodView::subclassRef() and
      this.getParent() = api_node.getAnImmediateUse().asExpr()
    }

would no longer recognize the Nested class itself as being a MethodView subclass 😞 (since the ClassExpr was not treated as a subclass)

    @flask_admin.expose_plugview("/flask-class") # $ routeSetup="/flask-class"
    @flask_admin.expose_plugview(url="/flask-class/<arg>") # $ routeSetup="/flask-class/<arg>"
    class Nested(MethodView):
        def get(self, cls, arg="default"): # $ requestHandler routedParameter=arg
            assert isinstance(cls, ExampleClass)
            ensure_tainted(arg) # $ tainted
            ensure_not_tainted(cls)
            return "GET: " + arg # $ HttpResponse

@RasmusWL
Copy link
Member Author

Results from initial DCA run did not look good at all. I'll do a new one now after having accepted your fix, and hopefully that should do better 🤞

@tausbn
Copy link
Contributor

tausbn commented Jun 17, 2022

I wonder if it would be even more correct to say that (for the purposes of the API graph), the results of applying the decorators are not just subclasses of the same superclass, but in fact the very same class. In some sense, decorating a class should not really change the identity of that class (though it may e.g. wrap it in some other object).

This might also be needed in order to get tracking of instances through decorators to work correctly. Consider

@foo
class Bar:
    ...
    def baz(self):
        ...

Bar().baz()

we want the call above to resolve Bar.foo, but if we just follow the flow, we'll find that Bar comes from a desugared assignment Bar = foo(Bar), which doesn't obviously have a baz method (at least, not syntactically). If we let classes "flow through" decorators, then there will be flow from the inner Bar to the call-site.

Copy link
Contributor

@yoff yoff left a comment

Choose a reason for hiding this comment

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

LGTM

@yoff yoff merged commit 20febb6 into github:main Aug 8, 2022
@RasmusWL RasmusWL deleted the typetracker-decorators branch August 8, 2022 10:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants