Skip to content

Commit ff6ba2e

Browse files
committed
Add AddMissingAttributeQuickFix
1 parent e66ed4e commit ff6ba2e

File tree

8 files changed

+245
-21
lines changed

8 files changed

+245
-21
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Rubberduck.Inspections.Abstract;
2+
using Rubberduck.Inspections.Concrete;
3+
using Rubberduck.Parsing.Annotations;
4+
using Rubberduck.Parsing.Inspections.Abstract;
5+
using Rubberduck.Parsing.Rewriter;
6+
using Rubberduck.Parsing.Symbols;
7+
using Rubberduck.Parsing.VBA;
8+
using Rubberduck.Parsing.VBA.Parsing;
9+
10+
namespace Rubberduck.Inspections.QuickFixes
11+
{
12+
public sealed class AddMissingAttributeQuickFix : QuickFixBase
13+
{
14+
private readonly IAttributesUpdater _attributesUpdater;
15+
16+
public AddMissingAttributeQuickFix(IAttributesUpdater attributesUpdater)
17+
: base(typeof(MissingAttributeInspection))
18+
{
19+
_attributesUpdater = attributesUpdater;
20+
}
21+
22+
public override void Fix(IInspectionResult result, IRewriteSession rewriteSession)
23+
{
24+
var declaration = result.Target;
25+
IAttributeAnnotation annotation = result.Properties.Annotation;
26+
27+
var attributeName = declaration.DeclarationType.HasFlag(DeclarationType.Module)
28+
? annotation.Attribute
29+
: $"{declaration.IdentifierName}.{annotation.Attribute}";
30+
31+
_attributesUpdater.AddAttribute(rewriteSession, declaration, attributeName, annotation.AttributeValues);
32+
}
33+
34+
public override string Description(IInspectionResult result) => Resources.Inspections.QuickFixes.AddMissingAttributeQuickFix;
35+
36+
public override CodeKind TargetCodeKind => CodeKind.AttributesCode;
37+
38+
public override bool CanFixInProcedure => true;
39+
public override bool CanFixInModule => true;
40+
public override bool CanFixInProject => true;
41+
}
42+
}

Rubberduck.Parsing/VBA/AttributesUpdater.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ public void AddAttribute(IRewriteSession rewriteSession, Declaration declaration
5151
return;
5252
}
5353

54-
var codeToInsert = $"{Environment.NewLine}Attribute {attribute} ={AttributeValuesText(values)}";
55-
5654
var rewriter = rewriteSession.CheckOutModuleRewriter(declaration.QualifiedModuleName);
5755
if (declaration.DeclarationType.HasFlag(DeclarationType.Module))
5856
{
@@ -61,11 +59,22 @@ public void AddAttribute(IRewriteSession rewriteSession, Declaration declaration
6159
.Where(moduleAttributes => moduleAttributes.attributeStmt() != null)
6260
.SelectMany(moduleAttributes => moduleAttributes.attributeStmt())
6361
.OrderBy(moduleAttribute => moduleAttribute.stop.TokenIndex)
64-
.Last();
65-
rewriter.InsertAfter(lastModuleAttribute.stop.TokenIndex, codeToInsert);
62+
.LastOrDefault();
63+
if (lastModuleAttribute == null)
64+
{
65+
//This should never happen for a real module.
66+
var codeToInsert = $"Attribute {attribute} ={AttributeValuesText(values)}{Environment.NewLine}";
67+
rewriter.InsertBefore(0, codeToInsert);
68+
}
69+
else
70+
{
71+
var codeToInsert = $"{Environment.NewLine}Attribute {attribute} ={AttributeValuesText(values)}";
72+
rewriter.InsertAfter(lastModuleAttribute.stop.TokenIndex, codeToInsert);
73+
}
6674
}
6775
else
6876
{
77+
var codeToInsert = $"{Environment.NewLine}Attribute {attribute} ={AttributeValuesText(values)}";
6978
rewriter.InsertAfter(declaration.AttributesPassContext.Stop.TokenIndex, codeToInsert);
7079
}
7180
}

Rubberduck.Resources/Inspections/QuickFixes.Designer.cs

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Rubberduck.Resources/Inspections/QuickFixes.de.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,4 +261,7 @@
261261
<data name="IsMissingOnInappropriateArgumentQuickFix" xml:space="preserve">
262262
<value>'IsMissing'-Aufruf in Prüfung eines Standardwerts umschreiben.</value>
263263
</data>
264+
<data name="AddMissingAttributeQuickFix" xml:space="preserve">
265+
<value>Füge das fehlende Attribut hinzu.</value>
266+
</data>
264267
</root>

Rubberduck.Resources/Inspections/QuickFixes.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,4 +261,7 @@
261261
<data name="IsMissingOnInappropriateArgumentQuickFix" xml:space="preserve">
262262
<value>Change 'IsMissing' call to test for default value.</value>
263263
</data>
264+
<data name="AddMissingAttributeQuickFix" xml:space="preserve">
265+
<value>Add the missing attribute.</value>
266+
</data>
264267
</root>

RubberduckTests/PostProcessing/AttributesUpdaterTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,43 @@ End Sub
212212
Assert.AreEqual(expectedCode, actualCode);
213213
}
214214

