Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
},
"dependencies": {
"@microsoft/powerquery-formatter": "0.3.20",
"@microsoft/powerquery-parser": "0.18.5",
"@microsoft/powerquery-parser": "0.18.6",
"vscode-languageserver-textdocument": "1.0.12",
"vscode-languageserver-types": "3.17.5"
}
Expand Down
18 changes: 17 additions & 1 deletion src/powerquery-language-services/analysis/analysisBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
import { LanguageAutocompleteItemProvider, LibraryProvider, LocalDocumentProvider } from "../providers";
import type { Analysis } from "./analysis";
import type { AnalysisSettings } from "./analysisSettings";
import { normalizeInspectionSettingsForParser } from "../inspectionSettings";
import { ValidationTraceConstant } from "../trace";

// Implementation of Analysis.
Expand Down Expand Up @@ -615,6 +616,7 @@ export class AnalysisBase implements Analysis {
);

const activeNode: TActiveNode | undefined = await this.getActiveNodeOkOrThrow(position, trace);
const parseState: ParseState | undefined = await this.getParseStateOkOrThrow(trace);

if (activeNode === undefined || (ActiveNodeUtils.isPositionInBounds(activeNode) && activeNode.isInKey)) {
trace.exit();
Expand Down Expand Up @@ -648,7 +650,14 @@ export class AnalysisBase implements Analysis {

if (activeLeafIdentifier !== undefined) {
result = {
activeNode,
autocomplete,
inspectionSettings: {
...this.inspectionSettings,
cancellationToken,
initialCorrelationId: trace.id,
},
parseState: Assert.asDefined(parseState, "autocomplete context requires parse state"),
triedNodeScope,
triedScopeType,
traceManager: this.traceManager,
Expand All @@ -660,7 +669,14 @@ export class AnalysisBase implements Analysis {
};
} else {
result = {
activeNode,
autocomplete,
inspectionSettings: {
...this.inspectionSettings,
cancellationToken,
initialCorrelationId: trace.id,
},
parseState: Assert.asDefined(parseState, "autocomplete context requires parse state"),
triedNodeScope,
triedScopeType,
traceManager: this.traceManager,
Expand Down Expand Up @@ -980,7 +996,7 @@ export class AnalysisBase implements Analysis {
};

const triedLexParse: PQP.Task.TriedLexParseTask = await PQP.TaskUtils.tryLexParse(
updatedSettings,
normalizeInspectionSettingsForParser(updatedSettings),
this.textDocument.getText(),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ const AllowedExtendedTypeKindsForFieldEntries: ReadonlyArray<Type.ExtendedTypeKi
Type.ExtendedTypeKind.AnyUnion,
Type.ExtendedTypeKind.DefinedRecord,
Type.ExtendedTypeKind.DefinedTable,
Type.ExtendedTypeKind.RecordType,
];

async function autocompleteFieldAccess(
Expand Down Expand Up @@ -196,6 +197,7 @@ function fieldEntriesFromFieldType(type: Type.TPowerQueryType): ReadonlyArray<[s

case Type.ExtendedTypeKind.DefinedRecord:
case Type.ExtendedTypeKind.DefinedTable:
case Type.ExtendedTypeKind.RecordType:
return [...type.fields.entries()];

default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ async function inspectInvokeExpression(

let invokeExpressionArgs: InvokeExpressionArguments | undefined;

if (TypeUtils.isDefinedFunction(functionType)) {
if (TypeUtils.isFunctionSignature(functionType)) {
const iterableArguments: ReadonlyArray<TXorNode> = NodeIdMapIterator.iterInvokeExpression(
nodeIdMapCollection,
invokeExpressionXorNode,
Expand All @@ -120,7 +120,7 @@ async function inspectInvokeExpression(
numMinExpectedArguments,
typeChecked: TypeUtils.typeCheckInvocation(
givenArgumentTypes,
functionType,
asDefinedFunction(functionType),
settings.traceManager,
trace.id,
),
Expand All @@ -147,6 +147,15 @@ async function inspectInvokeExpression(
return result;
}

function asDefinedFunction(functionType: Type.FunctionSignature): Type.DefinedFunction {
return {
...functionType,
kind: Type.TypeKind.Function,
extendedKind: Type.ExtendedTypeKind.DefinedFunction,
isNullable: false,
};
}

async function getIsNameInLocalScope(
settings: InspectionSettings,
nodeIdMapCollection: NodeIdMap.Collection,
Expand Down Expand Up @@ -191,7 +200,7 @@ async function getIsNameInLocalScope(
}
}

function getNumExpectedArguments(functionType: Type.DefinedFunction): [number, number] {
function getNumExpectedArguments(functionType: Type.FunctionSignature): [number, number] {
const nonOptionalArguments: ReadonlyArray<Type.FunctionParameter> = functionType.parameters.filter(
(parameter: Type.FunctionParameter) => !parameter.isOptional,
);
Expand Down
9 changes: 6 additions & 3 deletions src/powerquery-language-services/inspection/scope/scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import * as PQP from "@microsoft/powerquery-parser";
import { Ast, Constant, Type } from "@microsoft/powerquery-parser/lib/powerquery-parser/language";
import { TXorNode } from "@microsoft/powerquery-parser/lib/powerquery-parser/parser";

export interface TypeDirective {
readonly kind: "Type";
readonly value?: string;
}

// Type for the async resolver function that resolves a scope item to its type.
type ScopeItemTypeResolver = (scopeItem: TScopeItem) => Promise<Type.TPowerQueryType>;

Expand Down Expand Up @@ -146,9 +151,6 @@ export interface NodeScope {
readonly scopeItemByKey: ReadonlyMap<string, TScopeItem>;
}

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

export type TScopeItem =
| EachScopeItem
| LetVariableScopeItem
Expand Down Expand Up @@ -180,6 +182,7 @@ export interface IKeyValuePairScopeItem<
> extends IScopeItem {
readonly kind: Kind;
readonly key: Key;
readonly typeDirective: TypeDirective | undefined;
readonly value: TXorNode | undefined;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
SectionMemberScopeItem,
TriedNodeScope,
TScopeItem,
TypeDirective,
} from "./scope";
import {
PseduoFunctionExpressionType,
Expand Down Expand Up @@ -452,6 +453,7 @@ function inspectLetExpression(state: ScopeInspectionState, letExpr: TXorNode, co

// Places the assignments from the 'let' into LetExpression.expression
const newEntries: ReadonlyArray<[string, LetVariableScopeItem]> = scopeItemFactoryForKeyValuePairs(
state,
keyValuePairs,
-1,
{ allowRecursive: true },
Expand Down Expand Up @@ -535,6 +537,7 @@ function inspectSection(state: ScopeInspectionState, section: TXorNode, correlat
kvp.value.node.id,
getParentScope(state, kvp.value.node.id),
scopeItemFactoryForKeyValuePairs(
state,
keyValuePairs,
kvp.key.id,
{ allowRecursive: true },
Expand All @@ -556,7 +559,7 @@ function inspectKeyValuePairs<
inheritedScope: NodeScope | undefined,
keyValuePairs: ReadonlyArray<KVP>,
getAllowedIdentifiersOptions: IdentifierUtils.GetAllowedIdentifiersOptions,
scopeItemFactory: (keyValuePair: KVP, recursive: boolean) => T,
scopeItemFactory: (state: ScopeInspectionState, keyValuePair: KVP, recursive: boolean) => T,
correlationId: number,
): void {
const trace: Trace = state.traceManager.entry(
Expand All @@ -576,7 +579,13 @@ function inspectKeyValuePairs<
state,
kvp.value.node.id,
inheritedScope,
scopeItemFactoryForKeyValuePairs(keyValuePairs, kvp.key.id, getAllowedIdentifiersOptions, scopeItemFactory),
scopeItemFactoryForKeyValuePairs(
state,
keyValuePairs,
kvp.key.id,
getAllowedIdentifiersOptions,
scopeItemFactory,
),
trace.id,
);
}
Expand All @@ -588,10 +597,11 @@ function scopeItemFactoryForKeyValuePairs<
T extends Extract<TScopeItem, LetVariableScopeItem | RecordFieldScopeItem | SectionMemberScopeItem>,
KVP extends NodeIdMapIterator.TKeyValuePair,
>(
state: ScopeInspectionState,
keyValuePairs: ReadonlyArray<KVP>,
keyNodeId: number,
getAllowedIdentifiersOptions: IdentifierUtils.GetAllowedIdentifiersOptions,
scopeItemFactory: (keyValuePair: KVP, isRecursive: boolean) => T,
scopeItemFactory: (state: ScopeInspectionState, keyValuePair: KVP, isRecursive: boolean) => T,
): ReadonlyArray<[string, T]> {
const result: [string, T][] = [];

Expand All @@ -600,7 +610,7 @@ function scopeItemFactoryForKeyValuePairs<

for (const key of IdentifierUtils.getAllowedIdentifiers(kvp.key.literal, getAllowedIdentifiersOptions)) {
if (!isRecursive || key.includes("@")) {
result.push([key, scopeItemFactory(kvp, isRecursive)]);
result.push([key, scopeItemFactory(state, kvp, isRecursive)]);
}
}
}
Expand All @@ -609,6 +619,7 @@ function scopeItemFactoryForKeyValuePairs<
}

function scopeItemFactoryForLetVariable(
state: ScopeInspectionState,
keyValuePair: NodeIdMapIterator.LetKeyValuePair,
isRecursive: boolean,
): LetVariableScopeItem {
Expand All @@ -617,6 +628,7 @@ function scopeItemFactoryForLetVariable(
nodeId: keyValuePair.source.node.id,
isRecursive,
key: keyValuePair.key,
typeDirective: findTypeDirective(state, keyValuePair.source.node.id),
value: keyValuePair.value,
};
}
Expand All @@ -637,6 +649,7 @@ function scopeItemFactoryForParameter(
}

function scopeItemFactoryForRecordMember(
state: ScopeInspectionState,
keyValuePair: NodeIdMapIterator.RecordKeyValuePair,
isRecursive: boolean,
): RecordFieldScopeItem {
Expand All @@ -645,11 +658,13 @@ function scopeItemFactoryForRecordMember(
nodeId: keyValuePair.source.node.id,
isRecursive,
key: keyValuePair.key,
typeDirective: findTypeDirective(state, keyValuePair.source.node.id),
value: keyValuePair.value,
};
}

function scopeItemFactoryForSectionMember(
state: ScopeInspectionState,
keyValuePair: NodeIdMapIterator.SectionKeyValuePair,
isRecursive: boolean,
): SectionMemberScopeItem {
Expand All @@ -658,6 +673,17 @@ function scopeItemFactoryForSectionMember(
nodeId: keyValuePair.source.node.id,
isRecursive,
key: keyValuePair.key,
typeDirective: findTypeDirective(state, keyValuePair.source.node.id),
value: keyValuePair.value,
};
}

function findTypeDirective(state: ScopeInspectionState, nodeId: number): TypeDirective | undefined {
const astNode: Ast.TNode | undefined = state.nodeIdMapCollection.astNodeById.get(nodeId);

const directives: ReadonlyArray<TypeDirective> | undefined = (
astNode as (Ast.TNode & { precedingDirectives?: ReadonlyArray<TypeDirective> }) | undefined
)?.precedingDirectives;

return directives?.find((directive: TypeDirective) => directive.kind === "Type");
}
7 changes: 5 additions & 2 deletions src/powerquery-language-services/inspection/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import type { Position } from "vscode-languageserver-types";
import { ActiveNodeUtils, TActiveNode } from "./activeNode";
import { findDirectUpperScopeExpression, findScopeItemByLiteral, scopeCreatorIdentifier } from "./scope/scopeUtils";
import { Inspection, InspectionTraceConstant } from "..";
import { InspectionSettings, normalizeInspectionSettingsForParser } from "../inspectionSettings";
import { ScopeTypeByKey, TriedNodeScope, tryNodeScope, TScopeItem } from "./scope";
import { TriedExpectedType, tryExpectedType } from "./expectedType";
import { TriedScopeType, tryScopeType } from "./type";
import { TypeCache, TypeCacheUtils } from "./typeCache";
import { autocomplete } from "./autocomplete";
import { Inspected } from "./commonTypes";
import { InspectionSettings } from "../inspectionSettings";
import { TriedCurrentInvokeExpression } from "./invokeExpression";
import { tryCurrentInvokeExpression } from "./invokeExpression/currentInvokeExpression";

Expand Down Expand Up @@ -254,7 +254,10 @@ export async function tryInspect(
initialCorrelationId: trace.id,
};

const triedLexParse: PQP.Task.TriedLexParseTask = await PQP.TaskUtils.tryLexParse(updatedSettings, text);
const triedLexParse: PQP.Task.TriedLexParseTask = await PQP.TaskUtils.tryLexParse(
normalizeInspectionSettingsForParser(updatedSettings),
text,
);

let parseState: PQP.Parser.ParseState;
let parseError: PQP.Parser.ParseError.ParseError | undefined;
Expand Down
Loading
Loading