Skip to content

Commit 0bb8bd2

Browse files
committed
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck into ReinstateTests
2 parents 35b5961 + d374061 commit 0bb8bd2

26 files changed

+1956
-114
lines changed

RetailCoder.VBE/Common/DeclarationExtensions.cs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4+
using System.Diagnostics.CodeAnalysis;
45
using System.Linq;
56
using System.Windows.Media.Imaging;
67
using Microsoft.Vbe.Interop;
78
using Rubberduck.Annotations;
9+
using Rubberduck.Parsing;
810
using Rubberduck.Parsing.Grammar;
911
using Rubberduck.Parsing.Symbols;
1012
using Rubberduck.VBEditor;
@@ -77,7 +79,56 @@ public static bool HasMultipleDeclarationsInStatement(this Declaration target)
7779

7880
var statement = target.Context.Parent as VBAParser.VariableListStmtContext;
7981

80-
return statement != null && statement.children.Count(i => i is VBAParser.VariableSubStmtContext) > 1;
82+
return statement != null && statement.children.OfType<VBAParser.VariableSubStmtContext>().Any();
83+
}
84+
85+
/// <summary>
86+
/// Returns the number of variable declarations in a single statement.
87+
/// </summary>
88+
/// <exception cref="ArgumentException">Throws when target's DeclarationType is not Variable.</exception>
89+
/// <param name="target"></param>
90+
/// <returns></returns>
91+
public static int CountOfDeclarationsInStatement(this Declaration target)
92+
{
93+
if (target.DeclarationType != DeclarationType.Variable)
94+
{
95+
throw new ArgumentException("Target DeclarationType is not Variable.", "target");
96+
}
97+
98+
var statement = target.Context.Parent as VBAParser.VariableListStmtContext;
99+
100+
if (statement != null)
101+
{
102+
return statement.children.OfType<VBAParser.VariableSubStmtContext>().Count();
103+
}
104+
105+
throw new ArgumentException("'target.Context.Parent' is not type VBAParser.VariabelListStmtContext", "target");
106+
}
107+
108+
/// <summary>
109+
/// Returns the number of variable declarations in a single statement. Adjusted to be 1-indexed rather than 0-indexed.
110+
/// </summary>
111+
/// <exception cref="ArgumentException">Throws when target's DeclarationType is not Variable.</exception>
112+
/// <param name="target"></param>
113+
/// <returns></returns>
114+
public static int IndexOfVariableDeclarationInStatement(this Declaration target)
115+
{
116+
if (target.DeclarationType != DeclarationType.Variable)
117+
{
118+
throw new ArgumentException("Target DeclarationType is not Variable.", "target");
119+
}
120+
121+
var statement = target.Context.Parent as VBAParser.VariableListStmtContext;
122+
123+
if (statement != null)
124+
{
125+
return statement.children.OfType<VBAParser.VariableSubStmtContext>()
126+
.ToList()
127+
.IndexOf((VBAParser.VariableSubStmtContext)target.Context) + 1;
128+
}
129+
130+
// ReSharper disable once LocalizableElement
131+
throw new ArgumentException("'target.Context.Parent' is not type VBAParser.VariabelListStmtContext", "target");
81132
}
82133

83134
public static readonly DeclarationType[] ProcedureTypes =
@@ -441,5 +492,34 @@ public static Declaration FindVariable(this IEnumerable<Declaration> declaration
441492
}
442493
return null;
443494
}
495+
496+
/// <summary>
497+
/// Returns the interface for a QualifiedSelection contained by a statement similar to "Implements IClass1"
498+
/// </summary>
499+
/// <param name="declarations"></param>
500+
/// <param name="selection"></param>
501+
/// <returns></returns>
502+
[SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")]
503+
public static Declaration FindInterface(this IEnumerable<Declaration> declarations, QualifiedSelection selection)
504+
{
505+
foreach (var declaration in declarations.FindInterfaces())
506+
{
507+
foreach (var reference in declaration.References)
508+
{
509+
var implementsStmt = reference.Context.Parent as VBAParser.ImplementsStmtContext;
510+
511+
if (implementsStmt == null) { continue; }
512+
513+
if (reference.QualifiedModuleName == selection.QualifiedName &&
514+
(implementsStmt.GetSelection().Contains(selection.Selection)
515+
|| reference.Selection.Contains(selection.Selection)))
516+
{
517+
return declaration;
518+
}
519+
}
520+
}
521+
522+
return null;
523+
}
444524
}
445525
}

