Skip to content

Commit c337646

Browse files
authored
Merge pull request #4784 from bclothier/MiscBugFixes
Misc bug fixes
2 parents 3d870f7 + 5cae35b commit c337646

File tree

25 files changed

+533
-70
lines changed

25 files changed

+533
-70
lines changed

Rubberduck.CodeAnalysis/Inspections/Concrete/AssignmentNotUsedInspection.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
using Rubberduck.Parsing.Symbols;
77
using Rubberduck.Inspections.CodePathAnalysis.Extensions;
88
using System.Linq;
9-
using Rubberduck.Inspections.CodePathAnalysis.Nodes;
109
using Rubberduck.Inspections.Results;
11-
using Rubberduck.Parsing;
1210
using Rubberduck.Parsing.Grammar;
1311

1412
namespace Rubberduck.Inspections.Concrete
@@ -40,8 +38,11 @@ protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
4038

4139
var tree = _walker.GenerateTree(parentScopeDeclaration.Context, variable);
4240

43-
44-
nodes.AddRange(tree.GetIdentifierReferences());
41+
var references = tree.GetIdentifierReferences();
42+
// ignore set-assignments to 'Nothing'
43+
nodes.AddRange(references.Where(r =>
44+
!(r.Context.Parent is VBAParser.SetStmtContext setStmtContext &&
45+
setStmtContext.expression().GetText().Equals(Tokens.Nothing))));
4546
}
4647

4748
return nodes

Rubberduck.CodeAnalysis/Inspections/Concrete/FunctionReturnValueNotUsedInspection.cs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,14 @@ private bool IsRecursive(Declaration function)
7575

7676
private bool IsReturnValueUsed(Declaration function)
7777
{
78+
// TODO: This is O(MG) at work here. Need to refactor the whole shebang.
7879
return (from usage in function.References
79-
where !IsAddressOfCall(usage)
80-
where !IsTypeOfExpression(usage)
81-
where !IsCallStmt(usage)
82-
where !IsLet(usage)
83-
where !IsSet(usage)
84-
select usage).Any(usage => !IsReturnStatement(function, usage));
80+
where !IsLet(usage)
81+
where !IsSet(usage)
82+
where !IsCallStmt(usage)
83+
where !IsTypeOfExpression(usage)
84+
where !IsAddressOfCall(usage)
85+
select usage).Any(usage => !IsReturnStatement(function, usage));
8586
}
8687

