Skip to content
This repository has been archived by the owner on Jul 12, 2022. It is now read-only.

Allow codeformatter to use analyzers from external DLLs #217

Merged
merged 17 commits into from
Apr 12, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/CodeFormatter/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,35 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.0.0" newVersion="1.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.1.36.0" newVersion="1.1.36.0" />
<bindingRedirect oldVersion="0.0.0.0-1.1.37.0" newVersion="1.1.37.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.21.0" newVersion="1.0.21.0" />
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Desktop" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.0.0" newVersion="1.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Workspaces" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.0.0" newVersion="1.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp.Desktop" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-0.7.0.0" newVersion="0.7.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-0.7.0.0" newVersion="0.7.0.0" />
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp.Workspaces" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-0.7.0.0" newVersion="0.7.0.0" />
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Engine" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
Expand Down
51 changes: 51 additions & 0 deletions src/CodeFormatter/BasicAnalyzerAssemblyLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;

namespace CodeFormatter
{
public class BasicAnalyzerAssemblyLoader : IAnalyzerAssemblyLoader
{
private readonly Dictionary<string, Assembly> _pathsToAssemblies = new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, Assembly> _namesToAssemblies = new Dictionary<string, Assembly>();
private readonly List<string> _dependencyPaths = new List<string>();

public void AddDependencyLocation(string fullPath)
{
if (fullPath == null)
{
throw new ArgumentNullException(nameof(fullPath));
}

if (!_dependencyPaths.Contains(fullPath, StringComparer.OrdinalIgnoreCase))
{
_dependencyPaths.Add(fullPath);
}
}

public Assembly LoadFromPath(string fullPath)
{
if (fullPath == null)
{
throw new ArgumentNullException(nameof(fullPath));
}

Assembly assembly;
if (_pathsToAssemblies.TryGetValue(fullPath, out assembly))
{
return assembly;
}
else
{
assembly = Assembly.LoadFrom(fullPath);
_pathsToAssemblies[fullPath] = assembly;
_namesToAssemblies[assembly.FullName] = assembly;
return assembly;
}
}
}
}
34 changes: 18 additions & 16 deletions src/CodeFormatter/CodeFormatter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,33 @@
<HintPath>..\packages\CommandLineParser.2.0.273-beta\lib\net45\CommandLine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.1.1.1\lib\net45\Microsoft.CodeAnalysis.dll</HintPath>
<Reference Include="Microsoft.Build" />
<Reference Include="Microsoft.CodeAnalysis, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.1.2.0-beta1-20160226-01\lib\net45\Microsoft.CodeAnalysis.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.1.1.1\lib\net45\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.1.2.0-beta1-20160226-01\lib\net45\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.CSharp.Workspaces, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.1.1\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll</HintPath>
<Reference Include="Microsoft.CodeAnalysis.CSharp.Workspaces, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.2.0-beta1-20160226-01\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.VisualBasic, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.VisualBasic.1.1.1\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll</HintPath>
<Reference Include="Microsoft.CodeAnalysis.VisualBasic, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.VisualBasic.1.2.0-beta1-20160226-01\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.1.1\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll</HintPath>
<Reference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.2.0-beta1-20160226-01\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.Workspaces, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.1.1\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll</HintPath>
<Reference Include="Microsoft.CodeAnalysis.Workspaces, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.2.0-beta1-20160226-01\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.Workspaces.Desktop, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.1.1\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll</HintPath>
<Reference Include="Microsoft.CodeAnalysis.Workspaces.Desktop, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.2.0-beta1-20160226-01\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
Expand Down Expand Up @@ -75,8 +76,8 @@
<Private>True</Private>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.Reflection.Metadata, Version=1.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reflection.Metadata.1.1.0\lib\dotnet5.2\System.Reflection.Metadata.dll</HintPath>
<Reference Include="System.Reflection.Metadata, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reflection.Metadata.1.2.0-rc3-23811\lib\dotnet5.2\System.Reflection.Metadata.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
Expand All @@ -86,6 +87,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="BasicAnalyzerAssemblyLoader.cs" />
<Compile Include="ExportOptions.cs" />
<Compile Include="FormatOptions.cs" />
<Compile Include="ListOptions.cs" />
Expand Down
86 changes: 69 additions & 17 deletions src/CodeFormatter/FormatOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,58 +15,98 @@

