Skip to content

Commit fc9d6a2

Browse files
committed
Fix bug with signature support and boundaries
Signed-off-by: worksofliam <[email protected]>
1 parent df26627 commit fc9d6a2

File tree

6 files changed

+149
-32
lines changed

6 files changed

+149
-32
lines changed

src/language/providers/hoverProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import Statement from "../../database/statement";
66
import { getParmAttributes, prepareParamType } from "./logic/completion";
77
import { StatementType } from "../sql/types";
88
import { remoteAssistIsEnabled } from "./logic/available";
9-
import { getPositionData } from "./logic/callable";
109
import { CallableSignature } from "../../database/callable";
10+
import { getPositionData } from "../sql/document";
1111

1212
// =================================
1313
// We need to open provider to exist so symbols can be cached for hover support when opening files

src/language/providers/logic/callable.ts

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Statement from "../../../database/statement";
55
import { createCompletionItem, getParmAttributes } from "./completion";
66
import { DbCache } from "./cache";
77
import { SQLParm } from "../../../types";
8+
import { getPositionData } from "../../sql/document";
89

910
/**
1011
* Checks if the ref exists as a procedure or function. Then,
@@ -117,27 +118,4 @@ export function getCallableParameters(ref: CallableReference, offset: number): C
117118
});
118119
}
119120
return [];
120-
}
121-
122-
export function getPositionData(ref: CallableReference, offset: number) {
123-
const paramCommas = ref.tokens.filter(token => token.type === `comma`);
124-
125-
let currentParm = paramCommas.findIndex(t => offset < t.range.end);
126-
127-
if (currentParm === -1) {
128-
currentParm = paramCommas.length;
129-
}
130-
131-
const firstNamedPipe = ref.tokens.find((token, i) => token.type === `rightpipe`);
132-
let firstNamedParameter = firstNamedPipe ? paramCommas.findIndex((token, i) => token.range.start > firstNamedPipe.range.start) : undefined;
133-
134-
if (firstNamedParameter === -1) {
135-
firstNamedParameter = undefined;
136-
}
137-
138-
return {
139-
currentParm,
140-
currentCount: paramCommas.length + 1,
141-
firstNamedParameter
142-
};
143121
}

src/language/providers/parameterProvider.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { MarkdownString, ParameterInformation, Position, Range, SignatureHelp, SignatureInformation, TextEdit, languages } from "vscode";
22
import Statement from "../../database/statement";
3-
import Document from "../sql/document";
4-
import { getCallableParameters, getPositionData, isCallableType } from "./logic/callable";
5-
import { getParmAttributes, prepareParamType } from "./logic/completion";
3+
import Document, { getPositionData } from "../sql/document";
4+
import { isCallableType } from "./logic/callable";
5+
import { prepareParamType } from "./logic/completion";
66
import { CallableType } from "../../database/callable";
77
import { StatementType } from "../sql/types";
88
import { remoteAssistIsEnabled } from "./logic/available";
@@ -22,7 +22,7 @@ export const signatureProvider = languages.registerSignatureHelpProvider({ langu
2222
const currentStatement = sqlDoc.getStatementByOffset(offset);
2323

2424
if (currentStatement) {
25-
const routineType: CallableType = currentStatement.type === StatementType.Call ? `PROCEDURE` : `FUNCTION`;
25+
const routineType: CallableType = currentStatement. type === StatementType.Call ? `PROCEDURE` : `FUNCTION`;
2626
const callableRef = currentStatement.getCallableDetail(offset, true);
2727
// TODO: check the function actually exists before returning
2828
if (callableRef) {

src/language/sql/document.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Statement from "./statement";
22
import SQLTokeniser from "./tokens";
3-
import { Definition, IRange, ParsedEmbeddedStatement, StatementGroup, StatementType, StatementTypeWord, Token } from "./types";
3+
import { CallableReference, Definition, IRange, ParsedEmbeddedStatement, StatementGroup, StatementType, StatementTypeWord, Token } from "./types";
44

55
export default class Document {
66
content: string;
@@ -261,6 +261,30 @@ export default class Document {
261261
}
262262
}
263263

264+
265+
export function getPositionData(ref: CallableReference, offset: number) {
266+
const paramCommas = ref.tokens.filter(token => token.type === `comma`);
267+
268+
let currentParm = paramCommas.findIndex(t => offset < t.range.start);
269+
270+
if (currentParm === -1) {
271+
currentParm = paramCommas.length;
272+
}
273+
274+
const firstNamedPipe = ref.tokens.find((token, i) => token.type === `rightpipe`);
275+
let firstNamedParameter = firstNamedPipe ? paramCommas.findIndex((token, i) => token.range.start > firstNamedPipe.range.start) : undefined;
276+
277+
if (firstNamedParameter === -1) {
278+
firstNamedParameter = undefined;
279+
}
280+
281+
return {
282+
currentParm,
283+
currentCount: paramCommas.length + 1,
284+
firstNamedParameter
285+
};
286+
}
287+
264288
function getSymbolsForStatements(statements: Statement[]) {
265289
let defintions: Definition[] = [];
266290

src/language/sql/statement.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,16 @@ export default class Statement {
117117
if (tokenInOffset) {
118118
if (tokenInOffset.type === `block`) {
119119
if (tokenInOffset.block!.length > 0) {
120-
return blockContainsOffset(cOffset, tokenInOffset.block!);
120+
let blockRange = blockContainsOffset(cOffset, tokenInOffset.block!);
121+
if (!blockRange) {
122+
blockRange = {
123+
start: this.tokens.findIndex(token => token.range.start === tokenInOffset.range.start) + 1,
124+
end: this.tokens.findIndex(token => token.range.end === tokenInOffset.range.end)
125+
}
126+
}
127+
128+
return blockRange;
129+
121130
} else {
122131
const rawEnd = this.tokens.findIndex(token => token.range.end === tokenInOffset.range.end);
123132
return {

src/language/sql/tests/statements.test.ts

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { assert, describe, expect, test } from 'vitest'
22
import SQLTokeniser from '../tokens'
3-
import Document from '../document';
4-
import { ClauseType, StatementType } from '../types';
3+
import Document, { getPositionData } from '../document';
4+
import { CallableReference, ClauseType, StatementType } from '../types';
55

66
const parserScenarios = describe.each([
77
{newDoc: (content: string) => new Document(content)},
@@ -2003,6 +2003,112 @@ describe(`Parameter statement tests`, () => {
20032003
expect(callableC.parentRef.object.schema).toBe(`qsys2`);
20042004
expect(callableC.parentRef.object.name).toBe(`create_abcd`);
20052005
});
2006+
2007+
test('Partial parameters 1: Position data for procedure call', () => {
2008+
const sql = `call qsys2.ifs_write('asdasd', )`;
2009+
2010+
const document = new Document(sql);
2011+
const statements = document.statements;
2012+
2013+
expect(statements.length).toBe(1);
2014+
2015+
const callableReference: CallableReference = statements[0].getCallableDetail(29);
2016+
expect(callableReference).toBeDefined();
2017+
expect(callableReference.parentRef.object.name).toBe(`ifs_write`);
2018+
expect(callableReference.parentRef.object.schema).toBe(`qsys2`);
2019+
2020+
const positionData = getPositionData(callableReference, 29);
2021+
expect(positionData).toBeDefined();
2022+
2023+
expect(positionData.currentParm).toBe(1);
2024+
expect(positionData.currentCount).toBe(2);
2025+
});
2026+
2027+
test('Partial parameters 1.2: Position data for procedure call', () => {
2028+
const sql = `call qsys2.ifs_write('asdasd', )`;
2029+
2030+
const document = new Document(sql);
2031+
const statements = document.statements;
2032+
2033+
expect(statements.length).toBe(1);
2034+
2035+
const callableReference: CallableReference = statements[0].getCallableDetail(31);
2036+
expect(callableReference).toBeDefined();
2037+
expect(callableReference.parentRef.object.name).toBe(`ifs_write`);
2038+
expect(callableReference.parentRef.object.schema).toBe(`qsys2`);
2039+
2040+
const positionData = getPositionData(callableReference, 31);
2041+
expect(positionData).toBeDefined();
2042+
2043+
expect(positionData.currentParm).toBe(1);
2044+
expect(positionData.currentCount).toBe(2);
2045+
});
2046+
2047+
test('Partial parameters 2: Position data for procedure call', () => {
2048+
const sql = `call qsys2.ifs_write('asdasd', 243)`;
2049+
2050+
const document = new Document(sql);
2051+
const statements = document.statements;
2052+
2053+
expect(statements.length).toBe(1);
2054+
2055+
const callableReference: CallableReference = statements[0].getCallableDetail(25);
2056+
expect(callableReference).toBeDefined();
2057+
expect(callableReference.parentRef.object.name).toBe(`ifs_write`);
2058+
expect(callableReference.parentRef.object.schema).toBe(`qsys2`);
2059+
2060+
const positionData = getPositionData(callableReference, 25);
2061+
expect(positionData).toBeDefined();
2062+
2063+
expect(positionData.currentParm).toBe(0);
2064+
expect(positionData.currentCount).toBe(2);
2065+
});
2066+
2067+
test('Partial parameters 3: Position data for procedure call', () => {
2068+
const sql = `call qsys2.ifs_write('asdasd', 243, )`;
2069+
2070+
const document = new Document(sql);
2071+
const statements = document.statements;
2072+
2073+
expect(statements.length).toBe(1);
2074+
2075+
const callableReference: CallableReference = statements[0].getCallableDetail(25);
2076+
expect(callableReference).toBeDefined();
2077+
expect(callableReference.parentRef.object.name).toBe(`ifs_write`);
2078+
expect(callableReference.parentRef.object.schema).toBe(`qsys2`);
2079+
2080+
const positionDataA = getPositionData(callableReference, 25);
2081+
expect(positionDataA).toBeDefined();
2082+
2083+
expect(positionDataA.currentParm).toBe(0);
2084+
expect(positionDataA.currentCount).toBe(3);
2085+
2086+
const positionDataB = getPositionData(callableReference, 29);
2087+
expect(positionDataB).toBeDefined();
2088+
2089+
expect(positionDataB.currentParm).toBe(1);
2090+
expect(positionDataB.currentCount).toBe(3);
2091+
});
2092+
2093+
test('Partial parameters 4: Position data for procedure call', () => {
2094+
const sql = `call qsys2.ifs_write('asdasd', 'asdasd', overwrite => 'asdad')`;
2095+
2096+
const document = new Document(sql);
2097+
const statements = document.statements;
2098+
2099+
expect(statements.length).toBe(1);
2100+
2101+
const callableReference: CallableReference = statements[0].getCallableDetail(50);
2102+
expect(callableReference).toBeDefined();
2103+
expect(callableReference.parentRef.object.name).toBe(`ifs_write`);
2104+
expect(callableReference.parentRef.object.schema).toBe(`qsys2`);
2105+
2106+
const positionDataA = getPositionData(callableReference, 50);
2107+
expect(positionDataA).toBeDefined();
2108+
2109+
expect(positionDataA.currentParm).toBe(2);
2110+
expect(positionDataA.currentCount).toBe(3);
2111+
});
20062112
});
20072113

20082114
describe(`Prefix tests`, () => {

0 commit comments

Comments
 (0)