From 2c9b6c0c1f2dde14f2d079f04f4807c5e5b6d8d8 Mon Sep 17 00:00:00 2001 From: Keen Yee Liau Date: Fri, 14 Dec 2018 13:40:01 -0800 Subject: [PATCH] fix(compiler-cli): create LiteralLikeNode for String and Number literal (#27536) Typescript 3.2 introduced BigInt type, and consequently the implementation for checkExpressionWorker() in checkers.ts is refactored. For NumberLiteral and StringLiteral types, 'text' filed must be present in the Node type, therefore they must be LiteralLikeNode instead of Node. PR Close #27536 --- .../src/diagnostics/typescript_symbols.ts | 13 +++++++--- .../diagnostics/typescript_symbols_spec.ts | 25 ++++++++++++++++++- packages/compiler-cli/test/ngc_spec.ts | 6 ++--- .../language-service/test/diagnostics_spec.ts | 9 +++++++ 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/packages/compiler-cli/src/diagnostics/typescript_symbols.ts b/packages/compiler-cli/src/diagnostics/typescript_symbols.ts index b55e96faf2..30fa65cb52 100644 --- a/packages/compiler-cli/src/diagnostics/typescript_symbols.ts +++ b/packages/compiler-cli/src/diagnostics/typescript_symbols.ts @@ -718,13 +718,20 @@ function getBuiltinTypeFromTs(kind: BuiltinType, context: TypeContext): ts.Type checker.getTypeAtLocation(setParents({kind: ts.SyntaxKind.NullKeyword}, node)); break; case BuiltinType.Number: - const numeric = {kind: ts.SyntaxKind.NumericLiteral}; + const numeric = { + kind: ts.SyntaxKind.NumericLiteral, + text: node.getText(), + }; setParents({kind: ts.SyntaxKind.ExpressionStatement, expression: numeric}, node); type = checker.getTypeAtLocation(numeric); break; case BuiltinType.String: - type = checker.getTypeAtLocation( - setParents({kind: ts.SyntaxKind.NoSubstitutionTemplateLiteral}, node)); + type = checker.getTypeAtLocation(setParents( + { + kind: ts.SyntaxKind.NoSubstitutionTemplateLiteral, + text: node.getText(), + }, + node)); break; case BuiltinType.Undefined: type = checker.getTypeAtLocation(setParents( diff --git a/packages/compiler-cli/test/diagnostics/typescript_symbols_spec.ts b/packages/compiler-cli/test/diagnostics/typescript_symbols_spec.ts index def8a986c2..58123d97c7 100644 --- a/packages/compiler-cli/test/diagnostics/typescript_symbols_spec.ts +++ b/packages/compiler-cli/test/diagnostics/typescript_symbols_spec.ts @@ -12,7 +12,7 @@ import {EmittingCompilerHost, MockAotCompilerHost, MockCompilerHost, MockData, M import {ReflectorHost} from '@angular/language-service/src/reflector_host'; import * as ts from 'typescript'; -import {Symbol, SymbolQuery, SymbolTable} from '../../src/diagnostics/symbols'; +import {BuiltinType, Symbol, SymbolQuery, SymbolTable} from '../../src/diagnostics/symbols'; import {getSymbolQuery, toSymbolTableFactory} from '../../src/diagnostics/typescript_symbols'; import {CompilerOptions} from '../../src/transformers/api'; import {Directory} from '../mocks'; @@ -55,6 +55,29 @@ describe('symbol query', () => { const symbol = query.getTypeSymbol(unknownType); expect(symbol).toBeUndefined(); }); + + it('should return correct built-in types', () => { + const tests: Array<[BuiltinType, boolean, ts.TypeFlags?]> = [ + // builtinType, throws, want + [BuiltinType.Any, false, ts.TypeFlags.Any], + [BuiltinType.Boolean, false, ts.TypeFlags.BooleanLiteral], + [BuiltinType.Null, false, ts.TypeFlags.Null], + [BuiltinType.Number, false, ts.TypeFlags.NumberLiteral], + [BuiltinType.String, false, ts.TypeFlags.StringLiteral], + [BuiltinType.Undefined, false, ts.TypeFlags.Undefined], + [BuiltinType.Unbound, true], + [BuiltinType.Other, true], + ]; + for (const [builtinType, throws, want] of tests) { + if (throws) { + expect(() => query.getBuiltinType(builtinType)).toThrow(); + } else { + const symbol = query.getBuiltinType(builtinType); + const got: ts.TypeFlags = (symbol as any).tsType.flags; + expect(got).toBe(want !); + } + } + }); }); describe('toSymbolTableFactory(tsVersion)', () => { diff --git a/packages/compiler-cli/test/ngc_spec.ts b/packages/compiler-cli/test/ngc_spec.ts index 59b7c28214..55dbc8ca0e 100644 --- a/packages/compiler-cli/test/ngc_spec.ts +++ b/packages/compiler-cli/test/ngc_spec.ts @@ -145,9 +145,7 @@ describe('ngc transformer command-line', () => { const exitCode = main(['-p', basePath], errorSpy); expect(errorSpy).toHaveBeenCalledWith( - `test.ts(1,9): error TS2305: Module '"` + path.join(basePath, 'empty-deps') + - `"' has no exported member 'MyClass'.` + - '\n'); + `test.ts(1,9): error TS2305: Module '"./empty-deps"' has no exported member 'MyClass'.\n`); expect(exitCode).toEqual(1); }); @@ -874,7 +872,7 @@ describe('ngc transformer command-line', () => { write('mymodule.ts', ` import {Component, NgModule} from '@angular/core'; import {RouterModule} from '@angular/router'; - + export function foo(): string { console.log('side-effect'); return 'test'; diff --git a/packages/language-service/test/diagnostics_spec.ts b/packages/language-service/test/diagnostics_spec.ts index d8692fe35e..c756a995f6 100644 --- a/packages/language-service/test/diagnostics_spec.ts +++ b/packages/language-service/test/diagnostics_spec.ts @@ -149,6 +149,15 @@ describe('diagnostics', () => { }); }); + it('should not report an error for sub-types of number', () => { + const code = + ` @Component({template: \`
\`}) export class MyComponent { something: 123 | 456; }`; + addCode(code, fileName => { + const diagnostics = ngService.getDiagnostics(fileName); + expectOnlyModuleDiagnostics(diagnostics); + }); + }); + it('should report a warning if an event results in a callable expression', () => { const code = ` @Component({template: \`
\`}) export class MyComponent { onClick() { } }`;