Skip to content

Commit bccaf03

Browse files
authored
Merge pull request #3069 from rkapka/next
Created RedundantByRefModifier inspection
2 parents 4dcc4f2 + e5c24b6 commit bccaf03

File tree

7 files changed

+748
-0
lines changed

7 files changed

+748
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Antlr4.Runtime;
4+
using Rubberduck.Common;
5+
using Rubberduck.Inspections.Abstract;
6+
using Rubberduck.Inspections.Results;
7+
using Rubberduck.Parsing;
8+
using Rubberduck.Parsing.Grammar;
9+
using Rubberduck.Parsing.Inspections.Abstract;
10+
using Rubberduck.Parsing.Inspections.Resources;
11+
using Rubberduck.Parsing.VBA;
12+
using Rubberduck.VBEditor;
13+
14+
namespace Rubberduck.Inspections.Concrete
15+
{
16+
public sealed class RedundantByRefModifierInspection : ParseTreeInspectionBase
17+
{
18+
public RedundantByRefModifierInspection(RubberduckParserState state)
19+
: base(state, CodeInspectionSeverity.Hint)
20+
{
21+
}
22+
23+
public override CodeInspectionType InspectionType => CodeInspectionType.CodeQualityIssues;
24+
25+
public override IInspectionListener Listener { get; } = new RedundantByRefModifierListener();
26+
27+
public override IEnumerable<IInspectionResult> GetInspectionResults()
28+
{
29+
var builtInEventHandlerContexts = State.DeclarationFinder.FindEventHandlers().Select(handler => handler.Context).ToHashSet();
30+
var interfaceImplementationMemberContexts = UserDeclarations.FindInterfaceImplementationMembers().Select(member => member.Context).ToHashSet();
31+
32+
var issues = Listener.Contexts.Where(context =>
33+
!IsIgnoringInspectionResultFor(context.ModuleName, context.Context.Start.Line) &&
34+
!builtInEventHandlerContexts.Contains(context.Context.Parent.Parent) &&
35+
!interfaceImplementationMemberContexts.Contains(context.Context.Parent.Parent));
36+
37+
return issues.Select(issue =>
38+
{
39+
var identifier = ((VBAParser.ArgContext) issue.Context)
40+
.unrestrictedIdentifier()
41+
.identifier();
42+
43+
return new QualifiedContextInspectionResult(this,
44+
string.Format(InspectionsUI.RedundantByRefModifierInspectionResultFormat,
45+
identifier.untypedIdentifier() != null
46+
? identifier.untypedIdentifier().identifierValue().GetText()
47+
: identifier.typedIdentifier().untypedIdentifier().identifierValue().GetText()),
48+
State, issue);
49+
});
50+
}
51+
52+
public class RedundantByRefModifierListener : VBAParserBaseListener, IInspectionListener
53+
{
54+
private readonly List<QualifiedContext<ParserRuleContext>> _contexts = new List<QualifiedContext<ParserRuleContext>>();
55+
56+
public IReadOnlyList<QualifiedContext<ParserRuleContext>> Contexts => _contexts;
57+
58+
public QualifiedModuleName CurrentModuleName { get; set; }
59+
60+
public void ClearContexts()
61+
{
62+
_contexts.Clear();
63+
}
64+
65+
public override void ExitArg(VBAParser.ArgContext context)
66+
{
67+
if (context.BYREF() != null)
68+
{
69+
_contexts.Add(new QualifiedContext<ParserRuleContext>(CurrentModuleName, context));
70+
}
71+
}
72+
}
73+
}
74+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using System;
2+
using Rubberduck.Parsing.Grammar;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using Rubberduck.Common;
6+
using Rubberduck.Inspections.Concrete;
7+
using Rubberduck.Parsing.Inspections.Abstract;
8+
using Rubberduck.Parsing.Inspections.Resources;
9+
using Rubberduck.Parsing.Rewriter;
10+
using Rubberduck.Parsing.Symbols;
11+
using Rubberduck.Parsing.VBA;
12+
13+
namespace Rubberduck.Inspections.QuickFixes
14+
{
15+
public class RemoveExplicitByRefModifierQuickFix : IQuickFix
16+
{
17+
private readonly RubberduckParserState _state;
18+
19+
private static readonly HashSet<Type> _supportedInspections = new HashSet<Type>
20+
{
21+
typeof(RedundantByRefModifierInspection)
22+
};
23+
24+
public RemoveExplicitByRefModifierQuickFix(RubberduckParserState state)
25+
{
26+
_state = state;
27+
}
28+
29+
public IReadOnlyCollection<Type> SupportedInspections => _supportedInspections.ToList();
30+
31+
public void Fix(IInspectionResult result)
32+
{
33+
var context = (VBAParser.ArgContext) result.Context;
34+
35+
RemoveByRefIdentifier(_state.GetRewriter(result.QualifiedSelection.QualifiedName), context);
36+
37+
var interfaceMembers = _state.DeclarationFinder.FindAllInterfaceMembers().ToArray();
38+
39+
var matchingInterfaceMemberContext = interfaceMembers.Select(member => member.Context).FirstOrDefault(c => c == context.Parent.Parent);
40+
41+
if (matchingInterfaceMemberContext != null)
42+
{
43+
var interfaceParameterIndex = GetParameterIndex(context);
44+
45+
var implementationMembers =
46+
_state.AllUserDeclarations.FindInterfaceImplementationMembers(interfaceMembers.First(
47+
member => member.Context == matchingInterfaceMemberContext)).ToHashSet();
48+
49+
var parameters =
50+
_state.DeclarationFinder.UserDeclarations(DeclarationType.Parameter)
51+
.Where(p => implementationMembers.Contains(p.ParentDeclaration))
52+
.Cast<ParameterDeclaration>()
53+
.ToArray();
54+
55+
foreach (var parameter in parameters)
56+
{
57+
var parameterContext = (VBAParser.ArgContext) parameter.Context;
58+
var parameterIndex = GetParameterIndex(parameterContext);
59+
60+
if (parameterIndex == interfaceParameterIndex)
61+
{
62+
RemoveByRefIdentifier(_state.GetRewriter(parameter), parameterContext);
63+
}
64+
}
65+
}
66+
}
67+
68+
public string Description(IInspectionResult result)
69+
{
70+
return InspectionsUI.RedundantByRefModifierQuickFix;
71+
}
72+
73+
public bool CanFixInProcedure => true;
74+
public bool CanFixInModule => true;
75+
public bool CanFixInProject => true;
76+
77+
private static int GetParameterIndex(VBAParser.ArgContext context)
78+
{
79+
return Array.IndexOf(((VBAParser.ArgListContext)context.Parent).arg().ToArray(), context);
80+
}
81+
82+
private static void RemoveByRefIdentifier(IModuleRewriter rewriter, VBAParser.ArgContext context)
83+
{
84+
if (context.BYREF() != null)
85+
{
86+
rewriter.Remove(context.BYREF());
87+
rewriter.Remove(context.whiteSpace().First());
88+
}
89+
}
90+
}
91+
}

Rubberduck.Inspections/Rubberduck.Inspections.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
<Compile Include="Concrete\MissingAnnotationInspection.cs" />
7777
<Compile Include="Concrete\MissingAttributeInspection.cs" />
7878
<Compile Include="Abstract\InspectionResultBase.cs" />
79+
<Compile Include="Concrete\RedundantByRefModifierInspection.cs" />
7980
<Compile Include="Inspector.cs" />
8081
<Compile Include="Concrete\MemberNotOnInterfaceInspection.cs" />
8182
<Compile Include="Concrete\MissingAnnotationArgumentInspection.cs" />
@@ -119,6 +120,7 @@
119120
<Compile Include="QuickFixes\RemoveExplicitCallStatmentQuickFix.cs" />
120121
<Compile Include="QuickFixes\RemoveExplicitLetStatementQuickFix.cs" />
121122
<Compile Include="QuickFixes\RemoveOptionBaseStatementQuickFix.cs" />
123+
<Compile Include="QuickFixes\RemoveExplicitByRefModifierQuickFix.cs" />
122124
<Compile Include="QuickFixes\RemoveTypeHintsQuickFix.cs" />
123125
<Compile Include="QuickFixes\RemoveUnassignedIdentifierQuickFix.cs" />
124126
<Compile Include="QuickFixes\RemoveUnassignedVariableUsageQuickFix.cs" />

Rubberduck.Parsing/Inspections/Resources/InspectionsUI.resx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,4 +717,16 @@ If the parameter can be null, ignore this inspection result; passing a null valu
717717
<value>'{0}' has no effect.</value>
718718
<comment>'{0}' the whole ModuleOptionContext text</comment>
719719
</data>
720+
<data name="RedundantByRefModifierInspectionMeta" xml:space="preserve">
721+
<value>By default, all parameters are passed by reference, so it is not necessary to include the ByRef modifier declaration</value>
722+
</data>
723+
<data name="RedundantByRefModifierInspectionName" xml:space="preserve">
724+
<value>Redundant ByRef modifier</value>
725+
</data>
726+
<data name="RedundantByRefModifierInspectionResultFormat" xml:space="preserve">
727+
<value>Parameter '{0}' has a redundant ByRef modifier</value>
728+
</data>
729+
<data name="RedundantByRefModifierQuickFix" xml:space="preserve">
730+
<value>Remove redundant ByRef modifier</value>
731+
</data>
720732
</root>

Rubberduck.Parsing/Inspections/Resources/InspectionsUI1.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.

0 commit comments

Comments
 (0)