Skip to content

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

@jeongsoolee09

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.

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