RetailCoder.VBE/Refactorings/EncapsulateField/EncapsulateFieldRefactoring.cs

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using System;
2-
using System.Linq;
32
using Microsoft.Vbe.Interop;
43
using Rubberduck.Common;
54
using Rubberduck.Parsing.Symbols;
5+
using Rubberduck.Parsing.VBA;
66
using Rubberduck.VBEditor;
77

88
namespace Rubberduck.Refactorings.EncapsulateField
@@ -119,7 +119,8 @@ private void RemoveField(Declaration target)
119119
if (multipleDeclarations)
120120
{
121121
selection = target.GetVariableStmtContextSelection();
122-
newLines = RemoveExtraComma(_editor.GetLines(selection).Replace(oldLines, newLines));
122+
newLines = RemoveExtraComma(_editor.GetLines(selection).Replace(oldLines, newLines),
123+
target.CountOfDeclarationsInStatement(), target.IndexOfVariableDeclarationInStatement());
123124
}
124125

125126
_editor.DeleteLines(selection);
@@ -130,34 +131,40 @@ private void RemoveField(Declaration target)
130131
}
131132
}
132133

133-
private string RemoveExtraComma(string str)
134+
private string RemoveExtraComma(string str, int numParams, int indexRemoved)
134135
{
135-
if (str.Count(c => c == ',') == 1)
136-
{
137-
return str.Remove(str.IndexOf(','), 1);
138-
}
139-
140-
var significantCharacterAfterComma = false;
141-
142-
for (var index = str.IndexOf("Dim", StringComparison.Ordinal) + 3; index < str.Length; index++)
143-
{
144-
if (!significantCharacterAfterComma && str[index] == ',')
145-
{
146-
return str.Remove(index, 1);
147-
}
148-
149-
if (!char.IsWhiteSpace(str[index]) && str[index] != '_' && str[index] != ',')
150-
{
151-
significantCharacterAfterComma = true;
152-
}
153-
154-
if (str[index] == ',')
155-
{
156-
significantCharacterAfterComma = false;
157-
}
158-
}
159-
160-
return str.Remove(str.LastIndexOf(','), 1);
136+
// Example use cases for this method (fields and variables):
137+
// Dim fizz as Boolean, dizz as Double
138+
// Private fizz as Boolean, dizz as Double
139+
// Public fizz as Boolean, _
140+
// dizz as Double
141+
// Private fizz as Boolean _
142+
// , dizz as Double _
143+
// , iizz as Integer
144+
145+
// Before this method is called, the parameter to be removed has
146+
// already been removed. This means 'str' will look like:
147+
// Dim fizz as Boolean,
148+
// Private , dizz as Double
149+
// Public fizz as Boolean, _
150+
//
151+
// Private _
152+
// , dizz as Double _
153+
// , iizz as Integer
154+
155+
// This method is responsible for removing the redundant comma
156+
// and returning a string similar to:
157+
// Dim fizz as Boolean
158+
// Private dizz as Double
159+
// Public fizz as Boolean _
160+
//
161+
// Private _
162+
// dizz as Double _
163+
// , iizz as Integer
164+
165+
var commaToRemove = numParams == indexRemoved ? indexRemoved - 1 : indexRemoved;
166+
167+
return str.Remove(str.NthIndexOf(',', commaToRemove), 1);
161168
}
162169

