/// <summary> /// Convert the given check tree into serialized list of commands that can be written to /// the Yaml. The goal here is to determine the minimal sequence of check commands that /// will produce the exact configuration displayed in the UI. This is complicated by the /// fact that an inherited True is not the same as an explicitly specified True. If the /// user has chosen to inherit a setting in a .clang-tidy file, then changing it in the /// parent should show the reflected changes in the current file as well. So we cannot /// simply -* everything and then add in the checks we need, because -* immediately marks /// every single check as explicitly false, thus disabling inheritance. /// </summary> /// <param name="CommandList">State passed through this recursive algorithm representing /// the sequence of commands we have determined so far. /// </param> /// <param name="Tree">The check tree to serialize. This is the parameter that will be /// recursed on as successive subtrees get serialized to `CommandList`. /// </param> /// <param name="CurrentOp">The current state of the subtree. For example, if the /// algorithm decides to -* an entire subtree and then add back one single check, /// after adding a -subtree-* command to CommandList, it would pass in a value of /// CurrentOp=TreeLevelOp.Disable when it recurses down. This allows deeper iterations /// of the algorithm to know what kind of command (if any) needs to be added to CommandList /// in order to put a particular check into a particular state. /// </param> private static void SerializeCheckTree(List <string> CommandList, CheckTree Tree, TreeLevelOp CurrentOp) { int NumChecks = Tree.CountChecks; int NumDisabled = Tree.CountExplicitlyDisabledChecks; int NumEnabled = Tree.CountExplicitlyEnabledChecks; int NumInherited = Tree.CountInheritedChecks; if (NumChecks == 0) { return; } if (NumInherited > 0) { System.Diagnostics.Debug.Assert(CurrentOp == TreeLevelOp.Inherit); } // If this entire tree is inherited, just exit, nothing about this needs to // go in the clang-tidy file. if (NumInherited == NumChecks) { return; } TreeLevelOp NewOp = CurrentOp; // If there are no inherited properties in this subtree, decide whether to // explicitly enable or disable this subtree. Decide by looking at whether // there is a larger proportion of disabled or enabled descendants. If // there are more disabled items in this subtree for example, disabling the // subtree will lead to a smaller configuration file. if (NumInherited == 0) { if (NumDisabled >= NumEnabled) { NewOp = TreeLevelOp.Disable; } else { NewOp = TreeLevelOp.Enable; } } if (NewOp == TreeLevelOp.Disable) { // Only add an explicit disable command if the tree was not already disabled // to begin with. if (CurrentOp != TreeLevelOp.Disable) { string WildcardPath = "*"; if (Tree.Path != null) { WildcardPath = Tree.Path + "-" + WildcardPath; } CommandList.Add("-" + WildcardPath); } // If the entire subtree was disabled, there's no point descending. if (NumDisabled == NumChecks) { return; } } else if (NewOp == TreeLevelOp.Enable) { // Only add an explicit enable command if the tree was not already enabled // to begin with. Note that if we're at the root, all checks are already // enabled by default, so there's no need to explicitly include * if (CurrentOp != TreeLevelOp.Enable && Tree.Path != null) { string WildcardPath = Tree.Path + "-*"; CommandList.Add(WildcardPath); } // If the entire subtree was enabled, there's no point descending. if (NumEnabled == NumChecks) { return; } } foreach (var Child in Tree.Children) { if (Child.Value is CheckLeaf) { CheckLeaf Leaf = (CheckLeaf)Child.Value; if (Leaf.CountExplicitlyEnabledChecks == 1 && NewOp != TreeLevelOp.Enable) { CommandList.Add(Leaf.Path); } else if (Leaf.CountExplicitlyDisabledChecks == 1 && NewOp != TreeLevelOp.Disable) { CommandList.Add("-" + Leaf.Path); } continue; } System.Diagnostics.Debug.Assert(Child.Value is CheckTree); CheckTree ChildTree = (CheckTree)Child.Value; SerializeCheckTree(CommandList, ChildTree, NewOp); } }
private void AddLeaf(string Name, DynamicPropertyDescriptor <bool> Property) { Children_[Name] = new CheckLeaf(Name, this, Property); }
private void AddLeaf(string Name, DynamicPropertyDescriptor<bool> Property) { Children_[Name] = new CheckLeaf(Name, this, Property); }