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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions