3
3
using System . Collections . Generic ;
4
4
using System . Diagnostics ;
5
5
using System . Linq ;
6
+ using System . Runtime . InteropServices . WindowsRuntime ;
6
7
using Antlr4 . Runtime ;
7
8
using NLog ;
8
9
using Rubberduck . Parsing . Annotations ;
@@ -475,16 +476,16 @@ public IEnumerable<ModuleBodyElementDeclaration> FindInterfaceImplementationMemb
475
476
: Enumerable . Empty < ModuleBodyElementDeclaration > ( ) ;
476
477
}
477
478
478
- public ParameterDeclaration FindParameter ( Declaration procedure , string parameterName )
479
+ public ParameterDeclaration FindParameter ( Declaration parameterizedMember , string parameterName )
479
480
{
480
- return _parametersByParent . TryGetValue ( procedure , out List < ParameterDeclaration > parameters )
481
+ return _parametersByParent . TryGetValue ( parameterizedMember , out List < ParameterDeclaration > parameters )
481
482
? parameters . SingleOrDefault ( parameter => parameter . IdentifierName == parameterName )
482
483
: null ;
483
484
}
484
485
485
- public IEnumerable < ParameterDeclaration > Parameters ( Declaration procedure )
486
+ public IEnumerable < ParameterDeclaration > Parameters ( Declaration parameterizedMember )
486
487
{
487
- return _parametersByParent . TryGetValue ( procedure , out List < ParameterDeclaration > result )
488
+ return _parametersByParent . TryGetValue ( parameterizedMember , out List < ParameterDeclaration > result )
488
489
? result
489
490
: Enumerable . Empty < ParameterDeclaration > ( ) ;
490
491
}
@@ -542,46 +543,34 @@ public IEnumerable<Declaration> MatchName(string name)
542
543
: Enumerable . Empty < Declaration > ( ) ;
543
544
}
544
545
545
- public ParameterDeclaration FindParameterFromArgument ( VBAParser . ArgumentExpressionContext argExpression , Declaration enclosingProcedure )
546
+ public ParameterDeclaration FindParameterOfNonDefaultMemberFromSimpleArgumentNotPassedByValExplicitly ( VBAParser . ArgumentExpressionContext argumentExpression , Declaration enclosingProcedure )
546
547
{
547
- if ( argExpression == null ||
548
- argExpression . GetDescendent < VBAParser . ParenthesizedExprContext > ( ) != null ||
549
- argExpression . BYVAL ( ) != null )
550
- {
551
- // not an argument, or argument is parenthesized and thus passed ByVal
552
- return null ;
553
- }
554
-
555
- var callStmt = argExpression . GetAncestor < VBAParser . CallStmtContext > ( ) ;
556
-
557
- var identifier = callStmt ?
558
- . GetDescendent < VBAParser . LExpressionContext > ( )
559
- . GetDescendents < VBAParser . IdentifierContext > ( )
560
- . LastOrDefault ( ) ;
548
+ return FindParameterOfNonDefaultMemberFromSimpleArgumentNotPassedByValExplicitly ( argumentExpression , enclosingProcedure . QualifiedModuleName ) ;
549
+ }
561
550
562
- if ( identifier == null )
563
- {
564
- // if we don't know what we're calling, we can't dig any further
565
- return null ;
566
- }
551
+ public ParameterDeclaration FindParameterOfNonDefaultMemberFromSimpleArgumentNotPassedByValExplicitly ( VBAParser . ArgumentExpressionContext argumentExpression , QualifiedModuleName module )
552
+ {
553
+ //todo: Rename after making it work for more general cases.
567
554
568
- var selection = new QualifiedSelection ( enclosingProcedure . QualifiedModuleName , identifier . GetSelection ( ) ) ;
569
- if ( ! _referencesBySelection . TryGetValue ( selection , out var matches ) )
555
+ if ( argumentExpression == null
556
+ || argumentExpression . GetDescendent < VBAParser . ParenthesizedExprContext > ( ) != null
557
+ || argumentExpression . BYVAL ( ) != null )
570
558
{
559
+ // not a simple argument, or argument is parenthesized and thus passed ByVal
571
560
return null ;
572
561
}
573
562
574
- var procedure = matches . SingleOrDefault ( ) ? . Declaration ;
575
- if ( procedure ? . ParentScopeDeclaration is ClassModuleDeclaration )
563
+ var callingNonDefaultMember = CallingNonDefaultMember ( argumentExpression , module ) ;
564
+ if ( callingNonDefaultMember == null )
576
565
{
577
- // we can't know that the member is on the class' default interface
566
+ // Either we could not resolve the call or there is a default member call involved.
578
567
return null ;
579
568
}
580
569
581
- var parameters = Parameters ( procedure ) ;
570
+ var parameters = Parameters ( callingNonDefaultMember ) ;
582
571
583
572
ParameterDeclaration parameter ;
584
- var namedArg = argExpression . GetAncestor < VBAParser . NamedArgumentContext > ( ) ;
573
+ var namedArg = argumentExpression . GetAncestor < VBAParser . NamedArgumentContext > ( ) ;
585
574
if ( namedArg != null )
586
575
{
587
576
// argument is named: we're lucky
@@ -591,12 +580,12 @@ public ParameterDeclaration FindParameterFromArgument(VBAParser.ArgumentExpressi
591
580
else
592
581
{
593
582
// argument is positional: work out its index
594
- var argList = callStmt . GetDescendent < VBAParser . ArgumentListContext > ( ) ;
595
- var args = argList . GetDescendents < VBAParser . PositionalArgumentContext > ( ) . ToArray ( ) ;
583
+ var argumentList = argumentExpression . GetAncestor < VBAParser . ArgumentListContext > ( ) ;
584
+ var arguments = argumentList . GetDescendents < VBAParser . PositionalArgumentContext > ( ) . ToArray ( ) ;
596
585
597
- var parameterIndex = args
598
- . Select ( ( param , index ) => param . GetDescendent < VBAParser . ArgumentExpressionContext > ( ) == argExpression ? ( param , index ) : ( null , - 1 ) )
599
- . SingleOrDefault ( item => item . param != null ) . index ;
586
+ var parameterIndex = arguments
587
+ . Select ( ( arg , index ) => arg . GetDescendent < VBAParser . ArgumentExpressionContext > ( ) == argumentExpression ? ( arg , index ) : ( null , - 1 ) )
588
+ . SingleOrDefault ( item => item . arg != null ) . index ;
600
589
601
590
parameter = parameters
602
591
. OrderBy ( p => p . Selection )
@@ -607,6 +596,121 @@ public ParameterDeclaration FindParameterFromArgument(VBAParser.ArgumentExpressi
607
596
return parameter ;
608
597
}
609
598
599
+ private ModuleBodyElementDeclaration CallingNonDefaultMember ( VBAParser . ArgumentExpressionContext argumentExpression , QualifiedModuleName module )
600
+ {
601
+ //todo: Make this work for default member calls.
602
+
603
+ var argumentList = argumentExpression . GetAncestor < VBAParser . ArgumentListContext > ( ) ;
604
+ var cannotHaveDefaultMemberCall = false ;
605
+
606
+ ParserRuleContext callingExpression ;
607
+ switch ( argumentList . Parent )
608
+ {
609
+ case VBAParser . CallStmtContext callStmt :
610
+ cannotHaveDefaultMemberCall = true ;
611
+ callingExpression = callStmt . lExpression ( ) ;
612
+ break ;
613
+ case VBAParser . IndexExprContext indexExpr :
614
+ callingExpression = indexExpr . lExpression ( ) ;
615
+ break ;
616
+ case VBAParser . WhitespaceIndexExprContext indexExpr :
617
+ callingExpression = indexExpr . lExpression ( ) ;
618
+ break ;
619
+ default :
620
+ //This should never happen.
621
+ return null ;
622
+ }
623
+
624
+ VBAParser . IdentifierContext callingIdentifier ;
625
+ if ( cannotHaveDefaultMemberCall )
626
+ {
627
+ callingIdentifier = callingExpression
628
+ . GetDescendents < VBAParser . IdentifierContext > ( )
629
+ . LastOrDefault ( ) ;
630
+ }
631
+ else
632
+ {
633
+ switch ( callingExpression )
634
+ {
635
+ case VBAParser . SimpleNameExprContext simpleName :
636
+ callingIdentifier = simpleName . identifier ( ) ;
637
+ break ;
638
+ case VBAParser . MemberAccessExprContext memberAccess :
639
+ callingIdentifier = memberAccess
640
+ . GetDescendents < VBAParser . IdentifierContext > ( )
641
+ . LastOrDefault ( ) ;
642
+ break ;
643
+ case VBAParser . WithMemberAccessExprContext memberAccess :
644
+ callingIdentifier = memberAccess
645
+ . GetDescendents < VBAParser . IdentifierContext > ( )
646
+ . LastOrDefault ( ) ;
647
+ break ;
648
+ default :
649
+ //This is only possible in case of a default member access.
650
+ return null ;
651
+ }
652
+ }
653
+
654
+ if ( callingIdentifier == null )
655
+ {
656
+ return null ;
657
+ }
658
+
659
+ var referencedMember = IdentifierReferences ( callingIdentifier , module )
660
+ . Select ( reference => reference . Declaration )
661
+ . OfType < ModuleBodyElementDeclaration > ( )
662
+ . FirstOrDefault ( ) ;
663
+
664
+ return referencedMember ;
665
+ }
666
+
667
+ public ParameterDeclaration FindParameterFromSimpleEventArgumentNotPassedByValExplicitly ( VBAParser . EventArgumentContext eventArgument , QualifiedModuleName module )
668
+ {
669
+ if ( eventArgument == null
670
+ || eventArgument . GetDescendent < VBAParser . ParenthesizedExprContext > ( ) != null
671
+ || eventArgument . BYVAL ( ) != null )
672
+ {
673
+ // not a simple argument, or argument is parenthesized and thus passed ByVal
674
+ return null ;
675
+ }
676
+
677
+ var raisedEvent = RaisedEvent ( eventArgument , module ) ;
678
+ if ( raisedEvent == null )
679
+ {
680
+ return null ;
681
+ }
682
+
683
+ var parameters = Parameters ( raisedEvent ) ;
684
+
685
+ // event arguments are always positional: work out the index
686
+ var argumentList = eventArgument . GetAncestor < VBAParser . EventArgumentListContext > ( ) ;
687
+ var arguments = argumentList . eventArgument ( ) ;
688
+
689
+ var parameterIndex = arguments
690
+ . Select ( ( arg , index ) => arg == eventArgument ? ( arg , index ) : ( null , - 1 ) )
691
+ . SingleOrDefault ( tpl => tpl . arg != null ) . index ;
692
+
693
+ var parameter = parameters
694
+ . OrderBy ( p => p . Selection )
695
+ . Select ( ( param , index ) => ( param , index ) )
696
+ . SingleOrDefault ( tpl => tpl . index == parameterIndex ) . param ;
697
+
698
+ return parameter ;
699
+ }
700
+
701
+ private EventDeclaration RaisedEvent ( VBAParser . EventArgumentContext argument , QualifiedModuleName module )
702
+ {
703
+ var raiseEventContext = argument . GetAncestor < VBAParser . RaiseEventStmtContext > ( ) ;
704
+ var eventIdentifier = raiseEventContext . identifier ( ) ;
705
+
706
+ var referencedMember = IdentifierReferences ( eventIdentifier , module )
707
+ . Select ( reference => reference . Declaration )
708
+ . OfType < EventDeclaration > ( )
709
+ . FirstOrDefault ( ) ;
710
+
711
+ return referencedMember ;
712
+ }
713
+
610
714
private string ToNormalizedName ( string name )
611
715
{
612
716
var lower = name . ToLowerInvariant ( ) ;
@@ -1253,6 +1357,16 @@ public IEnumerable<IdentifierReference> IdentifierReferences(QualifiedModuleName
1253
1357
: Enumerable . Empty < IdentifierReference > ( ) ;
1254
1358
}
1255
1359
1360
+ /// <summary>
1361
+ /// Gets all identifier references for an IdentifierContext.
1362
+ /// </summary>
1363
+ public IEnumerable < IdentifierReference > IdentifierReferences ( VBAParser . IdentifierContext identifierContext , QualifiedModuleName module )
1364
+ {
1365
+ var qualifiedSelection = new QualifiedSelection ( module , identifierContext . GetSelection ( ) ) ;
1366
+ return IdentifierReferences ( qualifiedSelection )
1367
+ . Where ( identifierReference => identifierReference . IdentifierName . Equals ( identifierContext . GetText ( ) ) ) ;
1368
+ }
1369
+
1256
1370
/// <summary>
1257
1371
/// Gets all identifier references with the specified selection.
1258
1372
/// </summary>
0 commit comments