Skip to content

Commit

Permalink
Merge pull request #61293 from CyrusNajmabadi/attributeLookup
Browse files Browse the repository at this point in the history
Add helper for source generators to filter to nodes with attribute matching an attribute name
  • Loading branch information
CyrusNajmabadi committed Jun 14, 2022
2 parents d03120e + 303d0a1 commit 44c573d
Show file tree
Hide file tree
Showing 32 changed files with 7,221 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@

using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Linq;
using System.ComponentModel;
using Microsoft.CodeAnalysis.SourceGeneration;

namespace Microsoft.CodeAnalysis.CSharp
{
Expand Down Expand Up @@ -74,5 +75,7 @@ internal override SyntaxTree ParseGeneratedSourceText(GeneratedSourceText input,
internal override CommonMessageProvider MessageProvider => CSharp.MessageProvider.Instance;

internal override string SourceExtension => ".cs";

internal override ISyntaxHelper SyntaxHelper => CSharpSyntaxHelper.Instance;
}
}
101 changes: 101 additions & 0 deletions src/Compilers/CSharp/Portable/SourceGeneration/CSharpSyntaxHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.CodeAnalysis.SourceGeneration;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed class CSharpSyntaxHelper : AbstractSyntaxHelper
{
public static readonly ISyntaxHelper Instance = new CSharpSyntaxHelper();

private CSharpSyntaxHelper()
{
}

public override bool IsCaseSensitive
=> true;

public override bool IsValidIdentifier(string name)
=> SyntaxFacts.IsValidIdentifier(name);

public override bool IsAnyNamespaceBlock(SyntaxNode node)
=> node is BaseNamespaceDeclarationSyntax;

public override bool IsAttribute(SyntaxNode node)
=> node is AttributeSyntax;

public override SyntaxNode GetNameOfAttribute(SyntaxNode node)
=> ((AttributeSyntax)node).Name;

public override bool IsAttributeList(SyntaxNode node)
=> node is AttributeListSyntax;

public override void AddAttributeTargets(SyntaxNode node, ArrayBuilder<SyntaxNode> targets)
{
var attributeList = (AttributeListSyntax)node;
var container = attributeList.Parent;
RoslynDebug.AssertNotNull(container);

// For fields/events, the attribute applies to all the variables declared.
if (container is FieldDeclarationSyntax field)
targets.AddRange(field.Declaration.Variables);
else if (container is EventFieldDeclarationSyntax ev)
targets.AddRange(ev.Declaration.Variables);
else
targets.Add(container);
}

public override SeparatedSyntaxList<SyntaxNode> GetAttributesOfAttributeList(SyntaxNode node)
=> ((AttributeListSyntax)node).Attributes;

public override bool IsLambdaExpression(SyntaxNode node)
=> node is LambdaExpressionSyntax;

public override SyntaxToken GetUnqualifiedIdentifierOfName(SyntaxNode node)
=> ((NameSyntax)node).GetUnqualifiedName().Identifier;

public override void AddAliases(SyntaxNode node, ArrayBuilder<(string aliasName, string symbolName)> aliases, bool global)
{
if (node is CompilationUnitSyntax compilationUnit)
{
AddAliases(compilationUnit.Usings, aliases, global);
}
else if (node is BaseNamespaceDeclarationSyntax namespaceDeclaration)
{
AddAliases(namespaceDeclaration.Usings, aliases, global);
}
else
{
throw ExceptionUtilities.UnexpectedValue(node.Kind());
}
}

private static void AddAliases(SyntaxList<UsingDirectiveSyntax> usings, ArrayBuilder<(string aliasName, string symbolName)> aliases, bool global)
{
foreach (var usingDirective in usings)
{
if (usingDirective.Alias is null)
continue;

if (global != usingDirective.GlobalKeyword.Kind() is SyntaxKind.GlobalKeyword)
continue;

var aliasName = usingDirective.Alias.Name.Identifier.ValueText;
var symbolName = usingDirective.Name.GetUnqualifiedName().Identifier.ValueText;
aliases.Add((aliasName, symbolName));
}
}

public override void AddAliases(CompilationOptions compilation, ArrayBuilder<(string aliasName, string symbolName)> aliases)
{
// C# doesn't have global aliases at the compilation level.
return;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,15 @@ private void VisitNamedTypeWithoutNullability(INamedTypeSymbol symbol)
if (IncludeNamedType(symbol.ContainingType))
{
symbol.ContainingType.Accept(this.NotFirstVisitor);
AddPunctuation(SyntaxKind.DotToken);

if (format.CompilerInternalOptions.HasFlag(SymbolDisplayCompilerInternalOptions.UsePlusForNestedTypes))
{
AddPunctuation(SyntaxKind.PlusToken);
}
else
{
AddPunctuation(SyntaxKind.DotToken);
}
}
}

Expand Down
Loading

0 comments on commit 44c573d

Please sign in to comment.