Skip to content

Commit

Permalink
Improve code and simplify literal handling
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed May 16, 2021
1 parent 92b1e1d commit 224a4e1
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 39 deletions.
2 changes: 1 addition & 1 deletion src/ast/nodes/Literal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default class Literal<T extends LiteralValue = LiteralValue> extends Node
context: HasEffectsContext
): boolean {
if (path.length === 1) {
return hasMemberEffectWhenCalled(this.members, path[0], this.included, callOptions, context);
return hasMemberEffectWhenCalled(this.members, path[0], callOptions, context);
}
return true;
}
Expand Down
34 changes: 15 additions & 19 deletions src/ast/values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { EMPTY_PATH, ObjectPath, ObjectPathKey } from './utils/PathTracker';

export interface MemberDescription {
callsArgs: number[] | null;
mutatesSelf: boolean;
returns: { new (): ExpressionEntity } | null;
returnsPrimitive: ExpressionEntity | null;
}
Expand Down Expand Up @@ -35,7 +34,6 @@ export const UNDEFINED_EXPRESSION: ExpressionEntity = new (class UndefinedExpres
const returnsUnknown: RawMemberDescription = {
value: {
callsArgs: null,
mutatesSelf: false,
returns: null,
returnsPrimitive: UNKNOWN_EXPRESSION
}
Expand All @@ -53,10 +51,13 @@ export const UNKNOWN_LITERAL_BOOLEAN: ExpressionEntity = new (class UnknownBoole
return path.length > 1;
}

hasEffectsWhenCalledAtPath(path: ObjectPath) {
hasEffectsWhenCalledAtPath(
path: ObjectPath,
callOptions: CallOptions,
context: HasEffectsContext
) {
if (path.length === 1) {
const subPath = path[0];
return typeof subPath !== 'string' || !literalBooleanMembers[subPath];
return hasMemberEffectWhenCalled(literalBooleanMembers, path[0], callOptions, context);
}
return true;
}
Expand All @@ -65,7 +66,6 @@ export const UNKNOWN_LITERAL_BOOLEAN: ExpressionEntity = new (class UnknownBoole
const returnsBoolean: RawMemberDescription = {
value: {
callsArgs: null,
mutatesSelf: false,
returns: null,
returnsPrimitive: UNKNOWN_LITERAL_BOOLEAN
}
Expand All @@ -83,10 +83,13 @@ export const UNKNOWN_LITERAL_NUMBER: ExpressionEntity = new (class UnknownNumber
return path.length > 1;
}

hasEffectsWhenCalledAtPath(path: ObjectPath) {
hasEffectsWhenCalledAtPath(
path: ObjectPath,
callOptions: CallOptions,
context: HasEffectsContext
) {
if (path.length === 1) {
const subPath = path[0];
return typeof subPath !== 'string' || !literalNumberMembers[subPath];
return hasMemberEffectWhenCalled(literalNumberMembers, path[0], callOptions, context);
}
return true;
}
Expand All @@ -95,7 +98,6 @@ export const UNKNOWN_LITERAL_NUMBER: ExpressionEntity = new (class UnknownNumber
const returnsNumber: RawMemberDescription = {
value: {
callsArgs: null,
mutatesSelf: false,
returns: null,
returnsPrimitive: UNKNOWN_LITERAL_NUMBER
}
Expand All @@ -119,7 +121,7 @@ export const UNKNOWN_LITERAL_STRING: ExpressionEntity = new (class UnknownString
context: HasEffectsContext
) {
if (path.length === 1) {
return hasMemberEffectWhenCalled(literalStringMembers, path[0], true, callOptions, context);
return hasMemberEffectWhenCalled(literalStringMembers, path[0], callOptions, context);
}
return true;
}
Expand All @@ -128,7 +130,6 @@ export const UNKNOWN_LITERAL_STRING: ExpressionEntity = new (class UnknownString
const returnsString: RawMemberDescription = {
value: {
callsArgs: null,
mutatesSelf: false,
returns: null,
returnsPrimitive: UNKNOWN_LITERAL_STRING
}
Expand Down Expand Up @@ -180,7 +181,6 @@ const literalStringMembers: MemberDescriptions = assembleMemberDescriptions(
replace: {
value: {
callsArgs: [1],
mutatesSelf: false,
returns: null,
returnsPrimitive: UNKNOWN_LITERAL_STRING
}
Expand Down Expand Up @@ -217,16 +217,12 @@ export function getLiteralMembersForValue<T extends LiteralValue = LiteralValue>
export function hasMemberEffectWhenCalled(
members: MemberDescriptions,
memberName: ObjectPathKey,
parentIncluded: boolean,
callOptions: CallOptions,
context: HasEffectsContext
) {
if (
typeof memberName !== 'string' ||
!members[memberName] ||
(members[memberName].mutatesSelf && parentIncluded)
)
if (typeof memberName !== 'string' || !members[memberName]) {
return true;
}
if (!members[memberName].callsArgs) return false;
for (const argIndex of members[memberName].callsArgs!) {
if (
Expand Down
9 changes: 9 additions & 0 deletions test/form/samples/builtin-prototypes/literal/_expected.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
// retained
true.valueOf().unknown.unknown();
true.valueOf()();
(1).valueOf().unknown.unknown();
(1).valueOf().unknown();
(1).valueOf()[globalThis.unknown]();
(1).valueOf()();
'ab'.charAt(1).unknown.unknown();
'ab'.charAt(1)();
'ab'.replace( 'a', () => console.log( 1 ) || 'b' );

// deep property access is forbidden
Expand Down
28 changes: 9 additions & 19 deletions test/form/samples/builtin-prototypes/literal/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,15 @@ const valueOf2 = true.valueOf();
const valueOf3 = true.valueOf().valueOf();
const valueOf4 = true.valueOf().valueOf().valueOf();

const number = 1;
const toExponential1 = number.toExponential( 2 );
const toExponential2 = (1).toExponential( 2 );
const toExponential3 = (1).toExponential( 2 ).trim();

const string = ' b ';
const trim1 = string.trim();
const trim2 = ' x '.trim();
const trim3 = ' x '.trim().trim();
const trim4 = ' x '.trim().trim().trim();

// boolean prototype
const _booleanValueOf = true.valueOf().valueOf();
// inherited
const _booleanHasOwnProperty = true.hasOwnProperty( 'toString' ).valueOf();
const _booleanIsPrototypeOf = true.isPrototypeOf( true ).valueOf();
const _booleanPropertyIsEnumerable = true.propertyIsEnumerable( 'toString' ).valueOf();
const _booleanToLocaleString = true.toLocaleString().trim();
const _booleanToString = true.toString().trim();
// retained
true.valueOf().unknown.unknown();
true.valueOf()();
(1).valueOf().unknown.unknown();
(1).valueOf().unknown();
(1).valueOf()[globalThis.unknown]();
(1).valueOf()();
'ab'.charAt(1).unknown.unknown();
'ab'.charAt(1)();

// number prototype
const _toExponential = (1).toExponential( 2 ).trim();
Expand Down

0 comments on commit 224a4e1

Please sign in to comment.