Compare commits
3 commits
main
...
documentHi
Author | SHA1 | Date | |
---|---|---|---|
b6b48c2afa | |||
34b9ad5b54 | |||
46247157ae |
|
@ -274,6 +274,18 @@ namespace ts {
|
|||
getJsxNamespace: () => unescapeLeadingUnderscores(getJsxNamespace()),
|
||||
getAccessibleSymbolChain,
|
||||
resolveExternalModuleSymbol,
|
||||
nodeHasBadModifier: node => {
|
||||
const sourceFile = getSourceFileOfNode(node);
|
||||
// Make `parseDiagnostics` empty so we actually get grammar errors. But shadow `diagnostics` so grammar errors don't stick.
|
||||
const saveParseDiagnostics = sourceFile.parseDiagnostics;
|
||||
const saveDiagnostics = diagnostics;
|
||||
sourceFile.parseDiagnostics = [];
|
||||
diagnostics = createDiagnosticCollection();
|
||||
const res = checkGrammarModifiers(node);
|
||||
sourceFile.parseDiagnostics = saveParseDiagnostics;
|
||||
diagnostics = saveDiagnostics;
|
||||
return res;
|
||||
},
|
||||
};
|
||||
|
||||
const tupleTypes: GenericType[] = [];
|
||||
|
@ -412,7 +424,7 @@ namespace ts {
|
|||
const potentialNewTargetCollisions: Node[] = [];
|
||||
const awaitedTypeStack: number[] = [];
|
||||
|
||||
const diagnostics = createDiagnosticCollection();
|
||||
let diagnostics = createDiagnosticCollection();
|
||||
|
||||
const enum TypeFacts {
|
||||
None = 0,
|
||||
|
@ -25505,8 +25517,8 @@ namespace ts {
|
|||
}
|
||||
switch (modifier.kind) {
|
||||
case SyntaxKind.ConstKeyword:
|
||||
if (node.kind !== SyntaxKind.EnumDeclaration && node.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword));
|
||||
if (node.kind !== SyntaxKind.EnumDeclaration) {
|
||||
return grammarErrorOnNode(node, Diagnostics._0_modifier_cannot_be_used_here, tokenToString(SyntaxKind.ConstKeyword));
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.PublicKeyword:
|
||||
|
|
|
@ -803,10 +803,6 @@
|
|||
"category": "Error",
|
||||
"code": 1247
|
||||
},
|
||||
"A class member cannot have the '{0}' keyword.": {
|
||||
"category": "Error",
|
||||
"code": 1248
|
||||
},
|
||||
"A decorator can only decorate a method implementation, not an overload.": {
|
||||
"category": "Error",
|
||||
"code": 1249
|
||||
|
|
|
@ -2316,7 +2316,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
node.decorators = parseDecorators();
|
||||
node.modifiers = parseModifiers();
|
||||
node.modifiers = parseModifiers(/*permitConstAsModifier*/ true);
|
||||
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
|
||||
|
||||
// FormalParameter [Yield,Await]:
|
||||
|
|
|
@ -2876,6 +2876,7 @@ namespace ts {
|
|||
/* @internal */ getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] | undefined;
|
||||
|
||||
/* @internal */ resolveExternalModuleSymbol(symbol: Symbol): Symbol;
|
||||
/* @internal */ nodeHasBadModifier(node: Node): boolean;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
|
|
@ -449,8 +449,7 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
public goToEachRange(action: () => void) {
|
||||
const ranges = this.getRanges();
|
||||
public goToEachRange(ranges: ReadonlyArray<Range>, action: () => void) {
|
||||
assert(ranges.length);
|
||||
for (const range of ranges) {
|
||||
this.goToRangeStart(range);
|
||||
|
@ -3786,8 +3785,12 @@ namespace FourSlashInterface {
|
|||
this.state.goToRangeStart(range);
|
||||
}
|
||||
|
||||
public eachRange(action: () => void) {
|
||||
this.state.goToEachRange(action);
|
||||
public eachRange(action: () => void): void;
|
||||
public eachRange(ranges: ReadonlyArray<FourSlash.Range>, action: () => void): void;
|
||||
public eachRange(a: {}, b?: {}) {
|
||||
const ranges = b === undefined ? this.state.getRanges() : a as ReadonlyArray<FourSlash.Range>;
|
||||
const action = (b === undefined ? a : b) as () => void;
|
||||
this.state.goToEachRange(ranges, action);
|
||||
}
|
||||
|
||||
public bof() {
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace Harness.Parallel.Worker {
|
|||
retries() { return this; },
|
||||
slow() { return this; },
|
||||
timeout(n) {
|
||||
timeout = n;
|
||||
timeout = n as number;
|
||||
return this;
|
||||
},
|
||||
};
|
||||
|
@ -127,7 +127,7 @@ namespace Harness.Parallel.Worker {
|
|||
const fakeContext: Mocha.ITestCallbackContext = {
|
||||
skip() { return this; },
|
||||
timeout(n) {
|
||||
timeout = n;
|
||||
timeout = n as number;
|
||||
return this;
|
||||
},
|
||||
retries() { return this; },
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* @internal */
|
||||
namespace ts.DocumentHighlights {
|
||||
export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] | undefined {
|
||||
type HasBadModifier = TypeChecker["nodeHasBadModifier"];
|
||||
export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: SourceFile[], hasBadModifier: HasBadModifier): DocumentHighlights[] | undefined {
|
||||
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
|
||||
if (node.parent && (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent))) {
|
||||
|
@ -10,7 +11,7 @@ namespace ts.DocumentHighlights {
|
|||
return [{ fileName: sourceFile.fileName, highlightSpans }];
|
||||
}
|
||||
|
||||
return getSemanticDocumentHighlights(position, node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile);
|
||||
return getSemanticDocumentHighlights(position, node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile, hasBadModifier);
|
||||
}
|
||||
|
||||
function getHighlightSpanForNode(node: Node, sourceFile: SourceFile): HighlightSpan {
|
||||
|
@ -40,8 +41,8 @@ namespace ts.DocumentHighlights {
|
|||
return arrayFrom(fileNameToDocumentHighlights.entries(), ([fileName, highlightSpans ]) => ({ fileName, highlightSpans }));
|
||||
}
|
||||
|
||||
function getSyntacticDocumentHighlights(node: Node, sourceFile: SourceFile): DocumentHighlights[] {
|
||||
const highlightSpans = getHighlightSpans(node, sourceFile);
|
||||
function getSyntacticDocumentHighlights(node: Node, sourceFile: SourceFile, hasBadModifier: HasBadModifier): DocumentHighlights[] {
|
||||
const highlightSpans = getHighlightSpans(node, sourceFile, hasBadModifier);
|
||||
if (!highlightSpans || highlightSpans.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -49,7 +50,7 @@ namespace ts.DocumentHighlights {
|
|||
return [{ fileName: sourceFile.fileName, highlightSpans }];
|
||||
}
|
||||
|
||||
function getHighlightSpans(node: Node, sourceFile: SourceFile): HighlightSpan[] | undefined {
|
||||
function getHighlightSpans(node: Node, sourceFile: SourceFile, hasBadModifier: HasBadModifier): HighlightSpan[] | undefined {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.IfKeyword:
|
||||
case SyntaxKind.ElseKeyword:
|
||||
|
@ -82,7 +83,7 @@ namespace ts.DocumentHighlights {
|
|||
return useParent(node.parent, isAccessor, getGetAndSetOccurrences);
|
||||
default:
|
||||
return isModifierKind(node.kind) && (isDeclaration(node.parent) || isVariableStatement(node.parent))
|
||||
? highlightSpans(getModifierOccurrences(node.kind, node.parent))
|
||||
? highlightSpans(getModifierOccurrences(node.kind, node.parent, hasBadModifier))
|
||||
: undefined;
|
||||
}
|
||||
|
||||
|
@ -204,9 +205,9 @@ namespace ts.DocumentHighlights {
|
|||
});
|
||||
}
|
||||
|
||||
function getModifierOccurrences(modifier: SyntaxKind, declaration: Node): Node[] {
|
||||
function getModifierOccurrences(modifier: SyntaxKind, declaration: Declaration | VariableStatement, hasBadModifier: HasBadModifier): Node[] | undefined {
|
||||
// Make sure we only highlight the keyword when it makes sense to do so.
|
||||
if (!isLegalModifier(modifier, declaration)) {
|
||||
if (hasBadModifier(declaration)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
@ -220,7 +221,7 @@ namespace ts.DocumentHighlights {
|
|||
});
|
||||
}
|
||||
|
||||
function getNodesToSearchForModifier(declaration: Node, modifierFlag: ModifierFlags): ReadonlyArray<Node> {
|
||||
function getNodesToSearchForModifier(declaration: Declaration | VariableStatement, modifierFlag: ModifierFlags): ReadonlyArray<Node> {
|
||||
const container = declaration.parent;
|
||||
switch (container.kind) {
|
||||
case SyntaxKind.ModuleBlock:
|
||||
|
@ -228,9 +229,8 @@ namespace ts.DocumentHighlights {
|
|||
case SyntaxKind.Block:
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.DefaultClause:
|
||||
// Container is either a class declaration or the declaration is a classDeclaration
|
||||
if (modifierFlag & ModifierFlags.Abstract) {
|
||||
return [...(<ClassDeclaration>declaration).members, declaration];
|
||||
if (modifierFlag & ModifierFlags.Abstract && isClassDeclaration(declaration)) {
|
||||
return [...declaration.members, declaration];
|
||||
}
|
||||
else {
|
||||
return (<ModuleBlock | SourceFile | Block | CaseClause | DefaultClause>container).statements;
|
||||
|
@ -258,33 +258,6 @@ namespace ts.DocumentHighlights {
|
|||
}
|
||||
}
|
||||
|
||||
function isLegalModifier(modifier: SyntaxKind, declaration: Node): boolean {
|
||||
const container = declaration.parent;
|
||||
switch (modifier) {
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
case SyntaxKind.PublicKeyword:
|
||||
switch (container.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
return true;
|
||||
case SyntaxKind.Constructor:
|
||||
return declaration.kind === SyntaxKind.Parameter;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case SyntaxKind.StaticKeyword:
|
||||
return container.kind === SyntaxKind.ClassDeclaration || container.kind === SyntaxKind.ClassExpression;
|
||||
case SyntaxKind.ExportKeyword:
|
||||
case SyntaxKind.DeclareKeyword:
|
||||
return container.kind === SyntaxKind.ModuleBlock || container.kind === SyntaxKind.SourceFile;
|
||||
case SyntaxKind.AbstractKeyword:
|
||||
return container.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.ClassDeclaration;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function pushKeywordIf(keywordList: Node[], token: Node, ...expected: SyntaxKind[]): boolean {
|
||||
if (token && contains(expected, token.kind)) {
|
||||
keywordList.push(token);
|
||||
|
|
|
@ -1581,7 +1581,7 @@ namespace ts {
|
|||
synchronizeHostData();
|
||||
const sourceFilesToSearch = map(filesToSearch, f => program.getSourceFile(f));
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
return DocumentHighlights.getDocumentHighlights(program, cancellationToken, sourceFile, position, sourceFilesToSearch);
|
||||
return DocumentHighlights.getDocumentHighlights(program, cancellationToken, sourceFile, position, sourceFilesToSearch, program.getTypeChecker().nodeHasBadModifier);
|
||||
}
|
||||
|
||||
function getOccurrencesAtPositionCore(fileName: string, position: number): ReferenceEntry[] {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
tests/cases/compiler/ClassDeclarationWithInvalidConstOnPropertyDeclaration.ts(2,3): error TS1248: A class member cannot have the 'const' keyword.
|
||||
tests/cases/compiler/ClassDeclarationWithInvalidConstOnPropertyDeclaration.ts(2,3): error TS1042: 'const' modifier cannot be used here.
|
||||
|
||||
|
||||
==== tests/cases/compiler/ClassDeclarationWithInvalidConstOnPropertyDeclaration.ts (1 errors) ====
|
||||
class AtomicNumbers {
|
||||
static const H = 1;
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS1248: A class member cannot have the 'const' keyword.
|
||||
!!! error TS1042: 'const' modifier cannot be used here.
|
||||
}
|
|
@ -125,6 +125,7 @@ declare namespace FourSlashInterface {
|
|||
eachMarker(markers: ReadonlyArray<string>, action: (marker: Marker, index: number) => void): void;
|
||||
eachMarker(action: (marker: Marker, index: number) => void): void;
|
||||
rangeStart(range: Range): void;
|
||||
eachRange(ranges: ReadonlyArray<Range>, action: () => void): void;
|
||||
eachRange(action: () => void): void;
|
||||
bof(): void;
|
||||
eof(): void;
|
||||
|
|
|
@ -6,15 +6,9 @@
|
|||
//// [|abstract|] makeSound(): void;
|
||||
////}
|
||||
////// abstract cannot appear here, won't get highlighted
|
||||
////let c = /*1*/abstract class Foo {
|
||||
//// /*2*/abstract foo(): void;
|
||||
////let c = [|abstract|] class Foo {
|
||||
//// [|abstract|] foo(): void;
|
||||
//// abstract bar(): void;
|
||||
////}
|
||||
|
||||
verify.rangesAreOccurrences(false);
|
||||
|
||||
goTo.marker("1");
|
||||
verify.occurrencesAtPositionCount(0);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.occurrencesAtPositionCount(2);
|
||||
goTo.eachRange(() => verify.occurrencesAtPositionCount(0));
|
||||
|
|
14
tests/cases/fourslash/getOccurrencesAsync.ts
Normal file
14
tests/cases/fourslash/getOccurrencesAsync.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////[|async|] function f([|async|] p) {}
|
||||
////[|async|] function g() {}
|
||||
|
||||
////[|async|] class C {
|
||||
//// [|async|] m() {}
|
||||
//// [|async|] n() {}
|
||||
////}
|
||||
|
||||
const [f, p, g, C, m, n] = test.ranges();
|
||||
goTo.eachRange([f, g], () => verify.occurrencesAtPositionCount(3));
|
||||
goTo.eachRange([m, n], () => verify.occurrencesAtPositionCount(2));
|
||||
goTo.eachRange([p, C], () => verify.occurrencesAtPositionCount(0));
|
|
@ -8,7 +8,7 @@
|
|||
/////*2*/const c = 0;
|
||||
|
||||
goTo.marker("1");
|
||||
verify.occurrencesAtPositionCount(0);
|
||||
verify.occurrencesAtPositionCount(1);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.occurrencesAtPositionCount(0);
|
||||
|
|
|
@ -10,4 +10,6 @@
|
|||
////declare [|const|] enum E {
|
||||
////}
|
||||
|
||||
goTo.eachRange(() => verify.occurrencesAtPositionCount(0));
|
||||
const [r0, r1, r2, r3] = test.ranges();
|
||||
goTo.eachRange([r0, r2], () => verify.occurrencesAtPositionCount(0));
|
||||
goTo.eachRange([r1, r3], () => verify.occurrencesAtPositionCount(1));
|
||||
|
|
|
@ -10,4 +10,6 @@
|
|||
////export [|const|] enum E {
|
||||
////}
|
||||
|
||||
goTo.eachRange(() => verify.occurrencesAtPositionCount(0));
|
||||
const [r0, r1, r2, r3] = test.ranges();
|
||||
goTo.eachRange([r0, r2], () => verify.occurrencesAtPositionCount(0));
|
||||
goTo.eachRange([r1, r3], () => verify.occurrencesAtPositionCount(1));
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////export const class C {
|
||||
//// private static c/*1*/onst f/*2*/oo;
|
||||
//// constructor(public con/*3*/st foo) {
|
||||
//// private static [|const|] [|foo|];
|
||||
//// constructor(public [|const|] foo) {
|
||||
//// }
|
||||
////}
|
||||
|
||||
goTo.marker("1");
|
||||
verify.occurrencesAtPositionCount(0);
|
||||
goTo.marker("2");
|
||||
const [r0, r1, r2] = test.ranges();
|
||||
goTo.eachRange([r0, r2], () => verify.occurrencesAtPositionCount(0));
|
||||
goTo.rangeStart(r1);
|
||||
verify.occurrencesAtPositionCount(1);
|
||||
goTo.marker("3");
|
||||
verify.occurrencesAtPositionCount(0);
|
|
@ -61,4 +61,8 @@
|
|||
////[|declare|] module dm { }
|
||||
////export class EC { }
|
||||
|
||||
verify.rangesAreOccurrences(false);
|
||||
const [r0, r1, r2, r3] = test.ranges();
|
||||
goTo.eachRange([r0, r1, r3], () => verify.occurrencesAtPositionCount(4));
|
||||
// r2 has a grammar error, so no occurrences
|
||||
goTo.rangeStart(r2);
|
||||
verify.occurrencesAtPositionCount(0);
|
||||
|
|
|
@ -61,4 +61,8 @@
|
|||
////declare module dm { }
|
||||
////[|export|] class EC { }
|
||||
|
||||
verify.rangesAreOccurrences(false);
|
||||
const [r0, r1, r2] = test.ranges();
|
||||
goTo.eachRange([r0, r2], () => verify.occurrencesAtPositionCount(3));
|
||||
// r1 has a grammar error
|
||||
goTo.rangeStart(r1);
|
||||
verify.occurrencesAtPositionCount(0);
|
||||
|
|
Loading…
Reference in a new issue