Skip to content

Commit 0b93e50

Browse files
committed
Add new inspection for Excel UDFs hidden by cells.
1 parent 0aaf7c1 commit 0b93e50

14 files changed

+279
-179
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text.RegularExpressions;
5+
using Rubberduck.Inspections.Abstract;
6+
using Rubberduck.Inspections.Results;
7+
using Rubberduck.Parsing.Inspections;
8+
using Rubberduck.Parsing.Inspections.Abstract;
9+
using Rubberduck.Parsing.Symbols;
10+
using Rubberduck.Parsing.VBA;
11+
using Rubberduck.Resources.Inspections;
12+
13+
namespace Rubberduck.Inspections.Inspections.Concrete
14+
{
15+
[RequiredLibrary("Excel")]
16+
public class ExcelUdfNameIsValidCellReferenceInspection : InspectionBase
17+
{
18+
public ExcelUdfNameIsValidCellReferenceInspection(RubberduckParserState state) : base(state) { }
19+
20+
private static readonly Regex ValidCellIdRegex =
21+
new Regex(@"^([a-z]|[a-z]{2}|[a-w][a-z]{2}|x([a-e][a-z]|f[a-d]))(?<Row>\d+)$",
22+
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
23+
24+
private static readonly HashSet<Accessibility> VisibleAsUdf = new HashSet<Accessibility> { Accessibility.Public, Accessibility.Implicit };
25+
26+
private const uint MaximumExcelRows = 1048576;
27+
28+
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
29+
{
30+
var excel = State.DeclarationFinder.Projects.SingleOrDefault(item => !item.IsUserDefined && item.IdentifierName == "Excel");
31+
if (excel == null)
32+
{
33+
return Enumerable.Empty<IInspectionResult>();
34+
}
35+
36+
var candidates = UserDeclarations.OfType<FunctionDeclaration>().Where(decl =>
37+
decl.ParentScopeDeclaration.DeclarationType == DeclarationType.ProceduralModule &&
38+
VisibleAsUdf.Contains(decl.Accessibility));
39+
40+
return (from function in candidates.Where(decl => ValidCellIdRegex.IsMatch(decl.IdentifierName))
41+
let row = Convert.ToUInt32(ValidCellIdRegex.Matches(function.IdentifierName)[0].Groups["Row"].Value)
42+
where row > 0 && row <= MaximumExcelRows && !IsIgnoringInspectionResultFor(function, AnnotationName)
43+
select new DeclarationInspectionResult(this,
44+
string.Format(InspectionResults.ExcelUdfNameIsValidCellReferenceInspection, function.IdentifierName),
45+
function))
46+
.Cast<IInspectionResult>().ToList();
47+
}
48+
}
49+
}

Rubberduck.CodeAnalysis/QuickFixes/RenameDeclarationQuickFix.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Globalization;
22
using Rubberduck.Inspections.Abstract;
33
using Rubberduck.Inspections.Concrete;
4+
using Rubberduck.Inspections.Inspections.Concrete;
45
using Rubberduck.Interaction;
56
using Rubberduck.Parsing.Inspections.Abstract;
67
using Rubberduck.Parsing.VBA;
@@ -18,7 +19,10 @@ public sealed class RenameDeclarationQuickFix : QuickFixBase
1819
private readonly IMessageBox _messageBox;
1920

2021
public RenameDeclarationQuickFix(IVBE vbe, RubberduckParserState state, IMessageBox messageBox)
21-
: base(typeof(HungarianNotationInspection), typeof(UseMeaningfulNameInspection), typeof(DefaultProjectNameInspection))
22+
: base(typeof(HungarianNotationInspection),
23+
typeof(UseMeaningfulNameInspection),
24+
typeof(DefaultProjectNameInspection),
25+
typeof(ExcelUdfNameIsValidCellReferenceInspection))
2226
{
2327
_vbe = vbe;
2428
_state = state;

Rubberduck.Core/Properties/Settings.settings

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -268,26 +268,13 @@
268268
</Setting>
269269
<Setting Name="AutoCompleteSettings" Type="Rubberduck.Settings.AutoCompleteSettings" Scope="Application">
270270
<Value Profile="(Default)">&lt;?xml version="1.0" encoding="utf-16"?&gt;
271-
&lt;AutoCompleteSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IsEnabled="false" CompleteBlockOnTab="true" CompleteBlockOnEnter="true" EnableSmartConcat="true"&gt;
272-
&lt;AutoCompletes&gt;
273-
&lt;AutoComplete Key="AutoCompleteClosingBrace" IsEnabled="true" /&gt;
274-
&lt;AutoComplete Key="AutoCompleteClosingBracket" IsEnabled="true" /&gt;
275-
&lt;AutoComplete Key="AutoCompleteClosingParenthese" IsEnabled="true" /&gt;
276-
&lt;AutoComplete Key="AutoCompleteClosingString" IsEnabled="true" /&gt;
277-
&lt;AutoComplete Key="AutoCompleteDoBlock" IsEnabled="true" /&gt;
278-
&lt;AutoComplete Key="AutoCompleteEnumBlock" IsEnabled="true" /&gt;
279-
&lt;AutoComplete Key="AutoCompleteForBlock" IsEnabled="true" /&gt;
280-
&lt;AutoComplete Key="AutoCompleteFunctionBlock" IsEnabled="true" /&gt;
281-
&lt;AutoComplete Key="AutoCompleteIfBlock" IsEnabled="true" /&gt;
282-
&lt;AutoComplete Key="AutoCompleteOnErrorResumeNextBlock" IsEnabled="true" /&gt;
283-
&lt;AutoComplete Key="AutoCompletePrecompilerIfBlock" IsEnabled="true" /&gt;
284-
&lt;AutoComplete Key="AutoCompletePropertyBlock" IsEnabled="true" /&gt;
285-
&lt;AutoComplete Key="AutoCompleteSelectBlock" IsEnabled="true" /&gt;
286-
&lt;AutoComplete Key="AutoCompleteSubBlock" IsEnabled="true" /&gt;
287-
&lt;AutoComplete Key="AutoCompleteTypeBlock" IsEnabled="true" /&gt;
288-
&lt;AutoComplete Key="AutoCompleteWhileBlock" IsEnabled="true" /&gt;
289-
&lt;AutoComplete Key="AutoCompleteWithBlock" IsEnabled="true" /&gt;
290-
&lt;/AutoCompletes&gt;
271+
&lt;AutoCompleteSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IsEnabled="false"&gt;
272+
&lt;SmartConcat&gt;
273+
&lt;IsEnabled&gt;false&lt;/IsEnabled&gt;
274+
&lt;ConcatVbNewLineModifier&gt;None&lt;/ConcatVbNewLineModifier&gt;
275+
&lt;/SmartConcat&gt;
276+
&lt;SelfClosingPairs IsEnabled="false" /&gt;
277+
&lt;BlockCompletion IsEnabled="false" CompleteOnEnter="false" CompleteOnTab="false" /&gt;
291278
&lt;/AutoCompleteSettings&gt;</Value>
292279
</Setting>
293280
</Settings>

Rubberduck.Core/app.config

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -395,27 +395,13 @@
395395
<setting name="AutoCompleteSettings" serializeAs="Xml">
396396
<value>
397397
<AutoCompleteSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
398-
xmlns:xsd="http://www.w3.org/2001/XMLSchema" IsEnabled="false"
399-
CompleteBlockOnTab="true" CompleteBlockOnEnter="true" EnableSmartConcat="true">
400-
<AutoCompletes>
401-
<AutoComplete Key="AutoCompleteClosingBrace" IsEnabled="true" />
402-
<AutoComplete Key="AutoCompleteClosingBracket" IsEnabled="true" />
403-
<AutoComplete Key="AutoCompleteClosingParenthese" IsEnabled="true" />
404-
<AutoComplete Key="AutoCompleteClosingString" IsEnabled="true" />
405-
<AutoComplete Key="AutoCompleteDoBlock" IsEnabled="true" />
406-
<AutoComplete Key="AutoCompleteEnumBlock" IsEnabled="true" />
407-
<AutoComplete Key="AutoCompleteForBlock" IsEnabled="true" />
408-
<AutoComplete Key="AutoCompleteFunctionBlock" IsEnabled="true" />
409-
<AutoComplete Key="AutoCompleteIfBlock" IsEnabled="true" />
410-
<AutoComplete Key="AutoCompleteOnErrorResumeNextBlock" IsEnabled="true" />
411-
<AutoComplete Key="AutoCompletePrecompilerIfBlock" IsEnabled="true" />
412-
<AutoComplete Key="AutoCompletePropertyBlock" IsEnabled="true" />
413-
<AutoComplete Key="AutoCompleteSelectBlock" IsEnabled="true" />
414-
<AutoComplete Key="AutoCompleteSubBlock" IsEnabled="true" />
415-
<AutoComplete Key="AutoCompleteTypeBlock" IsEnabled="true" />
416-
<AutoComplete Key="AutoCompleteWhileBlock" IsEnabled="true" />
417-
<AutoComplete Key="AutoCompleteWithBlock" IsEnabled="true" />
418-
</AutoCompletes>
398+
xmlns:xsd="http://www.w3.org/2001/XMLSchema" IsEnabled="false">
399+
<SmartConcat>
400+
<IsEnabled>false</IsEnabled>
401+
<ConcatVbNewLineModifier>None</ConcatVbNewLineModifier>
402+
</SmartConcat>
403+
<SelfClosingPairs IsEnabled="false" />
404+
<BlockCompletion IsEnabled="false" CompleteOnEnter="false" CompleteOnTab="false" />
419405
</AutoCompleteSettings>
420406
</value>
421407
</setting>

Rubberduck.Resources/Inspections/InspectionInfo.Designer.cs

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

Rubberduck.Resources/Inspections/InspectionInfo.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,4 +349,7 @@ If the parameter can be null, ignore this inspection result; passing a null valu
349349
<data name="AssignmentNotUsedInspection" xml:space="preserve">
350350
<value>An assignment is immediately overridden by another assignment or is never referenced.</value>
351351
</data>
352+
<data name="ExcelUdfNameIsValidCellReferenceInspection" xml:space="preserve">
353+
<value>Functions that are visible to Excel as User-Defined Functions will return a '#REF' error when used on a Worksheet if they match the name of a valid cell reference. If the function is intended to be used as a UDF, it must be renamed. If the function is not intended to be used as a UDF, it should be scoped as 'Private' or moved out of a standard Module.</value>
354+
</data>
352355
</root>

Rubberduck.Resources/Inspections/InspectionNames.Designer.cs

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

Rubberduck.Resources/Inspections/InspectionNames.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,4 +348,7 @@
348348
<data name="AssignmentNotUsedInspection" xml:space="preserve">
349349
<value>Assignment is not used</value>
350350
</data>
351+
<data name="ExcelUdfNameIsValidCellReferenceInspection" xml:space="preserve">
352+
<value>Function is hidden by Excel cell reference</value>
353+
</data>
351354
</root>

Rubberduck.Resources/Inspections/InspectionResults.Designer.cs

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

Rubberduck.Resources/Inspections/InspectionResults.resx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,4 +378,8 @@
378378
<data name="AssignmentNotUsedInspection" xml:space="preserve">
379379
<value>An assignment is immediately overridden by another assignment or is never referenced.</value>
380380
</data>
381+
<data name="ExcelUdfNameIsValidCellReferenceInspection" xml:space="preserve">
382+
<value>'{0}' is hidden by a valid Excel cell reference.</value>
383+
<comment>{0} Function name</comment>
384+
</data>
381385
</root>

0 commit comments

Comments
 (0)