Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
comintern committed Mar 1, 2017
2 parents 50ec8a5 + ee893d2 commit 17a7a28
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 1 deletion.
7 changes: 6 additions & 1 deletion Rubberduck.Parsing/Symbols/DeclarationFinder.cs
Expand Up @@ -141,7 +141,12 @@ public IEnumerable<Declaration> Undeclared

public IEnumerable<Declaration> Members(Declaration module)
{
return _declarations[module.QualifiedName.QualifiedModuleName];
return Members(module.QualifiedName.QualifiedModuleName);
}

public IEnumerable<Declaration> Members(QualifiedModuleName module)
{
return _declarations[module];
}

private IEnumerable<Declaration> _nonBaseAsType;
Expand Down
22 changes: 22 additions & 0 deletions Rubberduck.Parsing/VBA/ModuleState.cs
Expand Up @@ -6,6 +6,7 @@
using Antlr4.Runtime.Tree;
using Rubberduck.Parsing.Annotations;
using Rubberduck.Parsing.Symbols;
using Rubberduck.VBEditor;

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

public bool IsNew { get; private set; }

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

IsNew = true;
}
Expand All @@ -58,6 +63,8 @@ public ModuleState(ParserState state)
Annotations = new List<IAnnotation>();
ModuleException = null;
ModuleAttributes = new Dictionary<Tuple<string, DeclarationType>, Attributes>();
HasReferenceToModule = new ConcurrentDictionary<QualifiedModuleName, byte>();
IsReferencedByModule = new HashSet<QualifiedModuleName>();

IsNew = true;
}
Expand All @@ -73,6 +80,8 @@ public ModuleState(SyntaxErrorException moduleException)
Annotations = new List<IAnnotation>();
ModuleException = moduleException;
ModuleAttributes = new Dictionary<Tuple<string, DeclarationType>, Attributes>();
HasReferenceToModule = new ConcurrentDictionary<QualifiedModuleName, byte>();
IsReferencedByModule = new HashSet<QualifiedModuleName>();

IsNew = true;
}
Expand All @@ -88,6 +97,8 @@ public ModuleState(IDictionary<Tuple<string, DeclarationType>, Attributes> modul
Annotations = new List<IAnnotation>();
ModuleException = null;
ModuleAttributes = moduleAttributes;
HasReferenceToModule = new ConcurrentDictionary<QualifiedModuleName, byte>();
IsReferencedByModule = new HashSet<QualifiedModuleName>();

IsNew = true;
}
Expand Down Expand Up @@ -141,6 +152,17 @@ public ModuleState SetModuleAttributes(IDictionary<Tuple<string, DeclarationType
return this;
}

public void RefreshHasReferenceToModule()
{
HasReferenceToModule = new ConcurrentDictionary<QualifiedModuleName, byte>();
}

public void RefreshIsReferencedByModule()
{
IsReferencedByModule = new HashSet<QualifiedModuleName>();
}


