refactor(core): remove unused embedded view instructions (#34715)

This commit performs a cleanup and removes unused embedded view instructions and corresponding tests.

PR Close #34715
This commit is contained in:
Andrew Kushnir
2020-01-09 17:50:29 -08:00
committed by Misko Hevery
parent ed1b4a8f19
commit 0c8adbc4ec
30 changed files with 447 additions and 3542 deletions

View File

@ -125,9 +125,6 @@ export {
ɵɵclassProp,
ɵɵComponentDefWithMeta,
ɵɵcomponentHostSyntheticListener,
ɵɵcontainer,
ɵɵcontainerRefreshEnd,
ɵɵcontainerRefreshStart,
ɵɵcontentQuery,
ɵɵCopyDefinitionFeature,
ɵɵdefineComponent,
@ -143,8 +140,6 @@ export {
ɵɵelementContainerStart,
ɵɵelementEnd,
ɵɵelementStart,
ɵɵembeddedViewEnd,
ɵɵembeddedViewStart,
ɵɵenableBindings,
ɵɵFactoryDef,
ɵɵgetCurrentView,

View File

@ -57,11 +57,6 @@ export function assertDataNext(lView: LView, index: number, arr?: any[]) {
arr.length, index, `index ${index} expected to be at the end of arr (length ${arr.length})`);
}
export function assertLContainerOrUndefined(value: any): asserts value is LContainer|undefined|
null {
value && assertEqual(isLContainer(value), true, 'Expecting LContainer or undefined or null');
}
export function assertLContainer(value: any): asserts value is LContainer {
assertDefined(value, 'LContainer must be defined');
assertEqual(isLContainer(value), true, 'Expecting LContainer');

View File

@ -50,23 +50,15 @@ export {
ɵɵclassProp,
ɵɵcomponentHostSyntheticListener,
ɵɵcontainer,
ɵɵcontainerRefreshEnd,
ɵɵcontainerRefreshStart,
ɵɵdirectiveInject,
ɵɵelement,
ɵɵelementContainer,
ɵɵelementContainerEnd,
ɵɵelementContainerStart,
ɵɵelementEnd,
ɵɵelementStart,
ɵɵembeddedViewEnd,
ɵɵembeddedViewStart,
ɵɵgetCurrentView,
ɵɵhostProperty,

View File

@ -33,7 +33,6 @@ export * from './storage';
export * from './di';
export * from './element';
export * from './element_container';
export * from './embedded_view';
export * from './get_current_view';
export * from './listener';
export * from './namespace';

View File

@ -5,46 +5,20 @@
* 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 {assertDataInRange, assertEqual} from '../../util/assert';
import {assertFirstCreatePass, assertHasParent} from '../assert';
import {assertFirstCreatePass} from '../assert';
import {attachPatchData} from '../context_discovery';
import {executeCheckHooks, executeInitAndCheckHooks, incrementInitPhaseFlags, registerPostOrderHooks} from '../hooks';
import {ACTIVE_INDEX, CONTAINER_HEADER_OFFSET, LContainer} from '../interfaces/container';
import {registerPostOrderHooks} from '../hooks';
import {ComponentTemplate} from '../interfaces/definition';
import {LocalRefExtractor, TAttributes, TContainerNode, TNode, TNodeType, TViewNode} from '../interfaces/node';
import {LocalRefExtractor, TAttributes, TContainerNode, TNodeType, TViewNode} from '../interfaces/node';
import {isDirectiveHost} from '../interfaces/type_checks';
import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, RENDERER, T_HOST, TView, TViewType} from '../interfaces/view';
import {assertNodeType} from '../node_assert';
import {appendChild, removeView} from '../node_manipulation';
import {getBindingIndex, getCheckNoChangesMode, getIsParent, getLView, getPreviousOrParentTNode, getTView, setIsNotParent, setPreviousOrParentTNode} from '../state';
import {getConstant, getLContainerActiveIndex, load} from '../util/view_utils';
import {HEADER_OFFSET, LView, RENDERER, T_HOST, TView, TViewType} from '../interfaces/view';
import {appendChild} from '../node_manipulation';
import {getLView, getTView, setPreviousOrParentTNode} from '../state';
import {getConstant} from '../util/view_utils';
import {addToViewTree, createDirectivesInstances, createLContainer, createTNode, createTView, getOrCreateTNode, resolveDirectives, saveResolvedLocalsInData} from './shared';
/**
* Creates an LContainer for inline views, e.g.
*
* % if (showing) {
* <div></div>
* % }
*
* @param index The index of the container in the data array
*
* @codeGenApi
*/
export function ɵɵcontainer(index: number): void {
const lView = getLView();
const tView = getTView();
const tNode = containerInternal(tView, lView, index, null, null);
if (tView.firstCreatePass) {
tNode.tViews = [];
}
setIsNotParent();
}
function templateFirstCreatePass(
index: number, tView: TView, lView: LView, templateFn: ComponentTemplate<any>|null,
decls: number, vars: number, tagName?: string|null, attrsIndex?: number|null,
@ -121,97 +95,4 @@ export function ɵɵtemplate(
if (localRefsIndex != null) {
saveResolvedLocalsInData(lView, tNode, localRefExtractor);
}
}
/**
* Sets a container up to receive views.
*
* @param index The index of the container in the data array
*
* @codeGenApi
*/
export function ɵɵcontainerRefreshStart(index: number): void {
const lView = getLView();
const tView = getTView();
let previousOrParentTNode = load(tView.data, index) as TNode;
ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Container);
setPreviousOrParentTNode(previousOrParentTNode, true);
lView[index + HEADER_OFFSET][ACTIVE_INDEX] = 0;
// We need to execute init hooks here so ngOnInit hooks are called in top level views
// before they are called in embedded views (for backwards compatibility).
if (!getCheckNoChangesMode()) {
const hooksInitPhaseCompleted =
(lView[FLAGS] & LViewFlags.InitPhaseStateMask) === InitPhaseState.InitPhaseCompleted;
if (hooksInitPhaseCompleted) {
const preOrderCheckHooks = tView.preOrderCheckHooks;
if (preOrderCheckHooks !== null) {
executeCheckHooks(lView, preOrderCheckHooks, null);
}
} else {
const preOrderHooks = tView.preOrderHooks;
if (preOrderHooks !== null) {
executeInitAndCheckHooks(lView, preOrderHooks, InitPhaseState.OnInitHooksToBeRun, null);
}
incrementInitPhaseFlags(lView, InitPhaseState.OnInitHooksToBeRun);
}
}
}
/**
* Marks the end of the LContainer.
*
* Marking the end of LContainer is the time when to child views get inserted or removed.
*
* @codeGenApi
*/
export function ɵɵcontainerRefreshEnd(): void {
let previousOrParentTNode = getPreviousOrParentTNode();
if (getIsParent()) {
setIsNotParent();
} else {
ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.View);
ngDevMode && assertHasParent(previousOrParentTNode);
previousOrParentTNode = previousOrParentTNode.parent!;
setPreviousOrParentTNode(previousOrParentTNode, false);
}
ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Container);
const lContainer: LContainer = getLView()[previousOrParentTNode.index];
const nextIndex = getLContainerActiveIndex(lContainer);
// remove extra views at the end of the container
while (nextIndex < lContainer.length - CONTAINER_HEADER_OFFSET) {
removeView(lContainer, nextIndex);
}
}
function containerInternal(
tView: TView, lView: LView, nodeIndex: number, tagName: string|null,
attrs: TAttributes|null): TContainerNode {
ngDevMode &&
assertEqual(
getBindingIndex(), tView.bindingStartIndex,
'container nodes should be created before any bindings');
const adjustedIndex = nodeIndex + HEADER_OFFSET;
ngDevMode && assertDataInRange(lView, nodeIndex + HEADER_OFFSET);
ngDevMode && ngDevMode.rendererCreateComment++;
const comment = lView[adjustedIndex] =
lView[RENDERER].createComment(ngDevMode ? 'container' : '');
const tNode =
getOrCreateTNode(tView, lView[T_HOST], nodeIndex, TNodeType.Container, tagName, attrs);
const lContainer = lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode);
appendChild(tView, lView, comment, tNode);
attachPatchData(comment, lView);
// Containers are added to the current view tree instead of their embedded views
// because views can be removed and re-inserted.
addToViewTree(lView, lContainer);
ngDevMode && assertNodeType(getPreviousOrParentTNode(), TNodeType.Container);
return tNode;
}

