File: Linker.Steps\SubStepsDispatcher.cs
Web Access
Project: src\src\tools\illink\src\linker\Mono.Linker.csproj (illink)
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
using System.Collections.Generic;
using System.Diagnostics;
 
using Mono.Cecil;
using Mono.Collections.Generic;
 
namespace Mono.Linker.Steps
{
	struct CategorizedSubSteps
	{
		public List<ISubStep> on_assemblies;
		public List<ISubStep> on_types;
		public List<ISubStep> on_fields;
		public List<ISubStep> on_methods;
		public List<ISubStep> on_properties;
		public List<ISubStep> on_events;
	}
 
	//
	// Generic steps dispatcher is intended to by used by custom ILLink step which
	// consist of multiple steps. It simplifies their implementation as well as the
	// way how to hook them into the pipeline of existing steps.
	//
	public abstract class SubStepsDispatcher : IStep
	{
		readonly List<ISubStep> substeps;
 
		CategorizedSubSteps? categorized;
		CategorizedSubSteps Categorized {
			get {
				Debug.Assert (categorized.HasValue);
				return categorized.Value;
			}
		}
 
		protected SubStepsDispatcher ()
		{
			substeps = new List<ISubStep> ();
		}
 
		protected SubStepsDispatcher (IEnumerable<ISubStep> subSteps)
		{
			substeps = new List<ISubStep> (subSteps);
		}
 
		public void Add (ISubStep substep)
		{
			substeps.Add (substep);
		}
 
		public virtual void Process (LinkContext context)
		{
			InitializeSubSteps (context);
 
			BrowseAssemblies (context.GetAssemblies ());
		}
 
		static bool HasSubSteps (List<ISubStep> substeps) => substeps?.Count > 0;
 
		void BrowseAssemblies (IEnumerable<AssemblyDefinition> assemblies)
		{
			foreach (var assembly in assemblies) {
				CategorizeSubSteps (assembly);
 
				if (HasSubSteps (Categorized.on_assemblies))
					DispatchAssembly (assembly);
 
				if (!ShouldDispatchTypes ())
					continue;
 
				BrowseTypes (assembly.MainModule.Types);
			}
		}
 
		bool ShouldDispatchTypes ()
		{
			return HasSubSteps (Categorized.on_types)
				|| HasSubSteps (Categorized.on_fields)
				|| HasSubSteps (Categorized.on_methods)
				|| HasSubSteps (Categorized.on_properties)
				|| HasSubSteps (Categorized.on_events);
		}
 
		void BrowseTypes (Collection<TypeDefinition> types)
		{
			foreach (TypeDefinition type in types) {
				DispatchType (type);
 
				if (type.HasFields && HasSubSteps (Categorized.on_fields)) {
					foreach (FieldDefinition field in type.Fields)
						DispatchField (field);
				}
 
				if (type.HasMethods && HasSubSteps (Categorized.on_methods)) {
					foreach (MethodDefinition method in type.Methods)
						DispatchMethod (method);
				}
 
				if (type.HasProperties && HasSubSteps (Categorized.on_properties)) {
					foreach (PropertyDefinition property in type.Properties)
						DispatchProperty (property);
				}
 
				if (type.HasEvents && HasSubSteps (Categorized.on_events)) {
					foreach (EventDefinition @event in type.Events)
						DispatchEvent (@event);
				}
 
				if (type.HasNestedTypes)
					BrowseTypes (type.NestedTypes);
			}
		}
 
		void DispatchAssembly (AssemblyDefinition assembly)
		{
			foreach (var substep in Categorized.on_assemblies) {
				substep.ProcessAssembly (assembly);
			}
		}
 
		void DispatchType (TypeDefinition type)
		{
			foreach (var substep in Categorized.on_types) {
				substep.ProcessType (type);
			}
		}
 
		void DispatchField (FieldDefinition field)
		{
			foreach (var substep in Categorized.on_fields) {
				substep.ProcessField (field);
			}
		}
 
		void DispatchMethod (MethodDefinition method)
		{
			foreach (var substep in Categorized.on_methods) {
				substep.ProcessMethod (method);
			}
		}
 
		void DispatchProperty (PropertyDefinition property)
		{
			foreach (var substep in Categorized.on_properties) {
				substep.ProcessProperty (property);
			}
		}
 
		void DispatchEvent (EventDefinition @event)
		{
			foreach (var substep in Categorized.on_events) {
				substep.ProcessEvent (@event);
			}
		}
 
		void InitializeSubSteps (LinkContext context)
		{
			foreach (var substep in substeps)
				substep.Initialize (context);
		}
 
		void CategorizeSubSteps (AssemblyDefinition assembly)
		{
			categorized = new CategorizedSubSteps {
				on_assemblies = new List<ISubStep> (),
				on_types = new List<ISubStep> (),
				on_fields = new List<ISubStep> (),
				on_methods = new List<ISubStep> (),
				on_properties = new List<ISubStep> (),
				on_events = new List<ISubStep> ()
			};
 
			foreach (var substep in substeps)
				CategorizeSubStep (substep, assembly);
		}
 
		void CategorizeSubStep (ISubStep substep, AssemblyDefinition assembly)
		{
			if (!substep.IsActiveFor (assembly))
				return;
 
			CategorizeTarget (substep, SubStepTargets.Assembly, Categorized.on_assemblies);
			CategorizeTarget (substep, SubStepTargets.Type, Categorized.on_types);
			CategorizeTarget (substep, SubStepTargets.Field, Categorized.on_fields);
			CategorizeTarget (substep, SubStepTargets.Method, Categorized.on_methods);
			CategorizeTarget (substep, SubStepTargets.Property, Categorized.on_properties);
			CategorizeTarget (substep, SubStepTargets.Event, Categorized.on_events);
		}
 
		static void CategorizeTarget (ISubStep substep, SubStepTargets target, List<ISubStep> list)
		{
			if (!Targets (substep, target))
				return;
 
			list.Add (substep);
		}
 
		static bool Targets (ISubStep substep, SubStepTargets target) => (substep.Targets & target) == target;
	}
}