Skip to content

Commit 41d40a5

Browse files
committed
Merge branch 'main' of https://github.com/rubberduck-vba/Rubberduck into inspections-cleanup
2 parents a89e2d2 + 4ec0ddb commit 41d40a5

File tree

22 files changed

+399
-92
lines changed

22 files changed

+399
-92
lines changed

Rubberduck.CodeAnalysis/QuickFixes/Concrete/ChangeProcedureToFunctionQuickFix.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,31 @@ public override void Fix(IInspectionResult result, IRewriteSession rewriteSessio
5959
var arg = parameterizedDeclaration.Parameters.First(p => p.IsByRef || p.IsImplicitByRef);
6060
var argIndex = parameterizedDeclaration.Parameters.IndexOf(arg);
6161

62-
UpdateSignature(result.Target, arg, rewriteSession);
62+
UpdateProcedure(result.Target, arg, rewriteSession);
6363
foreach (var reference in result.Target.References.Where(reference => !reference.IsDefaultMemberAccess))
6464
{
6565
UpdateCall(reference, argIndex, rewriteSession);
6666
}
6767
}
6868

69-
private void UpdateSignature(Declaration target, ParameterDeclaration arg, IRewriteSession rewriteSession)
69+
private void UpdateProcedure(Declaration target, ParameterDeclaration arg, IRewriteSession rewriteSession)
7070
{
7171
var subStmt = (VBAParser.SubStmtContext) target.Context;
7272
var argContext = (VBAParser.ArgContext)arg.Context;
73-
73+
var argName = argContext.unrestrictedIdentifier().GetText();
7474
var rewriter = rewriteSession.CheckOutModuleRewriter(target.QualifiedModuleName);
7575

76+
UpdateSignature(subStmt, arg, rewriter);
77+
AddReturnStatement(subStmt, argName, rewriter);
78+
ReplaceExitSubs(subStmt, argName, rewriter);
79+
}
80+
81+
private void UpdateSignature(VBAParser.SubStmtContext subStmt, ParameterDeclaration arg, IModuleRewriter rewriter)
82+
{
7683
rewriter.Replace(subStmt.SUB(), Tokens.Function);
7784
rewriter.Replace(subStmt.END_SUB(), "End Function");
7885

86+
var argContext = (VBAParser.ArgContext)arg.Context;
7987
rewriter.InsertAfter(subStmt.argList().Stop.TokenIndex, $" As {arg.AsTypeName}");
8088

8189
if (arg.IsByRef)
@@ -86,11 +94,26 @@ private void UpdateSignature(Declaration target, ParameterDeclaration arg, IRewr
8694
{
8795
rewriter.InsertBefore(argContext.unrestrictedIdentifier().Start.TokenIndex, Tokens.ByVal);
8896
}
97+
}
8998

90-
var returnStmt = $" {subStmt.subroutineName().GetText()} = {argContext.unrestrictedIdentifier().GetText()}{Environment.NewLine}";
99+
private void AddReturnStatement(VBAParser.SubStmtContext subStmt, string argName, IModuleRewriter rewriter)
100+
{
101+
var returnStmt = $" {subStmt.subroutineName().GetText()} = {argName}{Environment.NewLine}";
102+
// This exploits that the VBE will realign the End Function statement automatically.
91103
rewriter.InsertBefore(subStmt.END_SUB().Symbol.TokenIndex, returnStmt);
92104
}
93105

106+
private void ReplaceExitSubs(VBAParser.SubStmtContext subStmt, string argName, IModuleRewriter rewriter)
107+
{
108+
// We use a statement separator here to be able to deal with single line if statments without too much issues.
109+
var exitFunctionCode = $"{subStmt.subroutineName().GetText()} = {argName}: Exit Function";
110+
foreach (var exitSub in subStmt.GetDescendents<VBAParser.ExitStmtContext>())
111+
{
112+
rewriter.Replace(exitSub, exitFunctionCode);
113+
}
114+
}
115+
116+
94117
private void UpdateCall(IdentifierReference reference, int argIndex, IRewriteSession rewriteSession)
95118
{
96119
var rewriter = rewriteSession.CheckOutModuleRewriter(reference.QualifiedModuleName);

Rubberduck.Core/Properties/Settings.Designer.cs

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

Rubberduck.Core/Rubberduck.Core.csproj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,17 @@
9393
<Version>2.0.20525</Version>
9494
</PackageReference>
9595
</ItemGroup>
96+
<ItemGroup>
97+
<Compile Update="Properties\Settings.Designer.cs">
98+
<DesignTimeSharedInput>True</DesignTimeSharedInput>
99+
<AutoGen>True</AutoGen>
100+
<DependentUpon>Settings.settings</DependentUpon>
101+
</Compile>
102+
</ItemGroup>
103+
<ItemGroup>
104+
<None Update="Properties\Settings.settings">
105+
<Generator>SettingsSingleFileGenerator</Generator>
106+
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
107+
</None>
108+
</ItemGroup>
96109
</Project>

Rubberduck.Core/Settings/GeneralSettings.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public interface IGeneralSettings
1313
DisplayLanguageSetting Language { get; set; }
1414
bool CanShowSplash { get; set; }
1515
bool CanCheckVersion { get; set; }
16+
string ApiBaseUrl { get; set; }
1617
bool IncludePreRelease { get; set; }
1718
bool CompileBeforeParse { get; set; }
1819
bool IsSmartIndenterPrompted { get; set; }
@@ -45,6 +46,7 @@ public DisplayLanguageSetting Language
4546

4647
public bool CanShowSplash { get; set; }
4748
public bool CanCheckVersion { get; set; }
49+
public string ApiBaseUrl { get; set; }
4850
public bool IncludePreRelease { get; set; }
4951
public bool CompileBeforeParse { get; set; }
5052
public bool IsSmartIndenterPrompted { get; set; }
@@ -103,7 +105,8 @@ public bool Equals(GeneralSettings other)
103105
EnableExperimentalFeatures.Count == other.EnableExperimentalFeatures.Count &&
104106
EnableExperimentalFeatures.All(other.EnableExperimentalFeatures.Contains) &&
105107
SetDpiUnaware == other.SetDpiUnaware &&
106-
EnableFolderDragAndDrop == other.EnableFolderDragAndDrop;
108+
EnableFolderDragAndDrop == other.EnableFolderDragAndDrop &&
109+
ApiBaseUrl == other.ApiBaseUrl;
107110
}
108111
}
109112
}

