Skip to content
This repository was archived by the owner on Jun 30, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Improved and completed the proxy codefix for C# and VB
The preview now works with project references and in VB too.
  • Loading branch information
kzu committed Jul 6, 2017
commit 301fae66cee7f82163bbc7899afaded703f54bea
14 changes: 12 additions & 2 deletions src/Analyzer.Vsix/Moq.Analyzer.Vsix.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,22 @@
<CopyOutputSymbolsToOutputDirectory>false</CopyOutputSymbolsToOutputDirectory>
<VSSDKTargetPlatformRegRootSuffix>Moq</VSSDKTargetPlatformRegRootSuffix>

<TargetVsixContainerName>Moq.Analyzer.vsix</TargetVsixContainerName>
<TargetVsixContainerName>Moq.vsix</TargetVsixContainerName>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="15.1.192" />
<Content Include="Properties\launchSettings.json" />
</ItemGroup>

<ItemGroup>
<None Include="BindingRedirects.targets" />
<None Include="Moq.Analyzer.Vsix.targets" />
<None Include="source.extension.vsixmanifest" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="15.1.192" Condition="'$(BuildingInsideVisualStudio)' != 'true'" />
<PackageReference Include="Xamarin.VSSDK.BuildTools" Version="0.2.1-alpha-build0001" />
<PackageReference Include="Roslynator" Version="0.2.3" />
</ItemGroup>
Expand Down
13 changes: 13 additions & 0 deletions src/Analyzer.Vsix/Moq.Analyzer.Vsix.targets
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,17 @@
</ItemGroup>
</Target>

<!-- Additional items we don't want XVS to ship at all -->
<Target Name="ExcludeVisualStudioAssemblies"
DependsOnTargets="GetVsixSourceItems"
BeforeTargets="RemoveVSSDKAssemblies"
Condition="'$(IncludeCopyLocalReferencesInVSIXContainer)' == 'true'">
<ItemGroup>
<SuppressPackaging Include="@(VSIXSourceItem)"
Condition=" $([System.String]::new('%(Filename)').StartsWith('Microsoft.VisualStudio')) " />
<SuppressPackaging Include="@(VSIXSourceItem)"
Condition=" $([System.String]::new('%(Filename)').StartsWith('System.')) " />
</ItemGroup>
</Target>

</Project>
1 change: 0 additions & 1 deletion src/Analyzer.Vsix/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="File" Path="Moq.Sdk.Generator.dll"/>
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="File" Path="Moq.Analyzer.dll"/>
<Asset Type="Microsoft.VisualStudio.Analyzer" d:Source="File" Path="Moq.Analyzer.dll"/>
<!--<Asset Type="Microsoft.VisualStudio.Analyzer" d:Source="File" Path="Roslyn.Services.Editor.UnitTests.dll" />-->
<!--<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="File" Path="BindingRedirects.pkgdef" />-->
</Assets>
<Prerequisites>
Expand Down
56 changes: 34 additions & 22 deletions src/Analyzer/MissingProxyCodeFix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,18 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host;
using System.IO;
using Microsoft.CodeAnalysis.Text;
using Moq.Analyzer.Properties;
using Moq.Proxy;
using Microsoft.CodeAnalysis.Editing;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Formatting;

namespace Moq.Analyzer
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(MissingProxyCodeFix)), Shared]
[ExportCodeFixProvider(LanguageNames.CSharp, new [] { LanguageNames.VisualBasic }, Name = nameof(MissingProxyCodeFix)), Shared]
public class MissingProxyCodeFix : CodeFixProvider
{
ICodeAnalysisServices analysisServices;
Expand All @@ -47,10 +42,12 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
var sourceToken = root.FindToken(diagnostic.Location.SourceSpan.Start);

// Find the invocation identified by the diagnostic.
var invocation = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<InvocationExpressionSyntax>().First();
var invocation =
(SyntaxNode)sourceToken.Parent.AncestorsAndSelf().OfType<Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax>().FirstOrDefault() ??
(SyntaxNode)sourceToken.Parent.AncestorsAndSelf().OfType<Microsoft.CodeAnalysis.VisualBasic.Syntax.InvocationExpressionSyntax>().FirstOrDefault();

// Register a code action that will invoke the fix.
context.RegisterCodeFix(
Expand All @@ -61,7 +58,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
diagnostic);
}

