Skip to content

Commit a302e55

Browse files
committed
Saved the unresolved member declarations on the module states and refilled the unresolved and undeclared collections on the DeclarationFinder upon refresh.
1 parent 4ad4e25 commit a302e55

File tree

4 files changed

+104
-27
lines changed

4 files changed

+104
-27
lines changed

Rubberduck.Parsing/Symbols/DeclarationFinder.cs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public static IEnumerable<TValue> AllValues<TKey, TValue>(
3030
public static ConcurrentDictionary<TKey, ConcurrentBag<TValue>> ToConcurrentDictionary<TKey, TValue>(this IEnumerable<IGrouping<TKey, TValue>> source)
3131
{
3232
return new ConcurrentDictionary<TKey, ConcurrentBag<TValue>>(source.Select(x => new KeyValuePair<TKey, ConcurrentBag<TValue>>(x.Key, new ConcurrentBag<TValue>(x))));
33-
}
33+
}
3434
}
3535

3636
public class DeclarationFinder
@@ -42,8 +42,10 @@ public class DeclarationFinder
4242
private readonly AnnotationService _annotationService;
4343
private readonly ConcurrentDictionary<string, ConcurrentBag<Declaration>> _declarationsByName;
4444
private readonly ConcurrentDictionary<QualifiedModuleName, ConcurrentBag<Declaration>> _declarations;
45-
private readonly ConcurrentDictionary<QualifiedMemberName, ConcurrentBag<Declaration>> _undeclared;
46-
private readonly ConcurrentBag<UnboundMemberDeclaration> _unresolved;
45+
private readonly ConcurrentDictionary<QualifiedMemberName, ConcurrentBag<Declaration>> _newUndeclared;
46+
private readonly ConcurrentBag<UnboundMemberDeclaration> _newUnresolved;
47+
private readonly Dictionary<QualifiedMemberName, List<Declaration>> _undeclared;
48+
private readonly List<UnboundMemberDeclaration> _unresolved;
4749
private readonly ConcurrentDictionary<QualifiedModuleName, ConcurrentBag<IAnnotation>> _annotations;
4850
private readonly ConcurrentDictionary<Declaration, ConcurrentBag<Declaration>> _parametersByParent;
4951
private readonly ConcurrentDictionary<DeclarationType, ConcurrentBag<Declaration>> _userDeclarationsByType;
@@ -54,7 +56,7 @@ public class DeclarationFinder
5456

5557
private static readonly object ThreadLock = new object();
5658

57-
public DeclarationFinder(IReadOnlyList<Declaration> declarations, IEnumerable<IAnnotation> annotations, IHostApplication hostApp = null)
59+
public DeclarationFinder(IReadOnlyList<Declaration> declarations, IEnumerable<IAnnotation> annotations, IReadOnlyList<UnboundMemberDeclaration> unresolvedMemberDeclarations, IHostApplication hostApp = null)
5860
{
5961
_hostApp = hostApp;
6062
_annotations = annotations.GroupBy(node => node.QualifiedSelection.QualifiedName).ToConcurrentDictionary();
@@ -90,8 +92,11 @@ public DeclarationFinder(IReadOnlyList<Declaration> declarations, IEnumerable<IA
9092
.ToDictionary(item => item.WithEventsField, item => item.Handlers.ToArray())
9193
), true);
9294

93-
_undeclared = new ConcurrentDictionary<QualifiedMemberName, ConcurrentBag<Declaration>>(new Dictionary<QualifiedMemberName, ConcurrentBag<Declaration>>());
94-
_unresolved = new ConcurrentBag<UnboundMemberDeclaration>(new List<UnboundMemberDeclaration>());
95+
_newUndeclared = new ConcurrentDictionary<QualifiedMemberName, ConcurrentBag<Declaration>>(new Dictionary<QualifiedMemberName, ConcurrentBag<Declaration>>());
96+
_undeclared = declarations.Where(declaration => declaration.IsUndeclared).GroupBy(item => item.QualifiedName).ToDictionary(group => group.Key, group => group.ToList());
97+
_newUnresolved = new ConcurrentBag<UnboundMemberDeclaration>(new List<UnboundMemberDeclaration>());
98+
_unresolved = unresolvedMemberDeclarations.ToList();
99+
95100
_annotationService = new AnnotationService(this);
96101

97102
var implementsInstructions = UserDeclarations(DeclarationType.ClassModule).SelectMany(cls =>
@@ -134,9 +139,14 @@ public DeclarationFinder(IReadOnlyList<Declaration> declarations, IEnumerable<IA
134139
implementableMembers.ToDictionary(item => item.Context, item => item.Members)), true);
135140
}
136141

