Skip to content
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
6 changes: 4 additions & 2 deletions src/Features/Core/Shared/Options/OrganizerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ internal partial class OrganizerOptions
{
public const string FeatureName = "Organizer";

[ExportOption]
public static readonly PerLanguageOption<bool> PlaceSystemNamespaceFirst = new PerLanguageOption<bool>(FeatureName, "PlaceSystemNamespaceFirst", defaultValue: true);
public static PerLanguageOption<bool> PlaceSystemNamespaceFirst
{
get { return Microsoft.CodeAnalysis.Editing.GenerationOptions.PlaceSystemNamespaceFirst; }
}

/// <summary>
/// This option is currently unused by Roslyn, but we might want to implement it in the
Expand Down
3 changes: 2 additions & 1 deletion src/Workspaces/CSharp/Portable/CSharpWorkspace.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
<DesignTime>True</DesignTime>
<DependentUpon>CSharpWorkspaceResources.resx</DependentUpon>
</Compile>
<Compile Include="Editing\CSharpImportAdder.cs" />
<Compile Include="Extensions\ArgumentSyntaxExtensions.cs" />
<Compile Include="Extensions\BaseArgumentListSyntaxExtensions.cs" />
<Compile Include="Extensions\BaseParameterListSyntaxExtensions.cs" />
Expand Down Expand Up @@ -266,4 +267,4 @@
<Import Project="..\..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration
Expand Down Expand Up @@ -3541,22 +3542,25 @@ public override SyntaxNode WithTypeArguments(SyntaxNode expression, IEnumerable<
switch (expression.Kind())
{
case SyntaxKind.IdentifierName:
case SyntaxKind.GenericName:
var sname = (SimpleNameSyntax)expression;
return SyntaxFactory.GenericName(sname.Identifier, SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(typeArguments.Cast<TypeSyntax>())));

case SyntaxKind.GenericName:
var gname = (GenericNameSyntax)expression;
return gname.WithTypeArgumentList(SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(typeArguments.Cast<TypeSyntax>())));

case SyntaxKind.QualifiedName:
var qname = (QualifiedNameSyntax)expression;
return SyntaxFactory.QualifiedName(qname.Left, (SimpleNameSyntax)WithTypeArguments(qname.Right, typeArguments));
return qname.WithRight((SimpleNameSyntax)WithTypeArguments(qname.Right, typeArguments));

case SyntaxKind.AliasQualifiedName:
var aname = (AliasQualifiedNameSyntax)expression;
return SyntaxFactory.AliasQualifiedName(aname.Alias, (SimpleNameSyntax)WithTypeArguments(aname.Name, typeArguments));
return aname.WithName((SimpleNameSyntax)WithTypeArguments(aname.Name, typeArguments));

case SyntaxKind.SimpleMemberAccessExpression:
case SyntaxKind.PointerMemberAccessExpression:
var sma = (MemberAccessExpressionSyntax)expression;
return SyntaxFactory.MemberAccessExpression(expression.Kind(), sma.Expression, (SimpleNameSyntax)WithTypeArguments(sma.Name, typeArguments));
return sma.WithName((SimpleNameSyntax)WithTypeArguments(sma.Name, typeArguments));

default:
return expression;
Expand All @@ -3565,7 +3569,7 @@ public override SyntaxNode WithTypeArguments(SyntaxNode expression, IEnumerable<

public override SyntaxNode QualifiedName(SyntaxNode left, SyntaxNode right)
{
return SyntaxFactory.QualifiedName((NameSyntax)left, (SimpleNameSyntax)right);
return SyntaxFactory.QualifiedName((NameSyntax)left, (SimpleNameSyntax)right).WithAdditionalAnnotations(Simplifier.Annotation);
}

public override SyntaxNode TypeExpression(ITypeSymbol typeSymbol)
Expand Down
84 changes: 84 additions & 0 deletions src/Workspaces/CSharp/Portable/Editing/CSharpImportAdder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Utilities;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Editing
{
[ExportLanguageService(typeof(ImportAdderService), LanguageNames.CSharp), Shared]
internal class CSharpImportAdder : ImportAdderService
{
protected override INamespaceSymbol GetImportedNamespaceSymbol(SyntaxNode import, SemanticModel model)
{
var @using = import as UsingDirectiveSyntax;
if (@using != null && @using.Alias == null)
{
return model.GetSymbolInfo(@using.Name).Symbol as INamespaceSymbol;
}

return null;
}

protected override INamespaceSymbol GetExplicitNamespaceSymbol(SyntaxNode node, SemanticModel model)
{
var name = node as QualifiedNameSyntax;
if (name != null)
{
return GetExplicitNamespaceSymbol(name, name.Left, model);
}

var memberAccess = node as MemberAccessExpressionSyntax;
if (memberAccess != null)
{
return GetExplicitNamespaceSymbol(memberAccess, memberAccess.Expression, model);
}

return null;
}

private INamespaceSymbol GetExplicitNamespaceSymbol(ExpressionSyntax fullName, ExpressionSyntax namespacePart, SemanticModel model)
{
// name must refer to something that is not a namespace, but be qualified with a namespace.
var symbol = model.GetSymbolInfo(fullName).Symbol;
var nsSymbol = model.GetSymbolInfo(namespacePart).Symbol as INamespaceSymbol;
if (symbol != null && symbol.Kind != SymbolKind.Namespace && nsSymbol != null)
{
// use the symbols containing namespace, and not the potentially less than fully qualified namespace in the full name expression.
var ns = symbol.ContainingNamespace;
if (ns != null)
{
return model.Compilation.GetCompilationNamespace(ns);
}
}

return null;
}

protected override SyntaxNode InsertNamespaceImport(SyntaxNode root, SyntaxGenerator gen, SyntaxNode import, OptionSet options)
{
var comparer = options.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp)
? UsingsAndExternAliasesDirectiveComparer.SystemFirstInstance
: UsingsAndExternAliasesDirectiveComparer.NormalInstance;

// find insertion point
foreach (var existingImport in gen.GetNamespaceImports(root))
{
if (comparer.Compare(import, existingImport) < 0)
{
return gen.InsertNodesBefore(root, existingImport, new[] { import });
}
}

return gen.AddNamespaceImports(root, import);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Utilities;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Simplification
Expand Down Expand Up @@ -161,5 +164,26 @@ protected override bool CanNodeBeSimplifiedWithoutSpeculation(SyntaxNode node)
{
return false;
}

private static readonly string CS8019_UnusedUsingDirective = "CS8019";

protected override void GetUnusedNamespaceImports(SemanticModel model, HashSet<SyntaxNode> namespaceImports, CancellationToken cancellationToken)
{
var root = model.SyntaxTree.GetRoot();
var diagnostics = model.GetDiagnostics(cancellationToken: cancellationToken);

foreach (var diagnostic in diagnostics)
{
if (diagnostic.Id == CS8019_UnusedUsingDirective)
{
var node = root.FindNode(diagnostic.Location.SourceSpan) as UsingDirectiveSyntax;

if (node != null)
{
namespaceImports.Add(node);
}
}
}
}
}
}
3 changes: 2 additions & 1 deletion src/Workspaces/CSharpTest/CSharpServicesTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,12 @@
<Compile Include="Formatting\FormattingMultipleSpanTests.cs" />
<Compile Include="Formatting\FormattingTests.cs" />
<Compile Include="Formatting\FormattingTriviaTests.cs" />
<Compile Include="CodeGeneration\AddImportsTests.cs" />
</ItemGroup>
<ImportGroup Label="Targets">
<Import Project="..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Imports.targets" />
<Import Project="..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="..\..\..\build\Roslyn.Toolsets.Xunit.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
Loading