8788
private bool IsAddressOfCall(IdentifierReference usage)
@@ -93,7 +94,7 @@ private bool IsTypeOfExpression(IdentifierReference usage)
9394
{
9495
return usage.Context.IsDescendentOf<VBAParser.TypeofexprContext>();
9596
}
96-
97+
9798
private bool IsReturnStatement(Declaration function, IdentifierReference assignment)
9899
{
99100
return assignment.ParentScoping.Equals(function) && assignment.Declaration.Equals(function);
@@ -111,6 +112,19 @@ private bool IsCallStmt(IdentifierReference usage)
111112
{
112113
return false;
113114
}
115+
116+
var indexExpr = usage.Context.GetAncestor<VBAParser.IndexExprContext>();
117+
if (indexExpr != null)
118+
{
119+
var memberAccessStmt = usage.Context.GetAncestor<VBAParser.MemberAccessExprContext>();
120+
if (memberAccessStmt != null &&
121+
callStmt.SourceInterval.ProperlyContains(memberAccessStmt.SourceInterval) &&
122+
memberAccessStmt.SourceInterval.ProperlyContains(indexExpr.SourceInterval))
123+
{
124+
return false;
125+
}
126+
}
127+
114128
var argumentList = CallStatement.GetArgumentList(callStmt);
115129
if (argumentList == null)
116130
{

Rubberduck.Core/Navigation/CodeExplorer/CodeExplorerComponentViewModel.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,12 @@ private void SetName()
103103
case ComponentType.Document:
104104
using (var app = _vbe?.HostApplication())
105105
{
106-
var parenthesized = app?.GetDocument(qualifiedModuleName)?.DocumentName ?? string.Empty;
107-
_name = string.IsNullOrEmpty(parenthesized) ? _name : $"{_name} ({parenthesized})";
106+
var document = app?.GetDocument(qualifiedModuleName);
107+
if (document != null)
108+
{
109+
var parenthesized = document.DocumentName ?? string.Empty;
110+
_name = string.IsNullOrEmpty(parenthesized) ? _name : $"{_name} ({parenthesized})";
111+
}
108112
}
109113

110114
break;

Rubberduck.Core/UI/CodeExplorer/Commands/OpenDesignerCommand.cs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using Rubberduck.Navigation.CodeExplorer;
55
using Rubberduck.Parsing.Symbols;
66
using Rubberduck.VBEditor.ComManagement;
7+
using Rubberduck.VBEditor.SafeComWrappers;
8+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
79

810
namespace Rubberduck.UI.CodeExplorer.Commands
911
{
@@ -16,10 +18,12 @@ public class OpenDesignerCommand : CodeExplorerCommandBase
1618
};
1719

1820
private readonly IProjectsProvider _projectsProvider;
21+
private readonly IVBE _vbe;
1922

20-
public OpenDesignerCommand(IProjectsProvider projectsProvider)
23+
public OpenDesignerCommand(IProjectsProvider projectsProvider, IVBE vbe)
2124
{
2225
_projectsProvider = projectsProvider;
26+
_vbe = vbe;
2327
}
2428

2529
public sealed override IEnumerable<Type> ApplicableNodeTypes => ApplicableNodes;
@@ -34,8 +38,26 @@ protected override bool EvaluateCanExecute(object parameter)
3438
try
3539
{
3640
var declaration = node.Declaration;
37-
return declaration != null && declaration.DeclarationType == DeclarationType.ClassModule &&
38-
_projectsProvider.Component(declaration.QualifiedName.QualifiedModuleName).HasDesigner;
41+
if (declaration == null)
42+
{
43+
return false;
44+
}
45+
46+
var qualifiedModuleName = declaration.QualifiedModuleName;
47+
48+
// ReSharper disable once SwitchStatementMissingSomeCases
49+
switch (declaration.DeclarationType)
50+
{
51+
case DeclarationType.ClassModule when qualifiedModuleName.ComponentType != ComponentType.Document:
52+
return _projectsProvider.Component(qualifiedModuleName).HasDesigner;
53+
case DeclarationType.ClassModule:
54+
using (var app = _vbe.HostApplication())
55+
{
56+
return app?.CanOpenDocumentDesigner(qualifiedModuleName) ?? false;
57+
}
58+
default:
59+
return false;
60+
}
3961
}
4062
catch (COMException)
4163
{
@@ -46,11 +68,25 @@ protected override bool EvaluateCanExecute(object parameter)
4668

4769
protected override void OnExecute(object parameter)
4870
{
49-
if (!base.EvaluateCanExecute(parameter) || !(parameter is CodeExplorerItemViewModel node) || node.Declaration == null)
71+
if (!base.EvaluateCanExecute(parameter) ||
72+
!(parameter is CodeExplorerItemViewModel node) ||
73+
node.Declaration == null ||
74+
node.Declaration.DeclarationType != DeclarationType.ClassModule)
5075
{
5176
return;
5277
}
5378

79+
if(node.Declaration.QualifiedModuleName.ComponentType == ComponentType.Document)
80+
{
81+
using (var app = _vbe.HostApplication())
82+
{
83+
if (app?.TryOpenDocumentDesigner(node.Declaration.QualifiedModuleName) ?? false)
84+
{
85+
return;
86+
}
87+
}
88+
}
89+
5490
var component = _projectsProvider.Component(node.Declaration.QualifiedName.QualifiedModuleName);
5591
using (var designer = component.DesignerWindow())
5692
{

Rubberduck.Deployment.Build/RubberduckPostBuildTask.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,40 @@ private void CreateIdlFile(DllFileParameters parameters)
240240

241241
private void CompileWithMidl(DllFileParameters parameters, string batchPath)
242242
{
243-
var targetPath = TargetDir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
243+
var targetPath = Path.Combine(Path.GetTempPath(), "RubberduckMidl");
244+
if (Directory.Exists(targetPath))
245+
{
246+
Directory.Delete(targetPath, true);
247+
}
248+
Directory.CreateDirectory(targetPath);
249+
250+
targetPath = targetPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
251+
244252
var command = $"call \"{batchPath}\"{Environment.NewLine}" +
245253
$"midl.exe /win32 /tlb \"{parameters.Tlb32File}\" \"{parameters.IdlFile}\" /out \"{targetPath}\"{Environment.NewLine}" +
246254
$"midl.exe /amd64 /tlb \"{parameters.Tlb64File}\" \"{parameters.IdlFile}\" /out \"{targetPath}\"";
247255
ExecuteTask(command, SourceDir);
256+
257+
MoveFileWithOverwrite(Path.Combine(targetPath, parameters.Tlb32File), Path.Combine(TargetDir, parameters.Tlb32File));
258+
MoveFileWithOverwrite(Path.Combine(targetPath, parameters.Tlb64File), Path.Combine(TargetDir, parameters.Tlb64File));
259+
260+
try
261+
{
262+
Directory.Delete(targetPath, true);
263+
}
264+
catch (Exception ex)
265+
{
266+
this.LogMessage($"Unable to delete temporary working directory: {targetPath}. Exception: {ex}");
267+
}
268+
}
269+
270+
private static void MoveFileWithOverwrite(string sourceFile, string destFile)
271+
{
272+
if (File.Exists(destFile))
273+
{
274+
File.Delete(destFile);
275+
}
276+
File.Move(sourceFile, destFile);
248277
}
249278

250279
private void CompileWithTlbExp(DllFileParameters parameters)

Rubberduck.Main/Extension.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using Rubberduck.VBEditor.ComManagement;
2222
using Rubberduck.VBEditor.Events;
2323
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
24+
using Rubberduck.VBEditor.VbeRuntime;
2425

2526
namespace Rubberduck
2627
{
@@ -40,6 +41,7 @@ public class _Extension : IDTExtensibility2
4041
{
4142
private IVBE _vbe;
4243
private IAddIn _addin;
44+
private IVbeNativeApi _vbeNativeApi;
4345
private bool _isInitialized;
4446
private bool _isBeginShutdownExecuted;
4547

@@ -63,6 +65,7 @@ public void OnConnection(object Application, ext_ConnectMode ConnectMode, object
6365
VbeProvider.Initialize(_vbe);
6466
VbeNativeServices.HookEvents(_vbe);
6567

68+
_vbeNativeApi = VbeProvider.VbeRuntime;
6669
#if DEBUG
6770
// FOR DEBUGGING/DEVELOPMENT PURPOSES, ALLOW ACCESS TO SOME VBETypeLibsAPI FEATURES FROM VBA
6871
_addin.Object = new VBEditor.ComManagement.TypeLibsAPI.VBETypeLibsAPI_Object(_vbe);
@@ -227,7 +230,7 @@ private void Startup()
227230
currentDomain.UnhandledException += HandlAppDomainException;
228231
currentDomain.AssemblyResolve += LoadFromSameFolder;
229232

230-
_container = new WindsorContainer().Install(new RubberduckIoCInstaller(_vbe, _addin, _initialSettings));
233+
_container = new WindsorContainer().Install(new RubberduckIoCInstaller(_vbe, _addin, _initialSettings, _vbeNativeApi));
231234

232235
_app = _container.Resolve<App>();
233236
_app.Startup();

Rubberduck.Main/Root/RubberduckIoCInstaller.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,7 @@
5454
using Rubberduck.VBEditor.Utility;
5555
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
5656
using Rubberduck.VBEditor.SourceCodeHandling;
57-
using Rubberduck.Parsing.VBA.DeclarationCaching;
58-
using Rubberduck.Parsing.VBA.Parsing.ParsingExceptions;
59-
using Rubberduck.UI.AddRemoveReferences;
57+
using Rubberduck.VBEditor.VbeRuntime;
6058
using Rubberduck.UnitTesting.Settings;
6159

6260
namespace Rubberduck.Root
@@ -66,12 +64,14 @@ public class RubberduckIoCInstaller : IWindsorInstaller
6664
private readonly IVBE _vbe;
6765
private readonly IAddIn _addin;
6866
private readonly GeneralSettings _initialSettings;
67+
private readonly IVbeNativeApi _vbeNativeApi;
6968

70-
public RubberduckIoCInstaller(IVBE vbe, IAddIn addin, GeneralSettings initialSettings)
69+
public RubberduckIoCInstaller(IVBE vbe, IAddIn addin, GeneralSettings initialSettings, IVbeNativeApi vbeNativeApi)
7170
{
7271
_vbe = vbe;
7372
_addin = addin;
7473
_initialSettings = initialSettings;
74+
_vbeNativeApi = vbeNativeApi;
7575
}
7676

7777
//Guidelines and words of caution:
@@ -959,6 +959,7 @@ private void RegisterInstances(IWindsorContainer container)
959959
container.Register(Component.For<IVBEEvents>().Instance(VBEEvents.Initialize(_vbe)).LifestyleSingleton());
960960
container.Register(Component.For<ITempSourceFileHandler>().Instance(_vbe.TempSourceFileHandler).LifestyleSingleton());
961961
container.Register(Component.For<IPersistancePathProvider>().Instance(PersistancePathProvider.Instance).LifestyleSingleton());
962+
container.Register(Component.For<IVbeNativeApi>().Instance(_vbeNativeApi).LifestyleSingleton());
962963
}
963964
}
964965
}

Rubberduck.Parsing/VBA/DeclarationCaching/DeclarationFinder.cs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,23 +1199,34 @@ private List<Declaration> FindAllEventHandlers()
11991199

12001200
var handlers = DeclarationsWithType(DeclarationType.Procedure)
12011201
.Where(item =>
1202-
// class module built-in events
1203-
(item.ParentDeclaration.DeclarationType == DeclarationType.ClassModule && (
1204-
item.IdentifierName.Equals("Class_Initialize", StringComparison.InvariantCultureIgnoreCase) ||
1205-
item.IdentifierName.Equals("Class_Terminate", StringComparison.InvariantCultureIgnoreCase))) ||
1206-
// standard module built-in handlers (Excel specific):
1207-
(_hostApp != null &&
1208-
_hostApp.ApplicationName.Equals("Excel", StringComparison.InvariantCultureIgnoreCase) &&
1209-
item.ParentDeclaration.DeclarationType == DeclarationType.ProceduralModule && (
1210-
item.IdentifierName.Equals("auto_open", StringComparison.InvariantCultureIgnoreCase) ||
1211-
item.IdentifierName.Equals("auto_close", StringComparison.InvariantCultureIgnoreCase))))
1202+
IsVBAClassSpecificHandler(item) ||
1203+
IsHostSpecificHandler(item))
12121204
.Concat(
12131205
UserDeclarations(DeclarationType.Procedure)
12141206
.Where(item => handlerNames.Contains(item.IdentifierName))
12151207
)
12161208
.Concat(_handlersByWithEventsField.Value.AllValues())
12171209
.Concat(FindAllFormControlHandlers());
12181210
return handlers.ToList();
1211+
1212+
// Local functions to help break up the complex logic in finding built-in handlers
1213+
bool IsVBAClassSpecificHandler(Declaration item)
1214+
{
1215+
return item.ParentDeclaration.DeclarationType == DeclarationType.ClassModule && (
1216+
item.IdentifierName.Equals("Class_Initialize",
1217+
StringComparison.InvariantCultureIgnoreCase) ||
1218+
item.IdentifierName.Equals("Class_Terminate", StringComparison.InvariantCultureIgnoreCase));
1219+
}
1220+
1221+
bool IsHostSpecificHandler(Declaration item)
1222+
{
1223+
return _hostApp?.AutoMacroIdentifiers.Any(i =>
1224+
i.ComponentTypes.Any(t => t == item.QualifiedModuleName.ComponentType) &&
1225+
(item.Accessibility != Accessibility.Private || i.MayBePrivate) &&
1226+
(i.ModuleName == null || i.ModuleName == item.QualifiedModuleName.ComponentName) &&
1227+
(i.ProcedureName == null || i.ProcedureName == item.IdentifierName)
1228+
) ?? false;
1229+
}
12191230
}
12201231

12211232
/// <summary>

Rubberduck.VBEEditor/SafeComWrappers/Abstract/HostApplicationBase.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,18 @@ public virtual HostDocument GetDocument(QualifiedModuleName moduleName)
173173
return null;
174174
}
175175

176+
public virtual bool CanOpenDocumentDesigner(QualifiedModuleName moduleName)
177+
{
178+
return false;
179+
}
180+
181+
public virtual bool TryOpenDocumentDesigner(QualifiedModuleName moduleName)
182+
{
183+
return false;
184+
}
185+
186+
public virtual IEnumerable<HostAutoMacro> AutoMacroIdentifiers => null;
187+
176188
private static string GetName(IVBComponent component)
177189
{
178190
var name = string.Empty;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System.Collections.Generic;
2+
3+
namespace Rubberduck.VBEditor.SafeComWrappers.Abstract
4+
{
5+
/// <summary>
6+
/// Provide information about naming schemes that the host
7+
/// may use to identify a VBA procedure used as part of
8+
/// automatic execution via macros (e.g. Excel's auto_open or
9+
/// Word's AutoOpen
10+
/// </summary>
11+
public readonly struct HostAutoMacro
12+
{
13+
/// <summary>
14+
/// Enumerates all component types that the host may search for such auto macro
15+
/// </summary>
16+
public IEnumerable<ComponentType> ComponentTypes { get; }
17+
18+
/// <summary>
19+
/// Indicates whether host will require public access or may ignore the access modifier
20+
/// </summary>
21+
public bool MayBePrivate { get; }
22+
23+
/// <summary>
24+
/// If the host requires the module to have a specific name, this should be specified.
25+
/// Otherwise leave null. The procedure name must be specified in this case.
26+
/// </summary>
27+
public string ModuleName { get; }
28+
29+
/// <summary>
30+
/// If the host requires the procedure to have a specific name, this should be
31+
/// specified. Otherwise leave null. The module name must be specified in this case.
32+
/// </summary>
33+
public string ProcedureName { get; }
34+
35+
public HostAutoMacro(IEnumerable<ComponentType> componentTypes, bool mayBePrivate, string moduleName,
36+
string procedureName)
37+
{
38+
ComponentTypes = componentTypes;
39+
MayBePrivate = mayBePrivate;
40+
ModuleName = moduleName;
41+
ProcedureName = procedureName;
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)