-
Notifications
You must be signed in to change notification settings - Fork 25.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(compiler-cli): exclude abstract classes from `strictInjectionPar…
…ameters` requirement (#44615) In AOT compilations, the `strictInjectionParameters` compiler option can be enabled to report errors when an `@Injectable` annotated class has a constructor with parameters that do not provide an injection token, e.g. only a primitive type or interface. Since Ivy it's become required that any class with Angular behavior (e.g. the `ngOnDestroy` lifecycle hook) is decorated using an Angular decorator, which meant that `@Injectable()` may need to have been added to abstract base classes. Doing so would then report an error if `strictInjectionParameters` is enabled, if the abstract class has an incompatible constructor for DI purposes. This may be fine though, as a subclass may call the constructor explicitly without relying on Angular's DI mechanism. Therefore, this commit excludes abstract classes from the `strictInjectionParameters` check. This avoids an error from being reported at compile time. If the constructor ends up being used by Angular's DI system at runtime, then the factory function of the abstract class will throw an error by means of the `ɵɵinvalidFactory` instruction. In addition to the runtime error, this commit also analyzes the inheritance chain of an injectable without a constructor to verify that their inherited constructor is valid. Closes #37914 PR Close #44615
- Loading branch information
Showing
23 changed files
with
632 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
packages/compiler-cli/src/ngtsc/annotations/common/src/injectable_registry.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
import {R3DependencyMetadata} from '@angular/compiler'; | ||
|
||
import {hasInjectableFields} from '../../../metadata'; | ||
import {ClassDeclaration, ReflectionHost} from '../../../reflection'; | ||
|
||
import {getConstructorDependencies, unwrapConstructorDependencies} from './di'; | ||
|
||
|
||
export interface InjectableMeta { | ||
ctorDeps: R3DependencyMetadata[]|'invalid'|null; | ||
} | ||
|
||
/** | ||
* Registry that keeps track of classes that can be constructed via dependency injection (e.g. | ||
* injectables, directives, pipes). | ||
*/ | ||
export class InjectableClassRegistry { | ||
private classes = new Map<ClassDeclaration, InjectableMeta>(); | ||
|
||
constructor(private host: ReflectionHost, private isCore: boolean) {} | ||
|
||
registerInjectable(declaration: ClassDeclaration, meta: InjectableMeta): void { | ||
this.classes.set(declaration, meta); | ||
} | ||
|
||
getInjectableMeta(declaration: ClassDeclaration): InjectableMeta|null { | ||
// Figure out whether the class is injectable based on the registered classes, otherwise | ||
// fall back to looking at its members since we might not have been able to register the class | ||
// if it was compiled in another compilation unit. | ||
if (this.classes.has(declaration)) { | ||
return this.classes.get(declaration)!; | ||
} | ||
|
||
if (!hasInjectableFields(declaration, this.host)) { | ||
return null; | ||
} | ||
|
||
const ctorDeps = getConstructorDependencies(declaration, this.host, this.isCore); | ||
return { | ||
ctorDeps: unwrapConstructorDependencies(ctorDeps), | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.