Skip to content

Commit ed67a07

Browse files
JoostKAndrewKushnir
authored andcommitted
fix(compiler): properly compile DI factories when coverage reporting is enabled (#44732)
When running tests with code coverage using Istanbul, the code is instrumented with coverage reporting statements. These statements are also inserted into synthesized constructors, preventing Angular from properly recognizing them as synthesized constructor. This commit changes the regex to detect synthesized constructors to allow for statements within the constructor before the `super(...arguments);` call. This is limited to code that does not contain a `}`, but this is sufficient to support Istanbul's coverage instrumentation statements. The tests have been extended with an input file that is being instrumented using `babel-plugin-istanbul` for both ES2015 and ES5 targets, in order to verify that the approach works for real-world usages. Fixes #31337 PR Close #44732
1 parent 43eb934 commit ed67a07

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

packages/core/src/reflection/reflection_capabilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const ES2015_INHERITED_CLASS_WITH_CTOR =
6363
* and inherit a constructor.
6464
*/
6565
export const ES2015_INHERITED_CLASS_WITH_DELEGATE_CTOR =
66-
/^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{\s*super\(\.\.\.arguments\)/;
66+
/^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{[^}]*super\(\.\.\.arguments\)/;
6767

6868
/**
6969
* Determine whether a stringified type is a class which delegates its constructor

packages/core/test/reflection/reflector_spec.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,13 +292,59 @@ class TestObj {
292292
expect(isDelegateCtor(ChildWithCtorComplexBase)).toBe(false);
293293
});
294294

295+
it('should deal with coverage instrumentation statements', () => {
296+
// The Istanbul coverage tool augments code with additional statements to capture coverage
297+
// information, and this test verifies that those do not interfere with our ability to
298+
// detect delegate constructors.
299+
const Es2015ClassNoCtor = `class TestService extends Parent {
300+
constructor() {
301+
cov_8nt6qq5zt().f[2]++;
302+
cov_8nt6qq5zt().s[6]++;
303+
super(...arguments);
304+
cov_8nt6qq5zt().s[7]++;
305+
this.foo = 'bar';
306+
}
307+
}`;
308+
const Es2015ClassWithCtor = `class TestService extends Parent {
309+
constructor() {
310+
cov_8nt6qq5zt().f[2]++;
311+
cov_8nt6qq5zt().s[6]++;
312+
super();
313+
cov_8nt6qq5zt().s[7]++;
314+
this.foo = 'bar';
315+
}
316+
}`;
317+
const Es5ClassNoCtor = `function TestService() {
318+
cov_8nt6qq5zt().f[4]++;
319+
var _this = (cov_8nt6qq5zt().s[8]++, (cov_8nt6qq5zt().b[0][0]++, _super !== null) && (cov_8nt6qq5zt().b[0][1]++, _super.apply(this, arguments)) || (cov_8nt6qq5zt().b[0][2]++, this));
320+
cov_8nt6qq5zt().s[9]++;
321+
_this.foo = 'bar';
322+
cov_8nt6qq5zt().s[10]++;
323+
return _this;
324+
}`;
325+
const Es5ClassWithCtor = `function TestService() {
326+
cov_8nt6qq5zt().f[4]++;
327+
var _this = _super.call();
328+
cov_8nt6qq5zt().s[9]++;
329+
_this.foo = 'bar';
330+
cov_8nt6qq5zt().s[10]++;
331+
return _this;
332+
}`;
333+
334+
expect(isDelegateCtor(Es2015ClassNoCtor)).toBe(true);
335+
expect(isDelegateCtor(Es2015ClassWithCtor)).toBe(false);
336+
expect(isDelegateCtor(Es5ClassNoCtor)).toBe(true);
337+
expect(isDelegateCtor(Es5ClassWithCtor)).toBe(false);
338+
});
339+
295340
it('should properly handle all class forms', () => {
296341
const ctor = (str: string) => expect(isDelegateCtor(str)).toBe(false);
297342
const noCtor = (str: string) => expect(isDelegateCtor(str)).toBe(true);
298343

299344
ctor(`class Bar extends Foo {constructor(){}}`);
300345
ctor(`class Bar extends Foo { constructor ( ) {} }`);
301346
ctor(`class Bar extends Foo { other(){}; constructor(){} }`);
347+
ctor(`class Bar extends Foo { constructor(){} a(){super(...arguments)} }`);
302348

303349
noCtor(`class extends Foo{}`);
304350
noCtor(`class extends Foo {}`);

0 commit comments

Comments
 (0)