Skip to content

Address FN involving CAP remote flow sources #222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,27 @@ class ServiceInstanceFromConstructor extends ServiceInstance {
}

/**
* A read to `this` variable which represents the service whose definition encloses this variable access.
* A read to `this` variable which represents the service whose definition encloses
* this variable access.
* e.g.1. Given this code:
* ``` javascript
* const cds = require("@sap/cds");
* module.exports = class SomeService extends cds.ApplicationService {
* init() {
* this.on("SomeEvent", (req) => { ... } )
* }
* }
* ```
* This class captures the access to the `this` variable as in `this.on(...)`.
*
* e.g.2. Given this code:
* ``` javascript
* const cds = require('@sap/cds');
* module.exports = cds.service.impl (function() {
* this.on("SomeEvent", (req) => { ... })
* })
* ```
* This class captures the access to the `this` variable as in `this.on(...)`.
*/
class ServiceInstanceFromThisNode extends ServiceInstance, ThisNode {
UserDefinedApplicationService userDefinedApplicationService;
Expand Down Expand Up @@ -294,12 +314,56 @@ class DbServiceInstanceFromCdsConnectTo extends ServiceInstanceFromCdsConnectTo,
override UserDefinedApplicationService getDefinition() { none() }
}

/**
* The 0-th parameter of an exported closure that represents the service being implemented. e.g.
* ``` javascript
* const cds = require('@sap/cds')
* module.exports = (srv) => {
* srv.on("SomeEvent1", (req) => { ... })
* }
* ```
* This class captures the `srv` parameter of the exported arrow function. Also see
* `ServiceInstanceFromImplMethodCallClosureParameter` which is similar to this.
*/
class ServiceInstanceFromExportedClosureParameter extends ServiceInstance {
ExportedClosureApplicationServiceDefinition exportedClosure;

ServiceInstanceFromExportedClosureParameter() { this = exportedClosure.getParameter(0) }

override UserDefinedApplicationService getDefinition() { result = exportedClosure }
}

/**
* The 0-th parameter of a callback (usually an arrow function) passed to `cds.service.impl` that
* represents the service being implemented. e.g.
* ``` javascript
* const cds = require('@sap/cds')
* module.exports = cds.service.impl((srv) => {
* srv.on("SomeEvent1", (req) => { ... })
* })
* ```
* This class captures the `srv` parameter of the exported arrow function. Also see
* `ServiceInstanceFromExportedClosureParameter` which is similar to this.
*/
class ServiceInstanceFromImplMethodCallClosureParameter extends ServiceInstance, ParameterNode {
ImplMethodCallApplicationServiceDefinition implMethodCallApplicationServiceDefinition;

ServiceInstanceFromImplMethodCallClosureParameter() {
this = implMethodCallApplicationServiceDefinition.getInitFunction().getParameter(0)
}

override UserDefinedApplicationService getDefinition() {
result = implMethodCallApplicationServiceDefinition
}
}

