Skip to content

Commit

Permalink
fix(compiler): report errors properly in G3 in certain conditions (#2…
Browse files Browse the repository at this point in the history
…0041)

Condition: static analysis error, given:
- noResolve:true
- generateCodeForLibraries: false
- CompilerHost.getSourceFile throws on non existent files

All of these are true in G3.
PR Close #20041
  • Loading branch information
tbosch authored and matsko committed Oct 31, 2017
1 parent 951bd33 commit 54480f7
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 25 deletions.
4 changes: 2 additions & 2 deletions packages/compiler-cli/src/transformers/program.ts
Expand Up @@ -456,13 +456,13 @@ class AngularCompilerProgram implements Program {
};


let rootNames = this.rootNames;
let rootNames = [...this.rootNames];
if (this.options.generateCodeForLibraries !== false) {
// if we should generateCodeForLibraries, never include
// generated files in the program as otherwise we will
// ovewrite them and typescript will report the error
// TS5055: Cannot write file ... because it would overwrite input file.
rootNames = this.rootNames.filter(fn => !GENERATED_FILES.test(fn));
rootNames = rootNames.filter(fn => !GENERATED_FILES.test(fn));
}
if (this.options.noResolve) {
this.rootNames.forEach(rootName => {
Expand Down
67 changes: 44 additions & 23 deletions packages/compiler-cli/test/transformers/program_spec.ts
Expand Up @@ -78,6 +78,15 @@ describe('ng program', () => {
return {emitResult, program};
}

function resolveFiles(rootNames: string[]) {
const preOptions = testSupport.createCompilerOptions();
const preHost = ts.createCompilerHost(preOptions);
// don't resolve symlinks
preHost.realpath = (f) => f;
const preProgram = ts.createProgram(rootNames, preOptions, preHost);
return preProgram.getSourceFiles().map(sf => sf.fileName);
}

describe('reuse of old program', () => {
it('should reuse generated code for libraries from old programs', () => {
compileLib('lib');
Expand Down Expand Up @@ -373,13 +382,7 @@ describe('ng program', () => {
testSupport.writeFiles({
'src/main.ts': createModuleAndCompSource('main'),
});
const preOptions = testSupport.createCompilerOptions();
const preHost = ts.createCompilerHost(preOptions);
// don't resolve symlinks
preHost.realpath = (f) => f;
const preProgram =
ts.createProgram([path.resolve(testSupport.basePath, 'src/main.ts')], preOptions, preHost);
const allRootNames = preProgram.getSourceFiles().map(sf => sf.fileName);
const allRootNames = resolveFiles([path.resolve(testSupport.basePath, 'src/main.ts')]);

// now do the actual test with noResolve
const program = compile(undefined, {noResolve: true}, allRootNames);
Expand Down Expand Up @@ -932,23 +935,41 @@ describe('ng program', () => {
});
});

it('should be able to use a program with structural errors as oldProgram', () => {
testSupport.write('src/index.ts', fileWithStructuralError);
it('should be able report structural errors with noResolve:true and generateCodeForLibraries:false ' +
'even if getSourceFile throws for non existent files',
() => {
testSupport.write('src/index.ts', fileWithGoodContent);

const options = testSupport.createCompilerOptions();
const host = ng.createCompilerHost({options});
const program1 = ng.createProgram(
{rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')], options, host});
expect(program1.getNgStructuralDiagnostics().length).toBe(1);
// compile angular and produce .ngsummary.json / ngfactory.d.ts files
compile();

testSupport.write('src/index.ts', fileWithGoodContent);
const program2 = ng.createProgram({
rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')],
options,
host,
oldProgram: program1
});
expectNoDiagnosticsInProgram(options, program2);
});
testSupport.write('src/ok.ts', fileWithGoodContent);
testSupport.write('src/error.ts', fileWithStructuralError);

// Make sure the ok.ts file is before the error.ts file,
// so we added a .ngfactory.ts file for it.
const allRootNames = resolveFiles(
['src/ok.ts', 'src/error.ts'].map(fn => path.resolve(testSupport.basePath, fn)));

const options = testSupport.createCompilerOptions({
noResolve: true,
generateCodeForLibraries: false,
});
const host = ng.createCompilerHost({options});
const originalGetSourceFile = host.getSourceFile;
host.getSourceFile =
(fileName: string, languageVersion: ts.ScriptTarget,
onError?: ((message: string) => void) | undefined): ts.SourceFile => {
// We should never try to load .ngfactory.ts files
if (fileName.match(/\.ngfactory\.ts$/)) {
throw new Error(`Non existent ngfactory file: ` + fileName);
}
return originalGetSourceFile.call(host, fileName, languageVersion, onError);
};
const program = ng.createProgram({rootNames: allRootNames, options, host});
const structuralErrors = program.getNgStructuralDiagnostics();
expect(structuralErrors.length).toBe(1);
expect(structuralErrors[0].messageText).toContain('Function calls are not supported.');
});
});
});

0 comments on commit 54480f7

Please sign in to comment.