@@ -559,3 +559,84 @@ private module FolderHeuristic {
559559 )
560560 }
561561}
562+
563+ /**
564+ * Holds if `access` may resolve to `target` through the enclosing `accessingClass`.
565+ *
566+ * `instanceAccess` indicates if this this member should be accessed as an instance of `accessingClass`
567+ * or as a static member.
568+ */
569+ private predicate unqualifiedMemberAccessCand (
570+ PotentialLocalNameAccess access , boolean instanceAccess , NameDeclaration target ,
571+ ClassLikeDeclaration accessingClass
572+ ) {
573+ not access instanceof NameDeclaration and
574+ (
575+ // Resolved by local scoping
576+ exists ( LocalName local |
577+ target .getLocalName ( ) = local and
578+ access .getLocalName ( ) = local and
579+ target .getDeclaration ( ) = accessingClass .getAMember ( )
580+ |
581+ instanceAccess = true and
582+ isInstanceMember ( target .getDeclaration ( ) )
583+ or
584+ instanceAccess = false and
585+ isStaticMember ( target .getDeclaration ( ) )
586+ )
587+ or
588+ // Resolved in an uncertain scope
589+ exists ( NamespaceNode namespace , string name |
590+ name = access .getName ( ) and
591+ accessingClass = LocalNameBindingOutput:: getAnUncertainScope ( access , name )
592+ |
593+ instanceAccess = true and
594+ namespace .isInstanceMemberNamespace ( accessingClass ) and
595+ namespace .getMember ( name ) .isIdentifier ( target )
596+ or
597+ instanceAccess = false and
598+ namespace .isStaticMemberNamespace ( accessingClass ) and
599+ namespace .getMember ( name ) .isIdentifier ( target )
600+ )
601+ )
602+ }
603+
604+ private int unqualifiedMemberAccessDepth ( PotentialLocalNameAccess access ) {
605+ result = max ( AstNode scope | unqualifiedMemberAccessCand ( access , _, _, scope ) | scope .getDepth ( ) )
606+ }
607+
608+ /**
609+ * Holds if `access` is an unqualified access to `target`.
610+ *
611+ * `accessingClass` is the enclosing class in which the member was found, and
612+ * `instanceAccess` indicates if it is an instance member or static member.
613+ */
614+ predicate unqualifiedMemberAccess (
615+ PotentialLocalNameAccess access , boolean instanceAccess , NameDeclaration target ,
616+ ClassLikeDeclaration accessingClass
617+ ) {
618+ unqualifiedMemberAccessCand ( access , instanceAccess , target , accessingClass ) and
619+ accessingClass .getDepth ( ) = unqualifiedMemberAccessDepth ( access )
620+ }
621+
622+ /**
623+ * An identifier appearing in a unqualified position, referring to a member of an enclosing class.
624+ */
625+ class UnqualifiedMemberAccess extends Identifier {
626+ private boolean instanceAccess ;
627+ private NameDeclaration target ;
628+ private ClassLikeDeclaration accessingClass ;
629+
630+ UnqualifiedMemberAccess ( ) {
631+ unqualifiedMemberAccess ( this , instanceAccess , target , accessingClass )
632+ }
633+
634+ /** Gets the name declaration of the member being accessed. */
635+ NameDeclaration getTarget ( ) { result = target }
636+
637+ /** Gets the enclosing class whose (possibly inherited) member is being accessed. */
638+ ClassLikeDeclaration getAccessingClass ( ) { result = accessingClass }
639+
640+ /** Holds if this is an instance access on the accessing class. */
641+ predicate isInstanceAccess ( ) { instanceAccess = true }
642+ }
0 commit comments