163170
private string GetPropertyText()
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Rubberduck.Parsing.Grammar;
4+
using Rubberduck.Parsing.Symbols;
5+
using Rubberduck.Parsing.VBA;
6+
using Rubberduck.VBEditor;
7+
8+
namespace Rubberduck.Refactorings.ExtractInterface
9+
{
10+
public class ExtractInterfaceModel
11+
{
12+
private readonly RubberduckParserState _parseResult;
13+
public RubberduckParserState ParseResult { get { return _parseResult; } }
14+
15+
private readonly IEnumerable<Declaration> _declarations;
16+
public IEnumerable<Declaration> Declarations { get { return _declarations; } }
17+
18+
private readonly QualifiedSelection _selection;
19+
public QualifiedSelection Selection { get { return _selection; } }
20+
21+
private readonly Declaration _targetDeclaration;
22+
public Declaration TargetDeclaration { get { return _targetDeclaration; } }
23+
24+
public string InterfaceName { get; set; }
25+
public List<InterfaceMember> Members { get; set; }
26+
27+
private readonly static DeclarationType[] DeclarationTypes =
28+
{
29+
DeclarationType.Class,
30+
DeclarationType.Document,
31+
DeclarationType.UserForm
32+
};
33+
34+
public readonly string[] PrimitiveTypes =
35+
{
36+
Tokens.Boolean,
37+
Tokens.Byte,
38+
Tokens.Date,
39+
Tokens.Decimal,
40+
Tokens.Double,
41+
Tokens.Long,
42+
Tokens.LongLong,
43+
Tokens.LongPtr,
44+
Tokens.Integer,
45+
Tokens.Single,
46+
Tokens.String,
47+
Tokens.StrPtr
48+
};
49+
50+
public ExtractInterfaceModel(RubberduckParserState parseResult, QualifiedSelection selection)
51+
{
52+
_parseResult = parseResult;
53+
_selection = selection;
54+
_declarations = parseResult.AllDeclarations.ToList();
55+
56+
_targetDeclaration =
57+
_declarations.SingleOrDefault(
58+
item =>
59+
!item.IsBuiltIn && DeclarationTypes.Contains(item.DeclarationType)
60+
&& item.Project == selection.QualifiedName.Project
61+
&& item.QualifiedSelection.QualifiedName == selection.QualifiedName);
62+
63+
InterfaceName = "I" + TargetDeclaration.IdentifierName;
64+
65+
Members = _declarations.Where(item => !item.IsBuiltIn &&
66+
item.Project == _targetDeclaration.Project &&
67+
item.ComponentName == _targetDeclaration.ComponentName &&
68+
item.Accessibility == Accessibility.Public &&
69+
item.DeclarationType != DeclarationType.Variable &&
70+
item.DeclarationType != DeclarationType.Event)
71+
.OrderBy(o => o.Selection.StartLine)
72+
.ThenBy(t => t.Selection.StartColumn)
73+
.Select(d => new InterfaceMember(d, _declarations))
74+
.ToList();
75+
}
76+
}
77+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.Linq;
2+
using System.Windows.Forms;
3+
using Microsoft.Vbe.Interop;
4+
5+
namespace Rubberduck.Refactorings.ExtractInterface
6+
{
7+
public interface IExtractInterfacePresenter
8+
{
9+
ExtractInterfaceModel Show();
10+
}
11+
12+
public class ExtractInterfacePresenter : IExtractInterfacePresenter
13+
{
14+
private readonly IExtractInterfaceView _view;
15+
private readonly ExtractInterfaceModel _model;
16+
17+
public ExtractInterfacePresenter(IExtractInterfaceView view, ExtractInterfaceModel model)
18+
{
19+
_view = view;
20+
_model = model;
21+
}
22+
23+
public ExtractInterfaceModel Show()
24+
{
25+
if (_model.TargetDeclaration == null) { return null; }
26+
27+
_view.ComponentNames =
28+
_model.TargetDeclaration.Project.VBComponents.Cast<VBComponent>().Select(c => c.Name).ToList();
29+
_view.InterfaceName = _model.InterfaceName;
30+
_view.Members = _model.Members;
31+
32+
if (_view.ShowDialog() != DialogResult.OK)
33+
{
34+
return null;
35+
}
36+
37+
_model.InterfaceName = _view.InterfaceName;
38+
_model.Members = _view.Members;
39+
return _model;
40+
}
41+
}
42+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Rubberduck.Parsing.VBA;
2+
using Rubberduck.VBEditor;
3+
4+
namespace Rubberduck.Refactorings.ExtractInterface
5+
{
6+
public class ExtractInterfacePresenterFactory : IRefactoringPresenterFactory<ExtractInterfacePresenter>
7+
{
8+
private readonly IActiveCodePaneEditor _editor;
9+
private readonly IExtractInterfaceView _view;
10+
private readonly RubberduckParserState _parseResult;
11+
12+
public ExtractInterfacePresenterFactory(RubberduckParserState parseResult, IActiveCodePaneEditor editor, IExtractInterfaceView view)
13+
{
14+
_editor = editor;
15+
_view = view;
16+
_parseResult = parseResult;
17+
}
18+
19+
public ExtractInterfacePresenter Create()
20+
{
21+
var selection = _editor.GetSelection();
22+
if (selection == null)
23+
{
24+
return null;
25+
}
26+
27+
var model = new ExtractInterfaceModel(_parseResult, selection.Value);
28+
return new ExtractInterfacePresenter(_view, model);
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)