Skip to content

Commit dc7b5eb

Browse files
committed
Merge remote-tracking branch 'blessed/next' into csproj-format-update
2 parents 1715c4b + de6f994 commit dc7b5eb

File tree

66 files changed

+2781
-1282
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+2781
-1282
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+
"VBA6.DLL;VBA.Information.IsMissing"
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/Abstract/QuickFixBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Rubberduck.Inspections.Abstract
1010
{
1111
public abstract class QuickFixBase : IQuickFix
1212
{
13-
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
13+
protected readonly ILogger Logger = LogManager.GetCurrentClassLogger();
1414
private HashSet<Type> _supportedInspections;
1515
public IReadOnlyCollection<Type> SupportedInspections => _supportedInspections.ToList();
1616

@@ -27,7 +27,7 @@ public void RegisterInspections(params Type[] inspections)
2727
throw new ArgumentException($"Parameters must implement {nameof(IInspection)}", nameof(inspections));
2828
#else
2929
inspections.Where(s => s.GetInterfaces().All(i => i != typeof(IInspection))).ToList()
30-
.ForEach(i => _logger.Error($"Type {i.Name} does not implement {nameof(IInspection)}"));
30+
.ForEach(i => Logger.Error($"Type {i.Name} does not implement {nameof(IInspection)}"));
3131
#endif
3232
}
3333

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 System.Linq;
3+
using Rubberduck.Inspections.Inspections.Abstract;
4+
using Rubberduck.Inspections.Results;
5+
using Rubberduck.Parsing.Grammar;
6+
using Rubberduck.Parsing.Inspections.Abstract;
7+
using Rubberduck.Parsing.VBA;
8+
using Rubberduck.Resources.Inspections;
9+
10+
namespace Rubberduck.Inspections.Concrete
11+
{
12+
public class IsMissingOnInappropriateArgumentInspection : IsMissingInspectionBase
13+
{
14+
public IsMissingOnInappropriateArgumentInspection(RubberduckParserState state)
15+
: base(state) { }
16+
17+
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
18+
{
19+
var results = new List<IInspectionResult>();
20+
21+
foreach (var reference in IsMissingDeclarations.SelectMany(decl => decl.References.Where(candidate => !IsIgnoringInspectionResultFor(candidate, AnnotationName))))
22+
{
23+
var parameter = GetParameterForReference(reference);
24+
25+
if (parameter == null ||
26+
parameter.IsOptional
27+
&& parameter.AsTypeName.Equals(Tokens.Variant)
28+
&& string.IsNullOrEmpty(parameter.DefaultValue)
29+
&& !parameter.IsArray)
30+
{
31+
continue;
32+
}
33+
34+
results.Add(new IdentifierReferenceInspectionResult(this, InspectionResults.IsMissingOnInappropriateArgumentInspection, State, reference, parameter));
35+
}
36+
37+
return results;
38+
}
39+
}
40+
}
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+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Rubberduck.Inspections.Abstract;
5+
using Rubberduck.Inspections.Concrete;
6+
using Rubberduck.Parsing;
7+
using Rubberduck.Parsing.Grammar;
8+
using Rubberduck.Parsing.Inspections.Abstract;
9+
using Rubberduck.Parsing.Symbols;
10+
using Rubberduck.Parsing.VBA;
11+
12+
namespace Rubberduck.Inspections.QuickFixes
13+
{
14+
public class IsMissingOnInappropriateArgumentQuickFix : QuickFixBase
15+
{
16+
private readonly RubberduckParserState _state;
17+
18+
public IsMissingOnInappropriateArgumentQuickFix(RubberduckParserState state)
19+
: base(typeof(IsMissingOnInappropriateArgumentInspection))
20+
{
21+
_state = state;
22+
}
23+
24+
public override void Fix(IInspectionResult result)
25+
{
26+
if (!(result.Properties is ParameterDeclaration parameter))
27+
{
28+
Logger.Trace(
29+
$"Properties for IsMissingOnInappropriateArgumentQuickFix was {(result.Properties == null ? "null" : "not a ParameterDeclaration")}.");
30+
return;
31+
}
32+
33+
var rewriter = _state.GetRewriter(result.QualifiedSelection.QualifiedName);
34+
if (!result.Context.TryGetAncestor<VBAParser.LExprContext>(out var context))
35+
{
36+
Logger.Trace("IsMissingOnInappropriateArgumentQuickFix could not locate containing LExprContext for replacement.");
37+
return;
38+
}
39+
40+
if (parameter.IsParamArray || parameter.IsArray)
41+
{
42+
rewriter.Replace(context, $"{Tokens.LBound}({parameter.IdentifierName}) > {Tokens.UBound}({parameter.IdentifierName})");
43+
return;
44+
}
45+
46+
if (!string.IsNullOrEmpty(parameter.DefaultValue))
47+
{
48+
if (parameter.DefaultValue.Equals("\"\""))
49+
{
50+
rewriter.Replace(context, $"{parameter.IdentifierName} = {Tokens.vbNullString}");
51+
}
52+
else if (parameter.DefaultValue.Equals(Tokens.Nothing, StringComparison.InvariantCultureIgnoreCase))
53+
{
54+
rewriter.Replace(context, $"{parameter.IdentifierName} Is {Tokens.Nothing}");
55+
}
56+
else
57+
{
58+
rewriter.Replace(context, $"{parameter.IdentifierName} = {parameter.DefaultValue}");
59+
}
60+
return;
61+
}
62+
rewriter.Replace(context, UninitializedComparisonForParameter(parameter));
63+
}
64+
65+
private static readonly Dictionary<string, string> BaseTypeUninitializedValues = new Dictionary<string, string>
66+
{
67+
{ Tokens.Boolean.ToUpper(), Tokens.False },
68+
{ Tokens.Byte.ToUpper(), "0" },
69+
{ Tokens.Currency.ToUpper(), "0" },
70+
{ Tokens.Date.ToUpper(), "CDate(0)" },
71+
{ Tokens.Decimal.ToUpper(), "0" },
72+
{ Tokens.Double.ToUpper(), "0" },
73+
{ Tokens.Integer.ToUpper(), "0" },
74+
{ Tokens.Long.ToUpper(), "0" },
75+
{ Tokens.LongLong.ToUpper(), "0" },
76+
{ Tokens.LongPtr.ToUpper(), "0" },
77+
{ Tokens.Single.ToUpper(), "0" },
78+
{ Tokens.String.ToUpper(), Tokens.vbNullString }
79+
};
80+
81+
private string UninitializedComparisonForParameter(ParameterDeclaration parameter)
82+
{
83+
var type = parameter.AsTypeName?.ToUpper() ?? string.Empty;
84+
if (string.IsNullOrEmpty(type))
85+
{
86+
type = parameter.HasTypeHint
87+
? SymbolList.TypeHintToTypeName[parameter.TypeHint].ToUpper()
88+
: Tokens.Variant.ToUpper();
89+
}
90+
91+
if (BaseTypeUninitializedValues.ContainsKey(type))
92+
{
93+
return $"{parameter.IdentifierName} = {BaseTypeUninitializedValues[type]}";
94+
}
95+
96+
if (type.Equals(Tokens.Object, StringComparison.InvariantCultureIgnoreCase))
97+
{
98+
return $"{parameter.IdentifierName} Is {Tokens.Nothing}";
99+
}
100+
101+
if (type.Equals(Tokens.Object, StringComparison.InvariantCultureIgnoreCase) || parameter.AsTypeDeclaration == null)
102+
{
103+
return $"IsEmpty({parameter.IdentifierName})";
104+
}
105+
106+
switch (parameter.AsTypeDeclaration.DeclarationType)
107+
{
108+
case DeclarationType.ClassModule:
109+
return $"{parameter.IdentifierName} Is {Tokens.Nothing}";
110+
case DeclarationType.Enumeration:
111+
var members = _state.DeclarationFinder.AllDeclarations.OfType<ValuedDeclaration>()
112+
.FirstOrDefault(decl =>
113+
ReferenceEquals(decl.ParentDeclaration, parameter.AsTypeDeclaration) &&
114+
decl.Expression.Equals("0"));
115+
return $"{parameter.IdentifierName} = {members?.IdentifierName ?? "0"}";
116+
default:
117+
return $"IsError({parameter.IdentifierName})";
118+
}
119+
}
120+
121+
public override string Description(IInspectionResult result) => Resources.Inspections.QuickFixes.IsMissingOnInappropriateArgumentQuickFix;
122+
123+
public override bool CanFixInProcedure => true;
124+
public override bool CanFixInModule => false;
125+
public override bool CanFixInProject => false;
126+
}
127+
}

Rubberduck.Core/Properties/Settings.Designer.cs

Lines changed: 8 additions & 5 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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@
281281
&lt;CodeInspection Name="DuplicatedAnnotationInspection" Severity="Error" InspectionType="RubberduckOpportunities" /&gt;
282282
&lt;CodeInspection Name="ModuleWithoutFolderInspection" Severity="Suggestion" InspectionType="RubberduckOpportunities" /&gt;
283283
&lt;CodeInspection Name="OnLocalErrorInspection" Severity="Suggestion" InspectionType="LanguageOpportunities" /&gt;
284+
&lt;CodeInspection Name="IsMissingOnInappropriateArgumentInspection" Severity="Warning" InspectionType="CodeQualityIssues" /&gt;
285+
&lt;CodeInspection Name="IsMissingWithNonArgumentParameterInspection" Severity="Warning" InspectionType="CodeQualityIssues" /&gt;
284286
&lt;CodeInspection Name="AssignmentNotUsedInspection" Severity="Suggestion" InspectionType="CodeQualityIssues" /&gt;
285287
&lt;/CodeInspections&gt;
286288
&lt;WhitelistedIdentifiers /&gt;

0 commit comments

Comments
 (0)