Skip to content

Commit d4343b5

Browse files
committed
Revert "fix(compiler-cli): identify aliased initializer functions (#54480)" (#54595)
This reverts commit f04ecc0. PR Close #54595
1 parent dcb9deb commit d4343b5

26 files changed

Lines changed: 129 additions & 560 deletions

packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import ts from 'typescript';
1212
import {Cycle, CycleAnalyzer, CycleHandlingStrategy} from '../../../cycles';
1313
import {ErrorCode, FatalDiagnosticError, makeDiagnostic, makeRelatedInformation} from '../../../diagnostics';
1414
import {absoluteFrom, relative} from '../../../file_system';
15-
import {assertSuccessfulReferenceEmit, DeferredSymbolTracker, ImportedFile, ImportedSymbolsTracker, LocalCompilationExtraImportsTracker, ModuleResolver, Reference, ReferenceEmitter} from '../../../imports';
15+
import {assertSuccessfulReferenceEmit, DeferredSymbolTracker, ImportedFile, LocalCompilationExtraImportsTracker, ModuleResolver, Reference, ReferenceEmitter} from '../../../imports';
1616
import {DependencyTracker} from '../../../incremental/api';
1717
import {extractSemanticTypeParameters, SemanticDepGraphUpdater} from '../../../incremental/semantic_graph';
1818
import {IndexingContext} from '../../../indexer';
@@ -83,8 +83,7 @@ export class ComponentDecoratorHandler implements
8383
private injectableRegistry: InjectableClassRegistry,
8484
private semanticDepGraphUpdater: SemanticDepGraphUpdater|null,
8585
private annotateForClosureCompiler: boolean, private perf: PerfRecorder,
86-
private hostDirectivesResolver: HostDirectivesResolver,
87-
private importTracker: ImportedSymbolsTracker, private includeClassMetadata: boolean,
86+
private hostDirectivesResolver: HostDirectivesResolver, private includeClassMetadata: boolean,
8887
private readonly compilationMode: CompilationMode,
8988
private readonly deferredSymbolTracker: DeferredSymbolTracker,
9089
private readonly forbidOrphanRendering: boolean, private readonly enableBlockSyntax: boolean,
@@ -226,8 +225,8 @@ export class ComponentDecoratorHandler implements
226225
// @Component inherits @Directive, so begin by extracting the @Directive metadata and building
227226
// on it.
228227
const directiveResult = extractDirectiveMetadata(
229-
node, decorator, this.reflector, this.importTracker, this.evaluator, this.refEmitter,
230-
this.referencesRegistry, this.isCore, this.annotateForClosureCompiler, this.compilationMode,
228+
node, decorator, this.reflector, this.evaluator, this.refEmitter, this.referencesRegistry,
229+
this.isCore, this.annotateForClosureCompiler, this.compilationMode,
231230
this.elementSchemaRegistry.getDefaultComponentElementName(), this.useTemplatePipeline);
232231
if (directiveResult === undefined) {
233232
// `extractDirectiveMetadata` returns undefined when the @Directive has `jit: true`. In this

packages/compiler-cli/src/ngtsc/annotations/component/test/component_spec.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {CycleAnalyzer, CycleHandlingStrategy, ImportGraph} from '../../../cycles
1313
import {ErrorCode, FatalDiagnosticError, ngErrorCode} from '../../../diagnostics';
1414
import {absoluteFrom} from '../../../file_system';
1515
import {runInEachFileSystem} from '../../../file_system/testing';
16-
import {DeferredSymbolTracker, ImportedSymbolsTracker, ModuleResolver, Reference, ReferenceEmitter} from '../../../imports';
16+
import {DeferredSymbolTracker, ModuleResolver, Reference, ReferenceEmitter} from '../../../imports';
1717
import {CompoundMetadataReader, DtsMetadataReader, HostDirectivesResolver, LocalMetadataRegistry, ResourceRegistry} from '../../../metadata';
1818
import {PartialEvaluator} from '../../../partial_evaluator';
1919
import {NOOP_PERF_RECORDER} from '../../../perf';
@@ -68,7 +68,6 @@ function setup(
6868
const typeCheckScopeRegistry =
6969
new TypeCheckScopeRegistry(scopeRegistry, metaReader, hostDirectivesResolver);
7070
const resourceLoader = new StubResourceLoader();
71-
const importTracker = new ImportedSymbolsTracker();
7271

7372
const handler = new ComponentDecoratorHandler(
7473
reflectionHost,
@@ -100,7 +99,6 @@ function setup(
10099
/* annotateForClosureCompiler */ false,
101100
NOOP_PERF_RECORDER,
102101
hostDirectivesResolver,
103-
importTracker,
104102
true,
105103
compilationMode,
106104
new DeferredSymbolTracker(checker, /* onlyExplicitDeferDependencyImports */ false),

packages/compiler-cli/src/ngtsc/annotations/directive/src/handler.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import {compileClassMetadata, compileDeclareClassMetadata, compileDeclareDirectiveFromMetadata, compileDirectiveFromMetadata, ConstantPool, FactoryTarget, makeBindingParser, R3ClassMetadata, R3DirectiveMetadata, WrappedNodeExpr} from '@angular/compiler';
1010
import ts from 'typescript';
1111

12-
import {ImportedSymbolsTracker, Reference, ReferenceEmitter} from '../../../imports';
12+
import {Reference, ReferenceEmitter} from '../../../imports';
1313
import {extractSemanticTypeParameters, SemanticDepGraphUpdater} from '../../../incremental/semantic_graph';
1414
import {ClassPropertyMapping, DirectiveTypeCheckMeta, extractDirectiveTypeCheckMeta, HostDirectiveMeta, InputMapping, MatchSource, MetadataReader, MetadataRegistry, MetaKind} from '../../../metadata';
1515
import {PartialEvaluator} from '../../../partial_evaluator';
@@ -62,7 +62,6 @@ export class DirectiveDecoratorHandler implements
6262
private semanticDepGraphUpdater: SemanticDepGraphUpdater|null,
6363
private annotateForClosureCompiler: boolean,
6464
private perf: PerfRecorder,
65-
private importTracker: ImportedSymbolsTracker,
6665
private includeClassMetadata: boolean,
6766
private readonly compilationMode: CompilationMode,
6867
private readonly useTemplatePipeline: boolean,
@@ -105,8 +104,8 @@ export class DirectiveDecoratorHandler implements
105104
this.perf.eventCount(PerfEvent.AnalyzeDirective);
106105

107106
const directiveResult = extractDirectiveMetadata(
108-
node, decorator, this.reflector, this.importTracker, this.evaluator, this.refEmitter,
109-
this.referencesRegistry, this.isCore, this.annotateForClosureCompiler, this.compilationMode,
107+
node, decorator, this.reflector, this.evaluator, this.refEmitter, this.referencesRegistry,
108+
this.isCore, this.annotateForClosureCompiler, this.compilationMode,
110109
/* defaultSelector */ null, this.useTemplatePipeline);
111110
if (directiveResult === undefined) {
112111
return {};

packages/compiler-cli/src/ngtsc/annotations/directive/src/initializer_functions.ts

Lines changed: 66 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import ts from 'typescript';
1010

11-
import {ImportedSymbolsTracker} from '../../../imports';
1211
import {ClassMember, ReflectionHost} from '../../../reflection';
1312
import {CORE_MODULE} from '../../common';
1413

@@ -40,18 +39,6 @@ interface InitializerFunctionMetadata {
4039
isRequired: boolean;
4140
}
4241

43-
/**
44-
* Metadata that can be inferred from an initializer
45-
* statically without going through the type checker.
46-
*/
47-
interface StaticInitializerData {
48-
/** Identifier in the initializer that refers to the Angular API. */
49-
node: ts.Identifier;
50-
51-
/** Whether the call is required. */
52-
isRequired: boolean;
53-
}
54-
5542
/**
5643
* Attempts to identify an Angular class member that is declared via
5744
* its initializer referring to a given initializer API function.
@@ -61,110 +48,97 @@ interface StaticInitializerData {
6148
*/
6249
export function tryParseInitializerApiMember<FnNames extends InitializerApiFunction[]>(
6350
fnNames: FnNames, member: Pick<ClassMember, 'value'>, reflector: ReflectionHost,
64-
importTracker: ImportedSymbolsTracker): InitializerFunctionMetadata|null {
51+
isCore: boolean): InitializerFunctionMetadata&{apiName: FnNames[number]}|null {
6552
if (member.value === null || !ts.isCallExpression(member.value)) {
6653
return null;
6754
}
68-
6955
const call = member.value;
70-
const staticResult = parseTopLevelCall(call, fnNames, importTracker) ||
71-
parseTopLevelRequiredCall(call, fnNames, importTracker) ||
72-
parseTopLevelCallFromNamespace(call, fnNames, importTracker);
7356

74-
if (staticResult === null) {
57+
// Extract target. Either:
58+
// - `[input]`
59+
// - `core.[input]`
60+
// - `input.[required]`
61+
// - `core.input.[required]`.
62+
let target = extractPropertyTarget(call.expression);
63+
if (target === null) {
7564
return null;
7665
}
7766

78-
// Once we've statically determined that the initializer is one of the APIs we're looking for, we
79-
// need to verify it using the type checker which accounts for things like shadowed variables.
80-
// This should be done as the absolute last step since using the type check can be expensive.
81-
const resolvedImport = reflector.getImportOfIdentifier(staticResult.node);
82-
if (resolvedImport === null || !(fnNames as string[]).includes(resolvedImport.name)) {
67+
// Find if the `target` matches one of the expected APIs we are looking for.
68+
// e.g. `input`, or `viewChild`.
69+
let apiName = fnNames.find(n => n === target!.text);
70+
71+
// Case 1: API is directly called. e.g. `input`
72+
// If no API name was matched, continue looking for `input.required`.
73+
if (apiName !== undefined) {
74+
if (!isReferenceToInitializerApiFunction(apiName, target, isCore, reflector)) {
75+
return null;
76+
}
77+
return {apiName, call, isRequired: false};
78+
}
79+
80+
// Case 2: API is the `.required`
81+
// Ensure there is a property access to `[input].required` or `[core.input].required`.
82+
if (target.text !== 'required' || !ts.isPropertyAccessExpression(call.expression)) {
8383
return null;
8484
}
8585

86-
return {
87-
call,
88-
isRequired: staticResult.isRequired,
89-
apiName: resolvedImport.name as InitializerApiFunction,
90-
};
91-
}
86+
// e.g. `[input.required]` (the full property access is this)
87+
const apiPropertyAccess = call.expression;
88+
// e.g. `[input].required` (we now extract the left side of the access).
89+
target = extractPropertyTarget(apiPropertyAccess.expression);
90+
if (target === null) {
91+
return null;
92+
}
9293

93-
/**
94-
* Attempts to parse a top-level call to an initializer function,
95-
* e.g. `prop = input()`. Returns null if it can't be parsed.
96-
*/
97-
function parseTopLevelCall(
98-
call: ts.CallExpression, fnNames: InitializerApiFunction[],
99-
importTracker: ImportedSymbolsTracker): StaticInitializerData|null {
100-
const node = call.expression;
94+
// Find if the `target` matches one of the expected APIs are are looking for.
95+
apiName = fnNames.find(n => n === target!.text);
10196

102-
if (!ts.isIdentifier(node)) {
97+
// Ensure the call refers to the real API function from Angular core.
98+
if (apiName === undefined ||
99+
!isReferenceToInitializerApiFunction(apiName, target, isCore, reflector)) {
103100
return null;
104101
}
105102

106-
return fnNames.some(
107-
name => importTracker.isPotentialReferenceToNamedImport(node, name, CORE_MODULE)) ?
108-
{node, isRequired: false} :
109-
null;
103+
return {
104+
apiName,
105+
call,
106+
isRequired: true,
107+
};
110108
}
111109

112110
/**
113-
* Attempts to parse a top-level call to a required initializer,
114-
* e.g. `prop = input.required()`. Returns null if it can't be parsed.
111+
* Extracts the identifier property target of a expression, supporting
112+
* one level deep property accesses.
113+
*
114+
* e.g. `input.required` will return `required`.
115+
* e.g. `input` will return `input`.
116+
*
115117
*/
116-
function parseTopLevelRequiredCall(
117-
call: ts.CallExpression, fnNames: InitializerApiFunction[],
118-
importTracker: ImportedSymbolsTracker): StaticInitializerData|null {
119-
const node = call.expression;
120-
121-
if (!ts.isPropertyAccessExpression(node) || !ts.isIdentifier(node.expression) ||
122-
node.name.text !== 'required') {
123-
return null;
118+
function extractPropertyTarget(node: ts.Expression): ts.Identifier|null {
119+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name)) {
120+
return node.name;
121+
} else if (ts.isIdentifier(node)) {
122+
return node;
124123
}
125-
126-
const expression = node.expression;
127-
const matchesCoreApi = fnNames.some(
128-
name => importTracker.isPotentialReferenceToNamedImport(expression, name, CORE_MODULE));
129-
130-
return matchesCoreApi ? {node: expression, isRequired: true} : null;
124+
return null;
131125
}
132126

133-
134127
/**
135-
* Attempts to parse a top-level call to a function referenced via a namespace import,
136-
* e.g. `prop = core.input.required()`. Returns null if it can't be parsed.
128+
* Verifies that the given identifier resolves to the given initializer API
129+
* function expression from Angular core.
137130
*/
138-
function parseTopLevelCallFromNamespace(
139-
call: ts.CallExpression, fnNames: InitializerApiFunction[],
140-
importTracker: ImportedSymbolsTracker): StaticInitializerData|null {
141-
const node = call.expression;
142-
143-
if (!ts.isPropertyAccessExpression(node)) {
144-
return null;
145-
}
146-
147-
let apiReference: ts.Identifier|null = null;
148-
let isRequired = false;
149-
150-
// `prop = core.input()`
151-
if (ts.isIdentifier(node.expression) && ts.isIdentifier(node.name) &&
152-
importTracker.isPotentialReferenceToNamespaceImport(node.expression, CORE_MODULE)) {
153-
apiReference = node.name;
154-
} else if (
155-
// `prop = core.input.required()`
156-
ts.isPropertyAccessExpression(node.expression) &&
157-
ts.isIdentifier(node.expression.expression) && ts.isIdentifier(node.expression.name) &&
158-
importTracker.isPotentialReferenceToNamespaceImport(
159-
node.expression.expression, CORE_MODULE) &&
160-
node.name.text === 'required') {
161-
apiReference = node.expression.name;
162-
isRequired = true;
163-
}
164-
165-
if (apiReference === null || !(fnNames as string[]).includes(apiReference.text)) {
166-
return null;
131+
function isReferenceToInitializerApiFunction(
132+
functionName: InitializerApiFunction, target: ts.Identifier, isCore: boolean,
133+
reflector: ReflectionHost): boolean {
134+
let targetImport: {name: string, from: string}|null = reflector.getImportOfIdentifier(target);
135+
if (targetImport === null) {
136+
if (!isCore) {
137+
return false;
138+
}
139+
// We are compiling the core module, where no import can be present.
140+
targetImport = {name: target.text, from: CORE_MODULE};
167141
}
168142

169-
return {node: apiReference, isRequired};
143+
return targetImport.name === functionName && targetImport.from === CORE_MODULE;
170144
}

packages/compiler-cli/src/ngtsc/annotations/directive/src/input_function.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99
import ts from 'typescript';
1010

11-
import {ImportedSymbolsTracker} from '../../../imports';
11+
import {ErrorCode, FatalDiagnosticError} from '../../../diagnostics';
1212
import {InputMapping} from '../../../metadata';
13-
import {ClassMember, ReflectionHost} from '../../../reflection';
13+
import {ClassMember, ReflectionHost, reflectObjectLiteral} from '../../../reflection';
1414

1515
import {tryParseInitializerApiMember} from './initializer_functions';
1616
import {parseAndValidateInputAndOutputOptions} from './input_output_parse_options';
@@ -21,8 +21,8 @@ import {parseAndValidateInputAndOutputOptions} from './input_output_parse_option
2121
*/
2222
export function tryParseSignalInputMapping(
2323
member: Pick<ClassMember, 'name'|'value'>, reflector: ReflectionHost,
24-
importTracker: ImportedSymbolsTracker): InputMapping|null {
25-
const signalInput = tryParseInitializerApiMember(['input'], member, reflector, importTracker);
24+
isCore: boolean): InputMapping|null {
25+
const signalInput = tryParseInitializerApiMember(['input'], member, reflector, isCore);
2626
if (signalInput === null) {
2727
return null;
2828
}

packages/compiler-cli/src/ngtsc/annotations/directive/src/model_function.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import ts from 'typescript';
1010

11-
import {ImportedSymbolsTracker} from '../../../imports';
1211
import {ModelMapping} from '../../../metadata';
1312
import {ClassMember, ReflectionHost} from '../../../reflection';
1413

@@ -20,8 +19,8 @@ import {parseAndValidateInputAndOutputOptions} from './input_output_parse_option
2019
*/
2120
export function tryParseSignalModelMapping(
2221
member: Pick<ClassMember, 'name'|'value'>, reflector: ReflectionHost,
23-
importTracker: ImportedSymbolsTracker): ModelMapping|null {
24-
const model = tryParseInitializerApiMember(['model'], member, reflector, importTracker);
22+
isCore: boolean): ModelMapping|null {
23+
const model = tryParseInitializerApiMember(['model'], member, reflector, isCore);
2524
if (model === null) {
2625
return null;
2726
}

packages/compiler-cli/src/ngtsc/annotations/directive/src/output_function.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import ts from 'typescript';
1010

1111
import {ErrorCode, FatalDiagnosticError} from '../../../diagnostics';
12-
import {ImportedSymbolsTracker} from '../../../imports';
1312
import {InputOrOutput} from '../../../metadata';
1413
import {ClassMember, ReflectionHost} from '../../../reflection';
1514

@@ -22,10 +21,8 @@ import {parseAndValidateInputAndOutputOptions} from './input_output_parse_option
2221
*/
2322
export function tryParseInitializerBasedOutput(
2423
member: Pick<ClassMember, 'name'|'value'>, reflector: ReflectionHost,
25-
importTracker: ImportedSymbolsTracker): {call: ts.CallExpression, metadata: InputOrOutput}|
26-
null {
27-
const output =
28-
tryParseInitializerApiMember(['output', 'ɵoutput'], member, reflector, importTracker);
24+
isCore: boolean): {call: ts.CallExpression, metadata: InputOrOutput}|null {
25+
const output = tryParseInitializerApiMember(['output', 'ɵoutput'], member, reflector, isCore);
2926
if (output === null) {
3027
return null;
3128
}

packages/compiler-cli/src/ngtsc/annotations/directive/src/query_functions.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {createMayBeForwardRefExpression, ForwardRefHandling, MaybeForwardRefExpr
1111
import ts from 'typescript';
1212

1313
import {ErrorCode, FatalDiagnosticError} from '../../../diagnostics';
14-
import {ImportedSymbolsTracker} from '../../../imports';
1514
import {ClassMember, ReflectionHost, reflectObjectLiteral} from '../../../reflection';
1615
import {tryUnwrapForwardRef} from '../../common';
1716

@@ -36,10 +35,9 @@ const defaultDescendantsValue = (type: QueryFunctionName) => type !== 'contentCh
3635
* @returns Resolved query metadata, or null if no query is declared.
3736
*/
3837
export function tryParseSignalQueryFromInitializer(
39-
member: Pick<ClassMember, 'name'|'value'>, reflector: ReflectionHost,
40-
importTracker: ImportedSymbolsTracker):
38+
member: Pick<ClassMember, 'name'|'value'>, reflector: ReflectionHost, isCore: boolean):
4139
{name: QueryFunctionName, metadata: R3QueryMetadata, call: ts.CallExpression}|null {
42-
const query = tryParseInitializerApiMember(queryFunctionNames, member, reflector, importTracker);
40+
const query = tryParseInitializerApiMember(queryFunctionNames, member, reflector, isCore);
4341
if (query === null) {
4442
return null;
4543
}
@@ -60,10 +58,10 @@ export function tryParseSignalQueryFromInitializer(
6058
const read = options?.has('read') ? parseReadOption(options.get('read')!) : null;
6159
const descendants = options?.has('descendants') ?
6260
parseDescendantsOption(options.get('descendants')!) :
63-
defaultDescendantsValue(query.apiName as QueryFunctionName);
61+
defaultDescendantsValue(query.apiName);
6462

6563
return {
66-
name: query.apiName as QueryFunctionName,
64+
name: query.apiName,
6765
call: query.call,
6866
metadata: {
6967
isSignal: true,

0 commit comments

Comments
 (0)