Skip to content

Commit 3d2af9f

Browse files
authored
Relocate Debug namespace to reduce duplication (#31524)
1 parent c3055e5 commit 3d2af9f

13 files changed

+274
-286
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2515,7 +2515,7 @@ namespace ts {
25152515
break;
25162516

25172517
default:
2518-
Debug.fail(Debug.showSyntaxKind(thisContainer));
2518+
Debug.failBadSyntaxKind(thisContainer);
25192519
}
25202520
}
25212521

src/compiler/checker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5695,7 +5695,7 @@ namespace ts {
56955695
type = getTypeOfEnumMember(symbol);
56965696
}
56975697
else {
5698-
return Debug.fail("Unhandled declaration kind! " + Debug.showSyntaxKind(declaration) + " for " + Debug.showSymbol(symbol));
5698+
return Debug.fail("Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + Debug.formatSymbol(symbol));
56995699
}
57005700

57015701
if (!popTypeResolution()) {
@@ -25536,7 +25536,7 @@ namespace ts {
2553625536
case SyntaxKind.ImportSpecifier: // https://github.com/Microsoft/TypeScript/pull/7591
2553725537
return DeclarationSpaces.ExportValue;
2553825538
default:
25539-
return Debug.fail(Debug.showSyntaxKind(d));
25539+
return Debug.failBadSyntaxKind(d);
2554025540
}
2554125541
}
2554225542
}

