@@ -19,12 +19,20 @@ protected MemberAccessMayReturnNothingInspectionBase(IDeclarationFinderProvider
19
19
: base ( declarationFinderProvider )
20
20
{ }
21
21
22
+ /// <summary>
23
+ /// Members that might return Nothing
24
+ /// </summary>
25
+ /// <remarks>
26
+ /// It must not be legal to call the members unqualified. In particular, user-defined members will not be considered.
27
+ /// Moreover, this disqualifies all members on global objects.
28
+ /// </remarks>
22
29
public abstract IEnumerable < Declaration > MembersUnderTest ( DeclarationFinder finder ) ;
23
30
public abstract string ResultTemplate { get ; }
24
31
25
32
protected override IEnumerable < Declaration > ObjectionableDeclarations ( DeclarationFinder finder )
26
33
{
27
- return MembersUnderTest ( finder ) ;
34
+ //This restriction is in place because the inspection currently cannot handle unqualified accesses.
35
+ return MembersUnderTest ( finder ) . Where ( member => ! member . IsUserDefined ) ;
28
36
}
29
37
30
38
protected override bool IsResultReference ( IdentifierReference reference , DeclarationFinder finder )
@@ -46,7 +54,7 @@ protected override bool IsResultReference(IdentifierReference reference, Declara
46
54
{
47
55
return usageContext is VBAParser . MemberAccessExprContext
48
56
|| ! ( usageContext is VBAParser . CallStmtContext )
49
- && ! ContextIsNothingTest ( usageContext ) ;
57
+ && ! ContextIsNothing ( usageContext ) ;
50
58
}
51
59
52
60
var assignedTo = AssignmentTarget ( reference , finder , setter ) ;
@@ -65,14 +73,21 @@ private static IdentifierReference AssignmentTarget(IdentifierReference referenc
65
73
66
74
private static RuleContext UsageContext ( IdentifierReference reference )
67
75
{
68
- var access = reference . Context . GetAncestor < VBAParser . MemberAccessExprContext > ( ) ;
69
- var usageContext = access . Parent is VBAParser . IndexExprContext indexExpr
76
+ //We prefer the with member access over the member access, because the accesses are resolved right to left.
77
+ var access = reference . Context . GetAncestor < VBAParser . WithMemberAccessExprContext > ( ) as VBAParser . LExpressionContext
78
+ ?? reference . Context . GetAncestor < VBAParser . MemberAccessExprContext > ( ) ;
79
+
80
+ if ( access == null )
81
+ {
82
+ return null ;
83
+ }
84
+
85
+ return access . Parent is VBAParser . IndexExprContext indexExpr
70
86
? indexExpr . Parent
71
87
: access . Parent ;
72
- return usageContext ;
73
88
}
74
89
75
- private static bool ContextIsNothingTest ( IParseTree context )
90
+ private static bool ContextIsNothing ( IParseTree context )
76
91
{
77
92
return context is VBAParser . LExprContext
78
93
&& context . Parent is VBAParser . RelationalOpContext comparison
@@ -86,7 +101,7 @@ private static bool IsUsedBeforeCheckingForNothing(IdentifierReference assignedT
86
101
var firstUse = GetReferenceNodes ( tree ) . FirstOrDefault ( ) ;
87
102
88
103
return ! ( firstUse is null )
89
- && ! ContextIsNothingTest ( firstUse . Reference . Context . Parent ) ;
104
+ && ! ContextIsNothing ( firstUse . Reference . Context . Parent ) ;
90
105
}
91
106
92
107
private static IEnumerable < INode > GetReferenceNodes ( INode node )
0 commit comments