Skip to content
Draft
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<!-- Analyzers -->
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.12.0-beta1.25218.8" />
<!-- SilkTouch -->
<PackageVersion Include="ClangSharp.PInvokeGenerator" Version="20.1.2.4" />
<PackageVersion Include="ClangSharp.PInvokeGenerator" Version="21.1.8.3" />
<PackageVersion Include="CSharpier.Core" Version="0.30.2" />
<PackageVersion Include="Humanizer.Core" Version="2.14.1" />
<PackageVersion Include="Microsoft.Build.Locator" Version="1.11.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,40 @@ public class IdentifierRenamingTransformer : LocationTransformer
{
private ISymbol symbol = null!;

private readonly IReadOnlyDictionary<string, List<(ISymbol Symbol, string NewName)>> newNameLookup;
private readonly IReadOnlyDictionary<
string,
List<(ISymbol Symbol, string NewName)>
> newNameLookup;

/// <summary>
/// Creates a new IdentifierRenamingTransformer.
/// </summary>
/// <param name="newNames">The new names for each symbol</param>
public IdentifierRenamingTransformer(IEnumerable<(ISymbol Symbol, string NewName)> newNames) : this(CreateNameLookup(newNames)) {}
public IdentifierRenamingTransformer(IEnumerable<(ISymbol Symbol, string NewName)> newNames)
: this(CreateNameLookup(newNames)) { }

/// <summary>
/// Creates a new IdentifierRenamingTransformer.
/// </summary>
/// <param name="newNameLookup">The new names for each symbol grouped by symbol name.</param>
public IdentifierRenamingTransformer(IReadOnlyDictionary<string, List<(ISymbol Symbol, string NewName)>> newNameLookup)
public IdentifierRenamingTransformer(
IReadOnlyDictionary<string, List<(ISymbol Symbol, string NewName)>> newNameLookup
)
{
this.newNameLookup = newNameLookup;
}

/// <summary>
/// Creates a name lookup dictionary designed for <see cref="IdentifierRenamingTransformer"/>.
/// </summary>
public static IReadOnlyDictionary<string, List<(ISymbol Symbol, string NewName)>> CreateNameLookup(IEnumerable<(ISymbol Symbol, string NewName)> names)
public static IReadOnlyDictionary<
string,
List<(ISymbol Symbol, string NewName)>
> CreateNameLookup(IEnumerable<(ISymbol Symbol, string NewName)> names)
{
return names.GroupBy(t => t.Symbol.Name).ToDictionary(group => group.Key, group => group.ToList());
return names
.GroupBy(t => t.Symbol.Name)
.ToDictionary(group => group.Key, group => group.ToList());
}

/// <inheritdoc />
Expand Down Expand Up @@ -68,7 +79,7 @@ private SyntaxToken GetRenamed(ISymbol symbol, SyntaxToken currentNameIdentifier
return currentNameIdentifier;
}

// ----- Types -----
// ----- Types -----

/// <inheritdoc />
public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,50 @@ namespace Silk.NET.SilkTouch.Mods.LocationTransformation;
/// and modifies the nodes only when coming back up.
/// <br/>
/// Modifying nodes cause them to be detached from the semantic model (meaning no symbol information),
/// so this ensures that we gather all of the data we need before making changes.
/// so this ensures that we gather all the data we need before making changes.
/// </remarks>
/// <param name="symbols">Symbols to search for.</param>
/// <param name="transformers">Transformers to use on each found symbol reference.</param>
public class LocationTransformationRewriter(HashSet<ISymbol> symbols, List<LocationTransformer> transformers) : CSharpSyntaxRewriter
public class LocationTransformationRewriter : CSharpSyntaxRewriter
{
// Symbols can also be referenced within XML doc, which are trivia nodes.
/// <inheritdoc />
public override bool VisitIntoStructuredTrivia => true;

private readonly Dictionary<SyntaxNode, QueuedTransformation> queuedTransformations = new();
private readonly Dictionary<SyntaxNode, QueuedTransformation> _queuedTransformations = new();

/// <param name="Symbol">The symbol for the node.</param>
/// <param name="TransformerIndex">The index of the transformer that should be used when continuing the transformation process.</param>
private record struct QueuedTransformation(ISymbol Symbol, int TransformerIndex);

private readonly List<SyntaxNode> tempNodeList = new();
private readonly List<SyntaxNode> _tempNodeList = new();

/// <summary>
/// The semantic model of the currently processed document.
/// </summary>
private SemanticModel semanticModel = null!;
private SemanticModel _semanticModel = null!;

private readonly HashSet<ISymbol> _symbols;
private readonly List<LocationTransformer> _transformers;
private readonly HashSet<string> _relevantIdentifiers;

/// <param name="symbols">Symbols to search for.</param>
/// <param name="transformers">Transformers to use on each found symbol reference.</param>
public LocationTransformationRewriter(
HashSet<ISymbol> symbols,
List<LocationTransformer> transformers
)
{
_symbols = symbols;
_transformers = transformers;

// Used to skip symbol lookups
// Does not handle the omission of the "-Attribute" suffix, but generally, we don't need to transform attributes
_relevantIdentifiers = _symbols.Select(s => s.Name).ToHashSet();
}

/// <summary>
/// Initializes the renamer to work for a new document. Must be called before visiting any nodes.
/// </summary>
public void Initialize(SemanticModel semanticModel)
{
this.semanticModel = semanticModel;
}
public void Initialize(SemanticModel semanticModel) => _semanticModel = semanticModel;

/// <inheritdoc />
[return: NotNullIfNotNull("unmodifiedNode")]
Expand All @@ -60,24 +74,25 @@ public void Initialize(SemanticModel semanticModel)
// Check for queued transformation
// To apply a transformation, we must be in the same level in the hierarchy as the selected node
// We also must apply transformations when going back up in the hierarchy so we don't overwrite previous transformations
if (queuedTransformations.Remove(unmodifiedNode, out var transformation))
if (_queuedTransformations.Remove(unmodifiedNode, out var transformation))
{
if (transformation.TransformerIndex >= 0)
{
// Apply deferred transformer
var deferredTransformer = transformers[transformation.TransformerIndex];
modifiedNode = deferredTransformer.Visit(modifiedNode)
var deferredTransformer = _transformers[transformation.TransformerIndex];
modifiedNode = deferredTransformer
.Visit(modifiedNode)
.WithLeadingTrivia(unmodifiedNode.GetLeadingTrivia().Select(VisitTrivia))
.WithTrailingTrivia(unmodifiedNode.GetTrailingTrivia());
}

// Continue applying remaining transformers
for (var i = transformation.TransformerIndex + 1; i < transformers.Count; i++)
for (var i = transformation.TransformerIndex + 1; i < _transformers.Count; i++)
{
var transformer = transformers[i];
var transformer = _transformers[i];

// Calculate hierarchy
var hierarchy = tempNodeList;
var hierarchy = _tempNodeList;
{
hierarchy.Clear();

Expand Down Expand Up @@ -105,13 +120,17 @@ public void Initialize(SemanticModel semanticModel)
{
// We can't directly transform the node since we are at the wrong place in the hierarchy
// Defer it so it is processed later
queuedTransformations.Add(selectedNode, new QueuedTransformation(transformation.Symbol, i));
_queuedTransformations.Add(
selectedNode,
new QueuedTransformation(transformation.Symbol, i)
);

break;
}

// Transform the node
modifiedNode = transformer.Visit(modifiedNode)
modifiedNode = transformer
.Visit(modifiedNode)
.WithLeadingTrivia(unmodifiedNode.GetLeadingTrivia().Select(VisitTrivia))
.WithTrailingTrivia(unmodifiedNode.GetTrailingTrivia());
}
Expand All @@ -122,20 +141,20 @@ public void Initialize(SemanticModel semanticModel)

private void ReportSymbol(SyntaxNode node, ISymbol? symbol)
{
if (symbol == null || !symbols.Contains(symbol))
if (symbol == null || !_symbols.Contains(symbol))
{
return;
}

queuedTransformations.Add(node, new QueuedTransformation(symbol, -1));
_queuedTransformations.Add(node, new QueuedTransformation(symbol, -1));
}

// ----- Types -----

/// <inheritdoc />
public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitClassDeclaration(node)!;
Expand All @@ -144,7 +163,7 @@ public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
/// <inheritdoc />
public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitStructDeclaration(node)!;
Expand All @@ -153,7 +172,7 @@ public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node)
/// <inheritdoc />
public override SyntaxNode VisitInterfaceDeclaration(InterfaceDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitInterfaceDeclaration(node)!;
Expand All @@ -162,7 +181,7 @@ public override SyntaxNode VisitInterfaceDeclaration(InterfaceDeclarationSyntax
/// <inheritdoc />
public override SyntaxNode VisitRecordDeclaration(RecordDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitRecordDeclaration(node)!;
Expand All @@ -171,7 +190,7 @@ public override SyntaxNode VisitRecordDeclaration(RecordDeclarationSyntax node)
/// <inheritdoc />
public override SyntaxNode VisitDelegateDeclaration(DelegateDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitDelegateDeclaration(node)!;
Expand All @@ -180,7 +199,7 @@ public override SyntaxNode VisitDelegateDeclaration(DelegateDeclarationSyntax no
/// <inheritdoc />
public override SyntaxNode VisitEnumDeclaration(EnumDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitEnumDeclaration(node)!;
Expand All @@ -191,7 +210,7 @@ public override SyntaxNode VisitEnumDeclaration(EnumDeclarationSyntax node)
/// <inheritdoc />
public override SyntaxNode VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitEnumMemberDeclaration(node)!;
Expand All @@ -200,7 +219,7 @@ public override SyntaxNode VisitEnumMemberDeclaration(EnumMemberDeclarationSynta
/// <inheritdoc />
public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitPropertyDeclaration(node)!;
Expand All @@ -209,7 +228,7 @@ public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax no
/// <inheritdoc />
public override SyntaxNode VisitEventDeclaration(EventDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitEventDeclaration(node)!;
Expand All @@ -218,7 +237,7 @@ public override SyntaxNode VisitEventDeclaration(EventDeclarationSyntax node)
/// <inheritdoc />
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitMethodDeclaration(node)!;
Expand All @@ -227,7 +246,7 @@ public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
/// <inheritdoc />
public override SyntaxNode VisitConstructorDeclaration(ConstructorDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitConstructorDeclaration(node)!;
Expand All @@ -236,7 +255,7 @@ public override SyntaxNode VisitConstructorDeclaration(ConstructorDeclarationSyn
/// <inheritdoc />
public override SyntaxNode VisitDestructorDeclaration(DestructorDeclarationSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitDestructorDeclaration(node)!;
Expand All @@ -247,7 +266,12 @@ public override SyntaxNode VisitDestructorDeclaration(DestructorDeclarationSynta
/// <inheritdoc />
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node)
{
var symbol = semanticModel.GetSymbolInfo(node).Symbol ?? semanticModel.GetTypeInfo(node).Type;
if (!_relevantIdentifiers.Contains(node.Identifier.Text))
{
return node;
}

var symbol = _semanticModel.GetSymbolInfo(node).Symbol;
ReportSymbol(node, symbol);

return base.VisitIdentifierName(node)!;
Expand All @@ -257,9 +281,14 @@ public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node)
/// <inheritdoc />
public override SyntaxNode VisitVariableDeclarator(VariableDeclaratorSyntax node)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
var symbol = _semanticModel.GetDeclaredSymbol(node);
ReportSymbol(node, symbol);

return base.VisitVariableDeclarator(node)!;
}

// ----- Skipped nodes -----

/// <inheritdoc />
public override SyntaxNode VisitUsingDirective(UsingDirectiveSyntax node) => node;
}
Loading
Loading