src/compiler/core.ts

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,89 +1686,6 @@ namespace ts {
16861686
export type AnyFunction = (...args: never[]) => void;
16871687
export type AnyConstructor = new (...args: unknown[]) => unknown;
16881688

1689-
export namespace Debug {
1690-
export let currentAssertionLevel = AssertionLevel.None;
1691-
export let isDebugging = false;
1692-
1693-
export function shouldAssert(level: AssertionLevel): boolean {
1694-
return currentAssertionLevel >= level;
1695-
}
1696-
1697-
export function assert(expression: boolean, message?: string, verboseDebugInfo?: string | (() => string), stackCrawlMark?: AnyFunction): void {
1698-
if (!expression) {
1699-
if (verboseDebugInfo) {
1700-
message += "\r\nVerbose Debug Information: " + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo());
1701-
}
1702-
fail(message ? "False expression: " + message : "False expression.", stackCrawlMark || assert);
1703-
}
1704-
}
1705-
1706-
export function assertEqual<T>(a: T, b: T, msg?: string, msg2?: string): void {
1707-
if (a !== b) {
1708-
const message = msg ? msg2 ? `${msg} ${msg2}` : msg : "";
1709-
fail(`Expected ${a} === ${b}. ${message}`);
1710-
}
1711-
}
1712-
1713-
export function assertLessThan(a: number, b: number, msg?: string): void {
1714-
if (a >= b) {
1715-
fail(`Expected ${a} < ${b}. ${msg || ""}`);
1716-
}
1717-
}
1718-
1719-
export function assertLessThanOrEqual(a: number, b: number): void {
1720-
if (a > b) {
1721-
fail(`Expected ${a} <= ${b}`);
1722-
}
1723-
}
1724-
1725-
export function assertGreaterThanOrEqual(a: number, b: number): void {
1726-
if (a < b) {
1727-
fail(`Expected ${a} >= ${b}`);
1728-
}
1729-
}
1730-
1731-
export function fail(message?: string, stackCrawlMark?: AnyFunction): never {
1732-
debugger;
1733-
const e = new Error(message ? `Debug Failure. ${message}` : "Debug Failure.");
1734-
if ((<any>Error).captureStackTrace) {
1735-
(<any>Error).captureStackTrace(e, stackCrawlMark || fail);
1736-
}
1737-
throw e;
1738-
}
1739-
1740-
export function assertDefined<T>(value: T | null | undefined, message?: string): T {
1741-
if (value === undefined || value === null) return fail(message);
1742-
return value;
1743-
}
1744-
1745-
export function assertEachDefined<T, A extends ReadonlyArray<T>>(value: A, message?: string): A {
1746-
for (const v of value) {
1747-
assertDefined(v, message);
1748-
}
1749-
return value;
1750-
}
1751-
1752-
export function assertNever(member: never, message = "Illegal value:", stackCrawlMark?: AnyFunction): never {
1753-
const detail = typeof member === "object" && "kind" in member && "pos" in member ? "SyntaxKind: " + showSyntaxKind(member as Node) : JSON.stringify(member);
1754-
return fail(`${message} ${detail}`, stackCrawlMark || assertNever);
1755-
}
1756-
1757-
export function getFunctionName(func: AnyFunction) {
1758-
if (typeof func !== "function") {
1759-
return "";
1760-
}
1761-
else if (func.hasOwnProperty("name")) {
1762-
return (<any>func).name;
1763-
}
1764-
else {
1765-
const text = Function.prototype.toString.call(func);
1766-
const match = /^function\s+([\w\$]+)\s*\(/.exec(text);
1767-
return match ? match[1] : "";
1768-
}
1769-
}
1770-
}
1771-
17721689
export function equateValues<T>(a: T, b: T) {
17731690
return a === b;
17741691
}

src/compiler/debug.ts

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/* @internal */
2+
namespace ts {
3+
export namespace Debug {
4+
export let currentAssertionLevel = AssertionLevel.None;
5+
export let isDebugging = false;
6+
7+
export function shouldAssert(level: AssertionLevel): boolean {
8+
return currentAssertionLevel >= level;
9+
}
10+
11+
export function assert(expression: boolean, message?: string, verboseDebugInfo?: string | (() => string), stackCrawlMark?: AnyFunction): void {
12+
if (!expression) {
13+
if (verboseDebugInfo) {
14+
message += "\r\nVerbose Debug Information: " + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo());
15+
}
16+
fail(message ? "False expression: " + message : "False expression.", stackCrawlMark || assert);
17+
}
18+
}
19+
20+
export function assertEqual<T>(a: T, b: T, msg?: string, msg2?: string): void {
21+
if (a !== b) {
22+
const message = msg ? msg2 ? `${msg} ${msg2}` : msg : "";
23+
fail(`Expected ${a} === ${b}. ${message}`);
24+
}
25+
}
26+
27+
export function assertLessThan(a: number, b: number, msg?: string): void {
28+
if (a >= b) {
29+
fail(`Expected ${a} < ${b}. ${msg || ""}`);
30+
}
31+
}
32+
33+
export function assertLessThanOrEqual(a: number, b: number): void {
34+
if (a > b) {
35+
fail(`Expected ${a} <= ${b}`);
36+
}
37+
}
38+
39+
export function assertGreaterThanOrEqual(a: number, b: number): void {
40+
if (a < b) {
41+
fail(`Expected ${a} >= ${b}`);
42+
}
43+
}
44+
45+
export function fail(message?: string, stackCrawlMark?: AnyFunction): never {
46+
debugger;
47+
const e = new Error(message ? `Debug Failure. ${message}` : "Debug Failure.");
48+
if ((<any>Error).captureStackTrace) {
49+
(<any>Error).captureStackTrace(e, stackCrawlMark || fail);
50+
}
51+
throw e;
52+
}
53+
54+
export function assertDefined<T>(value: T | null | undefined, message?: string): T {
55+
if (value === undefined || value === null) return fail(message);
56+
return value;
57+
}
58+
59+
export function assertEachDefined<T, A extends ReadonlyArray<T>>(value: A, message?: string): A {
60+
for (const v of value) {
61+
assertDefined(v, message);
62+
}
63+
return value;
64+
}
65+
66+
export function assertNever(member: never, message = "Illegal value:", stackCrawlMark?: AnyFunction): never {
67+
const detail = typeof member === "object" && "kind" in member && "pos" in member && formatSyntaxKind ? "SyntaxKind: " + formatSyntaxKind((member as Node).kind) : JSON.stringify(member);
68+
return fail(`${message} ${detail}`, stackCrawlMark || assertNever);
69+
}
70+
71+
export function getFunctionName(func: AnyFunction) {
72+
if (typeof func !== "function") {
73+
return "";
74+
}
75+
else if (func.hasOwnProperty("name")) {
76+
return (<any>func).name;
77+
}
78+
else {
79+
const text = Function.prototype.toString.call(func);
80+
const match = /^function\s+([\w\$]+)\s*\(/.exec(text);
81+
return match ? match[1] : "";
82+
}
83+
}
84+
85+
export function formatSymbol(symbol: Symbol): string {
86+
return `{ name: ${unescapeLeadingUnderscores(symbol.escapedName)}; flags: ${formatSymbolFlags(symbol.flags)}; declarations: ${map(symbol.declarations, node => formatSyntaxKind(node.kind))} }`;
87+
}
88+
89+
/**
90+
* Formats an enum value as a string for debugging and debug assertions.
91+
*/
92+
export function formatEnum(value = 0, enumObject: any, isFlags?: boolean) {
93+
const members = getEnumMembers(enumObject);
94+
if (value === 0) {
95+
return members.length > 0 && members[0][0] === 0 ? members[0][1] : "0";
96+
}
97+
if (isFlags) {
98+
let result = "";
99+
let remainingFlags = value;
100+
for (let i = members.length - 1; i >= 0 && remainingFlags !== 0; i--) {
101+
const [enumValue, enumName] = members[i];
102+
if (enumValue !== 0 && (remainingFlags & enumValue) === enumValue) {
103+
remainingFlags &= ~enumValue;
104+
result = `${enumName}${result ? "|" : ""}${result}`;
105+
}
106+
}
107+
if (remainingFlags === 0) {
108+
return result;
109+
}
110+
}
111+
else {
112+
for (const [enumValue, enumName] of members) {
113+
if (enumValue === value) {
114+
return enumName;
115+
}
116+
}
117+
}
118+
return value.toString();
119+
}
120+
121+
function getEnumMembers(enumObject: any) {
122+
const result: [number, string][] = [];
123+
for (const name in enumObject) {
124+
const value = enumObject[name];
125+
if (typeof value === "number") {
126+
result.push([value, name]);
127+
}
128+
}
129+
130+
return stableSort<[number, string]>(result, (x, y) => compareValues(x[0], y[0]));
131+
}
132+
133+
export function formatSyntaxKind(kind: SyntaxKind | undefined): string {
134+
return formatEnum(kind, (<any>ts).SyntaxKind, /*isFlags*/ false);
135+
}
136+
137+
export function formatNodeFlags(flags: NodeFlags | undefined): string {
138+
return formatEnum(flags, (<any>ts).NodeFlags, /*isFlags*/ true);
139+
}
140+
141+
export function formatModifierFlags(flags: ModifierFlags | undefined): string {
142+
return formatEnum(flags, (<any>ts).ModifierFlags, /*isFlags*/ true);
143+
}
144+
145+
export function formatTransformFlags(flags: TransformFlags | undefined): string {
146+
return formatEnum(flags, (<any>ts).TransformFlags, /*isFlags*/ true);
147+
}
148+
149+
export function formatEmitFlags(flags: EmitFlags | undefined): string {
150+
return formatEnum(flags, (<any>ts).EmitFlags, /*isFlags*/ true);
151+
}
152+
153+
export function formatSymbolFlags(flags: SymbolFlags | undefined): string {
154+
return formatEnum(flags, (<any>ts).SymbolFlags, /*isFlags*/ true);
155+
}
156+
157+
export function formatTypeFlags(flags: TypeFlags | undefined): string {
158+
return formatEnum(flags, (<any>ts).TypeFlags, /*isFlags*/ true);
159+
}
160+
161+
export function formatObjectFlags(flags: ObjectFlags | undefined): string {
162+
return formatEnum(flags, (<any>ts).ObjectFlags, /*isFlags*/ true);
163+
}
164+
165+
export function failBadSyntaxKind(node: Node, message?: string): never {
166+
return fail(
167+
`${message || "Unexpected node."}\r\nNode ${formatSyntaxKind(node.kind)} was unexpected.`,
168+
failBadSyntaxKind);
169+
}
170+
171+
export const assertEachNode = shouldAssert(AssertionLevel.Normal)
172+
? (nodes: Node[], test: (node: Node) => boolean, message?: string): void => assert(
173+
test === undefined || every(nodes, test),
174+
message || "Unexpected node.",
175+
() => `Node array did not pass test '${getFunctionName(test)}'.`,
176+
assertEachNode)
177+
: noop;
178+
179+
export const assertNode = shouldAssert(AssertionLevel.Normal)
180+
? (node: Node | undefined, test: ((node: Node | undefined) => boolean) | undefined, message?: string): void => assert(
181+
test === undefined || test(node),
182+
message || "Unexpected node.",
183+
() => `Node ${formatSyntaxKind(node!.kind)} did not pass test '${getFunctionName(test!)}'.`,
184+
assertNode)
185+
: noop;
186+
187+
export const assertOptionalNode = shouldAssert(AssertionLevel.Normal)
188+
? (node: Node, test: (node: Node) => boolean, message?: string): void => assert(
189+
test === undefined || node === undefined || test(node),
190+
message || "Unexpected node.",
191+
() => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`,
192+
assertOptionalNode)
193+
: noop;
194+
195+
export const assertOptionalToken = shouldAssert(AssertionLevel.Normal)
196+
? (node: Node, kind: SyntaxKind, message?: string): void => assert(
197+
kind === undefined || node === undefined || node.kind === kind,
198+
message || "Unexpected node.",
199+
() => `Node ${formatSyntaxKind(node.kind)} was not a '${formatSyntaxKind(kind)}' token.`,
200+
assertOptionalToken)
201+
: noop;
202+
203+
export const assertMissingNode = shouldAssert(AssertionLevel.Normal)
204+
? (node: Node, message?: string): void => assert(
205+
node === undefined,
206+
message || "Unexpected node.",
207+
() => `Node ${formatSyntaxKind(node.kind)} was unexpected'.`,
208+
assertMissingNode)
209+
: noop;
210+
211+
let isDebugInfoEnabled = false;
212+
213+
/**
214+
* Injects debug information into frequently used types.
215+
*/
216+
export function enableDebugInfo() {
217+
if (isDebugInfoEnabled) return;
218+
219+
// Add additional properties in debug mode to assist with debugging.
220+
Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, {
221+
__debugFlags: { get(this: Symbol) { return formatSymbolFlags(this.flags); } }
222+
});
223+
224+
Object.defineProperties(objectAllocator.getTypeConstructor().prototype, {
225+
__debugFlags: { get(this: Type) { return formatTypeFlags(this.flags); } },
226+
__debugObjectFlags: { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((<ObjectType>this).objectFlags) : ""; } },
227+
__debugTypeToString: { value(this: Type) { return this.checker.typeToString(this); } },
228+
});
229+
230+
const nodeConstructors = [
231+
objectAllocator.getNodeConstructor(),
232+
objectAllocator.getIdentifierConstructor(),
233+
objectAllocator.getTokenConstructor(),
234+
objectAllocator.getSourceFileConstructor()
235+
];
236+
237+
for (const ctor of nodeConstructors) {
238+
if (!ctor.prototype.hasOwnProperty("__debugKind")) {
239+
Object.defineProperties(ctor.prototype, {
240+
__debugKind: { get(this: Node) { return formatSyntaxKind(this.kind); } },
241+
__debugNodeFlags: { get(this: Node) { return formatNodeFlags(this.flags); } },
242+
__debugModifierFlags: { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } },
243+
__debugTransformFlags: { get(this: Node) { return formatTransformFlags(this.transformFlags); } },
244+
__debugIsParseTreeNode: { get(this: Node) { return isParseTreeNode(this); } },
245+
__debugEmitFlags: { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } },
246+
__debugGetText: {
247+
value(this: Node, includeTrivia?: boolean) {
248+
if (nodeIsSynthesized(this)) return "";
249+
const parseNode = getParseTreeNode(this);
250+
const sourceFile = parseNode && getSourceFileOfNode(parseNode);
251+
return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : "";
252+
}
253+
}
254+
});
255+
}
256+
}
257+
258+
isDebugInfoEnabled = true;
259+
}
260+
}
261+
}

src/compiler/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
"files": [
1010
"core.ts",
11+
"debug.ts",
1112
"performance.ts",
1213
"semver.ts",
1314

0 commit comments

Comments
 (0)