View File

@ -1,145 +0,0 @@
/**
* @license
* Copyright Google Inc. 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 {assertDefined, assertEqual} from '../../util/assert';
import {assertLContainerOrUndefined} from '../assert';
import {ACTIVE_INDEX, ActiveIndexFlag, CONTAINER_HEADER_OFFSET, LContainer} from '../interfaces/container';
import {RenderFlags} from '../interfaces/definition';
import {TContainerNode, TNodeType} from '../interfaces/node';
import {CONTEXT, LView, LViewFlags, PARENT, T_HOST, TVIEW, TView, TViewType} from '../interfaces/view';
import {assertNodeType} from '../node_assert';
import {insertView, removeView} from '../node_manipulation';
import {enterView, getIsParent, getLView, getPreviousOrParentTNode, getTView, leaveView, setIsParent, setPreviousOrParentTNode} from '../state';
import {getLContainerActiveIndex, isCreationMode} from '../util/view_utils';
import {assignTViewNodeToLView, createLView, createTView, refreshView, renderView} from './shared';
/**
* Marks the start of an embedded view.
*
* @param viewBlockId The ID of this view
* @return boolean Whether or not this view is in creation mode
*
* @codeGenApi
*/
export function ɵɵembeddedViewStart(viewBlockId: number, decls: number, vars: number): RenderFlags {
const lView = getLView();
const previousOrParentTNode = getPreviousOrParentTNode();
// The previous node can be a view node if we are processing an inline for loop
const containerTNode = previousOrParentTNode.type === TNodeType.View ?
previousOrParentTNode.parent! :
previousOrParentTNode;
const lContainer = lView[containerTNode.index] as LContainer;
ngDevMode && assertNodeType(containerTNode, TNodeType.Container);
let viewToRender = scanForView(lContainer, getLContainerActiveIndex(lContainer), viewBlockId);
if (viewToRender) {
setIsParent();
enterView(viewToRender, viewToRender[TVIEW].node);
} else {
// When we create a new LView, we always reset the state of the instructions.
viewToRender = createLView(
lView, getOrCreateEmbeddedTView(viewBlockId, decls, vars, containerTNode as TContainerNode),
null, LViewFlags.CheckAlways, null, null);
const tParentNode = getIsParent() ? previousOrParentTNode :
previousOrParentTNode && previousOrParentTNode.parent;
assignTViewNodeToLView(viewToRender[TVIEW], tParentNode, viewBlockId, viewToRender);
enterView(viewToRender, viewToRender[TVIEW].node);
}
if (lContainer) {
if (isCreationMode(viewToRender)) {
// it is a new view, insert it into collection of views for a given container
insertView(
viewToRender[TVIEW], viewToRender, lContainer, getLContainerActiveIndex(lContainer));
}
lContainer[ACTIVE_INDEX] += ActiveIndexFlag.INCREMENT;
}
return isCreationMode(viewToRender) ? RenderFlags.Create | RenderFlags.Update :
RenderFlags.Update;
}
/**
* Initialize the TView (e.g. static data) for the active embedded view.
*
* Each embedded view block must create or retrieve its own TView. Otherwise, the embedded view's
* static data for a particular node would overwrite the static data for a node in the view above
* it with the same index (since it's in the same template).
*
* @param viewIndex The index of the TView in TNode.tViews
* @param decls The number of nodes, local refs, and pipes in this template
* @param vars The number of bindings and pure function bindings in this template
* @param container The parent container in which to look for the view's static data
* @returns TView
*/
function getOrCreateEmbeddedTView(
viewIndex: number, decls: number, vars: number, parent: TContainerNode): TView {
const tView = getLView()[TVIEW];
ngDevMode && assertNodeType(parent, TNodeType.Container);
const containerTViews = parent.tViews as TView[];
ngDevMode && assertDefined(containerTViews, 'TView expected');
ngDevMode && assertEqual(Array.isArray(containerTViews), true, 'TViews should be in an array');
if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) {
containerTViews[viewIndex] = createTView(
TViewType.Embedded, viewIndex, null, decls, vars, tView.directiveRegistry,
tView.pipeRegistry, null, null, tView.consts);
}
return containerTViews[viewIndex];
}
/**
* Looks for a view with a given view block id inside a provided LContainer.
* Removes views that need to be deleted in the process.
*
* @param lContainer to search for views
* @param startIdx starting index in the views array to search from
* @param viewBlockId exact view block id to look for
*/
function scanForView(lContainer: LContainer, startIdx: number, viewBlockId: number): LView|null {
for (let i = startIdx + CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
const viewAtPositionId = lContainer[i][TVIEW].id;
if (viewAtPositionId === viewBlockId) {
return lContainer[i];
} else if (viewAtPositionId < viewBlockId) {
// found a view that should not be at this position - remove
removeView(lContainer, i - CONTAINER_HEADER_OFFSET);
} else {
// found a view with id greater than the one we are searching for
// which means that required view doesn't exist and can't be found at
// later positions in the views array - stop the searchdef.cont here
break;
}
}
return null;
}
/**
* Marks the end of an embedded view.
*
* @codeGenApi
*/
export function ɵɵembeddedViewEnd(): void {
const lView = getLView();
const tView = getTView();
const viewHost = lView[T_HOST];
const context = lView[CONTEXT];
if (isCreationMode(lView)) {
renderView(tView, lView, context); // creation mode pass
}
refreshView(tView, lView, tView.template, context); // update mode pass
const lContainer = lView[PARENT] as LContainer;
ngDevMode && assertLContainerOrUndefined(lContainer);
leaveView();
setPreviousOrParentTNode(viewHost!, false);
}

