Skip to content

Commit 8f64c9b

Browse files
author
Andrin Meier
committed
implement member access expression type binding context
1 parent 863e540 commit 8f64c9b

18 files changed

+738
-174
lines changed

RetailCoder.VBE/App.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,12 @@ private void RegisterComponentsEventSink(DispatcherEventArgs<VBProject> e, VBPro
212212
componentsSink.ComponentRemoved += sink_ComponentRemoved;
213213
componentsSink.ComponentRenamed += sink_ComponentRenamed;
214214
componentsSink.ComponentSelected += sink_ComponentSelected;
215-
_componentsEventSinks.Add(sink, componentsSink);
215+
//_componentsEventSinks.Add(sink, componentsSink);
216216

217-
int cookie;
218-
connectionPoint.Advise(componentsSink, out cookie);
217+
//int cookie;
218+
//connectionPoint.Advise(componentsSink, out cookie);
219219

220-
_componentsEventsConnectionPoints.Add(sink, Tuple.Create(connectionPoint, cookie));
220+
//_componentsEventsConnectionPoints.Add(sink, Tuple.Create(connectionPoint, cookie));
221221
}
222222

223223
async void sink_ComponentSelected(object sender, DispatcherEventArgs<VBComponent> e)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Antlr4.Runtime;
2+
using Rubberduck.Parsing.Symbols;
3+
4+
namespace Rubberduck.Parsing.Binding
5+
{
6+
public sealed class MemberAccessExpression : BoundExpression
7+
{
8+
private readonly IBoundExpression _lExpression;
9+
10+
public MemberAccessExpression(
11+
Declaration referencedDeclaration,
12+
ExpressionClassification classification,
13+
ParserRuleContext context,
14+
IBoundExpression lExpression)
15+
: base(referencedDeclaration, classification, context)
16+
{
17+
_lExpression = lExpression;
18+
}
19+
20+
public IBoundExpression LExpression
21+
{
22+
get
23+
{
24+
return _lExpression;
25+
}
26+
}
27+
}
28+
}
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
using Antlr4.Runtime;
2+
using Rubberduck.Parsing.Symbols;
3+
4+
namespace Rubberduck.Parsing.Binding
5+
{
6+
public sealed class MemberAccessTypeBinding : IExpressionBinding
7+
{
8+
private readonly DeclarationFinder _declarationFinder;
9+
private readonly Declaration _project;
10+
private readonly Declaration _module;
11+
private readonly Declaration _parent;
12+
private readonly VBAExpressionParser.MemberAccessExpressionContext _memberAccessExpression;
13+
private readonly VBAExpressionParser.MemberAccessExprContext _memberAccessExpr;
14+
private readonly IExpressionBinding _lExpressionBinding;
15+
16+
public MemberAccessTypeBinding(
17+
DeclarationFinder declarationFinder,
18+
Declaration module,
19+
Declaration parent,
20+
VBAExpressionParser.MemberAccessExpressionContext expression,
21+
IExpressionBinding lExpressionBinding)
22+
{
23+
_declarationFinder = declarationFinder;
24+
_project = module.ParentDeclaration;
25+
_module = module;
26+
_parent = parent;
27+
_memberAccessExpression = expression;
28+
_lExpressionBinding = lExpressionBinding;
29+
}
30+
31+
public MemberAccessTypeBinding(
32+
DeclarationFinder declarationFinder,
33+
Declaration module,
34+
Declaration parent,
35+
VBAExpressionParser.MemberAccessExprContext expression,
36+
IExpressionBinding lExpressionBinding)
37+
{
38+
_declarationFinder = declarationFinder;
39+
_project = module.ParentDeclaration;
40+
_module = module;
41+
_parent = parent;
42+
_memberAccessExpr = expression;
43+
_lExpressionBinding = lExpressionBinding;
44+
}
45+
46+
private ParserRuleContext GetExpressionContext()
47+
{
48+
if (_memberAccessExpression != null)
49+
{
50+
return _memberAccessExpression;
51+
}
52+
return _memberAccessExpr;
53+
}
54+
55+
private string GetUnrestrictedName()
56+
{
57+
if (_memberAccessExpression != null)
58+
{
59+
return ExpressionName.GetName(_memberAccessExpression.unrestrictedName());
60+
}
61+
return ExpressionName.GetName(_memberAccessExpr.unrestrictedName());
62+
}
63+
64+
public IBoundExpression Resolve()
65+
{
66+
IBoundExpression boundExpression = null;
67+
var lExpression = _lExpressionBinding.Resolve();
68+
string unrestrictedName = GetUnrestrictedName();
69+
boundExpression = ResolveLExpressionIsProject(lExpression, unrestrictedName);
70+
if (boundExpression != null)
71+
{
72+
return boundExpression;
73+
}
74+
boundExpression = ResolveLExpressionIsModule(lExpression, unrestrictedName);
75+
return boundExpression;
76+
}
77+
78+
private IBoundExpression ResolveLExpressionIsProject(IBoundExpression lExpression, string name)
79+
{
80+
if (lExpression.Classification != ExpressionClassification.Project)
81+
{
82+
return null;
83+
}
84+
IBoundExpression boundExpression = null;
85+
var referencedProject = lExpression.ReferencedDeclaration;
86+
bool lExpressionIsEnclosingProject = _project.Equals(referencedProject);
87+
boundExpression = ResolveProject(lExpression, name);
88+
if (boundExpression != null)
89+
{
90+
return boundExpression;
91+
}
92+
boundExpression = ResolveProceduralModule(lExpressionIsEnclosingProject, lExpression, name, referencedProject);
93+
if (boundExpression != null)
94+
{
95+
return boundExpression;
96+
}
97+
boundExpression = ResolveClassModule(lExpressionIsEnclosingProject, lExpression, name, referencedProject);
98+
if (boundExpression != null)
99+
{
100+
return boundExpression;
101+
}
102+
boundExpression = ResolveMemberInReferencedProject(lExpressionIsEnclosingProject, lExpression, name, referencedProject, DeclarationType.UserDefinedType);
103+
if (boundExpression != null)
104+
{
105+
return boundExpression;
106+
}
107+
boundExpression = ResolveMemberInReferencedProject(lExpressionIsEnclosingProject, lExpression, name, referencedProject, DeclarationType.Enumeration);
108+
if (boundExpression != null)
109+
{
110+
return boundExpression;
111+
}
112+
return boundExpression;
113+
}
114+
115+
private IBoundExpression ResolveProject(IBoundExpression lExpression, string name)
116+
{
117+
/*
118+
<l-expression> refers to the enclosing project and <unrestricted-name> is either the name of
119+
the enclosing project or a referenced project. In this case, the member access expression is
120+
classified as a project and refers to the specified project.
121+
*/
122+
if (_project.Project.Name == name)
123+
{
124+
return new MemberAccessExpression(_project, ExpressionClassification.Project, GetExpressionContext(), lExpression);
125+
}
126+
var referencedProjectRightOfDot = _declarationFinder.FindReferencedProject(_project, name);
127+
if (referencedProjectRightOfDot != null)
128+
{
129+
return new MemberAccessExpression(referencedProjectRightOfDot, ExpressionClassification.Project, GetExpressionContext(), lExpression);
130+
}
131+
return null;
132+
}
133+
134+
private IBoundExpression ResolveProceduralModule(bool lExpressionIsEnclosingProject, IBoundExpression lExpression, string name, Declaration referencedProject)
135+
{
136+
/*
137+
The project has an accessible procedural module named <unrestricted-name>. In this case, the
138+
member access expression is classified as a procedural module and refers to the specified
139+
procedural module.
140+
*/
141+
if (lExpressionIsEnclosingProject)
142+
{
143+
if (_module.DeclarationType == DeclarationType.ProceduralModule && _module.IdentifierName == name)
144+
{
145+
return new MemberAccessExpression(_module, ExpressionClassification.ProceduralModule, GetExpressionContext(), lExpression);
146+
}
147+
var proceduralModuleEnclosingProject = _declarationFinder.FindModuleEnclosingProjectWithoutEnclosingModule(_project, _module, name, DeclarationType.ProceduralModule);
148+
if (proceduralModuleEnclosingProject != null)
149+
{
150+
return new MemberAccessExpression(proceduralModuleEnclosingProject, ExpressionClassification.ProceduralModule, GetExpressionContext(), lExpression);
151+
}
152+
}
153+
else
154+
{
155+
var proceduralModuleInReferencedProject = _declarationFinder.FindModuleReferencedProject(_project, referencedProject, _module, name, DeclarationType.ClassModule);
156+
if (proceduralModuleInReferencedProject != null)
157+
{
158+
return new MemberAccessExpression(proceduralModuleInReferencedProject, ExpressionClassification.ProceduralModule, GetExpressionContext(), lExpression);
159+
}
160+
}
161+
return null;
162+
}
163+
164+
private IBoundExpression ResolveClassModule(bool lExpressionIsEnclosingProject, IBoundExpression lExpression, string name, Declaration referencedProject)
165+
{
166+
/*
167+
The project has an accessible class module named <unrestricted-name>. In this case, the
168+
member access expression is classified as a type and refers to the specified class.
169+
*/
170+
if (lExpressionIsEnclosingProject)
171+
{
172+
if (_module.DeclarationType == DeclarationType.ClassModule && _module.IdentifierName == name)
173+
{
174+
return new MemberAccessExpression(_module, ExpressionClassification.Type, GetExpressionContext(), lExpression);
175+
}
176+
var classModuleEnclosingProject = _declarationFinder.FindModuleEnclosingProjectWithoutEnclosingModule(_project, _module, name, DeclarationType.ClassModule);
177+
if (classModuleEnclosingProject != null)
178+
{
179+
return new MemberAccessExpression(classModuleEnclosingProject, ExpressionClassification.Type, GetExpressionContext(), lExpression);
180+
}
181+
}
182+
else
183+
{
184+
var classModuleInReferencedProject = _declarationFinder.FindModuleReferencedProject(_project, _module, referencedProject, name, DeclarationType.ClassModule);
185+
if (classModuleInReferencedProject != null)
186+
{
187+
return new MemberAccessExpression(classModuleInReferencedProject, ExpressionClassification.Type, GetExpressionContext(), lExpression);
188+
}
189+
}
190+
return null;
191+
}
192+
193+
private IBoundExpression ResolveMemberInReferencedProject(bool lExpressionIsEnclosingProject, IBoundExpression lExpression, string name, Declaration referencedProject, DeclarationType memberType)
194+
{
195+
/*
196+
The project does not have an accessible module named <unrestricted-name> and exactly one of
197+
the procedural modules within the project contains a UDT or Enum definition named
198+
<unrestricted-name>. In this case, the member access expression is classified as a type and
199+
refers to the specified UDT or enum.
200+
*/
201+
if (lExpressionIsEnclosingProject)
202+
{
203+
var foundType = _declarationFinder.FindMemberEnclosingModule(_project, _module, _parent, name, memberType);
204+
if (foundType != null)
205+
{
206+
return new MemberAccessExpression(foundType, ExpressionClassification.Type, GetExpressionContext(), lExpression);
207+
}
208+
var accessibleType = _declarationFinder.FindMemberEnclosedProjectWithoutEnclosingModule(_project, _module, _parent, name, memberType);
209+
if (accessibleType != null)
210+
{
211+
return new MemberAccessExpression(accessibleType, ExpressionClassification.Type, GetExpressionContext(), lExpression);
212+
}
213+
}
214+
else
215+
{
216+
var referencedProjectType = _declarationFinder.FindMemberReferencedProject(_project, _module, _parent, referencedProject, name, memberType);
217+
if (referencedProjectType != null)
218+
{
219+
return new MemberAccessExpression(referencedProjectType, ExpressionClassification.Type, GetExpressionContext(), lExpression);
220+
}
221+
}
222+
return null;
223+
}
224+
225+
private IBoundExpression ResolveLExpressionIsModule(IBoundExpression lExpression, string name)
226+
{
227+
if (lExpression.Classification != ExpressionClassification.ProceduralModule && lExpression.Classification != ExpressionClassification.Type)
228+
{
229+
return null;
230+
}
231+
IBoundExpression boundExpression = null;
232+
boundExpression = ResolveMemberInModule(lExpression, name, lExpression.ReferencedDeclaration, DeclarationType.UserDefinedType);
233+
if (boundExpression != null)
234+
{
235+
return boundExpression;
236+
}
237+
boundExpression = ResolveMemberInModule(lExpression, name, lExpression.ReferencedDeclaration, DeclarationType.Enumeration);
238+
if (boundExpression != null)
239+
{
240+
return boundExpression;
241+
}
242+
return boundExpression;
243+
}
244+
245+
private IBoundExpression ResolveMemberInModule(IBoundExpression lExpression, string name, Declaration module, DeclarationType memberType)
246+
{
247+
/*
248+
<l-expression> is classified as a procedural module or a type referencing a class defined in a
249+
class module, and one of the following is true:
250+
251+
This module has an accessible UDT or Enum definition named <unrestricted-name>. In this
252+
case, the member access expression is classified as a type and refers to the specified UDT or
253+
Enum type.
254+
*/
255+
var enclosingProjectType = _declarationFinder.FindMemberEnclosedProjectInModule(_project, _module, _parent, module, name, memberType);
256+
if (enclosingProjectType != null)
257+
{
258+
return new MemberAccessExpression(enclosingProjectType, ExpressionClassification.Type, GetExpressionContext(), lExpression);
259+
}
260+
261+
var referencedProjectType = _declarationFinder.FindMemberReferencedProjectInModule(_project, _module, _parent, module, name, memberType);
262+
if (referencedProjectType != null)
263+
{
264+
return new MemberAccessExpression(referencedProjectType, ExpressionClassification.Type, GetExpressionContext(), lExpression);
265+
}
266+
return null;
267+
}
268+
}
269+
}

0 commit comments

Comments
 (0)