1 #region Copyright & License Information
2 /*
3  * Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4  * This file is part of OpenRA, which is free software. It is made
5  * available to you under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, either version 3 of
7  * the License, or (at your option) any later version. For more
8  * information, see COPYING.
9  */
10 #endregion
11 
12 using System;
13 using System.Collections.Generic;
14 using System.Linq;
15 using OpenRA.Mods.Common.Traits;
16 using OpenRA.Traits;
17 
18 namespace OpenRA.Mods.Common.Lint
19 {
20 	public class CheckConditions : ILintRulesPass
21 	{
Run(Action<string> emitError, Action<string> emitWarning, Ruleset rules)22 		public void Run(Action<string> emitError, Action<string> emitWarning, Ruleset rules)
23 		{
24 			foreach (var actorInfo in rules.Actors)
25 			{
26 				var granted = new HashSet<string>();
27 				var consumed = new HashSet<string>();
28 
29 				foreach (var trait in actorInfo.Value.TraitInfos<ITraitInfo>())
30 				{
31 					var fieldConsumed = trait.GetType().GetFields()
32 						.Where(x => x.HasAttribute<ConsumedConditionReferenceAttribute>())
33 						.SelectMany(f => LintExts.GetFieldValues(trait, f, emitError));
34 
35 					var propertyConsumed = trait.GetType().GetProperties()
36 						.Where(x => x.HasAttribute<ConsumedConditionReferenceAttribute>())
37 						.SelectMany(p => LintExts.GetPropertyValues(trait, p, emitError));
38 
39 					var fieldGranted = trait.GetType().GetFields()
40 						.Where(x => x.HasAttribute<GrantedConditionReferenceAttribute>())
41 						.SelectMany(f => LintExts.GetFieldValues(trait, f, emitError));
42 
43 					var propertyGranted = trait.GetType().GetProperties()
44 						.Where(x => x.HasAttribute<GrantedConditionReferenceAttribute>())
45 						.SelectMany(f => LintExts.GetPropertyValues(trait, f, emitError));
46 
47 					foreach (var c in fieldConsumed.Concat(propertyConsumed))
48 						if (!string.IsNullOrEmpty(c))
49 							consumed.Add(c);
50 
51 					foreach (var g in fieldGranted.Concat(propertyGranted))
52 						if (!string.IsNullOrEmpty(g))
53 							granted.Add(g);
54 				}
55 
56 				var unconsumed = granted.Except(consumed);
57 				if (unconsumed.Any())
58 					emitWarning("Actor type `{0}` grants conditions that are not consumed: {1}".F(actorInfo.Key, unconsumed.JoinWith(", ")));
59 
60 				var ungranted = consumed.Except(granted);
61 				if (ungranted.Any())
62 					emitError("Actor type `{0}` consumes conditions that are not granted: {1}".F(actorInfo.Key, ungranted.JoinWith(", ")));
63 
64 				if ((consumed.Any() || granted.Any()) && actorInfo.Value.TraitInfoOrDefault<ConditionManagerInfo>() == null)
65 					emitError("Actor type `{0}` defines conditions but does not include a ConditionManager".F(actorInfo.Key));
66 			}
67 		}
68 	}
69 }
70