Skip to content

Commit 17a7a28

Browse files
committed
2 parents 50ec8a5 + ee893d2 commit 17a7a28

File tree

4 files changed

+134
-1
lines changed

4 files changed

+134
-1
lines changed

Rubberduck.Parsing/Symbols/DeclarationFinder.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,12 @@ public IEnumerable<Declaration> Undeclared
141141

142142
public IEnumerable<Declaration> Members(Declaration module)
143143
{
144-
return _declarations[module.QualifiedName.QualifiedModuleName];
144+
return Members(module.QualifiedName.QualifiedModuleName);
145+
}
146+
147+
public IEnumerable<Declaration> Members(QualifiedModuleName module)
148+
{
149+
return _declarations[module];
145150
}
146151

147152
private IEnumerable<Declaration> _nonBaseAsType;

Rubberduck.Parsing/VBA/ModuleState.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Antlr4.Runtime.Tree;
77
using Rubberduck.Parsing.Annotations;
88
using Rubberduck.Parsing.Symbols;
9+
using Rubberduck.VBEditor;
910

1011
namespace Rubberduck.Parsing.VBA
1112
{
@@ -20,6 +21,8 @@ public class ModuleState
2021
public List<IAnnotation> Annotations { get; private set; }
2122
public SyntaxErrorException ModuleException { get; private set; }
2223
public IDictionary<Tuple<string, DeclarationType>, Attributes> ModuleAttributes { get; private set; }
24+
public ConcurrentDictionary<QualifiedModuleName, byte> HasReferenceToModule { get; private set; }
25+
public HashSet<QualifiedModuleName> IsReferencedByModule { get; private set; }
2326

2427
public bool IsNew { get; private set; }
2528

@@ -43,6 +46,8 @@ public ModuleState(ConcurrentDictionary<Declaration, byte> declarations)
4346
Annotations = new List<IAnnotation>();
4447
ModuleException = null;
4548
ModuleAttributes = new Dictionary<Tuple<string, DeclarationType>, Attributes>();
49+
HasReferenceToModule = new ConcurrentDictionary<QualifiedModuleName, byte>();
50+
IsReferencedByModule = new HashSet<QualifiedModuleName>();
4651

4752
IsNew = true;
4853
}
@@ -58,6 +63,8 @@ public ModuleState(ParserState state)
5863
Annotations = new List<IAnnotation>();
5964
ModuleException = null;
6065
ModuleAttributes = new Dictionary<Tuple<string, DeclarationType>, Attributes>();
66+
HasReferenceToModule = new ConcurrentDictionary<QualifiedModuleName, byte>();
67+
IsReferencedByModule = new HashSet<QualifiedModuleName>();
6168

6269
IsNew = true;
6370
}
@@ -73,6 +80,8 @@ public ModuleState(SyntaxErrorException moduleException)
7380
Annotations = new List<IAnnotation>();
7481
ModuleException = moduleException;
7582
ModuleAttributes = new Dictionary<Tuple<string, DeclarationType>, Attributes>();
83+
HasReferenceToModule = new ConcurrentDictionary<QualifiedModuleName, byte>();
84+
IsReferencedByModule = new HashSet<QualifiedModuleName>();
7685

7786
IsNew = true;
7887
}
@@ -88,6 +97,8 @@ public ModuleState(IDictionary<Tuple<string, DeclarationType>, Attributes> modul
8897
Annotations = new List<IAnnotation>();
8998
ModuleException = null;
9099
ModuleAttributes = moduleAttributes;
100+
HasReferenceToModule = new ConcurrentDictionary<QualifiedModuleName, byte>();
101+
IsReferencedByModule = new HashSet<QualifiedModuleName>();
91102

92103
IsNew = true;
93104
}
@@ -141,6 +152,17 @@ public ModuleState SetModuleAttributes(IDictionary<Tuple<string, DeclarationType
141152
return this;
142153
}
143154

