diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000000..5c23afc0c4
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,41 @@
+# Build Rubberduck in GitHub Actions using windows-2019
+# For now we don't run the tests, but might add it in the future.
+# This is a simple build script that builds the Rubberduck project using MSBuild.
+# It uses the latest version of Visual Studio 2019 and the .NET Framework 4.6.2
+
+name: Build Rubberduck
+
+on:
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: windows-2019
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup MSBuild
+ uses: microsoft/setup-msbuild@v1.1
+
+ - name: Setup NuGet
+ uses: NuGet/setup-nuget@v1.1.1
+
+ - name: Restore NuGet packages
+ run: |
+ nuget RubberduckMeta.sln
+ nuget restore Rubberduck.sln
+
+ - name: Build Solution (Release)
+ run: msbuild Rubberduck.sln /p:Configuration=Release /p:Platform="Any CPU" /p:TargetFrameworkVersion=v4.6.2 /verbosity:minimal
+
+ - name: Upload Build Artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: rubberduck-Release
+ path: |
+ Rubberduck.Main/bin/Release/net462/
+ if-no-files-found: error
+
diff --git a/Rubberduck.InternalApi/Common/StringLineBuilder.cs b/Rubberduck.InternalApi/Common/StringLineBuilder.cs
new file mode 100644
index 0000000000..c1d576ff44
--- /dev/null
+++ b/Rubberduck.InternalApi/Common/StringLineBuilder.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Rubberduck.InternalApi.Common
+{
+ ///
+ /// Extension to StringBuilder to allow adding text line by line.
+ ///
+ public class StringLineBuilder
+ {
+ private readonly StringBuilder _document = new StringBuilder();
+
+ public override string ToString() => _document.ToString();
+
+ public void AppendLine(string value = "")
+ => _document.Append(value + "\r\n");
+
+ public void AppendLineNoNullChars(string value)
+ => AppendLine(value.Replace("\0", string.Empty));
+ }
+}
diff --git a/Rubberduck.Main/Extension.cs b/Rubberduck.Main/Extension.cs
index 3e9880c29c..2f2d981ae5 100644
--- a/Rubberduck.Main/Extension.cs
+++ b/Rubberduck.Main/Extension.cs
@@ -2,6 +2,7 @@
using Extensibility;
using NLog;
using Rubberduck.Common.WinAPI;
+using Rubberduck.ExternalApi;
using Rubberduck.Resources;
using Rubberduck.Resources.Registration;
using Rubberduck.Root;
@@ -9,6 +10,7 @@
using Rubberduck.Settings;
using Rubberduck.SettingsProvider;
using Rubberduck.UI;
+using Rubberduck.UnitTesting;
using Rubberduck.VBEditor.ComManagement;
using Rubberduck.VBEditor.ComManagement.TypeLibs;
using Rubberduck.VBEditor.Events;
@@ -50,12 +52,16 @@ public class _Extension : IDTExtensibility2
private bool _isInitialized;
private bool _isBeginShutdownExecuted;
+ private IExternalAPI _externalAPI;
+
private GeneralSettings _initialSettings;
private IWindsorContainer _container;
private App _app;
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
+
+
public void OnAddInsUpdate(ref Array custom) { }
[SuppressMessage("ReSharper", "InconsistentNaming")]
@@ -91,12 +97,10 @@ public void OnConnection(object Application, ext_ConnectMode ConnectMode, object
Console.WriteLine(e);
}
}
-
- [Conditional("DEBUG")]
private void SetAddInObject()
{
- // FOR DEBUGGING/DEVELOPMENT PURPOSES, ALLOW ACCESS TO SOME VBETypeLibsAPI FEATURES FROM VBA
- _addin.Object = new VBETypeLibsAPI_Object(_vbe);
+ _externalAPI = new ExternalAPI(new VBETypeLibsAPI_Object(_vbe));
+ _addin.Object = _externalAPI;
}
private Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
@@ -239,6 +243,8 @@ private void Startup()
_app = _container.Resolve();
_app.Startup();
+ InitializeExternalAPI();
+
_isInitialized = true;
}
catch (Exception e)
@@ -248,6 +254,11 @@ private void Startup()
}
}
+ private void InitializeExternalAPI()
+ {
+ _externalAPI.InitializeAPIs(_container.Resolve());
+ }
+
private void HandleAppDomainException(object sender, UnhandledExceptionEventArgs e)
{
var message = e.IsTerminating
diff --git a/Rubberduck.Main/ExternalAPIs/ExternalAPI.cs b/Rubberduck.Main/ExternalAPIs/ExternalAPI.cs
new file mode 100644
index 0000000000..e90900303c
--- /dev/null
+++ b/Rubberduck.Main/ExternalAPIs/ExternalAPI.cs
@@ -0,0 +1,66 @@
+using Rubberduck.Resources.Registration;
+using Rubberduck.UnitTesting;
+using Rubberduck.VBEditor.ComManagement.TypeLibs;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Rubberduck.ExternalApi
+{
+ [
+ ComVisible(true),
+ Guid(RubberduckGuid.IExternalAPIInterfaceGuid),
+ InterfaceType(ComInterfaceType.InterfaceIsDual),
+ EditorBrowsable(EditorBrowsableState.Always)
+ ]
+ public interface IExternalAPI
+ {
+ [DispId(1)]
+ void InitializeAPIs(ITestEngine testEngine);
+ [DispId(2)]
+ ITestEngineAPI TestEngineAPI { get; }
+ [DispId(3)]
+ IVBETypeLibsAPI_Object VBETypeLibsAPI { get; }
+ }
+
+ [
+ ComVisible(true),
+ Guid(RubberduckGuid.ExternalAPIObjectGuid),
+ ProgId(RubberduckProgId.ExternalAPIObject),
+ ClassInterface(ClassInterfaceType.None),
+ ComDefaultInterface(typeof(IExternalAPI)),
+ EditorBrowsable(EditorBrowsableState.Always)
+ ]
+ public class ExternalAPI : IExternalAPI
+ {
+ private readonly IVBETypeLibsAPI_Object _vbeTypeLibsAPI_Object;
+ private ITestEngineAPI _testEngineAPI;
+
+ public ExternalAPI(IVBETypeLibsAPI_Object vbeTypeLibsAPI_Object)
+ {
+ _vbeTypeLibsAPI_Object = vbeTypeLibsAPI_Object;
+ }
+
+ public void InitializeAPIs(ITestEngine testEngine)
+ {
+ _testEngineAPI = new TestEngineAPI(testEngine);
+ }
+
+ public IVBETypeLibsAPI_Object VBETypeLibsAPI { get => _vbeTypeLibsAPI_Object; }
+ public ITestEngineAPI TestEngineAPI
+ {
+ get
+ {
+ if (_testEngineAPI == null)
+ {
+ throw new InvalidOperationException("TestEngineAPI is not initialized.");
+ }
+ return _testEngineAPI;
+ }
+ }
+ }
+}
diff --git a/Rubberduck.Main/ExternalAPIs/TestEngineAPI.cs b/Rubberduck.Main/ExternalAPIs/TestEngineAPI.cs
new file mode 100644
index 0000000000..b90355d8a6
--- /dev/null
+++ b/Rubberduck.Main/ExternalAPIs/TestEngineAPI.cs
@@ -0,0 +1,66 @@
+using Rubberduck.InternalApi.Common;
+using Rubberduck.Resources.Registration;
+using Rubberduck.UnitTesting;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Rubberduck.ExternalApi
+{
+ [
+ ComVisible(true),
+ Guid(RubberduckGuid.ITestEngineAPIInterfaceGuid),
+ InterfaceType(ComInterfaceType.InterfaceIsDual),
+ EditorBrowsable(EditorBrowsableState.Always)
+ ]
+ public interface ITestEngineAPI
+ {
+ [DispId(1)]
+ string RunAllTestsAndGetResults(string filePath);
+ }
+
+ [
+ ComVisible(true),
+ Guid(RubberduckGuid.TestEngineAPIObjectGuid),
+ ProgId(RubberduckProgId.TestEngineAPIProgId),
+ ClassInterface(ClassInterfaceType.None),
+ ComDefaultInterface(typeof(ITestEngineAPI)),
+ EditorBrowsable(EditorBrowsableState.Always)
+ ]
+ public class TestEngineAPI : ITestEngineAPI
+ {
+ private readonly ITestEngine _testEngine;
+
+ public TestEngineAPI(ITestEngine testEngine)
+ {
+ _testEngine = testEngine;
+ }
+
+ ///
+ /// Runs all unit tests and returns the results as a formatted string.
+ ///
+ /// A string containing the test results.
+ public string RunAllTestsAndGetResults(string logPath)
+ {
+
+ // Note that we can't use CanRun in case we are triggering the test via VBA since DesignMode is always set to false when you run a macro.
+ // and CanRun interprets this as "not ready to run tests".
+
+ var task = Task.Run(() => {
+ var output = _testEngine.RunWithResults(_testEngine.Tests);
+ if (!string.IsNullOrEmpty(logPath))
+ {
+ FileSystemProvider.FileSystem.File.WriteAllText(logPath, output.ToString());
+ }
+ });
+
+ return "Task started to run tests asynchronously. Check the log file for results.";
+
+ }
+ }
+
+}
diff --git a/Rubberduck.Resources/Registration/RubberduckGuid.cs b/Rubberduck.Resources/Registration/RubberduckGuid.cs
index 1429bc8307..638c7c04ef 100644
--- a/Rubberduck.Resources/Registration/RubberduckGuid.cs
+++ b/Rubberduck.Resources/Registration/RubberduckGuid.cs
@@ -71,7 +71,7 @@ public static class RubberduckGuid
public const string ITimesGuid = UnitTestingGuidspace + "EE" + GuidSuffix;
public const string TimesGuid = UnitTestingGuidspace + "EF" + GuidSuffix;
- // Rubberduck API Guids:
+ // Rubberduck Internal API Guids:
private const string ApiGuidspace = "69E0F7";
public const string IDeclarationGuid = ApiGuidspace + "81" + GuidSuffix;
public const string DeclarationClassGuid = ApiGuidspace + "82" + GuidSuffix;
@@ -87,6 +87,12 @@ public static class RubberduckGuid
public const string IIdentifierReferencesGuid = ApiGuidspace + "8C" + GuidSuffix;
public const string IdentifierReferencesClassGuid = ApiGuidspace + "8D" + GuidSuffix;
+ // Rubberduck External API Guids:
+ public const string ExternalAPIObjectGuid = ApiGuidspace + "A0" + GuidSuffix;
+ public const string IExternalAPIInterfaceGuid = ApiGuidspace + "A1" + GuidSuffix;
+ public const string TestEngineAPIObjectGuid = ApiGuidspace + "A2" + GuidSuffix;
+ public const string ITestEngineAPIInterfaceGuid = ApiGuidspace + "A3" + GuidSuffix;
+
// Enum Guids:
private const string RecordGuidspace = "69E100";
public const string DeclarationTypeGuid = RecordGuidspace + "23" + GuidSuffix;
diff --git a/Rubberduck.Resources/Registration/RubberduckProgId.cs b/Rubberduck.Resources/Registration/RubberduckProgId.cs
index fdb3b18419..d79e83564a 100644
--- a/Rubberduck.Resources/Registration/RubberduckProgId.cs
+++ b/Rubberduck.Resources/Registration/RubberduckProgId.cs
@@ -50,5 +50,8 @@ public static class RubberduckProgId
public const string TimesProgId = BaseNamespace + "Times";
public const string DebugAddinObject = BaseNamespace + "VBETypeLibsAPI";
+
+ public const string ExternalAPIObject = BaseNamespace + "ExternalAPI";
+ public const string TestEngineAPIProgId = BaseNamespace + "TestEngineAPI";
}
}
diff --git a/Rubberduck.UnitTesting/UnitTesting/ITestEngine.cs b/Rubberduck.UnitTesting/UnitTesting/ITestEngine.cs
index c47a639cb3..7a134aa700 100644
--- a/Rubberduck.UnitTesting/UnitTesting/ITestEngine.cs
+++ b/Rubberduck.UnitTesting/UnitTesting/ITestEngine.cs
@@ -17,6 +17,7 @@ public interface ITestEngine
bool CanRun { get; }
bool CanRepeatLastRun { get; }
void Run(IEnumerable tests);
+ string RunWithResults(IEnumerable tests);
void RunByOutcome(TestOutcome outcome);
void RepeatLastRun();
void RequestCancellation();
diff --git a/Rubberduck.UnitTesting/UnitTesting/TestEngine.cs b/Rubberduck.UnitTesting/UnitTesting/TestEngine.cs
index 6a79d7b644..40bd124678 100644
--- a/Rubberduck.UnitTesting/UnitTesting/TestEngine.cs
+++ b/Rubberduck.UnitTesting/UnitTesting/TestEngine.cs
@@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Text;
using System.Threading.Tasks;
using NLog;
using Rubberduck.InternalApi.Extensions;
@@ -15,6 +16,7 @@
using Rubberduck.VBEditor.ComManagement;
using Rubberduck.VBEditor.ComManagement.TypeLibs.Abstract;
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
+using Rubberduck.InternalApi.Common;
namespace Rubberduck.UnitTesting
{
@@ -158,6 +160,103 @@ public void Run(IEnumerable tests)
RunInternal(queued);
});
}
+ public string RunWithResults(IEnumerable tests)
+ {
+ if (tests == null)
+ {
+ // Trigger the ParseRequest programmatically to make the Tests property available.
+ var parseCompletion = new TaskCompletionSource();
+ EventHandler parseCompletedHandler = null;
+
+ parseCompletedHandler = (sender, args) =>
+ {
+ if (args.State == ParserState.Ready)
+ {
+ _state.StateChanged -= parseCompletedHandler; // Unsubscribe from the event
+ parseCompletion.SetResult(true); // Signal that parsing is complete
+ }
+ };
+
+ _state.StateChanged += parseCompletedHandler;
+ _state.OnParseRequested(this);
+
+ parseCompletion.Task.Wait();
+
+ tests = Tests;
+ }
+
+ var queued = tests.ToList();
+ var results = new List();
+
+ foreach (var test in queued.Where(item => _knownOutcomes.ContainsKey(item)))
+ {
+ _knownOutcomes.Remove(test);
+ }
+
+ Task.Run(() =>
+ {
+ var suspensionResult = _state.OnSuspendParser(this, AllowedRunStates, () =>
+ {
+ results.AddRange(RunWhileSuspendedWithResults(tests));
+ });
+
+ switch (suspensionResult.Outcome)
+ {
+ case SuspensionOutcome.Completed:
+ break;
+ case SuspensionOutcome.Canceled:
+ Logger.Debug("Test execution canceled.");
+ break;
+ default:
+ Logger.Warn($"Test execution failed with suspension outcome {suspensionResult.Outcome}.");
+ if (suspensionResult.EncounteredException != null)
+ {
+ Logger.Error(suspensionResult.EncounteredException);
+ }
+ break;
+ }
+ }).GetAwaiter().GetResult(); // Ensure the task completes before returning results.
+
+ var resultBuilder = new StringLineBuilder();
+ foreach (var result in results)
+ {
+ // Get the TestName, but stop at the first \r\n to get only the signature
+ int index = result.TestName.IndexOf("\r\n");
+ var signature = index >= 0 ? result.TestName.Substring(0, index) : result.TestName;
+ resultBuilder.AppendLine($"{result.Result.Outcome}: {signature}");
+ }
+
+ return resultBuilder.ToString();
+ }
+
+ private IEnumerable RunWhileSuspendedWithResults(IEnumerable tests)
+ {
+ var results = new List();
+
+ var testTask = _uiDispatcher.StartTask(() =>
+ {
+ results.AddRange(RunWhileSuspendedOnUiThread(tests));
+ });
+ testTask.Wait();
+
+ return results;
+ }
+
+ private T TestResultOrTestInfo(TestMethod test, TestResult testResult)
+ {
+ if (typeof(T) == typeof(TestResult))
+ {
+ return (T)(object)testResult;
+ }
+ else if (typeof(T) == typeof(TestInfo))
+ {
+ return (T)(object)new TestInfo(test.TestCode, testResult);
+ }
+ else
+ {
+ throw new InvalidOperationException("Unsupported type for test result.");
+ }
+ }
public void RunByOutcome(TestOutcome outcome)
{
@@ -235,10 +334,16 @@ protected void RunWhileSuspended(IEnumerable tests)
private void RunWhileSuspendedOnUiThread(IEnumerable tests)
{
+ RunWhileSuspendedOnUiThread(tests);
+ }
+
+ private IEnumerable RunWhileSuspendedOnUiThread(IEnumerable tests)
+ {
+ var results = new List();
var testMethods = tests as IList ?? tests.ToList();
if (!testMethods.Any())
{
- return;
+ return results;
}
_lastRun.Clear();
@@ -252,9 +357,12 @@ private void RunWhileSuspendedOnUiThread(IEnumerable tests)
Logger.Warn(e);
foreach (var test in testMethods)
{
- OnTestCompleted(test, new TestResult(TestOutcome.Failed, AssertMessages.Prerequisite_EarlyBindingReferenceMissing));
+ var testResult = new TestResult(TestOutcome.Failed, AssertMessages.Prerequisite_EarlyBindingReferenceMissing);
+ var result = TestResultOrTestInfo(test, testResult);
+ OnTestCompleted(test, testResult);
+ results.Add(result);
}
- return;
+ return results;
}
var overallTime = new Stopwatch();
@@ -283,7 +391,9 @@ private void RunWhileSuspendedOnUiThread(IEnumerable tests)
Logger.Error(ex, "Unexpected COM exception while initializing tests for module {0}. The module will be skipped.", moduleName.Name);
foreach (var method in moduleTestMethods)
{
- OnTestCompleted(method, new TestResult(TestOutcome.Unknown, AssertMessages.TestRunner_ModuleInitializeFailure));
+ var result = new TestResult(TestOutcome.Unknown, AssertMessages.TestRunner_ModuleInitializeFailure);
+ OnTestCompleted(method, result);
+ results.Add(TestResultOrTestInfo(method, result));
}
continue;
}
@@ -294,7 +404,9 @@ private void RunWhileSuspendedOnUiThread(IEnumerable tests)
// no need to run setup/teardown for ignored tests
if (test.Declaration.Annotations.Any(a => a.Annotation is IgnoreTestAnnotation))
{
- OnTestCompleted(test, new TestResult(TestOutcome.Ignored));
+ var result = new TestResult(TestOutcome.Ignored);
+ OnTestCompleted(test, result);
+ results.Add(TestResultOrTestInfo(test, result));
continue;
}
@@ -307,7 +419,9 @@ private void RunWhileSuspendedOnUiThread(IEnumerable tests)
}
catch (COMException trace)
{
- OnTestCompleted(test, new TestResult(TestOutcome.Inconclusive, AssertMessages.TestRunner_TestInitializeFailure));
+ var newResult = new TestResult(TestOutcome.Inconclusive, AssertMessages.TestRunner_TestInitializeFailure);
+ OnTestCompleted(test, newResult);
+ results.Add(TestResultOrTestInfo(test, newResult));
Logger.Trace(trace, "Unexpected COMException when running TestInitialize");
continue;
}
@@ -328,6 +442,7 @@ private void RunWhileSuspendedOnUiThread(IEnumerable tests)
// we can trigger this event, because cleanup can fail without affecting the result
OnTestCompleted(test, result);
+ results.Add(TestResultOrTestInfo(test, result));
RunTestCleanup(typeLibWrapper, testCleanup);
}
@@ -354,13 +469,15 @@ private void RunWhileSuspendedOnUiThread(IEnumerable tests)
catch (Exception ex)
{
// FIXME somehow notify the user of this mess
- Logger.Error(ex, "Unexpected expection while running unit tests; unit tests will be aborted");
+ Logger.Error(ex, "Unexpected exception while running unit tests; unit tests will be aborted");
}
CancellationRequested = false;
overallTime.Stop();
TestRunCompleted?.Invoke(this, new TestRunCompletedEventArgs(overallTime.ElapsedMilliseconds));
+
+ return results;
}
private void RunTestCleanup(ITypeLibWrapper wrapper, List cleanupMethods)
diff --git a/Rubberduck.UnitTesting/UnitTesting/TestResult.cs b/Rubberduck.UnitTesting/UnitTesting/TestResult.cs
index d3f0ed5aa0..6ba20ac2ac 100644
--- a/Rubberduck.UnitTesting/UnitTesting/TestResult.cs
+++ b/Rubberduck.UnitTesting/UnitTesting/TestResult.cs
@@ -24,4 +24,23 @@ public override bool Equals(object obj)
&& Output == other.Output;
}
}
+
+ public readonly struct TestInfo
+ {
+ public TestInfo(string testName, TestResult result)
+ {
+ TestName = testName;
+ Result = result;
+ }
+ public string TestName { get; }
+ public TestResult Result { get; }
+ public override int GetHashCode() => HashCode.Compute(TestName, Result);
+ public override bool Equals(object obj)
+ {
+ return obj is TestInfo other
+ && TestName == other.TestName
+ && Result.Equals(other.Result);
+ }
+
+ }
}
diff --git a/Rubberduck.VBEEditor/ComManagement/TypeLibs/Public/TypeLibsAPI.cs b/Rubberduck.VBEEditor/ComManagement/TypeLibs/Public/TypeLibsAPI.cs
index 0e3f527445..a524735115 100644
--- a/Rubberduck.VBEEditor/ComManagement/TypeLibs/Public/TypeLibsAPI.cs
+++ b/Rubberduck.VBEEditor/ComManagement/TypeLibs/Public/TypeLibsAPI.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
+using System.Threading.Tasks;
using Rubberduck.InternalApi.Common;
using Rubberduck.Resources.Registration;
using Rubberduck.VBEditor.ComManagement.TypeLibs.Abstract;
@@ -68,6 +69,7 @@ public class VBETypeLibsAPI_Object : IVBETypeLibsAPI_Object
{
private IVBE _ide;
private readonly VBETypeLibsAPI _api;
+ private object _testEngineProvider;
public VBETypeLibsAPI_Object(IVBE ide)
{
diff --git a/Rubberduck.VBEEditor/ComManagement/TypeLibs/Utility/DocClassHelper.cs b/Rubberduck.VBEEditor/ComManagement/TypeLibs/Utility/DocClassHelper.cs
index 1a7c4bda77..566e7c74f0 100644
--- a/Rubberduck.VBEEditor/ComManagement/TypeLibs/Utility/DocClassHelper.cs
+++ b/Rubberduck.VBEEditor/ComManagement/TypeLibs/Utility/DocClassHelper.cs
@@ -3,22 +3,6 @@
namespace Rubberduck.VBEditor.ComManagement.TypeLibs.Utility
{
- ///
- /// Extension to StringBuilder to allow adding text line by line.
- ///
- internal class StringLineBuilder
- {
- private readonly StringBuilder _document = new StringBuilder();
-
- public override string ToString() => _document.ToString();
-
- public void AppendLine(string value = "")
- => _document.Append(value + "\r\n");
-
- public void AppendLineNoNullChars(string value)
- => AppendLine(value.Replace("\0", string.Empty));
- }
-
///
/// An enumeration used for identifying the type of a VBA document class
///
diff --git a/Rubberduck.VBEEditor/ComManagement/TypeLibs/Utility/TypeInfoDocumentationExtensions.cs b/Rubberduck.VBEEditor/ComManagement/TypeLibs/Utility/TypeInfoDocumentationExtensions.cs
index aea0c3c014..ae671168a7 100644
--- a/Rubberduck.VBEEditor/ComManagement/TypeLibs/Utility/TypeInfoDocumentationExtensions.cs
+++ b/Rubberduck.VBEEditor/ComManagement/TypeLibs/Utility/TypeInfoDocumentationExtensions.cs
@@ -1,4 +1,5 @@
using Rubberduck.VBEditor.ComManagement.TypeLibs.Abstract;
+using Rubberduck.InternalApi.Common;
namespace Rubberduck.VBEditor.ComManagement.TypeLibs.Utility
{