Skip to content

Port classes that model UI5's JavaScript APIs to MaD as much as possible #277

Description

@jeongsoolee09

Port classes that model UI5's JavaScript APIs to MaD as much as possible. Take the characteristic predicate of ControlReference for example:

/**
 * A JS reference to a `UI5Control`, commonly obtained via its ID.
 */
class ControlReference extends Reference {
  string controlId;

  ControlReference() {
    this.getArgument(0).getALocalSource().getStringValue() = controlId and
    (
      exists(CustomController controller |
        this = controller.getAViewReference().getAMemberCall("byId") or
        this = controller.getAThisNode().getAMemberCall("byId")
      )
      or
      exists(SapUiCore sapUiCore | this = sapUiCore.getAMemberCall("byId"))
    )
  }
  ...
}

This will break the controller's view reference this.getView() (where this denotes the controller) is stored in a property of the controller (e.g. this.myView = this.getView()) in a method f and later that gets used in another method g instead of calling this.getView() again. (The #258 PR gives an excellent example of this.)

MaD can solve these cases easily. In ui5.model.yml we already have:

extensions:
  - addsTo:
      pack: codeql/javascript-all
      extensible: "typeModel"
    data:
      - ["Controller", "sap/ui/core/mvc/Controller", ""]
      - ["ViewReference", "CustomController", "Member[getView].ReturnValue"]
      - ["ControlReference", "ViewReference", "Member[byId].ReturnValue"]

Now, we'd just have to connect them in QL.

ControlReference() {
  /* ... */
  exists(API::Node controlReferenceAbstract, API::Node customControllerAbstract, CustomController customController |
    controlReferenceAbstract = ModelOutput::getATypeNode("ControlReference") and
    customControllerAbstract = ModelOutput::getATypeNode("CustomController") and
    controlReferenceAbstract = customControllerAbstract.getASuccessor+() and
    this = controlReferenceAbstract.getInducingNode() and
    customController = customControllerAbstract.getInducingNode()
  )
}

(The controlReferenceAbstract = customControllerAbstract.getASuccessor+() may not even be necessary as API::Nodes are closely tied to DataFlow::Nodes.) Anyways, the API graph library takes the MaD strings above in the typeModel, performs interprocedural tracking all the way to the hypothetical this.myView property read in a different method.

Therefore, use the above MaD + API graph method whenever such interprocedural tracking is needed, instead of using .getAMemberCall/1 which only tracks local flows.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions