Skip to content

Commit ac7fc8f

Browse files
author
Arthur Ozga
committed
Handle TODO's
1 parent 4fa32a2 commit ac7fc8f

File tree

6 files changed

+102
-50
lines changed

6 files changed

+102
-50
lines changed

src/compiler/checker.ts

Lines changed: 72 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2203,25 +2203,23 @@ namespace ts {
22032203
return createTypeParameterDeclaration(name, constraint, defaultParameter);
22042204
}
22052205

2206-
// TODO: enclosing declaration appears to be unused in getTypeOfSymbolAtLocation
22072206
function createParameterDeclarationFromSymbol(parameterSymbol: Symbol, enclosingDeclaration: Node): ParameterDeclaration {
22082207
const parameterDeclaration = parameterSymbol.declarations[0] as ParameterDeclaration;
22092208
const parameterType = getTypeOfSymbol(parameterSymbol);
22102209
const parameterTypeNode = createTypeNode(parameterType, enclosingDeclaration);
2211-
// TODO: clone binding names correctly.
2212-
// TODO: copy initialzer in a way that checks whether all symbols used in expression are accessible here, and qualify them appropriately.
2210+
// TODO: how should we clone members/modifiers?
2211+
// TODO: check initializer accessibility correctly.
22132212
const parameterNode = createParameter(
22142213
parameterDeclaration.decorators && parameterDeclaration.decorators.map(getSynthesizedDeepClone)
22152214
, parameterDeclaration.modifiers && parameterDeclaration.modifiers.map(getSynthesizedDeepClone)
22162215
, parameterDeclaration.dotDotDotToken && createToken(SyntaxKind.DotDotDotToken)
22172216
, getSynthesizedDeepClone(parameterDeclaration.name)
22182217
, parameterDeclaration.questionToken && createToken(SyntaxKind.QuestionToken)
22192218
, parameterTypeNode
2220-
, /*initializer*/ undefined);
2219+
, parameterDeclaration.initializer && getSynthesizedDeepClone(parameterDeclaration.initializer));
22212220
return parameterNode;
22222221
}
22232222

2224-
// TODO: expose this, remove copy from helper, possibly don't expose createParameter/TypeParameter?
22252223
function createSignatureParts(signature: Signature, enclosingDeclaration: Node): SignatureParts {
22262224
return {
22272225
typeParameters: signature.typeParameters && signature.typeParameters.map(parameter => createTypeParameterDeclarationFromType(parameter,enclosingDeclaration)),
@@ -2242,23 +2240,16 @@ namespace ts {
22422240
let checkAlias = true;
22432241
let symbolStack: Symbol[] = undefined;
22442242

2245-
let result = createTypeNodeWorker(type);
2246-
if (result) {
2247-
(<any>result).__type_source = type;
2248-
(<any>result).__type_source_str = typeToString(type);
2249-
}
2250-
return result;
2243+
const result = createTypeNodeWorker(type);
2244+
return encounteredError ? undefined: result;
22512245

22522246
function createTypeNodeWorker(type: Type): TypeNode {
22532247
if (!type) {
22542248
if (undefinedArgumentIsError) { encounteredError = true; }
22552249
return undefined;
22562250
}
22572251

2258-
const typeString = typeToString(type, enclosingDeclaration); typeString; // TODO: remove.
2259-
22602252
if (type.flags & TypeFlags.Any) {
2261-
// TODO: add other case where type ends up being `any`.
22622253
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
22632254
}
22642255
if (type.flags & TypeFlags.String) {
@@ -2318,19 +2309,16 @@ namespace ts {
23182309
}
23192310
if (objectFlags & ObjectFlags.ClassOrInterface) {
23202311
Debug.assert(!!(type.flags & TypeFlags.Object));
2321-
// TODO: Detect whether class is named and fail if not.
23222312
const name = createNameFromSymbol(type.symbol);
23232313
// TODO: handle type arguments.
2324-
return createTypeReferenceNode(name, /*typeParameters*/undefined);
2314+
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
23252315
}
23262316
if (type.flags & TypeFlags.TypeParameter) {
2327-
// TODO: get qualified name when necessary instead of string.
23282317
const name = createNameFromSymbol(type.symbol);
23292318
// Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter.
23302319
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
23312320
}
23322321

2333-
// TODO: move back up later on?
23342322
if (checkAlias && type.aliasSymbol) {
23352323
const name = createNameFromSymbol(type.aliasSymbol);
23362324
const typeArgumentNodes = mapToTypeNodeArray(type.aliasTypeArguments);
@@ -2352,18 +2340,14 @@ namespace ts {
23522340
return createAnonymousTypeNode(<ObjectType>type);
23532341
}
23542342

2355-
// TODO: implement when this is testable.
2356-
// else if (type.flags & TypeFlags.StringOrNumberLiteral) {
2357-
// writer.writeStringLiteral(literalTypeToString(<LiteralType>type));
2343+
// TODO (aozgaa): implement string and number literals here once there is a testable case.
23582344

23592345
if (type.flags & TypeFlags.Index) {
2360-
// TODO: test.
2361-
const indexType = getIndexType(getApparentType((<IndexType>type).type));
2362-
const indexTypeNode = createTypeNodeWorker(indexType);
2346+
const indexedType = (<IndexType>type).type;
2347+
const indexTypeNode = createTypeNodeWorker(indexedType);
23632348
return createTypeOperatorNode(indexTypeNode);
23642349
}
23652350
if (type.flags & TypeFlags.IndexedAccess) {
2366-
// TODO: test.
23672351
const objectTypeNode = createTypeNodeWorker((<IndexedAccessType>type).objectType);
23682352
const indexTypeNode = createTypeNodeWorker((<IndexedAccessType>type).indexType);
23692353
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
@@ -2375,27 +2359,15 @@ namespace ts {
23752359
return types && asNodeArray(types.map(createTypeNodeWorker) as TypeNode[]);
23762360
}
23772361

2378-
function createNameFromSymbol(symbol: Symbol): Identifier;
2379-
function createNameFromSymbol(symbol: Symbol): EntityName;
2380-
function createNameFromSymbol(symbol: Symbol): EntityName {
2381-
symbol; enclosingDeclaration;
2382-
// TODO: actually implement this
2383-
return createIdentifier(symbolToString(symbol, enclosingDeclaration));
2384-
}
2385-
23862362
function createMappedTypeNodeFromType(type: MappedType) {
23872363
Debug.assert(!!(type.flags & TypeFlags.Object));
2388-
2389-
// TODO: does typeParameter have the same constraint or do we need to overwrite it somehow?
23902364
const typeParameter = getTypeParameterFromMappedType(<MappedType>type);
2391-
// const constraintType = getConstraintTypeFromMappedType(<MappedType>type);
23922365
const typeParameterNode = createTypeParameterDeclarationFromType(typeParameter, enclosingDeclaration);
23932366

23942367
const templateTypeNode = createTypeNode(getTemplateTypeFromMappedType(<MappedType>type), enclosingDeclaration);
23952368
const readonlyToken = (<MappedType>type).declaration && (<MappedType>type).declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
23962369
const questionToken = (<MappedType>type).declaration && (<MappedType>type).declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined;
23972370

2398-
// TODO: test.
23992371
return createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode);
24002372
}
24012373

@@ -2501,7 +2473,6 @@ namespace ts {
25012473
return createTupleTypeNode(typeArguments.length > 0 ? mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type))) : undefined);
25022474
}
25032475
else {
2504-
// TODO: handle type parameters in qualified names...
25052476
const outerTypeParameters = type.target.outerTypeParameters;
25062477
let i = 0;
25072478
let qualifiedName: QualifiedName | undefined = undefined;
@@ -2516,10 +2487,9 @@ namespace ts {
25162487
} while (i < length && getParentSymbolOfTypeParameter(outerTypeParameters[i]) === parent);
25172488
// When type parameters are their own type arguments for the whole group (i.e. we have
25182489
// the default outer type arguments), we don't show the group.
2519-
// TODO: figure out how to handle type arguments
25202490
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
25212491
const name = createNameFromSymbol(parent);
2522-
const qualifiedNamePart = name; // createTypeReferenceNode(name, mapToTypeNodeArray(typeArguments.slice(start, i - start)));
2492+
const qualifiedNamePart = name;
25232493
if (!qualifiedName) {
25242494
qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/undefined);
25252495
}
@@ -2534,7 +2504,6 @@ namespace ts {
25342504
let entityName: EntityName = undefined;
25352505
const nameIdentifier = createNameFromSymbol(type.symbol);
25362506
if (qualifiedName) {
2537-
// TODO: handle checking of type arguments for qualified names?
25382507
Debug.assert(!qualifiedName.right);
25392508
qualifiedName.right = nameIdentifier;
25402509
entityName = qualifiedName;
@@ -2597,6 +2566,68 @@ namespace ts {
25972566
}
25982567
return typeElements.length ? typeElements : undefined;
25992568
}
2569+
2570+
function createNameFromSymbol(symbol: Symbol): Identifier;
2571+
function createNameFromSymbol(symbol: Symbol): EntityName;
2572+
function createNameFromSymbol(symbol: Symbol): EntityName {
2573+
let parentSymbol: Symbol;
2574+
symbol; enclosingDeclaration;
2575+
let meaning: SymbolFlags;
2576+
2577+
// Get qualified name if the symbol is not a type parameter
2578+
// and there is an enclosing declaration.
2579+
let chain: Symbol[];
2580+
const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter;
2581+
if (!isTypeParameter && enclosingDeclaration) {
2582+
chain = getSymbolChain(symbol, meaning, /*endOfChain*/ true);
2583+
Debug.assert(chain && chain.length > 0);
2584+
}
2585+
else {
2586+
chain = [symbol];
2587+
}
2588+
2589+
const result = createEntityNameFromSymbolChain(chain, chain.length - 1);
2590+
return result;
2591+
2592+
function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName {
2593+
Debug.assert(chain && 0 <= index && index < chain.length);
2594+
const identifier = createIdentifier(getNameOfSymbol(chain[index]));
2595+
return index > 0 ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier;
2596+
}
2597+
2598+
/** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */
2599+
function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined {
2600+
let accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/false);
2601+
2602+
if (!accessibleSymbolChain ||
2603+
needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
2604+
2605+
// Go up and add our parent.
2606+
const parent = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
2607+
if (parent) {
2608+
const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
2609+
if (parentChain) {
2610+
accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [symbol]);
2611+
}
2612+
}
2613+
}
2614+
2615+
if (accessibleSymbolChain) {
2616+
return accessibleSymbolChain;
2617+
}
2618+
2619+
else if (
2620+
// If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols.
2621+
endOfChain ||
2622+
// If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.)
2623+
!(!parentSymbol && ts.forEach(symbol.declarations, hasExternalModuleSymbol)) &&
2624+
// If a parent symbol is an anonymous type, don't write it.
2625+
!(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral))) {
2626+
2627+
return [symbol];
2628+
}
2629+
}
2630+
}
26002631
}
26012632
}
26022633

src/compiler/visitor.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,13 +333,18 @@ namespace ts {
333333
return updateTypeOperatorNode(<TypeOperatorNode>node, visitNode((<TypeOperatorNode>node).type, visitor, isTypeNode));
334334
case SyntaxKind.IndexedAccessType:
335335
return updateIndexedAccessTypeNode((<IndexedAccessTypeNode>node)
336-
, visitNode((<IndexedAccessTypeNode>node).objectType, visitor, isTypeNode)
337-
, visitNode((<IndexedAccessTypeNode>node).indexType, visitor, isTypeNode));
336+
, visitNode((<IndexedAccessTypeNode>node).objectType, visitor, isTypeNode)
337+
, visitNode((<IndexedAccessTypeNode>node).indexType, visitor, isTypeNode));
338338
case SyntaxKind.MappedType:
339-
throw new Error("reached unsupported type in visitor.");
339+
return updateMappedTypeNode((<MappedTypeNode>node)
340+
, visitNode((<MappedTypeNode>node).readonlyToken, visitor, isToken)
341+
, visitNode((<MappedTypeNode>node).typeParameter, visitor, isTypeParameter)
342+
, visitNode((<MappedTypeNode>node).questionToken, visitor, isToken)
343+
, visitNode((<MappedTypeNode>node).type, visitor, isTypeNode));
344+
340345
case SyntaxKind.LiteralType:
341346
return updateLiteralTypeNode(<LiteralTypeNode>node
342-
, visitNode((<LiteralTypeNode>node).literal, visitor, isExpression));
347+
, visitNode((<LiteralTypeNode>node).literal, visitor, isExpression));
343348

