Skip to content

Commit

Permalink
Add a clang-tidy visual studio extension.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Zachary Turner committed Sep 7, 2016
1 parent b7a619c commit 1122be8
Show file tree
Hide file tree
Showing 38 changed files with 3,309 additions and 0 deletions.
1 change: 1 addition & 0 deletions clang-tools-extra/CMakeLists.txt
Expand Up @@ -4,6 +4,7 @@ add_subdirectory(clang-reorder-fields)
add_subdirectory(modularize)
if(CLANG_ENABLE_STATIC_ANALYZER)
add_subdirectory(clang-tidy)
add_subdirectory(clang-tidy-vs)
endif()

add_subdirectory(clang-query)
Expand Down
7 changes: 7 additions & 0 deletions clang-tools-extra/clang-tidy-vs/.gitignore
@@ -0,0 +1,7 @@
obj/
bin/
.vs/
Key.snk
clang-tidy.exe
packages/
*.csproj.user
28 changes: 28 additions & 0 deletions clang-tools-extra/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()
22 changes: 22 additions & 0 deletions clang-tools-extra/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
70 changes: 70 additions & 0 deletions clang-tools-extra/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
{
/// <summary>
/// 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.
/// </summary>
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);
}
}
}
67 changes: 67 additions & 0 deletions clang-tools-extra/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; }
}

/// <summary>
/// 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.
/// </summary>
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<CheckRoot>(Reader);
Checks_ = Root.Checks;

HashSet<string> Names = new HashSet<string>();
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<CheckInfo> Checks
{
get
{
return Checks_;
}
}
}
}

0 comments on commit 1122be8

Please sign in to comment.