Index: clang-tools-extra/trunk/CMakeLists.txt
===================================================================
--- clang-tools-extra/trunk/CMakeLists.txt
+++ clang-tools-extra/trunk/CMakeLists.txt
@@ -4,6 +4,7 @@
add_subdirectory(modularize)
if(CLANG_ENABLE_STATIC_ANALYZER)
add_subdirectory(clang-tidy)
+add_subdirectory(clang-tidy-vs)
endif()
add_subdirectory(clang-query)
Index: clang-tools-extra/trunk/clang-tidy-vs/.gitignore
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/.gitignore
+++ clang-tools-extra/trunk/clang-tidy-vs/.gitignore
@@ -0,0 +1,7 @@
+obj/
+bin/
+.vs/
+Key.snk
+clang-tidy.exe
+packages/
+*.csproj.user
Index: clang-tools-extra/trunk/clang-tidy-vs/CMakeLists.txt
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/CMakeLists.txt
+++ clang-tools-extra/trunk/clang-tidy-vs/CMakeLists.txt
@@ -0,0 +1,28 @@
+option(BUILD_CLANG_TIDY_VS_PLUGIN "Build clang-tidy VS plugin" OFF)
+if (BUILD_CLANG_TIDY_VS_PLUGIN)
+ add_custom_target(clang_tidy_exe_for_vsix
+ ${CMAKE_COMMAND} -E copy_if_different
+ "${LLVM_TOOLS_BINARY_DIR}/clang-tidy.exe"
+ "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy/clang-tidy.exe"
+ DEPENDS clang-tidy)
+
+ add_custom_target(clang_tidy_license
+ ${CMAKE_COMMAND} -E copy_if_different
+ "${CLANG_SOURCE_DIR}/LICENSE.TXT"
+ "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy/license.txt")
+
+ if (NOT CLANG_TIDY_VS_VERSION)
+ set(CLANG_TIDY_VS_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
+ endif()
+
+ configure_file("source.extension.vsixmanifest.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy/source.extension.vsixmanifest")
+
+ add_custom_target(clang_tidy_vsix ALL
+ devenv "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy.sln" /Build Release
+ DEPENDS clang_tidy_exe_for_vsix "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy/source.extension.vsixmanifest"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy/bin/Release/ClangTidy.vsix"
+ "${LLVM_TOOLS_BINARY_DIR}/ClangTidy.vsix"
+ DEPENDS clang_tidy_exe_for_vsix clang_tidy_license)
+endif()
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy.sln
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy.sln
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25123.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClangTidy", "ClangTidy\ClangTidy.csproj", "{BE261DA1-36C6-449A-95C5-4653A549170A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BE261DA1-36C6-449A-95C5-4653A549170A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BE261DA1-36C6-449A-95C5-4653A549170A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BE261DA1-36C6-449A-95C5-4653A549170A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BE261DA1-36C6-449A-95C5-4653A549170A}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/CategoryVerb.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/CategoryVerb.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/CategoryVerb.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ ///
+ /// Allows entire categories of properties to be enabled, disabled, or inherited
+ /// in one fell swoop. We add properties to each category with the value being
+ /// this enum, and when the value is selected, we use reflection to find all other
+ /// properties in the same category and perform the corresponding action.
+ ///
+ public enum CategoryVerb
+ {
+ None,
+ Disable,
+ Enable,
+ Inherit
+ }
+
+ public class CategoryVerbConverter : EnumConverter
+ {
+ public CategoryVerbConverter() : base(typeof(CategoryVerb))
+ {
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ if (value is string)
+ {
+ switch ((string)value)
+ {
+ case "Disable Category":
+ return CategoryVerb.Disable;
+ case "Enable Category":
+ return CategoryVerb.Enable;
+ case "Inherit Category":
+ return CategoryVerb.Inherit;
+ case "":
+ return CategoryVerb.None;
+ }
+ }
+ return base.ConvertFrom(context, culture, value);
+ }
+
+ public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
+ {
+ if (value is CategoryVerb && destinationType == typeof(string))
+ {
+ switch ((CategoryVerb)value)
+ {
+ case CategoryVerb.Disable:
+ return "Disable Category";
+ case CategoryVerb.Enable:
+ return "Enable Category";
+ case CategoryVerb.Inherit:
+ return "Inherit Category";
+ case CategoryVerb.None:
+ return String.Empty;
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/CheckDatabase.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/CheckDatabase.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/CheckDatabase.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+
+namespace LLVM.ClangTidy
+{
+ public class CheckInfo
+ {
+ [YamlAlias("Name")]
+ public string Name { get; set; }
+
+ [YamlAlias("Label")]
+ public string Label { get; set; }
+
+ [YamlAlias("Description")]
+ public string Desc { get; set; }
+
+ [YamlAlias("Category")]
+ public string Category { get; set; }
+ }
+
+ ///
+ /// Reads the list of checks from Yaml and builds a description of each one.
+ /// This list of checks is then used by the PropertyGrid to determine what
+ /// items to display.
+ ///
+ public static class CheckDatabase
+ {
+ static CheckInfo[] Checks_ = null;
+
+ class CheckRoot
+ {
+ [YamlAlias("Checks")]
+ public CheckInfo[] Checks { get; set; }
+ }
+
+ static CheckDatabase()
+ {
+ using (StringReader Reader = new StringReader(Resources.ClangTidyChecks))
+ {
+ Deserializer D = new Deserializer(namingConvention: new PascalCaseNamingConvention());
+ var Root = D.Deserialize(Reader);
+ Checks_ = Root.Checks;
+
+ HashSet Names = new HashSet();
+ foreach (var Check in Checks_)
+ {
+ if (Names.Contains(Check.Name))
+ throw new ArgumentException(String.Format("Check {0} exists more than once!", Check.Name));
+ Names.Add(Check.Name);
+ }
+ }
+ }
+
+ public static IEnumerable Checks
+ {
+ get
+ {
+ return Checks_;
+ }
+ }
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/CheckTree.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/CheckTree.cs
+++ clang-tools-extra/trunk/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;
+ }
+ }
+
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidy.csproj
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidy.csproj
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidy.csproj
@@ -0,0 +1,267 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 2.0
+ {BE261DA1-36C6-449A-95C5-4653A549170A}
+ {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ Properties
+ LLVM.ClangTidy
+ ClangTidy
+ true
+ Key.snk
+ v4.5
+ 14.0
+
+
+
+
+ 4.0
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 0
+ false
+ AnyCPU
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\packages\YamlDotNet.3.3.0\lib\net35\YamlDotNet.dll
+ True
+
+
+ ..\packages\YamlDotNet.Dynamic.3.2.3\lib\net40\YamlDotNet.Dynamic.dll
+ True
+
+
+
+
+ {80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2}
+ 8
+ 0
+ 0
+ primary
+ False
+ False
+
+
+ {26AD1324-4B7C-44BC-84F8-B86AED45729F}
+ 10
+ 0
+ 0
+ primary
+ False
+ False
+
+
+ {1A31287A-4D7D-413E-8E32-3B374931BD89}
+ 8
+ 0
+ 0
+ primary
+ False
+ False
+
+
+ {2CE2370E-D744-4936-A090-3FFFE667B0E1}
+ 9
+ 0
+ 0
+ primary
+ False
+ False
+
+
+ {1CBA492E-7263-47BB-87FE-639000619B15}
+ 8
+ 0
+ 0
+ primary
+ False
+ False
+
+
+ {00020430-0000-0000-C000-000000000046}
+ 2
+ 0
+ 0
+ primary
+ False
+ False
+
+
+
+
+
+
+
+
+ Component
+
+
+ Component
+
+
+
+
+
+
+ Component
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+
+ UserControl
+
+
+ ClangTidyPropertyGrid.cs
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ ClangTidyPropertyGrid.cs
+
+
+ true
+ VSPackage
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+ Menus.ctmenu
+ Designer
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+
+
+
+ False
+ Microsoft .NET Framework 4 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+ False
+ Windows Installer 4.5
+ true
+
+
+
+ true
+
+
+ 10.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+
+ if not exist $(ProjectDir)Key.snk ("$(SDKToolsPath)\sn.exe" -k $(ProjectDir)Key.snk)
+
+
+
+
+
+
\ No newline at end of file
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidy.vsct
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidy.vsct
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidy.vsct
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyCheckAttribute.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyCheckAttribute.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyCheckAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ public class ClangTidyCheckAttribute : Attribute
+ {
+ private string CheckName_;
+ public ClangTidyCheckAttribute(string CheckName)
+ {
+ this.CheckName_ = CheckName;
+ }
+
+ public string CheckName
+ {
+ get { return CheckName_; }
+ }
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyConfigParser.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyConfigParser.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyConfigParser.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+
+namespace LLVM.ClangTidy
+{
+ static class ClangTidyConfigParser
+ {
+ public class CheckOption
+ {
+ [YamlAlias("key")]
+ public string Key { get; set; }
+
+ [YamlAlias("value")]
+ public string Value { get; set; }
+ }
+ public class ClangTidyYaml
+ {
+ [YamlAlias("Checks")]
+ public string Checks { get; set; }
+
+ [YamlAlias("CheckOptions")]
+ public List CheckOptions { get; set; }
+ }
+
+ public static List> ParseConfigurationChain(string ClangTidyFile)
+ {
+ List> Result = new List>();
+ Result.Add(new KeyValuePair(null, ClangTidyProperties.RootProperties));
+
+ foreach (string P in Utility.SplitPath(ClangTidyFile).Reverse())
+ {
+ if (!Utility.HasClangTidyFile(P))
+ continue;
+
+ string ConfigFile = Path.Combine(P, ".clang-tidy");
+
+ using (StreamReader Reader = new StreamReader(ConfigFile))
+ {
+ Deserializer D = new Deserializer(namingConvention: new PascalCaseNamingConvention());
+ ClangTidyYaml Y = D.Deserialize(Reader);
+ ClangTidyProperties Parent = Result[Result.Count - 1].Value;
+ ClangTidyProperties NewProps = new ClangTidyProperties(Parent);
+ SetPropertiesFromYaml(Y, NewProps);
+ Result.Add(new KeyValuePair(P, NewProps));
+ }
+ }
+ return Result;
+ }
+
+ enum TreeLevelOp
+ {
+ Enable,
+ Disable,
+ Inherit
+ }
+
+ public static void SerializeClangTidyFile(ClangTidyProperties Props, string ClangTidyFilePath)
+ {
+ List CommandList = new List();
+ SerializeCheckTree(CommandList, Props.GetCheckTree(), TreeLevelOp.Inherit);
+
+ CommandList.Sort((x, y) =>
+ {
+ bool LeftSub = x.StartsWith("-");
+ bool RightSub = y.StartsWith("-");
+ if (LeftSub && !RightSub)
+ return -1;
+ if (RightSub && !LeftSub)
+ return 1;
+ return StringComparer.CurrentCulture.Compare(x, y);
+ });
+
+ string ConfigFile = Path.Combine(ClangTidyFilePath, ".clang-tidy");
+ using (StreamWriter Writer = new StreamWriter(ConfigFile))
+ {
+ Serializer S = new Serializer(namingConvention: new PascalCaseNamingConvention());
+ ClangTidyYaml Yaml = new ClangTidyYaml();
+ Yaml.Checks = String.Join(",", CommandList.ToArray());
+ S.Serialize(Writer, Yaml);
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ /// State passed through this recursive algorithm representing
+ /// the sequence of commands we have determined so far.
+ ///
+ /// The check tree to serialize. This is the parameter that will be
+ /// recursed on as successive subtrees get serialized to `CommandList`.
+ ///
+ /// 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.
+ ///
+ private static void SerializeCheckTree(List 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 static void SetPropertiesFromYaml(ClangTidyYaml Yaml, ClangTidyProperties Props)
+ {
+ string[] CheckCommands = Yaml.Checks.Split(',');
+ foreach (string Command in CheckCommands)
+ {
+ if (Command == null || Command.Length == 0)
+ continue;
+ bool Add = true;
+ string Pattern = Command;
+ if (Pattern[0] == '-')
+ {
+ Pattern = Pattern.Substring(1);
+ Add = false;
+ }
+
+ foreach (var Match in CheckDatabase.Checks.Where(x => Utility.MatchWildcardString(x.Name, Pattern)))
+ {
+ Props.SetDynamicValue(Match.Name, Add);
+ }
+ }
+ }
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyConfigurationPage.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyConfigurationPage.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyConfigurationPage.cs
@@ -0,0 +1,61 @@
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace LLVM.ClangTidy
+{
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [CLSCompliant(false), ComVisible(true)]
+ public class ClangTidyConfigurationPage : DialogPage
+ {
+ ClangTidyPropertyGrid Grid = null;
+ protected override IWin32Window Window
+ {
+ get
+ {
+ if (Grid == null)
+ Grid = new ClangTidyPropertyGrid();
+ return Grid;
+ }
+ }
+
+ protected override void SaveSetting(PropertyDescriptor property)
+ {
+ base.SaveSetting(property);
+ }
+
+ public override void SaveSettingsToStorage()
+ {
+ if (Grid != null)
+ Grid.SaveSettingsToStorage();
+
+ base.SaveSettingsToStorage();
+ }
+
+ public override void ResetSettings()
+ {
+ base.ResetSettings();
+ }
+
+ protected override void LoadSettingFromStorage(PropertyDescriptor prop)
+ {
+ base.LoadSettingFromStorage(prop);
+ }
+
+ public override void LoadSettingsFromStorage()
+ {
+ if (Grid != null)
+ Grid.InitializeSettings();
+ base.LoadSettingsFromStorage();
+ }
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPackage.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPackage.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPackage.cs
@@ -0,0 +1,56 @@
+//===-- ClangTidyPackages.cs - VSPackage for clang-tidy ----------*- C# -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class contains a VS extension package that runs clang-tidy over a
+// file in a VS text editor.
+//
+//===----------------------------------------------------------------------===//
+
+using Microsoft.VisualStudio.Editor;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.TextManager.Interop;
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+using System.Xml.Linq;
+
+namespace LLVM.ClangTidy
+{
+ [PackageRegistration(UseManagedResourcesOnly = true)]
+ [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
+ [ProvideMenuResource("Menus.ctmenu", 1)]
+ [Guid(GuidList.guidClangTidyPkgString)]
+ [ProvideOptionPage(typeof(ClangTidyConfigurationPage), "LLVM/Clang", "ClangTidy", 0, 0, true)]
+ public sealed class ClangTidyPackage : Package
+ {
+ #region Package Members
+ protected override void Initialize()
+ {
+ base.Initialize();
+
+ var commandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
+ if (commandService != null)
+ {
+ var menuCommandID = new CommandID(GuidList.guidClangTidyCmdSet, (int)PkgCmdIDList.cmdidClangTidy);
+ var menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
+ commandService.AddCommand(menuItem);
+ }
+ }
+ #endregion
+
+ private void MenuItemCallback(object sender, EventArgs args)
+ {
+ }
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyProperties.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyProperties.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyProperties.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+
+ public class ClangTidyProperties : DynamicPropertyComponent
+ {
+ private static ClangTidyProperties RootProperties_ = null;
+ private CheckTree CheckTree_;
+ private bool HasUnsavedChanges_ = false;
+
+ public struct CheckMapping
+ {
+ public string CheckName;
+ public string Property;
+ }
+
+ public ClangTidyProperties()
+ : base(null)
+ {
+ AddClangCheckProperties();
+ CheckTree_ = CheckTree.Build(this);
+ }
+
+ public ClangTidyProperties(DynamicPropertyComponent Parent)
+ : base(Parent)
+ {
+ AddClangCheckProperties();
+ CheckTree_ = CheckTree.Build(this);
+ }
+
+ static ClangTidyProperties()
+ {
+ RootProperties_ = new ClangTidyProperties(null);
+ PropertyDescriptor D;
+ }
+
+ public static ClangTidyProperties RootProperties
+ {
+ get { return RootProperties_; }
+ }
+
+ private void AddClangCheckProperties()
+ {
+ // Add each check in the check database
+ HashSet Categories = new HashSet();
+ foreach (var Check in CheckDatabase.Checks)
+ {
+ string Name = Check.Name.Replace('-', '_');
+ List Attrs = new List();
+ Attrs.Add(new CategoryAttribute(Check.Category));
+ Attrs.Add(new DisplayNameAttribute(Check.Label));
+ Attrs.Add(new DefaultValueAttribute(true));
+ Attrs.Add(new DescriptionAttribute(Check.Desc));
+ Attrs.Add(new ClangTidyCheckAttribute(Check.Name));
+ Categories.Add(Check.Category);
+ AddDynamicProperty(Check.Name, Attrs.ToArray());
+ }
+
+ // Add a category verb for each unique category.
+ foreach (string Cat in Categories)
+ {
+ List Attrs = new List();
+ Attrs.Add(new CategoryAttribute(Cat));
+ Attrs.Add(new DisplayNameAttribute("(Category Verbs)"));
+ Attrs.Add(new TypeConverterAttribute(typeof(CategoryVerbConverter)));
+ Attrs.Add(new DefaultValueAttribute(CategoryVerb.None));
+ AddDynamicProperty(Cat + "Verb", Attrs.ToArray());
+ }
+ }
+
+ public CheckTree GetCheckTree() { return CheckTree_; }
+ public bool GetHasUnsavedChanges() { return HasUnsavedChanges_; }
+ public void SetHasUnsavedChanges(bool Value) { HasUnsavedChanges_ = Value; }
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.Designer.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.Designer.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.Designer.cs
@@ -0,0 +1,119 @@
+namespace LLVM.ClangTidy
+{
+ partial class ClangTidyPropertyGrid
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.button1 = new System.Windows.Forms.Button();
+ this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
+ this.clangTidyProperties1 = new LLVM.ClangTidy.ClangTidyProperties();
+ this.clangTidyConfigurationPage1 = new LLVM.ClangTidy.ClangTidyConfigurationPage();
+ this.linkLabelPath = new System.Windows.Forms.LinkLabel();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(14, 17);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(88, 13);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "Configuration File";
+ //
+ // textBox1
+ //
+ this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.textBox1.Location = new System.Drawing.Point(108, 14);
+ this.textBox1.Name = "textBox1";
+ this.textBox1.Size = new System.Drawing.Size(222, 20);
+ this.textBox1.TabIndex = 1;
+ //
+ // button1
+ //
+ this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.button1.Location = new System.Drawing.Point(336, 14);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(78, 20);
+ this.button1.TabIndex = 2;
+ this.button1.Text = "Browse";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // propertyGrid1
+ //
+ this.propertyGrid1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.propertyGrid1.Location = new System.Drawing.Point(20, 73);
+ this.propertyGrid1.Name = "propertyGrid1";
+ this.propertyGrid1.SelectedObject = this.clangTidyProperties1;
+ this.propertyGrid1.Size = new System.Drawing.Size(391, 384);
+ this.propertyGrid1.TabIndex = 6;
+ this.propertyGrid1.ViewBorderColor = System.Drawing.SystemColors.ControlDarkDark;
+ this.propertyGrid1.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.propertyGrid1_PropertyValueChanged);
+ //
+ // linkLabelPath
+ //
+ this.linkLabelPath.AutoSize = true;
+ this.linkLabelPath.Location = new System.Drawing.Point(29, 50);
+ this.linkLabelPath.Name = "linkLabelPath";
+ this.linkLabelPath.Size = new System.Drawing.Size(55, 13);
+ this.linkLabelPath.TabIndex = 7;
+ this.linkLabelPath.TabStop = true;
+ this.linkLabelPath.Text = "linkLabel1";
+ this.linkLabelPath.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelPath_LinkClicked);
+ //
+ // ClangTidyPropertyGrid
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.Controls.Add(this.linkLabelPath);
+ this.Controls.Add(this.propertyGrid1);
+ this.Controls.Add(this.button1);
+ this.Controls.Add(this.textBox1);
+ this.Controls.Add(this.label1);
+ this.Name = "ClangTidyPropertyGrid";
+ this.Size = new System.Drawing.Size(444, 469);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.TextBox textBox1;
+ private System.Windows.Forms.Button button1;
+ private System.Windows.Forms.PropertyGrid propertyGrid1;
+ private ClangTidyProperties clangTidyProperties1;
+ private ClangTidyConfigurationPage clangTidyConfigurationPage1;
+ private System.Windows.Forms.LinkLabel linkLabelPath;
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.cs
@@ -0,0 +1,215 @@
+//===-- ClangTidyPropertyGrid.cs - UI for configuring clang-tidy -*- C# -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class contains a UserControl consisting of a .NET PropertyGrid control
+// allowing configuration of checks and check options for ClangTidy.
+//
+//===----------------------------------------------------------------------===//
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.IO;
+using Microsoft.VisualStudio.Shell;
+
+namespace LLVM.ClangTidy
+{
+ ///
+ /// A UserControl displaying a PropertyGrid allowing configuration of clang-tidy
+ /// checks and check options, as well as serialization and deserialization of
+ /// clang-tidy configuration files. When a configuration file is loaded, the
+ /// entire chain of configuration files is analyzed based on the file path,
+ /// and quick access is provided to edit or view any of the files in the
+ /// configuration chain, allowing easy visualization of where values come from
+ /// (similar in spirit to the -explain-config option of clang-tidy).
+ ///
+ public partial class ClangTidyPropertyGrid : UserControl
+ {
+ ///
+ /// The sequence of .clang-tidy configuration files, starting from the root
+ /// of the filesystem, down to the selected file.
+ ///
+ List> PropertyChain_ = null;
+
+ ///
+ /// A tree representing all the checks that the extension knows about, used
+ /// when serializing a file to intelligently determine when to use wildcard
+ /// include / exclude rules.
+ ///
+ CheckTree Checks_;
+
+ public ClangTidyPropertyGrid()
+ {
+ InitializeComponent();
+ InitializeSettings();
+ }
+
+ private enum ShouldCancel
+ {
+ Yes,
+ No,
+ }
+
+ public void SaveSettingsToStorage()
+ {
+ PersistUnsavedChanges(false);
+ }
+
+ private ShouldCancel PersistUnsavedChanges(bool PromptFirst)
+ {
+ var UnsavedResults = PropertyChain_.Where(x => x.Key != null && x.Value.GetHasUnsavedChanges());
+ if (UnsavedResults.Count() == 0)
+ return ShouldCancel.No;
+
+ bool ShouldSave = false;
+ if (PromptFirst)
+ {
+ var Response = MessageBox.Show(
+ "You have unsaved changes! Do you want to save before loading a new file?",
+ "clang-tidy",
+ MessageBoxButtons.YesNoCancel);
+
+ ShouldSave = (Response == DialogResult.Yes);
+ if (Response == DialogResult.Cancel)
+ return ShouldCancel.Yes;
+ }
+ else
+ ShouldSave = true;
+
+ if (ShouldSave)
+ {
+ foreach (var Result in UnsavedResults)
+ {
+ ClangTidyConfigParser.SerializeClangTidyFile(Result.Value, Result.Key);
+ Result.Value.SetHasUnsavedChanges(false);
+ }
+ }
+ return ShouldCancel.No;
+ }
+
+ public void InitializeSettings()
+ {
+ PropertyChain_ = new List>();
+ PropertyChain_.Add(new KeyValuePair(null, ClangTidyProperties.RootProperties));
+ reloadPropertyChain();
+ }
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ ShouldCancel Cancel = PersistUnsavedChanges(true);
+ if (Cancel == ShouldCancel.Yes)
+ return;
+
+ using (OpenFileDialog D = new OpenFileDialog())
+ {
+ D.Filter = "Clang Tidy files|.clang-tidy";
+ D.CheckPathExists = true;
+ D.CheckFileExists = true;
+
+ if (D.ShowDialog() == DialogResult.OK)
+ {
+ PropertyChain_.Clear();
+ PropertyChain_ = ClangTidyConfigParser.ParseConfigurationChain(D.FileName);
+ textBox1.Text = D.FileName;
+ reloadPropertyChain();
+ }
+ }
+ }
+
+ private static readonly string DefaultText = "(Default)";
+ private static readonly string BrowseText = "Browse for a file to edit its properties";
+
+ ///
+ /// After a new configuration file is chosen, analyzes the directory hierarchy
+ /// and finds all .clang-tidy files in the path, parses them and updates the
+ /// PropertyGrid and quick-access LinkLabel control to reflect the new property
+ /// chain.
+ ///
+ private void reloadPropertyChain()
+ {
+ StringBuilder LinkBuilder = new StringBuilder();
+ LinkBuilder.Append(DefaultText);
+ LinkBuilder.Append(" > ");
+ int PrefixLength = LinkBuilder.Length;
+
+ if (PropertyChain_.Count == 1)
+ LinkBuilder.Append(BrowseText);
+ else
+ LinkBuilder.Append(PropertyChain_[PropertyChain_.Count - 1].Key);
+
+ linkLabelPath.Text = LinkBuilder.ToString();
+
+ // Given a path like D:\Foo\Bar\Baz, construct a LinkLabel where individual
+ // components of the path are clickable iff they contain a .clang-tidy file.
+ // Clicking one of the links then updates the PropertyGrid to display the
+ // selected .clang-tidy file.
+ ClangTidyProperties LastProps = ClangTidyProperties.RootProperties;
+ linkLabelPath.Links.Clear();
+ linkLabelPath.Links.Add(0, DefaultText.Length, LastProps);
+ foreach (var Prop in PropertyChain_.Skip(1))
+ {
+ LastProps = Prop.Value;
+ string ClangTidyFolder = Path.GetFileName(Prop.Key);
+ int ClangTidyFolderOffset = Prop.Key.Length - ClangTidyFolder.Length;
+ linkLabelPath.Links.Add(PrefixLength + ClangTidyFolderOffset, ClangTidyFolder.Length, LastProps);
+ }
+ propertyGrid1.SelectedObject = LastProps;
+ }
+
+ private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
+ {
+ ClangTidyProperties Props = (ClangTidyProperties)propertyGrid1.SelectedObject;
+ Props.SetHasUnsavedChanges(true);
+
+ // When a CategoryVerb is selected, perform the corresponding action.
+ PropertyDescriptor Property = e.ChangedItem.PropertyDescriptor;
+ if (!(e.ChangedItem.Value is CategoryVerb))
+ return;
+
+ CategoryVerb Action = (CategoryVerb)e.ChangedItem.Value;
+ if (Action == CategoryVerb.None)
+ return;
+
+ var Category = Property.Attributes.OfType().FirstOrDefault();
+ if (Category == null)
+ return;
+ var SameCategoryProps = Props.GetProperties(new Attribute[] { Category });
+ foreach (PropertyDescriptor P in SameCategoryProps)
+ {
+ if (P == Property)
+ continue;
+ switch (Action)
+ {
+ case CategoryVerb.Disable:
+ P.SetValue(propertyGrid1.SelectedObject, false);
+ break;
+ case CategoryVerb.Enable:
+ P.SetValue(propertyGrid1.SelectedObject, true);
+ break;
+ case CategoryVerb.Inherit:
+ P.ResetValue(propertyGrid1.SelectedObject);
+ break;
+ }
+ }
+ Property.ResetValue(propertyGrid1.SelectedObject);
+ propertyGrid1.Invalidate();
+ }
+
+ private void linkLabelPath_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ ClangTidyProperties Props = (ClangTidyProperties)e.Link.LinkData;
+ propertyGrid1.SelectedObject = Props;
+ }
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.resx
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.resx
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 183, 17
+
+
\ No newline at end of file
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.Designer.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.Designer.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.Designer.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ partial class DynamicPropertyComponent
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ components = new System.ComponentModel.Container();
+ }
+
+ #endregion
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ ///
+ /// The goal of this class is to enable displaying of a PropertyGrid in much the
+ /// same way that Visual Studio's C++ project system does. A project or file can
+ /// have properties which might inherit from their parent, or be overridden.
+ /// It turns out this is somewhat non-trivial. The .NET PropertyGrid is good makes
+ /// displaying simple properties with a static notion of what constitutes a
+ /// "default" value very easy. You simply apply an Attribute to the class that says
+ /// what the default value is and you're done. But when you try to introduce the idea
+ /// that a property's default value depends on some other factor, things get much more
+ /// complicated due to the static nature of Attributes.
+ ///
+ /// The solution to this is to inherit from ICustomTypeDescriptor. This is the mechanism
+ /// by which you can inject or modify attributes or properties at runtime. The .NET
+ /// PropertyGrid is designed in such a way that instead of using simple .NET Reflection to
+ /// look for the properties and attributes on a class, it will invoke the methods of
+ /// ICustomTypeDescriptor (if your type inherits from it), and ask those methods. Our
+ /// implementation of ICustomTypeDescriptor works by waiting until the PropertyGrid requests
+ /// PropertyDescriptors for each of the properties, and then "decorating" them with our
+ /// own custom PropertyDescriptor implementation which understands the proeprty inheritance
+ /// model we wish to implement.
+ ///
+ public partial class DynamicPropertyComponent : Component, ICustomTypeDescriptor
+ {
+ PropertyDescriptorCollection DynamicProperties_ = new PropertyDescriptorCollection(null);
+ private DynamicPropertyComponent Parent_;
+
+ public DynamicPropertyComponent(DynamicPropertyComponent Parent)
+ {
+ Parent_ = Parent;
+ }
+
+ public DynamicPropertyComponent(DynamicPropertyComponent Parent, IContainer container)
+ {
+ Parent_ = Parent;
+
+ container.Add(this);
+ InitializeComponent();
+ }
+
+ public AttributeCollection GetAttributes()
+ {
+ return TypeDescriptor.GetAttributes(GetType());
+ }
+
+ public string GetClassName()
+ {
+ return TypeDescriptor.GetClassName(GetType());
+ }
+
+ public string GetComponentName()
+ {
+ return TypeDescriptor.GetComponentName(GetType());
+ }
+
+ public TypeConverter GetConverter()
+ {
+ return TypeDescriptor.GetConverter(GetType());
+ }
+
+ public EventDescriptor GetDefaultEvent()
+ {
+ return TypeDescriptor.GetDefaultEvent(GetType());
+ }
+
+ public PropertyDescriptor GetDefaultProperty()
+ {
+ return TypeDescriptor.GetDefaultProperty(GetType());
+ }
+
+ public object GetEditor(Type editorBaseType)
+ {
+ return TypeDescriptor.GetEditor(GetType(), editorBaseType);
+ }
+
+ public EventDescriptorCollection GetEvents()
+ {
+ return TypeDescriptor.GetEvents(GetType());
+ }
+
+ public EventDescriptorCollection GetEvents(Attribute[] attributes)
+ {
+ return TypeDescriptor.GetEvents(GetType(), attributes);
+ }
+
+ public PropertyDescriptorCollection GetProperties()
+ {
+ return DynamicProperties_;
+ }
+
+ public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
+ {
+ var Props = DynamicProperties_.OfType();
+ var Filtered = Props.Where(x => x.Attributes.Contains(attributes)).ToArray();
+ return new PropertyDescriptorCollection(Filtered);
+ }
+
+ public object GetPropertyOwner(PropertyDescriptor pd)
+ {
+ return this;
+ }
+
+ public void SetDynamicValue(string Name, T Value)
+ {
+ Name = Name.Replace('-', '_');
+ DynamicPropertyDescriptor Descriptor = (DynamicPropertyDescriptor)DynamicProperties_.Find(Name, false);
+ Descriptor.SetValue(this, Value);
+ }
+
+ public T GetDynamicValue(string Name)
+ {
+ Name = Name.Replace('-', '_');
+ DynamicPropertyDescriptor Descriptor = (DynamicPropertyDescriptor)DynamicProperties_.Find(Name, false);
+ return (T)Descriptor.GetValue(this);
+ }
+
+ protected void AddDynamicProperty(string Name, Attribute[] Attributes)
+ {
+ Name = Name.Replace('-', '_');
+
+ // If we have a parent, find the corresponding PropertyDescriptor with the same
+ // name from the parent.
+ DynamicPropertyDescriptor ParentDescriptor = null;
+ if (Parent_ != null)
+ ParentDescriptor = (DynamicPropertyDescriptor)Parent_.GetProperties().Find(Name, false);
+
+ DynamicProperties_.Add(new DynamicPropertyDescriptor(Name, ParentDescriptor, Name, Attributes));
+ }
+ }
+}
Index: clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/DynamicPropertyConverter.cs
===================================================================
--- clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/DynamicPropertyConverter.cs
+++ clang-tools-extra/trunk/clang-tidy-vs/ClangTidy/DynamicPropertyConverter.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ class MagicInheritance
+ {
+ public static readonly string Value = "{3A27184D-1774-489B-9BB7-7191B8E8E622}";
+ public static readonly string Text = "";
+ }
+
+
+ class DynamicPropertyConverter : TypeConverter
+ {
+ private DynamicPropertyDescriptor Descriptor_;
+ private TypeConverter Root_;
+
+ public DynamicPropertyConverter(DynamicPropertyDescriptor Descriptor, TypeConverter Root)
+ {
+ Descriptor_ = Descriptor;
+ Root_ = Root;
+ }
+
+ ///
+ /// Returns true if there are specific values that can be chosen from a dropdown
+ /// for this property. Regardless of whether standard values are supported for
+ /// the underlying type, we always support standard values because we need to
+ /// display the inheritance option.
+ ///
+ /// true
+ public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ ///
+ /// Get the set of all standard values that can be chosen from a dropdown for this
+ /// property. If the underlying type supports standard values, we want to include
+ /// all those. Additionally, we want to display the option to inherit the value,
+ /// but only if the value is not already inheriting.
+ ///
+ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+ {
+ List