mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-17 02:51:45 -05:00
Fixed null ref exception in GetSignatureHelp (#175)
- Fixed a few places where ScriptParseInfo was being used before it was verified to be non-null - Added 1 basic test for GetSignatureHelp scenario
This commit is contained in:
committed by
Kevin Cunnane
parent
431dfa4156
commit
40c1434745
@@ -847,6 +847,12 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
|
|
||||||
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
|
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
|
||||||
|
|
||||||
|
if (scriptParseInfo == null)
|
||||||
|
{
|
||||||
|
// Cache not set up yet - skip and wait until later
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
ConnectionInfo connInfo;
|
ConnectionInfo connInfo;
|
||||||
LanguageService.ConnectionServiceInstance.TryFindConnection(
|
LanguageService.ConnectionServiceInstance.TryFindConnection(
|
||||||
scriptFile.ClientFilePath,
|
scriptFile.ClientFilePath,
|
||||||
@@ -858,7 +864,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
ParseAndBind(scriptFile, connInfo);
|
ParseAndBind(scriptFile, connInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scriptParseInfo != null && scriptParseInfo.ParseResult != null)
|
if (scriptParseInfo.ParseResult != null)
|
||||||
{
|
{
|
||||||
if (Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock))
|
if (Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock))
|
||||||
{
|
{
|
||||||
@@ -928,13 +934,14 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
|
|
||||||
// get the current script parse info object
|
// get the current script parse info object
|
||||||
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
|
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
|
||||||
ScriptDocumentInfo scriptDocumentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
|
|
||||||
|
|
||||||
if (scriptParseInfo == null)
|
if (scriptParseInfo == null)
|
||||||
{
|
{
|
||||||
return AutoCompleteHelper.GetDefaultCompletionItems(scriptDocumentInfo, useLowerCaseSuggestions);
|
return AutoCompleteHelper.GetDefaultCompletionItems(ScriptDocumentInfo.CreateDefaultDocumentInfo(textDocumentPosition, scriptFile), useLowerCaseSuggestions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScriptDocumentInfo scriptDocumentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo);
|
||||||
|
|
||||||
// reparse and bind the SQL statement if needed
|
// reparse and bind the SQL statement if needed
|
||||||
if (RequiresReparse(scriptParseInfo, scriptFile))
|
if (RequiresReparse(scriptParseInfo, scriptFile))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,6 +18,16 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion
|
|||||||
/// Create new instance
|
/// Create new instance
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ScriptDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile, ScriptParseInfo scriptParseInfo)
|
public ScriptDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile, ScriptParseInfo scriptParseInfo)
|
||||||
|
: this(textDocumentPosition, scriptFile)
|
||||||
|
{
|
||||||
|
Validate.IsNotNull(nameof(scriptParseInfo), scriptParseInfo);
|
||||||
|
|
||||||
|
ScriptParseInfo = scriptParseInfo;
|
||||||
|
// need to adjust line & column for base-1 parser indices
|
||||||
|
Token = GetToken(scriptParseInfo, ParserLine, ParserColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScriptDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile)
|
||||||
{
|
{
|
||||||
StartLine = textDocumentPosition.Position.Line;
|
StartLine = textDocumentPosition.Position.Line;
|
||||||
ParserLine = textDocumentPosition.Position.Line + 1;
|
ParserLine = textDocumentPosition.Position.Line + 1;
|
||||||
@@ -30,11 +40,18 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion
|
|||||||
textDocumentPosition.Position.Line,
|
textDocumentPosition.Position.Line,
|
||||||
textDocumentPosition.Position.Character);
|
textDocumentPosition.Position.Character);
|
||||||
ParserColumn = textDocumentPosition.Position.Character + 1;
|
ParserColumn = textDocumentPosition.Position.Character + 1;
|
||||||
ScriptParseInfo = scriptParseInfo;
|
|
||||||
Contents = scriptFile.Contents;
|
Contents = scriptFile.Contents;
|
||||||
|
}
|
||||||
|
|
||||||
// need to adjust line & column for base-1 parser indices
|
/// <summary>
|
||||||
Token = GetToken(scriptParseInfo, ParserLine, ParserColumn);
|
/// Creates a new <see cref="ScriptDocumentInfo"/> with no backing <see cref="ScriptParseInfo"/> defined
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="textDocumentPosition">A <see cref="TextDocumentPosition"/></param>
|
||||||
|
/// <param name="scriptFile">A <see cref="ScriptFile"/> to process</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static ScriptDocumentInfo CreateDefaultDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile)
|
||||||
|
{
|
||||||
|
return new ScriptDocumentInfo(textDocumentPosition, scriptFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||||
using Microsoft.SqlTools.Test.Utility;
|
using Microsoft.SqlTools.Test.Utility;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@@ -126,6 +127,36 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServer
|
|||||||
Assert.Equal(3, fileMarkers[1].ScriptRegion.EndLineNumber);
|
Assert.Equal(3, fileMarkers[1].ScriptRegion.EndLineNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetSignatureHelpReturnsNullIfParseInfoNotInitialized()
|
||||||
|
{
|
||||||
|
// Given service doesn't have parseinfo intialized for a document
|
||||||
|
const string docContent = "SELECT * FROM sys.objects";
|
||||||
|
LanguageService service = TestObjects.GetTestLanguageService();
|
||||||
|
var scriptFile = new ScriptFile();
|
||||||
|
scriptFile.SetFileContents(docContent);
|
||||||
|
|
||||||
|
// When requesting SignatureHelp
|
||||||
|
SignatureHelp signatureHelp = service.GetSignatureHelp(CreateDummyDocPosition(), scriptFile);
|
||||||
|
|
||||||
|
// Then null is returned as no parse info can be used to find the signature
|
||||||
|
Assert.Null(signatureHelp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextDocumentPosition CreateDummyDocPosition()
|
||||||
|
{
|
||||||
|
return new TextDocumentPosition
|
||||||
|
{
|
||||||
|
TextDocument = new TextDocumentIdentifier { Uri = TestObjects.ScriptUri },
|
||||||
|
Position = new Position
|
||||||
|
{
|
||||||
|
Line = 0,
|
||||||
|
Character = 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "General Language Service tests"
|
#region "General Language Service tests"
|
||||||
|
|||||||
Reference in New Issue
Block a user