From 1122be8e15b8244afeae5d38383f2410ba7fa102 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Wed, 7 Sep 2016 18:28:55 +0000 Subject: Add a clang-tidy visual studio extension. For now this only adds the UI necessary to configure clang-tidy settings graphically, and it enables reading in and saving out of .clang-tidy files. It does not actually run clang-tidy on any source files yet. Differential Revision: https://reviews.llvm.org/D23848 llvm-svn: 280840 --- .../clang-tidy-vs/ClangTidy/CheckTree.cs | 272 +++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 clang-tools-extra/clang-tidy-vs/ClangTidy/CheckTree.cs (limited to 'clang-tools-extra/clang-tidy-vs/ClangTidy/CheckTree.cs') diff --git a/clang-tools-extra/clang-tidy-vs/ClangTidy/CheckTree.cs b/clang-tools-extra/clang-tidy-vs/ClangTidy/CheckTree.cs new file mode 100644 index 00000000000..ab746fe32b7 --- /dev/null +++ b/clang-tools-extra/clang-tidy-vs/ClangTidy/CheckTree.cs @@ -0,0 +1,272 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace LLVM.ClangTidy +{ + /// + /// CheckTree is used to group checks into categories and subcategories. For + /// example, given the following list of checks: + /// + /// llvm-include-order + /// llvm-namespace-comment + /// llvm-twine-local + /// llvm-header-guard + /// google-runtime-member-string-references + /// google-runtime-int + /// google-readability-namespace-comments + /// + /// the corresponding CheckTree would look like this: + /// + /// llvm + /// include-order + /// namespace-comment + /// twine-local + /// header-guard + /// google + /// runtime + /// member-string-references + /// int + /// readability + /// namespace-comments + /// redundant-smartptr-get + /// + /// This is useful when serializing a set of options out to a .clang-tidy file, + /// because we need to decide the most efficient way to serialize the sequence + /// of check commands, when to use wildcards, etc. For example, if everything + /// under google is inherited, we can simply leave that entry out entirely from + /// the .clang-tidy file. On the other hand, if anything is inherited, we *must + /// not* add or remove google-* by wildcard because that, by definition, means + /// the property is no longer inherited. When we can categorize the checks into + /// groups and subgroups like this, it is possible to efficiently serialize to + /// a minimal representative .clang-tidy file. + /// + + public abstract class CheckTreeNode + { + private string Name_; + private CheckTreeNode Parent_; + + protected CheckTreeNode(string Name, CheckTreeNode Parent) + { + Name_ = Name; + Parent_ = Parent; + } + + public string Path + { + get + { + if (Parent_ == null) + return null; + string ParentPath = Parent_.Path; + if (ParentPath == null) + return Name_; + return ParentPath + "-" + Name_; + } + } + + public string Name + { + get + { + return Name_; + } + } + + + public abstract int CountChecks { get; } + public abstract int CountExplicitlyDisabledChecks { get; } + public abstract int CountExplicitlyEnabledChecks { get; } + public abstract int CountInheritedChecks { get; } + } + + public class CheckTree : CheckTreeNode + { + private Dictionary Children_ = new Dictionary(); + public CheckTree() + : base(null, null) + { + + } + + private CheckTree(string Name, CheckTree Parent) + : base(Name, Parent) + { + } + + private void AddLeaf(string Name, DynamicPropertyDescriptor Property) + { + Children_[Name] = new CheckLeaf(Name, this, Property); + } + + 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 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() + .OfType>() + .Where(x => x.Attributes.OfType().Count() > 0) + .Select(x => new KeyValuePair, string>( + x, x.Attributes.OfType().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 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 override int CountChecks + { + get + { + return Children_.Aggregate(0, (X, V) => { return X + V.Value.CountChecks; }); + } + } + + public override int CountExplicitlyDisabledChecks + { + get + { + return Children_.Aggregate(0, (X, V) => { return X + V.Value.CountExplicitlyDisabledChecks; }); + } + } + + public override int CountExplicitlyEnabledChecks + { + get + { + return Children_.Aggregate(0, (X, V) => { return X + V.Value.CountExplicitlyEnabledChecks; }); + } + } + public override int CountInheritedChecks + { + get + { + return Children_.Aggregate(0, (X, V) => { return X + V.Value.CountInheritedChecks; }); + } + } + + public IDictionary Children + { + get { return Children_; } + } + } + + public class CheckLeaf : CheckTreeNode + { + private DynamicPropertyDescriptor Property_; + + public CheckLeaf(string Name, CheckTree Parent, DynamicPropertyDescriptor Property) + : base(Name, Parent) + { + Property_ = Property; + } + + public override int CountChecks + { + get + { + return 1; + } + } + + public override int CountExplicitlyDisabledChecks + { + get + { + if (Property_.IsInheriting) + return 0; + return (bool)Property_.GetValue(null) ? 0 : 1; + } + } + + public override int CountExplicitlyEnabledChecks + { + get + { + if (Property_.IsInheriting) + return 0; + return (bool)Property_.GetValue(null) ? 1 : 0; + } + } + + public override int CountInheritedChecks + { + get + { + return (Property_.IsInheriting) ? 1 : 0; + } + } + + } +} -- cgit v1.2.3