namespace CodeFormatter
{
[Verb("format", HelpText = "Apply code formatting rules and analyzers to specified project.")]
internal class FormatOptions
internal class CommandLineOptions
{
[Value(
0,
HelpText = "Project, solution or response file to drive code formatting.",
HelpText = "Project, solution or response file to drive code formatting.",
Required = true)]
public IEnumerable<string> FormatTargets { get; set; }
public IEnumerable<string> Targets { get; set; }

[Option(
'o',
"options-file-path",
HelpText = "Path to an options file that should be used to configure analysis")]
public string OptionsFilePath { get; set; }

[Option(
"file-filters",
HelpText = "Only apply changes to files with specified name(s).",
"file-filters",
HelpText = "Only apply changes to files with specified name(s).",
Separator = ',')]
public IEnumerable<string> FileFilters { get; set; }

[Option(
'l', "lang",
'l', "lang",
HelpText = "Specifies the language to use when a response file is specified, e.g., 'C#', 'Visual Basic', ... (default: 'C#').")]
public string Language { get; set; }

[Option(
'c', "configs",
HelpText = "Comma-separated list of preprocessor configurations the formatter should run under.",
'c', "configs",
HelpText = "Comma-separated list of preprocessor configurations the formatter should run under.",
Separator = ',')]
public IEnumerable<string> PreprocessorConfigurations { get; set; }

[Option(
"copyright",
"copyright",
HelpText = "Specifies file containing copyright header.")]
public string CopyrightHeaderFile { get; set; }
public string CopyrightHeaderFile { get; set; }

[Option(
'v', "verbose",
'v', "verbose",
HelpText = "Verbose output.")]
public bool Verbose { get; set; }

[Option(
"define-dotnet_formatter",
"define-dotnet_formatter",
HelpText = "Define DOTNET_FORMATTER in order to allow #if !DOTNET_FORMATTER constructs in code (to opt out of reformatting).")]
public bool DefineDotNetFormatter { get; set; }

[Option(
"use-analyzers",
HelpText = "TEMPORARY: invoke built-in analyzers rather than rules to perform reformatting.")]
public bool UseAnalyzers { get; set; }

[Option(
"analyzer-list",
HelpText = "A file containing a newline separated list of analyzer assemblies to be run against the target source.")]
public string AnalyzerListFile { get; set; }

[Option(
"log-output-path",
HelpText = "Path to a file where analysis or format results will be logged.")]
public string LogOutputPath { get; set; }

public virtual bool ApplyFixes { get; }

private ImmutableArray<string> _analyzerListText;
public ImmutableArray<string> AnalyzerListText
{
get
{
if (_analyzerListText == null)
{
_analyzerListText = InitializeAnalyzerListText(AnalyzerListFile);
}
return _analyzerListText;
}
internal set
{
_analyzerListText = value;
}
}

private static ImmutableArray<string> InitializeAnalyzerListText(string analyzerListFile)
{
ImmutableArray<string> analyzerListText = new ImmutableArray<string>();

if (!String.IsNullOrEmpty(analyzerListFile))
{
analyzerListText = ImmutableArray.CreateRange(File.ReadAllLines(analyzerListFile));
}

return analyzerListText;
}

private ImmutableArray<string> _copyrightHeaderText;
public ImmutableArray<string> CopyrightHeaderText
{
Expand Down Expand Up @@ -122,12 +162,24 @@ private ImmutableDictionary<string, bool> BuildRuleMapFromOptions()
Debug.Assert(tokens.Length == 2);
Debug.Assert(tokens[1].Equals("Enabled"));

string rule = tokens[0];
string rule = tokens[0];
result[rule] = (bool)propertyBag[key];
}

_ruleMap = result.ToImmutableDictionary();
return _ruleMap;
}
}
}

[Verb("format", HelpText = "Apply code formatting rules and analyzers to specified targets.")]
internal class FormatOptions : CommandLineOptions
{
public override bool ApplyFixes { get { return true; } }
}

[Verb("analyze", HelpText = "Apply analyzers to specified targets but do not apply code fixes.")]
internal class AnalyzeOptions : CommandLineOptions
{
public override bool ApplyFixes { get { return false; } }
}
}
Loading