fix(compiler): Report references to non-exported symbols.

Includes fixes to places now reported as errors.

Part of #8310
This commit is contained in:
Chuck Jazdzewski 2016-08-02 14:38:31 -07:00
parent 6195a45ae2
commit 9925aa89dc
6 changed files with 57 additions and 5 deletions

View File

@ -6,14 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, ElementRef, Host, Input, OnDestroy, Optional, Renderer, forwardRef} from '@angular/core';
import {Directive, ElementRef, Host, Input, OnDestroy, OpaqueToken, Optional, Renderer, Type, forwardRef} from '@angular/core';
import {MapWrapper} from '../../facade/collection';
import {StringWrapper, isBlank, isPresent, isPrimitive, isString, looseIdentical} from '../../facade/lang';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
const SELECT_MULTIPLE_VALUE_ACCESSOR = {
export const SELECT_MULTIPLE_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SelectMultipleControlValueAccessor),
multi: true

View File

@ -35,7 +35,7 @@ import {NG_VALIDATORS, Validators} from '../validators';
*/
export interface Validator { validate(c: AbstractControl): {[key: string]: any}; }
const REQUIRED = Validators.required;
export const REQUIRED = Validators.required;
export const REQUIRED_VALIDATOR: any = {
provide: NG_VALIDATORS,

View File

@ -594,6 +594,10 @@ function expandedMessage(error: any): string {
error.context && error.context.name ? `Calling function '${error.context.name}', f` : 'F';
return prefix +
'unction calls are not supported. Consider replacing the function or lambda with a reference to an exported function';
case 'Reference to a local symbol':
if (error.context && error.context.name) {
return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`;
}
}
return error.message;
}

View File

@ -6,14 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, ElementRef, Host, Input, OnDestroy, Optional, Renderer, forwardRef} from '@angular/core';
import {Directive, ElementRef, Host, Input, OnDestroy, OpaqueToken, Optional, Renderer, Type, forwardRef} from '@angular/core';
import {MapWrapper} from '../facade/collection';
import {StringWrapper, isBlank, isPresent, isPrimitive, isString, looseIdentical} from '../facade/lang';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
const SELECT_MULTIPLE_VALUE_ACCESSOR = {
export const SELECT_MULTIPLE_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SelectMultipleControlValueAccessor),
multi: true

View File

@ -297,13 +297,19 @@ export class MetadataCollector {
} else {
varValue = errorSym('Variable not initialized', nameNode);
}
let exported = false;
if (variableStatement.flags & ts.NodeFlags.Export ||
variableDeclaration.flags & ts.NodeFlags.Export) {
if (!metadata) metadata = {};
metadata[nameNode.text] = varValue;
exported = true;
}
if (isPrimitive(varValue)) {
locals.define(nameNode.text, varValue);
} else if (!exported) {
locals.define(
nameNode.text,
errorSym('Reference to a local symbol', nameNode, {name: nameNode.text}));
}
} else {
// Destructuring (or binding) declarations are not supported,

View File

@ -24,6 +24,7 @@ describe('Collector', () => {
'exported-functions.ts',
'exported-enum.ts',
'exported-consts.ts',
'local-symbol-ref.ts',
're-exports.ts',
'static-field-reference.ts',
'static-method.ts',
@ -486,6 +487,28 @@ describe('Collector', () => {
{from: 'angular2/core'}
]);
});
it('should collect an error symbol if collecting a reference to a non-exported symbol', () => {
let source = program.getSourceFile('/local-symbol-ref.ts');
let metadata = collector.getMetadata(source);
expect(metadata.metadata).toEqual({
REQUIRED_VALIDATOR: {
__symbolic: 'error',
message: 'Reference to a local symbol',
line: 3,
character: 9,
context: {name: 'REQUIRED'}
},
SomeComponent: {
__symbolic: 'class',
decorators: [{
__symbolic: 'call',
expression: {__symbolic: 'reference', module: 'angular2/core', name: 'Component'},
arguments: [{providers: [{__symbolic: 'reference', name: 'REQUIRED_VALIDATOR'}]}]
}]
}
});
});
});
// TODO: Do not use \` in a template literal as it confuses clang-format
@ -799,6 +822,22 @@ const FILES: Directory = {
export {Foo as OtherModule} from './static-field-reference.ts';
export * from 'angular2/core';
`,
'local-symbol-ref.ts': `
import {Component, Validators} from 'angular2/core';
const REQUIRED = Validators.required;
export const REQUIRED_VALIDATOR: any = {
provide: 'SomeToken',
useValue: REQUIRED,
multi: true
};
@Component({
providers: [REQUIRED_VALIDATOR]
})
export class SomeComponent {}
`,
'node_modules': {
'angular2': {
'core.d.ts': `
@ -849,6 +888,9 @@ const FILES: Directory = {
export interface OnInit {
ngOnInit(): any;
}
export class Validators {
static required(): void;
}
`,
'common.d.ts': `
export declare class NgFor {