Skip to content

Commit 8db3f69

Browse files
authored
Merge pull request #3783 from bclothier/CompileBeforeParse
Introducing "Compile before parsing" setting (enabled by default), to help reduce/prevent parser errors caused by uncompilable code.
2 parents f92736b + 3be0a5e commit 8db3f69

File tree

16 files changed

+874
-91
lines changed

16 files changed

+874
-91
lines changed

RetailCoder.VBE/Properties/Settings.Designer.cs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RetailCoder.VBE/Properties/Settings.settings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@
162162
<Language Code="en-US" />
163163
<CanShowSplash>true</CanShowSplash>
164164
<CanCheckVersion>true</CanCheckVersion>
165+
<CompileBeforeParse>true</CompileBeforeParse>
165166
<IsSmartIndenterPrompted>false</IsSmartIndenterPrompted>
166167
<IsAutoSaveEnabled>false</IsAutoSaveEnabled>
167168
<AutoSavePeriod>10</AutoSavePeriod>

RetailCoder.VBE/Root/RubberduckIoCInstaller.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
using Rubberduck.UI.CodeMetrics;
4646
using Rubberduck.VBEditor.ComManagement;
4747
using Rubberduck.Parsing.Common;
48+
using Rubberduck.VBEditor.ComManagement.TypeLibsAPI;
4849

4950

5051
namespace Rubberduck.Root
@@ -104,6 +105,7 @@ public void Install(IWindsorContainer container, IConfigurationStore store)
104105

105106
RegisterSmartIndenter(container);
106107
RegisterParsingEngine(container);
108+
RegisterTypeLibApi(container);
107109

108110
container.Register(Component.For<TestExplorerModel>()
109111
.LifestyleSingleton());
@@ -169,7 +171,7 @@ private void RegisterConfiguration(IWindsorContainer container, Assembly[] assem
169171
container.Register(Component.For(typeof(IPersistanceService<>), typeof(IFilePersistanceService<>))
170172
.ImplementedBy(typeof(XmlPersistanceService<>))
171173
.LifestyleSingleton());
172-
174+
173175
container.Register(Component.For<IConfigProvider<IndenterSettings>>()
174176
.ImplementedBy<IndenterConfigProvider>()
175177
.LifestyleSingleton());
@@ -716,6 +718,13 @@ private void RegisterParsingEngine(IWindsorContainer container)
716718
.Instance(() => new VBAPreprocessor(double.Parse(_vbe.Version, CultureInfo.InvariantCulture))));
717719
}
718720

