Skip to content

Commit c749555

Browse files
committed
resolve document modules' subclass (implemented for Excel host)
1 parent 5ff6dc0 commit c749555

File tree

11 files changed

+232
-21
lines changed

11 files changed

+232
-21
lines changed

Rubberduck.Parsing/Emitter.cs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using System.Diagnostics;
2+
using System.Runtime.InteropServices;
3+
using Rubberduck.Parsing.Grammar;
4+
using Rubberduck.Parsing.VBA;
5+
using Rubberduck.VBEditor.SafeComWrappers;
6+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
7+
8+
namespace Rubberduck.Parsing
9+
{
10+
public class Emitter
11+
{
12+
private readonly RubberduckParserState _state;
13+
14+
public Emitter(RubberduckParserState state)
15+
{
16+
_state = state;
17+
}
18+
19+
private static readonly string TempModuleName = "Rubberduck___0";
20+
21+
private static readonly string GetTypeNameFunctionTemplate = @"
22+
Public Function GetTypeName() As String
23+
GetTypeName = TypeName({0})
24+
End Function
25+
";
26+
27+
public string GetTypeNameFunctionBody(string arg)
28+
{
29+
return string.Format(GetTypeNameFunctionTemplate, arg);
30+
}
31+
32+
private static readonly object ThreadLock = new object();
33+
34+
/// <summary>
35+
/// Emits specified code into a new, temporary modules, executes specified function, returns the result and destroys the temporary module.
36+
/// </summary>
37+
/// <typeparam name="TResult">The result type.</typeparam>
38+
/// <param name="project">The project to execute the code in.</param>
39+
/// <param name="content">The content of the module to emit.</param>
40+
/// <param name="name">The function to execute.</param>
41+
/// <param name="args">The arguments to be passed to the function.</param>
42+
/// <returns>The result of the function, or the default value for the specified return type.</returns>
43+
public TResult ExecuteWithResult<TResult>(IVBProject project, string content, string name, params object[] args)
44+
{
45+
lock (ThreadLock)
46+
{
47+
Debug.Assert(content.Contains(Tokens.Public + ' ' + Tokens.Function + ' ' + name));
48+
Debug.Assert(project.Protection == ProjectProtection.Unprotected);
49+
50+
_state.IsEnabled = false;
51+
IVBComponent component = null;
52+
object result;
53+
try
54+
{
55+
component = project.VBComponents.Add(ComponentType.StandardModule);
56+
component.Name = TempModuleName;
57+
component.CodeModule.AddFromString(content);
58+
var host = project.VBE.HostApplication();
59+
result = host.Run(name, args);
60+
}
61+
catch (COMException)
62+
{
63+
// IHostApplication.Run is supported, but the call failed.
64+
return default(TResult);
65+
}
66+
finally
67+
{
68+
if (component != null)
69+
{
70+
project.VBComponents.Remove(component);
71+
}
72+
}
73+
74+
_state.IsEnabled = true;
75+
if (result == null)
76+
{
77+
return default(TResult);
78+
}
79+
return (TResult) result;
80+
}
81+
}
82+
}
83+
}

Rubberduck.Parsing/Rubberduck.Parsing.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
<Compile Include="ComReflection\ComStruct.cs" />
120120
<Compile Include="ComReflection\ComType.cs" />
121121
<Compile Include="ComReflection\ComVariant.cs" />
122+
<Compile Include="Emitter.cs" />
122123
<Compile Include="Grammar\Annotations.cs" />
123124
<Compile Include="Grammar\Tokens.cs" />
124125
<Compile Include="Grammar\VBALexer.cs" />

