@@ -29,6 +29,8 @@ class NameBindingNode extends TNameBindingNode {
2929
3030 Identifier asIdentifier ( ) { this .isIdentifier ( result ) }
3131
32+ predicate isMember ( Member m ) { this .asIdentifier ( ) = m .getNameNode ( ) }
33+
3234 predicate isBulkImport ( BulkImportingPattern p ) { this = TBulkImport ( p ) }
3335
3436 predicate isLocalName ( LocalName local ) { this = TLocalName ( local ) }
@@ -312,6 +314,10 @@ signature module TrackInputSig {
312314 /** Holds if the forward-flow of `node` should be tracked. */
313315 predicate shouldTrack ( NameBindingNode node ) ;
314316
317+ default NameBindingNode getMember ( NamespaceNode namespace , string name ) {
318+ result = namespace .getMember ( name )
319+ }
320+
315321 default predicate additionalValueStep ( NameBindingNode node1 , NameBindingNode node2 ) { none ( ) }
316322}
317323
@@ -327,6 +333,25 @@ module Track<TrackInputSig Input> {
327333 exists ( NameBindingNode prev | prev = track ( node ) | valueStepEx ( prev , result ) )
328334 }
329335
336+ pragma [ nomagic]
337+ private predicate derivedStoreReadStep0 (
338+ NamespaceNode namespace , string name , NameBindingNode node2
339+ ) {
340+ readStep ( namespace .ref ( ) , name , node2 )
341+ }
342+
343+ /**
344+ * Holds if `node1 -> node2` is derived by combining a store and a read step, with zero or more value steps and inheritance steps in-between.
345+ */
346+ pragma [ nomagic]
347+ private predicate derivedStoreReadStep ( NameBindingNode node1 , NameBindingNode node2 ) {
348+ exists ( NamespaceNode namespace , string name |
349+ node1 = getMember ( namespace , name ) and // getMember() combines a store step with subsequent inheritance steps
350+ derivedStoreReadStep0 ( namespace , name , node2 ) and
351+ node1 != node2
352+ )
353+ }
354+
330355 /** Holds if there is an effective value step `node1 -> node2`. */
331356 pragma [ inline]
332357 private predicate valueStepEx ( NameBindingNode node1 , NameBindingNode node2 ) {
@@ -338,23 +363,6 @@ module Track<TrackInputSig Input> {
338363 }
339364}
340365
341- pragma [ nomagic]
342- private predicate derivedStoreReadStep0 ( NamespaceNode namespace , string name , NameBindingNode node2 ) {
343- readStep ( namespace .ref ( ) , pragma [ only_bind_into ] ( name ) , node2 )
344- }
345-
346- /**
347- * Holds if `node1 -> node2` is derived by combining a store and a read step, with zero or more value steps and inheritance steps in-between.
348- */
349- pragma [ nomagic]
350- private predicate derivedStoreReadStep ( NameBindingNode node1 , NameBindingNode node2 ) {
351- exists ( NamespaceNode namespace , string name |
352- node1 = namespace .getMember ( name ) and // getMember() combines a store step with subsequent inheritance steps
353- derivedStoreReadStep0 ( namespace , name , node2 ) and
354- node1 != node2
355- )
356- }
357-
358366/** Holds if the member represented by `node` can be inherited. */
359367pragma [ nomagic]
360368private predicate isInheritableMemberNode ( NameBindingNode node ) {
@@ -423,23 +431,47 @@ class NamespaceNode extends NameBindingNode {
423431 /** Gets a namespace that directly inherits from this one. */
424432 NamespaceNode getAnInheritanceChild ( ) { result .getAnInheritanceParent ( ) = this }
425433
434+ pragma [ nomagic]
435+ private predicate hasOwnMemberWithShadowingKey ( string name , string shadowingKey ) {
436+ shadowingKey = getShadowingKey ( this .getOwnMember ( name ) ) .asSome ( )
437+ }
438+
439+ /**
440+ * Gets a potential member of this namespace of the given name.
441+ *
442+ * Unlike `getMember`, this predicate does not filter away invalid members.
443+ */
444+ pragma [ nomagic]
445+ NameBindingNode getMemberFull ( string name , ShadowingKeyOpt shadowingKey ) {
446+ result = this .getOwnMember ( name ) and
447+ shadowingKey = getShadowingKey ( result )
448+ or
449+ not this .hasOwnMemberWithShadowingKey ( name , shadowingKey .asSome ( ) ) and
450+ result = this .getAnInheritanceParent ( ) .getMemberFull ( name , shadowingKey ) and
451+ isInheritableMemberNode ( result )
452+ or
453+ result = this .getAnExtension ( ) .getMemberFull ( name , shadowingKey )
454+ }
455+
426456 /** Gets a member of this namespace of the given name. */
427457 cached
428458 NameBindingNode getMember ( string name ) {
429459 CachedStage:: ref ( ) and
430- result = this .getOwnMember ( name )
431- or
432- not this .hasOwnMember ( name ) and
433- result = this .getAnInheritanceParent ( ) .getMember ( name ) and
434- isInheritableMemberNode ( result )
435- or
436- result = this .getAnExtension ( ) .getMember ( name )
460+ result = this .getMemberFull ( name , _) and
461+ not exists ( Member m |
462+ result .isMember ( m ) and
463+ isInvalidMember ( this , m )
464+ )
437465 }
438466}
439467
440468private module TrackNamespaceInput implements TrackInputSig {
441469 predicate shouldTrack ( NameBindingNode node ) { node instanceof NamespaceNode }
442470
471+ NameBindingNode getMember ( NamespaceNode namespace , string name ) {
472+ result = namespace .getMemberFull ( name , _)
473+ }
474+
443475 predicate additionalValueStep ( NameBindingNode node1 , NameBindingNode node2 ) {
444476 // Namespace-tracking goes through aliases, but declaration-tracking does not
445477 exists ( TypeAliasDeclaration decl |
0 commit comments