721+
private void RegisterTypeLibApi(IWindsorContainer container)
722+
{
723+
container.Register(Component.For<IVBETypeLibsAPI>()
724+
.ImplementedBy<VBETypeLibsAPI>()
725+
.LifestyleSingleton());
726+
}
727+
719728
private void RegisterCustomDeclarationLoadersToParser(IWindsorContainer container)
720729
{
721730
container.Register(Classes.FromAssemblyContaining<ICustomDeclarationLoader>()

RetailCoder.VBE/Settings/GeneralSettings.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public interface IGeneralSettings
1212
DisplayLanguageSetting Language { get; set; }
1313
bool CanShowSplash { get; set; }
1414
bool CanCheckVersion { get; set; }
15+
bool CompileBeforeParse { get; set; }
1516
bool IsSmartIndenterPrompted { get; set; }
1617
bool IsAutoSaveEnabled { get; set; }
1718
int AutoSavePeriod { get; set; }
@@ -26,6 +27,7 @@ public class GeneralSettings : IGeneralSettings, IEquatable<GeneralSettings>
2627
public DisplayLanguageSetting Language { get; set; }
2728
public bool CanShowSplash { get; set; }
2829
public bool CanCheckVersion { get; set; }
30+
public bool CompileBeforeParse { get; set; }
2931
public bool IsSmartIndenterPrompted { get; set; }
3032
public bool IsAutoSaveEnabled { get; set; }
3133
public int AutoSavePeriod { get; set; }
@@ -59,6 +61,7 @@ public bool Equals(GeneralSettings other)
5961
Language.Equals(other.Language) &&
6062
CanShowSplash == other.CanShowSplash &&
6163
CanCheckVersion == other.CanCheckVersion &&
64+
CompileBeforeParse == other.CompileBeforeParse &&
6265
IsSmartIndenterPrompted == other.IsSmartIndenterPrompted &&
6366
IsAutoSaveEnabled == other.IsAutoSaveEnabled &&
6467
AutoSavePeriod == other.AutoSavePeriod &&

RetailCoder.VBE/UI/Command/ReparseCommand.cs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,36 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
14
using System.Runtime.InteropServices;
5+
using System.Windows.Forms;
26
using NLog;
37
using Rubberduck.Parsing.VBA;
8+
using Rubberduck.Settings;
9+
using Rubberduck.SettingsProvider;
410
using Rubberduck.UI.CodeExplorer.Commands;
11+
using Rubberduck.VBEditor.ComManagement.TypeLibsAPI;
12+
using Rubberduck.VBEditor.SafeComWrappers;
13+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
514

615
namespace Rubberduck.UI.Command
716
{
817
[ComVisible(false)]
918
[CodeExplorerCommand]
1019
public class ReparseCommand : CommandBase
1120
{
21+
private readonly IVBE _vbe;
22+
private readonly IVBETypeLibsAPI _typeLibApi;
23+
private readonly IMessageBox _messageBox;
1224
private readonly RubberduckParserState _state;
25+
private readonly GeneralSettings _settings;
1326

14-
public ReparseCommand(RubberduckParserState state) : base(LogManager.GetCurrentClassLogger())
27+
public ReparseCommand(IVBE vbe, IConfigProvider<GeneralSettings> settingsProvider, RubberduckParserState state, IVBETypeLibsAPI typeLibApi, IMessageBox messageBox) : base(LogManager.GetCurrentClassLogger())
1528
{
29+
_vbe = vbe;
30+
_typeLibApi = typeLibApi;
1631
_state = state;
32+
_settings = settingsProvider.Create();
33+
_messageBox = messageBox;
1734
}
1835

1936
protected override bool EvaluateCanExecute(object parameter)
@@ -26,7 +43,54 @@ protected override bool EvaluateCanExecute(object parameter)
2643

2744
protected override void OnExecute(object parameter)
2845
{
46+
if (_settings.CompileBeforeParse)
47+
{
48+
if (CompileAllProjects(out var failedNames))
49+
{
50+
if (!PromptUserToContinue(failedNames))
51+
{
52+
return;
53+
}
54+
}
55+
}
2956
_state.OnParseRequested(this);
3057
}
58+
59+
private bool CompileAllProjects(out List<string> failedNames)
60+
{
61+
failedNames = new List<string>();
62+
using (var projects = _vbe.VBProjects)
63+
{
64+
foreach (var project in projects)
65+
{
66+
using (project)
67+
{
68+
if (project.Protection != ProjectProtection.Unprotected)
69+
{
70+
continue;
71+
}
72+
73+
if (!_typeLibApi.CompileProject(project))
74+
{
75+
failedNames.Add(project.Name);
76+
}
77+
}
78+
}
79+
}
80+
81+
return failedNames.Any();
82+
}
83+
84+
private bool PromptUserToContinue(List<string> failedNames)
85+
{
86+
var formattedList = string.Concat(Environment.NewLine, Environment.NewLine,
87+
string.Join(Environment.NewLine, failedNames));
88+
var result = _messageBox.Show(
89+
string.Format(RubberduckUI.Command_Reparse_CannotCompile,
90+
formattedList),
91+
RubberduckUI.Command_Reparse_CannotCompile_Caption, MessageBoxButtons.YesNo,
92+
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
93+
return result == DialogResult.Yes;
94+
}
3195
}
3296
}

RetailCoder.VBE/UI/RubberduckUI.Designer.cs

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

RetailCoder.VBE/UI/RubberduckUI.resx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,4 +1780,13 @@ Would you like to import them to Rubberduck?</value>
17801780
<data name="GeneralSettings_ModifierWarning" xml:space="preserve">
17811781
<value>Modifier Warning</value>
17821782
</data>
1783+
<data name="Command_Reparse_CannotCompile" xml:space="preserve">
1784+
<value>The following project(s) cannot be compiled, which will most likely result in parser errors. Continue anyway? {0}</value>
1785+
</data>
1786+
<data name="Command_Reparse_CannotCompile_Caption" xml:space="preserve">
1787+
<value>Unable to compile for parsing</value>
1788+
</data>
1789+
<data name="GeneralSettings_CompileBeforeParse" xml:space="preserve">
1790+
<value>Compile code before parsing</value>
1791+
</data>
17831792
</root>

RetailCoder.VBE/UI/Settings/GeneralSettings.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@
124124

125125
<CheckBox Margin="5,0,0,5" Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=GeneralSettings_CheckVersion}"
126126
IsChecked="{Binding CheckVersionAtStartup}" />
127+
<CheckBox Margin="5,0,0,5" Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=GeneralSettings_CompileBeforeParse}"
128+
IsChecked="{Binding CompileBeforeParse}" />
127129
<StackPanel Orientation="Horizontal"/>
128130

129131
<Label Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=GeneralSettings_MinimumLogLevelLabel}" FontWeight="SemiBold" />