344349
// Type Declarations
345350

src/services/codefixes/fixAddMissingMember.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ namespace ts.codefix {
5050
, /*questionToken*/ undefined
5151
, typeNode
5252
, /*initializer*/ undefined);
53-
// TODO: make index signature.
5453
const propertyChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
5554
propertyChangeTracker.insertNodeAfter(sourceFile, openBrace, property, { suffix: context.newLineCharacter });
5655

src/services/codefixes/helpers.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ namespace ts.codefix {
44
export function newNodesToChanges(newNodes: Node[], insertAfter: Node, context: CodeFixContext) {
55
const sourceFile = context.sourceFile;
66
if (!(newNodes)) {
7-
// TODO: make the appropriate value flow through gracefully.
87
throw new Error("newNodesToChanges expects an array");
98
}
109

@@ -13,6 +12,7 @@ namespace ts.codefix {
1312
for (const newNode of newNodes) {
1413
changeTracker.insertNodeAfter(sourceFile, insertAfter, newNode, { suffix: context.newLineCharacter });
1514
}
15+
// TODO (aozgaa): concatenate changes into a single change.
1616
return changeTracker.getChanges();
1717
}
1818

@@ -51,7 +51,6 @@ namespace ts.codefix {
5151
}
5252

5353
const declaration = declarations[0] as Declaration;
54-
// TODO: get name as identifier or computer property name, etc.
5554
const name = declaration.name ? getSynthesizedDeepClone(declaration.name) as PropertyName : undefined;
5655
const visibilityModifier = createVisibilityModifier(getModifierFlags(declaration));
5756
const modifiers = visibilityModifier ? [visibilityModifier] : undefined;
@@ -63,7 +62,6 @@ namespace ts.codefix {
6362
case SyntaxKind.PropertySignature:
6463
case SyntaxKind.PropertyDeclaration:
6564
const typeNode = checker.createTypeNode(type, enclosingDeclaration);
66-
// TODO: add modifiers.
6765
const property = createProperty(
6866
/*decorators*/undefined
6967
, modifiers
@@ -96,7 +94,6 @@ namespace ts.codefix {
9694

9795
let signatureDeclarations = [];
9896
for (let i = 0; i < signatures.length; i++) {
99-
// TODO: make signatures instead of methods
10097
const signature = signatures[i];
10198
const signatureParts = checker.createSignatureParts(signature, enclosingDeclaration);
10299
signatureDeclarations.push(createMethod(
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// interface I<X> {
4+
//// x: keyof X;
5+
//// }
6+
//// class C<Y> implements I<Y> {[| |]}
7+
8+
verify.rangeAfterCodeFix(`
9+
x: keyof Y;
10+
`);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// interface I<X> {
4+
//// x: { readonly [K in keyof X]: X[K] };
5+
//// }
6+
//// class C<Y> implements I<Y> {[| |]}
7+
8+
verify.rangeAfterCodeFix(`
9+
x: { readonly [K in keyof X]: Y[K]; };
10+
`);

0 commit comments

Comments
 (0)