Rubberduck.Parsing/Symbols/DeclarationSymbolsListener.cs

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public DeclarationSymbolsListener(
3434
ComponentType type,
3535
IEnumerable<IAnnotation> annotations,
3636
IDictionary<Tuple<string, DeclarationType>, Attributes> attributes,
37-
Declaration projectDeclaration)
37+
Declaration projectDeclaration, string asTypeName = null)
3838
{
3939
_qualifiedName = qualifiedName;
4040
_annotations = annotations;
@@ -66,34 +66,42 @@ public DeclarationSymbolsListener(
6666
Declaration superType = null;
6767
if (type == ComponentType.Document)
6868
{
69-
foreach (var coclass in state.CoClasses)
69+
if (!string.IsNullOrEmpty(asTypeName))
7070
{
71-
try
71+
superType = state.CoClasses.FirstOrDefault(cls => cls.Value.IdentifierName == asTypeName).Value;
72+
}
73+
else
74+
{
75+
foreach (var coclass in state.CoClasses)
7276
{
73-
if (_qualifiedName.Component == null || coclass.Key.Count != _qualifiedName.Component.Properties.Count)
77+
try
7478
{
75-
continue;
76-
}
79+
if (_qualifiedName.Component == null ||
80+
coclass.Key.Count != _qualifiedName.Component.Properties.Count)
81+
{
82+
continue;
83+
}
7784

78-
var allNamesMatch = true;
79-
for (var i = 0; i < coclass.Key.Count; i++)
80-
{
81-
if (coclass.Key[i] != _qualifiedName.Component.Properties[i + 1].Name)
85+
var allNamesMatch = true;
86+
for (var i = 0; i < coclass.Key.Count; i++)
8287
{
83-
allNamesMatch = false;
88+
if (coclass.Key[i] != _qualifiedName.Component.Properties[i + 1].Name)
89+
{
90+
allNamesMatch = false;
91+
break;
92+
}
93+
}
94+
95+
if (allNamesMatch)
96+
{
97+
superType = coclass.Value;
8498
break;
8599
}
86100
}
87-
88-
if (allNamesMatch)
101+
catch (COMException)
89102
{
90-
superType = coclass.Value;
91-
break;
92103
}
93104
}
94-
catch (COMException)
95-
{
96-
}
97105
}
98106
}
99107

Rubberduck.Parsing/VBA/ParseCoordinator.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Runtime.InteropServices;
1919
using Rubberduck.VBEditor.Application;
2020
using Rubberduck.VBEditor.Extensions;
21+
using Rubberduck.VBEditor.SafeComWrappers;
2122

2223
// ReSharper disable LoopCanBeConvertedToQuery
2324

@@ -138,6 +139,7 @@ private void ExecuteCommonParseActivities(List<IVBComponent> toParse, Cancellati
138139

139140
if (token.IsCancellationRequested || State.Status >= ParserState.Error)
140141
{
142+
_state.IsEnabled = true;
141143
return;
142144
}
143145

@@ -146,6 +148,7 @@ private void ExecuteCommonParseActivities(List<IVBComponent> toParse, Cancellati
146148

147149
if (token.IsCancellationRequested || State.Status >= ParserState.Error)
148150
{
151+
_state.IsEnabled = true;
149152
return;
150153
}
151154

@@ -611,7 +614,14 @@ private void ResolveDeclarations(IVBComponent component, IParseTree tree)
611614
}
612615
Logger.Debug("Creating declarations for module {0}.", qualifiedModuleName.Name);
613616

614-
var declarationsListener = new DeclarationSymbolsListener(State, qualifiedModuleName, component.Type, State.GetModuleAnnotations(component), State.GetModuleAttributes(component), projectDeclaration);
617+
var emitter = new Emitter(_state);
618+
string typeName = null;
619+
if (component.Type == ComponentType.Document)
620+
{
621+
//typeName = emitter.ExecuteWithResult<string>(project, emitter.GetTypeNameFunctionBody(component.Name), "GetTypeName");
622+
}
623+
624+
var declarationsListener = new DeclarationSymbolsListener(State, qualifiedModuleName, component.Type, State.GetModuleAnnotations(component), State.GetModuleAttributes(component), projectDeclaration, typeName);
615625
ParseTreeWalker.Default.Walk(declarationsListener, tree);
616626
foreach (var createdDeclaration in declarationsListener.CreatedDeclarations)
617627
{

Rubberduck.Parsing/VBA/RubberduckParserState.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ public sealed class RubberduckParserState : IDisposable
6161

6262
public readonly ConcurrentDictionary<List<string>, Declaration> CoClasses = new ConcurrentDictionary<List<string>, Declaration>();
6363

64+
public bool IsEnabled { get; internal set; }
65+
6466
public DeclarationFinder DeclarationFinder { get; private set; }
6567

6668
internal void RefreshFinder(IHostApplication host)
@@ -87,6 +89,8 @@ public RubberduckParserState(ISinks sinks)
8789
_sinks.ComponentRemoved += Sinks_ComponentRemoved;
8890
_sinks.ComponentRenamed += Sinks_ComponentRenamed;
8991
}
92+
93+
IsEnabled = true;
9094
}
9195

9296
private bool _started;
@@ -866,7 +870,7 @@ public bool RemoveDeclaration(Declaration declaration)
866870
public void OnParseRequested(object requestor, IVBComponent component = null)
867871
{
868872
var handler = ParseRequest;
869-
if (handler != null)
873+
if (handler != null && IsEnabled)
870874
{
871875
var args = EventArgs.Empty;
872876
handler.Invoke(requestor, args);

Rubberduck.VBEEditor/Application/ExcelApp.cs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Path = System.IO.Path;
1+
using System;
2+
using Path = System.IO.Path;
23
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
34

45
namespace Rubberduck.VBEditor.Application
@@ -14,6 +15,77 @@ public override void Run(dynamic declaration)
1415
Application.Run(call);
1516
}
1617

18+
public override object Run(string name, params object[] args)
19+
{
20+
switch (args.Length)
21+
{
22+
case 0:
23+
return Application.Run(name);
24+
case 1:
25+
return Application.Run(name, args[0]);
26+
case 2:
27+
return Application.Run(name, args[0], args[1]);
28+
case 3:
29+
return Application.Run(name, args[0], args[1], args[2]);
30+
case 4:
31+
return Application.Run(name, args[0], args[1], args[2], args[3]);
32+
case 5:
33+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4]);
34+
case 6:
35+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5]);
36+
case 7:
37+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
38+
case 8:
39+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
40+
case 9:
41+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
42+
case 10:
43+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
44+
case 11:
45+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
46+
case 12:
47+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]);
48+
case 13:
49+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12]);
50+
case 14:
51+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]);
52+
case 15:
53+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14]);
54+
case 16:
55+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15]);
56+
case 17:
57+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16]);
58+
case 18:
59+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17]);
60+
case 19:
61+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18]);
62+
case 20:
63+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19]);
64+
case 21:
65+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19],args[20]);
66+
case 22:
67+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21]);
68+
case 23:
69+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22]);
70+
case 24:
71+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], args[23]);
72+
case 25:
73+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], args[23], args[24]);
74+
case 26:
75+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], args[23], args[24], args[25]);
76+
case 27:
77+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], args[23], args[24], args[25], args[26]);
78+
case 28:
79+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], args[23], args[24], args[25], args[26], args[27]);
80+
case 29:
81+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], args[23], args[24], args[25], args[26], args[27], args[28]);
82+
case 30:
83+
return Application.Run(name, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], args[23], args[24], args[25], args[26], args[27], args[28], args[29]);
84+
default:
85+
throw new ArgumentException("Too many arguments.");
86+
}
87+
}
88+
1789
protected virtual string GenerateMethodCall(dynamic declaration)
1890
{
1991
var qualifiedMemberName = declaration.QualifiedName;

Rubberduck.VBEEditor/Application/FallbackApp.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ public void Run(dynamic declaration)
3636
// note: this can't work... because the .Execute() call isn't blocking, so method returns before test method actually runs.
3737
}
3838

