@@ -101,7 +101,7 @@ class CdsConnectToCall extends DataFlow::CallNode {
101101}
102102
103103/**
104- * A dataflow node that represents a service.
104+ * A data flow node that represents a service.
105105 * Note that its definition is a `UserDefinedApplicationService`, not a `ServiceInstance`.
106106 */
107107abstract class ServiceInstance extends SourceNode {
@@ -146,7 +146,7 @@ class ServiceInstanceFromCdsServe extends ServiceInstance {
146146 * const Service1 = cds.connect.to("service-2");
147147 * ```
148148 */
149- class ServiceInstanceFromCdsConnectTo extends ServiceInstance , SourceNode instanceof PropRead {
149+ class ServiceInstanceFromCdsConnectTo extends ServiceInstance {
150150 string serviceDesignator ;
151151 string serviceName ;
152152
@@ -155,9 +155,8 @@ class ServiceInstanceFromCdsConnectTo extends ServiceInstance, SourceNode instan
155155 }
156156
157157 override UserDefinedApplicationService getDefinition ( ) {
158- /* 1. The service */
159158 exists ( RequiredService serviceDecl |
160- serviceDecl .getName ( ) = [ serviceName , serviceDesignator ] and
159+ serviceDecl .getName ( ) = serviceDesignator and
161160 result .hasLocationInfo ( serviceDecl .getImplementationFile ( ) .getAbsolutePath ( ) , _, _, _, _)
162161 )
163162 or
@@ -169,10 +168,6 @@ class ServiceInstanceFromCdsConnectTo extends ServiceInstance, SourceNode instan
169168 string getServiceName ( ) { result = serviceName }
170169}
171170
172- class DBServiceInstanceFromCdsConnectTo extends ServiceInstanceFromCdsConnectTo {
173- DBServiceInstanceFromCdsConnectTo ( ) { serviceDesignator = "db" }
174- }
175-
176171/**
177172 * A service instance obtained by directly calling the constructor
178173 * of its class with a `new` keyword. e.g.
@@ -271,6 +266,28 @@ class ServiceInstanceFromServeWithParameter extends ServiceInstance {
271266 }
272267}
273268
269+ abstract class CdsDbService extends ServiceInstance {
270+ /* A DB service is implicitly defined. */
271+ override UserDefinedApplicationService getDefinition ( ) { none ( ) }
272+ }
273+
274+ class GloballyAccessedCdsDbService extends CdsDbService {
275+ GloballyAccessedCdsDbService ( ) {
276+ exists ( CdsFacade cds |
277+ this = cds .getMember ( "db" ) .asSource ( ) or
278+ this = cds .asSource ( )
279+ )
280+ }
281+ }
282+
283+ /* Note: This should not extend `ServiceInstanceFromCdsConnectTo`, as it does NOT do a property read! */
284+ class DbServiceInstanceFromCdsConnectTo extends CdsDbService {
285+ DbServiceInstanceFromCdsConnectTo ( ) { this = serviceInstanceFromCdsConnectTo ( "db" ) }
286+
287+ /* A DB service is implicitly defined. */
288+ override UserDefinedApplicationService getDefinition ( ) { none ( ) }
289+ }
290+
274291/**
275292 * A call to `before`, `on`, or `after` on an `cds.ApplicationService`.
276293 * It registers an handler to be executed when an event is fired,
@@ -564,16 +581,30 @@ class CdsUser extends API::Node {
564581 }
565582}
566583
567- class CdsTransaction extends MethodCallNode {
584+ class CdsTransaction extends SourceNode {
568585 ServiceInstance srv ;
586+ CallNode txCall ;
569587
570- CdsTransaction ( ) { this = srv .getAMemberCall ( "tx" ) }
588+ CdsTransaction ( ) {
589+ txCall = srv .getAMemberCall ( "tx" ) and
590+ (
591+ this = txCall or
592+ this =
593+ txCall
594+ .getABoundCallbackParameter ( [
595+ 0 , // When the context object is absent
596+ 1 // When the context object is present
597+ ] , 0 )
598+ )
599+ }
571600
572601 ServiceInstance getRunner ( ) { result = srv }
573602
574603 SourceNode getContextObject ( ) {
575- result = this .getAnArgument ( ) .getALocalSource ( ) and not result instanceof FunctionNode
604+ /* 1. An object node passed as the first argument to a call to `srv.tx`. */
605+ result = txCall .getALocalSource ( ) and not result instanceof FunctionNode
576606 or
607+ /* 2. A manually overriden `cds.context`. */
577608 exists ( Stmt stmt , CdsFacade cds |
578609 stmt = this .asExpr ( ) .getFirstControlFlowNode ( ) .getAPredecessor + ( ) and
579610 result = cds .getMember ( "context" ) .asSink ( ) and
@@ -583,25 +614,10 @@ class CdsTransaction extends MethodCallNode {
583614
584615 DataFlow:: Node getUser ( ) { result = this .getContextObject ( ) .getAPropertyWrite ( "user" ) .getRhs ( ) }
585616
586- MethodCallNode getATransactionCall ( ) {
587- exists ( ControlFlowNode exprOrStmt |
588- exprOrStmt =
589- this .getAnArgument ( ) .( FunctionNode ) .getALocalSource ( ) .asExpr ( ) .( Function ) .getABodyStmt ( ) and
590- exprOrStmt .( Stmt ) .getAChildExpr ( ) .flow ( ) .( MethodCallNode ) .getReceiver ( ) .getALocalSource ( ) =
591- this .getAnArgument ( ) .( FunctionNode ) .getParameter ( _) and
592- result = exprOrStmt .( Stmt ) .getAChildExpr ( ) .flow ( )
593- or
594- exprOrStmt =
595- this .getAnArgument ( ) .( FunctionNode ) .getALocalSource ( ) .asExpr ( ) .( Function ) .getAChildExpr ( ) and
596- exprOrStmt .( Expr ) .flow ( ) .( MethodCallNode ) .getReceiver ( ) .getALocalSource ( ) =
597- this .getAnArgument ( ) .( FunctionNode ) .getParameter ( _) and
598- result = exprOrStmt .( MethodCallExpr ) .flow ( )
599- or
600- exprOrStmt = this .asExpr ( ) .getFirstControlFlowNode ( ) .getASuccessor + ( ) and
601- exprOrStmt .( Expr ) .flow ( ) .( MethodCallNode ) .getReceiver ( ) .getALocalSource ( ) = this and
602- result = exprOrStmt .( MethodCallExpr ) .flow ( )
603- )
604- }
617+ /**
618+ * Gets a method call on this transaction object.
619+ */
620+ MethodCallNode getATransactionCall ( ) { result = this .getAMemberCall ( _) }
605621
606622 CqlClause getAnExecutedCqlClause ( ) {
607623 result .asExpr ( ) = this .getATransactionCall ( ) .getAnArgument ( ) .asExpr ( )
@@ -722,13 +738,11 @@ class EntityReferenceFromUserDefinedServiceEntities extends EntityReferenceFromE
722738}
723739
724740/**
725- * db .entities, db .entities(...), cds.entities, cds.entities(...)
741+ * cds .entities, cds .entities(...), cds.db. entities, cds.db .entities(...)
726742 */
727743class EntityReferenceFromDbOrCdsEntities extends EntityReferenceFromEntities {
728744 EntityReferenceFromDbOrCdsEntities ( ) {
729- this .getReceiver ( ) .getALocalSource ( ) instanceof DBServiceInstanceFromCdsConnectTo or
730- exists ( CdsFacade cds | this .getReceiver ( ) .getALocalSource ( ) = cds .getNode ( ) ) or
731- exists ( CdsFacade cds | this .getReceiver ( ) .getALocalSource ( ) = cds .getMember ( "db" ) .asSource ( ) )
745+ this .getReceiver ( ) .getALocalSource ( ) instanceof CdsDbService
732746 }
733747
734748 override CdlEntity getCqlDefinition ( ) {
@@ -823,8 +837,16 @@ abstract class CqlQueryRunnerCall extends MethodCallNode {
823837
824838 exists ( CdsFacade cds | base = cds .asSource ( ) ) or
825839 exists ( CdsDb cdsDb | base = cdsDb ) or
826- /* 2. Method call on a service instance object. */
827- exists ( ServiceInstance srv | base = srv )
840+ /*
841+ * 2. Method call on a service instance object.
842+ */
843+
844+ exists ( ServiceInstance srv | base .getALocalSource ( ) = srv ) or
845+ /*
846+ * 3. Method call on a transaction object.
847+ */
848+
849+ exists ( CdsTransaction tx | base = tx )
828850 )
829851 }
830852
@@ -911,3 +933,38 @@ class CqlUpsertMethodCall extends CqlShortcutMethodCall {
911933 )
912934 }
913935}
936+
937+ /**
938+ * A call to APIs that takes the given input string written in CDL and parses it according to
939+ * the CQN specification.
940+ *
941+ * Note that the outcome of calling the fluent APIs is also a CQN, which means both can be run
942+ * against a service with `srv.run`.
943+ */
944+ abstract class CqlClauseParserCall extends DataFlow:: CallNode {
945+ DataFlow:: ExprNode cdlString ;
946+
947+ DataFlow:: ExprNode getCdlString ( ) { result = cdlString }
948+ }
949+
950+ class GlobalCQLFunction extends CqlClauseParserCall {
951+ GlobalCQLFunction ( ) { this = DataFlow:: globalVarRef ( "CQL" ) .getACall ( ) }
952+ }
953+
954+ class CdsParseCqlCall extends CqlClauseParserCall {
955+ CdsParseCqlCall ( ) {
956+ exists ( CdsFacade cds |
957+ this = cds .getMember ( "parse" ) .getMember ( "cql" ) .getACall ( ) and
958+ cdlString = this .getArgument ( 0 )
959+ )
960+ }
961+ }
962+
963+ class CdsQlCall extends CqlClauseParserCall {
964+ CdsQlCall ( ) {
965+ exists ( CdsFacade cds |
966+ this = cds .getMember ( "ql" ) .getACall ( ) and
967+ cdlString = this .getArgument ( 0 )
968+ )
969+ }
970+ }
0 commit comments