155+
public void RefreshHasReferenceToModule()
156+
{
157+
HasReferenceToModule = new ConcurrentDictionary<QualifiedModuleName, byte>();
158+
}
159+
160+
public void RefreshIsReferencedByModule()
161+
{
162+
IsReferencedByModule = new HashSet<QualifiedModuleName>();
163+
}
164+
165+
144166
private bool _isDisposed;
145167
public void Dispose()
146168
{

Rubberduck.Parsing/VBA/ParseCoordinator.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ private void ExecuteCommonParseActivities(List<IVBComponent> toParse, Cancellati
217217
_projectDeclarations.Clear();
218218
State.ClearAllReferences();
219219

220+
ClearModuleToModuleReferences(toParse);
221+
220222
ParseComponents(toParse, token);
221223

222224
if (token.IsCancellationRequested || State.Status >= ParserState.Error)
@@ -268,6 +270,14 @@ private void SetModuleStates(List<IVBComponent> components, ParserState parserSt
268270
}
269271
}
270272

273+
private void ClearModuleToModuleReferences(List<IVBComponent> toClear)
274+
{
275+
foreach (var component in toClear)
276+
{
277+
State.ClearModuleToModuleReferencesFromModule(new QualifiedModuleName(component));
278+
}
279+
}
280+
271281
private void ParseComponents(List<IVBComponent> components, CancellationToken token)
272282
{
273283
token.ThrowIfCancellationRequested();
@@ -496,6 +506,10 @@ private void ResolveAllReferences(CancellationToken token)
496506

497507
token.ThrowIfCancellationRequested();
498508

509+
AddModuleToModuleReferences(State.DeclarationFinder, token);
510+
511+
token.ThrowIfCancellationRequested();
512+
499513
AddUndeclaredVariablesToDeclarations();
500514

501515
//This is here and not in the calling method because it has to happen before the ready state is reached.
@@ -555,6 +569,41 @@ private void ResolveReferences(DeclarationFinder finder, QualifiedModuleName qua
555569
}
556570
}
557571

572+
private void AddModuleToModuleReferences(DeclarationFinder finder, CancellationToken token)
573+
{
574+
var options = new ParallelOptions();
575+
options.CancellationToken = token;
576+
options.MaxDegreeOfParallelism = _maxDegreeOfReferenceResolverParallelism;
577+
try
578+
{
579+
Parallel.For(0, State.ParseTrees.Count, options,
580+
(index) => AddModuleToModuleReferences(finder, State.ParseTrees[index].Key)
581+
);
582+
}
583+
catch (AggregateException exception)
584+
{
585+
if (exception.Flatten().InnerExceptions.All(ex => ex is OperationCanceledException))
586+
{
587+
throw exception.InnerException; //This eliminates the stack trace, but for the cancellation, this is irrelevant.
588+
}
589+
State.SetStatusAndFireStateChanged(this, ParserState.ResolverError);
590+
throw;
591+
}
592+
}
593+
594+
private void AddModuleToModuleReferences(DeclarationFinder finder, QualifiedModuleName referencedModule)
595+
{
596+
var referencingModules = finder.Members(referencedModule)
597+
.SelectMany(declaration => declaration.References)
598+
.Select(reference => reference.QualifiedModuleName)
599+
.Distinct()
600+
.Where(referencingModule => !referencedModule.Equals(referencingModule));
601+
foreach (var referencingModule in referencingModules)
602+
{
603+
State.AddModuleToModuleReference(referencedModule, referencingModule);
604+
}
605+
}
606+
558607
private void AddUndeclaredVariablesToDeclarations()
559608
{
560609
var undeclared = State.DeclarationFinder.Undeclared.ToList();
@@ -651,6 +700,7 @@ private bool CleanUpRemovedComponents(List<IVBComponent> components)
651700
var componentRemoved = removedModuledecalrations.Any();
652701
foreach (var declaration in removedModuledecalrations)
653702
{
703+
State.ClearModuleToModuleReferencesFromModule(declaration.QualifiedName.QualifiedModuleName);
654704
State.ClearStateCache(declaration.QualifiedName.QualifiedModuleName);
655705
}
656706
return componentRemoved;

Rubberduck.Parsing/VBA/RubberduckParserState.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,62 @@ public void RemoveBuiltInDeclarations(IReference reference)
10911091
}
10921092
}
10931093

1094+
public void AddModuleToModuleReference(QualifiedModuleName referencedModule, QualifiedModuleName referencingModule)
1095+
{
1096+
ModuleState referencedModuleState;
1097+
ModuleState referencingModuleState;
1098+
if (!_moduleStates.TryGetValue(referencedModule, out referencedModuleState) || !_moduleStates.TryGetValue(referencingModule, out referencingModuleState))
1099+
{
1100+
return;
1101+
}
1102+
if (referencedModuleState.IsReferencedByModule.Contains(referencingModule))
1103+
{
1104+
return;
1105+
}
1106+
referencedModuleState.IsReferencedByModule.Add(referencingModule);
1107+
referencingModuleState.HasReferenceToModule.AddOrUpdate(referencedModule, 1, (key, value) => value);
1108+
}
1109+
1110+
public void ClearModuleToModuleReferencesFromModule(QualifiedModuleName referencingModule)
1111+
{
1112+
ModuleState referencingModuleState;
1113+
if (!_moduleStates.TryGetValue(referencingModule, out referencingModuleState))
1114+
{
1115+
return;
1116+
}
1117+
1118+
ModuleState referencedModuleState;
1119+
foreach (var referencedModule in referencingModuleState.HasReferenceToModule.Keys)
1120+
{
1121+
if (!_moduleStates.TryGetValue(referencedModule,out referencedModuleState))
1122+
{
1123+
continue;
1124+
}
1125+
referencedModuleState.IsReferencedByModule.Remove(referencingModule);
1126+
}
1127+
referencingModuleState.RefreshHasReferenceToModule();
1128+
}
1129+
1130+
public HashSet<QualifiedModuleName> ModulesReferencedBy(QualifiedModuleName referencingModule)
1131+
{
1132+
ModuleState referencingModuleState;
1133+
if (!_moduleStates.TryGetValue(referencingModule, out referencingModuleState))
1134+
{
1135+
return new HashSet<QualifiedModuleName>();
1136+
}
1137+
return new HashSet<QualifiedModuleName>(referencingModuleState.HasReferenceToModule.Keys);
1138+
}
1139+
1140+
public HashSet<QualifiedModuleName> ModulesReferencing(QualifiedModuleName referencedModule)
1141+
{
1142+
ModuleState referencedModuleState;
1143+
if (!_moduleStates.TryGetValue(referencedModule, out referencedModuleState))
1144+
{
1145+
return new HashSet<QualifiedModuleName>();
1146+
}
1147+
return new HashSet<QualifiedModuleName>(referencedModuleState.IsReferencedByModule);
1148+
}
1149+
10941150
private bool _isDisposed;
10951151

10961152
public void Dispose()

0 commit comments

Comments
 (0)