提交 fce57c59 编写于 作者: C CyrusNajmabadi

Fix crash when trying to get speculative info on too small an expression.

上级 5f014b56
......@@ -229,9 +229,31 @@ private static IEnumerable<SyntaxTrivia> MassageTrivia(IEnumerable<SyntaxTrivia>
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var previousSymbol = semanticModel.GetSymbolInfo(invocationOrCreation).Symbol;
var updatedInvocationOrCreation = invocationOrCreation.ReplaceNode(identifier, declarationExpression);
var updatedSymbolInfo = semanticModel.GetSpeculativeSymbolInfo(
invocationOrCreation.SpanStart, updatedInvocationOrCreation, SpeculativeBindingOption.BindAsExpression);
// Now, create a speculative model in which we make the change. Make sure
// we still point to the same symbol afterwards.
var topmostContainer = GetTopmostContainer(invocationOrCreation);
if (topmostContainer == null)
{
// Couldn't figure out what we were contained in. Have to assume that semantics
// Are changing.
return true;
}
var annotation = new SyntaxAnnotation();
var updatedTopmostContainer = topmostContainer.ReplaceNode(
invocationOrCreation, invocationOrCreation.ReplaceNode(identifier, declarationExpression)
.WithAdditionalAnnotations(annotation));
if (!TryGetSpeculativeSemanticModel(semanticModel,
topmostContainer.SpanStart, updatedTopmostContainer, out var speculativeModel))
{
// Couldn't figure out the new semantics. Assume semantics changed.
return true;
}
var updatedInvocationOrCreation = updatedTopmostContainer.GetAnnotatedNodes(annotation).Single();
var updatedSymbolInfo = speculativeModel.GetSymbolInfo(updatedInvocationOrCreation);
if (!SymbolEquivalenceComparer.Instance.Equals(previousSymbol, updatedSymbolInfo.Symbol))
{
......@@ -243,6 +265,36 @@ private static IEnumerable<SyntaxTrivia> MassageTrivia(IEnumerable<SyntaxTrivia>
return false;
}
private SyntaxNode GetTopmostContainer(ExpressionSyntax expression)
{
return expression.GetAncestorsOrThis(
a => a is StatementSyntax ||
a is EqualsValueClauseSyntax ||
a is ArrowExpressionClauseSyntax ||
a is ConstructorInitializerSyntax).LastOrDefault();
}
private bool TryGetSpeculativeSemanticModel(
SemanticModel semanticModel,
int position, SyntaxNode topmostContainer,
out SemanticModel speculativeModel)
{
switch (topmostContainer)
{
case StatementSyntax statement:
return semanticModel.TryGetSpeculativeSemanticModel(position, statement, out speculativeModel);
case EqualsValueClauseSyntax equalsValue:
return semanticModel.TryGetSpeculativeSemanticModel(position, equalsValue, out speculativeModel);
case ArrowExpressionClauseSyntax arrowExpression:
return semanticModel.TryGetSpeculativeSemanticModel(position, arrowExpression, out speculativeModel);
case ConstructorInitializerSyntax constructorInitializer:
return semanticModel.TryGetSpeculativeSemanticModel(position, constructorInitializer, out speculativeModel);
}
speculativeModel = null;
return false;
}
private TypeSyntax GetDeclarationType(
TypeSyntax type, bool useVarWhenDeclaringLocals, bool useImplicitTypeForIntrinsicTypes)
{
......
......@@ -193,12 +193,12 @@ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymb
// The variable is read or written from outside the block that the new variable
// would be scoped in. This would cause a break.
//
// Note(cyrusn): We coudl still offer the refactoring, but just show an error in the
// Note(cyrusn): We could still offer the refactoring, but just show an error in the
// preview in this case.
return;
}
// Make sure the variable isn't ever acessed before the usage in this out-var.
// Make sure the variable isn't ever accessed before the usage in this out-var.
if (IsAccessed(semanticModel, outSymbol, enclosingBlockOfLocalStatement,
localStatement, argumentNode, cancellationToken))
{
......@@ -293,7 +293,7 @@ where outSymbol.Equals(symbol)
// NOTE: there is no current compiler API to determine if a variable is definitely
// assigned or not. So, for now, we just get diagnostics for this block and see if
// we get any definite assigment errors where we have a reference to the symbol. If
// we get any definite assignment errors where we have a reference to the symbol. If
// so, then we don't offer the fix.
rootWithoutInitializer = (CompilationUnitSyntax)rootWithoutInitializerTree.GetRoot(cancellationToken);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册