@@ -165,11 +165,17 @@ class SapDefineModule extends AmdModuleDefinition::Range, MethodCallExpr, UserMo
165165 sap .getName ( ) = "sap" and
166166 sapUi .getBase ( ) = sap and
167167 sapUi .getPropertyName ( ) = "ui" and
168- this .getReceiver ( ) = sapUiDefine
169- // and this.getMethodName() = "define"
168+ this .getReceiver ( ) = sapUiDefine and
169+ this .getMethodName ( ) = [ "define" , "require" ] // TODO: Treat sap.ui.declare in its own class
170170 )
171171 }
172172
173+ SapExtendCall getExtendCall ( ) { result .getDefine ( ) = this }
174+
175+ string getName ( ) { result = this .getExtendCall ( ) .getName ( ) }
176+
177+ Module asModule ( ) { result = this .getTopLevel ( ) }
178+
173179 string getDependency ( int i ) {
174180 result = this .( AmdModuleDefinition ) .getDependencyExpr ( i ) .getStringValue ( )
175181 }
@@ -185,20 +191,67 @@ class SapDefineModule extends AmdModuleDefinition::Range, MethodCallExpr, UserMo
185191 WebApp getWebApp ( ) { this .getFile ( ) = result .getAResource ( ) }
186192
187193 /**
188- * Gets the module defined with sap.ui.define that imports and extends this module.
194+ * Gets the module defined with sap.ui.define that imports and extends (subclasses) this module.
189195 */
190196 SapDefineModule getExtendingModule ( ) {
191- exists ( SapExtendCall baseExtendCall , SapExtendCall subclassExtendCall |
192- baseExtendCall .getDefine ( ) = this and
193- result = subclassExtendCall .getDefine ( ) and
194- result
195- .getRequiredObject ( baseExtendCall .getName ( ) .replaceAll ( "." , "/" ) )
196- .asSourceNode ( )
197- .flowsTo ( subclassExtendCall .getReceiver ( ) )
198- )
197+ // exists(SapExtendCall baseExtendCall, SapExtendCall subclassExtendCall |
198+ // baseExtendCall.getDefine() = this and
199+ // result = subclassExtendCall.getDefine() and
200+ // result
201+ // .getRequiredObject(baseExtendCall.getName().replaceAll(".", "/"))
202+ // .asSourceNode()
203+ // .flowsTo(subclassExtendCall.getReceiver())
204+ // )
205+ none ( ) // TODO
199206 }
200207}
201208
209+ /**
210+ * Holds if the `importingModule` "imports" the `importedModule` via path `importPath`.
211+ */
212+ private predicate importerAndImportee (
213+ SapDefineModule importingModule , SapDefineModule importedModule , string importPath
214+ ) {
215+ /* 1. Absolute import paths: We resolve this ourselves. */
216+ exists ( string importedModuleDefinitionPath , string importedModuleDefinitionPathSlashNormalized |
217+ /*
218+ * Let `importPath` = "my/app/path1/path2/controller/Some.controller",
219+ * `importedModuleDefinitionPath` = "my.app.path1.path2.controller.Some",
220+ * `importedModuleDefinitionPathSlashNormalized` = "my/app/path1/path2/controller/Some".
221+ * Then, `importedModuleDefinitionPathSlashNormalized` matches `importPath`.
222+ */
223+
224+ importPath = importingModule .asModule ( ) .getAnImport ( ) .getImportedPathExpr ( ) .getStringValue ( ) and
225+ importedModuleDefinitionPath = importedModule .getExtendCall ( ) .getName ( ) and
226+ importedModuleDefinitionPathSlashNormalized = importedModuleDefinitionPath .replaceAll ( "." , "/" ) and
227+ importPath .matches ( importedModuleDefinitionPathSlashNormalized + "%" )
228+ )
229+ or
230+ /*
231+ * 2. Relative import paths: We delegate the heaving lifting of resolving to
232+ * `Import.resolveImportedPath/0`.
233+ */
234+
235+ exists ( Import import_ |
236+ importPath = import_ .getImportedPathExpr ( ) .getStringValue ( ) and
237+ import_ = importingModule .asModule ( ) .getAnImport ( ) and
238+ import_ .resolveImportedPath ( ) = importedModule .getTopLevel ( )
239+ )
240+ }
241+
242+ /**
243+ * Holds if the `importingModule` extends the `importedModule`, imported via path `importPath`.
244+ */
245+ private predicate importerExtendsImportee (
246+ SapDefineModule importingModule , SapDefineModule importedModule , string importPath
247+ ) {
248+ importerAndImportee ( importingModule , importedModule , importPath ) and
249+ importingModule
250+ .getRequiredObject ( importPath )
251+ .asSourceNode ( )
252+ .flowsTo ( importingModule .getExtendCall ( ) .getReceiver ( ) )
253+ }
254+
202255class JQuerySap extends DataFlow:: SourceNode {
203256 JQuerySap ( ) {
204257 exists ( DataFlow:: GlobalVarRefNode global |
@@ -738,6 +791,11 @@ abstract class UI5InternalModel extends UI5Model, NewNode {
738791 abstract string getPathString ( ) ;
739792
740793 abstract string getPathString ( Property property ) ;
794+
795+ /**
796+ * Holds if the content of the model is statically determinable.
797+ */
798+ abstract predicate contentIsStaticallyVisible ( ) ;
741799}
742800
743801import ManifestJson
@@ -1118,6 +1176,16 @@ class JsonModel extends UI5InternalModel {
11181176 )
11191177 }
11201178
1179+ override predicate contentIsStaticallyVisible ( ) {
1180+ /* 1. There is at least one path string that can be constructed out of the path string. */
1181+ exists ( this .getPathString ( ) )
1182+ or
1183+ /* 2. There is a JSON file that can be loaded from. */
1184+ exists ( JsonObject jsonObject |
1185+ jsonObject = resolveDirectPath ( this .getArgument ( 0 ) .getStringValue ( ) )
1186+ )
1187+ }
1188+
11211189 /**
11221190 * A model possibly supporting two-way binding explicitly set as a one-way binding model.
11231191 */
@@ -1175,6 +1243,8 @@ class XmlModel extends UI5InternalModel {
11751243 }
11761244
11771245 override string getPathString ( ) { result = "TODO" }
1246+
1247+ override predicate contentIsStaticallyVisible ( ) { exists ( this .getPathString ( ) ) }
11781248}
11791249
11801250class ResourceModel extends UI5Model , ModelReference {
0 commit comments