/**
* A call to `before`, `on`, or `after` on an `cds.ApplicationService`.
* It registers an handler to be executed when an event is fired,
* to do something with the incoming request or event as its parameter.
*/
class HandlerRegistration extends MethodCallNode {
/** The instance of the service a handler is registered on. */
ServiceInstance srv;
string methodName;

Expand All @@ -308,6 +372,9 @@ class HandlerRegistration extends MethodCallNode {
methodName = ["before", "on", "after"]
}

/**
* Gets the instance of the service a handler is registered on.
*/
ServiceInstance getService() { result = srv }

/**
Expand Down Expand Up @@ -347,7 +414,7 @@ class HandlerRegistration extends MethodCallNode {

/**
* The first parameter of a handler, representing the request object received either directly
* from a user, or from another service that may be internal (defined in the same application)
* from a user, or from another service that may be internal (defined in the same application)
* or external (defined in another application, or even served from a different server).
* e.g.
* ``` javascript
Expand All @@ -356,7 +423,7 @@ class HandlerRegistration extends MethodCallNode {
* this.before("SomeEvent", "SomeEntity", (req, next) => { ... });
* this.after("SomeEvent", "SomeEntity", (req, next) => { ... });
* }
* ```
* ```
* All parameters named `req` above are captured. Also see `HandlerParameterOfExposedService`
* for a subset of this class that is only about handlers exposed to some protocol.
*/
Expand Down Expand Up @@ -506,7 +573,7 @@ abstract class UserDefinedApplicationService extends UserDefinedService {
/**
* Holds if this service supports access from the outside through any kind of protocol.
*/
predicate isExposed() { not this.isInternal() }
predicate isExposed() { exists(this.getCdsDeclaration()) and not this.isInternal() }

/**
* Holds if this service does not support access from the outside through any kind of protocol, thus being internal only.
Expand Down Expand Up @@ -539,9 +606,21 @@ class ES6ApplicationServiceDefinition extends ClassNode, UserDefinedApplicationS

/**
* Subclassing `cds.ApplicationService` via a call to `cds.service.impl`.
* ```js
* e.g.1. Given this code:
* ``` javascript
* const cds = require('@sap/cds')
* module.exports = cds.service.impl (function() {
* this.on("SomeEvent1", (req) => { ... })
* })
* ```
* This class captures the call `cds.service.impl (function() { ... })`.
*
* e.g.2. Given this code:
* ``` javascript
* const cds = require('@sap/cds')
* module.exports = cds.service.impl (function() { ... })
* module.exports = cds.service.impl ((srv) => {
* srv.on("SomeEvent1", (req) => { ... })
* })
* ```
*/
class ImplMethodCallApplicationServiceDefinition extends MethodCallNode,
Expand All @@ -554,6 +633,40 @@ class ImplMethodCallApplicationServiceDefinition extends MethodCallNode,
override FunctionNode getInitFunction() { result = this.getArgument(0) }
}

/**
* A user-defined application service that comes in a form of an exported
* closure. e.g. Given the below code,
* ``` javascript
* const cds = require("@sap/cds");
*
* module.exports = (srv) => {
* srv.before("SomeEvent1", "SomeEntity", (req, res) => { ... })
* srv.on("SomeEvent2", (req) => { ... } )
* srv.after("SomeEvent3", (req) => { ... } )
* }
* ```
* This class captures the entire `(srv) => { ... }` function that is
* exported.
*/
class ExportedClosureApplicationServiceDefinition extends FunctionNode,
UserDefinedApplicationService
{
ExportedClosureApplicationServiceDefinition() {
/*
* ==================== HACK ====================
* See issue #221.
*/

exists(PropWrite moduleExports |
moduleExports.getBase().asExpr().(VarAccess).getName() = "module" and
moduleExports.getPropertyName() = "exports" and
this = moduleExports.getRhs()
)
}

override FunctionNode getInitFunction() { result = this }
}

abstract class InterServiceCommunicationMethodCall extends MethodCallNode {
string name;
ServiceInstance recipient;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ class HandlerParameterOfExposedService extends HandlerParameter {
* is known.
*/

not exists(this.getHandler().getHandlerRegistration().getService().getDefinition())
not exists(
this.getHandler().getHandlerRegistration().getService().getDefinition().getCdsDeclaration()
)
}
}

Expand All @@ -54,7 +56,9 @@ class UserProvidedPropertyReadOfHandlerParameterOfExposedService extends RemoteF

UserProvidedPropertyReadOfHandlerParameterOfExposedService() {
/* 1. `req.(data|params|headers|id)` */
this = handlerParameterOfExposedService.getAPropertyRead(["data", "params", "headers", "id"])
this =
handlerParameterOfExposedService
.getAPropertyRead(["data", "params", "headers", "id", "_queryOptions"])
or
/* 2. APIs stemming from `req.http.req`: Defined by Express.js */
exists(PropRead reqHttpReq |
Expand Down