Skip to content

Commit 8be8e1f

Browse files
Merge pull request #708 from Microsoft/classifiedQuickInfo
Initial work on classified quick info.
2 parents 60b29e9 + d6fc3fc commit 8be8e1f

File tree

7 files changed

+785
-201
lines changed

7 files changed

+785
-201
lines changed

src/compiler/checker.ts

Lines changed: 376 additions & 141 deletions
Large diffs are not rendered by default.

src/compiler/emitter.ts

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ module ts {
101101
};
102102
}
103103

104-
function createTextWriter(writeSymbol: (symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags)=> void): EmitTextWriter {
104+
function createTextWriter(trackSymbol: (symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags)=> void): EmitTextWriter {
105105
var output = "";
106106
var indent = 0;
107107
var lineStart = true;
@@ -149,7 +149,7 @@ module ts {
149149

150150
return {
151151
write: write,
152-
writeSymbol: writeSymbol,
152+
trackSymbol: trackSymbol,
153153
rawWrite: rawWrite,
154154
writeLiteral: writeLiteral,
155155
writeLine: writeLine,
@@ -182,7 +182,7 @@ module ts {
182182
});
183183
}
184184

185-
function emitComments(comments: Comment[], trailingSeparator: boolean, writer: EmitTextWriter, writeComment: (comment: Comment, writer: EmitTextWriter) => void) {
185+
function emitComments(comments: CommentRange[], trailingSeparator: boolean, writer: EmitTextWriter, writeComment: (comment: CommentRange, writer: EmitTextWriter) => void) {
186186
var emitLeadingSpace = !trailingSeparator;
187187
forEach(comments, comment => {
188188
if (emitLeadingSpace) {
@@ -203,15 +203,15 @@ module ts {
203203
});
204204
}
205205

206-
function emitNewLineBeforeLeadingComments(node: TextRange, leadingComments: Comment[], writer: EmitTextWriter) {
206+
function emitNewLineBeforeLeadingComments(node: TextRange, leadingComments: CommentRange[], writer: EmitTextWriter) {
207207
// If the leading comments start on different line than the start of node, write new line
208208
if (leadingComments && leadingComments.length && node.pos !== leadingComments[0].pos &&
209209
getLineOfLocalPosition(node.pos) !== getLineOfLocalPosition(leadingComments[0].pos)) {
210210
writer.writeLine();
211211
}
212212
}
213213

214-
function writeCommentRange(comment: Comment, writer: EmitTextWriter) {
214+
function writeCommentRange(comment: CommentRange, writer: EmitTextWriter) {
215215
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
216216
var firstCommentLineAndCharacter = currentSourceFile.getLineAndCharacterFromPosition(comment.pos);
217217
var firstCommentLineIndent: number;
@@ -307,7 +307,7 @@ module ts {
307307
}
308308

309309
function emitJavaScript(jsFilePath: string, root?: SourceFile) {
310-
var writer = createTextWriter(writeSymbol);
310+
var writer = createTextWriter(trackSymbol);
311311
var write = writer.write;
312312
var writeLine = writer.writeLine;
313313
var increaseIndent = writer.increaseIndent;
@@ -363,7 +363,7 @@ module ts {
363363
/** Sourcemap data that will get encoded */
364364
var sourceMapData: SourceMapData;
365365

366-
function writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) { }
366+
function trackSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) { }
367367

368368
function initializeEmitterWithSourceMaps() {
369369
var sourceMapDir: string; // The directory in which sourcemap will be
@@ -585,7 +585,7 @@ module ts {
585585
sourceMapNameIndices.pop();
586586
};
587587

588-
function writeCommentRangeWithMap(comment: Comment, writer: EmitTextWriter) {
588+
function writeCommentRangeWithMap(comment: CommentRange, writer: EmitTextWriter) {
589589
recordSourceMapSpan(comment.pos);
590590
writeCommentRange(comment, writer);
591591
recordSourceMapSpan(comment.end);
@@ -916,14 +916,15 @@ module ts {
916916
}
917917

918918
function emitPropertyAccess(node: PropertyAccess) {
919-
var text = resolver.getPropertyAccessSubstitution(node);
920-
if (text) {
921-
write(text);
922-
return;
919+
var constantValue = resolver.getConstantValue(node);
920+
if (constantValue !== undefined) {
921+
write(constantValue.toString() + " /* " + identifierToString(node.right) + " */");
922+
}
923+
else {
924+
emit(node.left);
925+
write(".");
926+
emit(node.right);
923927
}
924-
emit(node.left);
925-
write(".");
926-
emit(node.right);
927928
}
928929

929930
function emitIndexedAccess(node: IndexedAccess) {
@@ -2155,7 +2156,7 @@ module ts {
21552156

21562157
function getLeadingCommentsWithoutDetachedComments() {
21572158
// get the leading comments from detachedPos
2158-
var leadingComments = getLeadingComments(currentSourceFile.text, detachedCommentsInfo[detachedCommentsInfo.length - 1].detachedCommentEndPos);
2159+
var leadingComments = getLeadingCommentRanges(currentSourceFile.text, detachedCommentsInfo[detachedCommentsInfo.length - 1].detachedCommentEndPos);
21592160
if (detachedCommentsInfo.length - 1) {
21602161
detachedCommentsInfo.pop();
21612162
}
@@ -2169,14 +2170,14 @@ module ts {
21692170
function getLeadingCommentsToEmit(node: Node) {
21702171
// Emit the leading comments only if the parent's pos doesn't match because parent should take care of emitting these comments
21712172
if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) {
2172-
var leadingComments: Comment[];
2173+
var leadingComments: CommentRange[];
21732174
if (hasDetachedComments(node.pos)) {
21742175
// get comments without detached comments
21752176
leadingComments = getLeadingCommentsWithoutDetachedComments();
21762177
}
21772178
else {
21782179
// get the leading comments from the node
2179-
leadingComments = getLeadingCommentsOfNode(node, currentSourceFile);
2180+
leadingComments = getLeadingCommentRangesOfNode(node, currentSourceFile);
21802181
}
21812182
return leadingComments;
21822183
}
@@ -2192,32 +2193,32 @@ module ts {
21922193
function emitTrailingDeclarationComments(node: Node) {
21932194
// Emit the trailing comments only if the parent's end doesn't match
21942195
if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) {
2195-
var trailingComments = getTrailingComments(currentSourceFile.text, node.end);
2196+
var trailingComments = getTrailingCommentRanges(currentSourceFile.text, node.end);
21962197
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
21972198
emitComments(trailingComments, /*trailingSeparator*/ false, writer, writeComment);
21982199
}
21992200
}
22002201

22012202
function emitLeadingCommentsOfLocalPosition(pos: number) {
2202-
var leadingComments: Comment[];
2203+
var leadingComments: CommentRange[];
22032204
if (hasDetachedComments(pos)) {
22042205
// get comments without detached comments
22052206
leadingComments = getLeadingCommentsWithoutDetachedComments();
22062207
}
22072208
else {
22082209
// get the leading comments from the node
2209-
leadingComments = getLeadingComments(currentSourceFile.text, pos);
2210+
leadingComments = getLeadingCommentRanges(currentSourceFile.text, pos);
22102211
}
22112212
emitNewLineBeforeLeadingComments({ pos: pos, end: pos }, leadingComments, writer);
22122213
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
22132214
emitComments(leadingComments, /*trailingSeparator*/ true, writer, writeComment);
22142215
}
22152216

22162217
function emitDetachedCommentsAtPosition(node: TextRange) {
2217-
var leadingComments = getLeadingComments(currentSourceFile.text, node.pos);
2218+
var leadingComments = getLeadingCommentRanges(currentSourceFile.text, node.pos);
22182219
if (leadingComments) {
2219-
var detachedComments: Comment[] = [];
2220-
var lastComment: Comment;
2220+
var detachedComments: CommentRange[] = [];
2221+
var lastComment: CommentRange;
22212222

22222223
forEach(leadingComments, comment => {
22232224
if (lastComment) {
@@ -2261,7 +2262,7 @@ module ts {
22612262
function emitPinnedOrTripleSlashCommentsOfNode(node: Node) {
22622263
var pinnedComments = ts.filter(getLeadingCommentsToEmit(node), isPinnedOrTripleSlashComment);
22632264

2264-
function isPinnedOrTripleSlashComment(comment: Comment) {
2265+
function isPinnedOrTripleSlashComment(comment: CommentRange) {
22652266
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
22662267
return currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
22672268
}
@@ -2300,7 +2301,7 @@ module ts {
23002301
}
23012302

23022303
function emitDeclarations(jsFilePath: string, root?: SourceFile) {
2303-
var writer = createTextWriter(writeSymbol);
2304+
var writer = createTextWriter(trackSymbol);
23042305
var write = writer.write;
23052306
var writeLine = writer.writeLine;
23062307
var increaseIndent = writer.increaseIndent;
@@ -2328,7 +2329,7 @@ module ts {
23282329
var oldWriter = writer;
23292330
forEach(importDeclarations, aliasToWrite => {
23302331
var aliasEmitInfo = forEach(aliasDeclarationEmitInfo, declEmitInfo => declEmitInfo.declaration === aliasToWrite ? declEmitInfo : undefined);
2331-
writer = createTextWriter(writeSymbol);
2332+
writer = createTextWriter(trackSymbol);
23322333
for (var declarationIndent = aliasEmitInfo.indent; declarationIndent; declarationIndent--) {
23332334
writer.increaseIndent();
23342335
}
@@ -2339,10 +2340,9 @@ module ts {
23392340
writer = oldWriter;
23402341
}
23412342

2342-
function writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
2343+
function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
23432344
var symbolAccesibilityResult = resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning);
23442345
if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
2345-
resolver.writeSymbol(symbol, enclosingDeclaration, meaning, writer);
23462346

23472347
// write the aliases
23482348
if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) {

src/compiler/parser.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,25 +138,27 @@ module ts {
138138
return (<Identifier>(<ExpressionStatement>node).expression).text === "use strict";
139139
}
140140

141-
export function getLeadingCommentsOfNode(node: Node, sourceFileOfNode: SourceFile) {
141+
export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode?: SourceFile) {
142+
sourceFileOfNode = sourceFileOfNode || getSourceFileOfNode(node);
143+
142144
// If parameter/type parameter, the prev token trailing comments are part of this node too
143145
if (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter) {
144146
// e.g. (/** blah */ a, /** blah */ b);
145-
return concatenate(getTrailingComments(sourceFileOfNode.text, node.pos),
147+
return concatenate(getTrailingCommentRanges(sourceFileOfNode.text, node.pos),
146148
// e.g.: (
147149
// /** blah */ a,
148150
// /** blah */ b);
149-
getLeadingComments(sourceFileOfNode.text, node.pos));
151+
getLeadingCommentRanges(sourceFileOfNode.text, node.pos));
150152
}
151153
else {
152-
return getLeadingComments(sourceFileOfNode.text, node.pos);
154+
return getLeadingCommentRanges(sourceFileOfNode.text, node.pos);
153155
}
154156
}
155157

156158
export function getJsDocComments(node: Declaration, sourceFileOfNode: SourceFile) {
157-
return filter(getLeadingCommentsOfNode(node, sourceFileOfNode), comment => isJsDocComment(comment));
159+
return filter(getLeadingCommentRangesOfNode(node, sourceFileOfNode), comment => isJsDocComment(comment));
158160

159-
function isJsDocComment(comment: Comment) {
161+
function isJsDocComment(comment: CommentRange) {
160162
// True if the comment starts with '/**' but not if it is '/**/'
161163
return sourceFileOfNode.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
162164
sourceFileOfNode.text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk &&

src/compiler/scanner.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,8 @@ module ts {
371371
// between the given position and the next line break are returned. The return value is an array containing a TextRange for each
372372
// comment. Single-line comment ranges include the beginning '//' characters but not the ending line break. Multi-line comment
373373
// ranges include the beginning '/* and ending '*/' characters. The return value is undefined if no comments were found.
374-
function getCommentRanges(text: string, pos: number, trailing: boolean): Comment[] {
375-
var result: Comment[];
374+
function getCommentRanges(text: string, pos: number, trailing: boolean): CommentRange[] {
375+
var result: CommentRange[];
376376
var collecting = trailing || pos === 0;
377377
while (true) {
378378
var ch = text.charCodeAt(pos);
@@ -440,11 +440,11 @@ module ts {
440440
}
441441
}
442442

443-
export function getLeadingComments(text: string, pos: number): Comment[] {
443+
export function getLeadingCommentRanges(text: string, pos: number): CommentRange[] {
444444
return getCommentRanges(text, pos, /*trailing*/ false);
445445
}
446446

447-
export function getTrailingComments(text: string, pos: number): Comment[] {
447+
export function getTrailingCommentRanges(text: string, pos: number): CommentRange[] {
448448
return getCommentRanges(text, pos, /*trailing*/ true);
449449
}
450450

src/compiler/types.ts

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ module ts {
529529
filename: string;
530530
}
531531

532-
export interface Comment extends TextRange {
532+
export interface CommentRange extends TextRange {
533533
hasTrailingNewLine?: boolean;
534534
}
535535

@@ -640,15 +640,21 @@ module ts {
640640
getApparentType(type: Type): ApparentType;
641641
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
642642
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
643+
typeToDisplayParts(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[];
644+
symbolToDisplayParts(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): SymbolDisplayPart[];
643645
getFullyQualifiedName(symbol: Symbol): string;
644646
getAugmentedPropertiesOfApparentType(type: Type): Symbol[];
645647
getRootSymbol(symbol: Symbol): Symbol;
646648
getContextualType(node: Node): Type;
649+
650+
// Returns the constant value of this enum member, or 'undefined' if the enum member has a
651+
// computed value.
652+
getEnumMemberValue(node: EnumMember): number;
647653
}
648654

649655
export interface TextWriter {
650656
write(s: string): void;
651-
writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
657+
trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
652658
writeLine(): void;
653659
increaseIndent(): void;
654660
decreaseIndent(): void;
@@ -679,7 +685,6 @@ module ts {
679685
getProgram(): Program;
680686
getLocalNameOfContainer(container: Declaration): string;
681687
getExpressionNamePrefix(node: Identifier): string;
682-
getPropertyAccessSubstitution(node: PropertyAccess): string;
683688
getExportAssignmentName(node: SourceFile): string;
684689
isReferencedImportDeclaration(node: ImportDeclaration): boolean;
685690
isTopLevelValueImportedViaEntityName(node: ImportDeclaration): boolean;
@@ -690,9 +695,12 @@ module ts {
690695
isImplementationOfOverload(node: FunctionDeclaration): boolean;
691696
writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void;
692697
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void;
693-
writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, writer: TextWriter): void;
694698
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult;
695699
isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult;
700+
701+
// Returns the constant value this property access resolves to, or 'undefined' if it does
702+
// resolve to a constant.
703+
getConstantValue(node: PropertyAccess): number;
696704
}
697705

698706
export enum SymbolFlags {
@@ -794,13 +802,16 @@ module ts {
794802
}
795803

796804
export enum NodeCheckFlags {
797-
TypeChecked = 0x00000001, // Node has been type checked
798-
LexicalThis = 0x00000002, // Lexical 'this' reference
799-
CaptureThis = 0x00000004, // Lexical 'this' used in body
800-
EmitExtends = 0x00000008, // Emit __extends
801-
SuperInstance = 0x00000010, // Instance 'super' reference
802-
SuperStatic = 0x00000020, // Static 'super' reference
803-
ContextChecked = 0x00000040, // Contextual types have been assigned
805+
TypeChecked = 0x00000001, // Node has been type checked
806+
LexicalThis = 0x00000002, // Lexical 'this' reference
807+
CaptureThis = 0x00000004, // Lexical 'this' used in body
808+
EmitExtends = 0x00000008, // Emit __extends
809+
SuperInstance = 0x00000010, // Instance 'super' reference
810+
SuperStatic = 0x00000020, // Static 'super' reference
811+
ContextChecked = 0x00000040, // Contextual types have been assigned
812+
813+
// Values for enum members have been computed, and any errors have been reported for them.
814+
EnumValuesComputed = 0x00000080,
804815
}
805816

806817
export interface NodeLinks {
@@ -1171,6 +1182,48 @@ module ts {
11711182
verticalTab = 0x0B, // \v
11721183
}
11731184

1185+
export class SymbolDisplayPart {
1186+
constructor(public text: string,
1187+
public kind: SymbolDisplayPartKind,
1188+
public symbol: Symbol) {
1189+
}
1190+
1191+
public toJSON() {
1192+
return {
1193+
text: this.text,
1194+
kind: SymbolDisplayPartKind[this.kind]
1195+
};
1196+
}
1197+
}
1198+
1199+
export enum SymbolDisplayPartKind {
1200+
aliasName,
1201+
className,
1202+
enumName,
1203+
fieldName,
1204+
interfaceName,
1205+
keyword,
1206+
labelName,
1207+
lineBreak,
1208+
numericLiteral,
1209+
stringLiteral,
1210+
localName,
1211+
methodName,
1212+
moduleName,
1213+
namespaceName,
1214+
operator,
1215+
parameterName,
1216+
propertyName,
1217+
punctuation,
1218+
space,
1219+
anonymousTypeIndicator,
1220+
text,
1221+
typeParameterName,
1222+
enumMemberName,
1223+
functionName,
1224+
regularExpressionLiteral,
1225+
}
1226+
11741227
export interface CancellationToken {
11751228
isCancellationRequested(): boolean;
11761229
}

0 commit comments

Comments
 (0)