RetailCoder.VBE/UI/Settings/GeneralSettingsViewModel.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,21 @@ public bool CheckVersionAtStartup
124124
}
125125
}
126126

127+
private bool _compileBeforeParse;
128+
129+
public bool CompileBeforeParse
130+
{
131+
get => _compileBeforeParse;
132+
set
133+
{
134+
if (_compileBeforeParse != value)
135+
{
136+
_compileBeforeParse = value;
137+
OnPropertyChanged();
138+
}
139+
}
140+
}
141+
127142
private int _autoSavePeriod;
128143
public int AutoSavePeriod
129144
{
@@ -192,6 +207,7 @@ private Rubberduck.Settings.GeneralSettings GetCurrentGeneralSettings()
192207
Language = SelectedLanguage,
193208
CanShowSplash = ShowSplashAtStartup,
194209
CanCheckVersion = CheckVersionAtStartup,
210+
CompileBeforeParse = CompileBeforeParse,
195211
IsSmartIndenterPrompted = _indenterPrompted,
196212
IsAutoSaveEnabled = AutoSaveEnabled,
197213
AutoSavePeriod = AutoSavePeriod,
@@ -206,6 +222,7 @@ private void TransferSettingsToView(IGeneralSettings general, IHotkeySettings ho
206222
Hotkeys = new ObservableCollection<HotkeySetting>(hottkey.Settings);
207223
ShowSplashAtStartup = general.CanShowSplash;
208224
CheckVersionAtStartup = general.CanCheckVersion;
225+
CompileBeforeParse = general.CompileBeforeParse;
209226
_indenterPrompted = general.IsSmartIndenterPrompted;
210227
AutoSaveEnabled = general.IsAutoSaveEnabled;
211228
AutoSavePeriod = general.AutoSavePeriod;

RetailCoder.VBE/UnitTesting/TestEngine.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,18 @@ public class TestEngine : ITestEngine
2121
private readonly IVBE _vbe;
2222
private readonly RubberduckParserState _state;
2323
private readonly IFakesProviderFactory _fakesFactory;
24+
private readonly IVBETypeLibsAPI _typeLibApi;
2425

2526
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
2627

27-
public TestEngine(TestExplorerModel model, IVBE vbe, RubberduckParserState state, IFakesProviderFactory fakesFactory)
28+
public TestEngine(TestExplorerModel model, IVBE vbe, RubberduckParserState state, IFakesProviderFactory fakesFactory, IVBETypeLibsAPI typeLibApi)
2829
{
2930
Debug.WriteLine("TestEngine created.");
3031
Model = model;
3132
_vbe = vbe;
3233
_state = state;
3334
_fakesFactory = fakesFactory;
35+
_typeLibApi = typeLibApi;
3436
}
3537

3638
public TestExplorerModel Model { get; }
@@ -126,7 +128,7 @@ private void Run(IEnumerable<Declaration> members)
126128
{
127129
foreach (var member in group)
128130
{
129-
VBETypeLibsAPI.ExecuteCode(typeLib, member.QualifiedModuleName.ComponentName,
131+
_typeLibApi.ExecuteCode(typeLib, member.QualifiedModuleName.ComponentName,
130132
member.QualifiedName.MemberName);
131133
}
132134
}

0 commit comments

Comments
 (0)