Skip to content

Commit a70ffd8

Browse files
authored
Merge pull request #2549 from retailcoder/next
[SquareBracketedExpressionSupport]
2 parents fb829f8 + 37fb950 commit a70ffd8

15 files changed

+165
-38
lines changed

RetailCoder.VBE/UI/Command/MenuItems/CommandBars/IContextFormatter.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@ private string Format(Declaration declaration)
4545

4646
typeName = "(" + declarationType + (string.IsNullOrEmpty(typeName) ? string.Empty : ":" + typeName) + ")";
4747

48-
if (declaration.DeclarationType.HasFlag(DeclarationType.Project))
48+
if (declaration.DeclarationType.HasFlag(DeclarationType.Project) || declaration.DeclarationType == DeclarationType.BracketedExpression)
4949
{
50-
formattedDeclaration = System.IO.Path.GetFileName(declaration.QualifiedName.QualifiedModuleName.ProjectPath) + ";" + declaration.IdentifierName;
50+
formattedDeclaration = System.IO.Path.GetFileName(declaration.QualifiedName.QualifiedModuleName.ProjectPath) + ";" + declaration.IdentifierName + " (" + declarationType + ")";
5151
}
5252
else if (declaration.DeclarationType.HasFlag(DeclarationType.Module))
5353
{
54-
formattedDeclaration = moduleName.ToString();
54+
formattedDeclaration = moduleName + " (" + declarationType + ")";
5555
}
5656

5757
if (declaration.DeclarationType.HasFlag(DeclarationType.Member))
@@ -75,12 +75,13 @@ private string Format(Declaration declaration)
7575
else if (declaration.DeclarationType == DeclarationType.EnumerationMember
7676
|| declaration.DeclarationType == DeclarationType.UserDefinedTypeMember)
7777
{
78-
formattedDeclaration = string.Format("{0}.{1}.{2}",
78+
formattedDeclaration = string.Format("{0}.{1}.{2} {3}",
7979
declaration.IsBuiltIn
8080
? System.IO.Path.GetFileName(moduleName.ProjectPath) + ";" + moduleName.ProjectName
8181
: moduleName.ToString(),
8282
declaration.ParentDeclaration.IdentifierName,
83-
declaration.IdentifierName);
83+
declaration.IdentifierName,
84+
typeName);
8485
}
8586

8687
var subscripts = declaration.IsArray ? "()" : string.Empty;

RetailCoder.VBE/UI/RubberduckUI.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RetailCoder.VBE/UI/RubberduckUI.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,4 +1908,7 @@ Would you like to import them to Rubberduck?</value>
19081908
<data name="IndenterSettings_VerticalSpacingLabel" xml:space="preserve">
19091909
<value>Vertical Spacing</value>
19101910
</data>
1911+
<data name="DeclarationType_BracketedExpression" xml:space="preserve">
1912+
<value>runtime expression</value>
1913+
</data>
19111914
</root>

Rubberduck.Parsing/Binding/SimpleNameDefaultBinding.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Antlr4.Runtime;
22
using Rubberduck.Parsing.Symbols;
33
using System.Linq;
4+
using Rubberduck.Parsing.Grammar;
45

56
namespace Rubberduck.Parsing.Binding
67
{
@@ -28,7 +29,8 @@ public SimpleNameDefaultBinding(
2829
_module = module;
2930
_parent = parent;
3031
_context = context;
31-
_name = name;
32+
// hack; SimpleNameContext.Identifier() excludes the square brackets
33+
_name = context.Start.Text == "[" && context.Stop.Text == "]" ? "[" + name + "]" : name;
3234
_propertySearchType = StatementContext.GetSearchDeclarationType(statementContext);
3335
}
3436

@@ -68,8 +70,16 @@ public IBoundExpression Resolve()
6870
return boundExpression;
6971
}
7072