Rubberduck.Core/UI/Command/MenuItems/ParentMenus/ParentMenuItemBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ public async Task EvaluateCanExecuteAsync(RubberduckParserState state, Cancellat
154154
}
155155
catch (Exception exception)
156156
{
157-
value.IsEnabled = false;
158157
Logger.Error(exception, "Could not evaluate availability of commmand menu item {0}.", value.Tag ?? "{Unknown}");
158+
value.IsEnabled = false;
159159
}
160160
});
161161
break;

Rubberduck.Core/UI/Command/VersionCheckCommand.cs

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -53,40 +53,31 @@ protected override async void OnExecute(object parameter)
5353
Logger.Info("Executing version check...");
5454

5555
var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5));
56-
await _versionCheck
57-
.GetLatestVersionAsync(settings, tokenSource.Token)
58-
.ContinueWith(t =>
59-
{
60-
if (t.IsFaulted)
61-
{
62-
Logger.Warn(t.Exception);
63-
return;
64-
}
56+
var latest = await _versionCheck.GetLatestVersionAsync(settings, tokenSource.Token);
6557

66-
if (_versionCheck.CurrentVersion < t.Result)
67-
{
68-
var proceed = true;
69-
if (_versionCheck.IsDebugBuild || !settings.IncludePreRelease)
70-
{
71-
// if the latest version has a revision number and isn't a pre-release build,
72-
// avoid prompting since we can't know if the build already includes the latest version.
73-
proceed = t.Result.Revision == 0;
74-
}
58+
if (_versionCheck.CurrentVersion < latest)
59+
{
60+
var proceed = true;
61+
if (_versionCheck.IsDebugBuild || !settings.IncludePreRelease)
62+
{
63+
// if the latest version has a revision number and isn't a pre-release build,
64+
// avoid prompting since we can't know if the build already includes the latest version.
65+
proceed = latest.Revision == 0;
66+
}
7567

76-
if (proceed)
77-
{
78-
PromptAndBrowse(t.Result, settings.IncludePreRelease);
79-
}
80-
else
81-
{
82-
Logger.Info("Version check skips notification of an existing newer version available.");
83-
}
84-
}
85-
else
86-
{
87-
Logger.Info("Version check completed: running current latest.");
88-
}
89-
});
68+
if (proceed)
69+
{
70+
PromptAndBrowse(latest, settings.IncludePreRelease);
71+
}
72+
else
73+
{
74+
Logger.Info("Version check skips notification of an existing newer version available.");
75+
}
76+
}
77+
else if (latest != default)
78+
{
79+
Logger.Info("Version check completed: running current latest.");
80+
}
9081
}
9182