async Task<Solution> GenerateProxyAsync(Document document, InvocationExpressionSyntax invocation, CancellationToken cancellationToken)
async Task<Solution> GenerateProxyAsync(Document document, SyntaxNode invocation, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
var symbol = semanticModel.GetSymbolInfo(invocation);
Expand All @@ -73,32 +70,47 @@ async Task<Solution> GenerateProxyAsync(Document document, InvocationExpressionS
var (name, syntax) = ProxyGenerator.CreateProxy(method.TypeArguments, generator);

var code = syntax.NormalizeWhitespace().ToFullString();
var workspace = document.Project.Solution.Workspace;

var workspace = new AdhocWorkspace(document.Project.Solution.Workspace.Services.HostServices, "Proxy");
var info = ProjectInfo.Create(
ProjectId.CreateNewId(),
var projectId = ProjectId.CreateNewId();
var solution = workspace.CurrentSolution.AddProject(ProjectInfo.Create(
projectId,
VersionStamp.Create(),
"Proxy",
"Proxy",
document.Project.Language,
compilationOptions: document.Project.CompilationOptions,
parseOptions: document.Project.ParseOptions,
metadataReferences: document.Project.MetadataReferences);
var project = workspace.AddProject(info);
var file = Path.Combine(Path.GetDirectoryName(document.Project.FilePath), ProxyGenerator.ProxyNamespace, name + ".cs");
var proxy = project.AddDocument(Path.GetFileName(file),
SourceText.From(code),
new[] { "Proxies" },
file);
documents: document.Project.Documents
.Where(d => d.Id != document.Id)
.Select(d => DocumentInfo.Create(
DocumentId.CreateNewId(projectId), d.Name, d.Folders, d.SourceCodeKind, filePath: d.FilePath)),
projectReferences: document.Project.ProjectReferences,
metadataReferences: document.Project.MetadataReferences));

var extension = document.Project.Language == LanguageNames.CSharp ? ".cs" : ".vb";
var file = Path.Combine(Path.GetDirectoryName(document.Project.FilePath), ProxyGenerator.ProxyNamespace, name + extension);
var docId = DocumentId.CreateNewId(projectId);
solution = solution.AddDocument(DocumentInfo.Create(
docId,
Path.GetFileName(file),
filePath: file,
folders: new[] { "Proxies" },
loader: TextLoader.From(TextAndVersion.Create(SourceText.From(code), VersionStamp.Create()))));

var proxy = solution.GetDocument(docId);

proxy = await ProxyGenerator.ApplyVisitors(proxy, analysisServices, cancellationToken);
// This is somewhat expensive, but since we're adding it to the user' solution, we might
// as well make it look great ;)
proxy = await Simplifier.ReduceAsync(proxy);
proxy = await Formatter.FormatAsync(proxy);
syntax = await proxy.GetSyntaxRootAsync();

var output = syntax.NormalizeWhitespace().ToFullString();
code = syntax.NormalizeWhitespace().ToFullString();

return document.Project.AddDocument(Path.GetFileName(file),
output,
code,
new[] { "Proxies" },
file)
.Project.Solution;
Expand Down
1 change: 1 addition & 0 deletions src/Moq.Sdk.sln
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
..\build.proj = ..\build.proj
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
Version.targets = Version.targets
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Moq.Proxy.Generator.Console", "Proxy\Proxy.Generator.Console\Moq.Proxy.Generator.Console.csproj", "{886905FA-99B0-48E8-BD3E-6C6ED96CE69F}"
Expand Down
14 changes: 9 additions & 5 deletions src/Proxy/Proxy.Generator/Rewrite/VisualBasicProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ class VisualBasicProxy : VisualBasicSyntaxRewriter, IDocumentVisitor
return document.WithSyntaxRoot(syntax);
}

// The namespace for the proxy should be global, just like C#
public override SyntaxNode VisitNamespaceStatement(NamespaceStatementSyntax node)
=> base.VisitNamespaceStatement(node.WithName(ParseName("Global." + ProxyGenerator.ProxyNamespace)));


public override SyntaxNode VisitClassBlock(ClassBlockSyntax node)
{
// Turn event fields into event declarations.
Expand Down Expand Up @@ -68,10 +73,9 @@ public override SyntaxNode VisitClassBlock(ClassBlockSyntax node)
});
}

node = (ClassBlockSyntax)base.VisitClassBlock(node);

// Add the IProxy implementation last so it's not visited.
node = node.AddImplements(ImplementsStatement(IdentifierName(nameof(IProxy))));
node = (ClassBlockSyntax)generator.AddInterfaceType(
base.VisitClassBlock(node),
generator.IdentifierName(nameof(IProxy)));

var field = generator.FieldDeclaration(
"pipeline",
Expand All @@ -94,7 +98,7 @@ public override SyntaxNode VisitClassBlock(ClassBlockSyntax node)
property.PropertyStatement.WithImplementsClause(
ImplementsClause(QualifiedName(IdentifierName(nameof(IProxy)), IdentifierName(nameof(IProxy.Behaviors))))));

return generator.InsertMembers(node, 0, field, property);
return generator.AddMembers(node, field, property);
}

public override SyntaxNode VisitMethodBlock(MethodBlockSyntax node)
Expand Down
6 changes: 3 additions & 3 deletions src/Proxy/Proxy.Generator/Scaffold/CSharpCodeFixes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ class CSharpCodeFixes : CodeFixDocumentVisitor
[ImportingConstructor]
public CSharpCodeFixes(ICodeAnalysisServices services)
: base(services,
CodeFixNames.All.SimplifyNames,
CodeFixNames.All.RemoveUnnecessaryImports,
CodeFixNames.CSharp.ImplementAbstractClass,
CodeFixNames.CSharp.ImplementInterface)
CodeFixNames.CSharp.ImplementInterface,
CodeFixNames.All.SimplifyNames,
CodeFixNames.All.RemoveUnnecessaryImports)
{
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/Proxy/Proxy.Generator/Scaffold/VisualBasicCodeFixes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ class VisualBasicCodeFixes : CodeFixDocumentVisitor
[ImportingConstructor]
public VisualBasicCodeFixes(ICodeAnalysisServices services)
: base(services,
CodeFixNames.All.SimplifyNames,
CodeFixNames.All.RemoveUnnecessaryImports,
CodeFixNames.VisualBasic.ImplementAbstractClass,
CodeFixNames.VisualBasic.ImplementInterface,
CodeFixNames.VisualBasic.AddOverloads)
CodeFixNames.VisualBasic.AddOverloads,
CodeFixNames.All.SimplifyNames,
CodeFixNames.All.RemoveUnnecessaryImports)
{
}
}
Expand Down
78 changes: 0 additions & 78 deletions src/Sdk.Generator/CSharpFixup.cs

This file was deleted.

33 changes: 0 additions & 33 deletions src/Sdk.Generator/CSharpPrepare.cs

This file was deleted.

Loading