Skip to content

Commit 44b3deb

Browse files
committed
Add second part of IsMissing inpections. Closes #4212
1 parent 6d3e51e commit 44b3deb

15 files changed

+332
-35
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Antlr4.Runtime;
4+
using NLog;
5+
using Rubberduck.Inspections.Abstract;
6+
using Rubberduck.Parsing;
7+
using Rubberduck.Parsing.Grammar;
8+
using Rubberduck.Parsing.Symbols;
9+
using Rubberduck.Parsing.VBA;
10+
11+
namespace Rubberduck.Inspections.Inspections.Abstract
12+
{
13+
public abstract class IsMissingInspectionBase : InspectionBase
14+
{
15+
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
16+
17+
protected IsMissingInspectionBase(RubberduckParserState state)
18+
: base(state) { }
19+
20+
private static readonly List<string> IsMissingQualifiedNames = new List<string>
21+
{
22+
"VBE7.DLL;VBA.Information.IsMissing",
23+
// TODO find QN for VB6
24+
};
25+
26+
protected IReadOnlyList<Declaration> IsMissingDeclarations
27+
{
28+
get
29+
{
30+
var isMissing = BuiltInDeclarations.Where(decl => IsMissingQualifiedNames.Contains(decl.QualifiedName.ToString())).ToList();
31+
32+
if (isMissing.Count == 0)
33+
{
34+
_logger.Trace("No 'IsMissing' Declarations were not found in IsMissingInspectionBase.");
35+
}
36+
37+
return isMissing;
38+
}
39+
}
40+
41+
protected ParameterDeclaration GetParameterForReference(IdentifierReference reference)
42+
{
43+
// First case is for unqualified use: IsMissing(foo)
44+
// Second case if for use as a member access: VBA.IsMissing(foo)
45+
var argument = ((ParserRuleContext)reference.Context.Parent).GetDescendent<VBAParser.ArgumentExpressionContext>() ??
46+
((ParserRuleContext)reference.Context.Parent.Parent).GetDescendent<VBAParser.ArgumentExpressionContext>();
47+
48+
var name = argument?.GetDescendent<VBAParser.SimpleNameExprContext>();
49+
if (name == null || name.Parent.Parent != argument)
50+
{
51+
return null;
52+
}
53+
54+
var procedure = reference.Context.GetAncestor<VBAParser.ModuleBodyElementContext>();
55+
return UserDeclarations.Where(decl => decl is ModuleBodyElementDeclaration)
56+
.Cast<ModuleBodyElementDeclaration>()
57+
.FirstOrDefault(decl => decl.Context.Parent == procedure)?
58+
.Parameters.FirstOrDefault(param => param.IdentifierName.Equals(name.GetText()));
59+
}
60+
}
61+
}

Rubberduck.CodeAnalysis/Inspections/Concrete/IsMissingOnInappropriateArgumentInspection.cs

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,26 @@
11
using System.Collections.Generic;
22
using System.Linq;
3-
using Antlr4.Runtime;
4-
using NLog;
5-
using Rubberduck.Inspections.Abstract;
3+
using Rubberduck.Inspections.Inspections.Abstract;
64
using Rubberduck.Inspections.Results;
7-
using Rubberduck.Parsing;
85
using Rubberduck.Parsing.Grammar;
96
using Rubberduck.Parsing.Inspections.Abstract;
10-
using Rubberduck.Parsing.Symbols;
117
using Rubberduck.Parsing.VBA;
128
using Rubberduck.Resources.Inspections;
139