9283
private void PromptAndBrowse(Version latestVersion, bool includePreRelease)

Rubberduck.Core/UI/Splash2021.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Drawing;
22
using System.Windows.Forms;
3-
using Rubberduck.VersionCheck;
43

54
namespace Rubberduck.UI
65
{
@@ -11,9 +10,9 @@ public Splash2021()
1110
InitializeComponent();
1211
}
1312

14-
public Splash2021(IVersionCheckService versionCheck) : this()
13+
public Splash2021(string versionString) : this()
1514
{
16-
VersionLabel.Text = string.Format(Resources.RubberduckUI.Rubberduck_AboutBuild, versionCheck.VersionString);
15+
VersionLabel.Text = string.Format(Resources.RubberduckUI.Rubberduck_AboutBuild, versionString);
1716
VersionLabel.Parent = pictureBox1;
1817
VersionLabel.BackColor = Color.Transparent;
1918
}

Rubberduck.Core/VersionCheck/ApiClientBase.cs

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Newtonsoft.Json;
2+
using Rubberduck.Settings;
23
using System;
34
using System.Net;
45
using System.Net.Http;
@@ -9,40 +10,69 @@
910

1011
namespace Rubberduck.Client.Abstract
1112
{
12-
public abstract class ApiClientBase : IDisposable
13+
public interface IHttpClientProvider
14+
{
15+
HttpClient GetClient();
16+
}
17+
18+
public sealed class HttpClientProvider : IHttpClientProvider, IDisposable
19+
{
20+
private readonly Lazy<HttpClient> _client;
21+
22+
public HttpClientProvider(Func<HttpClient> getClient)
23+
{
24+
_client = new Lazy<HttpClient>(getClient);
25+
}
26+
27+
public HttpClient GetClient()
28+
{
29+
return _client.Value;
30+
}
31+
32+
public void Dispose()
33+
{
34+
if (_client.IsValueCreated)
35+
{
36+
_client.Value.Dispose();
37+
}
38+
}
39+
}
40+
41+
public abstract class ApiClientBase
1342
{
1443
protected static readonly string UserAgentName = "Rubberduck";
15-
protected static readonly string BaseUrl = "https://api.rubberduckvba.com/api/v1/";
1644
protected static readonly string ContentTypeApplicationJson = "application/json";
1745
protected static readonly int MaxAttempts = 3;
1846
protected static readonly TimeSpan RetryCooldownDelay = TimeSpan.FromSeconds(1);
1947

20-
protected readonly Lazy<HttpClient> _client;
48+
protected readonly IHttpClientProvider _clientProvider;
49+
protected readonly string _baseUrl;
2150

22-
protected ApiClientBase()
51+
protected ApiClientBase(IGeneralSettings settings, IHttpClientProvider clientProvider)
2352
{
24-
_client = new Lazy<HttpClient>(() => GetClient());
53+
_clientProvider = clientProvider;
54+
_baseUrl = string.IsNullOrWhiteSpace(settings.ApiBaseUrl) ? "https://api.rubberduckvba.com/api/v1/" : settings.ApiBaseUrl;
2555
}
2656

2757
protected HttpClient GetClient()
2858
{
2959
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
30-
var client = new HttpClient();
31-
return ConfigureClient(client);
60+
var client = _clientProvider.GetClient();
61+
ConfigureClient(client);
62+
return client;
3263
}
3364

34-
protected virtual HttpClient ConfigureClient(HttpClient client)
65+
protected virtual void ConfigureClient(HttpClient client)
3566
{
3667
var userAgentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(3);
3768
var userAgentHeader = new ProductInfoHeaderValue(UserAgentName, userAgentVersion);
3869

3970
client.DefaultRequestHeaders.UserAgent.Add(userAgentHeader);
40-
return client;
4171
}
4272

4373
protected virtual async Task<TResult> GetResponse<TResult>(string route, CancellationToken? cancellationToken = null)
4474
{
45-
var uri = new Uri($"{BaseUrl}{route}");
75+
var uri = new Uri($"{_baseUrl}{route}");
4676

4777
var attempt = 0;
4878
var token = cancellationToken ?? CancellationToken.None;
@@ -102,7 +132,7 @@ protected virtual async Task<TResult> GetResponse<TResult>(string route, Cancell
102132

103133
protected virtual async Task<TResult> Post<TArgs, TResult>(string route, TArgs args, CancellationToken? cancellationToken = null)
104134
{
105-
var uri = new Uri($"{BaseUrl}{route}");
135+
var uri = new Uri($"{_baseUrl}{route}");
106136
string json;
107137
try
108138
{
@@ -167,13 +197,5 @@ protected virtual async Task<TResult> Post<TArgs, TResult>(string route, TArgs a
167197
return default;
168198
}
169199
}
170-
171-
public void Dispose()
172-
{
173-
if (_client.IsValueCreated)
174-
{
175-
_client.Value.Dispose();
176-
}
177-
}
178200
}
179201
}

Rubberduck.Core/VersionCheck/PublicApiClient.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Linq;
43
using System.Threading;
54
using System.Threading.Tasks;
65
using Rubberduck.Client.Abstract;
6+
using Rubberduck.Settings;
77

88
namespace Rubberduck.VersionCheck
99
{
10-
public class PublicApiClient : ApiClientBase
10+
public interface IPublicApiClient
11+
{
12+
Task<IEnumerable<Tag>> GetLatestTagsAsync(CancellationToken token);
13+
}
14+
15+
public class PublicApiClient : ApiClientBase, IPublicApiClient
1116
{
1217
private static readonly string PublicTagsEndPoint = "public/tags";
1318

19+
public PublicApiClient(IGeneralSettings settings, IHttpClientProvider clientProvider)
20+
: base(settings, clientProvider)
21+
{
22+
}
23+
1424
public async Task<IEnumerable<Tag>> GetLatestTagsAsync(CancellationToken token)
1525
{
1626
return await GetResponse<Tag[]>(PublicTagsEndPoint, token);

Rubberduck.Core/VersionCheck/VersionCheckService.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ namespace Rubberduck.VersionCheck
1111
public class VersionCheckService : IVersionCheckService
1212
{
1313
private static readonly ILogger _logger = LogManager.GetCurrentClassLogger();
14+
private readonly IPublicApiClient _client;
1415

1516
/// <param name="version">That would be the version of the assembly for the <c>_Extension</c> class.</param>
16-
public VersionCheckService(Version version)
17+
/// <param name="client"></param>
18+
public VersionCheckService(Version version, IPublicApiClient client)
1719
{
1820
CurrentVersion = version;
21+
_client = client;
22+
1923
#if DEBUG
2024
IsDebugBuild = true;
2125
#endif
@@ -32,19 +36,23 @@ public async Task<Version> GetLatestVersionAsync(GeneralSettings settings, Cance
3236
return _latestVersion;
3337
}
3438

35-
using (var client = new PublicApiClient())
39+
try
3640
{
37-
var tags = await client.GetLatestTagsAsync(token);
41+
var tags = await _client.GetLatestTagsAsync(token);
3842

3943
var next = tags.Single(e => e.IsPreRelease);
4044
var main = tags.Single(e => !e.IsPreRelease);
4145
_logger.Info($"Main: v{main.Version.ToString(3)}; Next: v{next.Version.ToString(4)}");
4246

4347
_latestVersion = settings.IncludePreRelease ? next.Version : main.Version;
4448
_logger.Info($"Check prerelease: {settings.IncludePreRelease}; latest: v{_latestVersion.ToString(4)}");
49+
}
50+
catch ( Exception ex )
51+
{
52+
_logger.Warn(ex, "Version check failed.");
4553

46-
return _latestVersion;
4754
}
55+
return _latestVersion;
4856
}
4957

5058
public Version CurrentVersion { get; }

0 commit comments

Comments
 (0)