215+
[Test]
216+
[Category("AttributesUpdater")]
217+
//Should never happen in a real module.
218+
public void AddAttributeAddsModuleAttributeAtTopOfModuleIfThereAreNoModuleAttributesYet()
219+
{
220+
const string inputCode =
221+
@"Public Sub Foo(bar As String)
222+
bar = vbNullString
223+
End Sub
224+
";
225+
226+
const string expectedCode =
227+
@"Attribute VB_Exposed = False
228+
Public Sub Foo(bar As String)
229+
bar = vbNullString
230+
End Sub
231+
";
232+
var attributeToAdd = "VB_Exposed";
233+
var attributeValues = new List<string> { "False" };
234+
235+
string actualCode;
236+
var (component, rewriteSession, state) = TestSetup(inputCode);
237+
using (state)
238+
{
239+
var moduleDeclaration = state.DeclarationFinder
240+
.UserDeclarations(DeclarationType.ProceduralModule)
241+
.First();
242+
var attributesUpdater = new AttributesUpdater(state);
243+
244+
attributesUpdater.AddAttribute(rewriteSession, moduleDeclaration, attributeToAdd, attributeValues);
245+
rewriteSession.TryRewrite();
246+
247+
actualCode = component.CodeModule.Content();
248+
}
249+
Assert.AreEqual(expectedCode, actualCode);
250+
}
251+
215252
[Test]
216253
[Category("AttributesUpdater")]
217254
public void AddAttributeDoesNotAddAttributeAlreadyThere()
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using NUnit.Framework;
2+
using Rubberduck.Inspections.Concrete;
3+
using Rubberduck.Inspections.QuickFixes;
4+
using Rubberduck.Parsing.Inspections.Abstract;
5+
using Rubberduck.Parsing.VBA;
6+
using Rubberduck.Parsing.VBA.Parsing;
7+
8+
namespace RubberduckTests.QuickFixes
9+
{
10+
[TestFixture]
11+
public class AddMissingAttributeQuickFixTests : QuickFixTestBase
12+
{
13+
[Test]
14+
[Category("QuickFixes")]
15+
public void MissingModuleAttribute_QuickFixWorks()
16+
{
17+
const string inputCode =
18+
@"'@ModuleAttribute VB_Description, ""Desc""
19+
Public Sub Foo()
20+
Const const1 As Integer = 9
21+
End Sub";
22+
23+
const string expectedCode =
24+
@"Attribute VB_Description = ""Desc""
25+
'@ModuleAttribute VB_Description, ""Desc""
26+
Public Sub Foo()
27+
Const const1 As Integer = 9
28+
End Sub";
29+
30+
var actualCode = ApplyQuickFixToFirstInspectionResult(inputCode, state => new MissingAttributeInspection(state), CodeKind.AttributesCode);
31+
Assert.AreEqual(expectedCode, actualCode);
32+
}
33+
34+
[Test]
35+
[Category("QuickFixes")]
36+
public void MissingMemberAttribute_QuickFixWorks()
37+
{
38+
const string inputCode =
39+
@"'@MemberAttribute VB_Description, ""Desc""
40+
Public Sub Foo()
41+
Const const1 As Integer = 9
42+
End Sub";
43+
44+
const string expectedCode =
45+
@"'@MemberAttribute VB_Description, ""Desc""
46+
Public Sub Foo()
47+
Const const1 As Integer = 9
48+
End Sub
49+
Attribute Foo.VB_Description = ""Desc""";
50+
51+
var actualCode = ApplyQuickFixToFirstInspectionResult(inputCode, state => new MissingAttributeInspection(state), CodeKind.AttributesCode);
52+
Assert.AreEqual(expectedCode, actualCode);
53+
}
54+
55+
[Test]
56+
[Category("QuickFixes")]
57+
public void MissingModuleAttributeWithMultipleValues_QuickFixWorks()
58+
{
59+
const string inputCode =
60+
@"'@ModuleAttribute VB_Ext_Key, ""Key"", ""Value""
61+
Public Sub Foo()
62+
Const const1 As Integer = 9
63+
End Sub";
64+
65+
const string expectedCode =
66+
@"Attribute VB_Ext_Key = ""Key"", ""Value""
67+
'@ModuleAttribute VB_Ext_Key, ""Key"", ""Value""
68+
Public Sub Foo()
69+
Const const1 As Integer = 9
70+
End Sub";
71+
72+
var actualCode = ApplyQuickFixToFirstInspectionResult(inputCode, state => new MissingAttributeInspection(state), CodeKind.AttributesCode);
73+
Assert.AreEqual(expectedCode, actualCode);
74+
}
75+
76+
[Test]
77+
[Category("QuickFixes")]
78+
public void MissingMemberAttributeWithMultipleValues_QuickFixWorks()
79+
{
80+
const string inputCode =
81+
@"'@MemberAttribute VB_Ext_Key, ""Key"", ""Value""
82+
Public Sub Foo()
83+
Const const1 As Integer = 9
84+
End Sub";
85+
86+
const string expectedCode =
87+
@"'@MemberAttribute VB_Ext_Key, ""Key"", ""Value""
88+
Public Sub Foo()
89+
Const const1 As Integer = 9
90+
End Sub
91+
Attribute Foo.VB_Ext_Key = ""Key"", ""Value""";
92+
93+
var actualCode = ApplyQuickFixToFirstInspectionResult(inputCode, state => new MissingAttributeInspection(state), CodeKind.AttributesCode);
94+
Assert.AreEqual(expectedCode, actualCode);
95+
}
96+
97+
protected override IQuickFix QuickFix(RubberduckParserState state)
98+
{
99+
return new AddMissingAttributeQuickFix(new AttributesUpdater(state));
100+
}
101+
}
102+
}

0 commit comments

Comments
 (0)