Skip to content

Commit

Permalink
added support for prioritized project references (ref. #1340)
Browse files Browse the repository at this point in the history
  • Loading branch information
retailcoder committed Apr 21, 2016
1 parent ad79a9d commit 9508e47
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 51 deletions.
2 changes: 1 addition & 1 deletion RetailCoder.VBE/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ private void referencesSink_ReferenceAdded(object sender, DispatcherEventArgs<Re
{
Debug.WriteLine(string.Format("Reference '{0}' was added.", e.Item.Name));
var state = _parser.State.Status;
_parser.LoadComReference(e.Item);
_parser.LoadNewComReferences();
_parser.State.SetModuleState(state);
}

Expand Down
2 changes: 1 addition & 1 deletion Rubberduck.Parsing/IRubberduckParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Rubberduck.Parsing
public interface IRubberduckParser
{
RubberduckParserState State { get; }
void LoadComReference(Reference item);
void LoadNewComReferences();
void UnloadComReference(Reference reference);
void ParseComponent(VBComponent component, TokenStreamRewriter rewriter = null);
Task ParseAsync(VBComponent component, CancellationToken token, TokenStreamRewriter rewriter = null);
Expand Down
1 change: 1 addition & 0 deletions Rubberduck.Parsing/Rubberduck.Parsing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@
<Compile Include="VBA\Nodes\ProcedureNode.cs" />
<Compile Include="VBA\ParseErrorEventArgs.cs" />
<Compile Include="VBA\ParserState.cs" />
<Compile Include="VBA\ReferencePriorityMap.cs" />
<Compile Include="VBA\RubberduckParser.cs" />
<Compile Include="VBA\RubberduckParserState.cs" />
<Compile Include="VBA\StringExtensions.cs" />
Expand Down
38 changes: 38 additions & 0 deletions Rubberduck.Parsing/VBA/ReferencePriorityMap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Collections.Generic;
using Microsoft.Vbe.Interop;

namespace Rubberduck.Parsing.VBA
{
/// <summary>
/// A <c>Dictionary</c> keyed with a <see cref="VBProject"/>'s ID and valued with an <see cref="int"/> representing a <see cref="Reference"/>'s priority for that project.
/// </summary>
public class ReferencePriorityMap : Dictionary<string, int>
{
private readonly string _referenceId;

public ReferencePriorityMap(string referenceId)
{
_referenceId = referenceId;
}

public string ReferenceId
{
get { return _referenceId; }
}

public bool IsLoaded { get; set; }

public override bool Equals(object obj)
{
var other = obj as ReferencePriorityMap;
if (other == null) return false;

return other.ReferenceId == ReferenceId;
}

public override int GetHashCode()
{
return _referenceId.GetHashCode();
}
}
}
88 changes: 46 additions & 42 deletions Rubberduck.Parsing/VBA/RubberduckParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
using System.Globalization;
using Rubberduck.Parsing.Preprocessing;
using System.Diagnostics;
using Rubberduck.Common;
using Rubberduck.Parsing.Grammar;
using Rubberduck.Parsing.Nodes;
using Rubberduck.VBEditor.Extensions;

namespace Rubberduck.Parsing.VBA
{
Expand All @@ -27,6 +27,7 @@ public RubberduckParserState State
return _state;
}
}

private CancellationTokenSource _central = new CancellationTokenSource();
private CancellationTokenSource _resolverTokenSource; // linked to _central later
private readonly ConcurrentDictionary<VBComponent, Tuple<Task, CancellationTokenSource>> _currentTasks =
Expand Down Expand Up @@ -72,7 +73,6 @@ private void StateOnStateChanged(object sender, EventArgs e)

private void ReparseRequested(object sender, ParseRequestEventArgs e)
{
_force = false;
if (e.IsFullReparseRequest)
{
Cancel();
Expand All @@ -85,10 +85,8 @@ private void ReparseRequested(object sender, ParseRequestEventArgs e)
}
}

private bool _force;
public void Parse()
{
_force = true;
if (!_state.Projects.Any())
{
foreach (var project in _vbe.VBProjects.Cast<VBProject>())
Expand Down Expand Up @@ -131,7 +129,6 @@ public void Parse()
/// </summary>
private void ParseAll()
{
_force = false;
var projects = _state.Projects
.Where(project => project.Protection == vbext_ProjectProtection.vbext_pp_none)
.ToList();
Expand Down Expand Up @@ -161,58 +158,65 @@ private void ParseAll()
}
}

private readonly HashSet<Guid> _loadedReferences = new HashSet<Guid>();
private readonly HashSet<ReferencePriorityMap> _references = new HashSet<ReferencePriorityMap>();

private void LoadComReferences(IEnumerable<VBProject> projects)
{
var references = projects.SelectMany(p => p.References.Cast<Reference>()).ToList();
var newReferences = references
.Select(reference => new {Guid = new Guid(reference.Guid), Reference = reference})
.Where(item => !_loadedReferences.Contains(item.Guid));

for (var i = 0; i < references.Count; i++)
foreach (var vbProject in projects)
{

}
var projectId = vbProject.ProjectId();
for (var priority = 0; priority < vbProject.References.Count; priority++)
{
var reference = vbProject.References.Item(priority);
var referenceId = reference.ReferenceId();

foreach (var item in newReferences)
{
LoadComReference(item.Reference);
var map = _references.SingleOrDefault(r => r.ReferenceId == referenceId);
if (map == null)
{
map = new ReferencePriorityMap(referenceId) {{projectId, priority}};
_references.Add(map);
}
else
{
map[projectId] = priority;
}

if (!map.IsLoaded)
{
var items = _comReflector.GetDeclarationsForReference(reference).ToList();
foreach (var declaration in items)
{
_state.AddDeclaration(declaration);
}
map.IsLoaded = true;
}
}
}
}

public void LoadComReference(Reference item)
public void LoadNewComReferences()
{
var guid = new Guid(item.Guid);
if (_loadedReferences.Contains(guid))
{
return;
}

var items = _comReflector.GetDeclarationsForReference(item).ToList();
foreach (var declaration in items)
{
_state.AddDeclaration(declaration);
}

_loadedReferences.Add(new Guid(item.Guid));
LoadComReferences(_state.Projects);
}

public void UnloadComReference(Reference reference)
{
var projects = _state.Projects
.Where(project => project.Protection == vbext_ProjectProtection.vbext_pp_none)
.ToList();
var referenceId = reference.ReferenceId();
var map = _references.SingleOrDefault(r => r.ReferenceId == referenceId);
if (map == null || !map.IsLoaded)
{
// we're removing a reference we weren't tracking? ...this shouldn't happen.
Debug.Assert(false);
return;
}

var references = projects.SelectMany(p => p.References.Cast<Reference>()).ToList();
var target = references
.Select(item => new { Guid = new Guid(item.Guid), Reference = item })
.SingleOrDefault(item => _loadedReferences.Contains(item.Guid) && reference.Guid == item.Guid.ToString());
var projectId = reference.Collection.Parent.ProjectId();
map.Remove(projectId);

if (target != null)
if (!map.Any())
{
_state.RemoveBuiltInDeclarations(target.Reference);
var guid = new Guid(reference.Guid);
_loadedReferences.Remove(guid);
_references.Remove(map);
_state.RemoveBuiltInDeclarations(reference);
}
}

Expand Down
9 changes: 2 additions & 7 deletions Rubberduck.Parsing/VBA/RubberduckParserState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,7 @@ public void RemoveProject(string projectId)

public void RemoveProject(VBProject project)
{
var projectId = project.HelpFile;
RemoveProject(projectId);

// note: attempt to fix ghost projects
projectId = project.Name;
RemoveProject(projectId);
RemoveProject(project.ProjectId());
}

public IEnumerable<VBProject> Projects
Expand Down Expand Up @@ -577,7 +572,7 @@ public void RemoveBuiltInDeclarations(Reference reference)
ConcurrentDictionary<Declaration, byte> items;
if (!_declarations.TryRemove(key, out items))
{
Debug.WriteLine("Could not remove declarations for removed reference '{0}' ({1}).", reference.Name, reference.Guid);
Debug.WriteLine("Could not remove declarations for removed reference '{0}' ({1}).", reference.Name, reference.ReferenceId());
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions Rubberduck.VBEEditor/Extensions/VbProjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ namespace Rubberduck.VBEditor.Extensions
{
public static class ProjectExtensions
{
public static string ProjectId(this VBProject project)
{
return project.HelpFile;
}

public static string ReferenceId(this Reference reference)
{
return string.IsNullOrEmpty(reference.Guid)
? reference.FullPath
: reference.Guid;
}

public static IEnumerable<string> ComponentNames(this VBProject project)
{
return project.VBComponents.Cast<VBComponent>().Select(component => component.Name);
Expand Down

0 comments on commit 9508e47

Please sign in to comment.