142+
public IEnumerable<Declaration> FreshUndeclared
143+
{
144+
get { return _newUndeclared.AllValues(); }
145+
}
146+
137147
public IEnumerable<Declaration> Undeclared
138148
{
139-
get { return _undeclared.AllValues(); }
149+
get { return _undeclared.SelectMany(item => item.Value).ToList(); }
140150
}
141151

142152
public IEnumerable<Declaration> Members(Declaration module)
@@ -209,14 +219,19 @@ public IEnumerable<Declaration> UserDeclarations(DeclarationType type)
209219
return result;
210220
}
211221

212-
public IEnumerable<UnboundMemberDeclaration> UnresolvedMemberDeclarations()
222+
public IEnumerable<UnboundMemberDeclaration> FreshUnresolvedMemberDeclarations()
213223
{
214224
lock (ThreadLock)
215225
{
216-
return _unresolved.ToArray();
226+
return _newUnresolved.ToArray();
217227
}
218228
}
219229

230+
public IEnumerable<UnboundMemberDeclaration> UnresolvedMemberDeclarations()
231+
{
232+
return _unresolved.ToList();
233+
}
234+
220235
public IEnumerable<Declaration> FindHandlersForWithEventsField(Declaration field)
221236
{
222237
Declaration[] result;
@@ -510,13 +525,13 @@ public Declaration OnUndeclaredVariable(Declaration enclosingProcedure, string i
510525
Accessibility.Implicit, DeclarationType.Variable, context, context.GetSelection(), false, null,
511526
false, annotations, null, true);
512527

513-
var hasUndeclared = _undeclared.ContainsKey(enclosingProcedure.QualifiedName);
528+
var hasUndeclared = _newUndeclared.ContainsKey(enclosingProcedure.QualifiedName);
514529
if (hasUndeclared)
515530
{
516531
ConcurrentBag<Declaration> undeclared;
517-
while (!_undeclared.TryGetValue(enclosingProcedure.QualifiedName, out undeclared))
532+
while (!_newUndeclared.TryGetValue(enclosingProcedure.QualifiedName, out undeclared))
518533
{
519-
_undeclared.TryGetValue(enclosingProcedure.QualifiedName, out undeclared);
534+
_newUndeclared.TryGetValue(enclosingProcedure.QualifiedName, out undeclared);
520535
}
521536
var inScopeUndeclared = undeclared.FirstOrDefault(d => d.IdentifierName == identifierName);
522537
if (inScopeUndeclared != null)
@@ -527,7 +542,7 @@ public Declaration OnUndeclaredVariable(Declaration enclosingProcedure, string i
527542
}
528543
else
529544
{
530-
_undeclared.TryAdd(enclosingProcedure.QualifiedName, new ConcurrentBag<Declaration> { undeclaredLocal });
545+
_newUndeclared.TryAdd(enclosingProcedure.QualifiedName, new ConcurrentBag<Declaration> { undeclaredLocal });
531546
}
532547
return undeclaredLocal;
533548
}
@@ -550,7 +565,7 @@ public void AddUnboundContext(Declaration parentDeclaration, VBAParser.LExprCont
550565
(access is VBAParser.MemberAccessExprContext) ? (ParserRuleContext)access.children[0] : withExpression.Context,
551566
annotations);
552567

553-
_unresolved.Add(declaration);
568+
_newUnresolved.Add(declaration);
554569
}
555570

556571
public Declaration OnBracketedExpression(string expression, ParserRuleContext context)
@@ -561,13 +576,13 @@ public Declaration OnBracketedExpression(string expression, ParserRuleContext co
561576
var qualifiedName = hostApp.QualifiedName.QualifiedModuleName.QualifyMemberName(expression);
562577

563578
ConcurrentBag<Declaration> undeclared;
564-
if (_undeclared.TryGetValue(qualifiedName, out undeclared))
579+
if (_newUndeclared.TryGetValue(qualifiedName, out undeclared))
565580
{
566581
return undeclared.SingleOrDefault();
567582
}
568583

569584
var item = new Declaration(qualifiedName, hostApp, hostApp, Tokens.Variant, string.Empty, false, false, Accessibility.Global, DeclarationType.BracketedExpression, context, context.GetSelection(), false, null);
570-
_undeclared.TryAdd(qualifiedName, new ConcurrentBag<Declaration> { item });
585+
_newUndeclared.TryAdd(qualifiedName, new ConcurrentBag<Declaration> { item });
571586
return item;
572587
}
573588