1410
namespace Rubberduck.Inspections.Concrete
1511
{
16-
public class IsMissingOnInappropriateArgumentInspection : InspectionBase
12+
public class IsMissingOnInappropriateArgumentInspection : IsMissingInspectionBase
1713
{
18-
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
19-
2014
public IsMissingOnInappropriateArgumentInspection(RubberduckParserState state)
2115
: base(state) { }
2216

2317
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
2418
{
25-
var isMissing = BuiltInDeclarations.SingleOrDefault(decl => decl.QualifiedName.ToString().Equals("VBE7.DLL;VBA.Information.IsMissing"));
26-
27-
if (isMissing == null)
28-
{
29-
_logger.Trace("VBA.Information.IsMissing was not found in IsMissingOnInappropriateArgumentInspection.");
30-
return Enumerable.Empty<IInspectionResult>();
31-
}
32-
3319
var results = new List<IInspectionResult>();
3420

35-
foreach (var reference in isMissing.References.Where(candidate => !IsIgnoringInspectionResultFor(candidate, AnnotationName)))
21+
foreach (var reference in IsMissingDeclarations.SelectMany(decl => decl.References.Where(candidate => !IsIgnoringInspectionResultFor(candidate, AnnotationName))))
3622
{
37-
// First case is for unqualified use: IsMissing(foo)
38-
// Second case if for use as a member access: VBA.IsMissing(foo)
39-
var argument = ((ParserRuleContext)reference.Context.Parent).GetDescendent<VBAParser.ArgumentExpressionContext>() ??
40-
((ParserRuleContext)reference.Context.Parent.Parent).GetDescendent<VBAParser.ArgumentExpressionContext>();
41-
var name = argument.GetDescendent<VBAParser.SimpleNameExprContext>();
42-
if (name.Parent.Parent != argument)
43-
{
44-
continue;
45-
}
46-
47-
var procedure = reference.Context.GetAncestor<VBAParser.ModuleBodyElementContext>();
48-
var parameter = UserDeclarations.Where(decl => decl is ModuleBodyElementDeclaration)
49-
.Cast<ModuleBodyElementDeclaration>()
50-
.FirstOrDefault(decl => decl.Context.Parent == procedure)?
51-
.Parameters.FirstOrDefault(param => param.IdentifierName.Equals(name.GetText()));
23+
var parameter = GetParameterForReference(reference);
5224

5325
if (parameter == null ||
5426
parameter.IsOptional
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Rubberduck.Inspections.Inspections.Abstract;
4+
using Rubberduck.Inspections.Results;
5+
using Rubberduck.Parsing.Inspections.Abstract;
6+
using Rubberduck.Parsing.VBA;
7+
using Rubberduck.Resources.Inspections;
8+
9+
namespace Rubberduck.Inspections.Inspections.Concrete
10+
{
11+
public class IsMissingWithNonArgumentParameterInspection : IsMissingInspectionBase
12+
{
13+
public IsMissingWithNonArgumentParameterInspection(RubberduckParserState state)
14+
: base(state) { }
15+
16+
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
17+
{
18+
var results = new List<IInspectionResult>();
19+
20+
foreach (var reference in IsMissingDeclarations.SelectMany(decl => decl.References.Where(candidate => !IsIgnoringInspectionResultFor(candidate, AnnotationName))))
21+
{
22+
var parameter = GetParameterForReference(reference);
23+
24+
if (parameter != null)
25+
{
26+
continue;
27+
}
28+
29+
results.Add(new IdentifierReferenceInspectionResult(this, InspectionResults.IsMissingWithNonArgumentParameterInspection, State, reference));
30+
}
31+
32+
return results;
33+
}
34+
}
35+
}

Rubberduck.CodeAnalysis/Rubberduck.CodeAnalysis.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
<Compile Include="CodeMetrics\LineCountMetric.cs" />
7070
<Compile Include="CodeMetrics\NestingLevelMetric.cs" />
7171
<Compile Include="Inspections\Abstract\InspectionBase.cs" />
72+
<Compile Include="Inspections\Abstract\IsMissingInspectionBase.cs" />
7273
<Compile Include="Inspections\Abstract\ParseTreeInspectionBase.cs" />
7374
<Compile Include="Inspections\Concrete\ApplicationWorksheetFunctionInspection.cs" />
7475
<Compile Include="Inspections\Concrete\AssignedByValParameterInspection.cs" />
@@ -82,6 +83,7 @@
8283
<Compile Include="Inspections\Concrete\EmptyForLoopBlockInspection.cs" />
8384
<Compile Include="Inspections\Concrete\BooleanAssignedInIfElseInspection.cs" />
8485
<Compile Include="Inspections\Concrete\IsMissingOnInappropriateArgumentInspection.cs" />
86+
<Compile Include="Inspections\Concrete\IsMissingWithNonArgumentParameterInspection.cs" />
8587
<Compile Include="Inspections\Concrete\OnLocalErrorInspection.cs" />
8688
<Compile Include="Inspections\Concrete\ModuleWithoutFolderInspection.cs" />
8789
<Compile Include="Inspections\Concrete\EmptyWhileWendBlockInspection.cs" />

Rubberduck.Core/Properties/Settings.Designer.cs

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

Rubberduck.Core/Properties/Settings.settings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@
282282
&lt;CodeInspection Name="ModuleWithoutFolderInspection" Severity="Suggestion" InspectionType="RubberduckOpportunities" /&gt;
283283
&lt;CodeInspection Name="OnLocalErrorInspection" Severity="Suggestion" InspectionType="LanguageOpportunities" /&gt;
284284
&lt;CodeInspection Name="IsMissingOnInappropriateArgumentInspection" Severity="Warning" InspectionType="CodeQualityIssues" /&gt;
285+
&lt;CodeInspection Name="IsMissingWithNonArgumentParameterInspection" Severity="Warning" InspectionType="CodeQualityIssues" /&gt;
285286
&lt;/CodeInspections&gt;
286287
&lt;WhitelistedIdentifiers /&gt;
287288
&lt;RunInspectionsOnSuccessfulParse&gt;true&lt;/RunInspectionsOnSuccessfulParse&gt;

Rubberduck.Core/app.config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,8 @@
408408
InspectionType="LanguageOpportunities" />
409409
<CodeInspection Name="IsMissingOnInappropriateArgumentInspection"
410410
Severity="Warning" InspectionType="CodeQualityIssues" />
411+
<CodeInspection Name="IsMissingWithNonArgumentParameterInspection"
412+
Severity="Warning" InspectionType="CodeQualityIssues" />
411413
</CodeInspections>
412414
<WhitelistedIdentifiers />
413415
<RunInspectionsOnSuccessfulParse>true</RunInspectionsOnSuccessfulParse>

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
@@ -343,4 +343,7 @@ If the parameter can be null, ignore this inspection result; passing a null valu
343343
<data name="IsMissingOnInappropriateArgumentInspection" xml:space="preserve">
344344
<value>IsMissing is only intended to be called on optional arguments, and will only return correct results if the type of the argument is 'Variant' with no explicit default value. All other uses will return 'False'.</value>
345345
</data>
346+
<data name="IsMissingWithNonArgumentParameterInspection" xml:space="preserve">
347+
<value>IsMissing is only intended to be called on arguments of the containing procedure, and almost all other usages will return 'False'. Passing any other expression to the function is the equivalent to 'VarType({expression}) = vbError', and in rare circumstances can cause the host application to crash.</value>
348+
</data>
346349
</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.

0 commit comments

Comments
 (0)