Skip to content

Commit

Permalink
CCA: static check that the state classes are not overlapping
Browse files Browse the repository at this point in the history
Since all the types in StateUnion can be set on state (represented
currently as class on body tag), if the enum values overlap they will
have the same runtime values, and might cause strange issue if the two
enum are used as different things. Add a type level check for this.

Bug: None
Test: cca.py tsc <board>
Test: cca.py tsc <board> failed with CL:4318103 reverted
Change-Id: I8e25628abdca3b3e0322d728999db362c4f5ce57
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4321738
Reviewed-by: Shik Chen <shik@chromium.org>
Commit-Queue: Pi-Hsun Shih <pihsun@chromium.org>
Auto-Submit: Pi-Hsun Shih <pihsun@chromium.org>
Reviewed-by: Chu-Hsuan Yang <chuhsuan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1115553}
  • Loading branch information
peter50216 authored and Chromium LUCI CQ committed Mar 10, 2023
1 parent 802bd98 commit 4551167
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 8 deletions.
1 change: 1 addition & 0 deletions ash/webui/camera_app_ui/resources/js/js.gni
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ compile_js_files = [
"toast.ts",
"tooltip.ts",
"type.ts",
"type_utils.ts",
"unload.ts",
"untrusted_ga_helper.ts",
"untrusted_script_loader.ts",
Expand Down
33 changes: 25 additions & 8 deletions ash/webui/camera_app_ui/resources/js/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
PerfInformation,
ViewName,
} from './type.js';
import {AssertNever, CheckEnumValuesOverlap} from './type_utils.js';

export enum State {
CAMERA_CONFIGURING = 'camera-configuring',
Expand Down Expand Up @@ -61,15 +62,21 @@ export enum State {
USE_FAKE_CAMERA = 'use-fake-camera',
}

export type StateUnion = ExpertOption|Mode|PerfEvent|State|ViewName;
// All the string enum types that can be accepted by |get| / |set|.
const stateEnums = [ExpertOption, Mode, PerfEvent, State, ViewName] as const;

const stateValues = new Set<StateUnion>([
State,
Mode,
ViewName,
PerfEvent,
ExpertOption,
].flatMap((s) => Object.values(s)));
// Note that this can't be inlined into StateTypes since this relies on
// https://github.com/microsoft/TypeScript/pull/26063
type MapEnumTypesToEnums<T> = {
-readonly[K in keyof T]: T[K][keyof T[K]]
};
type StateTypes = MapEnumTypesToEnums<typeof stateEnums>;

// The union of all types accepted by |get| / |set|.
export type StateUnion = StateTypes[number];

const stateValues =
new Set<StateUnion>(stateEnums.flatMap((s) => Object.values(s)));

/**
* Asserts input string is valid state.
Expand Down Expand Up @@ -162,3 +169,13 @@ export function set(
observer(val, perfInfo);
}
}

// This checks that all the enums in stateEnums doesn't overlap, so we don't
// accidentally have two different enum defining the same value.
type OverlappingStates = CheckEnumValuesOverlap<StateTypes>;

// This is exported here to avoid getting unused type warning from typescript.
//
// If you got compile error here, check type of OverlappingStates to see which
// values are duplicated between the stateEnums, and change one of those.
export type AssertStatesNotOverlapping = AssertNever<OverlappingStates>;
23 changes: 23 additions & 0 deletions ash/webui/camera_app_ui/resources/js/type_utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
* Asserts that the given type is never.
*/
export type AssertNever<T extends never> = T;

type CheckEnumValuesOverlapImpl<Union, Overlap, Enums> =
Enums extends [infer Enum extends string, ...infer Rest] ?
CheckEnumValuesOverlapImpl<
Union|`${Enum}`, Overlap|(Union&`${Enum}`), Rest>:
Overlap;

/**
* Checks that a tuple of enum have pairwise non-overlapping values.
*
* The result type will be |never| if there's no overlap, and union of the
* overlapped values if there's overlap.
*/
export type CheckEnumValuesOverlap<Enums extends string[]> =
CheckEnumValuesOverlapImpl<never, never, Enums>;

0 comments on commit 4551167

Please sign in to comment.