Skip to content

Commit 7dbac24

Browse files
committed
Implement ApplicationWorksheetFunctionInspection.
1 parent 4343e99 commit 7dbac24

8 files changed

+619
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Rubberduck.Inspections.Abstract;
4+
using Rubberduck.Inspections.Resources;
5+
using Rubberduck.Inspections.Results;
6+
using Rubberduck.Parsing.Symbols;
7+
using Rubberduck.Parsing.VBA;
8+
using Rubberduck.VBEditor;
9+
10+
namespace Rubberduck.Inspections
11+
{
12+
public class ApplicationWorksheetFunctionInspection : InspectionBase
13+
{
14+
public ApplicationWorksheetFunctionInspection(RubberduckParserState state)
15+
: base(state, CodeInspectionSeverity.Suggestion)
16+
{ }
17+
18+
public override string Meta { get { return InspectionsUI.ApplicationWorksheetFunctionInspectionMeta; } }
19+
public override string Description { get { return InspectionsUI.ApplicationWorksheetFunctionInspectionName; } }
20+
public override CodeInspectionType InspectionType { get { return CodeInspectionType.CodeQualityIssues; } }
21+
22+
public override IEnumerable<InspectionResultBase> GetInspectionResults()
23+
{
24+
var excel = State.DeclarationFinder.Projects.SingleOrDefault(item => item.IsBuiltIn && item.IdentifierName == "Excel");
25+
if (excel == null) { return Enumerable.Empty<InspectionResultBase>(); }
26+
27+
var members = new HashSet<string>(BuiltInDeclarations.Where(decl => decl.DeclarationType == DeclarationType.Function &&
28+
decl.ParentDeclaration != null &&
29+
decl.ParentDeclaration.ComponentName.Equals("WorksheetFunction"))
30+
.Select(decl => decl.IdentifierName));
31+
32+
var usages = BuiltInDeclarations.Where(decl => decl.References.Any() &&
33+
decl.ProjectName.Equals("Excel") &&
34+
decl.ComponentName.Equals("Application") &&
35+
members.Contains(decl.IdentifierName));
36+
37+
return (from usage in usages
38+
from reference in usage.References.Where(use => !IsIgnoringInspectionResultFor(use, AnnotationName))
39+
let qualifiedSelection = new QualifiedSelection(reference.QualifiedModuleName, reference.Selection)
40+
select new ApplicationWorksheetFunctionInspectionResult(this, qualifiedSelection, usage.IdentifierName));
41+
}
42+
}
43+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Antlr4.Runtime;
7+
using Rubberduck.Inspections.Abstract;
8+
using Rubberduck.Inspections.Resources;
9+
using Rubberduck.VBEditor;
10+
11+
namespace Rubberduck.Inspections.QuickFixes
12+
{
13+
public class ApplicationWorksheetFunctionQuickFix : QuickFixBase
14+
{
15+
private readonly string _memberName;
16+
17+
public ApplicationWorksheetFunctionQuickFix(QualifiedSelection selection, string memberName)
18+
: base(null, selection, InspectionsUI.ApplicationWorksheetFunctionQuickFix)
19+
{
20+
_memberName = memberName;
21+
}
22+
23+
public override bool CanFixInModule { get { return true; } }
24+
public override bool CanFixInProject { get { return true; } }
25+
26+
public override void Fix()
27+
{
28+
var module = Selection.QualifiedName.Component.CodeModule;
29+
30+
var oldContent = module.GetLines(Selection.Selection);
31+
var newCall = string.Format("WorksheetFunction.{0}", _memberName);
32+
var start = Selection.Selection.StartColumn - 1;
33+
//The member being called will always be a single token, so this will always be safe (it will be a single line).
34+
var end = Selection.Selection.EndColumn - 1;
35+
var newContent = oldContent.Substring(0, start) + newCall +
36+
(oldContent.Length > end
37+
? oldContent.Substring(end, oldContent.Length - end)
38+
: string.Empty);
39+
40+
module.DeleteLines(Selection.Selection);
41+
module.InsertLines(Selection.Selection.StartLine, newContent);
42+
}
43+
}
44+
}

RetailCoder.VBE/Inspections/Resources/InspectionsUI.Designer.cs

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RetailCoder.VBE/Inspections/Resources/InspectionsUI.resx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,4 +634,17 @@ If the parameter can be null, ignore this inspection result; passing a null valu
634634
<data name="HostSpecificExpressionInspectionResultFormat" xml:space="preserve">
635635
<value>Expression '{0}' cannot be validated at compile-time.</value>
636636
</data>
637+
<data name="ApplicationWorksheetFunctionInspectionMeta" xml:space="preserve">
638+
<value>The Excel Application object does not implement the WorksheetFunction interface directly. All calls made to WorksheetFunction members are handled as late bound and errors in the called member will be returned wrapped in a Variant of VbVarType.vbError. This makes errors un-trappable with error handlers and adds a performance penalty in comparison to early bound calls. Consider calling Application.WorksheetFunction explicitly.</value>
639+
</data>
640+
<data name="ApplicationWorksheetFunctionInspectionName" xml:space="preserve">
641+
<value>Late bound WorksheetFunction call.</value>
642+
</data>
643+
<data name="ApplicationWorksheetFunctionInspectionResultFormat" xml:space="preserve">
644+
<value>Use of late bound Application.{0} member.</value>
645+
<comment>{0} Member name</comment>
646+
</data>
647+
<data name="ApplicationWorksheetFunctionQuickFix" xml:space="preserve">
648+
<value>Use Application.WorksheetFunction explicitly.</value>
649+
</data>
637650
</root>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System.Collections.Generic;
2+
using Rubberduck.Common;
3+
using Rubberduck.Inspections.Abstract;
4+
using Rubberduck.Inspections.QuickFixes;
5+
using Rubberduck.Inspections.Resources;
6+
using Rubberduck.VBEditor;
7+
8+
namespace Rubberduck.Inspections.Results
9+
{
10+
public class ApplicationWorksheetFunctionInspectionResult : InspectionResultBase
11+
{
12+
private readonly QualifiedSelection _qualifiedSelection;
13+
private readonly string _memberName;
14+
private IEnumerable<QuickFixBase> _quickFixes;
15+
16+
public ApplicationWorksheetFunctionInspectionResult(IInspection inspection, QualifiedSelection qualifiedSelection, string memberName)
17+
: base(inspection, qualifiedSelection.QualifiedName)
18+
{
19+
_memberName = memberName;
20+
_qualifiedSelection = qualifiedSelection;
21+
}
22+
23+
public override IEnumerable<QuickFixBase> QuickFixes
24+
{
25+
get
26+
{
27+
return _quickFixes ?? (_quickFixes = new QuickFixBase[]
28+
{
29+
new IgnoreOnceQuickFix(null, _qualifiedSelection, Inspection.AnnotationName),
30+
new ApplicationWorksheetFunctionQuickFix(_qualifiedSelection, _memberName)
31+
});
32+
}
33+
}
34+
35+
public override string Description
36+
{
37+
get { return string.Format(InspectionsUI.ApplicationWorksheetFunctionInspectionResultFormat, _memberName).Captialize(); }
38+
}
39+
}
40+
}

RetailCoder.VBE/Rubberduck.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,17 +365,20 @@
365365
<Compile Include="Common\WinAPI\WM.cs" />
366366
<Compile Include="Common\WindowsOperatingSystem.cs" />
367367
<Compile Include="Common\UndocumentedAttribute.cs" />
368+
<Compile Include="Inspections\ApplicationWorksheetFunctionInspection.cs" />
368369
<Compile Include="Inspections\HostSpecificExpressionInspection.cs" />
369370
<Compile Include="Inspections\HungarianNotationInspection.cs" />
370371
<Compile Include="Inspections\ImplicitDefaultMemberAssignmentInspection.cs" />
371372
<Compile Include="Inspections\MemberNotOnInterfaceInspection.cs" />
372373
<Compile Include="Inspections\QuickFixes\AddIdentifierToWhiteListQuickFix.cs" />
374+
<Compile Include="Inspections\QuickFixes\ApplicationWorksheetFunctionQuickFix.cs" />
373375
<Compile Include="Inspections\Resources\InspectionsUI.Designer.cs">
374376
<AutoGen>True</AutoGen>
375377
<DesignTime>True</DesignTime>
376378
<DependentUpon>InspectionsUI.resx</DependentUpon>
377379
</Compile>
378380
<Compile Include="Inspections\Results\AggregateInspectionResult.cs" />
381+
<Compile Include="Inspections\Results\ApplicationWorksheetFunctionInspectionResult.cs" />
379382
<Compile Include="Inspections\Results\HostSpecificExpressionInspectionResult.cs" />
380383
<Compile Include="Inspections\Results\ImplicitDefaultMemberAssignmentInspectionResult.cs" />
381384
<Compile Include="Inspections\QuickFixes\IntroduceLocalVariableQuickFix.cs" />

0 commit comments

Comments
 (0)