public static CheckTree Build(ClangTidyProperties Config) { // Since some check names contain dashes in them, it doesn't make sense to // simply split all check names by dash and construct a huge tree. For // example, in the check called google-runtime-member-string-references, // we don't need each of those to be a different subgroup. So instead we // explicitly specify the common breaking points at which a user might want // to use a -* and everything else falls as a leaf under one of these // categories. // FIXME: This should be configurable without recompilation CheckTree Root = new CheckTree(); string[][] Groups = new string[][] { new string[] { "boost" }, new string[] { "cert" }, new string[] { "clang", "diagnostic" }, new string[] { "cppcoreguidelines", "interfaces" }, new string[] { "cppcoreguidelines", "pro", "bounds" }, new string[] { "cppcoreguidelines", "pro", "type" }, new string[] { "google", "build" }, new string[] { "google", "readability" }, new string[] { "google", "runtime" }, new string[] { "llvm" }, new string[] { "misc" }, }; foreach (string[] Group in Groups) { CheckTree Subgroup = Root; foreach (string Component in Group) { Subgroup = Subgroup.AddOrCreateSubgroup(Component); } } var Props = Config.GetProperties() .Cast <PropertyDescriptor>() .OfType <DynamicPropertyDescriptor <bool> >() .Where(x => x.Attributes.OfType <ClangTidyCheckAttribute>().Count() > 0) .Select(x => new KeyValuePair <DynamicPropertyDescriptor <bool>, string>( x, x.Attributes.OfType <ClangTidyCheckAttribute>().First().CheckName)); var PropArray = Props.ToArray(); foreach (var CheckInfo in PropArray) { string LeafName = null; CheckTree Tree = Root.LocateCheckLeafGroup(CheckInfo.Value, out LeafName); Tree.AddLeaf(LeafName, CheckInfo.Key); } return(Root); }
private CheckTree AddOrCreateSubgroup(string Name) { CheckTreeNode Subgroup = null; if (Children_.TryGetValue(Name, out Subgroup)) { System.Diagnostics.Debug.Assert(Subgroup is CheckTree); return((CheckTree)Subgroup); } CheckTree SG = new CheckTree(Name, this); Children_[Name] = SG; return(SG); }
private CheckTree LocateCheckLeafGroup(string Check, out string LeafName) { string[] Components = Check.Split('-'); string FirstComponent = Components.FirstOrDefault(); if (FirstComponent == null) { LeafName = Check; return(this); } CheckTreeNode Subgroup = null; if (!Children_.TryGetValue(FirstComponent, out Subgroup)) { LeafName = Check; return(this); } System.Diagnostics.Debug.Assert(Subgroup is CheckTree); CheckTree Child = (CheckTree)Subgroup; string ChildName = Check.Substring(FirstComponent.Length + 1); return(Child.LocateCheckLeafGroup(ChildName, out LeafName)); }
public ClangTidyProperties(DynamicPropertyComponent Parent) : base(Parent) { AddClangCheckProperties(); CheckTree_ = CheckTree.Build(this); }
public ClangTidyProperties() : base(null) { AddClangCheckProperties(); CheckTree_ = CheckTree.Build(this); }
public CheckLeaf(string Name, CheckTree Parent, DynamicPropertyDescriptor <bool> Property) : base(Name, Parent) { Property_ = Property; }
/// <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 CheckTree(string Name, CheckTree Parent) : base(Name, Parent) { }
/// <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 CheckTree AddOrCreateSubgroup(string Name) { CheckTreeNode Subgroup = null; if (Children_.TryGetValue(Name, out Subgroup)) { System.Diagnostics.Debug.Assert(Subgroup is CheckTree); return (CheckTree)Subgroup; } CheckTree SG = new CheckTree(Name, this); Children_[Name] = SG; return SG; }
public CheckLeaf(string Name, CheckTree Parent, DynamicPropertyDescriptor<bool> Property) : base(Name, Parent) { Property_ = Property; }
public static CheckTree Build(ClangTidyProperties Config) { // Since some check names contain dashes in them, it doesn't make sense to // simply split all check names by dash and construct a huge tree. For // example, in the check called google-runtime-member-string-references, // we don't need each of those to be a different subgroup. So instead we // explicitly specify the common breaking points at which a user might want // to use a -* and everything else falls as a leaf under one of these // categories. // FIXME: This should be configurable without recompilation CheckTree Root = new CheckTree(); string[][] Groups = new string[][] { new string[] {"boost"}, new string[] {"cert"}, new string[] {"clang", "diagnostic"}, new string[] {"cppcoreguidelines", "interfaces"}, new string[] {"cppcoreguidelines", "pro", "bounds"}, new string[] {"cppcoreguidelines", "pro", "type"}, new string[] {"google", "build"}, new string[] {"google", "readability"}, new string[] {"google", "runtime"}, new string[] {"llvm"}, new string[] {"misc"}, }; foreach (string[] Group in Groups) { CheckTree Subgroup = Root; foreach (string Component in Group) Subgroup = Subgroup.AddOrCreateSubgroup(Component); } var Props = Config.GetProperties() .Cast<PropertyDescriptor>() .OfType<DynamicPropertyDescriptor<bool>>() .Where(x => x.Attributes.OfType<ClangTidyCheckAttribute>().Count() > 0) .Select(x => new KeyValuePair<DynamicPropertyDescriptor<bool>, string>( x, x.Attributes.OfType<ClangTidyCheckAttribute>().First().CheckName)); var PropArray = Props.ToArray(); foreach (var CheckInfo in PropArray) { string LeafName = null; CheckTree Tree = Root.LocateCheckLeafGroup(CheckInfo.Value, out LeafName); Tree.AddLeaf(LeafName, CheckInfo.Key); } return Root; }