提交 d8c89de9 编写于 作者: H Heejae Chang 提交者: GitHub

Merge pull request #20051 from heejaechang/FixRace

fix race on _storage field.
...@@ -65,7 +65,11 @@ public RecoverableWeakValueSource(RecoverableWeakValueSource<T> savedSource) ...@@ -65,7 +65,11 @@ public RecoverableWeakValueSource(RecoverableWeakValueSource<T> savedSource)
public override bool TryGetValue(out T value) public override bool TryGetValue(out T value)
{ {
return _weakInstance.TryGetTarget(out value); // it has 2 fields that can hold onto the value. if we only check weakInstance, we will
// return false for the initial case where weakInstance is set to s_noReference even if
// value can be retrieved from _recoverySource. so we check both here.
return _weakInstance.TryGetTarget(out value) ||
_recoverySource.TryGetValue(out value);
} }
public override T GetValue(CancellationToken cancellationToken) public override T GetValue(CancellationToken cancellationToken)
......
...@@ -82,6 +82,8 @@ internal sealed class RecoverableSyntaxRoot<TRoot> : RecoverableWeakValueSource< ...@@ -82,6 +82,8 @@ internal sealed class RecoverableSyntaxRoot<TRoot> : RecoverableWeakValueSource<
IRecoverableSyntaxTree<TRoot> containingTree) IRecoverableSyntaxTree<TRoot> containingTree)
: base(originalRoot) : base(originalRoot)
{ {
Contract.ThrowIfNull(originalRoot._storage);
_service = originalRoot._service; _service = originalRoot._service;
_storage = originalRoot._storage; _storage = originalRoot._storage;
_containingTree = containingTree; _containingTree = containingTree;
...@@ -89,14 +91,15 @@ internal sealed class RecoverableSyntaxRoot<TRoot> : RecoverableWeakValueSource< ...@@ -89,14 +91,15 @@ internal sealed class RecoverableSyntaxRoot<TRoot> : RecoverableWeakValueSource<
public RecoverableSyntaxRoot<TRoot> WithSyntaxTree(IRecoverableSyntaxTree<TRoot> containingTree) public RecoverableSyntaxRoot<TRoot> WithSyntaxTree(IRecoverableSyntaxTree<TRoot> containingTree)
{ {
// at this point, we should either have strongly held root or _storage should not be null
if (this.TryGetValue(out var root)) if (this.TryGetValue(out var root))
{ {
var result = new RecoverableSyntaxRoot<TRoot>(_service, root, containingTree); // we have strongly held root
result._storage = _storage; return new RecoverableSyntaxRoot<TRoot>(_service, root, containingTree);
return result;
} }
else else
{ {
// we have _storage here. _storage != null is checked inside
return new RecoverableSyntaxRoot<TRoot>(this, containingTree); return new RecoverableSyntaxRoot<TRoot>(this, containingTree);
} }
} }
......
...@@ -1465,6 +1465,34 @@ public async Task TestMassiveFileSize() ...@@ -1465,6 +1465,34 @@ public async Task TestMassiveFileSize()
} }
} }
[Fact, Trait(Traits.Feature, Traits.Features.Workspace)]
[WorkItem(18697, "https://github.com/dotnet/roslyn/issues/18697")]
public void TestWithSyntaxTree()
{
// get one to get to syntax tree factory
var dummyProject = CreateNotKeptAliveSolution().AddProject("dummy", "dummy", LanguageNames.CSharp);
var factory = dummyProject.LanguageServices.SyntaxTreeFactory;
// create the origin tree
var strongTree = factory.ParseSyntaxTree("dummy", dummyProject.ParseOptions, SourceText.From("// emtpy"), CancellationToken.None);
// create recoverable tree off the original tree
var recoverableTree = factory.CreateRecoverableTree(
dummyProject.Id,
strongTree.FilePath,
strongTree.Options,
new ConstantValueSource<TextAndVersion>(TextAndVersion.Create(strongTree.GetText(), VersionStamp.Create(), strongTree.FilePath)),
strongTree.GetText().Encoding,
strongTree.GetRoot());
// create new tree before it ever getting root node
var newTree = recoverableTree.WithFilePath("different/dummy");
// this shouldn't throw
var root = newTree.GetRoot();
}
private static void GetMultipleProjects( private static void GetMultipleProjects(
out Project csBrokenProject, out Project csBrokenProject,
out Project vbNormalProject, out Project vbNormalProject,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册