仿真平台内核初版 -tlib库 包含<sparc arm riscv powerPC>
This commit is contained in:
217
tools/analyzers/RenodeClassMembersOrderFixProvider.cs
Normal file
217
tools/analyzers/RenodeClassMembersOrderFixProvider.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// Copyright (c) 2010-2025 Antmicro
|
||||
//
|
||||
// This file is licensed under the MIT License.
|
||||
// Full license text is available in 'licenses/MIT.txt'.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Composition;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CodeActions;
|
||||
using Microsoft.CodeAnalysis.CodeFixes;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Editing;
|
||||
|
||||
namespace Antmicro.Renode.CustomAnalyzers
|
||||
{
|
||||
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(RenodeClassMembersOrderFixProvider)), Shared]
|
||||
public class RenodeClassMembersOrderFixProvider : CodeFixProvider
|
||||
{
|
||||
public sealed override ImmutableArray<string> FixableDiagnosticIds =>
|
||||
ImmutableArray.Create(RenodeClassMembersOrderAnalyzer.DiagnosticId);
|
||||
|
||||
public override FixAllProvider GetFixAllProvider() =>
|
||||
FixAllProvider.Create(async (context, document, _) =>
|
||||
await FixDocumentClassMembersOrder(document, context.CancellationToken).ConfigureAwait(false));
|
||||
|
||||
public override Task RegisterCodeFixesAsync(CodeFixContext context)
|
||||
{
|
||||
var document = context.Document;
|
||||
// We have only one entry in FixableDiagnosticIds,
|
||||
// so there should be just one entry on the list.
|
||||
var diagnostic = context.Diagnostics.First();
|
||||
|
||||
var codeAction = CodeAction.Create(
|
||||
title: "Fix Renode class member order",
|
||||
createChangedDocument: c => FixSingleClassMemberOrder(document, diagnostic, c),
|
||||
equivalenceKey: "RenodeClassMemberOrder"
|
||||
);
|
||||
|
||||
context.RegisterCodeFix(codeAction, diagnostic);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task<Document> FixDocumentClassMembersOrder(
|
||||
Document document,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var editor = await DocumentEditor.CreateAsync(document, cancellationToken);
|
||||
|
||||
// This fix provider is capable of fixing members order also within nested calsses, on arbitrary level.
|
||||
// In order to do so, it must handle nested classes first. Since we list members recursively
|
||||
// in document prefix order, we just have to reverse list to start with nested classes.
|
||||
var classes = editor
|
||||
.OriginalRoot
|
||||
.DescendantNodes()
|
||||
.Where(node => node.IsKind(SyntaxKind.ClassDeclaration))
|
||||
.Reverse();
|
||||
|
||||
foreach(var cls in classes)
|
||||
{
|
||||
var currentRoot = editor.GetChangedRoot();
|
||||
|
||||
var declarations = cls
|
||||
.ChildNodes()
|
||||
.OfType<MemberDeclarationSyntax>();
|
||||
|
||||
// We first find all misplaced members and remove them from tree.
|
||||
// When we reinsert removed nodes to tree, they are treated as new nodes, so we cannot reference them
|
||||
// in tree operations (i.e. we cannot use them as reference when inserting new nodes).
|
||||
// We also remember all well ordered nodes to use them as references when we reinsert misplaced nodes.
|
||||
var wellOrderedMembers = new List<MemberDeclarationSyntax>();
|
||||
var misplacedMembers = new List<MemberDeclarationSyntax>();
|
||||
|
||||
var currentMember = RenodeClassMembersOrderAnalyzer.ClassMemberOrder.StaticConstructor;
|
||||
foreach(var declaration in declarations)
|
||||
{
|
||||
if(RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder(declaration, out var nextMember))
|
||||
{
|
||||
if(nextMember < currentMember)
|
||||
{
|
||||
misplacedMembers.Add(declaration);
|
||||
editor.RemoveNode(declaration, SyntaxRemoveOptions.KeepNoTrivia);
|
||||
}
|
||||
else
|
||||
{
|
||||
wellOrderedMembers.Add(declaration);
|
||||
currentMember = nextMember;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This class already satisfies Renode class members order rule
|
||||
if(misplacedMembers.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// We know that this class content will be modified, so we want to track this class
|
||||
// in case we need to move it later
|
||||
editor.TrackNode(cls);
|
||||
|
||||
// At this point all members stored in wellOrderedMembers and misplacedMembers
|
||||
// have corresponding ClassMemberOrder, so we no longer need to check every call
|
||||
// to RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder.
|
||||
misplacedMembers.Sort((lhs, rhs) =>
|
||||
{
|
||||
RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder(lhs, out var lhsOrder);
|
||||
RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder(rhs, out var rhsOrder);
|
||||
return lhsOrder.CompareTo(rhsOrder);
|
||||
});
|
||||
|
||||
// If we are here, we know that there is at least one correct memeber and at least one misplaced member.
|
||||
// So calling MoveNext on Enumerator is safe.
|
||||
var correctMemberEnumerator = wellOrderedMembers.GetEnumerator();
|
||||
correctMemberEnumerator.MoveNext();
|
||||
|
||||
var correctMember = correctMemberEnumerator.Current;
|
||||
RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder(correctMember, out var correctOrder);
|
||||
|
||||
// We keep last valid order to easily break loop
|
||||
RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder(wellOrderedMembers.Last(), out var lastCorrectOrder);
|
||||
|
||||
foreach(var misplacedMember in misplacedMembers)
|
||||
{
|
||||
RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder(misplacedMember, out var misplacedOrder);
|
||||
if(misplacedOrder > lastCorrectOrder)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
while(misplacedOrder > correctOrder)
|
||||
{
|
||||
correctMemberEnumerator.MoveNext();
|
||||
correctMember = correctMemberEnumerator.Current;
|
||||
RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder(correctMember, out correctOrder);
|
||||
}
|
||||
|
||||
var upToDateMember = currentRoot.GetCurrentNode(misplacedMember) ?? misplacedMember;
|
||||
editor.InsertBefore(correctMember, upToDateMember);
|
||||
}
|
||||
|
||||
// correctMember now points to the last valid member.
|
||||
// We have to perform InsertAfter on remaining misplaced nodes
|
||||
// in reverse order to keep valid members order.
|
||||
misplacedMembers.Reverse();
|
||||
foreach(var misplacedMember in misplacedMembers)
|
||||
{
|
||||
RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder(misplacedMember, out var misplacedOrder);
|
||||
if(misplacedOrder <= lastCorrectOrder)
|
||||
{
|
||||
break;
|
||||
}
|
||||
var upToDateMember = currentRoot.GetCurrentNode(misplacedMember) ?? misplacedMember;
|
||||
editor.InsertAfter(correctMember, upToDateMember);
|
||||
}
|
||||
}
|
||||
|
||||
return editor.GetChangedDocument();
|
||||
}
|
||||
|
||||
private async Task<Document> FixSingleClassMemberOrder(
|
||||
Document document,
|
||||
Diagnostic diagnostic,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var editor = await DocumentEditor.CreateAsync(document, cancellationToken);
|
||||
var root = editor.OriginalRoot;
|
||||
|
||||
var misplacedDeclaration = root
|
||||
.FindToken(diagnostic.Location.SourceSpan.Start)
|
||||
.Parent
|
||||
.AncestorsAndSelf()
|
||||
.OfType<MemberDeclarationSyntax>()
|
||||
.First();
|
||||
|
||||
if(!RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder(misplacedDeclaration, out var misplacedOrder))
|
||||
{
|
||||
return document;
|
||||
}
|
||||
|
||||
var classMembers = misplacedDeclaration
|
||||
.Parent
|
||||
.ChildNodes()
|
||||
.OfType<MemberDeclarationSyntax>();
|
||||
|
||||
editor.RemoveNode(misplacedDeclaration, SyntaxRemoveOptions.KeepNoTrivia);
|
||||
|
||||
var successor = classMembers
|
||||
.FirstOrDefault(
|
||||
node => RenodeClassMembersOrderAnalyzer.TryGetClassMemberOrder(node, out var correctOrder) && misplacedOrder <= correctOrder);
|
||||
|
||||
// If there isn't any member, that is greater or equal than misplaced declaration,
|
||||
// then it must be last declaration.
|
||||
if(successor == null)
|
||||
{
|
||||
editor.InsertAfter(classMembers.Last(), misplacedDeclaration);
|
||||
}
|
||||
else
|
||||
{
|
||||
editor.InsertBefore(successor, misplacedDeclaration);
|
||||
}
|
||||
|
||||
return editor.GetChangedDocument();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user