71-
var undeclaredLocal = _declarationFinder.OnUndeclaredVariable(_parent, _name, _context);
72-
return new SimpleNameExpression(undeclaredLocal, ExpressionClassification.Variable, _context);
73+
if (_context.Start.Text == "[" && _context.Stop.Text == "]")
74+
{
75+
var bracketedExpression = _declarationFinder.OnBracketedExpression(_context.GetText(), _context);
76+
return new SimpleNameExpression(bracketedExpression, ExpressionClassification.Unbound, _context);
77+
}
78+
else
79+
{
80+
var undeclaredLocal = _declarationFinder.OnUndeclaredVariable(_parent, _name, _context);
81+
return new SimpleNameExpression(undeclaredLocal, ExpressionClassification.Variable, _context);
82+
}
7383
//return new ResolutionFailedExpression();
7484
}
7585

@@ -83,7 +93,9 @@ or explicit definition precedes this expression in an enclosing procedure.
8393
{
8494
return null;
8595
}
86-
var localVariable = _declarationFinder.FindMemberEnclosingProcedure(_parent, _name, DeclarationType.Variable);
96+
var localVariable = _declarationFinder.FindMemberEnclosingProcedure(_parent, _name, DeclarationType.Variable)
97+
?? _declarationFinder.FindMemberEnclosingProcedure(_parent, _name, DeclarationType.Variable)
98+
;
8799
if (IsValidMatch(localVariable, _name))
88100
{
89101
return new SimpleNameExpression(localVariable, ExpressionClassification.Variable, _context);

Rubberduck.Parsing/Rubberduck.Parsing.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@
258258
<Compile Include="Symbols\PropertyGetDeclaration.cs" />
259259
<Compile Include="Symbols\FunctionDeclaration.cs" />
260260
<Compile Include="Symbols\SerializableDeclaration.cs" />
261+
<Compile Include="Symbols\SquareBracketedNameComparer.cs" />
261262
<Compile Include="Symbols\SubroutineDeclaration.cs" />
262263
<Compile Include="Symbols\ProjectReferencePass.cs" />
263264
<Compile Include="Symbols\SyntaxErrorInfo.cs" />

Rubberduck.Parsing/Symbols/AliasDeclarations.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public IReadOnlyList<Declaration> Load()
5656

5757
private IReadOnlyList<Declaration> AddAliasDeclarations()
5858
{
59-
var finder = new DeclarationFinder(_state.AllDeclarations, new CommentNode[] { }, new IAnnotation[] { });
59+
var finder = new DeclarationFinder(_state.AllDeclarations, new IAnnotation[] { });
6060

6161
if (WeHaveAlreadyLoadedTheDeclarationsBefore(finder))
6262
{

Rubberduck.Parsing/Symbols/DebugDeclarations.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public DebugDeclarations(RubberduckParserState state)
1919

2020
public IReadOnlyList<Declaration> Load()
2121
{
22-
var finder = new DeclarationFinder(_state.AllDeclarations, new CommentNode[] { }, new IAnnotation[] { });
22+
var finder = new DeclarationFinder(_state.AllDeclarations, new IAnnotation[] { });
2323

2424
if (WeHaveAlreadyLoadedTheDeclarationsBefore(finder))
2525
{

Rubberduck.Parsing/Symbols/DeclarationFinder.cs

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,65 +3,90 @@
33
using Rubberduck.VBEditor;
44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics;
67
using System.Linq;
78
using Antlr4.Runtime;
9+
using Rubberduck.Parsing.Grammar;
10+
using Rubberduck.VBEditor.Application;
811

912
namespace Rubberduck.Parsing.Symbols
1013
{
14+
internal static class DictionaryExtensions
15+
{
16+
public static IEnumerable<TValue> AllValues<TKey, TValue>(
17+
this IDictionary<TKey, TValue[]> source)
18+
{
19+
return source.SelectMany(item => item.Value);
20+
}
21+
22+
public static IEnumerable<TValue> AllValues<TKey, TValue>(
23+
this IDictionary<TKey, IList<TValue>> source)
24+
{
25+
return source.SelectMany(item => item.Value);
26+
}
27+
}
28+
1129
public class DeclarationFinder
1230
{
13-
//private readonly IDictionary<QualifiedModuleName, CommentNode[]> _comments;
31+
private static readonly SquareBracketedNameComparer NameComparer = new SquareBracketedNameComparer();
32+
33+
private readonly IHostApplication _hostApp;
1434
private readonly IDictionary<QualifiedModuleName, IAnnotation[]> _annotations;
1535
private readonly IDictionary<QualifiedMemberName, IList<Declaration>> _undeclared;
1636
private readonly AnnotationService _annotationService;
1737

18-
private readonly IReadOnlyList<Declaration> _declarations;
38+
private readonly IDictionary<QualifiedModuleName, Declaration[]> _declarations;
1939
private readonly IDictionary<string, Declaration[]> _declarationsByName;
2040
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
2141

22-
public DeclarationFinder(
23-
IReadOnlyList<Declaration> declarations,
24-
IEnumerable<CommentNode> comments,
25-
IEnumerable<IAnnotation> annotations)
42+
public DeclarationFinder(IReadOnlyList<Declaration> declarations, IEnumerable<IAnnotation> annotations, IHostApplication hostApp = null)
2643
{
27-
//_comments = comments.GroupBy(node => node.QualifiedSelection.QualifiedName)
28-
// .ToDictionary(grouping => grouping.Key, grouping => grouping.ToArray());
44+
_hostApp = hostApp;
2945
_annotations = annotations.GroupBy(node => node.QualifiedSelection.QualifiedName)
3046
.ToDictionary(grouping => grouping.Key, grouping => grouping.ToArray());
31-
_declarations = declarations;
47+
_declarations = declarations.GroupBy(item => item.QualifiedName.QualifiedModuleName)
48+
.ToDictionary(grouping => grouping.Key, grouping => grouping.ToArray());
3249
_declarationsByName = declarations.GroupBy(declaration => new
3350
{
3451
IdentifierName = declaration.IdentifierName.ToLowerInvariant()
3552
})
36-
.ToDictionary(grouping => grouping.Key.IdentifierName, grouping => grouping.ToArray());
53+
.ToDictionary(grouping => grouping.Key.IdentifierName, grouping => grouping.ToArray(), NameComparer);
3754

3855
_undeclared = new Dictionary<QualifiedMemberName, IList<Declaration>>();
3956
_annotationService = new AnnotationService(this);
4057
}
4158

4259
public IEnumerable<Declaration> Undeclared
4360
{
44-
get { return _undeclared.SelectMany(e => e.Value); }
61+
get { return _undeclared.AllValues(); }
4562
}
4663

64+
private IEnumerable<Declaration> _nonBaseAsType;
4765
public IEnumerable<Declaration> FindDeclarationsWithNonBaseAsType()
4866
{
49-
return _declarations
67+
return _nonBaseAsType ?? (
68+
_nonBaseAsType = _declarations.AllValues()
5069
.Where(d =>
5170
!string.IsNullOrWhiteSpace(d.AsTypeName)
5271
&& !d.AsTypeIsBaseType
5372
&& d.DeclarationType != DeclarationType.Project
54-
&& d.DeclarationType != DeclarationType.ProceduralModule).ToList();
73+
&& d.DeclarationType != DeclarationType.ProceduralModule).ToList());
5574
}
5675

76+
private IEnumerable<Declaration> _classes;
5777
public IEnumerable<Declaration> FindClasses()
5878
{
59-
return _declarations.Where(d => d.DeclarationType == DeclarationType.ClassModule).ToList();
79+
return _classes ?? (
80+
_classes = _declarations.AllValues()
81+
.Where(d => d.DeclarationType == DeclarationType.ClassModule).ToList());
6082
}
6183

84+
private IEnumerable<Declaration> _projects;
6285
public IEnumerable<Declaration> FindProjects()
6386
{
64-
return _declarations.Where(d => d.DeclarationType == DeclarationType.Project).ToList();
87+
return _projects ?? (
88+
_projects = _declarations.AllValues()
89+
.Where(d => d.DeclarationType == DeclarationType.Project).ToList());
6590
}
6691

6792
public Declaration FindParameter(Declaration procedure, string parameterName)
@@ -77,7 +102,7 @@ public IEnumerable<IAnnotation> FindAnnotations(QualifiedModuleName module)
77102
{
78103
return result;
79104
}
80-
return new List<IAnnotation>();
105+
return Enumerable.Empty<IAnnotation>();
81106
}
82107

83108
public bool IsMatch(string declarationName, string potentialMatchName)
@@ -101,11 +126,9 @@ public IEnumerable<Declaration> MatchName(string name)
101126
{
102127
var normalizedName = name.ToLowerInvariant();
103128
Declaration[] result;
104-
if (_declarationsByName.TryGetValue(normalizedName, out result))
105-
{
106-
return result;
107-
}
108-
return Enumerable.Empty<Declaration>();
129+
return _declarationsByName.TryGetValue(normalizedName, out result)
130+
? result
131+
: Enumerable.Empty<Declaration>();
109132
}
110133

111134
public Declaration FindProject(string name, Declaration currentScope = null)
@@ -126,6 +149,7 @@ public Declaration FindProject(string name, Declaration currentScope = null)
126149

127150
public Declaration FindStdModule(string name, Declaration parent = null, bool includeBuiltIn = false)
128151
{
152+
Debug.Assert(parent != null);
129153
Declaration result = null;
130154
try
131155
{
@@ -144,6 +168,7 @@ public Declaration FindStdModule(string name, Declaration parent = null, bool in
144168

145169
public Declaration FindClassModule(string name, Declaration parent = null, bool includeBuiltIn = false)
146170
{
171+
Debug.Assert(parent != null);
147172
Declaration result = null;
148173
try
149174
{
@@ -283,7 +308,7 @@ public Declaration FindMemberEnclosingModule(Declaration callingModule, Declarat
283308

284309
public Declaration FindMemberEnclosingProcedure(Declaration enclosingProcedure, string memberName, DeclarationType memberType, ParserRuleContext onSiteContext = null)
285310
{
286-
if (memberType == DeclarationType.Variable && enclosingProcedure.IdentifierName.Equals(memberName))
311+
if (memberType == DeclarationType.Variable && NameComparer.Equals(enclosingProcedure.IdentifierName, memberName))
287312
{
288313
return enclosingProcedure;
289314
}
@@ -322,6 +347,24 @@ public Declaration OnUndeclaredVariable(Declaration enclosingProcedure, string i
322347
return undeclaredLocal;
323348
}
324349

350+
public Declaration OnBracketedExpression(string expression, ParserRuleContext context)
351+
{
352+
var hostApp = FindProject(_hostApp == null ? "VBA" : _hostApp.ApplicationName);
353+
var qualifiedName = hostApp.QualifiedName.QualifiedModuleName.QualifyMemberName(expression);
354+
355+
var exists = _undeclared.ContainsKey(qualifiedName);
356+
if (exists)
357+
{
358+
return _undeclared[qualifiedName][0];
359+
}
360+
else
361+
{
362+
var item = new Declaration(qualifiedName, hostApp, hostApp, Tokens.Variant, string.Empty, false, false, Accessibility.Global, DeclarationType.BracketedExpression, context, context.GetSelection(), false, null);
363+
_undeclared.Add(qualifiedName, new List<Declaration> { item });
364+
return item;
365+
}
366+
}
367+
325368
public Declaration FindMemberEnclosedProjectWithoutEnclosingModule(Declaration callingProject, Declaration callingModule, Declaration callingParent, string memberName, DeclarationType memberType)
326369
{
327370
var allMatches = MatchName(memberName);

Rubberduck.Parsing/Symbols/DeclarationType.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ public enum DeclarationType
6060
[DebuggerDisplay("LineLabel")]
6161
LineLabel = 1 << 25,
6262
[DebuggerDisplay("UnresolvedMember")]
63-
UnresolvedMember = 1 << 26
63+
UnresolvedMember = 1 << 26,
64+
[DebuggerDisplay("BracketedExpression")]
65+
BracketedExpression = 1 << 27,
6466
}
6567

6668
public interface IIdentifier { IdentifierNode Identifier { get; } }

Rubberduck.Parsing/Symbols/FormEventDeclarations.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public IReadOnlyList<Declaration> Load()
2828

2929
private static Declaration FormsClassModuleFromParserState(RubberduckParserState state)
3030
{
31-
var finder = new DeclarationFinder(state.AllDeclarations, new CommentNode[] { }, new IAnnotation[] { });
31+
var finder = new DeclarationFinder(state.AllDeclarations, new IAnnotation[] { });
3232

3333
var msForms = finder.FindProject("MSForms");
3434
if (msForms == null)

0 commit comments

Comments
 (0)