Repository: rollup/rollup
File: src/ast/nodes/shared/FunctionNode.ts (TypeScript)

Code before:
	createScope(parentScope: FunctionScope): void {
		this.scope = new FunctionScope(parentScope, this.context);
		this.constructedEntity = new ObjectEntity(Object.create(null), OBJECT_PROTOTYPE);
		// This makes sure that all deoptimizations of "this" are applied to the
		// constructed entity.
		this.scope.thisVariable.addEntityToBeDeoptimized(this.constructedEntity);
	}

	deoptimizeArgumentsOnInteractionAtPath(
		interaction: NodeInteraction,
		path: ObjectPath,
		recursionTracker: PathTracker
	): void {
		super.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
		if (interaction.type === INTERACTION_CALLED && path.length === 0 && interaction.args[0]) {
			// args[0] is the "this" argument
			this.scope.thisVariable.addEntityToBeDeoptimized(interaction.args[0]);
		}
	}

	hasEffects(context: HasEffectsContext): boolean {
		if (!this.deoptimized) this.applyDeoptimizations();

		if (
			(this.context.options.treeshake as NormalizedTreeshakingOptions).annotations &&
			this.annotations
		) {
			return false;
		}

		return !!this.id?.hasEffects(context);
	}

	hasEffectsOnInteractionAtPath(
		path: ObjectPath,
		interaction: NodeInteraction,
		context: HasEffectsContext
	): boolean {
		if (super.hasEffectsOnInteractionAtPath(path, interaction, context)) return true;

		if (
			(this.context.options.treeshake as NormalizedTreeshakingOptions).annotations &&
			this.annotations
		) {
			return false;
		}

		if (interaction.type === INTERACTION_CALLED) {
			const thisInit = context.replacedVariableInits.get(this.scope.thisVariable);
			context.replacedVariableInits.set(
				this.scope.thisVariable,

Review comment (suggestion):
If we use a different annotation, of course it means we cannot use this check as there are different kinds of annotations with different effects.
Here would be one way of handling it:
- we still create `this.annotations` containing ALL annotations because we need this to remove all annotations of a Node if the Node is tree-shaken (it contains the exact locations of the comments we need to remove)
- These annotations are collected in `pureComments.ts`. To avoid re-reading all annotation comments, we add additional flags. Currently it works by adding a `_rollupAnnotations` property to the acorn Node, which is translated in `Node.ts` to the `annotations` property. How about depending on the annotation, we additionally add a `_rollupPure` or `_rollupNoSideEffects` property to the acorn Node that is copied over to the Rollup Nodes?
- We just need to make sure we also adapt the code in `CallExpression.ts` and `NewExpression.ts`.

Code after:
		this.scope = new FunctionScope(parentScope, this.context);
		this.constructedEntity = new ObjectEntity(Object.create(null), OBJECT_PROTOTYPE);
		// This makes sure that all deoptimizations of "this" are applied to the
		// constructed entity.
		this.scope.thisVariable.addEntityToBeDeoptimized(this.constructedEntity);
	}

	deoptimizeArgumentsOnInteractionAtPath(
		interaction: NodeInteraction,
		path: ObjectPath,
		recursionTracker: PathTracker
	): void {
		super.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker);
		if (interaction.type === INTERACTION_CALLED && path.length === 0 && interaction.args[0]) {
			// args[0] is the "this" argument
			this.scope.thisVariable.addEntityToBeDeoptimized(interaction.args[0]);
		}
	}

	hasEffects(context: HasEffectsContext): boolean {
		if (!this.deoptimized) this.applyDeoptimizations();

		if (this.annotationNoSideEffects) {
			return false;
		}

		return !!this.id?.hasEffects(context);
	}

	hasEffectsOnInteractionAtPath(
		path: ObjectPath,
		interaction: NodeInteraction,
		context: HasEffectsContext
	): boolean {
		if (super.hasEffectsOnInteractionAtPath(path, interaction, context)) return true;

		if (this.annotationNoSideEffects) {
			return false;
		}

		if (interaction.type === INTERACTION_CALLED) {
			const thisInit = context.replacedVariableInits.get(this.scope.thisVariable);
			context.replacedVariableInits.set(
				this.scope.thisVariable,
				interaction.withNew ? this.constructedEntity : UNKNOWN_EXPRESSION
			);
			const { brokenFlow, ignore, replacedVariableInits } = context;
			context.ignore = {
				breaks: false,
				continues: false,
				labels: new Set(),