Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Fix wait for analysis complete, fix tests and avoid reload on all config changes #110

Merged
merged 17 commits into from
Sep 20, 2018
3 changes: 2 additions & 1 deletion src/Analysis/Engine/Impl/Definitions/IModuleAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

namespace Microsoft.PythonTools.Analysis {
public interface IModuleAnalysis {
int Version { get; }
IModuleContext InterpreterContext { get; }
PythonAnalyzer ProjectState { get; }
IScope Scope { get; }
Expand Down Expand Up @@ -146,7 +147,7 @@ public interface IModuleAnalysis {
/// <param name="location">
/// The location in the file where the available members should be looked up.
/// </param>
IEnumerable<IMemberResult> GetAllAvailableMembers(SourceLocation location, GetMemberOptions options = GetMemberOptions.IntersectMultipleResults);
IEnumerable<IMemberResult> GetAllMembers(SourceLocation location, GetMemberOptions options = GetMemberOptions.IntersectMultipleResults);

/// <summary>
/// Gets the AST for the given text as if it appeared at the specified location.
Expand Down
25 changes: 15 additions & 10 deletions src/Analysis/Engine/Impl/ModuleAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,21 @@ namespace Microsoft.PythonTools.Analysis {
///
/// Can be queried for various information about the resulting analysis.
/// </summary>
public sealed class ModuleAnalysis: IModuleAnalysis {
public sealed class ModuleAnalysis : IModuleAnalysis {
private readonly AnalysisUnit _unit;
private static Regex _otherPrivateRegex = new Regex("^_[a-zA-Z_]\\w*__[a-zA-Z_]\\w*$");

private static readonly IEnumerable<IOverloadResult> GetSignaturesError =
new[] { new OverloadResult(new ParameterResult[0], "Unknown", "IntellisenseError_Sigs", null) };

internal ModuleAnalysis(AnalysisUnit unit, InterpreterScope scope) {
internal ModuleAnalysis(AnalysisUnit unit, InterpreterScope scope, int version) {
_unit = unit;
Scope = scope;
Version = version;
}

#region Public API

public int Version { get; }
/// <summary>
/// Evaluates the given expression in at the provided line number and returns the values
/// that the expression can evaluate to.
Expand Down Expand Up @@ -350,7 +351,7 @@ public IEnumerable<IMemberResult> GetMembers(
GetMemberOptions options = GetMemberOptions.IntersectMultipleResults
) {
if (string.IsNullOrEmpty(exprText)) {
return GetAllAvailableMembers(location, options);
return GetAllMembers(location, options);
}

var expr = GetExpressionForText(exprText, location, out var scope, out var ast);
Expand Down Expand Up @@ -526,7 +527,7 @@ expr is TupleExpression ||
/// specified location.
/// </summary>
/// <param name="index">The 0-based absolute index into the file.</param>
internal IEnumerable<IMemberResult> GetDefinitionTreeByIndex(int index)
internal IEnumerable<IMemberResult> GetDefinitionTreeByIndex(int index)
=> GetDefinitionTree(_unit.Tree.IndexToLocation(index));

/// <summary>
Expand Down Expand Up @@ -630,7 +631,11 @@ public IEnumerable<IOverloadResult> GetOverrideable(SourceLocation location) {
internal IEnumerable<IMemberResult> GetAllAvailableMembersByIndex(
int index,
GetMemberOptions options = GetMemberOptions.IntersectMultipleResults
) => GetAllAvailableMembers(_unit.Tree.IndexToLocation(index), options);
) => GetAllMembers(_unit.Tree.IndexToLocation(index), options);

[Obsolete]
public IEnumerable<MemberResult> GetAllAvailableMembers(SourceLocation location, GetMemberOptions options = GetMemberOptions.IntersectMultipleResults)
=> GetAllMembers(location, options).OfType<MemberResult>();

/// <summary>
/// Gets the available names at the given location. This includes
Expand All @@ -641,7 +646,7 @@ internal IEnumerable<IMemberResult> GetAllAvailableMembersByIndex(
/// looked up.
/// </param>
/// <remarks>New in 2.2</remarks>
public IEnumerable<IMemberResult> GetAllAvailableMembers(SourceLocation location, GetMemberOptions options = GetMemberOptions.IntersectMultipleResults) {
public IEnumerable<IMemberResult> GetAllMembers(SourceLocation location, GetMemberOptions options = GetMemberOptions.IntersectMultipleResults) {
var result = new Dictionary<string, IEnumerable<AnalysisValue>>();

// collect builtins
Expand Down Expand Up @@ -989,9 +994,9 @@ private static bool IsInFunctionParameter(InterpreterScope scope, PythonAst tree
}

return function.Parameters.Any(p => {
var paramName = p.GetVerbatimImage(tree) ?? p.Name;
return index >= p.StartIndex && index <= p.StartIndex + paramName.Length;
});
var paramName = p.GetVerbatimImage(tree) ?? p.Name;
return index >= p.StartIndex && index <= p.StartIndex + paramName.Length;
});
}

private static int GetParentScopeIndent(InterpreterScope scope, PythonAst tree) {
Expand Down
47 changes: 24 additions & 23 deletions src/Analysis/Engine/Impl/ProjectEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,15 @@ namespace Microsoft.PythonTools.Analysis {
[SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
Justification = "Unclear ownership makes it unlikely this object will be disposed correctly")]
internal sealed class ProjectEntry : IPythonProjectEntry, IAggregateableProjectEntry, IDocument {
private AnalysisUnit _unit;
private TaskCompletionSource<IModuleAnalysis> _analysisTcs = new TaskCompletionSource<IModuleAnalysis>();
private readonly SortedDictionary<int, DocumentBuffer> _buffers;
private readonly ConcurrentQueue<WeakReference<ReferenceDict>> _backReferences = new ConcurrentQueue<WeakReference<ReferenceDict>>();
internal readonly HashSet<AggregateProjectEntry> _aggregates = new HashSet<AggregateProjectEntry>();
private readonly HashSet<AggregateProjectEntry> _aggregates = new HashSet<AggregateProjectEntry>();

private TaskCompletionSource<IModuleAnalysis> _analysisTcs = new TaskCompletionSource<IModuleAnalysis>();
private AnalysisUnit _unit;
private readonly ManualResetEventSlim _pendingParse = new ManualResetEventSlim(true);
private long _expectedParseVersion;
private long _expectedAnalysisVersion;

internal ProjectEntry(
PythonAnalyzer state,
Expand Down Expand Up @@ -84,17 +88,14 @@ internal static Uri MakeDocumentUri(string filePath) {
public event EventHandler<EventArgs> NewParseTree;
public event EventHandler<EventArgs> NewAnalysis;

private readonly ManualResetEventSlim _pendingParse = new ManualResetEventSlim(true);
private long _expectedParse;

private class ActivePythonParse : IPythonParse {
private readonly ProjectEntry _entry;
private readonly long _expected;
private readonly long _expectedVersion;
private bool _completed;

public ActivePythonParse(ProjectEntry entry, long expected) {
public ActivePythonParse(ProjectEntry entry, long expectedVersion) {
_entry = entry;
_expected = expected;
_expectedVersion = expectedVersion;
}

public PythonAst Tree { get; set; }
Expand All @@ -105,7 +106,7 @@ public void Dispose() {
return;
}
lock (_entry) {
if (_entry._expectedParse == _expected) {
if (_entry._expectedParseVersion == _expectedVersion) {
_entry._pendingParse.Set();
}
}
Expand All @@ -114,7 +115,7 @@ public void Dispose() {
public void Complete() {
_completed = true;
lock (_entry) {
if (_entry._expectedParse == _expected) {
if (_entry._expectedParseVersion == _expectedVersion) {
_entry.SetCurrentParse(Tree, Cookie);
_entry._pendingParse.Set();
}
Expand All @@ -125,8 +126,8 @@ public void Complete() {
public IPythonParse BeginParse() {
_pendingParse.Reset();
lock (this) {
_expectedParse += 1;
return new ActivePythonParse(this, _expectedParse);
_expectedParseVersion += 1;
return new ActivePythonParse(this, _expectedParseVersion);
}
}

Expand Down Expand Up @@ -157,14 +158,18 @@ public IPythonParse GetCurrentParse() {

internal void SetCompleteAnalysis() {
lock (this) {
if (_expectedAnalysisVersion != Analysis.Version) {
return;
}
_analysisTcs.TrySetResult(Analysis);
}
RaiseNewAnalysis();
}

internal void ResetCompleteAnalysis() {
TaskCompletionSource<IModuleAnalysis> analysisTcs;
TaskCompletionSource<IModuleAnalysis> analysisTcs = null;
lock (this) {
_expectedAnalysisVersion = AnalysisVersion + 1;
analysisTcs = _analysisTcs;
_analysisTcs = new TaskCompletionSource<IModuleAnalysis>(TaskCreationOptions.RunContinuationsAsynchronously);
}
Expand All @@ -188,14 +193,9 @@ public void SetCurrentParse(PythonAst tree, IAnalysisCookie cookie, bool notify
return GetCurrentParse();
}

internal bool IsVisible(ProjectEntry assigningScope) => true;

internal bool IsVisible(ProjectEntry assigningScope) {
return true;
}

public void Analyze(CancellationToken cancel) {
Analyze(cancel, false);
}
public void Analyze(CancellationToken cancel) => Analyze(cancel, false);

public void Analyze(CancellationToken cancel, bool enqueueOnly) {
if (cancel.IsCancellationRequested) {
Expand Down Expand Up @@ -290,7 +290,7 @@ private void Parse(bool enqueueOnly, CancellationToken cancel) {
string pathPrefix = PathUtils.EnsureEndSeparator(Path.GetDirectoryName(FilePath));
var children =
from pair in ProjectState.ModulesByFilename
// Is the candidate child package in a subdirectory of our package?
// Is the candidate child package in a subdirectory of our package?
let fileName = pair.Key
where fileName.StartsWithOrdinal(pathPrefix, ignoreCase: true)
let moduleName = pair.Value.Name
Expand All @@ -314,7 +314,8 @@ where lastDot > 0
// publish the analysis now that it's complete/running
Analysis = new ModuleAnalysis(
_unit,
((ModuleScope)_unit.Scope).CloneForPublish()
((ModuleScope)_unit.Scope).CloneForPublish(),
AnalysisVersion
);
}

Expand Down
Loading