View File

@ -20,6 +20,7 @@ import {HOST, LView, NEXT, PARENT, T_HOST, TRANSPLANTED_VIEWS_TO_REFRESH} from '
* `LContainer`.
*/
export const TYPE = 1;
/**
* Below are constants for LContainer indices to help us look up LContainer members
* without having to remember the specific indices.
@ -48,9 +49,7 @@ export const CONTAINER_HEADER_OFFSET = 10;
/**
* Used to track:
* - Inline embedded views (see: `ɵɵembeddedViewStart`)
* - Transplanted `LView`s (see: `LView[DECLARATION_COMPONENT_VIEW])`
* Used to track Transplanted `LView`s (see: `LView[DECLARATION_COMPONENT_VIEW])`
*/
export const enum ActiveIndexFlag {
/**
@ -72,13 +71,6 @@ export const enum ActiveIndexFlag {
* Number of bits to shift inline embedded views counter to make space for other flags.
*/
SHIFT = 1,
/**
* When incrementing the active index for inline embedded views, the amount to increment to leave
* space for other flags.
*/
INCREMENT = 1 << SHIFT,
}
/**
@ -111,10 +103,6 @@ export interface LContainer extends Array<any> {
* it is set to null to identify this scenario, as indices are "absolute" in that case,
* i.e. provided directly by the user of the ViewContainerRef API.
*
* This is used by `ɵɵembeddedViewStart` to track which `LView` is currently active.
* Because `ɵɵembeddedViewStart` is not generated by the compiler this feature is essentially
* unused.
*
* The lowest bit signals that this `LContainer` has transplanted views which need to be change
* detected as part of the declaration CD. (See `LView[DECLARATION_COMPONENT_VIEW]`)
*/

