Skip to content

Commit bcce32a

Browse files
committed
Merge branch 'next' of git://github.com/rubberduck-vba/Rubberduck into translate252
2 parents 013f2ea + a1f784d commit bcce32a

31 files changed

+307
-96
lines changed

Rubberduck.CodeAnalysis/Inspections/Abstract/IdentifierReferenceInspectionFromDeclarationsBase.cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System.Collections.Generic;
22
using System.Linq;
33
using Rubberduck.CodeAnalysis.Inspections.Results;
4+
using Rubberduck.Parsing;
5+
using Rubberduck.Parsing.Grammar;
46
using Rubberduck.Parsing.Symbols;
57
using Rubberduck.Parsing.VBA;
68
using Rubberduck.Parsing.VBA.DeclarationCaching;
@@ -19,6 +21,74 @@ protected IdentifierReferenceInspectionFromDeclarationsBase(IDeclarationFinderPr
1921

2022
protected virtual ICollection<string> DisabledQuickFixes(IdentifierReference reference) => new List<string>();
2123

24+
/// <summary>
25+
/// Gets the possible <see cref="Declaration"/> that qualifies an identifier reference in a member access expression.
26+
/// </summary>
27+
protected IEnumerable<Declaration> GetQualifierCandidates(IdentifierReference reference, DeclarationFinder finder)
28+
{
29+
if (reference.Context.TryGetAncestor<VBAParser.MemberAccessExprContext>(out var memberAccess))
30+
{
31+
var parentModule = Declaration.GetModuleParent(reference.ParentScoping);
32+
var qualifyingExpression = memberAccess.lExpression();
33+
if (qualifyingExpression is VBAParser.SimpleNameExprContext simpleName)
34+
{
35+
if (simpleName.GetText().Equals(Tokens.Me, System.StringComparison.InvariantCultureIgnoreCase))
36+
{
37+
// qualifier is 'Me'
38+
return new[] { parentModule };
39+
}
40+
41+
// todo get the actual qualifying declaration?
42+
return finder.MatchName(simpleName.GetText())
43+
.Where(candidate => !candidate.IdentifierName.Equals(reference.Declaration.IdentifierName, System.StringComparison.InvariantCultureIgnoreCase));
44+
}
45+
46+
if (qualifyingExpression.ChildCount == 1 && qualifyingExpression.GetText().Equals(Tokens.Me, System.StringComparison.InvariantCultureIgnoreCase))
47+
{
48+
// qualifier is 'Me'
49+
return new[] { parentModule };
50+
}
51+
}
52+
53+
if (reference.Context.TryGetAncestor<VBAParser.WithMemberAccessExprContext>(out var dot))
54+
{
55+
// qualifier is a With block
56+
var withBlock = dot.GetAncestor<VBAParser.WithStmtContext>();
57+
return finder.ContainedIdentifierReferences(new QualifiedSelection(reference.QualifiedModuleName, withBlock.GetSelection()))
58+
.Select(r => r.Declaration).Distinct()
59+
.Where(candidate => !candidate.Equals(reference.Declaration));
60+
}
61+
62+
if (reference.Context.TryGetAncestor<VBAParser.CallStmtContext>(out var callStmt))
63+
{
64+
if (reference.Context.TryGetAncestor<VBAParser.LExpressionContext>(out var lExpression))
65+
{
66+
// reference is in lexpression of a call statement
67+
68+
if (lExpression is VBAParser.MemberAccessExprContext member)
69+
{
70+
if (member.lExpression() is VBAParser.SimpleNameExprContext name)
71+
{
72+
if (reference.IdentifierName.Equals(name.identifier().GetText(), System.StringComparison.InvariantCultureIgnoreCase))
73+
{
74+
// unqualified
75+
return Enumerable.Empty<Declaration>();
76+
}
77+
78+
return finder.MatchName(name.identifier().GetText())
79+
.Where(candidate => !candidate.Equals(reference.Declaration));
80+
}
81+
82+
// todo get the actual qualifying declaration?
83+
return finder.MatchName(member.lExpression().children.First().GetText())
84+
.Where(candidate => !candidate.Equals(reference.Declaration));
85+
}
86+
}
87+
}
88+
89+
return Enumerable.Empty<Declaration>();
90+
}
91+
2292
protected override IEnumerable<IInspectionResult> DoGetInspectionResults(DeclarationFinder finder)
2393
{
2494
var objectionableReferences = ObjectionableReferences(finder);

Rubberduck.CodeAnalysis/Inspections/Abstract/ImplicitSheetReferenceInspectionBase.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ public ImplicitSheetReferenceInspectionBase(IDeclarationFinderProvider declarati
1414

1515
protected override IEnumerable<Declaration> ObjectionableDeclarations(DeclarationFinder finder)
1616
{
17-
var excel = finder.Projects
18-
.SingleOrDefault(item => !item.IsUserDefined
19-
&& item.IdentifierName == "Excel");
17+
var excel = finder.Projects.SingleOrDefault(item => !item.IsUserDefined && item.IdentifierName == "Excel");
2018
if (excel == null)
2119
{
2220
return Enumerable.Empty<Declaration>();
@@ -26,7 +24,6 @@ protected override IEnumerable<Declaration> ObjectionableDeclarations(Declaratio
2624
.Select(className => finder.FindClassModule(className, excel, true))
2725
.OfType<ModuleDeclaration>();
2826

29-
3027
return globalModules
3128
.SelectMany(moduleClass => moduleClass.Members)
3229
.Where(declaration => TargetMemberNames.Contains(declaration.IdentifierName)

Rubberduck.CodeAnalysis/Inspections/Abstract/ImplicitWorkbookReferenceInspectionBase.cs

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,50 @@ internal ImplicitWorkbookReferenceInspectionBase(IDeclarationFinderProvider decl
1212
: base(declarationFinderProvider)
1313
{ }
1414

15-
private static readonly string[] InterestingMembers =
15+
protected virtual string[] InterestingMembers => new[]
1616
{
1717
"Worksheets", "Sheets", "Names"
1818
};
1919

20-
private static readonly string[] InterestingClasses =
20+
protected virtual string[] InterestingClasses => new[]
2121
{
22-
"_Global", "_Application", "Global", "Application"
22+
"_Global", "_Application", "Global", "Application", "_Workbook", "Workbook"
2323
};
2424

25+
private IReadOnlyList<ModuleDeclaration> _relevantClasses;
26+
private IReadOnlyList<PropertyGetDeclaration> _relevantProperties;
27+
28+
protected Declaration Excel { get; private set; }
29+
2530
protected override IEnumerable<Declaration> ObjectionableDeclarations(DeclarationFinder finder)
2631
{
27-
if (!finder.TryFindProjectDeclaration("Excel", out var excel))
32+
if (Excel == null)
2833
{
29-
return Enumerable.Empty<Declaration>();
34+
if (!finder.TryFindProjectDeclaration("Excel", out var excel))
35+
{
36+
return Enumerable.Empty<Declaration>();
37+
}
38+
Excel = excel;
3039
}
3140

32-
var relevantClasses = InterestingClasses
33-
.Select(className => finder.FindClassModule(className, excel, true))
34-
.OfType<ModuleDeclaration>();
41+
if (_relevantClasses == null)
42+
{
43+
_relevantClasses = InterestingClasses
44+
.Select(className => finder.FindClassModule(className, Excel, true))
45+
.OfType<ModuleDeclaration>()
46+
.ToList();
47+
}
3548

36-
var relevantProperties = relevantClasses
37-
.SelectMany(classDeclaration => classDeclaration.Members)
38-
.OfType<PropertyGetDeclaration>()
39-
.Where(member => InterestingMembers.Contains(member.IdentifierName));
49+
if (_relevantProperties == null)
50+
{
51+
_relevantProperties = _relevantClasses
52+
.SelectMany(classDeclaration => classDeclaration.Members)
53+
.OfType<PropertyGetDeclaration>()
54+
.Where(member => InterestingMembers.Contains(member.IdentifierName))
55+
.ToList();
56+
}
4057

41-
return relevantProperties;
58+
return _relevantProperties;
4259
}
4360
}
4461
}

Rubberduck.CodeAnalysis/Inspections/Concrete/ImplicitActiveSheetReferenceInspection.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,8 @@ public ImplicitActiveSheetReferenceInspection(IDeclarationFinderProvider declara
5151

5252
protected override bool IsResultReference(IdentifierReference reference, DeclarationFinder finder)
5353
{
54-
var result = !(Declaration.GetModuleParent(reference.ParentNonScoping) is DocumentModuleDeclaration document)
54+
return !(Declaration.GetModuleParent(reference.ParentNonScoping) is DocumentModuleDeclaration document)
5555
|| !document.SupertypeNames.Contains("Worksheet");
56-
return result;
5756
}
5857

5958
protected override string ResultDescription(IdentifierReference reference)

Rubberduck.CodeAnalysis/Inspections/Concrete/ImplicitActiveWorkbookReferenceInspection.cs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,48 @@ namespace Rubberduck.CodeAnalysis.Inspections.Concrete
4343
internal sealed class ImplicitActiveWorkbookReferenceInspection : ImplicitWorkbookReferenceInspectionBase
4444
{
4545
public ImplicitActiveWorkbookReferenceInspection(IDeclarationFinderProvider declarationFinderProvider)
46-
: base(declarationFinderProvider)
47-
{}
46+
: base(declarationFinderProvider) { }
4847

49-
private static readonly List<string> _alwaysActiveWorkbookReferenceParents = new List<string>
50-
{
51-
"_Application", "Application"
52-
};
48+
private IReadOnlyList<Declaration> _applicationCandidates;
5349

5450
protected override bool IsResultReference(IdentifierReference reference, DeclarationFinder finder)
5551
{
56-
return !(Declaration.GetModuleParent(reference.ParentNonScoping) is DocumentModuleDeclaration document)
57-
|| !document.SupertypeNames.Contains("Workbook")
58-
|| _alwaysActiveWorkbookReferenceParents.Contains(reference.Declaration.ParentDeclaration.IdentifierName);
52+
var qualifiers = base.GetQualifierCandidates(reference, finder);
53+
var isQualified = qualifiers.Any();
54+
var document = Declaration.GetModuleParent(reference.ParentNonScoping) as DocumentModuleDeclaration;
55+
56+
var isHostWorkbook = (document?.SupertypeNames.Contains("Workbook") ?? false)
57+
&& (document?.ProjectId?.Equals(reference.QualifiedModuleName.ProjectId) ?? false);
58+
59+
if (!isQualified)
60+
{
61+
// unqualified calls aren't referring to ActiveWorkbook only inside a Workbook module:
62+
return !isHostWorkbook;
63+
}
64+
else
65+
{
66+
if (_applicationCandidates == null)
67+
{
68+
var applicationClass = finder.FindClassModule("Application", base.Excel, includeBuiltIn: true);
69+
// note: underscored declarations would be for unqualified calls
70+
var workbookClass = finder.FindClassModule("Workbook", base.Excel, includeBuiltIn: true);
71+
var worksheetClass = finder.FindClassModule("Worksheet", base.Excel, includeBuiltIn: true);
72+
var hostBook = finder.UserDeclarations(DeclarationType.Document)
73+
.Cast<DocumentModuleDeclaration>()
74+
.SingleOrDefault(doc => doc.ProjectId.Equals(reference.QualifiedModuleName.ProjectId)
75+
&& doc.SupertypeNames.Contains("Workbook"));
76+
77+
_applicationCandidates = finder.MatchName("Application")
78+
.Where(m => m.Equals(applicationClass)
79+
|| (m.ParentDeclaration.Equals(workbookClass) && m.DeclarationType.HasFlag(DeclarationType.PropertyGet))
80+
|| (m.ParentDeclaration.Equals(worksheetClass) && m.DeclarationType.HasFlag(DeclarationType.PropertyGet))
81+
|| (m.ParentDeclaration.Equals(hostBook) && m.DeclarationType.HasFlag(DeclarationType.PropertyGet)))
82+
.ToList();
83+
}
84+
85+
// qualified calls are referring to ActiveWorkbook if qualifier is the Application object:
86+
return _applicationCandidates.Any(candidate => qualifiers.Any(q => q.Equals(candidate)));
87+
}
5988
}
6089

6190
protected override string ResultDescription(IdentifierReference reference)

Rubberduck.CodeAnalysis/Inspections/Concrete/ImplicitContainingWorkbookReferenceInspection.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
using System.Collections.Generic;
22
using System.Linq;
3+
using Antlr4.Runtime;
34
using Rubberduck.CodeAnalysis.Inspections.Abstract;
45
using Rubberduck.CodeAnalysis.Inspections.Attributes;
6+
using Rubberduck.Parsing;
7+
using Rubberduck.Parsing.Grammar;
58
using Rubberduck.Parsing.Symbols;
69
using Rubberduck.Parsing.VBA;
710
using Rubberduck.Parsing.VBA.DeclarationCaching;
@@ -44,21 +47,24 @@ public ImplicitContainingWorkbookReferenceInspection(IDeclarationFinderProvider
4447
: base(declarationFinderProvider)
4548
{ }
4649

47-
private static readonly List<string> _alwaysActiveWorkbookReferenceParents = new List<string>
50+
private static readonly string[] ParentsNeverReferringToContainingWorkbook = new[]
4851
{
49-
"_Application", "Application"
52+
"Application", "_Application"
5053
};
5154

5255
protected override IEnumerable<Declaration> ObjectionableDeclarations(DeclarationFinder finder)
5356
{
5457
return base.ObjectionableDeclarations(finder)
55-
.Where(declaration => !_alwaysActiveWorkbookReferenceParents.Contains(declaration.ParentDeclaration.IdentifierName));
58+
.Where(declaration => !ParentsNeverReferringToContainingWorkbook
59+
.Any(name => declaration.ParentDeclaration.IdentifierName.Equals(name, System.StringComparison.InvariantCultureIgnoreCase)));
5660
}
5761

5862
protected override bool IsResultReference(IdentifierReference reference, DeclarationFinder finder)
5963
{
60-
return Declaration.GetModuleParent(reference.ParentNonScoping) is DocumentModuleDeclaration document
61-
&& document.SupertypeNames.Contains("Workbook");
64+
var qualifiers = base.GetQualifierCandidates(reference, finder);
65+
return Declaration.GetModuleParent(reference.ParentScoping) is DocumentModuleDeclaration document
66+
&& document.SupertypeNames.Contains("Workbook")
67+
&& !qualifiers.Any();
6268
}
6369

6470
protected override string ResultDescription(IdentifierReference reference)

Rubberduck.CodeAnalysis/Inspections/Concrete/ImplicitContainingWorksheetReferenceInspection.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Linq;
22
using Rubberduck.CodeAnalysis.Inspections.Abstract;
33
using Rubberduck.CodeAnalysis.Inspections.Attributes;
4+
using Rubberduck.Parsing;
45
using Rubberduck.Parsing.Symbols;
56
using Rubberduck.Parsing.VBA;
67
using Rubberduck.Parsing.VBA.DeclarationCaching;
@@ -46,7 +47,8 @@ public ImplicitContainingWorksheetReferenceInspection(IDeclarationFinderProvider
4647
protected override bool IsResultReference(IdentifierReference reference, DeclarationFinder finder)
4748
{
4849
return Declaration.GetModuleParent(reference.ParentNonScoping) is DocumentModuleDeclaration document
49-
&& document.SupertypeNames.Contains("Worksheet");
50+
&& document.SupertypeNames.Contains("Worksheet")
51+
&& !(reference.Context.Parent is Parsing.Grammar.VBAParser.MemberAccessExprContext); // if it's qualified, it's not an implicit reference
5052
}
5153

5254
protected override string ResultDescription(IdentifierReference reference)
13.6 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)