Rubberduck.Parsing/VBA/ModuleState.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace Rubberduck.Parsing.VBA
1313
public class ModuleState
1414
{
1515
public ConcurrentDictionary<Declaration, byte> Declarations { get; private set; }
16+
public ConcurrentDictionary<UnboundMemberDeclaration, byte> UnresolvedMemberDeclarations { get; private set; }
1617
public ITokenStream TokenStream { get; private set; }
1718
public IParseTree ParseTree { get; private set; }
1819
public ParserState State { get; private set; }
@@ -29,7 +30,8 @@ public class ModuleState
2930
public ModuleState(ConcurrentDictionary<Declaration, byte> declarations)
3031
{
3132
Declarations = declarations;
32-
TokenStream = null;
33+
UnresolvedMemberDeclarations = new ConcurrentDictionary<UnboundMemberDeclaration, byte>();
34+
TokenStream = null;UnboundMemberDeclaration
3335
ParseTree = null;
3436

3537
if (declarations.Any() && declarations.ElementAt(0).Key.QualifiedName.QualifiedModuleName.Component != null)
@@ -55,6 +57,7 @@ public ModuleState(ConcurrentDictionary<Declaration, byte> declarations)
5557
public ModuleState(ParserState state)
5658
{
5759
Declarations = new ConcurrentDictionary<Declaration, byte>();
60+
UnresolvedMemberDeclarations = new ConcurrentDictionary<UnboundMemberDeclaration, byte>();
5861
TokenStream = null;
5962
ParseTree = null;
6063
State = state;
@@ -72,6 +75,7 @@ public ModuleState(ParserState state)
7275
public ModuleState(SyntaxErrorException moduleException)
7376
{
7477
Declarations = new ConcurrentDictionary<Declaration, byte>();
78+
UnresolvedMemberDeclarations = new ConcurrentDictionary<UnboundMemberDeclaration, byte>();
7579
TokenStream = null;
7680
ParseTree = null;
7781
State = ParserState.Error;
@@ -89,6 +93,7 @@ public ModuleState(SyntaxErrorException moduleException)
8993
public ModuleState(IDictionary<Tuple<string, DeclarationType>, Attributes> moduleAttributes)
9094
{
9195
Declarations = new ConcurrentDictionary<Declaration, byte>();
96+
UnresolvedMemberDeclarations = new ConcurrentDictionary<UnboundMemberDeclaration, byte>();
9297
TokenStream = null;
9398
ParseTree = null;
9499
State = ParserState.None;

Rubberduck.Parsing/VBA/ParseCoordinator.cs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ private void ExecuteCommonParseActivities(List<IVBComponent> toParse, Cancellati
241241
throw new OperationCanceledException(token);
242242
}
243243

244-
ResolveAllReferences(token);
244+
var toResolveReferences = State.ParseTrees.Select(kvp => kvp.Key).ToHashSet();
245+
ResolveAllReferences(toResolveReferences, token);
245246

246247
if (token.IsCancellationRequested || State.Status >= ParserState.Error)
247248
{
@@ -469,11 +470,11 @@ private Declaration CreateProjectDeclaration(QualifiedModuleName projectQualifie
469470
}
470471

471472

472-
private void ResolveAllReferences(CancellationToken token)
473+
private void ResolveAllReferences(ICollection<QualifiedModuleName> toResolve, CancellationToken token)
473474
{
474475
token.ThrowIfCancellationRequested();
475476

476-
var components = State.ParseTrees.Select(kvp => kvp.Key.Component).ToList();
477+
var components = toResolve.Select(qmn => qmn.Component).ToList();
477478

478479
token.ThrowIfCancellationRequested();
479480

@@ -485,13 +486,15 @@ private void ResolveAllReferences(CancellationToken token)
485486

486487
token.ThrowIfCancellationRequested();
487488

489+
var parseTreesToResolve = State.ParseTrees.Where(kvp => toResolve.Contains(kvp.Key)).ToList();
490+
488491
var options = new ParallelOptions();
489492
options.CancellationToken = token;
490493
options.MaxDegreeOfParallelism = _maxDegreeOfReferenceResolverParallelism;
491494
try
492495
{
493-
Parallel.For(0, State.ParseTrees.Count, options,
494-
(index) => ResolveReferences(State.DeclarationFinder, State.ParseTrees[index].Key, State.ParseTrees[index].Value, token)
496+
Parallel.For(0, parseTreesToResolve.Count, options,
497+
(index) => ResolveReferences(State.DeclarationFinder, parseTreesToResolve[index].Key, parseTreesToResolve[index].Value, token)
495498
);
496499
}
497500
catch (AggregateException exception)
@@ -510,10 +513,11 @@ private void ResolveAllReferences(CancellationToken token)
510513

511514
token.ThrowIfCancellationRequested();
512515

513-
AddUndeclaredVariablesToDeclarations();
516+
AddNewUndeclaredVariablesToDeclarations();
517+
AddNewUnresolvedMemberDeclarations();
514518

515519
//This is here and not in the calling method because it has to happen before the ready state is reached.
516-
//RefreshDeclarationFinder(); //Commented out because it breaks the unresolved and undeclared collections.
520+
RefreshDeclarationFinder();
517521

518522
token.ThrowIfCancellationRequested();
519523

@@ -604,15 +608,24 @@ private void AddModuleToModuleReferences(DeclarationFinder finder, QualifiedModu
604608
}
605609
}
606610

607-
private void AddUndeclaredVariablesToDeclarations()
611+
private void AddNewUndeclaredVariablesToDeclarations()
608612
{
609-
var undeclared = State.DeclarationFinder.Undeclared.ToList();
613+
var undeclared = State.DeclarationFinder.FreshUndeclared.ToList();
610614
foreach (var declaration in undeclared)
611615
{
612616
State.AddDeclaration(declaration);
613617
}
614618
}
615619

620+
private void AddNewUnresolvedMemberDeclarations()
621+
{
622+
var unresolved = State.DeclarationFinder.FreshUnresolvedMemberDeclarations().ToList();
623+
foreach (var declaration in unresolved)
624+
{
625+
State.AddUnresolvedMemberDeclaration(declaration);
626+
}
627+
}
628+
616629

617630
/// <summary>
618631
/// Starts parsing all components of all unprotected VBProjects associated with the VBE-Instance passed to the constructor of this parser instance.

Rubberduck.Parsing/VBA/RubberduckParserState.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public sealed class RubberduckParserState : IDisposable
6969

7070
internal void RefreshFinder(IHostApplication host)
7171
{
72-
DeclarationFinder = new DeclarationFinder(AllDeclarations, AllAnnotations, host);
72+
DeclarationFinder = new DeclarationFinder(AllDeclarations, AllAnnotations, AllUnresolvedMemberDeclarations, host);
7373
}
7474

7575
private readonly IVBE _vbe;
@@ -629,6 +629,28 @@ public IReadOnlyList<Declaration> AllDeclarations
629629
}
630630
}
631631

632+
/// <summary>
633+
/// Gets a copy of the unresolved member declarations.
634+
/// </summary>
635+
public IReadOnlyList<UnboundMemberDeclaration> AllUnresolvedMemberDeclarations
636+
{
637+
get
638+
{
639+
var declarations = new List<UnboundMemberDeclaration>();
640+
foreach (var state in _moduleStates.Values)
641+
{
642+
if (state.UnresolvedMemberDeclarations == null)
643+
{
644+
continue;
645+
}
646+
647+
declarations.AddRange(state.UnresolvedMemberDeclarations.Keys);
648+
}
649+
650+
return declarations;
651+
}
652+
}
653+
632654
private readonly ConcurrentBag<SerializableProject> _builtInDeclarationTrees = new ConcurrentBag<SerializableProject>();
633655
public IProducerConsumerCollection<SerializableProject> BuiltInDeclarationTrees { get { return _builtInDeclarationTrees; } }
634656

@@ -694,6 +716,28 @@ public void AddDeclaration(Declaration declaration)
694716
}
695717
}
696718

719+
/// <summary>
720+
/// Adds the specified <see cref="UnboundMemberDeclaration"/> to the collection (replaces existing).
721+
/// </summary>
722+
public void AddUnresolvedMemberDeclaration(UnboundMemberDeclaration declaration)
723+
{
724+
var key = declaration.QualifiedName.QualifiedModuleName;
725+
var declarations = _moduleStates.GetOrAdd(key, new ModuleState(new ConcurrentDictionary<Declaration, byte>())).UnresolvedMemberDeclarations;
726+
727+
if (declarations.ContainsKey(declaration))
728+
{
729+
byte _;
730+
while (!declarations.TryRemove(declaration, out _))
731+
{
732+
Logger.Warn("Could not remove existing unresolved member declaration for '{0}' ({1}). Retrying.", declaration.IdentifierName, declaration.DeclarationType);
733+
}
734+
}
735+
while (!declarations.TryAdd(declaration, 0) && !declarations.ContainsKey(declaration))
736+
{
737+
Logger.Warn("Could not add unresolved member declaration '{0}' ({1}). Retrying.", declaration.IdentifierName, declaration.DeclarationType);
738+
}
739+
}
740+
697741
private void ClearStateCache(string projectId, bool notifyStateChanged = false)
698742
{
699743
try

0 commit comments

Comments
 (0)