View File

@ -49,10 +49,7 @@ export const angularCoreEnv: {[name: string]: Function} =
'ɵɵProvidersFeature': r3.ɵɵProvidersFeature,
'ɵɵCopyDefinitionFeature': r3.ɵɵCopyDefinitionFeature,
'ɵɵInheritDefinitionFeature': r3.ɵɵInheritDefinitionFeature,
'ɵɵcontainer': r3.ɵɵcontainer,
'ɵɵnextContext': r3.ɵɵnextContext,
'ɵɵcontainerRefreshStart': r3.ɵɵcontainerRefreshStart,
'ɵɵcontainerRefreshEnd': r3.ɵɵcontainerRefreshEnd,
'ɵɵnamespaceHTML': r3.ɵɵnamespaceHTML,
'ɵɵnamespaceMathML': r3.ɵɵnamespaceMathML,
'ɵɵnamespaceSVG': r3.ɵɵnamespaceSVG,
@ -152,8 +149,6 @@ export const angularCoreEnv: {[name: string]: Function} =
'ɵɵtextInterpolate7': r3.ɵɵtextInterpolate7,
'ɵɵtextInterpolate8': r3.ɵɵtextInterpolate8,
'ɵɵtextInterpolateV': r3.ɵɵtextInterpolateV,
'ɵɵembeddedViewStart': r3.ɵɵembeddedViewStart,
'ɵɵembeddedViewEnd': r3.ɵɵembeddedViewEnd,
'ɵɵi18n': r3.ɵɵi18n,
'ɵɵi18nAttributes': r3.ɵɵi18nAttributes,
'ɵɵi18nExp': r3.ɵɵi18nExp,