private bool _isDisposed;
public void Dispose()
{
Expand Down
50 changes: 50 additions & 0 deletions Rubberduck.Parsing/VBA/ParseCoordinator.cs
Expand Up @@ -217,6 +217,8 @@ private void ExecuteCommonParseActivities(List<IVBComponent> toParse, Cancellati
_projectDeclarations.Clear();
State.ClearAllReferences();

ClearModuleToModuleReferences(toParse);

ParseComponents(toParse, token);

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

private void ClearModuleToModuleReferences(List<IVBComponent> toClear)
{
foreach (var component in toClear)
{
State.ClearModuleToModuleReferencesFromModule(new QualifiedModuleName(component));
}
}

private void ParseComponents(List<IVBComponent> components, CancellationToken token)
{
token.ThrowIfCancellationRequested();
Expand Down Expand Up @@ -496,6 +506,10 @@ private void ResolveAllReferences(CancellationToken token)

token.ThrowIfCancellationRequested();

AddModuleToModuleReferences(State.DeclarationFinder, token);

token.ThrowIfCancellationRequested();

AddUndeclaredVariablesToDeclarations();

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

private void AddModuleToModuleReferences(DeclarationFinder finder, CancellationToken token)
{
var options = new ParallelOptions();
options.CancellationToken = token;
options.MaxDegreeOfParallelism = _maxDegreeOfReferenceResolverParallelism;
try
{
Parallel.For(0, State.ParseTrees.Count, options,
(index) => AddModuleToModuleReferences(finder, State.ParseTrees[index].Key)
);
}
catch (AggregateException exception)
{
if (exception.Flatten().InnerExceptions.All(ex => ex is OperationCanceledException))
{
throw exception.InnerException; //This eliminates the stack trace, but for the cancellation, this is irrelevant.
}
State.SetStatusAndFireStateChanged(this, ParserState.ResolverError);
throw;
}
}

private void AddModuleToModuleReferences(DeclarationFinder finder, QualifiedModuleName referencedModule)
{
var referencingModules = finder.Members(referencedModule)
.SelectMany(declaration => declaration.References)
.Select(reference => reference.QualifiedModuleName)
.Distinct()
.Where(referencingModule => !referencedModule.Equals(referencingModule));
foreach (var referencingModule in referencingModules)
{
State.AddModuleToModuleReference(referencedModule, referencingModule);
}
}

private void AddUndeclaredVariablesToDeclarations()
{
var undeclared = State.DeclarationFinder.Undeclared.ToList();
Expand Down Expand Up @@ -651,6 +700,7 @@ private bool CleanUpRemovedComponents(List<IVBComponent> components)
var componentRemoved = removedModuledecalrations.Any();
foreach (var declaration in removedModuledecalrations)
{
State.ClearModuleToModuleReferencesFromModule(declaration.QualifiedName.QualifiedModuleName);
State.ClearStateCache(declaration.QualifiedName.QualifiedModuleName);
}
return componentRemoved;
Expand Down
56 changes: 56 additions & 0 deletions Rubberduck.Parsing/VBA/RubberduckParserState.cs
Expand Up @@ -1091,6 +1091,62 @@ public void RemoveBuiltInDeclarations(IReference reference)
}
}

public void AddModuleToModuleReference(QualifiedModuleName referencedModule, QualifiedModuleName referencingModule)
{
ModuleState referencedModuleState;
ModuleState referencingModuleState;
if (!_moduleStates.TryGetValue(referencedModule, out referencedModuleState) || !_moduleStates.TryGetValue(referencingModule, out referencingModuleState))
{
return;
}
if (referencedModuleState.IsReferencedByModule.Contains(referencingModule))
{
return;
}
referencedModuleState.IsReferencedByModule.Add(referencingModule);
referencingModuleState.HasReferenceToModule.AddOrUpdate(referencedModule, 1, (key, value) => value);
}

public void ClearModuleToModuleReferencesFromModule(QualifiedModuleName referencingModule)
{
ModuleState referencingModuleState;
if (!_moduleStates.TryGetValue(referencingModule, out referencingModuleState))
{
return;
}

ModuleState referencedModuleState;
foreach (var referencedModule in referencingModuleState.HasReferenceToModule.Keys)
{
if (!_moduleStates.TryGetValue(referencedModule,out referencedModuleState))
{
continue;
}
referencedModuleState.IsReferencedByModule.Remove(referencingModule);
}
referencingModuleState.RefreshHasReferenceToModule();
}

public HashSet<QualifiedModuleName> ModulesReferencedBy(QualifiedModuleName referencingModule)
{
ModuleState referencingModuleState;
if (!_moduleStates.TryGetValue(referencingModule, out referencingModuleState))
{
return new HashSet<QualifiedModuleName>();
}
return new HashSet<QualifiedModuleName>(referencingModuleState.HasReferenceToModule.Keys);
}

public HashSet<QualifiedModuleName> ModulesReferencing(QualifiedModuleName referencedModule)
{
ModuleState referencedModuleState;
if (!_moduleStates.TryGetValue(referencedModule, out referencedModuleState))
{
return new HashSet<QualifiedModuleName>();
}
return new HashSet<QualifiedModuleName>(referencedModuleState.IsReferencedByModule);
}

private bool _isDisposed;

public void Dispose()
Expand Down

0 comments on commit 17a7a28

Please sign in to comment.