39+
public object Run(string name, object[] args)
40+
{
41+
return null;
42+
}
43+
3944
public TimeSpan TimedMethodCall(dynamic declaration)
4045
{
4146
var stopwatch = Stopwatch.StartNew();

Rubberduck.VBEEditor/Application/HostApplicationBase.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ public string ApplicationName
6767

6868
public abstract void Run(dynamic declaration);
6969

70+
public virtual object Run(string name, params object[] args)
71+
{
72+
return null;
73+
}
74+
7075
public void Dispose()
7176
{
7277
Dispose(true);

Rubberduck.VBEEditor/Application/IHostApplication.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ public interface IHostApplication : IDisposable
1111
/// <param name="declaration">The Declaration object for the method to be executed.</param>
1212
void Run(dynamic declaration);
1313

14+
/// <summary>
15+
/// Executes a VBA function by name, with specified parameters, and returns a result.
16+
/// </summary>
17+
/// <param name="name"></param>
18+
/// <param name="args"></param>
19+
/// <returns></returns>
20+
/// <remarks>
21+
/// May not be available in all host applications.
22+
/// </remarks>
23+
object Run(string name, params object[] args);
24+
1425
/// <summary>
1526
/// Gets the name of the application.
1627
/// </summary>

Rubberduck.VBEEditor/SafeComWrappers/VBA/VBE.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,17 @@ public static void SetSelection(IVBProject vbProject, Selection selection, strin
151151
{"SLDWORKS.EXE", typeof(SolidWorksApp)},
152152
};
153153

154+
private static IHostApplication _host;
155+
154156
/// <summary> Returns the type of Office Application that is hosting the VBE. </summary>
155157
public IHostApplication HostApplication()
156158
{
159+
// host app isn't going to change between calls. cache it.
160+
if (_host != null)
161+
{
162+
return _host;
163+
}
164+
157165
var host = Path.GetFileName(System.Windows.Forms.Application.ExecutablePath).ToUpperInvariant();
158166
//This needs the VBE as a ctor argument.
159167
if (host.Equals("SLDWORKS.EXE"))
@@ -225,6 +233,7 @@ public IHostApplication HostApplication()
225233
}
226234
}
227235

236+
_host = result;
228237
return result;
229238
}
230239
}

0 commit comments

Comments
 (0)