From 39d6efa8d0eac17ccfedac59107cd0d5c4cf06cc Mon Sep 17 00:00:00 2001 From: Chris Long Date: Thu, 28 Apr 2022 15:46:29 -0700 Subject: [PATCH 01/61] Add startup file creation for vb projects --- .../ActionHelpers/FolderUpdate.cs | 27 ++++++++++++------- .../Utils/VisualBasicUtils.cs | 17 ++++++++++++ src/CTA.Rules.Models/Enums.cs | 7 +++++ tst/CTA.Rules.Test/FolderUpdateTests.cs | 20 ++++++++++++++ tst/CTA.Rules.Test/UtilsTest.cs | 8 ++++++ 5 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 src/CTA.Rules.Common/Utils/VisualBasicUtils.cs diff --git a/src/CTA.Rules.Actions/ActionHelpers/FolderUpdate.cs b/src/CTA.Rules.Actions/ActionHelpers/FolderUpdate.cs index f33f879a..f3b751ea 100644 --- a/src/CTA.Rules.Actions/ActionHelpers/FolderUpdate.cs +++ b/src/CTA.Rules.Actions/ActionHelpers/FolderUpdate.cs @@ -1,4 +1,5 @@ using System.IO; +using CTA.Rules.Common.Helpers; using CTA.Rules.Config; using CTA.Rules.Models; @@ -9,12 +10,17 @@ public class FolderUpdate private readonly string _projectDir; private readonly string _projectFile; private readonly ProjectType _projectType; + private readonly string _codeFileExtension; public FolderUpdate(string projectFile, ProjectType projectType) { _projectFile = projectFile; _projectDir = Directory.GetParent(_projectFile).FullName; _projectType = projectType; + _codeFileExtension = + VisualBasicUtils.IsVisualBasicProject(projectFile) + ? FileExtension.VisualBasic + : FileExtension.CSharp; } //TODO Is there a better way to do this? @@ -37,25 +43,25 @@ public string Run() CreateMvcDirs(_projectDir); CreateStartupFiles(_projectDir, _projectType, FileTypeCreation.Program); CreateStartupFiles(_projectDir, _projectType, FileTypeCreation.Startup); - runResult = "Mvc project detected. Created static files, Program.cs, and Startup.cs"; + runResult = $"Mvc project detected. Created static files, Program{_codeFileExtension} and Startup{_codeFileExtension}"; } if (_projectType == ProjectType.WebApi) { CreateStartupFiles(_projectDir, _projectType, FileTypeCreation.Program); CreateStartupFiles(_projectDir, _projectType, FileTypeCreation.Startup); - runResult = "Web API project detected. Created Program.cs and Startup.cs"; + runResult = $"Web API project detected. Created Program{_codeFileExtension} and Startup{_codeFileExtension}"; } if (_projectType == ProjectType.WCFConfigBasedService) { CreateStartupFiles(_projectDir, _projectType, FileTypeCreation.Program); CreateStartupFiles(_projectDir, _projectType, FileTypeCreation.Startup); - runResult = "WCF Config Based Service Project detected. Created Program.cs and Startup.cs"; + runResult = $"WCF Config Based Service Project detected. Created Program{_codeFileExtension} and Startup{_codeFileExtension}"; } if (_projectType == ProjectType.WCFCodeBasedService) { CreateStartupFiles(_projectDir, _projectType, FileTypeCreation.Program); CreateStartupFiles(_projectDir, _projectType, FileTypeCreation.Startup); - runResult = "WCF Code Based Service Project detected. Created Program.cs and Startup.cs"; + runResult = $"WCF Code Based Service Project detected. Created Program{_codeFileExtension} and Startup{_codeFileExtension}"; } return runResult; } @@ -69,14 +75,14 @@ private void CreateStartupFiles(string projectDir, ProjectType projectType, File { string projectNamespace = GetProjectNamespace(); - var file = Path.Combine(projectDir, string.Concat(fileType.ToString(), ".cs")); + var file = Path.Combine(projectDir, string.Concat(fileType.ToString(), _codeFileExtension)); if (File.Exists(file)) { - File.Move(file, string.Concat(file, ".bak")); + File.Move(file, string.Concat(file, FileExtension.Backup)); } - File.WriteAllText(file, GetStartupFileContent(projectNamespace, projectType, fileType)); + File.WriteAllText(file, GetStartupFileContent(projectNamespace, projectType, fileType, _codeFileExtension)); - LogChange(string.Format("Created {0}.cs file using {1} template", fileType.ToString(), projectType.ToString())); + LogChange(string.Format("Created {0}{2} file using {1} template", fileType.ToString(), projectType.ToString(), _codeFileExtension)); } /// @@ -85,10 +91,11 @@ private void CreateStartupFiles(string projectDir, ProjectType projectType, File /// The project namespace /// The project type /// Type of the file to be retrieved + /// Extension of file to be retrieved /// The content of the startup file - private string GetStartupFileContent(string projectNamespace, ProjectType projectType, FileTypeCreation fileType) + private string GetStartupFileContent(string projectNamespace, ProjectType projectType, FileTypeCreation fileType, string fileExtension) { - return TemplateHelper.GetTemplateFileContent(projectNamespace, projectType, fileType.ToString() + ".cs"); + return TemplateHelper.GetTemplateFileContent(projectNamespace, projectType, fileType.ToString() + fileExtension); } /// diff --git a/src/CTA.Rules.Common/Utils/VisualBasicUtils.cs b/src/CTA.Rules.Common/Utils/VisualBasicUtils.cs new file mode 100644 index 00000000..70e83c81 --- /dev/null +++ b/src/CTA.Rules.Common/Utils/VisualBasicUtils.cs @@ -0,0 +1,17 @@ + + +namespace CTA.Rules.Common.Helpers +{ + public class VisualBasicUtils + { + /// + /// Checks project file for visual basic project extension + /// + /// projectFilePath + /// True if the file path contains the visual basic project extension + public static bool IsVisualBasicProject(string projectFilePath) + { + return projectFilePath.Contains("vbproj"); + } + } +} diff --git a/src/CTA.Rules.Models/Enums.cs b/src/CTA.Rules.Models/Enums.cs index 77a6adf7..315b4207 100644 --- a/src/CTA.Rules.Models/Enums.cs +++ b/src/CTA.Rules.Models/Enums.cs @@ -68,4 +68,11 @@ public enum WebFormsActionType ClassConversion, FileConversion } + + public static class FileExtension + { + public static readonly string VisualBasic = ".vb"; + public static readonly string CSharp = ".cs"; + public static readonly string Backup = ".bak"; + } } diff --git a/tst/CTA.Rules.Test/FolderUpdateTests.cs b/tst/CTA.Rules.Test/FolderUpdateTests.cs index b7813570..49760246 100644 --- a/tst/CTA.Rules.Test/FolderUpdateTests.cs +++ b/tst/CTA.Rules.Test/FolderUpdateTests.cs @@ -13,6 +13,8 @@ public class FolderUpdateTests Directory.GetCurrentDirectory(), "TestProject"); private string _testProjectPath = Path.Combine( Directory.GetCurrentDirectory(), "TestProject", "TestProject.csproj"); + private string _vbTestProjectPath = Path.Combine( + Directory.GetCurrentDirectory(), "TestProject", "TestProject.vbproj"); [SetUp] public void Setup() @@ -196,5 +198,23 @@ public void Folder_Update_for_WebApi_Project() Cleanup(_testProjectDir); } + + [Test] + public void Folder_Update_for_WebApi_Project_Vb() + { + // Run FolderUpdate on the test project + ProjectType projectType = ProjectType.WebApi; + FolderUpdate folderUpdate = new FolderUpdate( + _vbTestProjectPath, projectType); + folderUpdate.Run(); + + // Validate Program.cs and Startup.cs files are created + Assert.True(File.Exists(Path.Combine( + _testProjectDir, FileTypeCreation.Program.ToString() + FileExtension.VisualBasic))); + Assert.True(File.Exists(Path.Combine( + _testProjectDir, FileTypeCreation.Startup.ToString() + FileExtension.VisualBasic))); + + Cleanup(_testProjectDir); + } } } diff --git a/tst/CTA.Rules.Test/UtilsTest.cs b/tst/CTA.Rules.Test/UtilsTest.cs index 01a48f2e..a8e526a6 100644 --- a/tst/CTA.Rules.Test/UtilsTest.cs +++ b/tst/CTA.Rules.Test/UtilsTest.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using CTA.Rules.Common.Helpers; namespace CTA.Rules.Test { @@ -112,5 +113,12 @@ public void ThreadSafeExportStringToFile_Permits_Concurrent_Processes() // Confirm that text was written to file Assert.AreEqual(content, File.ReadAllText(filePath)); } + + [Test] + public void Test_Is_VisualBasic_Project() + { + Assert.IsFalse(VisualBasicUtils.IsVisualBasicProject("test.csproj")); + Assert.IsTrue(VisualBasicUtils.IsVisualBasicProject("C://user/john/repos/test.vbproj")); + } } } \ No newline at end of file From 1937d441dfa680823b822baf2aa8438fea370f6f Mon Sep 17 00:00:00 2001 From: Chris Long Date: Mon, 9 May 2022 13:39:03 -0700 Subject: [PATCH 02/61] Add project language property to rule file load and parsing --- src/CTA.Rules.Models/Enums.cs | 6 ++++++ src/CTA.Rules.RuleFiles/RulesFileLoader.cs | 9 ++++++--- src/CTA.Rules.RuleFiles/RulesFileParser.cs | 20 ++++++++++++++++--- .../ProjectRewriters/ProjectRewriter.cs | 7 +++++-- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/CTA.Rules.Models/Enums.cs b/src/CTA.Rules.Models/Enums.cs index 315b4207..2248629a 100644 --- a/src/CTA.Rules.Models/Enums.cs +++ b/src/CTA.Rules.Models/Enums.cs @@ -69,6 +69,12 @@ public enum WebFormsActionType FileConversion } + public enum ProjectLanguage + { + VisualBasic, + Csharp, + } + public static class FileExtension { public static readonly string VisualBasic = ".vb"; diff --git a/src/CTA.Rules.RuleFiles/RulesFileLoader.cs b/src/CTA.Rules.RuleFiles/RulesFileLoader.cs index e8d09199..e59c7349 100644 --- a/src/CTA.Rules.RuleFiles/RulesFileLoader.cs +++ b/src/CTA.Rules.RuleFiles/RulesFileLoader.cs @@ -20,6 +20,7 @@ public class RulesFileLoader private readonly string _overrideFile; private readonly string _assembliesDir; private readonly IEnumerable _projectReferences; + private readonly ProjectLanguage _projectLanguage; /// /// Initializes a new RulesFileLoader @@ -29,7 +30,8 @@ public class RulesFileLoader /// Target framework to port to /// Path to rules file containing override rules. The override rules will be added to the built in rules, overriding any matching existing rules /// Directory containing assemblies containing additional actions - public RulesFileLoader(IEnumerable projectReferences, string rulesFilesDir, List targetFramework, string overrideFile = "", string assembliesDir = "") + /// The language the project is written in, C# or VB + public RulesFileLoader(IEnumerable projectReferences, string rulesFilesDir, List targetFramework, ProjectLanguage projectLanguage, string overrideFile = "", string assembliesDir = "") { _rulesFilesDir = rulesFilesDir; try @@ -48,6 +50,7 @@ public RulesFileLoader(IEnumerable projectReferences, string rulesFil _overrideFile = overrideFile; _assembliesDir = assembliesDir; _projectReferences = projectReferences; + _projectLanguage = projectLanguage; } /// @@ -115,8 +118,8 @@ public RootNodes Load() mainFileTask.Result, overrideTask.Result, _assembliesDir, - _targetFramework - ); + _targetFramework, + _projectLanguage); var rootNodes = rulesFileParser.Process(); return rootNodes; diff --git a/src/CTA.Rules.RuleFiles/RulesFileParser.cs b/src/CTA.Rules.RuleFiles/RulesFileParser.cs index a83d34d7..8b18e81d 100644 --- a/src/CTA.Rules.RuleFiles/RulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/RulesFileParser.cs @@ -26,14 +26,27 @@ public class RulesFileParser private readonly NamespaceRecommendations _namespaceRecommendations; private readonly NamespaceRecommendations _overrideNamespaceRecommendations; + private readonly ProjectLanguage _projectLanguage; + /// /// Runs the rules parser /// + /// Override namespace recommendations /// Object containing built in rules /// Object containing override rules /// Directory containing additional actions assemblies - public RulesFileParser(NamespaceRecommendations namespaceRecommendations, NamespaceRecommendations overrideNamespaceRecommendations, - Rootobject rulesObject, Rootobject overrideObject, string assembliesDir, string targetFramework) + /// Namespace recommendations + /// Framework version being targeted for porting + /// Project language, C# or VB + /// + public RulesFileParser( + NamespaceRecommendations namespaceRecommendations, + NamespaceRecommendations overrideNamespaceRecommendations, + Rootobject rulesObject, + Rootobject overrideObject, + string assembliesDir, + string targetFramework, + ProjectLanguage projectLanguage) { _rootNodes = new RootNodes(); _rootNodes.ProjectTokens.Add(new ProjectToken() { Key = "Project" }); @@ -43,6 +56,7 @@ public RulesFileParser(NamespaceRecommendations namespaceRecommendations, Namesp _namespaceRecommendations = namespaceRecommendations; _overrideNamespaceRecommendations = overrideNamespaceRecommendations; _targetFramework = targetFramework; + _projectLanguage = projectLanguage; LoadActions(); } @@ -91,7 +105,7 @@ private void LoadActions() { assemblies = Directory.EnumerateFiles(_assembliesDir, "*.dll").ToList(); } - actionsLoader = new ActionsLoader(assemblies); + actionsLoader = new ActionsLoader(assemblies, _projectLanguage); } /// diff --git a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs index fceaa3f1..c92dee8e 100644 --- a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs +++ b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs @@ -6,6 +6,7 @@ using Codelyzer.Analysis.Build; using Codelyzer.Analysis.Model; using CTA.Rules.Analyzer; +using CTA.Rules.Common.Helpers; using CTA.Rules.Config; using CTA.Rules.Models; using CTA.Rules.RuleFiles; @@ -24,6 +25,7 @@ public class ProjectRewriter protected readonly ProjectResult _projectResult; protected readonly List _metaReferences; protected readonly AnalyzerResult _analyzerResult; + protected readonly ProjectLanguage _projectLanguage; /// /// Initializes a new instance of ProjectRewriter using an existing analysis @@ -53,6 +55,7 @@ public ProjectRewriter(AnalyzerResult analyzerResult, ProjectConfiguration proje _metaReferences = analyzerResult?.ProjectBuildResult?.Project?.MetadataReferences?.Select(m => m.Display).ToList() ?? projectConfiguration.MetaReferences; ProjectConfiguration = projectConfiguration; + _projectLanguage = VisualBasicUtils.IsVisualBasicProject(ProjectConfiguration.ProjectPath) ? ProjectLanguage.VisualBasic : ProjectLanguage.Csharp; } public ProjectRewriter(IDEProjectResult projectResult, ProjectConfiguration projectConfiguration) @@ -87,7 +90,7 @@ public ProjectResult Initialize() var allReferences = _sourceFileResults?.SelectMany(s => s.References) .Union(_sourceFileResults.SelectMany(s => s.Children.OfType())?.Select(u => new Reference() { Namespace = u.Identifier, Assembly = u.Identifier }).Distinct()) .Union(ProjectConfiguration.AdditionalReferences.Select(r => new Reference { Assembly = r, Namespace = r })); - RulesFileLoader rulesFileLoader = new RulesFileLoader(allReferences, ProjectConfiguration.RulesDir, ProjectConfiguration.TargetVersions, string.Empty, ProjectConfiguration.AssemblyDir); + RulesFileLoader rulesFileLoader = new RulesFileLoader(allReferences, ProjectConfiguration.RulesDir, ProjectConfiguration.TargetVersions, _projectLanguage, string.Empty, ProjectConfiguration.AssemblyDir); var projectRules = rulesFileLoader.Load(); @@ -150,7 +153,7 @@ public virtual List RunIncremental(List updatedFiles, Ro var ideFileActions = new List(); var allReferences = _sourceFileResults?.SelectMany(s => s.References).Distinct(); - RulesFileLoader rulesFileLoader = new RulesFileLoader(allReferences, Constants.RulesDefaultPath, ProjectConfiguration.TargetVersions, string.Empty, ProjectConfiguration.AssemblyDir); + RulesFileLoader rulesFileLoader = new RulesFileLoader(allReferences, Constants.RulesDefaultPath, ProjectConfiguration.TargetVersions, _projectLanguage, string.Empty, ProjectConfiguration.AssemblyDir); projectRules = rulesFileLoader.Load(); RulesAnalysis walker = new RulesAnalysis(_sourceFileResults, projectRules, ProjectConfiguration.ProjectType); From 06a4a93ce085d9a255f1c97f5b6dcee10ef6c2fc Mon Sep 17 00:00:00 2001 From: longachr Date: Mon, 9 May 2022 15:07:40 -0700 Subject: [PATCH 03/61] Create separate language namespaces for actions --- src/CTA.Rules.Actions/ActionsLoader.cs | 45 ++++- .../{ => Csharp}/AttributeActions.cs | 2 +- .../{ => Csharp}/AttributeListActions.cs | 2 +- .../{ => Csharp}/ClassActions.cs | 7 +- .../{ => Csharp}/CompilationUnitActions.cs | 2 +- .../{ => Csharp}/ElementAccessActions.cs | 2 +- .../{ => Csharp}/ExpressionActions.cs | 2 +- .../{ => Csharp}/IdentifierNameActions.cs | 2 +- .../{ => Csharp}/InterfaceActions.cs | 2 +- .../InvocationExpressionActions.cs | 2 +- .../{ => Csharp}/MemberAccessActions.cs | 2 +- .../{ => Csharp}/MethodDeclarationActions.cs | 2 +- .../{ => Csharp}/NamespaceActions.cs | 20 +-- .../ObjectCreationExpressionActions.cs | 2 +- .../VisualBasic/CompilationUnitActions.cs | 81 +++++++++ .../InvocationExpressionActions.cs | 168 ++++++++++++++++++ src/CTA.Rules.Config/Constants.cs | 1 + .../Actions/ActionsLoaderTests.cs | 2 +- .../Actions/AttributeActionsTests.cs | 2 +- .../Actions/AttributeListActionsTests.cs | 2 +- .../Actions/ClassActionsTests.cs | 2 +- .../Actions/CompilationUnitActionsTests.cs | 2 +- .../Actions/ElementAccessActionsTests.cs | 2 +- .../Actions/ExpressionActionsTests.cs | 2 +- .../Actions/IdentifierNameActionsTests.cs | 2 +- .../Actions/InterfaceActionsTests.cs | 2 +- .../InvocationExpressionActionsTests.cs | 2 +- .../Actions/MemberAccessActionsTests.cs | 2 +- .../Actions/MethodDeclarationActionsTests.cs | 2 +- .../Actions/NamespaceActionsTests.cs | 158 ++++++++-------- .../ObjectCreationExpressionActionsTests.cs | 2 +- 31 files changed, 404 insertions(+), 124 deletions(-) rename src/CTA.Rules.Actions/{ => Csharp}/AttributeActions.cs (95%) rename src/CTA.Rules.Actions/{ => Csharp}/AttributeListActions.cs (96%) rename src/CTA.Rules.Actions/{ => Csharp}/ClassActions.cs (98%) rename src/CTA.Rules.Actions/{ => Csharp}/CompilationUnitActions.cs (98%) rename src/CTA.Rules.Actions/{ => Csharp}/ElementAccessActions.cs (97%) rename src/CTA.Rules.Actions/{ => Csharp}/ExpressionActions.cs (98%) rename src/CTA.Rules.Actions/{ => Csharp}/IdentifierNameActions.cs (98%) rename src/CTA.Rules.Actions/{ => Csharp}/InterfaceActions.cs (99%) rename src/CTA.Rules.Actions/{ => Csharp}/InvocationExpressionActions.cs (99%) rename src/CTA.Rules.Actions/{ => Csharp}/MemberAccessActions.cs (97%) rename src/CTA.Rules.Actions/{ => Csharp}/MethodDeclarationActions.cs (99%) rename src/CTA.Rules.Actions/{ => Csharp}/NamespaceActions.cs (98%) rename src/CTA.Rules.Actions/{ => Csharp}/ObjectCreationExpressionActions.cs (99%) create mode 100644 src/CTA.Rules.Actions/VisualBasic/CompilationUnitActions.cs create mode 100644 src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs diff --git a/src/CTA.Rules.Actions/ActionsLoader.cs b/src/CTA.Rules.Actions/ActionsLoader.cs index 85d7a59d..ad6e0297 100644 --- a/src/CTA.Rules.Actions/ActionsLoader.cs +++ b/src/CTA.Rules.Actions/ActionsLoader.cs @@ -18,19 +18,45 @@ namespace CTA.Rules.Actions /// public class ActionsLoader { - private readonly List compilationUnitActions, attributeActions, attributeListActions, classActions, - identifierNameActions, invocationExpressionActions, expressionActions, methodDeclarationActions, elementAccessActions, - objectCreationExpressionActions, memberAccessActions, namespaceActions, projectLevelActions, projectFileActions, projectTypeActions, interfaceActions; + private readonly List compilationUnitActions, + attributeActions, + attributeListActions, + classActions, + identifierNameActions, + invocationExpressionActions, + expressionActions, + methodDeclarationActions, + elementAccessActions, + objectCreationExpressionActions, + memberAccessActions, + namespaceActions, + projectLevelActions, + projectFileActions, + projectTypeActions, + interfaceActions; - private readonly object attributeObject, attributeListObject, classObject, interfaceObject, compilationUnitObject, identifierNameObject - , invocationExpressionObject, expressionObject, methodDeclarationObject, elementAccessObject, memberAccessObject, objectExpressionObject, namespaceObject, projectLevelObject, - projectFileObject, projectTypeObject; + private readonly object attributeObject, + attributeListObject, + classObject, + interfaceObject, + compilationUnitObject, + identifierNameObject, + invocationExpressionObject, + expressionObject, + methodDeclarationObject, + elementAccessObject, + memberAccessObject, + objectExpressionObject, + namespaceObject, + projectLevelObject, + projectFileObject, + projectTypeObject; /// /// Initializes a new ActionLoader that loads the default actions /// /// A directory containing additional actions to be used - public ActionsLoader(List assemblyPaths) + public ActionsLoader(List assemblyPaths, ProjectLanguage language) { compilationUnitActions = new List(); attributeActions = new List(); @@ -73,7 +99,10 @@ public ActionsLoader(List assemblyPaths) { try { - var types = assembly.GetTypes().Where(t => t.Name.EndsWith("Actions")); + var types = assembly.GetTypes() + .Where(t => t.Name.EndsWith("Actions") && + (t.Namespace.EndsWith(language.ToString()) || + t.Name.StartsWith("Project"))); attributeObject = Activator.CreateInstance(types.FirstOrDefault(t => t.Name == Constants.AttributeActions)); attributeListObject = Activator.CreateInstance(types.FirstOrDefault(t => t.Name == Constants.AttributeListActions)); diff --git a/src/CTA.Rules.Actions/AttributeActions.cs b/src/CTA.Rules.Actions/Csharp/AttributeActions.cs similarity index 95% rename from src/CTA.Rules.Actions/AttributeActions.cs rename to src/CTA.Rules.Actions/Csharp/AttributeActions.cs index b78e1dc0..2ccd87db 100644 --- a/src/CTA.Rules.Actions/AttributeActions.cs +++ b/src/CTA.Rules.Actions/Csharp/AttributeActions.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { /// /// List of actions that can run on attributes diff --git a/src/CTA.Rules.Actions/AttributeListActions.cs b/src/CTA.Rules.Actions/Csharp/AttributeListActions.cs similarity index 96% rename from src/CTA.Rules.Actions/AttributeListActions.cs rename to src/CTA.Rules.Actions/Csharp/AttributeListActions.cs index 016021f0..1ec1fd77 100644 --- a/src/CTA.Rules.Actions/AttributeListActions.cs +++ b/src/CTA.Rules.Actions/Csharp/AttributeListActions.cs @@ -5,7 +5,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { /// /// List of actions that can run on attribute lists diff --git a/src/CTA.Rules.Actions/ClassActions.cs b/src/CTA.Rules.Actions/Csharp/ClassActions.cs similarity index 98% rename from src/CTA.Rules.Actions/ClassActions.cs rename to src/CTA.Rules.Actions/Csharp/ClassActions.cs index 85cfffa0..c3cc97bd 100644 --- a/src/CTA.Rules.Actions/ClassActions.cs +++ b/src/CTA.Rules.Actions/Csharp/ClassActions.cs @@ -9,8 +9,9 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; +using CSharpExtensions = Microsoft.CodeAnalysis.CSharp.CSharpExtensions; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { /// /// List of actions that can run on Class Declarations @@ -214,7 +215,7 @@ public Func Get { ClassDeclarationSyntax RemoveConstructorInitializer(SyntaxGenerator syntaxGenerator, ClassDeclarationSyntax node) { - var constructor = node.ChildNodes().Where(c => Microsoft.CodeAnalysis.CSharp.CSharpExtensions.Kind(c) == SyntaxKind.ConstructorDeclaration).FirstOrDefault(); + var constructor = node.ChildNodes().FirstOrDefault(c => c.IsKind(SyntaxKind.ConstructorDeclaration)); if (constructor != null) { ConstructorDeclarationSyntax constructorNode = (ConstructorDeclarationSyntax)constructor; @@ -249,7 +250,7 @@ public Func Get { ClassDeclarationSyntax AppendConstructorExpression(SyntaxGenerator syntaxGenerator, ClassDeclarationSyntax node) { - var constructor = node.Members.Where(c => Microsoft.CodeAnalysis.CSharp.CSharpExtensions.Kind(c) == SyntaxKind.ConstructorDeclaration).FirstOrDefault(); + var constructor = node.Members.FirstOrDefault(c => c.IsKind(SyntaxKind.ConstructorDeclaration)); if (constructor != null) { ConstructorDeclarationSyntax constructorNode = (ConstructorDeclarationSyntax)constructor; diff --git a/src/CTA.Rules.Actions/CompilationUnitActions.cs b/src/CTA.Rules.Actions/Csharp/CompilationUnitActions.cs similarity index 98% rename from src/CTA.Rules.Actions/CompilationUnitActions.cs rename to src/CTA.Rules.Actions/Csharp/CompilationUnitActions.cs index 96151367..0a0672e0 100644 --- a/src/CTA.Rules.Actions/CompilationUnitActions.cs +++ b/src/CTA.Rules.Actions/Csharp/CompilationUnitActions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { /// /// List of actions that can run on Compilation Units diff --git a/src/CTA.Rules.Actions/ElementAccessActions.cs b/src/CTA.Rules.Actions/Csharp/ElementAccessActions.cs similarity index 97% rename from src/CTA.Rules.Actions/ElementAccessActions.cs rename to src/CTA.Rules.Actions/Csharp/ElementAccessActions.cs index 16d49cc6..7846a5ba 100644 --- a/src/CTA.Rules.Actions/ElementAccessActions.cs +++ b/src/CTA.Rules.Actions/Csharp/ElementAccessActions.cs @@ -5,7 +5,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Update +namespace CTA.Rules.Update.Csharp { /// /// List of actions that can run on Element Accesses diff --git a/src/CTA.Rules.Actions/ExpressionActions.cs b/src/CTA.Rules.Actions/Csharp/ExpressionActions.cs similarity index 98% rename from src/CTA.Rules.Actions/ExpressionActions.cs rename to src/CTA.Rules.Actions/Csharp/ExpressionActions.cs index deaa5249..fd8fa257 100644 --- a/src/CTA.Rules.Actions/ExpressionActions.cs +++ b/src/CTA.Rules.Actions/Csharp/ExpressionActions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { public class ExpressionActions { diff --git a/src/CTA.Rules.Actions/IdentifierNameActions.cs b/src/CTA.Rules.Actions/Csharp/IdentifierNameActions.cs similarity index 98% rename from src/CTA.Rules.Actions/IdentifierNameActions.cs rename to src/CTA.Rules.Actions/Csharp/IdentifierNameActions.cs index 739cebbc..81f15d2e 100644 --- a/src/CTA.Rules.Actions/IdentifierNameActions.cs +++ b/src/CTA.Rules.Actions/Csharp/IdentifierNameActions.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { //TODO shouldn't this be inside ClassActions ? /// diff --git a/src/CTA.Rules.Actions/InterfaceActions.cs b/src/CTA.Rules.Actions/Csharp/InterfaceActions.cs similarity index 99% rename from src/CTA.Rules.Actions/InterfaceActions.cs rename to src/CTA.Rules.Actions/Csharp/InterfaceActions.cs index 87f7a1a7..eb73b423 100644 --- a/src/CTA.Rules.Actions/InterfaceActions.cs +++ b/src/CTA.Rules.Actions/Csharp/InterfaceActions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { /// /// List of actions that can run on Interface Declarations diff --git a/src/CTA.Rules.Actions/InvocationExpressionActions.cs b/src/CTA.Rules.Actions/Csharp/InvocationExpressionActions.cs similarity index 99% rename from src/CTA.Rules.Actions/InvocationExpressionActions.cs rename to src/CTA.Rules.Actions/Csharp/InvocationExpressionActions.cs index 7d38395f..19d19689 100644 --- a/src/CTA.Rules.Actions/InvocationExpressionActions.cs +++ b/src/CTA.Rules.Actions/Csharp/InvocationExpressionActions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { /// /// List of actions that can run on Invocation Expressions diff --git a/src/CTA.Rules.Actions/MemberAccessActions.cs b/src/CTA.Rules.Actions/Csharp/MemberAccessActions.cs similarity index 97% rename from src/CTA.Rules.Actions/MemberAccessActions.cs rename to src/CTA.Rules.Actions/Csharp/MemberAccessActions.cs index fd321c0c..ea981c03 100644 --- a/src/CTA.Rules.Actions/MemberAccessActions.cs +++ b/src/CTA.Rules.Actions/Csharp/MemberAccessActions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.Editing; using System.Linq; -namespace CTA.Rules.Update +namespace CTA.Rules.Update.Csharp { /// /// List of actions that can run on Member Accesses diff --git a/src/CTA.Rules.Actions/MethodDeclarationActions.cs b/src/CTA.Rules.Actions/Csharp/MethodDeclarationActions.cs similarity index 99% rename from src/CTA.Rules.Actions/MethodDeclarationActions.cs rename to src/CTA.Rules.Actions/Csharp/MethodDeclarationActions.cs index 55119797..b2919555 100644 --- a/src/CTA.Rules.Actions/MethodDeclarationActions.cs +++ b/src/CTA.Rules.Actions/Csharp/MethodDeclarationActions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { /// /// List of actions that can run on Method Declarations diff --git a/src/CTA.Rules.Actions/NamespaceActions.cs b/src/CTA.Rules.Actions/Csharp/NamespaceActions.cs similarity index 98% rename from src/CTA.Rules.Actions/NamespaceActions.cs rename to src/CTA.Rules.Actions/Csharp/NamespaceActions.cs index e132f6a8..cd3247d1 100644 --- a/src/CTA.Rules.Actions/NamespaceActions.cs +++ b/src/CTA.Rules.Actions/Csharp/NamespaceActions.cs @@ -1,11 +1,11 @@ using System; -using System.Linq; -using Microsoft.CodeAnalysis; +using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { public class NamespaceActions { @@ -19,11 +19,11 @@ NamespaceDeclarationSyntax RenameNamespace(SyntaxGenerator syntaxGenerator, Name return RenameNamespace; } - /// - /// Only support remove using directive actions inside Namespace block. - /// The add using directive actions will be happening in CompiliationUnit. - /// - /// + /// + /// Only support remove using directive actions inside Namespace block. + /// The add using directive actions will be happening in CompiliationUnit. + /// + /// /// public Func GetRemoveDirectiveAction(string @namespace) { @@ -37,8 +37,8 @@ NamespaceDeclarationSyntax RemoveDirective(SyntaxGenerator syntaxGenerator, Name if (removeItem == null) return node; - allUsings = allUsings.Remove(removeItem); - + allUsings = allUsings.Remove(removeItem); + node = node.WithUsings(allUsings).NormalizeWhitespace(); return RemoveDirective(syntaxGenerator, node); } diff --git a/src/CTA.Rules.Actions/ObjectCreationExpressionActions.cs b/src/CTA.Rules.Actions/Csharp/ObjectCreationExpressionActions.cs similarity index 99% rename from src/CTA.Rules.Actions/ObjectCreationExpressionActions.cs rename to src/CTA.Rules.Actions/Csharp/ObjectCreationExpressionActions.cs index b0b58b6c..438ba1b0 100644 --- a/src/CTA.Rules.Actions/ObjectCreationExpressionActions.cs +++ b/src/CTA.Rules.Actions/Csharp/ObjectCreationExpressionActions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Actions +namespace CTA.Rules.Actions.Csharp { public class ObjectCreationExpressionActions { diff --git a/src/CTA.Rules.Actions/VisualBasic/CompilationUnitActions.cs b/src/CTA.Rules.Actions/VisualBasic/CompilationUnitActions.cs new file mode 100644 index 00000000..2eb799b6 --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/CompilationUnitActions.cs @@ -0,0 +1,81 @@ +using System; +using System.Linq; +using CTA.Rules.Config; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; + +namespace CTA.Rules.Actions.VisualBasic +{ + /// + /// List of actions that can run on Compilation Units + /// + public class CompilationUnitActions + { + public Func GetAddStatementAction(string @namespace) + { + CompilationUnitSyntax AddStatement(SyntaxGenerator syntaxGenerator, CompilationUnitSyntax node) + { + var allImports = node.Imports; + var importStatement = SyntaxFactory.ImportsStatement( + SyntaxFactory.SeparatedList() + .Add(SyntaxFactory.SimpleImportsClause( + SyntaxFactory.ParseName(@namespace))) + ) + .NormalizeWhitespace(); + allImports = allImports.Add(importStatement); + + node = node.WithImports(allImports).NormalizeWhitespace(); + return node; + } + return AddStatement; + } + + public Func GetRemoveStatementAction(string @namespace) + { + CompilationUnitSyntax RemoveStatement(SyntaxGenerator syntaxGenerator, CompilationUnitSyntax node) + { + // remove duplicate directive references, don't use List based approach because + // since we will be replacing the node after each loop, it update text span which will not remove duplicate namespaces + var allImports = node.Imports; + + // difference in visual basic is that a single import statement can have multiple import clauses (namespaces) + var removeItem = allImports.FirstOrDefault(i => i.ImportsClauses.Any(c => c.ToString() == @namespace)); + if (removeItem == null) + { + return node; + } + allImports = allImports.Remove(removeItem); + // re-add import if it had multiple clauses + if (removeItem.ImportsClauses.Count > 1) + { + var removeClause = removeItem.ImportsClauses.FirstOrDefault(c => c.ToString() == @namespace); + if (removeClause != null) + { + var newClauses = removeItem.ImportsClauses.Remove(removeClause); + var newImportStatement = removeItem.WithImportsClauses(newClauses); + allImports = allImports.Add(newImportStatement); + } + } + node = node.WithImports(allImports).NormalizeWhitespace(); + return RemoveStatement(syntaxGenerator, node); + } + + return RemoveStatement; + } + + public Func GetAddCommentAction(string comment) + { + CompilationUnitSyntax AddComment(SyntaxGenerator syntaxGenerator, CompilationUnitSyntax node) + { + SyntaxTriviaList currentTrivia = node.GetLeadingTrivia(); + //TODO see if this will lead NPE + currentTrivia = currentTrivia.Add(SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, string.Format(Constants.VbCommentFormat, comment))); + node = node.WithLeadingTrivia(currentTrivia).NormalizeWhitespace(); + return node; + } + return AddComment; + } + } +} diff --git a/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs b/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs new file mode 100644 index 00000000..598346c7 --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs @@ -0,0 +1,168 @@ +using System; +using System.Linq; +using CTA.Rules.Config; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; + +namespace CTA.Rules.Actions.VisualBasic +{ + /// + /// List of actions that can run on Invocation Expressions + /// + public class InvocationExpressionActions + { + /// + /// This Method replaces the entire expression including the parameters. For example, Math.Round(5.5) invocation expression matching on Round with a newMethod parameter of Abs(9.5) would return Abs(9.5) not Math.Abs(9.5). + /// Please ensure to include the prefix part of the matching invocation expression since this method will replace it and the parameters as well. + /// + /// The new invocation expression including the method to replace with and the parameters. + /// The new invocation expression parameters to replace the old parameters with. + /// + public Func GetReplaceMethodWithObjectAndParametersAction(string newMethod, string newParameters) + { + //TODO what's the outcome if newMethod doesn't have a valid signature.. are there any options we could provide to parse expression ? + InvocationExpressionSyntax ReplaceMethod(SyntaxGenerator syntaxGenerator, InvocationExpressionSyntax node) + { + node = SyntaxFactory.InvocationExpression( + SyntaxFactory.IdentifierName(newMethod), + SyntaxFactory.ParseArgumentList(newParameters)) + .WithLeadingTrivia(node.GetLeadingTrivia()) + .NormalizeWhitespace(); + return node; + } + return ReplaceMethod; + } + + /// + /// This Method replaces the entire expression up to the matching invocation expression. For example, Math.Round(5.5) invocation expression matching on Round with a newMethod parameter of Abs would return Abs(5.5) not Math.Abs(5.5). + /// Please ensure to include the prefix part of the matching invocation expression since this method will replace it. + /// + /// The new invocation expression including the method to replace with. + /// + public Func GetReplaceMethodWithObjectAction(string newMethod) + { + //TODO what's the outcome if newMethod doesn't have a valid signature.. are there any options we could provide to parseexpression ? + InvocationExpressionSyntax ReplaceMethod(SyntaxGenerator syntaxGenerator, InvocationExpressionSyntax node) + { + node = node.WithExpression(SyntaxFactory.ParseExpression(newMethod)) + .WithLeadingTrivia(node.GetLeadingTrivia()) + .NormalizeWhitespace(); + return node; + } + return ReplaceMethod; + } + + /// + /// This Method replaces the entire expression up to the matching invocation expression. It also adds the type from the typed argument list to the list of arguments. + /// Example: DependencyResolver.Current.GetService() becomes DependencyResolver.Current.GetService(typeof(object)) + /// + /// The new invocation expression including the method to replace with. + /// + public Func GetReplaceMethodWithObjectAddTypeAction(string newMethod) + { + InvocationExpressionSyntax ReplaceMethod(SyntaxGenerator syntaxGenerator, InvocationExpressionSyntax node) + { + var typeToAdd = node.Expression.DescendantNodes()?.OfType()?.FirstOrDefault()?.TypeArgumentList; + + if (typeToAdd != null) + { + var argumentList = SyntaxFactory.ParseArgumentList($"(typeof({typeToAdd.Arguments.ToString()}))"); + node = node.WithArgumentList(argumentList).WithLeadingTrivia(node.GetLeadingTrivia()); + } + + node = node.WithExpression(SyntaxFactory.ParseExpression(newMethod)).WithLeadingTrivia(node.GetLeadingTrivia()).NormalizeWhitespace(); + return node; + } + return ReplaceMethod; + } + + /// + /// This Method replaces only matching method in the invocation expression and its parameters. + /// For example, Math.Round(5.5) invocation expression matching on Round with a newMethod parameter of Abs and an oldMethod parameter of Round with parameters of 8.5 would return Math.Abs(8.5). + /// + /// The matching method in the invocation expression to be replaced. + /// The new method to replace the old method with in the invocation expression. + /// The new invocation expression parameters to replace the old parameters with. + /// + public Func GeReplaceMethodAndParametersAction(string oldMethod, string newMethod, string newParameters) + { + //TODO what's the outcome if newMethod doesn't have a valid signature.. are there any options we could provide to parseexpression ? + InvocationExpressionSyntax ReplaceOnlyMethod(SyntaxGenerator syntaxGenerator, InvocationExpressionSyntax node) + { + node = node.WithExpression(SyntaxFactory.ParseExpression(node.Expression.ToString().Replace(oldMethod, newMethod))) + .WithArgumentList(SyntaxFactory.ParseArgumentList(newParameters)) + .WithLeadingTrivia(node.GetLeadingTrivia()) + .NormalizeWhitespace(); + return node; + } + return ReplaceOnlyMethod; + } + + /// + /// This Method replaces only matching method in the invocation expression. For example, Math.Round(5.5) invocation expression matching on Round with a newMethod parameter of Abs and an oldMethod parameter of Round would return Math.Abs(5.5). + /// + /// The matching method in the invocation expression to be replaced. + /// The new method to replace the old method with in the invocation expression. + /// + public Func GetReplaceMethodOnlyAction(string oldMethod, string newMethod) + { + //TODO what's the outcome if newMethod doesn't have a valid signature.. are there any options we could provide to parseexpression ? + InvocationExpressionSyntax ReplaceOnlyMethod(SyntaxGenerator syntaxGenerator, InvocationExpressionSyntax node) + { + node = node.WithExpression(SyntaxFactory.ParseExpression(node.Expression.ToString().Replace(oldMethod, newMethod))) + .WithLeadingTrivia(node.GetLeadingTrivia()) + .NormalizeWhitespace(); + return node; + } + return ReplaceOnlyMethod; + } + + /// + /// This Method replaces only the parameters in the invocation expression. For example, Math.Round(5.5) invocation expression matching on Round with a parameter of (8) would return Math.Abs(8). + /// + /// The new invocation expression parameters to replace the old parameters with. + /// + public Func GetReplaceParametersOnlyAction(string newParameters) + { + //TODO what's the outcome if newMethod doesn't have a valid signature.. are there any options we could provide to parseexpression ? + InvocationExpressionSyntax ReplaceOnlyMethod(SyntaxGenerator syntaxGenerator, InvocationExpressionSyntax node) + { + node = node.WithArgumentList(SyntaxFactory.ParseArgumentList(newParameters)).NormalizeWhitespace(); + return node; + } + return ReplaceOnlyMethod; + } + + public Func GetAppendMethodAction(string appendMethod) + { + InvocationExpressionSyntax ReplaceMethod(SyntaxGenerator syntaxGenerator, InvocationExpressionSyntax node) + { + //todo: apparently '!' is also a valid operator token? + SyntaxToken operatorToken = node.DescendantTokens().FirstOrDefault(t => Microsoft.CodeAnalysis.VisualBasicExtensions.IsKind(t, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.DotToken)); + node = SyntaxFactory.InvocationExpression( + SyntaxFactory.MemberAccessExpression( + Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.SimpleMemberAccessExpression, + operatorToken, + SyntaxFactory.IdentifierName(SyntaxFactory.ParseName(appendMethod).ToString())), + SyntaxFactory.ArgumentList()).NormalizeWhitespace(); + return node; + } + return ReplaceMethod; + } + + public Func GetAddCommentAction(string comment) + { + InvocationExpressionSyntax AddComment(SyntaxGenerator syntaxGenerator, InvocationExpressionSyntax node) + { + SyntaxTriviaList currentTrivia = node.GetLeadingTrivia(); + currentTrivia = currentTrivia.Add(SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, string.Format(Constants.VbCommentFormat, comment))); + node = node.WithLeadingTrivia(currentTrivia).NormalizeWhitespace(); + return node; + } + return AddComment; + } + } +} + diff --git a/src/CTA.Rules.Config/Constants.cs b/src/CTA.Rules.Config/Constants.cs index 1cdeffcc..fa846fa5 100644 --- a/src/CTA.Rules.Config/Constants.cs +++ b/src/CTA.Rules.Config/Constants.cs @@ -50,6 +50,7 @@ public class Constants public const string Templates = "Templates"; public const string CommentFormat = @"/* Added by CTA: {0} */"; + public const string VbCommentFormat = @"' Added by CTA: {0}"; public const string CommentFormatBlank = @"/* {0} */"; public const string WebSdkName = "Microsoft.NET.Sdk.Web"; public const string ClassLibrarySdkName = "Microsoft.NET.Sdk"; diff --git a/tst/CTA.Rules.Test/Actions/ActionsLoaderTests.cs b/tst/CTA.Rules.Test/Actions/ActionsLoaderTests.cs index ffb4617b..d7003926 100644 --- a/tst/CTA.Rules.Test/Actions/ActionsLoaderTests.cs +++ b/tst/CTA.Rules.Test/Actions/ActionsLoaderTests.cs @@ -17,7 +17,7 @@ public class ActionLoaderTests [SetUp] public void SetUp() { - _actionLoader = new ActionsLoader(new List()); + _actionLoader = new ActionsLoader(new List(), ProjectLanguage.Csharp); } [Test] diff --git a/tst/CTA.Rules.Test/Actions/AttributeActionsTests.cs b/tst/CTA.Rules.Test/Actions/AttributeActionsTests.cs index 6dc8c464..2172072d 100644 --- a/tst/CTA.Rules.Test/Actions/AttributeActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/AttributeActionsTests.cs @@ -1,4 +1,4 @@ -using CTA.Rules.Actions; +using CTA.Rules.Actions.Csharp; using CTA.Rules.Models; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/tst/CTA.Rules.Test/Actions/AttributeListActionsTests.cs b/tst/CTA.Rules.Test/Actions/AttributeListActionsTests.cs index 05b9f263..baada3a9 100644 --- a/tst/CTA.Rules.Test/Actions/AttributeListActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/AttributeListActionsTests.cs @@ -1,4 +1,4 @@ -using CTA.Rules.Actions; +using CTA.Rules.Actions.Csharp; using CTA.Rules.Models; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/tst/CTA.Rules.Test/Actions/ClassActionsTests.cs b/tst/CTA.Rules.Test/Actions/ClassActionsTests.cs index 38576cf8..b1ac563f 100644 --- a/tst/CTA.Rules.Test/Actions/ClassActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/ClassActionsTests.cs @@ -1,4 +1,4 @@ -using CTA.Rules.Actions; +using CTA.Rules.Actions.Csharp; using CTA.Rules.Models; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/tst/CTA.Rules.Test/Actions/CompilationUnitActionsTests.cs b/tst/CTA.Rules.Test/Actions/CompilationUnitActionsTests.cs index 8e8a6237..0b2f27bf 100644 --- a/tst/CTA.Rules.Test/Actions/CompilationUnitActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/CompilationUnitActionsTests.cs @@ -1,4 +1,4 @@ -using CTA.Rules.Actions; +using CTA.Rules.Actions.Csharp; using CTA.Rules.Models; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/tst/CTA.Rules.Test/Actions/ElementAccessActionsTests.cs b/tst/CTA.Rules.Test/Actions/ElementAccessActionsTests.cs index 8e590d9a..80ba1dfd 100644 --- a/tst/CTA.Rules.Test/Actions/ElementAccessActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/ElementAccessActionsTests.cs @@ -1,5 +1,5 @@ using CTA.Rules.Models; -using CTA.Rules.Update; +using CTA.Rules.Update.Csharp; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/tst/CTA.Rules.Test/Actions/ExpressionActionsTests.cs b/tst/CTA.Rules.Test/Actions/ExpressionActionsTests.cs index e82e9979..d0d67c2e 100644 --- a/tst/CTA.Rules.Test/Actions/ExpressionActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/ExpressionActionsTests.cs @@ -1,4 +1,4 @@ -using CTA.Rules.Actions; +using CTA.Rules.Actions.Csharp; using CTA.Rules.Models; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/tst/CTA.Rules.Test/Actions/IdentifierNameActionsTests.cs b/tst/CTA.Rules.Test/Actions/IdentifierNameActionsTests.cs index b2784886..8190918d 100644 --- a/tst/CTA.Rules.Test/Actions/IdentifierNameActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/IdentifierNameActionsTests.cs @@ -1,4 +1,4 @@ -using CTA.Rules.Actions; +using CTA.Rules.Actions.Csharp; using CTA.Rules.Models; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/tst/CTA.Rules.Test/Actions/InterfaceActionsTests.cs b/tst/CTA.Rules.Test/Actions/InterfaceActionsTests.cs index 57d933ea..400dc069 100644 --- a/tst/CTA.Rules.Test/Actions/InterfaceActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/InterfaceActionsTests.cs @@ -1,4 +1,4 @@ -using CTA.Rules.Actions; +using CTA.Rules.Actions.Csharp; using CTA.Rules.Models; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/tst/CTA.Rules.Test/Actions/InvocationExpressionActionsTests.cs b/tst/CTA.Rules.Test/Actions/InvocationExpressionActionsTests.cs index 06c0b405..72992246 100644 --- a/tst/CTA.Rules.Test/Actions/InvocationExpressionActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/InvocationExpressionActionsTests.cs @@ -1,4 +1,4 @@ -using CTA.Rules.Actions; +using CTA.Rules.Actions.Csharp; using CTA.Rules.Models; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/tst/CTA.Rules.Test/Actions/MemberAccessActionsTests.cs b/tst/CTA.Rules.Test/Actions/MemberAccessActionsTests.cs index 36125b97..a80be9d0 100644 --- a/tst/CTA.Rules.Test/Actions/MemberAccessActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/MemberAccessActionsTests.cs @@ -1,5 +1,5 @@ using CTA.Rules.Models; -using CTA.Rules.Update; +using CTA.Rules.Update.Csharp; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/tst/CTA.Rules.Test/Actions/MethodDeclarationActionsTests.cs b/tst/CTA.Rules.Test/Actions/MethodDeclarationActionsTests.cs index e7e86d5d..09b0f9f9 100644 --- a/tst/CTA.Rules.Test/Actions/MethodDeclarationActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/MethodDeclarationActionsTests.cs @@ -1,4 +1,4 @@ -using CTA.Rules.Actions; +using CTA.Rules.Actions.Csharp; using CTA.Rules.Models; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/tst/CTA.Rules.Test/Actions/NamespaceActionsTests.cs b/tst/CTA.Rules.Test/Actions/NamespaceActionsTests.cs index 0a13c335..1d0aad84 100644 --- a/tst/CTA.Rules.Test/Actions/NamespaceActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/NamespaceActionsTests.cs @@ -1,79 +1,79 @@ -using CTA.FeatureDetection.Common.Extensions; -using CTA.Rules.Actions; -using CTA.Rules.Models; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; -using NUnit.Framework; -using System.Linq; - -namespace CTA.Rules.Test.Actions -{ - internal class NamespaceActionsTests - { - private SyntaxGenerator _syntaxGenerator; - private NamespaceActions _namespaceActions; - private NamespaceDeclarationSyntax _node; - - [SetUp] - public void SetUp() - { - var workspace = new AdhocWorkspace(); - var language = LanguageNames.CSharp; - _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); - _namespaceActions = new NamespaceActions(); - - SyntaxTree tree = CSharpSyntaxTree.ParseText( - @$" - namespace DummyNamespace - {{ - using System.Web; - class MyClass - {{ - }}; - }}"); - _node = tree.GetRoot() - .DescendantNodes() - .OfType() - .FirstOrDefault(); - } - - [Test] - public void GetRenameNamespaceAction_Rename_Namespace() - { - const string newNamespaceName = "NewNamespace"; - var renameNamespaceFunc = _namespaceActions.GetRenameNamespaceAction(newNamespaceName); - var newNode = renameNamespaceFunc(_syntaxGenerator, _node); - - var expectedResult = CSharpSyntaxTree.ParseText(@$" - namespace NewNamespace - {{ - using System.Web; - class MyClass - {{ - }}; - }}").GetRoot(); - Assert.AreEqual(expectedResult.RemoveAllTrivia().ToFullString(), newNode.RemoveAllTrivia().ToFullString()); - } - - [Test] - public void GetRemoveDirectiveAction_Removes_Directive() - { - const string directive = "System.Web"; - var removeDirectiveFunc = _namespaceActions.GetRemoveDirectiveAction(directive); - var newNode = removeDirectiveFunc(_syntaxGenerator, _node); - - var expectedResult = CSharpSyntaxTree.ParseText(@$" - namespace DummyNamespace - {{ - class MyClass - {{ - }}; - }}").GetRoot(); - Assert.AreEqual(expectedResult.RemoveAllTrivia().ToFullString(), newNode.RemoveAllTrivia().ToFullString()); - } - - - } -} +using CTA.FeatureDetection.Common.Extensions; +using CTA.Rules.Actions.Csharp; +using CTA.Rules.Models; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; +using System.Linq; + +namespace CTA.Rules.Test.Actions +{ + internal class NamespaceActionsTests + { + private SyntaxGenerator _syntaxGenerator; + private NamespaceActions _namespaceActions; + private NamespaceDeclarationSyntax _node; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.CSharp; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _namespaceActions = new NamespaceActions(); + + SyntaxTree tree = CSharpSyntaxTree.ParseText( + @$" + namespace DummyNamespace + {{ + using System.Web; + class MyClass + {{ + }}; + }}"); + _node = tree.GetRoot() + .DescendantNodes() + .OfType() + .FirstOrDefault(); + } + + [Test] + public void GetRenameNamespaceAction_Rename_Namespace() + { + const string newNamespaceName = "NewNamespace"; + var renameNamespaceFunc = _namespaceActions.GetRenameNamespaceAction(newNamespaceName); + var newNode = renameNamespaceFunc(_syntaxGenerator, _node); + + var expectedResult = CSharpSyntaxTree.ParseText(@$" + namespace NewNamespace + {{ + using System.Web; + class MyClass + {{ + }}; + }}").GetRoot(); + Assert.AreEqual(expectedResult.RemoveAllTrivia().ToFullString(), newNode.RemoveAllTrivia().ToFullString()); + } + + [Test] + public void GetRemoveDirectiveAction_Removes_Directive() + { + const string directive = "System.Web"; + var removeDirectiveFunc = _namespaceActions.GetRemoveDirectiveAction(directive); + var newNode = removeDirectiveFunc(_syntaxGenerator, _node); + + var expectedResult = CSharpSyntaxTree.ParseText(@$" + namespace DummyNamespace + {{ + class MyClass + {{ + }}; + }}").GetRoot(); + Assert.AreEqual(expectedResult.RemoveAllTrivia().ToFullString(), newNode.RemoveAllTrivia().ToFullString()); + } + + + } +} diff --git a/tst/CTA.Rules.Test/Actions/ObjectCreationExpressionActionsTests.cs b/tst/CTA.Rules.Test/Actions/ObjectCreationExpressionActionsTests.cs index a5cdb00b..48d835d9 100644 --- a/tst/CTA.Rules.Test/Actions/ObjectCreationExpressionActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/ObjectCreationExpressionActionsTests.cs @@ -1,4 +1,4 @@ -using CTA.Rules.Actions; +using CTA.Rules.Actions.Csharp; using CTA.Rules.Models; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; From 39ca91d91254c8625f1d2d97dc25225cdadede03 Mon Sep 17 00:00:00 2001 From: longachr Date: Tue, 10 May 2022 11:20:37 -0700 Subject: [PATCH 04/61] Create vb action loader class and refactor shared functions --- src/CTA.Rules.Actions/ActionLoaderUtils.cs | 170 ++++++++++++++++ src/CTA.Rules.Actions/ActionsLoader.cs | 192 ++++-------------- .../InvocationExpressionActions.cs | 2 +- .../VisualBasicActionsLoader.cs | 166 +++++++++++++++ src/CTA.Rules.RuleFiles/RulesFileParser.cs | 2 +- .../Actions/ActionsLoaderTests.cs | 10 +- .../Actions/VisualBasicActionsLoaderTest.cs | 57 ++++++ 7 files changed, 432 insertions(+), 167 deletions(-) create mode 100644 src/CTA.Rules.Actions/ActionLoaderUtils.cs create mode 100644 src/CTA.Rules.Actions/VisualBasicActionsLoader.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasicActionsLoaderTest.cs diff --git a/src/CTA.Rules.Actions/ActionLoaderUtils.cs b/src/CTA.Rules.Actions/ActionLoaderUtils.cs new file mode 100644 index 00000000..f1ed70e1 --- /dev/null +++ b/src/CTA.Rules.Actions/ActionLoaderUtils.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using CTA.Rules.Config; +using Newtonsoft.Json; + +namespace CTA.Rules.Actions; + +public class ActionLoaderUtils +{ + /// + /// Gets the action by invoking the methods that will create it + /// + /// The type of the object + /// List of actions on the type T + /// The object that will be used to retrieve the action + /// Name of the action + /// Parameter(s) of the action + /// + public static T GetAction(List actions, object invokeObject, string name, dynamic value) + { + T val = default; + try + { + string actionName = GetActionName(name); + var method = actions.Where(m => m.Name == actionName).FirstOrDefault(); + if (method == null) + { + LogHelper.LogDebug(string.Format("No such action {0}", actionName)); + } + else + { + var parameters = ActionLoaderUtils.GetParameters(value, method); + + if (parameters != null) + { + val = (T)method.Invoke(invokeObject, parameters); + } + } + } + catch (Exception ex) + { + LogHelper.LogError(ex, "Error while loading action {0}", name); + } + return val; + } + + public static List GetAssemblies(List assemblyPaths) + { + var actionsAssembly = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(a => a.FullName.Contains("CTA.Rules.Actions")); + + var assemblies = new List + { + actionsAssembly + }; + + foreach (var path in assemblyPaths) + { + try + { + var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path); + assemblies.Add(assembly); + } + catch (Exception ex) + { + LogHelper.LogError(ex, + string.Format("Error loading assembly from {0}{1}{2}", path, Environment.NewLine, ex.Message)); + } + } + + return assemblies; + } + + private static string GetActionName(string name) + { + return string.Concat("Get", name, "Action"); + } + + public static List GetFuncMethods(Type t) => t.GetMethods().Where(m => m.ReturnType.ToString().Contains("System.Func")).ToList(); + + public static bool TryCreateInstance(string actionName, List types, out object obj) + { + obj = null; + var type = types.FirstOrDefault(t => t.Name == actionName); + if (type == null) + { + return false; + } + obj = Activator.CreateInstance(type); + return true; + } + + private static List GetJsonParameters(string value, MethodInfo method) + { + List result = new List(); + + Dictionary jsonParameters = JsonConvert.DeserializeObject>(value); + + var methodParams = method.GetParameters(); + foreach (var p in methodParams) + { + if (jsonParameters.ContainsKey(p.Name)) + { + result.Add(jsonParameters[p.Name]); + } + else if(p.IsOptional) + { + result.Add(p.HasDefaultValue && p.DefaultValue != null ? p.DefaultValue.ToString() : null); + } + else + { + LogHelper.LogDebug(string.Format("Parameter {0} is not available for action {1}", p.Name, method.Name)); + return null; + } + } + return result; + } + /// + /// Gets the parameters for the action. The parameters should match the action signature in the provided rules file + /// + /// The paramter(s) as a string or JSON object + /// The method for these parameters + /// + public static string[] GetParameters(dynamic value, MethodInfo method) + { + List result = new List(); + + try + { + if (value is string) + { + var strValue = value.ToString(); + if (strValue.StartsWith("{")) + { + try + { + result = ActionLoaderUtils.GetJsonParameters(value.ToString(), method); + } + catch (Exception) + { + result = new List() { value }; + } + } + else + { + result = new List() { value }; + var optionalParameters = method.GetParameters().Where(p => p.IsOptional); + // This should only run if optional parameter was not inlcuded originally. + // TODO: We do not support ONLY optional parameters > 1 at this time, this logic would need to be re-written properly, that scenario would fail at val = (T)method.Invoke(invokeObject, parameters); + if (optionalParameters.Any() && method.GetParameters().Count() > 1) + { + result.AddRange(optionalParameters.Select(p => p.HasDefaultValue && p.DefaultValue != null ? p.DefaultValue.ToString() : null)); + } + } + } + else + { + result = ActionLoaderUtils.GetJsonParameters(value.ToString(), method); + } + } + catch (Exception ex) + { + LogHelper.LogError(ex, "Error while loading parameters for action {0}", method.Name); + } + return result.ToArray(); + } +} diff --git a/src/CTA.Rules.Actions/ActionsLoader.cs b/src/CTA.Rules.Actions/ActionsLoader.cs index ad6e0297..c241bf9a 100644 --- a/src/CTA.Rules.Actions/ActionsLoader.cs +++ b/src/CTA.Rules.Actions/ActionsLoader.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -using Newtonsoft.Json; namespace CTA.Rules.Actions { @@ -56,7 +55,7 @@ public class ActionsLoader /// Initializes a new ActionLoader that loads the default actions /// /// A directory containing additional actions to be used - public ActionsLoader(List assemblyPaths, ProjectLanguage language) + public ActionsLoader(List assemblyPaths) { compilationUnitActions = new List(); attributeActions = new List(); @@ -101,8 +100,8 @@ public ActionsLoader(List assemblyPaths, ProjectLanguage language) { var types = assembly.GetTypes() .Where(t => t.Name.EndsWith("Actions") && - (t.Namespace.EndsWith(language.ToString()) || - t.Name.StartsWith("Project"))); + (t.Namespace.EndsWith(ProjectLanguage.Csharp.ToString()) || + t.Name.StartsWith("Project"))).ToList(); attributeObject = Activator.CreateInstance(types.FirstOrDefault(t => t.Name == Constants.AttributeActions)); attributeListObject = Activator.CreateInstance(types.FirstOrDefault(t => t.Name == Constants.AttributeListActions)); @@ -121,89 +120,88 @@ public ActionsLoader(List assemblyPaths, ProjectLanguage language) projectFileObject = Activator.CreateInstance(types.FirstOrDefault(t => t.Name == Constants.ProjectFileActions)); projectTypeObject = Activator.CreateInstance(types.FirstOrDefault(t => t.Name == Constants.ProjectTypeActions)); - foreach (var t in types) { switch (t.Name) { case Constants.AttributeActions: { - attributeActions.AddRange(GetFuncMethods(t)); + attributeActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.AttributeListActions: { - attributeListActions.AddRange(GetFuncMethods(t)); + attributeListActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.ClassActions: { - classActions.AddRange(GetFuncMethods(t)); + classActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.InterfaceActions: { - interfaceActions.AddRange(GetFuncMethods(t)); + interfaceActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.CompilationUnitActions: { - compilationUnitActions.AddRange(GetFuncMethods(t)); + compilationUnitActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.IdentifierNameActions: { - identifierNameActions.AddRange(GetFuncMethods(t)); + identifierNameActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.InvocationExpressionActions: { - invocationExpressionActions.AddRange(GetFuncMethods(t)); + invocationExpressionActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.ExpressionActions: { - expressionActions.AddRange(GetFuncMethods(t)); + expressionActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.MethodDeclarationActions: { - methodDeclarationActions.AddRange(GetFuncMethods(t)); + methodDeclarationActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.ElementAccessActions: { - elementAccessActions.AddRange(GetFuncMethods(t)); + elementAccessActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.MemberAccessActions: { - memberAccessActions.AddRange(GetFuncMethods(t)); + memberAccessActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.ObjectCreationExpressionActions: { - objectCreationExpressionActions.AddRange(GetFuncMethods(t)); + objectCreationExpressionActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.NamespaceActions: { - namespaceActions.AddRange(GetFuncMethods(t)); + namespaceActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.ProjectLevelActions: { - projectLevelActions.AddRange(GetFuncMethods(t)); + projectLevelActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.ProjectFileActions: { - projectFileActions.AddRange(GetFuncMethods(t)); + projectFileActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } case Constants.ProjectTypeActions: { - projectTypeActions.AddRange(GetFuncMethods(t)); + projectTypeActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } default: @@ -220,174 +218,54 @@ public ActionsLoader(List assemblyPaths, ProjectLanguage language) } } } - - private List GetFuncMethods(Type t) => t.GetMethods().Where(m => m.ReturnType.ToString().Contains("System.Func")).ToList(); - - private string GetActionName(string name) - { - return string.Concat("Get", name, "Action"); - } public Func GetCompilationUnitAction(string name, dynamic value) - => GetAction> + => ActionLoaderUtils.GetAction> (compilationUnitActions, compilationUnitObject, name, value); public Func GetAttributeAction(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (attributeActions, attributeObject, name, value); public Func GetAttributeListAction(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (attributeListActions, attributeListObject, name, value); public Func GetClassAction(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (classActions, classObject, name, value); public Func GetInterfaceAction(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (interfaceActions, interfaceObject, name, value); public Func GetIdentifierNameAction(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (identifierNameActions, identifierNameObject, name, value); public Func GetInvocationExpressionAction(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (invocationExpressionActions, invocationExpressionObject, name, value); public Func GetExpressionAction(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (expressionActions, expressionObject, name, value); public Func GetMethodDeclarationAction(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (methodDeclarationActions, methodDeclarationObject, name, value); public Func GetNamespaceActions(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (namespaceActions, namespaceObject, name, value); public Func GetObjectCreationExpressionActions(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (objectCreationExpressionActions, objectExpressionObject, name, value); public Func GetProjectLevelActions(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (projectLevelActions, projectLevelObject, name, value); public Func, Dictionary, List, List, string> GetProjectFileActions(string name, dynamic value) => - GetAction, Dictionary, List, List, string>> + ActionLoaderUtils.GetAction, Dictionary, List, List, string>> (projectFileActions, projectFileObject, name, value); public Func GetProjectTypeActions(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (projectTypeActions, projectTypeObject, name, value); public Func GetElementAccessExpressionActions(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (elementAccessActions, elementAccessObject, name, value); public Func GetMemberAccessExpressionActions(string name, dynamic value) => - GetAction> + ActionLoaderUtils.GetAction> (memberAccessActions, memberAccessObject, name, value); - - /// - /// Gets the action by invoking the methods that will create it - /// - /// The type of the object - /// List of actions on the type T - /// The object that will be used to retrieve the action - /// Name of the action - /// Parameter(s) of the action - /// - private T GetAction(List actions, object invokeObject, string name, dynamic value) - { - T val = default; - try - { - string actionName = GetActionName(name); - var method = actions.Where(m => m.Name == actionName).FirstOrDefault(); - if (method == null) - { - LogHelper.LogDebug(string.Format("No such action {0}", actionName)); - } - else - { - var parameters = GetParameters(value, method); - - if (parameters != null) - { - val = (T)method.Invoke(invokeObject, parameters); - } - } - } - catch (Exception ex) - { - LogHelper.LogError(ex, "Error while loading action {0}", name); - } - return val; - } - - /// - /// Gets the parameters for the action. The parameters should match the action signature in the provided rules file - /// - /// The paramter(s) as a string or JSON object - /// The method for these parameters - /// - private string[] GetParameters(dynamic value, MethodInfo method) - { - List result = new List(); - - try - { - if (value is string) - { - var strValue = value.ToString(); - if (strValue.StartsWith("{")) - { - try - { - result = GetJsonParameters(value.ToString(), method); - } - catch (Exception) - { - result = new List() { value }; - } - } - else - { - result = new List() { value }; - var optionalParameters = method.GetParameters().Where(p => p.IsOptional); - // This should only run if optional parameter was not inlcuded originally. - // TODO: We do not support ONLY optional parameters > 1 at this time, this logic would need to be re-written properly, that scenario would fail at val = (T)method.Invoke(invokeObject, parameters); - if (optionalParameters.Any() && method.GetParameters().Count() > 1) - { - result.AddRange(optionalParameters.Select(p => p.HasDefaultValue && p.DefaultValue != null ? p.DefaultValue.ToString() : null)); - } - } - } - else - { - result = GetJsonParameters(value.ToString(), method); - } - } - catch (Exception ex) - { - LogHelper.LogError(ex, "Error while loading parameters for action {0}", method.Name); - } - return result.ToArray(); - } - - private List GetJsonParameters(string value, MethodInfo method) - { - List result = new List(); - - Dictionary jsonParameters = JsonConvert.DeserializeObject>(value); - - var methodParams = method.GetParameters(); - foreach (var p in methodParams) - { - if (jsonParameters.ContainsKey(p.Name)) - { - result.Add(jsonParameters[p.Name]); - } - else if(p.IsOptional) - { - result.Add(p.HasDefaultValue && p.DefaultValue != null ? p.DefaultValue.ToString() : null); - } - else - { - LogHelper.LogDebug(string.Format("Parameter {0} is not available for action {1}", p.Name, method.Name)); - return null; - } - } - return result; - } } } diff --git a/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs b/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs index 598346c7..92521b65 100644 --- a/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs +++ b/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs @@ -86,7 +86,7 @@ InvocationExpressionSyntax ReplaceMethod(SyntaxGenerator syntaxGenerator, Invoca /// The new method to replace the old method with in the invocation expression. /// The new invocation expression parameters to replace the old parameters with. /// - public Func GeReplaceMethodAndParametersAction(string oldMethod, string newMethod, string newParameters) + public Func GetReplaceMethodAndParametersAction(string oldMethod, string newMethod, string newParameters) { //TODO what's the outcome if newMethod doesn't have a valid signature.. are there any options we could provide to parseexpression ? InvocationExpressionSyntax ReplaceOnlyMethod(SyntaxGenerator syntaxGenerator, InvocationExpressionSyntax node) diff --git a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs new file mode 100644 index 00000000..f8318271 --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using Codelyzer.Analysis; +using CTA.Rules.Config; +using CTA.Rules.Models; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Actions; + +public class VisualBasicActionsLoader +{ + private readonly List _compilationUnitActions, + _invocationExpressionActions; + + private readonly object _compilationUnitObject, + _invocationExpressionObject; + + /// + /// Initializes a new ActionLoader that loads the default actions + /// + /// A directory containing additional actions to be used + public VisualBasicActionsLoader(List assemblyPaths) + { + _compilationUnitActions = new List(); + _invocationExpressionActions = new List(); + + var assemblies = ActionLoaderUtils.GetAssemblies(assemblyPaths); + + foreach (var assembly in assemblies) + { + try + { + var types = assembly.GetTypes() + .Where(t => t.Name.EndsWith("Actions") && + (t.Namespace.EndsWith(ProjectLanguage.VisualBasic.ToString()) || + t.Name.StartsWith("Project"))).ToList(); + ActionLoaderUtils.TryCreateInstance(Constants.CompilationUnitActions, types, + out _compilationUnitObject); + ActionLoaderUtils.TryCreateInstance(Constants.InvocationExpressionActions, types, + out _invocationExpressionObject); + + foreach (var t in types) + { + switch (t.Name) + { + case Constants.CompilationUnitActions: + { + _compilationUnitActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + break; + } + case Constants.InvocationExpressionActions: + { + _invocationExpressionActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + break; + } + default: + { + LogHelper.LogError($"Action type {t.Name} is not found"); + break; + } + } + } + } + catch (Exception ex) + { + LogHelper.LogError(ex, string.Format("Error loading actions from {0}", assembly.FullName, ex.Message)); + } + } + } + + public Func GetInvocationExpressionAction(string name, dynamic value) + { + return ActionLoaderUtils.GetAction> + (_invocationExpressionActions, _invocationExpressionObject, name, value); + } + + public Func GetCompilationUnitAction(string name, + dynamic value) + { + return ActionLoaderUtils.GetAction> + (_compilationUnitActions, _compilationUnitObject, name, value); + } + + public Func GetAttributeAction(string name, dynamic value) + { + throw new NotImplementedException(); + } + + public Func GetAttributeListAction(string name, dynamic value) + { + throw new NotImplementedException(); + } + + /* + public Func GetClassAction(string name, dynamic value) + { + throw new NotImplementedException(); + } + */ + /* + public Func GetInterfaceAction(string name, dynamic value) + { + throw new NotImplementedException(); + } + */ + + public Func GetIdentifierNameAction(string name, dynamic value) + { + throw new NotImplementedException(); + } + + public Func GetExpressionAction(string name, dynamic value) + { + throw new NotImplementedException(); + } + + /* + public Func GetMethodDeclarationAction(string name, dynamic value) + { + throw new NotImplementedException(); + } + */ + /* + public Func GetNamespaceActions(string name, dynamic value) + { + throw new NotImplementedException(); + } + */ + + public Func GetObjectCreationExpressionActions(string name, dynamic value) + { + throw new NotImplementedException(); + } + + public Func GetProjectLevelActions(string name, dynamic value) + { + throw new NotImplementedException(); + } + + public Func, Dictionary, List, List, string> GetProjectFileActions(string name, dynamic value) + { + throw new NotImplementedException(); + } + + public Func GetProjectTypeActions(string name, dynamic value) + { + throw new NotImplementedException(); + } + + /* + public Func GetElementAccessExpressionActions(string name, dynamic value) + { + throw new NotImplementedException(); + } + */ + + public Func GetMemberAccessExpressionActions(string name, dynamic value) + { + throw new NotImplementedException(); + } +} diff --git a/src/CTA.Rules.RuleFiles/RulesFileParser.cs b/src/CTA.Rules.RuleFiles/RulesFileParser.cs index 8b18e81d..b79f56c7 100644 --- a/src/CTA.Rules.RuleFiles/RulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/RulesFileParser.cs @@ -105,7 +105,7 @@ private void LoadActions() { assemblies = Directory.EnumerateFiles(_assembliesDir, "*.dll").ToList(); } - actionsLoader = new ActionsLoader(assemblies, _projectLanguage); + actionsLoader = new ActionsLoader(assemblies); } /// diff --git a/tst/CTA.Rules.Test/Actions/ActionsLoaderTests.cs b/tst/CTA.Rules.Test/Actions/ActionsLoaderTests.cs index d7003926..b5916607 100644 --- a/tst/CTA.Rules.Test/Actions/ActionsLoaderTests.cs +++ b/tst/CTA.Rules.Test/Actions/ActionsLoaderTests.cs @@ -1,10 +1,4 @@ using CTA.Rules.Actions; -using CTA.Rules.Models; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; -using Newtonsoft.Json; using NUnit.Framework; using System.Collections.Generic; @@ -12,12 +6,12 @@ namespace CTA.Rules.Test.Actions { public class ActionLoaderTests { - ActionsLoader _actionLoader; + private ActionsLoader _actionLoader; [SetUp] public void SetUp() { - _actionLoader = new ActionsLoader(new List(), ProjectLanguage.Csharp); + _actionLoader = new ActionsLoader(new List()); } [Test] diff --git a/tst/CTA.Rules.Test/Actions/VisualBasicActionsLoaderTest.cs b/tst/CTA.Rules.Test/Actions/VisualBasicActionsLoaderTest.cs new file mode 100644 index 00000000..11c90106 --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasicActionsLoaderTest.cs @@ -0,0 +1,57 @@ +using CTA.Rules.Actions; +using CTA.Rules.Models; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Newtonsoft.Json; +using NUnit.Framework; +using System.Collections.Generic; + +namespace CTA.Rules.Test.Actions +{ + public class VisualBasicActionLoaderTests + { + private VisualBasicActionsLoader _actionLoader; + + [SetUp] + public void SetUp() + { + _actionLoader = new VisualBasicActionsLoader(new List()); + } + + [Test] + public void CompilationUnitActionsTest() + { + var addStatement = _actionLoader.GetCompilationUnitAction("AddStatement", "namespace"); + var removeStatement = _actionLoader.GetCompilationUnitAction("RemoveStatement", "namespace"); + var addComment = _actionLoader.GetCompilationUnitAction("AddComment", "comment"); + + Assert.IsNotNull(addStatement); + Assert.IsNotNull(removeStatement); + Assert.IsNotNull(addComment); + } + + [Test] + public void InvocationExpressionActionsTest() + { + var replaceMethodWithObjectAndParameters = _actionLoader.GetInvocationExpressionAction("ReplaceMethodWithObjectAndParameters", "{newMethod: \"method\", newParameters: \"params\"}"); + var replaceMethodWithObject = _actionLoader.GetInvocationExpressionAction("ReplaceMethodWithObject", "newMethod"); + var replaceMethodWithObjectAddType = _actionLoader.GetInvocationExpressionAction("ReplaceMethodWithObjectAddType", "newMethod"); + var replaceMethodAndParameters = _actionLoader.GetInvocationExpressionAction("ReplaceMethodAndParameters", "{ oldMethod: \"method\", newMethod: \"method\", newParameters: \"params\"}"); + var replaceMethodOnly = _actionLoader.GetInvocationExpressionAction("ReplaceMethodOnly", "{ oldMethod: \"method\", newMethod: \"method\" }"); + var replaceParametersOnly = _actionLoader.GetInvocationExpressionAction("ReplaceParametersOnly", "newParameters"); + var appendMethod = _actionLoader.GetInvocationExpressionAction("AppendMethod", "appendMethod"); + var addComment = _actionLoader.GetInvocationExpressionAction("AddComment", "comment"); + + Assert.IsNotNull(replaceMethodWithObjectAndParameters); + Assert.IsNotNull(replaceMethodWithObject); + Assert.IsNotNull(replaceMethodWithObjectAddType); + Assert.IsNotNull(replaceMethodAndParameters); + Assert.IsNotNull(replaceMethodOnly); + Assert.IsNotNull(replaceParametersOnly); + Assert.IsNotNull(appendMethod); + Assert.IsNotNull(addComment); + } + } +} \ No newline at end of file From 5344cc0984598f5f9f22727b586bba57081f3141 Mon Sep 17 00:00:00 2001 From: longachr Date: Thu, 12 May 2022 13:55:02 -0700 Subject: [PATCH 05/61] Initial commit for splitting C# and VB syntax processing Split off VB actions path Add CompilationUnit, InvocationExpression, and Namespace actions --- .../InvocationExpressionActions.cs | 19 +- .../VisualBasic/NamespaceActions.cs | 34 ++ .../VisualBasicActionsLoader.cs | 24 +- src/CTA.Rules.Analysis/RulesAnalysis.cs | 63 +-- .../Actions/Invocationexpressionaction.cs | 6 +- .../Actions/NamespaceAction.cs | 6 +- .../Actions/VisualBasic/ImportAction.cs | 24 + .../Csharp/CsharpRootNodes.cs | 40 ++ .../FileActions/FileActions.cs | 13 +- src/CTA.Rules.Models/ProjectActions.cs | 2 +- src/CTA.Rules.Models/RootNodes.cs | 2 - src/CTA.Rules.Models/Tokens/Attributetoken.cs | 2 +- .../Tokens/Classdeclarationtoken.cs | 2 +- .../Tokens/Csharp/CsharpNodeToken.cs | 61 +++ .../Tokens/Elementaccesstoken.cs | 2 +- .../Tokens/ExpressionToken.cs | 2 +- .../Tokens/Identifiernametoken.cs | 2 +- .../Tokens/InterfaceDeclarationToken.cs | 2 +- .../Tokens/Invocationexpressiontoken.cs | 2 +- .../Tokens/Memberaccesstoken.cs | 2 +- .../Tokens/MethodDeclarationToken.cs | 2 +- src/CTA.Rules.Models/Tokens/NamespaceToken.cs | 2 +- src/CTA.Rules.Models/Tokens/NodeToken.cs | 19 +- .../Tokens/ObjectCreationExpressionToken.cs | 2 +- src/CTA.Rules.Models/Tokens/ProjectToken.cs | 2 +- .../Tokens/Usingdirectivetoken.cs | 2 +- .../VisualBasic/ImportStatementToken.cs | 17 + .../VisualBasic/InvocationExpressionToken.cs | 18 + .../Tokens/VisualBasic/NamespaceToken.cs | 17 + .../Tokens/VisualBasic/ProjectToken.cs | 6 + .../VisualBasic/VisualBasicNodeToken.cs | 52 ++ .../VisualBasic/VisualBasicRootNodes.cs | 20 + .../ProjectRewriters/WCFProjectRewriter.cs | 2 +- src/CTA.Rules.PortCore/SolutionPort.cs | 4 +- src/CTA.Rules.RuleFiles/RulesFileLoader.cs | 35 +- src/CTA.Rules.RuleFiles/RulesFileParser.cs | 148 +++-- .../VisualBasicRulesFileParser.cs | 505 ++++++++++++++++++ src/CTA.Rules.Update/ActionsRewriter.cs | 16 +- .../ProjectRewriters/ProjectRewriter.cs | 6 +- src/CTA.Rules.Update/SolutionRewriter.cs | 2 +- .../InvocationExpressionActionsTests.cs | 4 +- .../Actions/VisualBasic/ActionsLoaderTests.cs | 59 ++ .../CompilationUnitActionsTests.cs | 77 +++ .../InvocationExpressionActionsTests.cs | 126 +++++ .../VisualBasic/NamespaceActionsTests.cs | 52 ++ 45 files changed, 1313 insertions(+), 192 deletions(-) create mode 100644 src/CTA.Rules.Actions/VisualBasic/NamespaceActions.cs create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs create mode 100644 src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs create mode 100644 src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/InvocationExpressionToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/NamespaceToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/ProjectToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs create mode 100644 src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs create mode 100644 src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/CompilationUnitActionsTests.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/InvocationExpressionActionsTests.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/NamespaceActionsTests.cs diff --git a/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs b/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs index 92521b65..8abfad3e 100644 --- a/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs +++ b/src/CTA.Rules.Actions/VisualBasic/InvocationExpressionActions.cs @@ -68,11 +68,12 @@ InvocationExpressionSyntax ReplaceMethod(SyntaxGenerator syntaxGenerator, Invoca if (typeToAdd != null) { - var argumentList = SyntaxFactory.ParseArgumentList($"(typeof({typeToAdd.Arguments.ToString()}))"); + var argumentList = SyntaxFactory.ParseArgumentList($"(TypeOf {typeToAdd.Arguments.ToString()})"); node = node.WithArgumentList(argumentList).WithLeadingTrivia(node.GetLeadingTrivia()); } - - node = node.WithExpression(SyntaxFactory.ParseExpression(newMethod)).WithLeadingTrivia(node.GetLeadingTrivia()).NormalizeWhitespace(); + + // in the test, the NormalizeWhitespace() was added weird white spaces .GetService(TypeOf Object )" + node = node.WithExpression(SyntaxFactory.ParseExpression(newMethod)).WithLeadingTrivia(node.GetLeadingTrivia()); return node; } return ReplaceMethod; @@ -139,14 +140,16 @@ public Func Microsoft.CodeAnalysis.VisualBasicExtensions.IsKind(t, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.DotToken)); + var operatorToken = node.DescendantTokens().FirstOrDefault(t => t.IsKind(SyntaxKind.DotToken)); node = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( - Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.SimpleMemberAccessExpression, + SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.InvocationExpression(node), operatorToken, - SyntaxFactory.IdentifierName(SyntaxFactory.ParseName(appendMethod).ToString())), - SyntaxFactory.ArgumentList()).NormalizeWhitespace(); + SyntaxFactory.IdentifierName(SyntaxFactory.ParseName(appendMethod).ToString()) + ), + SyntaxFactory.ArgumentList() + ).NormalizeWhitespace(); return node; } return ReplaceMethod; diff --git a/src/CTA.Rules.Actions/VisualBasic/NamespaceActions.cs b/src/CTA.Rules.Actions/VisualBasic/NamespaceActions.cs new file mode 100644 index 00000000..c988448c --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/NamespaceActions.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Actions.VisualBasic +{ + public class NamespaceActions + { + public Func GetRenameNamespaceAction(string newName) + { + NamespaceBlockSyntax RenameNamespace(SyntaxGenerator syntaxGenerator, NamespaceBlockSyntax node) + { + node = node.WithNamespaceStatement(SyntaxFactory.NamespaceStatement(SyntaxFactory.ParseName(newName))); + return node; + } + return RenameNamespace; + } + + /// + /// Only support remove using directive actions inside Namespace block. + /// The add using directive actions will be happening in CompiliationUnit. + /// + /// + /// + public Func GetRemoveDirectiveAction(string @namespace) + { + // Imports are not allowed within a namespace block in visual basic + throw new NotImplementedException(); + } + } +} diff --git a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs index f8318271..5b4f278f 100644 --- a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs +++ b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs @@ -15,10 +15,13 @@ namespace CTA.Rules.Actions; public class VisualBasicActionsLoader { private readonly List _compilationUnitActions, - _invocationExpressionActions; + _invocationExpressionActions, + _namespaceActions; + private readonly object _compilationUnitObject, - _invocationExpressionObject; + _invocationExpressionObject, + _namespaceObject; /// /// Initializes a new ActionLoader that loads the default actions @@ -28,6 +31,7 @@ public VisualBasicActionsLoader(List assemblyPaths) { _compilationUnitActions = new List(); _invocationExpressionActions = new List(); + _namespaceActions = new List(); var assemblies = ActionLoaderUtils.GetAssemblies(assemblyPaths); @@ -43,6 +47,8 @@ public VisualBasicActionsLoader(List assemblyPaths) out _compilationUnitObject); ActionLoaderUtils.TryCreateInstance(Constants.InvocationExpressionActions, types, out _invocationExpressionObject); + ActionLoaderUtils.TryCreateInstance(Constants.NamespaceActions, types, + out _namespaceObject); foreach (var t in types) { @@ -58,6 +64,11 @@ public VisualBasicActionsLoader(List assemblyPaths) _invocationExpressionActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); break; } + case Constants.NamespaceActions: + { + _namespaceActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + break; + } default: { LogHelper.LogError($"Action type {t.Name} is not found"); @@ -125,12 +136,13 @@ public Func G throw new NotImplementedException(); } */ - /* - public Func GetNamespaceActions(string name, dynamic value) + + public Func GetNamespaceActions(string name, dynamic value) { - throw new NotImplementedException(); + return ActionLoaderUtils.GetAction> + (_namespaceActions, _namespaceObject, name, value); } - */ + public Func GetObjectCreationExpressionActions(string name, dynamic value) { diff --git a/src/CTA.Rules.Analysis/RulesAnalysis.cs b/src/CTA.Rules.Analysis/RulesAnalysis.cs index 9e5435df..a3f91bb1 100644 --- a/src/CTA.Rules.Analysis/RulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/RulesAnalysis.cs @@ -8,6 +8,7 @@ using CTA.Rules.Config; using CTA.Rules.Models; using CTA.Rules.Models.Tokens; +using Microsoft.CodeAnalysis.CSharp.Syntax; namespace CTA.Rules.Analyzer { @@ -16,7 +17,7 @@ namespace CTA.Rules.Analyzer /// public class RulesAnalysis { - private readonly RootNodes _rootNodes; + private readonly CsharpRootNodes _csharpRootNodes; private readonly List _sourceFileResults; private readonly ProjectActions _projectActions; private readonly ProjectType _projectType; @@ -25,12 +26,12 @@ public class RulesAnalysis /// Initializes an RulesAnalysis instance /// /// List of analyzed code files - /// List of rules to be applied to the code files - public RulesAnalysis(List sourceFileResults, RootNodes rootNodes) + /// List of rules to be applied to the code files + public RulesAnalysis(List sourceFileResults, CsharpRootNodes csharpRootNodes) { _projectActions = new ProjectActions(); _sourceFileResults = sourceFileResults; - _rootNodes = rootNodes; + _csharpRootNodes = csharpRootNodes; _projectType = ProjectType.ClassLibrary; } @@ -38,13 +39,13 @@ public RulesAnalysis(List sourceFileResults, RootNodes rootNodes) /// Initializes a RulesAnalysis instance /// /// List of analyzed code files - /// List of rules to be applied to the code files + /// List of rules to be applied to the code files /// Type of project - public RulesAnalysis(List sourceFileResults, RootNodes rootNodes, ProjectType projectType = ProjectType.ClassLibrary) + public RulesAnalysis(List sourceFileResults, CsharpRootNodes csharpRootNodes, ProjectType projectType = ProjectType.ClassLibrary) { _projectActions = new ProjectActions(); _sourceFileResults = sourceFileResults; - _rootNodes = rootNodes; + _csharpRootNodes = csharpRootNodes; _projectType = projectType; } @@ -64,7 +65,7 @@ public ProjectActions Analyze() } }); - AddPackages(_rootNodes.ProjectTokens.Where(p => p.FullKey == _projectType.ToString())?.SelectMany(p => p.PackageActions)?.Distinct()?.ToList(), null); + AddPackages(_csharpRootNodes.ProjectTokens.Where(p => p.FullKey == _projectType.ToString())?.SelectMany(p => p.PackageActions)?.Distinct()?.ToList(), null); return _projectActions; } @@ -119,7 +120,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { var annotation = (Annotation)child; var compareToken = new AttributeToken() { Key = annotation.Identifier, Namespace = annotation.Reference.Namespace, Type = annotation.SemanticClassType }; - _rootNodes.Attributetokens.TryGetValue(compareToken, out var token); + _csharpRootNodes.Attributetokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -132,7 +133,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, string overrideKey = string.Empty; var compareToken = new UsingDirectiveToken() { Key = child.Identifier }; - _rootNodes.Usingdirectivetokens.TryGetValue(compareToken, out var token); + _csharpRootNodes.Usingdirectivetokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -142,7 +143,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, //Attempt a wildcard search, if applicable. This is using directive specific because it might want to include all sub-namespaces if (token == null) { - var wildcardMatches = _rootNodes.Usingdirectivetokens.Where(i => i.Key.Contains("*")); + var wildcardMatches = _csharpRootNodes.Usingdirectivetokens.Where(i => i.Key.Contains("*")); if (wildcardMatches.Any()) { token = wildcardMatches.FirstOrDefault(i => compareToken.Key.WildcardEquals(i.Key)); @@ -164,7 +165,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, case IdConstants.NamespaceIdName: { var compareToken = new NamespaceToken() { Key = child.Identifier }; - _rootNodes.NamespaceTokens.TryGetValue(compareToken, out var token); + _csharpRootNodes.NamespaceTokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -177,7 +178,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { var classType = (ClassDeclaration)child; var baseToken = new ClassDeclarationToken() { FullKey = classType.BaseType }; - _rootNodes.Classdeclarationtokens.TryGetValue(baseToken, out var token); + _csharpRootNodes.Classdeclarationtokens.TryGetValue(baseToken, out var token); if (token != null) { @@ -190,7 +191,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, token = null; string name = string.Concat(classType.Reference != null ? string.Concat(classType.Reference.Namespace, ".") : string.Empty, classType.Identifier); var nameToken = new ClassDeclarationToken() { FullKey = name }; - _rootNodes.Classdeclarationtokens.TryGetValue(nameToken, out token); + _csharpRootNodes.Classdeclarationtokens.TryGetValue(nameToken, out token); if (token != null) { @@ -204,7 +205,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, foreach (string interfaceName in classType.BaseList) { var baseListToken = new ClassDeclarationToken() { FullKey = interfaceName }; - _rootNodes.Classdeclarationtokens.TryGetValue(baseListToken, out token); + _csharpRootNodes.Classdeclarationtokens.TryGetValue(baseListToken, out token); if (token != null) { @@ -226,7 +227,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, if (!string.IsNullOrEmpty(interfaceType.BaseType)) { - _rootNodes.InterfaceDeclarationTokens.TryGetValue(baseToken, out token); + _csharpRootNodes.InterfaceDeclarationTokens.TryGetValue(baseToken, out token); } if (token != null) @@ -240,7 +241,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, token = null; string name = string.Concat(interfaceType.Reference != null ? string.Concat(interfaceType.Reference.Namespace, ".") : string.Empty, interfaceType.Identifier); var nameToken = new InterfaceDeclarationToken() { FullKey = name }; - _rootNodes.InterfaceDeclarationTokens.TryGetValue(nameToken, out token); + _csharpRootNodes.InterfaceDeclarationTokens.TryGetValue(nameToken, out token); if (token != null) { @@ -256,7 +257,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, case IdConstants.MethodIdName: { var compareToken = new MethodDeclarationToken() { FullKey = string.Concat(child.Identifier) }; - _rootNodes.MethodDeclarationTokens.TryGetValue(compareToken, out var token); + _csharpRootNodes.MethodDeclarationTokens.TryGetValue(compareToken, out var token); if (token != null) { AddNamedActions(fileAction, token, child.Identifier, child.TextSpan); @@ -276,12 +277,12 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, if (string.IsNullOrEmpty(invocationExpression.SemanticOriginalDefinition)) break; var compareToken = new InvocationExpressionToken() { Key = invocationExpression.SemanticOriginalDefinition, Namespace = invocationExpression.Reference.Namespace, Type = invocationExpression.SemanticClassType }; - _rootNodes.Invocationexpressiontokens.TryGetValue(compareToken, out var token); + _csharpRootNodes.Invocationexpressiontokens.TryGetValue(compareToken, out var token); //Attempt a wildcard search, if applicable. This is invocation expression specific because it has to look inside the invocation expressions only if(token == null) { - var wildcardMatches = _rootNodes.Invocationexpressiontokens.Where(i => i.Key.Contains("*")); + var wildcardMatches = _csharpRootNodes.Invocationexpressiontokens.Where(i => i.Key.Contains("*")); if (wildcardMatches.Any()) { token = wildcardMatches.FirstOrDefault(i => compareToken.Key.WildcardEquals(i.Key) && compareToken.Namespace == i.Namespace && compareToken.Type == i.Type); @@ -299,7 +300,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { string semanticClassType = invocationExpression.SemanticClassType.Substring(0,invocationExpression.SemanticClassType.IndexOf('<')); compareToken = new InvocationExpressionToken() { Key = invocationExpression.SemanticOriginalDefinition, Namespace = invocationExpression.Reference.Namespace, Type = semanticClassType }; - _rootNodes.Invocationexpressiontokens.TryGetValue(compareToken, out token); + _csharpRootNodes.Invocationexpressiontokens.TryGetValue(compareToken, out token); } } } @@ -322,7 +323,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, Type = elementAccess.SemanticClassType, Namespace = elementAccess.Reference?.Namespace }; - _rootNodes.ElementAccesstokens.TryGetValue(compareToken, out var token); + _csharpRootNodes.ElementAccesstokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -342,7 +343,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, Type = memberAccess.SemanticClassType, Namespace = memberAccess.Reference?.Namespace }; - _rootNodes.MemberAccesstokens.TryGetValue(compareToken, out var token); + _csharpRootNodes.MemberAccesstokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -355,7 +356,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { var declarationNode = (DeclarationNode)child; var compareToken = new IdentifierNameToken() { Key = string.Concat(declarationNode.Reference.Namespace, ".", declarationNode.Identifier), Namespace = declarationNode.Reference.Namespace }; - _rootNodes.Identifiernametokens.TryGetValue(compareToken, out var token); + _csharpRootNodes.Identifiernametokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -369,7 +370,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, var objectCreationNode = (ObjectCreationExpression)child; //Rules based on Object Creation Parent Hierarchy var compareToken = new ObjectCreationExpressionToken() { Key = objectCreationNode.Identifier, Namespace = objectCreationNode.Reference?.Namespace, Type = objectCreationNode.SemanticClassType }; - _rootNodes.ObjectCreationExpressionTokens.TryGetValue(compareToken, out var token); + _csharpRootNodes.ObjectCreationExpressionTokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -378,7 +379,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, //Rules based on Object Creation location within code var compareTokenLocation = new ObjectCreationExpressionToken() { Key = objectCreationNode.Identifier, Namespace = parentNamespace, Type = parentClass }; - _rootNodes.ObjectCreationExpressionTokens.TryGetValue(compareTokenLocation, out var tokenLocation); + _csharpRootNodes.ObjectCreationExpressionTokens.TryGetValue(compareTokenLocation, out var tokenLocation); if (tokenLocation != null) { AddActions(fileAction, tokenLocation, child.TextSpan); @@ -389,7 +390,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, if(!string.IsNullOrEmpty(objectCreationNode.SemanticOriginalDefinition)) { var nameToken = new ObjectCreationExpressionToken() { Key = objectCreationNode.SemanticOriginalDefinition, Namespace = objectCreationNode.SemanticNamespace, Type = objectCreationNode.SemanticClassType }; - _rootNodes.ObjectCreationExpressionTokens.TryGetValue(nameToken, out token); + _csharpRootNodes.ObjectCreationExpressionTokens.TryGetValue(nameToken, out token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -436,7 +437,7 @@ private string GetFullKey(string containingNamespace, string containingClass, st /// /// The file to run actions on /// The token that matched the file - private void AddActions(FileActions fileAction, NodeToken token, TextSpan textSpan, string overrideKey = "") + private void AddActions(FileActions fileAction, CsharpNodeToken token, TextSpan textSpan, string overrideKey = "") { fileAction.AttributeActions.UnionWith(token.AttributeActions.Select(a => new AttributeAction() { @@ -476,7 +477,7 @@ private void AddActions(FileActions fileAction, NodeToken token, TextSpan textSp IdentifierNameActionFunc = a.IdentifierNameActionFunc, }).ToList()); - fileAction.InvocationExpressionActions.UnionWith(token.InvocationExpressionActions.Select(a => new InvocationExpressionAction() + fileAction.InvocationExpressionActions.UnionWith(token.InvocationExpressionActions.Select(a => new InvocationExpressionAction() { Key = !string.IsNullOrEmpty(overrideKey) ? overrideKey : a.Key, Description = a.Description, @@ -525,7 +526,7 @@ private void AddActions(FileActions fileAction, NodeToken token, TextSpan textSp NamespaceUsingActionFunc = a.NamespaceUsingActionFunc, }).ToList()); - fileAction.NamespaceActions.UnionWith(token.NamespaceActions.Select(a => new NamespaceAction() + fileAction.NamespaceActions.UnionWith(token.NamespaceActions.Select(a => new NamespaceAction() { Key = a.Key, Description = a.Description, @@ -605,7 +606,7 @@ private void AddPackages(List packageActions, TextSpan textSpan) /// /// /// - private void AddNamedActions(FileActions fileAction, NodeToken token, string identifier, TextSpan textSpan) + private void AddNamedActions(FileActions fileAction, CsharpNodeToken token, string identifier, TextSpan textSpan) { fileAction.ClassDeclarationActions.UnionWith(token.ClassDeclarationActions diff --git a/src/CTA.Rules.Models/Actions/Invocationexpressionaction.cs b/src/CTA.Rules.Models/Actions/Invocationexpressionaction.cs index 8eef5821..1ad464e9 100644 --- a/src/CTA.Rules.Models/Actions/Invocationexpressionaction.cs +++ b/src/CTA.Rules.Models/Actions/Invocationexpressionaction.cs @@ -5,13 +5,13 @@ namespace CTA.Rules.Models { - public class InvocationExpressionAction : GenericAction + public class InvocationExpressionAction : GenericAction { - public Func InvocationExpressionActionFunc { get; set; } + public Func InvocationExpressionActionFunc { get; set; } public override bool Equals(object obj) { - var action = (InvocationExpressionAction)obj; + var action = (InvocationExpressionAction)obj; return action?.Key == this.Key && action?.Value == this.Value && action?.InvocationExpressionActionFunc.Method.Name == this.InvocationExpressionActionFunc.Method.Name; diff --git a/src/CTA.Rules.Models/Actions/NamespaceAction.cs b/src/CTA.Rules.Models/Actions/NamespaceAction.cs index 4c7dfb31..21e790be 100644 --- a/src/CTA.Rules.Models/Actions/NamespaceAction.cs +++ b/src/CTA.Rules.Models/Actions/NamespaceAction.cs @@ -5,13 +5,13 @@ namespace CTA.Rules.Models { - public class NamespaceAction : GenericAction + public class NamespaceAction : GenericAction { - public Func NamespaceActionFunc { get; set; } + public Func NamespaceActionFunc { get; set; } public override bool Equals(object obj) { - var action = (NamespaceAction)obj; + var action = (NamespaceAction)obj; return action?.Value == this.Value && action?.NamespaceActionFunc.Method.Name == this.NamespaceActionFunc.Method.Name; } diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs new file mode 100644 index 00000000..d0fa593d --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Models.VisualBasic; + +public class ImportAction : GenericAction +{ + public Func ImportActionFunc { get; set; } + public Func ImportsClauseActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (UsingAction)obj; + return action?.Value == Value && + (action?.UsingActionFunc.Method.Name == ImportActionFunc.Method.Name || + action?.NamespaceUsingActionFunc.Method.Name == ImportsClauseActionFunc.Method.Name); + } + + public override int GetHashCode() + { + return HashCode.Combine(Value, ImportActionFunc?.Method.Name); + } +} diff --git a/src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs b/src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs new file mode 100644 index 00000000..e96e4b27 --- /dev/null +++ b/src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using CTA.Rules.Models.Tokens; + +namespace CTA.Rules.Models +{ + public class CsharpRootNodes + { + public CsharpRootNodes() + { + Attributetokens = new HashSet(); + Classdeclarationtokens = new HashSet(); + ElementAccesstokens = new HashSet(); + Identifiernametokens = new HashSet(); + Invocationexpressiontokens = new HashSet(); + Expressiontokens = new HashSet(); + MemberAccesstokens = new HashSet(); + Usingdirectivetokens = new HashSet(); + MethodDeclarationTokens = new HashSet(); + ObjectCreationExpressionTokens = new HashSet(); + InterfaceDeclarationTokens = new HashSet(); + NamespaceTokens = new HashSet(); + ProjectTokens = new HashSet(); + } + + + public HashSet Attributetokens { get; set; } + public HashSet Classdeclarationtokens { get; set; } + public HashSet InterfaceDeclarationTokens { get; set; } + public HashSet ElementAccesstokens { get; set; } + public HashSet Identifiernametokens { get; set; } + public HashSet Invocationexpressiontokens { get; set; } + public HashSet Expressiontokens { get; set; } + public HashSet MemberAccesstokens { get; set; } + public HashSet Usingdirectivetokens { get; set; } + public HashSet MethodDeclarationTokens { get; set; } + public HashSet NamespaceTokens { get; set; } + public HashSet ObjectCreationExpressionTokens { get; set; } + public HashSet ProjectTokens { get; set; } + } +} diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index 03012f9b..d11c9e41 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using CTA.Rules.Models.Tokens; +using Microsoft.CodeAnalysis.CSharp.Syntax; namespace CTA.Rules.Models { @@ -12,18 +13,18 @@ public FileActions() MethodDeclarationActions = new HashSet(); ElementAccessActions = new HashSet(); IdentifierNameActions = new HashSet(); - InvocationExpressionActions = new HashSet(); + InvocationExpressionActions = new HashSet>(); ExpressionActions = new HashSet(); MemberAccessActions = new HashSet(); Usingactions = new HashSet(); - NamespaceActions = new HashSet(); + NamespaceActions = new HashSet>(); ObjectCreationExpressionActions = new HashSet(); PackageActions = new HashSet(); InterfaceDeclarationActions = new HashSet(); - NodeTokens = new List(); + NodeTokens = new List(); } - public List NodeTokens { get; set; } + public List NodeTokens { get; set; } public string FilePath { get; set; } public HashSet AttributeActions { get; set; } public HashSet MethodDeclarationActions { get; set; } @@ -31,12 +32,12 @@ public FileActions() public HashSet InterfaceDeclarationActions { get; set; } public HashSet ElementAccessActions { get; set; } public HashSet IdentifierNameActions { get; set; } - public HashSet InvocationExpressionActions { get; set; } + public HashSet> InvocationExpressionActions { get; set; } public HashSet ExpressionActions { get; set; } public HashSet MemberAccessActions { get; set; } public HashSet ObjectCreationExpressionActions { get; set; } public HashSet Usingactions { get; set; } - public HashSet NamespaceActions { get; set; } + public HashSet> NamespaceActions { get; set; } public HashSet PackageActions { get; set; } public List AllActions diff --git a/src/CTA.Rules.Models/ProjectActions.cs b/src/CTA.Rules.Models/ProjectActions.cs index 398b0df3..c80a9913 100644 --- a/src/CTA.Rules.Models/ProjectActions.cs +++ b/src/CTA.Rules.Models/ProjectActions.cs @@ -20,7 +20,7 @@ public ProjectActions() public BlockingCollection PackageActions { get; set; } public BlockingCollection ProjectReferenceActions { get; set; } public List ProjectLevelActions { get; set; } - public RootNodes ProjectRules { get; set; } + public CsharpRootNodes ProjectRules { get; set; } public override string ToString() { diff --git a/src/CTA.Rules.Models/RootNodes.cs b/src/CTA.Rules.Models/RootNodes.cs index 1255cff2..c43f10ad 100644 --- a/src/CTA.Rules.Models/RootNodes.cs +++ b/src/CTA.Rules.Models/RootNodes.cs @@ -14,7 +14,6 @@ public RootNodes() Invocationexpressiontokens = new HashSet(); Expressiontokens = new HashSet(); MemberAccesstokens = new HashSet(); - Usingdirectivetokens = new HashSet(); MethodDeclarationTokens = new HashSet(); ObjectCreationExpressionTokens = new HashSet(); InterfaceDeclarationTokens = new HashSet(); @@ -31,7 +30,6 @@ public RootNodes() public HashSet Invocationexpressiontokens { get; set; } public HashSet Expressiontokens { get; set; } public HashSet MemberAccesstokens { get; set; } - public HashSet Usingdirectivetokens { get; set; } public HashSet MethodDeclarationTokens { get; set; } public HashSet NamespaceTokens { get; set; } public HashSet ObjectCreationExpressionTokens { get; set; } diff --git a/src/CTA.Rules.Models/Tokens/Attributetoken.cs b/src/CTA.Rules.Models/Tokens/Attributetoken.cs index b60a776b..0ad3413c 100644 --- a/src/CTA.Rules.Models/Tokens/Attributetoken.cs +++ b/src/CTA.Rules.Models/Tokens/Attributetoken.cs @@ -5,7 +5,7 @@ namespace CTA.Rules.Models { - public class AttributeToken : NodeToken + public class AttributeToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/Classdeclarationtoken.cs b/src/CTA.Rules.Models/Tokens/Classdeclarationtoken.cs index fd2edbef..5a660a98 100644 --- a/src/CTA.Rules.Models/Tokens/Classdeclarationtoken.cs +++ b/src/CTA.Rules.Models/Tokens/Classdeclarationtoken.cs @@ -4,7 +4,7 @@ namespace CTA.Rules.Models { - public class ClassDeclarationToken : NodeToken + public class ClassDeclarationToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs b/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs new file mode 100644 index 00000000..aee7c8ad --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs @@ -0,0 +1,61 @@ +using System.Linq; +using System.Collections.Generic; +using CTA.Rules.Config; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using TextSpan = Codelyzer.Analysis.Model.TextSpan; + +namespace CTA.Rules.Models.Tokens +{ + public class CsharpNodeToken : NodeToken + { + public CsharpNodeToken() + { + UsingActions = new List(); + InvocationExpressionActions = new List>(); + NamespaceActions = new List>(); + } + + public List UsingActions { get; set; } + public List> InvocationExpressionActions { get; set; } + public List> NamespaceActions { get; set; } + + public CsharpNodeToken Clone() + { + CsharpNodeToken cloned = (CsharpNodeToken)this.MemberwiseClone(); + cloned.TextChanges = cloned.TextChanges?.Select(textChange => textChange.Clone()).ToList(); + cloned.TargetCPU = cloned.TargetCPU?.ToList(); + cloned.AttributeActions = cloned.AttributeActions?.Select(action => action.Clone())?.ToList(); + cloned.AttributeListActions = cloned.AttributeListActions?.Select(action => action.Clone())?.ToList(); + cloned.ClassDeclarationActions = cloned.ClassDeclarationActions?.Select(action => action.Clone())?.ToList(); + cloned.InterfaceDeclarationActions = cloned.InterfaceDeclarationActions.Select(action => action.Clone()).ToList(); + cloned.MethodDeclarationActions = cloned.MethodDeclarationActions.Select(action => action.Clone()).ToList(); + cloned.ElementAccessActions = cloned.ElementAccessActions.Select(action => action.Clone()).ToList(); + cloned.MemberAccessActions = cloned.MemberAccessActions.Select(action => action.Clone()).ToList(); + cloned.UsingActions = cloned.UsingActions.Select(action => action.Clone()).ToList(); + cloned.IdentifierNameActions = cloned.IdentifierNameActions.Select(action => action.Clone()).ToList(); + cloned.InvocationExpressionActions = cloned.InvocationExpressionActions.Select(action => action.Clone>()).ToList(); + cloned.ExpressionActions = cloned.ExpressionActions.Select(action => action.Clone()).ToList(); + cloned.NamespaceActions = cloned.NamespaceActions.Select(action => action.Clone>()).ToList(); + cloned.ObjectCreationExpressionActions = cloned.ObjectCreationExpressionActions.Select(action => action.Clone()).ToList(); + cloned.PackageActions = cloned.PackageActions.Select(action => action.Clone()).ToList(); + cloned.ProjectLevelActions = cloned.ProjectLevelActions.Select(action => action.Clone()).ToList(); + cloned.ProjectFileActions = cloned.ProjectFileActions.Select(action => action.Clone()).ToList(); + cloned.ProjectTypeActions = cloned.ProjectTypeActions.Select(action => action.Clone()).ToList(); + return cloned; + } + + public override List AllActions + { + get + { + var allActions = new List(); + allActions.AddRange(InvocationExpressionActions); + allActions.AddRange(UsingActions); + allActions.AddRange(NamespaceActions); + allActions.AddRange(base.AllActions); + return allActions; + } + } + + } +} diff --git a/src/CTA.Rules.Models/Tokens/Elementaccesstoken.cs b/src/CTA.Rules.Models/Tokens/Elementaccesstoken.cs index 36786c27..bb92bf40 100644 --- a/src/CTA.Rules.Models/Tokens/Elementaccesstoken.cs +++ b/src/CTA.Rules.Models/Tokens/Elementaccesstoken.cs @@ -4,7 +4,7 @@ namespace CTA.Rules.Models { - public class ElementAccessToken : NodeToken + public class ElementAccessToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/ExpressionToken.cs b/src/CTA.Rules.Models/Tokens/ExpressionToken.cs index eb3eab9e..ab46e1cb 100644 --- a/src/CTA.Rules.Models/Tokens/ExpressionToken.cs +++ b/src/CTA.Rules.Models/Tokens/ExpressionToken.cs @@ -3,7 +3,7 @@ namespace CTA.Rules.Models.Tokens { - public class ExpressionToken : NodeToken + public class ExpressionToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/Identifiernametoken.cs b/src/CTA.Rules.Models/Tokens/Identifiernametoken.cs index e1abab25..8ca31f72 100644 --- a/src/CTA.Rules.Models/Tokens/Identifiernametoken.cs +++ b/src/CTA.Rules.Models/Tokens/Identifiernametoken.cs @@ -5,7 +5,7 @@ namespace CTA.Rules.Models { - public class IdentifierNameToken : NodeToken + public class IdentifierNameToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/InterfaceDeclarationToken.cs b/src/CTA.Rules.Models/Tokens/InterfaceDeclarationToken.cs index d39e34cf..2766066d 100644 --- a/src/CTA.Rules.Models/Tokens/InterfaceDeclarationToken.cs +++ b/src/CTA.Rules.Models/Tokens/InterfaceDeclarationToken.cs @@ -4,7 +4,7 @@ namespace CTA.Rules.Models { - public class InterfaceDeclarationToken : NodeToken + public class InterfaceDeclarationToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/Invocationexpressiontoken.cs b/src/CTA.Rules.Models/Tokens/Invocationexpressiontoken.cs index b0e01826..28cf80fd 100644 --- a/src/CTA.Rules.Models/Tokens/Invocationexpressiontoken.cs +++ b/src/CTA.Rules.Models/Tokens/Invocationexpressiontoken.cs @@ -3,7 +3,7 @@ namespace CTA.Rules.Models.Tokens { - public class InvocationExpressionToken : NodeToken + public class InvocationExpressionToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/Memberaccesstoken.cs b/src/CTA.Rules.Models/Tokens/Memberaccesstoken.cs index f42dd2c7..83767ca2 100644 --- a/src/CTA.Rules.Models/Tokens/Memberaccesstoken.cs +++ b/src/CTA.Rules.Models/Tokens/Memberaccesstoken.cs @@ -5,7 +5,7 @@ namespace CTA.Rules.Models { - public class MemberAccessToken : NodeToken + public class MemberAccessToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/MethodDeclarationToken.cs b/src/CTA.Rules.Models/Tokens/MethodDeclarationToken.cs index 13d26610..c2486b96 100644 --- a/src/CTA.Rules.Models/Tokens/MethodDeclarationToken.cs +++ b/src/CTA.Rules.Models/Tokens/MethodDeclarationToken.cs @@ -2,7 +2,7 @@ namespace CTA.Rules.Models.Tokens { - public class MethodDeclarationToken : NodeToken + public class MethodDeclarationToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/NamespaceToken.cs b/src/CTA.Rules.Models/Tokens/NamespaceToken.cs index 5a62df35..45711213 100644 --- a/src/CTA.Rules.Models/Tokens/NamespaceToken.cs +++ b/src/CTA.Rules.Models/Tokens/NamespaceToken.cs @@ -3,7 +3,7 @@ namespace CTA.Rules.Models.Tokens { - public class NamespaceToken : NodeToken + public class NamespaceToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/NodeToken.cs b/src/CTA.Rules.Models/Tokens/NodeToken.cs index ffa0a9e7..ede98f24 100644 --- a/src/CTA.Rules.Models/Tokens/NodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/NodeToken.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Collections.Generic; using CTA.Rules.Config; +using Microsoft.CodeAnalysis.CSharp.Syntax; using TextSpan = Codelyzer.Analysis.Model.TextSpan; namespace CTA.Rules.Models.Tokens @@ -12,14 +13,11 @@ public NodeToken() AttributeActions = new List(); AttributeListActions = new List(); ClassDeclarationActions = new List(); - UsingActions = new List(); IdentifierNameActions = new List(); - InvocationExpressionActions = new List(); ExpressionActions = new List(); MethodDeclarationActions = new List(); ElementAccessActions = new List(); MemberAccessActions = new List(); - NamespaceActions = new List(); ObjectCreationExpressionActions = new List(); PackageActions = new List(); InterfaceDeclarationActions = new List(); @@ -45,20 +43,17 @@ public NodeToken() public List MethodDeclarationActions { get; set; } public List ElementAccessActions { get; set; } public List MemberAccessActions { get; set; } - public List UsingActions { get; set; } public List IdentifierNameActions { get; set; } - public List InvocationExpressionActions { get; set; } public List ExpressionActions { get; set; } - public List NamespaceActions { get; set; } public List ObjectCreationExpressionActions { get; set; } public List PackageActions { get; set; } public List ProjectLevelActions { get; set; } public List ProjectFileActions { get; set; } public List ProjectTypeActions { get; set; } - public NodeToken Clone() + public CsharpNodeToken Clone() { - NodeToken cloned = (NodeToken)this.MemberwiseClone(); + CsharpNodeToken cloned = (CsharpNodeToken)this.MemberwiseClone(); cloned.TextChanges = cloned.TextChanges?.Select(textChange => textChange.Clone()).ToList(); cloned.TargetCPU = cloned.TargetCPU?.ToList(); cloned.AttributeActions = cloned.AttributeActions?.Select(action => action.Clone())?.ToList(); @@ -68,11 +63,8 @@ public NodeToken Clone() cloned.MethodDeclarationActions = cloned.MethodDeclarationActions.Select(action => action.Clone()).ToList(); cloned.ElementAccessActions = cloned.ElementAccessActions.Select(action => action.Clone()).ToList(); cloned.MemberAccessActions = cloned.MemberAccessActions.Select(action => action.Clone()).ToList(); - cloned.UsingActions = cloned.UsingActions.Select(action => action.Clone()).ToList(); cloned.IdentifierNameActions = cloned.IdentifierNameActions.Select(action => action.Clone()).ToList(); - cloned.InvocationExpressionActions = cloned.InvocationExpressionActions.Select(action => action.Clone()).ToList(); cloned.ExpressionActions = cloned.ExpressionActions.Select(action => action.Clone()).ToList(); - cloned.NamespaceActions = cloned.NamespaceActions.Select(action => action.Clone()).ToList(); cloned.ObjectCreationExpressionActions = cloned.ObjectCreationExpressionActions.Select(action => action.Clone()).ToList(); cloned.PackageActions = cloned.PackageActions.Select(action => action.Clone()).ToList(); cloned.ProjectLevelActions = cloned.ProjectLevelActions.Select(action => action.Clone()).ToList(); @@ -81,7 +73,7 @@ public NodeToken Clone() return cloned; } - public List AllActions + public virtual List AllActions { get { @@ -94,12 +86,9 @@ public List AllActions allActions.AddRange(ElementAccessActions); allActions.AddRange(MemberAccessActions); allActions.AddRange(IdentifierNameActions); - allActions.AddRange(InvocationExpressionActions); allActions.AddRange(ExpressionActions); allActions.AddRange(MemberAccessActions); - allActions.AddRange(UsingActions); allActions.AddRange(ObjectCreationExpressionActions); - allActions.AddRange(NamespaceActions); return allActions; } } diff --git a/src/CTA.Rules.Models/Tokens/ObjectCreationExpressionToken.cs b/src/CTA.Rules.Models/Tokens/ObjectCreationExpressionToken.cs index 8371e590..7fc08e4f 100644 --- a/src/CTA.Rules.Models/Tokens/ObjectCreationExpressionToken.cs +++ b/src/CTA.Rules.Models/Tokens/ObjectCreationExpressionToken.cs @@ -4,7 +4,7 @@ namespace CTA.Rules.Models.Tokens { - public class ObjectCreationExpressionToken : NodeToken + public class ObjectCreationExpressionToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/ProjectToken.cs b/src/CTA.Rules.Models/Tokens/ProjectToken.cs index 0f66da6c..fe4b6857 100644 --- a/src/CTA.Rules.Models/Tokens/ProjectToken.cs +++ b/src/CTA.Rules.Models/Tokens/ProjectToken.cs @@ -1,6 +1,6 @@ namespace CTA.Rules.Models.Tokens { - public class ProjectToken : NodeToken + public class ProjectToken : CsharpNodeToken { } } diff --git a/src/CTA.Rules.Models/Tokens/Usingdirectivetoken.cs b/src/CTA.Rules.Models/Tokens/Usingdirectivetoken.cs index 1b5a1efe..cb9c4a53 100644 --- a/src/CTA.Rules.Models/Tokens/Usingdirectivetoken.cs +++ b/src/CTA.Rules.Models/Tokens/Usingdirectivetoken.cs @@ -3,7 +3,7 @@ namespace CTA.Rules.Models.Tokens { - public class UsingDirectiveToken : NodeToken + public class UsingDirectiveToken : CsharpNodeToken { public override bool Equals(object obj) { diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs new file mode 100644 index 00000000..23da982d --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs @@ -0,0 +1,17 @@ +using System; +using Microsoft.Build.Logging.StructuredLogger; + +namespace CTA.Rules.Models.Tokens.VisualBasic; + +public class ImportStatementToken : VisualBasicNodeToken +{ + public override bool Equals(object obj) + { + var token = (ImportStatementToken)obj; + return token?.Key == this.Key; + } + public override int GetHashCode() + { + return HashCode.Combine(Key); + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/InvocationExpressionToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/InvocationExpressionToken.cs new file mode 100644 index 00000000..85b466a8 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/InvocationExpressionToken.cs @@ -0,0 +1,18 @@ +using System; +using CTA.Rules.Config; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class InvocationExpressionToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (InvocationExpressionToken)obj; + return token?.Key == this.Key && token?.Namespace == this.Namespace && token?.Type == this.Type; + } + public override int GetHashCode() + { + return HashCode.Combine(Key, Namespace, Type); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/NamespaceToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/NamespaceToken.cs new file mode 100644 index 00000000..c8c7c206 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/NamespaceToken.cs @@ -0,0 +1,17 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class NamespaceToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (NamespaceToken)obj; + return token?.Key == this.Key; + } + public override int GetHashCode() + { + return HashCode.Combine(Key); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/ProjectToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/ProjectToken.cs new file mode 100644 index 00000000..b8940d59 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/ProjectToken.cs @@ -0,0 +1,6 @@ +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class ProjectToken : VisualBasicNodeToken + { + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs new file mode 100644 index 00000000..c5a2ee0c --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs @@ -0,0 +1,52 @@ +using System.Linq; +using System.Collections.Generic; +using CTA.Rules.Config; +using CTA.Rules.Models.VisualBasic; +using Microsoft.Build.Logging.StructuredLogger; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using TextSpan = Codelyzer.Analysis.Model.TextSpan; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class VisualBasicNodeToken : NodeToken + { + public VisualBasicNodeToken() + { + InvocationExpressionActions = new List>(); + ImportActions = new List(); + NamespaceActions = new List>(); + } + + public List> InvocationExpressionActions { get; set; } + public List ImportActions { get; set; } + public List> NamespaceActions { get; set; } + + public VisualBasicNodeToken Clone() + { + VisualBasicNodeToken cloned = (VisualBasicNodeToken)this.MemberwiseClone(); + cloned.TextChanges = cloned.TextChanges?.Select(textChange => textChange.Clone()).ToList(); + cloned.TargetCPU = cloned.TargetCPU?.ToList(); + cloned.InvocationExpressionActions = cloned.InvocationExpressionActions + .Select(action => action.Clone>()).ToList(); + cloned.ImportActions = cloned.ImportActions + .Select(action => action.Clone()).ToList(); + cloned.NamespaceActions = cloned.NamespaceActions + .Select(action => action.Clone>()).ToList(); + return cloned; + } + + public override List AllActions + { + get + { + var allActions = new List(); + allActions.AddRange(InvocationExpressionActions); + allActions.AddRange(NamespaceActions); + allActions.AddRange(ImportActions); + allActions.AddRange(base.AllActions); + return allActions; + } + } + + } +} diff --git a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs new file mode 100644 index 00000000..330390b3 --- /dev/null +++ b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using CTA.Rules.Models.Tokens.VisualBasic; +using NamespaceToken = CTA.Rules.Models.Tokens.VisualBasic.NamespaceToken; + +namespace CTA.Rules.Models.VisualBasic +{ + public class VisualBasicRootNodes + { + public VisualBasicRootNodes() + { + InvocationExpressionTokens = new HashSet(); + ImportStatementTokens = new HashSet(); + NamespaceTokens = new HashSet(); + } + + public HashSet InvocationExpressionTokens { get; set; } + public HashSet ImportStatementTokens { get; set; } + public HashSet NamespaceTokens { get; set; } + } +} diff --git a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs index a7f06690..9cbd6338 100644 --- a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs +++ b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs @@ -56,7 +56,7 @@ public override ProjectResult Run(ProjectActions projectActions) return _projectResult; } - public override List RunIncremental(List updatedFiles, RootNodes projectRules) + public override List RunIncremental(List updatedFiles, CsharpRootNodes projectRules) { base.RunIncremental(updatedFiles, projectRules); var ideFileActions = new List(); diff --git a/src/CTA.Rules.PortCore/SolutionPort.cs b/src/CTA.Rules.PortCore/SolutionPort.cs index 9aae14a2..1479ab25 100644 --- a/src/CTA.Rules.PortCore/SolutionPort.cs +++ b/src/CTA.Rules.PortCore/SolutionPort.cs @@ -350,7 +350,7 @@ public PortSolutionResult GenerateResults() /// The rules list to be used /// The files to be analyzed /// - public List RunIncremental(RootNodes projectRules, List updatedFiles) + public List RunIncremental(CsharpRootNodes projectRules, List updatedFiles) { return _solutionRewriter.RunIncremental(projectRules, updatedFiles); } @@ -360,7 +360,7 @@ public List RunIncremental(RootNodes projectRules, List /// The rules list to be used /// The file to be analyzed /// - public List RunIncremental(RootNodes projectRules, string updatedFile) + public List RunIncremental(CsharpRootNodes projectRules, string updatedFile) { return _solutionRewriter.RunIncremental(projectRules, new List { updatedFile }); } diff --git a/src/CTA.Rules.RuleFiles/RulesFileLoader.cs b/src/CTA.Rules.RuleFiles/RulesFileLoader.cs index e59c7349..c0c033e1 100644 --- a/src/CTA.Rules.RuleFiles/RulesFileLoader.cs +++ b/src/CTA.Rules.RuleFiles/RulesFileLoader.cs @@ -57,7 +57,7 @@ public RulesFileLoader(IEnumerable projectReferences, string rulesFil /// Loads rules from the main rules file and override file /// /// A RootNodes object containing all the rules after being merged - public RootNodes Load() + public T Load() { var mainNamespaceFileTasks = new Task(() => { @@ -113,16 +113,29 @@ public RootNodes Load() Task.WaitAll(mainNamespaceFileTasks, overrideNamespaceFileTasks, mainFileTask, overrideTask); - RulesFileParser rulesFileParser = new RulesFileParser(mainNamespaceFileTasks.Result, - overrideNamespaceFileTasks.Result, - mainFileTask.Result, - overrideTask.Result, - _assembliesDir, - _targetFramework, - _projectLanguage); - var rootNodes = rulesFileParser.Process(); - - return rootNodes; + if (_projectLanguage == ProjectLanguage.VisualBasic) + { + var rulesFileParser = new VisualBasicRulesFileParser(mainNamespaceFileTasks.Result, + overrideNamespaceFileTasks.Result, + mainFileTask.Result, + overrideTask.Result, + _assembliesDir, + _targetFramework); + var rootNodes = rulesFileParser.Process(); + return (T)Convert.ChangeType(rootNodes, typeof(T)); + } + else + { + RulesFileParser rulesFileParser = new RulesFileParser(mainNamespaceFileTasks.Result, + overrideNamespaceFileTasks.Result, + mainFileTask.Result, + overrideTask.Result, + _assembliesDir, + _targetFramework); + var rootNodes = rulesFileParser.Process(); + + return (T)Convert.ChangeType(rootNodes, typeof(T)); + } } diff --git a/src/CTA.Rules.RuleFiles/RulesFileParser.cs b/src/CTA.Rules.RuleFiles/RulesFileParser.cs index b79f56c7..088e23ce 100644 --- a/src/CTA.Rules.RuleFiles/RulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/RulesFileParser.cs @@ -6,6 +6,7 @@ using CTA.Rules.Config; using CTA.Rules.Models; using CTA.Rules.Models.Tokens; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Newtonsoft.Json; namespace CTA.Rules.RuleFiles @@ -15,7 +16,7 @@ namespace CTA.Rules.RuleFiles /// public class RulesFileParser { - private readonly RootNodes _rootNodes; + private readonly CsharpRootNodes _csharpRootNodes; private readonly string _assembliesDir; private readonly string _targetFramework; @@ -26,8 +27,6 @@ public class RulesFileParser private readonly NamespaceRecommendations _namespaceRecommendations; private readonly NamespaceRecommendations _overrideNamespaceRecommendations; - private readonly ProjectLanguage _projectLanguage; - /// /// Runs the rules parser /// @@ -37,7 +36,6 @@ public class RulesFileParser /// Directory containing additional actions assemblies /// Namespace recommendations /// Framework version being targeted for porting - /// Project language, C# or VB /// public RulesFileParser( NamespaceRecommendations namespaceRecommendations, @@ -45,18 +43,16 @@ public RulesFileParser( Rootobject rulesObject, Rootobject overrideObject, string assembliesDir, - string targetFramework, - ProjectLanguage projectLanguage) + string targetFramework) { - _rootNodes = new RootNodes(); - _rootNodes.ProjectTokens.Add(new ProjectToken() { Key = "Project" }); + _csharpRootNodes = new CsharpRootNodes(); + _csharpRootNodes.ProjectTokens.Add(new ProjectToken() { Key = "Project" }); _rulesObject = rulesObject; _overrideObject = overrideObject; _assembliesDir = assembliesDir; _namespaceRecommendations = namespaceRecommendations; _overrideNamespaceRecommendations = overrideNamespaceRecommendations; _targetFramework = targetFramework; - _projectLanguage = projectLanguage; LoadActions(); } @@ -65,7 +61,7 @@ public RulesFileParser( /// Runs the parser to merge the rules /// /// RootNodes object that contains the tokens and their associated actions - public RootNodes Process() + public CsharpRootNodes Process() { //Process overrides first: if (_overrideObject.NameSpaces != null) @@ -92,13 +88,13 @@ public RootNodes Process() ProcessObject(_namespaceRecommendations); } - return _rootNodes; + return _csharpRootNodes; } /// /// Loads actions from the actions project and additional assemblies /// - private void LoadActions() + public void LoadActions() { List assemblies = new List(); if (!string.IsNullOrEmpty(_assembliesDir)) @@ -112,7 +108,7 @@ private void LoadActions() /// Processes each rule object by creating tokens and associated actions /// /// An object containing tokens and actions to run on these tokens - private void ProcessObject(Rootobject rootobject) + public void ProcessObject(Rootobject rootobject) { var namespaces = rootobject.NameSpaces; @@ -123,7 +119,7 @@ private void ProcessObject(Rootobject rootobject) //Global Actions: if (@namespace.@namespace == Constants.Project && @namespace.Assembly == Constants.Project) { - var projectToken = _rootNodes.ProjectTokens.FirstOrDefault(); + var projectToken = _csharpRootNodes.ProjectTokens.FirstOrDefault(); ParseActions(projectToken, @namespace.Actions); } //Namespace specific actions: @@ -132,8 +128,8 @@ private void ProcessObject(Rootobject rootobject) var usingToken = new UsingDirectiveToken() { Key = @namespace.@namespace }; var namespaceToken = new NamespaceToken() { Key = @namespace.@namespace }; - if (!_rootNodes.Usingdirectivetokens.Contains(usingToken)) { _rootNodes.Usingdirectivetokens.Add(usingToken); } - if (!_rootNodes.NamespaceTokens.Contains(namespaceToken)) { _rootNodes.NamespaceTokens.Add(namespaceToken); } + if (!_csharpRootNodes.Usingdirectivetokens.Contains(usingToken)) { _csharpRootNodes.Usingdirectivetokens.Add(usingToken); } + if (!_csharpRootNodes.NamespaceTokens.Contains(namespaceToken)) { _csharpRootNodes.NamespaceTokens.Add(namespaceToken); } ParseActions(usingToken, @namespace.Actions); ParseActions(namespaceToken, @namespace.Actions); @@ -146,13 +142,13 @@ private void ProcessObject(Rootobject rootobject) if (@class.KeyType == CTA.Rules.Config.Constants.BaseClass || @class.KeyType == CTA.Rules.Config.Constants.ClassName) { var token = new ClassDeclarationToken() { Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace }; - if (!_rootNodes.Classdeclarationtokens.Contains(token)) { _rootNodes.Classdeclarationtokens.Add(token); } + if (!_csharpRootNodes.Classdeclarationtokens.Contains(token)) { _csharpRootNodes.Classdeclarationtokens.Add(token); } ParseActions(token, @class.Actions); } else if (@class.KeyType == CTA.Rules.Config.Constants.Identifier) { var token = new IdentifierNameToken() { Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace }; - if (!_rootNodes.Identifiernametokens.Contains(token)) { _rootNodes.Identifiernametokens.Add(token); } + if (!_csharpRootNodes.Identifiernametokens.Contains(token)) { _csharpRootNodes.Identifiernametokens.Add(token); } ParseActions(token, @class.Actions); } } @@ -161,7 +157,7 @@ private void ProcessObject(Rootobject rootobject) if (attribute.Actions != null && attribute.Actions.Count > 0) { var token = new AttributeToken() { Key = attribute.Key, Namespace = @namespace.@namespace, FullKey = attribute.FullKey, Type = @class.Key }; - if (!_rootNodes.Attributetokens.Contains(token)) { _rootNodes.Attributetokens.Add(token); } + if (!_csharpRootNodes.Attributetokens.Contains(token)) { _csharpRootNodes.Attributetokens.Add(token); } ParseActions(token, attribute.Actions); } } @@ -171,7 +167,7 @@ private void ProcessObject(Rootobject rootobject) if (method.Actions != null && method.Actions.Count > 0) { var token = new InvocationExpressionToken() { Key = method.Key, Namespace = @namespace.@namespace, FullKey = method.FullKey, Type = @class.Key }; - if (!_rootNodes.Invocationexpressiontokens.Contains(token)) { _rootNodes.Invocationexpressiontokens.Add(token); } + if (!_csharpRootNodes.Invocationexpressiontokens.Contains(token)) { _csharpRootNodes.Invocationexpressiontokens.Add(token); } ParseActions(token, method.Actions); } } @@ -181,7 +177,7 @@ private void ProcessObject(Rootobject rootobject) if (objectCreation.Actions != null && objectCreation.Actions.Count > 0) { var token = new ObjectCreationExpressionToken() { Key = objectCreation.Key, Namespace = @namespace.@namespace, FullKey = objectCreation.FullKey, Type = @class.Key }; - if (!_rootNodes.ObjectCreationExpressionTokens.Contains(token)) { _rootNodes.ObjectCreationExpressionTokens.Add(token); } + if (!_csharpRootNodes.ObjectCreationExpressionTokens.Contains(token)) { _csharpRootNodes.ObjectCreationExpressionTokens.Add(token); } ParseActions(token, objectCreation.Actions); } } @@ -194,13 +190,13 @@ private void ProcessObject(Rootobject rootobject) if (@interface.KeyType == CTA.Rules.Config.Constants.BaseClass || @interface.KeyType == CTA.Rules.Config.Constants.InterfaceName) { var token = new InterfaceDeclarationToken() { Key = @interface.FullKey, FullKey = @interface.FullKey, Namespace = @namespace.@namespace }; - if (!_rootNodes.InterfaceDeclarationTokens.Contains(token)) { _rootNodes.InterfaceDeclarationTokens.Add(token); } + if (!_csharpRootNodes.InterfaceDeclarationTokens.Contains(token)) { _csharpRootNodes.InterfaceDeclarationTokens.Add(token); } ParseActions(token, @interface.Actions); } else if (@interface.KeyType == CTA.Rules.Config.Constants.Identifier) { var token = new IdentifierNameToken() { Key = @interface.FullKey, FullKey = @interface.FullKey, Namespace = @namespace.@namespace }; - if (!_rootNodes.Identifiernametokens.Contains(token)) { _rootNodes.Identifiernametokens.Add(token); } + if (!_csharpRootNodes.Identifiernametokens.Contains(token)) { _csharpRootNodes.Identifiernametokens.Add(token); } ParseActions(token, @interface.Actions); } } @@ -209,7 +205,7 @@ private void ProcessObject(Rootobject rootobject) if (attribute.Actions != null && attribute.Actions.Count > 0) { var token = new AttributeToken() { Key = attribute.Key, Namespace = @namespace.@namespace, FullKey = attribute.FullKey, Type = @interface.Key }; - if (!_rootNodes.Attributetokens.Contains(token)) { _rootNodes.Attributetokens.Add(token); } + if (!_csharpRootNodes.Attributetokens.Contains(token)) { _csharpRootNodes.Attributetokens.Add(token); } ParseActions(token, attribute.Actions); } } @@ -219,7 +215,7 @@ private void ProcessObject(Rootobject rootobject) if (method.Actions != null && method.Actions.Count > 0) { var token = new InvocationExpressionToken() { Key = method.Key, Namespace = @namespace.@namespace, FullKey = method.FullKey, Type = @interface.Key }; - if (!_rootNodes.Invocationexpressiontokens.Contains(token)) { _rootNodes.Invocationexpressiontokens.Add(token); } + if (!_csharpRootNodes.Invocationexpressiontokens.Contains(token)) { _csharpRootNodes.Invocationexpressiontokens.Add(token); } ParseActions(token, method.Actions); } } @@ -232,7 +228,7 @@ private void ProcessObject(Rootobject rootobject) /// Processes each rule object by creating tokens and associated actions /// /// An object containing tokens and actions to run on these tokens - private void ProcessObject(NamespaceRecommendations namespaceRecommendations) + public void ProcessObject(NamespaceRecommendations namespaceRecommendations) { var namespaces = namespaceRecommendations.NameSpaces; @@ -270,8 +266,8 @@ private void ProcessObject(NamespaceRecommendations namespaceRecommendations) var usingToken = new UsingDirectiveToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs }; var namespaceToken = new NamespaceToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs }; - if (!_rootNodes.Usingdirectivetokens.Contains(usingToken)) { _rootNodes.Usingdirectivetokens.Add(usingToken); } - if (!_rootNodes.NamespaceTokens.Contains(namespaceToken)) { _rootNodes.NamespaceTokens.Add(namespaceToken); } + if (!_csharpRootNodes.Usingdirectivetokens.Contains(usingToken)) { _csharpRootNodes.Usingdirectivetokens.Add(usingToken); } + if (!_csharpRootNodes.NamespaceTokens.Contains(namespaceToken)) { _csharpRootNodes.NamespaceTokens.Add(namespaceToken); } ParseActions(usingToken, recommendedActions.Actions); ParseActions(namespaceToken, recommendedActions.Actions); @@ -282,13 +278,13 @@ private void ProcessObject(NamespaceRecommendations namespaceRecommendations) if (recommendation.KeyType == CTA.Rules.Config.Constants.BaseClass || recommendation.KeyType == CTA.Rules.Config.Constants.ClassName) { var token = new ClassDeclarationToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs, FullKey = recommendation.Value, Namespace = @namespace.Name }; - if (!_rootNodes.Classdeclarationtokens.Contains(token)) { _rootNodes.Classdeclarationtokens.Add(token); } + if (!_csharpRootNodes.Classdeclarationtokens.Contains(token)) { _csharpRootNodes.Classdeclarationtokens.Add(token); } ParseActions(token, recommendedActions.Actions); } else if (recommendation.KeyType == CTA.Rules.Config.Constants.Identifier) { var token = new IdentifierNameToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs, FullKey = recommendation.Value, Namespace = @namespace.Name }; - if (!_rootNodes.Identifiernametokens.Contains(token)) { _rootNodes.Identifiernametokens.Add(token); } + if (!_csharpRootNodes.Identifiernametokens.Contains(token)) { _csharpRootNodes.Identifiernametokens.Add(token); } ParseActions(token, recommendedActions.Actions); } break; @@ -299,13 +295,13 @@ private void ProcessObject(NamespaceRecommendations namespaceRecommendations) if (recommendation.KeyType == CTA.Rules.Config.Constants.BaseClass || recommendation.KeyType == CTA.Rules.Config.Constants.ClassName) { var token = new InterfaceDeclarationToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs, FullKey = recommendation.Value, Namespace = @namespace.Name }; - if (!_rootNodes.InterfaceDeclarationTokens.Contains(token)) { _rootNodes.InterfaceDeclarationTokens.Add(token); } + if (!_csharpRootNodes.InterfaceDeclarationTokens.Contains(token)) { _csharpRootNodes.InterfaceDeclarationTokens.Add(token); } ParseActions(token, recommendedActions.Actions); } else if (recommendation.KeyType == CTA.Rules.Config.Constants.Identifier) { var token = new IdentifierNameToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs, FullKey = recommendation.Value, Namespace = @namespace.Name }; - if (!_rootNodes.Identifiernametokens.Contains(token)) { _rootNodes.Identifiernametokens.Add(token); } + if (!_csharpRootNodes.Identifiernametokens.Contains(token)) { _csharpRootNodes.Identifiernametokens.Add(token); } ParseActions(token, recommendedActions.Actions); } break; @@ -314,21 +310,21 @@ private void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.Method: { var token = new InvocationExpressionToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_rootNodes.Invocationexpressiontokens.Contains(token)) { _rootNodes.Invocationexpressiontokens.Add(token); } + if (!_csharpRootNodes.Invocationexpressiontokens.Contains(token)) { _csharpRootNodes.Invocationexpressiontokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } case ActionTypes.Expression: { var token = new ExpressionToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_rootNodes.Expressiontokens.Contains(token)) { _rootNodes.Expressiontokens.Add(token); } + if (!_csharpRootNodes.Expressiontokens.Contains(token)) { _csharpRootNodes.Expressiontokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } case ActionTypes.Attribute: { var token = new AttributeToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_rootNodes.Attributetokens.Contains(token)) { _rootNodes.Attributetokens.Add(token); } + if (!_csharpRootNodes.Attributetokens.Contains(token)) { _csharpRootNodes.Attributetokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -336,7 +332,7 @@ private void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.ObjectCreation: { var token = new ObjectCreationExpressionToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_rootNodes.ObjectCreationExpressionTokens.Contains(token)) { _rootNodes.ObjectCreationExpressionTokens.Add(token); } + if (!_csharpRootNodes.ObjectCreationExpressionTokens.Contains(token)) { _csharpRootNodes.ObjectCreationExpressionTokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -344,7 +340,7 @@ private void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.MethodDeclaration: { var token = new MethodDeclarationToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_rootNodes.MethodDeclarationTokens.Contains(token)) { _rootNodes.MethodDeclarationTokens.Add(token); } + if (!_csharpRootNodes.MethodDeclarationTokens.Contains(token)) { _csharpRootNodes.MethodDeclarationTokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -352,7 +348,7 @@ private void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.ElementAccess: { var token = new ElementAccessToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_rootNodes.ElementAccesstokens.Contains(token)) { _rootNodes.ElementAccesstokens.Add(token); } + if (!_csharpRootNodes.ElementAccesstokens.Contains(token)) { _csharpRootNodes.ElementAccesstokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -360,7 +356,7 @@ private void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.MemberAccess: { var token = new MemberAccessToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_rootNodes.MemberAccesstokens.Contains(token)) { _rootNodes.MemberAccesstokens.Add(token); } + if (!_csharpRootNodes.MemberAccesstokens.Contains(token)) { _csharpRootNodes.MemberAccesstokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -368,7 +364,7 @@ private void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.Project: { var token = new ProjectToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value }; - if (!_rootNodes.ProjectTokens.Contains(token)) { _rootNodes.ProjectTokens.Add(token); } + if (!_csharpRootNodes.ProjectTokens.Contains(token)) { _csharpRootNodes.ProjectTokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -385,9 +381,9 @@ private void ProcessObject(NamespaceRecommendations namespaceRecommendations) /// /// Add actions to each node type /// - /// The token to add the action to + /// The token to add the action to /// The list of actions associated with this token - private void ParseActions(NodeToken nodeToken, List actions) + public void ParseActions(CsharpNodeToken csharpNodeToken, List actions) { foreach (var action in actions) { @@ -401,9 +397,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetInvocationExpressionAction(action.Name, action.Value); if (actionFunc != null) { - nodeToken.InvocationExpressionActions.Add(new InvocationExpressionAction() + csharpNodeToken.InvocationExpressionActions.Add(new InvocationExpressionAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -419,9 +415,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetExpressionAction(action.Name, action.Value); if (actionFunc != null) { - nodeToken.ExpressionActions.Add(new ExpressionAction() + csharpNodeToken.ExpressionActions.Add(new ExpressionAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -437,9 +433,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetClassAction(action.Name, action.Value); if (actionFunc != null) { - nodeToken.ClassDeclarationActions.Add(new ClassDeclarationAction() + csharpNodeToken.ClassDeclarationActions.Add(new ClassDeclarationAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -456,9 +452,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetInterfaceAction(action.Name, action.Value); if (actionFunc != null) { - nodeToken.InterfaceDeclarationActions.Add(new InterfaceDeclarationAction() + csharpNodeToken.InterfaceDeclarationActions.Add(new InterfaceDeclarationAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -478,9 +474,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var namespaceActionFunc = actionsLoader.GetNamespaceActions(action.Name, action.Value); if (actionFunc != null) { - nodeToken.UsingActions.Add(new UsingAction() + csharpNodeToken.UsingActions.Add(new UsingAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -497,9 +493,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetNamespaceActions(action.Name, action.Value); if (actionFunc != null) { - nodeToken.NamespaceActions.Add(new NamespaceAction() + csharpNodeToken.NamespaceActions.Add(new NamespaceAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -515,9 +511,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetIdentifierNameAction(action.Name, action.Value); if (actionFunc != null) { - nodeToken.IdentifierNameActions.Add(new IdentifierNameAction() + csharpNodeToken.IdentifierNameActions.Add(new IdentifierNameAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -533,9 +529,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetAttributeAction(action.Name, action.Value); if (actionFunc != null) { - nodeToken.AttributeActions.Add(new AttributeAction() + csharpNodeToken.AttributeActions.Add(new AttributeAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -551,9 +547,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetAttributeListAction(action.Name, action.Value); if (actionFunc != null) { - nodeToken.AttributeListActions.Add(new AttributeAction() + csharpNodeToken.AttributeListActions.Add(new AttributeAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -569,9 +565,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetObjectCreationExpressionActions(action.Name, action.Value); if (actionFunc != null) { - nodeToken.ObjectCreationExpressionActions.Add(new ObjectCreationExpressionAction() + csharpNodeToken.ObjectCreationExpressionActions.Add(new ObjectCreationExpressionAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -587,9 +583,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetMethodDeclarationAction(action.Name, action.Value); if (actionFunc != null) { - nodeToken.MethodDeclarationActions.Add(new MethodDeclarationAction() + csharpNodeToken.MethodDeclarationActions.Add(new MethodDeclarationAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -605,9 +601,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetElementAccessExpressionActions(action.Name, action.Value); if (actionFunc != null) { - nodeToken.ElementAccessActions.Add(new ElementAccessAction() + csharpNodeToken.ElementAccessActions.Add(new ElementAccessAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -623,9 +619,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetMemberAccessExpressionActions(action.Name, action.Value); if (actionFunc != null) { - nodeToken.MemberAccessActions.Add(new MemberAccessAction() + csharpNodeToken.MemberAccessActions.Add(new MemberAccessAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -641,9 +637,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetProjectLevelActions(action.Name, action.Value); if (actionFunc != null) { - nodeToken.ProjectLevelActions.Add(new ProjectLevelAction() + csharpNodeToken.ProjectLevelActions.Add(new ProjectLevelAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -659,9 +655,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetProjectFileActions(action.Name, action.Value); if (actionFunc != null) { - nodeToken.ProjectFileActions.Add(new ProjectLevelAction() + csharpNodeToken.ProjectFileActions.Add(new ProjectLevelAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -677,9 +673,9 @@ private void ParseActions(NodeToken nodeToken, List actions) var actionFunc = actionsLoader.GetProjectTypeActions(action.Name, action.Value); if (actionFunc != null) { - nodeToken.ProjectTypeActions.Add(new ProjectLevelAction() + csharpNodeToken.ProjectTypeActions.Add(new ProjectLevelAction() { - Key = nodeToken.Key, + Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), Description = action.Description, ActionValidation = action.ActionValidation, @@ -718,7 +714,7 @@ private void ParseActions(NodeToken nodeToken, List actions) packageAction.Version = jsonParameters[CTA.Rules.Config.Constants.PackageVersion]; } } - nodeToken.PackageActions.Add(packageAction); + csharpNodeToken.PackageActions.Add(packageAction); break; } } @@ -730,7 +726,7 @@ private void ParseActions(NodeToken nodeToken, List actions) } } - private string GetActionValue(dynamic value) + public string GetActionValue(dynamic value) { if (value is string) { diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs new file mode 100644 index 00000000..7b3065fa --- /dev/null +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -0,0 +1,505 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using CTA.Rules.Actions; +using CTA.Rules.Config; +using CTA.Rules.Models; +using CTA.Rules.Models.VisualBasic; +using CTA.Rules.Models.Tokens.VisualBasic; +using Microsoft.Build.Logging.StructuredLogger; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Newtonsoft.Json; + + + +namespace CTA.Rules.RuleFiles +{ + /// + /// Parser to load rules in form usable by the rules engine + /// + public class VisualBasicRulesFileParser + { + private readonly Models.VisualBasic.VisualBasicRootNodes _visualBasicRootNodes; + private readonly string _assembliesDir; + private readonly string _targetFramework; + + private VisualBasicActionsLoader _actionsLoader; + private readonly Rootobject _rulesObject; + private readonly Rootobject _overrideObject; + + private readonly NamespaceRecommendations _namespaceRecommendations; + private readonly NamespaceRecommendations _overrideNamespaceRecommendations; + + /// + /// Runs the rules parser + /// + /// Override namespace recommendations + /// Object containing built in rules + /// Object containing override rules + /// Directory containing additional actions assemblies + /// Namespace recommendations + /// Framework version being targeted for porting + /// Project language, C# or VB + /// + public VisualBasicRulesFileParser( + NamespaceRecommendations namespaceRecommendations, + NamespaceRecommendations overrideNamespaceRecommendations, + Rootobject rulesObject, + Rootobject overrideObject, + string assembliesDir, + string targetFramework) + { + _visualBasicRootNodes = new Models.VisualBasic.VisualBasicRootNodes(); + //_visualBasicRootNodes.ProjectTokens.Add(new ProjectToken() { Key = "Project" }); + _rulesObject = rulesObject; + _overrideObject = overrideObject; + _assembliesDir = assembliesDir; + _namespaceRecommendations = namespaceRecommendations; + _overrideNamespaceRecommendations = overrideNamespaceRecommendations; + _targetFramework = targetFramework; + + LoadActions(); + } + + /// + /// Runs the parser to merge the rules + /// + /// RootNodes object that contains the tokens and their associated actions + public Models.VisualBasic.VisualBasicRootNodes Process() + { + //Process overrides first: + if (_overrideObject.NameSpaces != null) + { + ProcessObject(_overrideObject); + } + + //Add remaining objects, if not available: + if (_overrideNamespaceRecommendations.NameSpaces != null) + { + ProcessObject(_overrideNamespaceRecommendations); + } + + //Add remaining objects, if not available: + if (_rulesObject.NameSpaces != null) + { + ProcessObject(_rulesObject); + } + + + //Add remaining objects, if not available: + if (_namespaceRecommendations.NameSpaces != null) + { + ProcessObject(_namespaceRecommendations); + } + + return _visualBasicRootNodes; + } + + /// + /// Loads actions from the actions project and additional assemblies + /// + public void LoadActions() + { + List assemblies = new List(); + if (!string.IsNullOrEmpty(_assembliesDir)) + { + assemblies = Directory.EnumerateFiles(_assembliesDir, "*.dll").ToList(); + } + _actionsLoader = new VisualBasicActionsLoader(assemblies); + } + + /// + /// Processes each rule object by creating tokens and associated actions + /// + /// An object containing tokens and actions to run on these tokens + public void ProcessObject(Rootobject rootobject) + { + var namespaces = rootobject.NameSpaces; + + foreach (var @namespace in namespaces) + { + if (@namespace.Actions != null && @namespace.Actions.Count > 0) + { + //Global Actions: + if (@namespace.@namespace == Constants.Project && @namespace.Assembly == Constants.Project) + { + /* + var projectToken = _rootNodes.ProjectTokens.FirstOrDefault(); + ParseActions(projectToken, @namespace.Actions); + */ + } + //Namespace specific actions: + else + { + /* + var usingToken = new UsingDirectiveToken() { Key = @namespace.@namespace }; + var namespaceToken = new NamespaceToken() { Key = @namespace.@namespace }; + + if (!_rootNodes.Usingdirectivetokens.Contains(usingToken)) { _rootNodes.Usingdirectivetokens.Add(usingToken); } + if (!_rootNodes.NamespaceTokens.Contains(namespaceToken)) { _rootNodes.NamespaceTokens.Add(namespaceToken); } + + ParseActions(usingToken, @namespace.Actions); + ParseActions(namespaceToken, @namespace.Actions); + */ + } + } + foreach (var @class in @namespace.Classes) + { + /* + if (@class.Actions != null && @class.Actions.Count > 0) + { + if (@class.KeyType == CTA.Rules.Config.Constants.BaseClass || @class.KeyType == CTA.Rules.Config.Constants.ClassName) + { + var token = new ClassDeclarationToken() { Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace }; + if (!_rootNodes.Classdeclarationtokens.Contains(token)) { _rootNodes.Classdeclarationtokens.Add(token); } + ParseActions(token, @class.Actions); + } + else if (@class.KeyType == CTA.Rules.Config.Constants.Identifier) + { + var token = new IdentifierNameToken() { Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace }; + if (!_rootNodes.Identifiernametokens.Contains(token)) { _rootNodes.Identifiernametokens.Add(token); } + ParseActions(token, @class.Actions); + } + } + foreach (var attribute in @class.Attributes) + { + if (attribute.Actions != null && attribute.Actions.Count > 0) + { + var token = new AttributeToken() { Key = attribute.Key, Namespace = @namespace.@namespace, FullKey = attribute.FullKey, Type = @class.Key }; + if (!_rootNodes.Attributetokens.Contains(token)) { _rootNodes.Attributetokens.Add(token); } + ParseActions(token, attribute.Actions); + } + } + foreach (var objectCreation in @class.ObjectCreations) + { + if (objectCreation.Actions != null && objectCreation.Actions.Count > 0) + { + var token = new ObjectCreationExpressionToken() { Key = objectCreation.Key, Namespace = @namespace.@namespace, FullKey = objectCreation.FullKey, Type = @class.Key }; + if (!_rootNodes.ObjectCreationExpressionTokens.Contains(token)) { _rootNodes.ObjectCreationExpressionTokens.Add(token); } + ParseActions(token, objectCreation.Actions); + } + } + */ + + foreach (var method in @class.Methods) + { + if (method.Actions != null && method.Actions.Count > 0) + { + var token = new InvocationExpressionToken() { Key = method.Key, Namespace = @namespace.@namespace, FullKey = method.FullKey, Type = @class.Key }; + if (!_visualBasicRootNodes.InvocationExpressionTokens.Contains(token)) { _visualBasicRootNodes.InvocationExpressionTokens.Add(token); } + ParseActions(token, method.Actions); + } + } + + } + + foreach (var @interface in @namespace.Interfaces) + { + if (@interface.Actions != null && @interface.Actions.Count > 0) + { + if (@interface.KeyType == CTA.Rules.Config.Constants.BaseClass || @interface.KeyType == CTA.Rules.Config.Constants.InterfaceName) + { + } + else if (@interface.KeyType == CTA.Rules.Config.Constants.Identifier) + { + } + } + foreach (var attribute in @interface.Attributes) + { + if (attribute.Actions != null && attribute.Actions.Count > 0) + { + } + } + + foreach (var method in @interface.Methods) + { + if (method.Actions != null && method.Actions.Count > 0) + { + var token = new InvocationExpressionToken() { Key = method.Key, Namespace = @namespace.@namespace, FullKey = method.FullKey, Type = @interface.Key }; + if (!_visualBasicRootNodes.InvocationExpressionTokens.Contains(token)) { _visualBasicRootNodes.InvocationExpressionTokens.Add(token); } + ParseActions(token, method.Actions); + } + } + } + } + } + + + /// + /// Processes each rule object by creating tokens and associated actions + /// + /// An object containing tokens and actions to run on these tokens + public void ProcessObject(NamespaceRecommendations namespaceRecommendations) + { + var namespaces = namespaceRecommendations.NameSpaces; + + foreach (var @namespace in namespaces) + { + foreach (var recommendation in @namespace.Recommendations) + { + var recommendedActions = recommendation.RecommendedActions.FirstOrDefault(ra => + ra.Preferred == "Yes" && ra.TargetFrameworks.Any(t => t.Name.Equals(_targetFramework))); + + //There are recommendations, but none of them are preferred + if (recommendedActions == null && recommendation.RecommendedActions.Count > 0) + { + LogHelper.LogError( + "No preferred recommendation set for recommendation {0} with target framework {1}", + recommendation.Value, _targetFramework); + continue; + } + + if (recommendedActions != null) + { + if (recommendedActions.Actions != null && recommendedActions.Actions.Count > 0) + { + var targetCPUs = new List { "x86", "x64", "ARM64" }; + try + { + targetCPUs = recommendedActions.TargetFrameworks + .FirstOrDefault(t => t.Name == _targetFramework)?.TargetCPU; + } + catch + { + LogHelper.LogError("Error parsing CPUs for target framework"); + } + + var recommendationType = Enum.Parse(typeof(ActionTypes), recommendation.Type); + switch (recommendationType) + { + case ActionTypes.Namespace: + { + var importToken = new ImportStatementToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs }; + var namespaceToken = new NamespaceToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs }; + + if (!_visualBasicRootNodes.ImportStatementTokens.Contains(importToken)) { _visualBasicRootNodes.ImportStatementTokens.Add(importToken); } + if (!_visualBasicRootNodes.NamespaceTokens.Contains(namespaceToken)) { _visualBasicRootNodes.NamespaceTokens.Add(namespaceToken); } + + ParseActions(importToken, recommendedActions.Actions); + ParseActions(namespaceToken, recommendedActions.Actions); + break; + } + case ActionTypes.Class: + { + throw new NotImplementedException(); + } + + case ActionTypes.Interface: + { + throw new NotImplementedException(); + } + + case ActionTypes.Method: + { + var token = new InvocationExpressionToken + { + Key = recommendation.Name, + Description = recommendedActions.Description, + TargetCPU = targetCPUs, + Namespace = @namespace.Name, + FullKey = recommendation.Value, + Type = recommendation.ContainingType + }; + if (!_visualBasicRootNodes.InvocationExpressionTokens.Contains(token)) + { + _visualBasicRootNodes.InvocationExpressionTokens.Add(token); + } + + ParseActions(token, recommendedActions.Actions); + break; + } + case ActionTypes.Expression: + { + throw new NotImplementedException(); + } + case ActionTypes.Attribute: + { + throw new NotImplementedException(); + } + + case ActionTypes.ObjectCreation: + { + throw new NotImplementedException(); + } + + case ActionTypes.MethodDeclaration: + { + throw new NotImplementedException(); + } + + case ActionTypes.ElementAccess: + { + throw new NotImplementedException(); + } + + case ActionTypes.MemberAccess: + { + throw new NotImplementedException(); + } + + case ActionTypes.Project: + { + throw new NotImplementedException(); + } + } + } + } + } + } + } + + /// + /// Add actions to each node type + /// + /// The token to add the action to + /// The list of actions associated with this token + public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List actions) + { + foreach (var action in actions) + { + try + { + var actionType = Enum.Parse(typeof(ActionTypes), action.Type); + switch (actionType) + { + case ActionTypes.Method: + { + var actionFunc = _actionsLoader.GetInvocationExpressionAction(action.Name, action.Value); + if (actionFunc != null) + { + visualBasicNodeToken.InvocationExpressionActions.Add( + new InvocationExpressionAction + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(action.Value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = action.Name, + Type = action.Type, + InvocationExpressionActionFunc = actionFunc + }); + } + + break; + } + case ActionTypes.Expression: + { + break; + } + case ActionTypes.Class: + { + break; + } + + case ActionTypes.Interface: + { + break; + } + case ActionTypes.Using: + { + var actionFunc = _actionsLoader.GetCompilationUnitAction(action.Name, action.Value); + // Using directives can be found in both ComplilationUnit and inside Namespace. + // Need to make sure remove action is taken if it's inside Namespace block. + // Only add using directives in the CompilationUnit as our convention, so it's not added twice. + var namespaceActionFunc = _actionsLoader.GetNamespaceActions(action.Name, action.Value); + if (actionFunc != null) + { + visualBasicNodeToken.ImportActions.Add(new ImportAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(action.Value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = action.Name, + Type = action.Type, + ImportActionFunc = actionFunc, + ImportsClauseActionFunc = namespaceActionFunc + }); + } + break; + } + case ActionTypes.Namespace: + { + var actionFunc = _actionsLoader.GetNamespaceActions(action.Name, action.Value); + if (actionFunc != null) + { + visualBasicNodeToken.NamespaceActions.Add(new NamespaceAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(action.Value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = action.Name, + Type = action.Type, + NamespaceActionFunc = actionFunc + }); + } + break; + } + case ActionTypes.Identifier: + { + break; + } + case ActionTypes.Attribute: + { + break; + } + case ActionTypes.AttributeList: + { + break; + } + case ActionTypes.ObjectCreation: + { + break; + } + case ActionTypes.MethodDeclaration: + { + break; + } + case ActionTypes.ElementAccess: + { + break; + } + case ActionTypes.MemberAccess: + { + break; + } + case ActionTypes.Project: + { + break; + } + case ActionTypes.ProjectFile: + { + break; + } + case ActionTypes.ProjectType: + { + break; + } + case ActionTypes.Package: + { + break; + } + } + } + catch (Exception ex) + { + LogHelper.LogError(ex, $"Error parsing action type {action.Type}"); + } + } + } + + private string GetActionValue(dynamic value) + { + if (value is string) + { + return value; + } + else + { + return value + string.Empty; + } + } + } +} diff --git a/src/CTA.Rules.Update/ActionsRewriter.cs b/src/CTA.Rules.Update/ActionsRewriter.cs index 30393b2c..4277e8a5 100644 --- a/src/CTA.Rules.Update/ActionsRewriter.cs +++ b/src/CTA.Rules.Update/ActionsRewriter.cs @@ -271,7 +271,7 @@ public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax var nodeKey = symbol.OriginalDefinition.ToString(); - foreach (var action in _allActions.OfType()) + foreach (var action in _allActions.OfType>()) { if (nodeKey == action.Key) { @@ -431,7 +431,7 @@ public override SyntaxNode VisitNamespaceDeclaration(NamespaceDeclarationSyntax { NamespaceDeclarationSyntax newNode = (NamespaceDeclarationSyntax)base.VisitNamespaceDeclaration(node); // Handle namespace renaming actions etc. - foreach (var action in _allActions.OfType()) + foreach (var action in _allActions.OfType>()) { if (action.Key == newNode.Name.ToString()) { @@ -456,18 +456,18 @@ public override SyntaxNode VisitNamespaceDeclaration(NamespaceDeclarationSyntax // Handle namespace remove using actions. foreach (var action in _allActions.OfType()) { - if (action.NamespaceUsingActionFunc == null) - { - continue; - } - + if (action.NamespaceUsingActionFunc == null) + { + continue; + } + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; try { - newNode = action.NamespaceUsingActionFunc(_syntaxGenerator, newNode); + newNode = action.NamespaceUsingActionFunc(_syntaxGenerator, newNode); LogHelper.LogInformation(string.Format("{0} in Namespace block.", action.Description)); } catch (Exception ex) diff --git a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs index c92dee8e..aeaa8550 100644 --- a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs +++ b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs @@ -92,7 +92,7 @@ public ProjectResult Initialize() .Union(ProjectConfiguration.AdditionalReferences.Select(r => new Reference { Assembly = r, Namespace = r })); RulesFileLoader rulesFileLoader = new RulesFileLoader(allReferences, ProjectConfiguration.RulesDir, ProjectConfiguration.TargetVersions, _projectLanguage, string.Empty, ProjectConfiguration.AssemblyDir); - var projectRules = rulesFileLoader.Load(); + var projectRules = rulesFileLoader.Load(); RulesAnalysis walker = new RulesAnalysis(_sourceFileResults, projectRules, ProjectConfiguration.ProjectType); projectActions = walker.Analyze(); @@ -148,13 +148,13 @@ public virtual ProjectResult Run(ProjectActions projectActions) return _projectResult; } - public virtual List RunIncremental(List updatedFiles, RootNodes projectRules) + public virtual List RunIncremental(List updatedFiles, CsharpRootNodes projectRules) { var ideFileActions = new List(); var allReferences = _sourceFileResults?.SelectMany(s => s.References).Distinct(); RulesFileLoader rulesFileLoader = new RulesFileLoader(allReferences, Constants.RulesDefaultPath, ProjectConfiguration.TargetVersions, _projectLanguage, string.Empty, ProjectConfiguration.AssemblyDir); - projectRules = rulesFileLoader.Load(); + projectRules = rulesFileLoader.Load(); RulesAnalysis walker = new RulesAnalysis(_sourceFileResults, projectRules, ProjectConfiguration.ProjectType); var projectActions = walker.Analyze(); diff --git a/src/CTA.Rules.Update/SolutionRewriter.cs b/src/CTA.Rules.Update/SolutionRewriter.cs index 8291d086..d0c36891 100644 --- a/src/CTA.Rules.Update/SolutionRewriter.cs +++ b/src/CTA.Rules.Update/SolutionRewriter.cs @@ -107,7 +107,7 @@ public SolutionResult Run(Dictionary projectActions) return _solutionResult; } - public List RunIncremental(RootNodes projectRules, List updatedFiles) + public List RunIncremental(CsharpRootNodes projectRules, List updatedFiles) { var ideFileActions = new BlockingCollection(); var options = new ParallelOptions { MaxDegreeOfParallelism = Constants.ThreadCount }; diff --git a/tst/CTA.Rules.Test/Actions/InvocationExpressionActionsTests.cs b/tst/CTA.Rules.Test/Actions/InvocationExpressionActionsTests.cs index 72992246..7462d098 100644 --- a/tst/CTA.Rules.Test/Actions/InvocationExpressionActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/InvocationExpressionActionsTests.cs @@ -115,8 +115,8 @@ public void GetAppendMethodAction_Appends_A_Method_Invocation() [Test] public void InvocationExpressionEquals() { - var invocationExpressionAction = new InvocationExpressionAction() { Key = "Test", Value = "Test2", InvocationExpressionActionFunc = _invocationExpressionActions.GetAddCommentAction("Test") }; - var cloned = invocationExpressionAction.Clone(); + var invocationExpressionAction = new InvocationExpressionAction() { Key = "Test", Value = "Test2", InvocationExpressionActionFunc = _invocationExpressionActions.GetAddCommentAction("Test") }; + var cloned = invocationExpressionAction.Clone>(); Assert.True(invocationExpressionAction.Equals(cloned)); cloned.Value = "DifferentValue"; diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs new file mode 100644 index 00000000..57fdb061 --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs @@ -0,0 +1,59 @@ +using CTA.Rules.Actions; +using NUnit.Framework; +using System.Collections.Generic; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class ActionLoaderTests + { + private VisualBasicActionsLoader _actionLoader; + + [SetUp] + public void SetUp() + { + _actionLoader = new VisualBasicActionsLoader(new List()); + } + + [Test] + public void CompilationUnitActionsTest() + { + var addStatement = _actionLoader.GetCompilationUnitAction("AddStatement", "namespace"); + var removeStatement = _actionLoader.GetCompilationUnitAction("RemoveStatement", "namespace"); + var addComment = _actionLoader.GetCompilationUnitAction("AddComment", "comment"); + + Assert.IsNotNull(addStatement); + Assert.IsNotNull(removeStatement); + Assert.IsNotNull(addComment); + } + + [Test] + public void InvocationExpressionActionsTest() + { + var replaceMethodWithObjectAndParameters = _actionLoader.GetInvocationExpressionAction("ReplaceMethodWithObjectAndParameters", "{newMethod: \"method\", newParameters: \"params\"}"); + var replaceMethodWithObject = _actionLoader.GetInvocationExpressionAction("ReplaceMethodWithObject", "newMethod"); + var replaceMethodWithObjectAddType = _actionLoader.GetInvocationExpressionAction("ReplaceMethodWithObjectAddType", "newMethod"); + var replaceMethodAndParameters = _actionLoader.GetInvocationExpressionAction("ReplaceMethodAndParameters", "{ oldMethod: \"method\", newMethod: \"method\", newParameters: \"params\"}"); + var replaceMethodOnly = _actionLoader.GetInvocationExpressionAction("ReplaceMethodOnly", "{ oldMethod: \"method\", newMethod: \"method\" }"); + var replaceParametersOnly = _actionLoader.GetInvocationExpressionAction("ReplaceParametersOnly", "newParameters"); + var appendMethod = _actionLoader.GetInvocationExpressionAction("AppendMethod", "appendMethod"); + var addComment = _actionLoader.GetInvocationExpressionAction("AddComment", "comment"); + + Assert.IsNotNull(replaceMethodWithObjectAndParameters); + Assert.IsNotNull(replaceMethodWithObject); + Assert.IsNotNull(replaceMethodWithObjectAddType); + Assert.IsNotNull(replaceMethodAndParameters); + Assert.IsNotNull(replaceMethodOnly); + Assert.IsNotNull(replaceParametersOnly); + Assert.IsNotNull(appendMethod); + Assert.IsNotNull(addComment); + } + + [Test] + public void NamespaceActionsTest() + { + var renameNamespace = _actionLoader.GetNamespaceActions("RenameNamespace", "newName"); + + Assert.IsNotNull(renameNamespace); + } + } +} \ No newline at end of file diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/CompilationUnitActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/CompilationUnitActionsTests.cs new file mode 100644 index 00000000..8f847ee9 --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/CompilationUnitActionsTests.cs @@ -0,0 +1,77 @@ +using CTA.Rules.Actions.VisualBasic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; +using VisualBasicSyntaxTree = Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree; + + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class CompilationUnitActionsTests + { + private SyntaxGenerator _syntaxGenerator; + private CompilationUnitActions _compilationUnitActions; + private CompilationUnitSyntax _node; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _compilationUnitActions = new CompilationUnitActions(); + + SyntaxTree tree = VisualBasicSyntaxTree.ParseText(@$"Imports System.Web +Class MyClass +End Class"); + _node = tree.GetCompilationUnitRoot(); + } + + [Test] + public void GetAddDirectiveAction_Adds_Directive() + { + const string directive = "System.Collections.Generic"; + var addStatementAction = _compilationUnitActions.GetAddStatementAction(directive); + var newNode = addStatementAction(_syntaxGenerator, _node); + + var expectedResult = @$"Imports System.Web +Imports {directive} + +Class MyClass +End Class +"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetRemoveDirectiveAction_Removes_Directive() + { + const string directive = "System.Web"; + var removeStatementAction = _compilationUnitActions.GetRemoveStatementAction(directive); + var newNode = removeStatementAction(_syntaxGenerator, _node); + + var expectedResult = @$"Class MyClass +End Class +"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetAddCommentAction_Adds_Comment_Above_Directive() + { + const string commentToAdd = "This is a comment"; + var addCommentFunc = _compilationUnitActions.GetAddCommentAction(commentToAdd); + var newNode = addCommentFunc(_syntaxGenerator, _node); + + var expectedResult = @$"' Added by CTA: {commentToAdd} +Imports System.Web + +Class MyClass +End Class +"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + } +} diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/InvocationExpressionActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/InvocationExpressionActionsTests.cs new file mode 100644 index 00000000..1f5f3efb --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/InvocationExpressionActionsTests.cs @@ -0,0 +1,126 @@ +using CTA.Rules.Actions.VisualBasic; +using CTA.Rules.Models; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class VisualBasicInvocationExpressionActionsTests + { + private SyntaxGenerator _syntaxGenerator; + private InvocationExpressionActions _invocationExpressionActions; + private InvocationExpressionSyntax _node; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _invocationExpressionActions = new InvocationExpressionActions(); + _node = SyntaxFactory.ParseExpression("' Comment \nMath.Abs(-1)") as InvocationExpressionSyntax; + } + + [Test] + public void GetReplaceMethodWithObjectAndParametersAction() + { + const string newMethod = "Math.Floor"; + const string newParameter = "(-2)"; + var replaceMethodFunc = + _invocationExpressionActions.GetReplaceMethodWithObjectAndParametersAction(newMethod, newParameter); + var newNode = replaceMethodFunc(_syntaxGenerator, _node); + + var expectedResult = "' Comment \r\nMath.Floor(-2)"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetReplaceMethodWithObjectAction() + { + const string newMethod = "Math.Floor"; + var replaceMethodFunc = + _invocationExpressionActions.GetReplaceMethodWithObjectAction(newMethod); + var newNode = replaceMethodFunc(_syntaxGenerator, _node); + + var expectedResult = "' Comment \r\nMath.Floor(-1)"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetReplaceMethodWithObjectAddTypeAction() + { + _node = SyntaxFactory.ParseExpression("' Comment \r\nDependencyResolver.Current.GetService(Of Object)()") as InvocationExpressionSyntax; + const string newMethod = "DependencyResolver.Current.GetService"; + var replaceMethodFunc = + _invocationExpressionActions.GetReplaceMethodWithObjectAddTypeAction(newMethod); + var newNode = replaceMethodFunc(_syntaxGenerator, _node); + + var expectedResult = "' Comment \r\nDependencyResolver.Current.GetService(TypeOf Object)"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetReplaceMethodAndParametersAction() + { + const string newMethod = "Floor"; + const string newParameter = "(-2)"; + var replaceMethodFunc = + _invocationExpressionActions.GetReplaceMethodAndParametersAction("Abs", newMethod, newParameter); + var newNode = replaceMethodFunc(_syntaxGenerator, _node); + + var expectedResult = "' Comment \r\nMath.Floor(-2)"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetReplaceMethodOnlyAction() + { + const string newMethod = "Floor"; + var replaceMethodFunc = + _invocationExpressionActions.GetReplaceMethodOnlyAction("Abs",newMethod); + var newNode = replaceMethodFunc(_syntaxGenerator, _node); + + var expectedResult = "' Comment \r\nMath.Floor(-1)"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetReplaceParameterOnlyAction() + { + const string newParam = "(8)"; + var replaceMethodFunc = + _invocationExpressionActions.GetReplaceParametersOnlyAction(newParam); + var newNode = replaceMethodFunc(_syntaxGenerator, _node); + + var expectedResult = "' Comment \r\nMath.Abs(8)"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetAppendMethodAction_Appends_A_Method_Invocation() + { + const string invocationToAppend = "ToString()"; + var appendMethodFunc = + _invocationExpressionActions.GetAppendMethodAction(invocationToAppend); + var newNode = appendMethodFunc(_syntaxGenerator, _node); + + var expectedResult = "' Comment \r\nMath.Abs(-1).ToString()"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + + [Test] + public void InvocationExpressionEquals() + { + var invocationExpressionAction = new InvocationExpressionAction() { Key = "Test", Value = "Test2", InvocationExpressionActionFunc = _invocationExpressionActions.GetAddCommentAction("Test") }; + var cloned = invocationExpressionAction.Clone>(); + Assert.True(invocationExpressionAction.Equals(cloned)); + + cloned.Value = "DifferentValue"; + Assert.False(invocationExpressionAction.Equals(cloned)); + } + } +} \ No newline at end of file diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/NamespaceActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/NamespaceActionsTests.cs new file mode 100644 index 00000000..d52c9736 --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/NamespaceActionsTests.cs @@ -0,0 +1,52 @@ +using CTA.FeatureDetection.Common.Extensions; +using CTA.Rules.Actions.VisualBasic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; +using System.Linq; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + internal class NamespaceActionsTests + { + private SyntaxGenerator _syntaxGenerator; + private NamespaceActions _namespaceActions; + private NamespaceBlockSyntax _node; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.CSharp; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _namespaceActions = new NamespaceActions(); + + SyntaxTree tree = VisualBasicSyntaxTree.ParseText(@$" + Namespace DummyNamespace + Class MyClass + End Class + End Namespace"); + _node = tree.GetRoot() + .DescendantNodes() + .OfType() + .FirstOrDefault(); + } + + [Test] + public void GetRenameNamespaceAction_Rename_Namespace() + { + const string newNamespaceName = "NewNamespace"; + var renameNamespaceFunc = _namespaceActions.GetRenameNamespaceAction(newNamespaceName); + var newNode = renameNamespaceFunc(_syntaxGenerator, _node); + + var expectedResult = VisualBasicSyntaxTree.ParseText(@$" + Namespace NewNamespace + Class MyClass + End Class + End Namespace").GetRoot(); + Assert.AreEqual(expectedResult.RemoveAllTrivia().ToFullString(), newNode.RemoveAllTrivia().ToFullString()); + } + } +} From 7e136ec64bf14d705e1686f00646b5a97a2ba998 Mon Sep 17 00:00:00 2001 From: longachr Date: Mon, 16 May 2022 10:40:18 -0700 Subject: [PATCH 06/61] Put shared functions and project actions into loader base class --- ...tionLoaderUtils.cs => ActionLoaderBase.cs} | 100 +++++++++++------- src/CTA.Rules.Actions/ActionsLoader.cs | 77 ++++++-------- .../VisualBasicActionsLoader.cs | 61 ++++++----- 3 files changed, 126 insertions(+), 112 deletions(-) rename src/CTA.Rules.Actions/{ActionLoaderUtils.cs => ActionLoaderBase.cs} (53%) diff --git a/src/CTA.Rules.Actions/ActionLoaderUtils.cs b/src/CTA.Rules.Actions/ActionLoaderBase.cs similarity index 53% rename from src/CTA.Rules.Actions/ActionLoaderUtils.cs rename to src/CTA.Rules.Actions/ActionLoaderBase.cs index f1ed70e1..af6c5f23 100644 --- a/src/CTA.Rules.Actions/ActionLoaderUtils.cs +++ b/src/CTA.Rules.Actions/ActionLoaderBase.cs @@ -3,13 +3,35 @@ using System.Linq; using System.Reflection; using System.Runtime.Loader; +using CTA.Rules.Models; +using Codelyzer.Analysis; using CTA.Rules.Config; using Newtonsoft.Json; namespace CTA.Rules.Actions; -public class ActionLoaderUtils +public class ActionLoaderBase { + protected List projectLevelActions, + projectFileActions, + projectTypeActions; + + protected object projectLevelObject, + projectFileObject, + projectTypeObject; + + public Func GetProjectLevelActions(string name, dynamic value) => + GetAction> + (projectLevelActions, projectLevelObject, name, value); + public Func, Dictionary, List, List, string> GetProjectFileActions(string name, dynamic value) => + GetAction, Dictionary, List, List, string>> + (projectFileActions, projectFileObject, name, value); + public Func GetProjectTypeActions(string name, dynamic value) => + GetAction> + (projectTypeActions, projectTypeObject, name, value); + + #region helper functions + /// /// Gets the action by invoking the methods that will create it /// @@ -25,14 +47,14 @@ public static T GetAction(List actions, object invokeObject, stri try { string actionName = GetActionName(name); - var method = actions.Where(m => m.Name == actionName).FirstOrDefault(); + var method = actions.FirstOrDefault(m => m.Name == actionName); if (method == null) { LogHelper.LogDebug(string.Format("No such action {0}", actionName)); } else { - var parameters = ActionLoaderUtils.GetParameters(value, method); + var parameters = GetParameters(value, method); if (parameters != null) { @@ -78,10 +100,10 @@ private static string GetActionName(string name) { return string.Concat("Get", name, "Action"); } - - public static List GetFuncMethods(Type t) => t.GetMethods().Where(m => m.ReturnType.ToString().Contains("System.Func")).ToList(); - public static bool TryCreateInstance(string actionName, List types, out object obj) + protected static List GetFuncMethods(Type t) => t.GetMethods().Where(m => m.ReturnType.ToString().Contains("System.Func")).ToList(); + + protected static bool TryCreateInstance(string actionName, List types, out object obj) { obj = null; var type = types.FirstOrDefault(t => t.Name == actionName); @@ -119,52 +141,54 @@ private static List GetJsonParameters(string value, MethodInfo method) return result; } /// - /// Gets the parameters for the action. The parameters should match the action signature in the provided rules file - /// - /// The paramter(s) as a string or JSON object - /// The method for these parameters - /// - public static string[] GetParameters(dynamic value, MethodInfo method) - { - List result = new List(); + /// Gets the parameters for the action. The parameters should match the action signature in the provided rules file + /// + /// The paramter(s) as a string or JSON object + /// The method for these parameters + /// + private static string[] GetParameters(dynamic value, MethodInfo method) + { + List result = new List(); - try + try + { + if (value is string) { - if (value is string) + var strValue = value.ToString(); + if (strValue.StartsWith("{")) { - var strValue = value.ToString(); - if (strValue.StartsWith("{")) + try { - try - { - result = ActionLoaderUtils.GetJsonParameters(value.ToString(), method); - } - catch (Exception) - { - result = new List() { value }; - } + result = GetJsonParameters(value.ToString(), method); } - else + catch (Exception) { result = new List() { value }; - var optionalParameters = method.GetParameters().Where(p => p.IsOptional); - // This should only run if optional parameter was not inlcuded originally. - // TODO: We do not support ONLY optional parameters > 1 at this time, this logic would need to be re-written properly, that scenario would fail at val = (T)method.Invoke(invokeObject, parameters); - if (optionalParameters.Any() && method.GetParameters().Count() > 1) - { - result.AddRange(optionalParameters.Select(p => p.HasDefaultValue && p.DefaultValue != null ? p.DefaultValue.ToString() : null)); - } } } else { - result = ActionLoaderUtils.GetJsonParameters(value.ToString(), method); + result = new List() { value }; + var optionalParameters = method.GetParameters().Where(p => p.IsOptional); + // This should only run if optional parameter was not inlcuded originally. + // TODO: We do not support ONLY optional parameters > 1 at this time, this logic would need to be re-written properly, that scenario would fail at val = (T)method.Invoke(invokeObject, parameters); + if (optionalParameters.Any() && method.GetParameters().Count() > 1) + { + result.AddRange(optionalParameters.Select(p => p.HasDefaultValue && p.DefaultValue != null ? p.DefaultValue.ToString() : null)); + } } } - catch (Exception ex) + else { - LogHelper.LogError(ex, "Error while loading parameters for action {0}", method.Name); + result = GetJsonParameters(value.ToString(), method); } - return result.ToArray(); } + catch (Exception ex) + { + LogHelper.LogError(ex, "Error while loading parameters for action {0}", method.Name); + } + return result.ToArray(); + } + + #endregion } diff --git a/src/CTA.Rules.Actions/ActionsLoader.cs b/src/CTA.Rules.Actions/ActionsLoader.cs index c241bf9a..391cbdef 100644 --- a/src/CTA.Rules.Actions/ActionsLoader.cs +++ b/src/CTA.Rules.Actions/ActionsLoader.cs @@ -15,7 +15,7 @@ namespace CTA.Rules.Actions /// /// Loads actions into the current execution context /// - public class ActionsLoader + public class ActionsLoader : ActionLoaderBase { private readonly List compilationUnitActions, attributeActions, @@ -29,9 +29,6 @@ public class ActionsLoader objectCreationExpressionActions, memberAccessActions, namespaceActions, - projectLevelActions, - projectFileActions, - projectTypeActions, interfaceActions; private readonly object attributeObject, @@ -46,10 +43,7 @@ public class ActionsLoader elementAccessObject, memberAccessObject, objectExpressionObject, - namespaceObject, - projectLevelObject, - projectFileObject, - projectTypeObject; + namespaceObject; /// /// Initializes a new ActionLoader that loads the default actions @@ -126,82 +120,82 @@ public ActionsLoader(List assemblyPaths) { case Constants.AttributeActions: { - attributeActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + attributeActions.AddRange(GetFuncMethods(t)); break; } case Constants.AttributeListActions: { - attributeListActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + attributeListActions.AddRange(GetFuncMethods(t)); break; } case Constants.ClassActions: { - classActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + classActions.AddRange(GetFuncMethods(t)); break; } case Constants.InterfaceActions: { - interfaceActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + interfaceActions.AddRange(GetFuncMethods(t)); break; } case Constants.CompilationUnitActions: { - compilationUnitActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + compilationUnitActions.AddRange(GetFuncMethods(t)); break; } case Constants.IdentifierNameActions: { - identifierNameActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + identifierNameActions.AddRange(GetFuncMethods(t)); break; } case Constants.InvocationExpressionActions: { - invocationExpressionActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + invocationExpressionActions.AddRange(GetFuncMethods(t)); break; } case Constants.ExpressionActions: { - expressionActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + expressionActions.AddRange(GetFuncMethods(t)); break; } case Constants.MethodDeclarationActions: { - methodDeclarationActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + methodDeclarationActions.AddRange(GetFuncMethods(t)); break; } case Constants.ElementAccessActions: { - elementAccessActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + elementAccessActions.AddRange(GetFuncMethods(t)); break; } case Constants.MemberAccessActions: { - memberAccessActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + memberAccessActions.AddRange(GetFuncMethods(t)); break; } case Constants.ObjectCreationExpressionActions: { - objectCreationExpressionActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + objectCreationExpressionActions.AddRange(GetFuncMethods(t)); break; } case Constants.NamespaceActions: { - namespaceActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + namespaceActions.AddRange(GetFuncMethods(t)); break; } case Constants.ProjectLevelActions: { - projectLevelActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + projectLevelActions.AddRange(GetFuncMethods(t)); break; } case Constants.ProjectFileActions: { - projectFileActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + projectFileActions.AddRange(GetFuncMethods(t)); break; } case Constants.ProjectTypeActions: { - projectTypeActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + projectTypeActions.AddRange(GetFuncMethods(t)); break; } default: @@ -219,52 +213,43 @@ public ActionsLoader(List assemblyPaths) } } public Func GetCompilationUnitAction(string name, dynamic value) - => ActionLoaderUtils.GetAction> + => GetAction> (compilationUnitActions, compilationUnitObject, name, value); public Func GetAttributeAction(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (attributeActions, attributeObject, name, value); public Func GetAttributeListAction(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (attributeListActions, attributeListObject, name, value); public Func GetClassAction(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (classActions, classObject, name, value); public Func GetInterfaceAction(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (interfaceActions, interfaceObject, name, value); public Func GetIdentifierNameAction(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (identifierNameActions, identifierNameObject, name, value); public Func GetInvocationExpressionAction(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (invocationExpressionActions, invocationExpressionObject, name, value); public Func GetExpressionAction(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (expressionActions, expressionObject, name, value); public Func GetMethodDeclarationAction(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (methodDeclarationActions, methodDeclarationObject, name, value); public Func GetNamespaceActions(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (namespaceActions, namespaceObject, name, value); public Func GetObjectCreationExpressionActions(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (objectCreationExpressionActions, objectExpressionObject, name, value); - public Func GetProjectLevelActions(string name, dynamic value) => - ActionLoaderUtils.GetAction> - (projectLevelActions, projectLevelObject, name, value); - public Func, Dictionary, List, List, string> GetProjectFileActions(string name, dynamic value) => - ActionLoaderUtils.GetAction, Dictionary, List, List, string>> - (projectFileActions, projectFileObject, name, value); - public Func GetProjectTypeActions(string name, dynamic value) => - ActionLoaderUtils.GetAction> - (projectTypeActions, projectTypeObject, name, value); public Func GetElementAccessExpressionActions(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (elementAccessActions, elementAccessObject, name, value); public Func GetMemberAccessExpressionActions(string name, dynamic value) => - ActionLoaderUtils.GetAction> + GetAction> (memberAccessActions, memberAccessObject, name, value); } diff --git a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs index 5b4f278f..a498c85e 100644 --- a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs +++ b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Runtime.Loader; -using Codelyzer.Analysis; using CTA.Rules.Config; using CTA.Rules.Models; using Microsoft.CodeAnalysis; @@ -12,7 +10,7 @@ namespace CTA.Rules.Actions; -public class VisualBasicActionsLoader +public class VisualBasicActionsLoader : ActionLoaderBase { private readonly List _compilationUnitActions, _invocationExpressionActions, @@ -32,8 +30,11 @@ public VisualBasicActionsLoader(List assemblyPaths) _compilationUnitActions = new List(); _invocationExpressionActions = new List(); _namespaceActions = new List(); + projectLevelActions = new List(); + projectFileActions = new List(); + projectTypeActions = new List(); - var assemblies = ActionLoaderUtils.GetAssemblies(assemblyPaths); + var assemblies = GetAssemblies(assemblyPaths); foreach (var assembly in assemblies) { @@ -43,12 +44,16 @@ public VisualBasicActionsLoader(List assemblyPaths) .Where(t => t.Name.EndsWith("Actions") && (t.Namespace.EndsWith(ProjectLanguage.VisualBasic.ToString()) || t.Name.StartsWith("Project"))).ToList(); - ActionLoaderUtils.TryCreateInstance(Constants.CompilationUnitActions, types, + TryCreateInstance(Constants.CompilationUnitActions, types, out _compilationUnitObject); - ActionLoaderUtils.TryCreateInstance(Constants.InvocationExpressionActions, types, + TryCreateInstance(Constants.InvocationExpressionActions, types, out _invocationExpressionObject); - ActionLoaderUtils.TryCreateInstance(Constants.NamespaceActions, types, + TryCreateInstance(Constants.NamespaceActions, types, out _namespaceObject); + TryCreateInstance(Constants.ProjectLevelActions, types, out projectLevelObject); + TryCreateInstance(Constants.ProjectFileActions, types, out projectFileObject); + TryCreateInstance(Constants.ProjectTypeActions, types, out projectTypeObject); + foreach (var t in types) { @@ -56,17 +61,32 @@ public VisualBasicActionsLoader(List assemblyPaths) { case Constants.CompilationUnitActions: { - _compilationUnitActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + _compilationUnitActions.AddRange(GetFuncMethods(t)); break; } case Constants.InvocationExpressionActions: { - _invocationExpressionActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + _invocationExpressionActions.AddRange(GetFuncMethods(t)); break; } case Constants.NamespaceActions: { - _namespaceActions.AddRange(ActionLoaderUtils.GetFuncMethods(t)); + _namespaceActions.AddRange(GetFuncMethods(t)); + break; + } + case Constants.ProjectLevelActions: + { + projectLevelActions.AddRange(GetFuncMethods(t)); + break; + } + case Constants.ProjectFileActions: + { + projectFileActions.AddRange(GetFuncMethods(t)); + break; + } + case Constants.ProjectTypeActions: + { + projectTypeActions.AddRange(GetFuncMethods(t)); break; } default: @@ -86,14 +106,14 @@ public VisualBasicActionsLoader(List assemblyPaths) public Func GetInvocationExpressionAction(string name, dynamic value) { - return ActionLoaderUtils.GetAction> + return GetAction> (_invocationExpressionActions, _invocationExpressionObject, name, value); } public Func GetCompilationUnitAction(string name, dynamic value) { - return ActionLoaderUtils.GetAction> + return GetAction> (_compilationUnitActions, _compilationUnitObject, name, value); } @@ -139,7 +159,7 @@ public Func G public Func GetNamespaceActions(string name, dynamic value) { - return ActionLoaderUtils.GetAction> + return GetAction> (_namespaceActions, _namespaceObject, name, value); } @@ -149,21 +169,6 @@ public Func G throw new NotImplementedException(); } - public Func GetProjectLevelActions(string name, dynamic value) - { - throw new NotImplementedException(); - } - - public Func, Dictionary, List, List, string> GetProjectFileActions(string name, dynamic value) - { - throw new NotImplementedException(); - } - - public Func GetProjectTypeActions(string name, dynamic value) - { - throw new NotImplementedException(); - } - /* public Func GetElementAccessExpressionActions(string name, dynamic value) { From 2767757ecc332d85ec5f8cfb9d5c5493742f3273 Mon Sep 17 00:00:00 2001 From: longachr Date: Mon, 16 May 2022 10:54:24 -0700 Subject: [PATCH 07/61] Split off visual basic rules analysis and set in Project Actions --- src/CTA.Rules.Analysis/IRulesAnalysis.cs | 15 + src/CTA.Rules.Analysis/RulesAnalysis.cs | 2 +- .../VisualBasicRulesAnalysis.cs | 421 ++++++++++++++++++ .../Csharp/CsharpRootNodes.cs | 4 +- .../FileActions/FileActions.cs | 22 + src/CTA.Rules.Models/ProjectActions.cs | 73 +-- .../RulesFiles/RulesFileLoaderResponse.cs | 9 + .../VisualBasic/VisualBasicRootNodes.cs | 5 + src/CTA.Rules.RuleFiles/RulesFileLoader.cs | 12 +- src/CTA.Rules.RuleFiles/RulesFileParser.cs | 2 +- .../VisualBasicRulesFileParser.cs | 45 ++ 11 files changed, 534 insertions(+), 76 deletions(-) create mode 100644 src/CTA.Rules.Analysis/IRulesAnalysis.cs create mode 100644 src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs create mode 100644 src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs diff --git a/src/CTA.Rules.Analysis/IRulesAnalysis.cs b/src/CTA.Rules.Analysis/IRulesAnalysis.cs new file mode 100644 index 00000000..35bdede1 --- /dev/null +++ b/src/CTA.Rules.Analysis/IRulesAnalysis.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using CTA.Rules.Models; + +namespace CTA.Rules.Analyzer; + +public interface IRulesAnalysis +{ + /// + /// Runs the Rules Analysis + /// + /// + ProjectActions Analyze(); + + ProjectActions AnalyzeFiles(ProjectActions projectActions, List updatedFiles); +} diff --git a/src/CTA.Rules.Analysis/RulesAnalysis.cs b/src/CTA.Rules.Analysis/RulesAnalysis.cs index a3f91bb1..cab27176 100644 --- a/src/CTA.Rules.Analysis/RulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/RulesAnalysis.cs @@ -15,7 +15,7 @@ namespace CTA.Rules.Analyzer /// /// Object to use for creating an analysis based on a code analysis and a list of rules /// - public class RulesAnalysis + public class RulesAnalysis : IRulesAnalysis { private readonly CsharpRootNodes _csharpRootNodes; private readonly List _sourceFileResults; diff --git a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs new file mode 100644 index 00000000..2a21b222 --- /dev/null +++ b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs @@ -0,0 +1,421 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Codelyzer.Analysis.Model; +using CTA.Rules.Common.Extensions; +using CTA.Rules.Config; +using CTA.Rules.Models; +using CTA.Rules.Models.Tokens; +using CTA.Rules.Models.Tokens.VisualBasic; +using CTA.Rules.Models.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using InvocationExpressionToken = CTA.Rules.Models.Tokens.VisualBasic.InvocationExpressionToken; +using NamespaceToken = CTA.Rules.Models.Tokens.VisualBasic.NamespaceToken; + +namespace CTA.Rules.Analyzer; + +public class VisualBasicRulesAnalysis : IRulesAnalysis +{ + private readonly VisualBasicRootNodes _visualBasicRootNodes; + private readonly List _sourceFileResults; + private readonly ProjectActions _projectActions; + private readonly ProjectType _projectType; + + /// + /// Initializes a RulesAnalysis instance for Visual Basic projects + /// + /// List of analyzed code files + /// List of rules to be applied to the code files + /// Type of project + public VisualBasicRulesAnalysis(List sourceFileResults, VisualBasicRootNodes visualBasicRootNodes, + ProjectType projectType = ProjectType.ClassLibrary) + { + _projectActions = new ProjectActions(); + _sourceFileResults = sourceFileResults; + _visualBasicRootNodes = visualBasicRootNodes; + _projectType = projectType; + } + + public ProjectActions Analyze() + { + var options = new ParallelOptions { MaxDegreeOfParallelism = Constants.ThreadCount }; + Parallel.ForEach(_sourceFileResults, options, result => + { + var fileAction = new FileActions { FilePath = result.FileFullPath }; + if (AnalyzeChildren(fileAction, result.Children, 0)) + { + _projectActions.FileActions.Add(fileAction); + } + }); + + //todo: project tokens + /* + AddPackages( + _visualBasicRootNodes.ProjectTokens.Where(p => p.FullKey == _projectType.ToString()) + ?.SelectMany(p => p.PackageActions)?.Distinct()?.ToList(), null); + */ + + return _projectActions; + } + + public ProjectActions AnalyzeFiles(ProjectActions projectActions, List updatedFiles) + { + var options = new ParallelOptions { MaxDegreeOfParallelism = Constants.ThreadCount }; + var selectedSourceFileResults = _sourceFileResults.Where(s => updatedFiles.Contains(s.FileFullPath)); + + Parallel.ForEach(selectedSourceFileResults, options, result => + { + var fileAction = new FileActions { FilePath = result.FileFullPath }; + + if (AnalyzeChildren(fileAction, result.Children, 0)) + { + var existingFileAction = + _projectActions.FileActions.FirstOrDefault(f => f.FilePath == fileAction.FilePath); + if (existingFileAction != null) + { + existingFileAction = fileAction; + } + else + { + _projectActions.FileActions.Add(fileAction); + } + } + }); + return _projectActions; + } + + /// + /// Analyzes children of nodes in a particular file + /// + /// The object containing the actions to run on the file + /// List of child nodes to check + /// Recursion level to avoid stack overflows + private bool AnalyzeChildren(FileActions fileAction, UstList children, int level, + string parentNamespace = "", string parentClass = "") + { + var containsActions = false; + + if (children == null || level > Constants.MaxRecursionDepth) + { + return false; + } + + foreach (var child in children) + { + try + { + switch (child.NodeType) + { + case IdConstants.AnnotationIdName: + { + break; + } + case IdConstants.UsingDirectiveIdName: + { + var overrideKey = string.Empty; + + var compareToken = new ImportStatementToken { Key = child.Identifier }; + _visualBasicRootNodes.ImportStatementTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + //Attempt a wildcard search, if applicable. This is using directive specific because it might want to include all sub-namespaces + if (token == null) + { + var wildcardMatches = _visualBasicRootNodes.ImportStatementTokens + .Where(i => i.Key.Contains("*")).ToList(); + if (wildcardMatches.Any()) + { + token = wildcardMatches.FirstOrDefault(i => compareToken.Key.WildcardEquals(i.Key)); + + if (token != null) + { + //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code + overrideKey = compareToken.Key; + } + } + } + if (token != null) + { + AddActions(fileAction, token, child.TextSpan, overrideKey); + containsActions = true; + } + break; + } + case IdConstants.NamespaceIdName: + { + var compareToken = new NamespaceToken { Key = child.Identifier }; + _visualBasicRootNodes.NamespaceTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, child.Identifier)) + { + containsActions = true; + } + break; + } + case IdConstants.ClassIdName: + { + break; + } + case IdConstants.InterfaceIdName: + { + break; + } + case IdConstants.MethodIdName: + { + break; + } + case IdConstants.InvocationIdName: + { + var overrideKey = string.Empty; + + InvocationExpression invocationExpression = (InvocationExpression)child; + + ////If we don't have a semantic analysis, we dont want to replace invocation expressions, otherwise we'll be replacing expressions regardless of their class/namespace + if (string.IsNullOrEmpty(invocationExpression.SemanticOriginalDefinition)) + { + break; + } + + var compareToken = new InvocationExpressionToken + { + Key = invocationExpression.SemanticOriginalDefinition, + Namespace = invocationExpression.Reference.Namespace, + Type = invocationExpression.SemanticClassType + }; + _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out var token); + + //Attempt a wildcard search, if applicable. This is invocation expression specific because it has to look inside the invocation expressions only + if (token == null) + { + var wildcardMatches = + _visualBasicRootNodes.InvocationExpressionTokens.Where(i => i.Key.Contains("*")); + if (wildcardMatches.Any()) + { + token = wildcardMatches.FirstOrDefault(i => + compareToken.Key.WildcardEquals(i.Key) && compareToken.Namespace == i.Namespace && + compareToken.Type == i.Type); + + if (token != null) + { + //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code + overrideKey = compareToken.Key; + } + } + + //If the semanticClassType is too specific to apply to all TData types + if (token == null) + { + if (invocationExpression.SemanticClassType.Contains('<')) + { + string semanticClassType = invocationExpression.SemanticClassType.Substring(0, + invocationExpression.SemanticClassType.IndexOf('<')); + compareToken = new InvocationExpressionToken + { + Key = invocationExpression.SemanticOriginalDefinition, + Namespace = invocationExpression.Reference.Namespace, + Type = semanticClassType + }; + _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out token); + } + } + } + + if (token != null) + { + AddActions(fileAction, token, child.TextSpan, overrideKey); + containsActions = true; + } + + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + { + containsActions = true; + } + + break; + } + case IdConstants.ElementAccessIdName: + { + break; + } + + case IdConstants.MemberAccessIdName: + { + break; + } + case IdConstants.DeclarationNodeIdName: + { + break; + } + case IdConstants.ObjectCreationIdName: + { + break; + } + default: + { + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + { + containsActions = true; + } + + break; + } + } + } + catch (Exception ex) + { + LogHelper.LogError(ex, "Error loading actions for item {0} of type {1}", child.Identifier, + child.NodeType); + } + } + + return containsActions; + } + + /// + /// Add actions matching the token + /// + /// The file to run actions on + /// The token that matched the file + private void AddActions(FileActions fileAction, VisualBasicNodeToken token, TextSpan textSpan, string overrideKey = "") + { + fileAction.VbInvocationExpressionActions.UnionWith(token.InvocationExpressionActions.Select(a => + new InvocationExpressionAction + { + Key = !string.IsNullOrEmpty(overrideKey) ? overrideKey : a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + InvocationExpressionActionFunc = a.InvocationExpressionActionFunc + }).ToList()); + + fileAction.VbImportActions.UnionWith(token.ImportActions.Select(a => new ImportAction() + { + Key = a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + ImportActionFunc= a.ImportActionFunc, + ImportsClauseActionFunc = a.ImportsClauseActionFunc + }).ToList()); + + fileAction.VbNamespaceActions.UnionWith(token.NamespaceActions.Select(a => + new NamespaceAction + { + Key = a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + NamespaceActionFunc = a.NamespaceActionFunc + }).ToList()); + + if (fileAction.InvocationExpressionActions.Any() + || fileAction.VbImportActions.Any() + || fileAction.NamespaceActions.Any()) + { + var nodeToken = token.Clone(); + nodeToken.TextSpan = textSpan; + fileAction.VbNodeTokens.Add(nodeToken); + } + + //AddPackages(token.PackageActions, textSpan); + } + + /// + /// Adds a list of packages to the project actions + /// + /// List of package actions based on the rules + private void AddPackages(List packageActions, TextSpan textSpan) + { + if (packageActions != null && packageActions.Count > 0) + { + packageActions.ForEach(p => + { + if (!_projectActions.PackageActions.Contains(p)) + { + _projectActions.PackageActions.Add(new PackageAction + { + Name = p.Name, Version = p.Version, TextSpan = textSpan + }); + } + }); + } + } + + /// + /// Add actions using the identifier of the object matching the token + /// + /// + /// + /// + private void AddNamedActions(FileActions fileAction, CsharpNodeToken token, string identifier, TextSpan textSpan) + { + fileAction.ClassDeclarationActions.UnionWith(token.ClassDeclarationActions + .Select(c => new ClassDeclarationAction + { + Key = identifier, + Value = c.Value, + Description = c.Description, + Name = c.Name, + Type = c.Type, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + ClassDeclarationActionFunc = c.ClassDeclarationActionFunc + })); + + fileAction.InterfaceDeclarationActions.UnionWith(token.InterfaceDeclarationActions + .Select(c => new InterfaceDeclarationAction + { + Key = identifier, + Value = c.Value, + Name = c.Name, + Type = c.Type, + Description = c.Description, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + InterfaceDeclarationActionFunc = c.InterfaceDeclarationActionFunc + })); + + fileAction.MethodDeclarationActions.UnionWith(token.MethodDeclarationActions + .Select(c => new MethodDeclarationAction + { + Key = identifier, + Value = c.Value, + Description = c.Description, + Name = c.Name, + Type = c.Type, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + MethodDeclarationActionFunc = c.MethodDeclarationActionFunc + })); + + if (fileAction.ClassDeclarationActions.Any() || fileAction.InterfaceDeclarationActions.Any() || + fileAction.MethodDeclarationActions.Any() || fileAction.ObjectCreationExpressionActions.Any()) + { + var nodeToken = token.Clone(); + nodeToken.TextSpan = textSpan; + nodeToken.AllActions.ForEach(action => + { + action.Key = identifier; + }); + fileAction.NodeTokens.Add(nodeToken); + } + } +} diff --git a/src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs b/src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs index e96e4b27..97894e1b 100644 --- a/src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs +++ b/src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs @@ -19,7 +19,7 @@ public CsharpRootNodes() ObjectCreationExpressionTokens = new HashSet(); InterfaceDeclarationTokens = new HashSet(); NamespaceTokens = new HashSet(); - ProjectTokens = new HashSet(); + ProjectTokens = new HashSet(); } @@ -35,6 +35,6 @@ public CsharpRootNodes() public HashSet MethodDeclarationTokens { get; set; } public HashSet NamespaceTokens { get; set; } public HashSet ObjectCreationExpressionTokens { get; set; } - public HashSet ProjectTokens { get; set; } + public HashSet ProjectTokens { get; set; } } } diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index d11c9e41..244a6bd6 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -1,6 +1,10 @@ using System.Collections.Generic; using CTA.Rules.Models.Tokens; +using CTA.Rules.Models.Tokens.VisualBasic; +using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using InvocationExpressionSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax; namespace CTA.Rules.Models { @@ -22,8 +26,21 @@ public FileActions() PackageActions = new HashSet(); InterfaceDeclarationActions = new HashSet(); NodeTokens = new List(); + + VbNodeTokens = new List(); + VbInvocationExpressionActions = + new HashSet>(); + VbImportActions = new HashSet(); + VbNamespaceActions = + new HashSet>(); } + public HashSet> VbNamespaceActions { get; set; } + public HashSet VbImportActions { get; set; } + public HashSet> VbInvocationExpressionActions { get; set; } + public List VbNodeTokens { get; set; } + public List NodeTokens { get; set; } public string FilePath { get; set; } public HashSet AttributeActions { get; set; } @@ -58,6 +75,11 @@ public List AllActions allActions.AddRange(Usingactions); allActions.AddRange(ObjectCreationExpressionActions); allActions.AddRange(NamespaceActions); + + // visual basic actions + allActions.AddRange(VbImportActions); + allActions.AddRange(VbNamespaceActions); + allActions.AddRange(VbInvocationExpressionActions); return allActions; } } diff --git a/src/CTA.Rules.Models/ProjectActions.cs b/src/CTA.Rules.Models/ProjectActions.cs index c80a9913..cb2e2077 100644 --- a/src/CTA.Rules.Models/ProjectActions.cs +++ b/src/CTA.Rules.Models/ProjectActions.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using CTA.Rules.Config; +using CTA.Rules.Models.VisualBasic; namespace CTA.Rules.Models { @@ -20,7 +21,8 @@ public ProjectActions() public BlockingCollection PackageActions { get; set; } public BlockingCollection ProjectReferenceActions { get; set; } public List ProjectLevelActions { get; set; } - public CsharpRootNodes ProjectRules { get; set; } + public CsharpRootNodes CsharpProjectRules { get; set; } + public VisualBasicRootNodes VbProjectRules { get; set; } public override string ToString() { @@ -33,39 +35,7 @@ public override string ToString() var actions = new List(); StringBuilder fileChanges = new StringBuilder(); - foreach (var action in fileAction.AttributeActions) - { - actions.Add(action.Description); - } - foreach (var action in fileAction.ClassDeclarationActions) - { - actions.Add(action.Description); - } - foreach (var action in fileAction.ElementAccessActions) - { - actions.Add(action.Description); - } - foreach (var action in fileAction.IdentifierNameActions) - { - actions.Add(action.Description); - } - foreach (var action in fileAction.InvocationExpressionActions) - { - actions.Add(action.Description); - } - foreach (var action in fileAction.ExpressionActions) - { - actions.Add(action.Description); - } - foreach (var action in fileAction.MemberAccessActions) - { - actions.Add(action.Description); - } - foreach (var action in fileAction.MethodDeclarationActions) - { - actions.Add(action.Description); - } - foreach (var action in fileAction.Usingactions) + foreach (var action in fileAction.AllActions) { actions.Add(action.Description); } @@ -99,40 +69,7 @@ public string ToSummaryString() { var actions = new List(); - StringBuilder fileChanges = new StringBuilder(); - foreach (var action in fileAction.AttributeActions) - { - actions.Add(string.Concat(action.Type, ":", action.Name, ":", action.Key)); - } - foreach (var action in fileAction.ClassDeclarationActions) - { - actions.Add(string.Concat(action.Type, ":", action.Name, ":", action.Key)); - } - foreach (var action in fileAction.ElementAccessActions) - { - actions.Add(string.Concat(action.Type, ":", action.Name, ":", action.Key)); - } - foreach (var action in fileAction.IdentifierNameActions) - { - actions.Add(string.Concat(action.Type, ":", action.Name, ":", action.Key)); - } - foreach (var action in fileAction.InvocationExpressionActions) - { - actions.Add(string.Concat(action.Type, ":", action.Name, ":", action.Key)); - } - foreach (var action in fileAction.ExpressionActions) - { - actions.Add(string.Concat(action.Type, ":", action.Name, ":", action.Key)); - } - foreach (var action in fileAction.MemberAccessActions) - { - actions.Add(string.Concat(action.Type, ":", action.Name, ":", action.Key)); - } - foreach (var action in fileAction.MethodDeclarationActions) - { - actions.Add(string.Concat(action.Type, ":", action.Name, ":", action.Key)); - } - foreach (var action in fileAction.Usingactions) + foreach (var action in fileAction.AllActions) { actions.Add(string.Concat(action.Type, ":", action.Name, ":", action.Key)); } diff --git a/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs b/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs new file mode 100644 index 00000000..20223762 --- /dev/null +++ b/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs @@ -0,0 +1,9 @@ +using CTA.Rules.Models.VisualBasic; + +namespace CTA.Rules.Models.RulesFiles; + +public class RulesFileLoaderResponse +{ + public CsharpRootNodes CsharpRootNodes { get; set; } + public VisualBasicRootNodes VisualBasicRootNodes { get; set; } +} diff --git a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs index 330390b3..946b2682 100644 --- a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs +++ b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; +using CTA.Rules.Models.Tokens; using CTA.Rules.Models.Tokens.VisualBasic; +using InvocationExpressionToken = CTA.Rules.Models.Tokens.VisualBasic.InvocationExpressionToken; using NamespaceToken = CTA.Rules.Models.Tokens.VisualBasic.NamespaceToken; +using ProjectToken = CTA.Rules.Models.Tokens.VisualBasic.ProjectToken; namespace CTA.Rules.Models.VisualBasic { @@ -11,10 +14,12 @@ public VisualBasicRootNodes() InvocationExpressionTokens = new HashSet(); ImportStatementTokens = new HashSet(); NamespaceTokens = new HashSet(); + ProjectTokens = new HashSet(); } public HashSet InvocationExpressionTokens { get; set; } public HashSet ImportStatementTokens { get; set; } public HashSet NamespaceTokens { get; set; } + public HashSet ProjectTokens { get; set; } } } diff --git a/src/CTA.Rules.RuleFiles/RulesFileLoader.cs b/src/CTA.Rules.RuleFiles/RulesFileLoader.cs index c0c033e1..a1c8ccb8 100644 --- a/src/CTA.Rules.RuleFiles/RulesFileLoader.cs +++ b/src/CTA.Rules.RuleFiles/RulesFileLoader.cs @@ -6,6 +6,7 @@ using Codelyzer.Analysis.Model; using CTA.Rules.Config; using CTA.Rules.Models; +using CTA.Rules.Models.RulesFiles; using Newtonsoft.Json; namespace CTA.Rules.RuleFiles @@ -57,7 +58,7 @@ public RulesFileLoader(IEnumerable projectReferences, string rulesFil /// Loads rules from the main rules file and override file /// /// A RootNodes object containing all the rules after being merged - public T Load() + public RulesFileLoaderResponse Load() { var mainNamespaceFileTasks = new Task(() => { @@ -113,6 +114,8 @@ public T Load() Task.WaitAll(mainNamespaceFileTasks, overrideNamespaceFileTasks, mainFileTask, overrideTask); + var response = new RulesFileLoaderResponse(); + if (_projectLanguage == ProjectLanguage.VisualBasic) { var rulesFileParser = new VisualBasicRulesFileParser(mainNamespaceFileTasks.Result, @@ -122,7 +125,7 @@ public T Load() _assembliesDir, _targetFramework); var rootNodes = rulesFileParser.Process(); - return (T)Convert.ChangeType(rootNodes, typeof(T)); + response.VisualBasicRootNodes = rootNodes; } else { @@ -133,9 +136,10 @@ public T Load() _assembliesDir, _targetFramework); var rootNodes = rulesFileParser.Process(); - - return (T)Convert.ChangeType(rootNodes, typeof(T)); + response.CsharpRootNodes = rootNodes; } + + return response; } diff --git a/src/CTA.Rules.RuleFiles/RulesFileParser.cs b/src/CTA.Rules.RuleFiles/RulesFileParser.cs index 088e23ce..811a5d48 100644 --- a/src/CTA.Rules.RuleFiles/RulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/RulesFileParser.cs @@ -120,7 +120,7 @@ public void ProcessObject(Rootobject rootobject) if (@namespace.@namespace == Constants.Project && @namespace.Assembly == Constants.Project) { var projectToken = _csharpRootNodes.ProjectTokens.FirstOrDefault(); - ParseActions(projectToken, @namespace.Actions); + ParseActions((ProjectToken)projectToken, @namespace.Actions); } //Namespace specific actions: else diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs index 7b3065fa..6abcbd51 100644 --- a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -340,6 +340,9 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.Project: { + var token = new ProjectToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value }; + if (!_visualBasicRootNodes.ProjectTokens.Contains(token)) { _visualBasicRootNodes.ProjectTokens.Add(token); } + ParseActions(token, recommendedActions.Actions); throw new NotImplementedException(); } } @@ -467,14 +470,56 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Project: { + var actionFunc = _actionsLoader.GetProjectLevelActions(action.Name, action.Value); + if (actionFunc != null) + { + visualBasicNodeToken.ProjectLevelActions.Add(new ProjectLevelAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(action.Value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = action.Name, + Type = action.Type, + ProjectLevelActionFunc = actionFunc + }); + } break; } case ActionTypes.ProjectFile: { + var actionFunc = _actionsLoader.GetProjectFileActions(action.Name, action.Value); + if (actionFunc != null) + { + visualBasicNodeToken.ProjectFileActions.Add(new ProjectLevelAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(action.Value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = action.Name, + Type = action.Type, + ProjectFileActionFunc = actionFunc + }); + } break; } case ActionTypes.ProjectType: { + var actionFunc = _actionsLoader.GetProjectTypeActions(action.Name, action.Value); + if (actionFunc != null) + { + visualBasicNodeToken.ProjectTypeActions.Add(new ProjectLevelAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(action.Value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = action.Name, + Type = action.Type, + ProjectTypeActionFunc = actionFunc + }); + } break; } case ActionTypes.Package: From bc1bddb0558708771e5ecbbf192bbbb8b5b592fa Mon Sep 17 00:00:00 2001 From: longachr Date: Mon, 16 May 2022 10:56:13 -0700 Subject: [PATCH 08/61] Create rewriter interface and start implementation of VB syntax rewriter --- src/CTA.Rules.Update/ActionsRewriter.cs | 34 +- src/CTA.Rules.Update/CodeReplacer.cs | 44 +- src/CTA.Rules.Update/ISyntaxRewriter.cs | 12 + .../ProjectRewriters/ProjectRewriter.cs | 39 +- .../VisualBasicActionsRewriter.cs | 442 ++++++++++++++++++ 5 files changed, 534 insertions(+), 37 deletions(-) create mode 100644 src/CTA.Rules.Update/ISyntaxRewriter.cs create mode 100644 src/CTA.Rules.Update/VisualBasicActionsRewriter.cs diff --git a/src/CTA.Rules.Update/ActionsRewriter.cs b/src/CTA.Rules.Update/ActionsRewriter.cs index 4277e8a5..3e393e3e 100644 --- a/src/CTA.Rules.Update/ActionsRewriter.cs +++ b/src/CTA.Rules.Update/ActionsRewriter.cs @@ -11,7 +11,7 @@ namespace CTA.Rules.Update.Rewriters { - public class ActionsRewriter : CSharpSyntaxRewriter + public class ActionsRewriter : CSharpSyntaxRewriter, ISyntaxRewriter { private readonly SemanticModel _semanticModel; private readonly SemanticModel _preportSemanticModel; @@ -20,7 +20,7 @@ public class ActionsRewriter : CSharpSyntaxRewriter private readonly string _filePath; private readonly List _allActions; - public List allExecutedActions { get; private set; } + public List AllExecutedActions { get; set; } private static readonly Type[] identifierNameTypes = new Type[] { typeof(MethodDeclarationSyntax), @@ -42,7 +42,7 @@ public ActionsRewriter(SemanticModel semanticModel, SemanticModel preportSemanti _syntaxGenerator = syntaxGenerator; _filePath = filePath; _allActions = allActions; - allExecutedActions = new List(); + AllExecutedActions = new List(); } public ActionsRewriter(SemanticModel semanticModel, SemanticModel preportSemanticModel, SyntaxGenerator syntaxGenerator, string filePath, GenericAction runningAction) @@ -52,7 +52,7 @@ public ActionsRewriter(SemanticModel semanticModel, SemanticModel preportSemanti _syntaxGenerator = syntaxGenerator; _filePath = filePath; _allActions = new List() { runningAction }; - allExecutedActions = new List(); + AllExecutedActions = new List(); } public override SyntaxNode VisitAttributeList(AttributeListSyntax node) @@ -82,7 +82,7 @@ public override SyntaxNode VisitAttributeList(AttributeListSyntax node) actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } } } @@ -115,7 +115,7 @@ public override SyntaxNode VisitAttribute(AttributeSyntax node) actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } } } @@ -146,7 +146,7 @@ public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } } return newNode; @@ -175,7 +175,7 @@ public override SyntaxNode VisitInterfaceDeclaration(InterfaceDeclarationSyntax actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } } return newNode; @@ -207,7 +207,7 @@ public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } } } @@ -252,7 +252,7 @@ public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax no actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } } return modifiedNode; @@ -290,7 +290,7 @@ public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } } return newNode; @@ -325,7 +325,7 @@ public override SyntaxNode VisitElementAccessExpression(ElementAccessExpressionS actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } } } @@ -360,7 +360,7 @@ public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyn actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } } } @@ -388,7 +388,7 @@ public override SyntaxNode VisitCompilationUnit(CompilationUnitSyntax node) actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } return newNode; @@ -410,7 +410,7 @@ public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressio { skipChildren = true; newNode = action.ObjectCreationExpressionGenericActionFunc(_syntaxGenerator, (ObjectCreationExpressionSyntax)newNode); - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); LogHelper.LogInformation(string.Format("{0}", action.Description)); } catch (Exception ex) @@ -450,7 +450,7 @@ public override SyntaxNode VisitNamespaceDeclaration(NamespaceDeclarationSyntax actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } } // Handle namespace remove using actions. @@ -476,7 +476,7 @@ public override SyntaxNode VisitNamespaceDeclaration(NamespaceDeclarationSyntax actionExecution.InvalidExecutions = 1; LogHelper.LogError(actionExecutionException); } - allExecutedActions.Add(actionExecution); + AllExecutedActions.Add(actionExecution); } return newNode; diff --git a/src/CTA.Rules.Update/CodeReplacer.cs b/src/CTA.Rules.Update/CodeReplacer.cs index cda0879f..2687aa3f 100644 --- a/src/CTA.Rules.Update/CodeReplacer.cs +++ b/src/CTA.Rules.Update/CodeReplacer.cs @@ -11,6 +11,7 @@ using CTA.Rules.Models; using CTA.Rules.Update.Rewriters; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editing; using TextChange = CTA.Rules.Models.TextChange; namespace CTA.Rules.Update @@ -22,9 +23,15 @@ public class CodeReplacer protected readonly List _metadataReferences; protected readonly AnalyzerResult _analyzerResult; protected readonly ProjectResult _projectResult; - - public CodeReplacer(List sourceFileBuildResults, ProjectConfiguration projectConfiguration, List metadataReferences, AnalyzerResult analyzerResult, - List updatedFiles = null, ProjectResult projectResult = null) + protected readonly ProjectLanguage _projectLanguage; + + public CodeReplacer(List sourceFileBuildResults, + ProjectConfiguration projectConfiguration, + List metadataReferences, + AnalyzerResult analyzerResult, + ProjectLanguage projectLanguage, + List updatedFiles = null, + ProjectResult projectResult = null) { _sourceFileBuildResults = sourceFileBuildResults; if (updatedFiles != null) @@ -35,6 +42,7 @@ public CodeReplacer(List sourceFileBuildResults, ProjectC _projectConfiguration = projectConfiguration; _metadataReferences = metadataReferences; _projectResult = projectResult ?? new ProjectResult(); + _projectLanguage = projectLanguage; } public Dictionary> Run(ProjectActions projectActions, ProjectType projectType) @@ -92,8 +100,8 @@ public Dictionary> Run(ProjectActions proje private void RunCodeChanges(SyntaxNode root, SourceFileBuildResult sourceFileBuildResult, FileActions currentFileActions, ConcurrentDictionary> actionsPerProject) { - ActionsRewriter oneRewriter = new ActionsRewriter(sourceFileBuildResult.SemanticModel, sourceFileBuildResult.PrePortSemanticModel, sourceFileBuildResult.SyntaxGenerator, currentFileActions.FilePath, currentFileActions.AllActions); - root = oneRewriter.Visit(root); + var syntaxRewriter = GetSyntaxRewriter(sourceFileBuildResult.SemanticModel, sourceFileBuildResult.PrePortSemanticModel, sourceFileBuildResult.SyntaxGenerator, currentFileActions.FilePath, currentFileActions.AllActions); + root = syntaxRewriter.Visit(root); var result = root.NormalizeWhitespace().ToFullString(); if (!_projectConfiguration.IsMockRun) @@ -101,8 +109,8 @@ private void RunCodeChanges(SyntaxNode root, SourceFileBuildResult sourceFileBui File.WriteAllText(sourceFileBuildResult.SourceFileFullPath, result); } - var processedActions = ValidateActions(oneRewriter.allExecutedActions, root); - processedActions = AddActionsWithoutExecutions(currentFileActions, oneRewriter.allExecutedActions); + var processedActions = ValidateActions(syntaxRewriter.AllExecutedActions, root); + processedActions = AddActionsWithoutExecutions(currentFileActions, syntaxRewriter.AllExecutedActions); if (!actionsPerProject.TryAdd(sourceFileBuildResult.SourceFileFullPath, processedActions)) { @@ -125,9 +133,9 @@ private void GenerateCodeChanges(SyntaxNode root, SourceFileBuildResult sourceFi currentFileActions.NodeTokens.ForEach(nodetoken => { nodetoken.AllActions.ForEach(nodeAction => { - ActionsRewriter oneRewriter = new ActionsRewriter(sourceFileBuildResult.SemanticModel, sourceFileBuildResult.PrePortSemanticModel, sourceFileBuildResult.SyntaxGenerator, currentFileActions.FilePath, nodeAction); + var syntaxRewriter = GetSyntaxRewriter(sourceFileBuildResult.SemanticModel, sourceFileBuildResult.PrePortSemanticModel, sourceFileBuildResult.SyntaxGenerator, currentFileActions.FilePath, nodeAction); - var newRoot = oneRewriter.Visit(root); + var newRoot = syntaxRewriter.Visit(root); var allChanges = newRoot.SyntaxTree.GetChanges(root.SyntaxTree); foreach (var textChange in allChanges) @@ -144,6 +152,24 @@ private void GenerateCodeChanges(SyntaxNode root, SourceFileBuildResult sourceFi } } + private ISyntaxRewriter GetSyntaxRewriter(SemanticModel semanticModel, SemanticModel preportSemanticModel, + SyntaxGenerator syntaxGenerator, string filePath, List allActions) + { + return _projectLanguage == ProjectLanguage.VisualBasic + ? new VisualBasicActionsRewriter(semanticModel, preportSemanticModel, syntaxGenerator, filePath, + allActions) + : new ActionsRewriter(semanticModel, preportSemanticModel, syntaxGenerator, filePath, allActions); + } + + private ISyntaxRewriter GetSyntaxRewriter(SemanticModel semanticModel, SemanticModel preportSemanticModel, + SyntaxGenerator syntaxGenerator, string filePath, GenericAction runningAction) + { + return _projectLanguage == ProjectLanguage.VisualBasic + ? new VisualBasicActionsRewriter(semanticModel, preportSemanticModel, syntaxGenerator, filePath, + runningAction) + : new ActionsRewriter(semanticModel, preportSemanticModel, syntaxGenerator, filePath, runningAction); + } + protected virtual List ApplyProjectActions(ProjectActions projectActions, ProjectType projectType) { var projectRunActions = new List(); diff --git a/src/CTA.Rules.Update/ISyntaxRewriter.cs b/src/CTA.Rules.Update/ISyntaxRewriter.cs new file mode 100644 index 00000000..65c57365 --- /dev/null +++ b/src/CTA.Rules.Update/ISyntaxRewriter.cs @@ -0,0 +1,12 @@ +#nullable enable +using System.Collections.Generic; +using CTA.Rules.Models; +using Microsoft.CodeAnalysis; + +namespace CTA.Rules.Update; + +public interface ISyntaxRewriter +{ + public SyntaxNode? Visit(SyntaxNode? node); + public List AllExecutedActions { get; set; } +} diff --git a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs index aeaa8550..c989a41e 100644 --- a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs +++ b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs @@ -9,6 +9,7 @@ using CTA.Rules.Common.Helpers; using CTA.Rules.Config; using CTA.Rules.Models; +using CTA.Rules.Models.Tokens; using CTA.Rules.RuleFiles; namespace CTA.Rules.Update @@ -26,6 +27,7 @@ public class ProjectRewriter protected readonly List _metaReferences; protected readonly AnalyzerResult _analyzerResult; protected readonly ProjectLanguage _projectLanguage; + private IRulesAnalysis _rulesAnalyzer; /// /// Initializes a new instance of ProjectRewriter using an existing analysis @@ -91,11 +93,25 @@ public ProjectResult Initialize() .Union(_sourceFileResults.SelectMany(s => s.Children.OfType())?.Select(u => new Reference() { Namespace = u.Identifier, Assembly = u.Identifier }).Distinct()) .Union(ProjectConfiguration.AdditionalReferences.Select(r => new Reference { Assembly = r, Namespace = r })); RulesFileLoader rulesFileLoader = new RulesFileLoader(allReferences, ProjectConfiguration.RulesDir, ProjectConfiguration.TargetVersions, _projectLanguage, string.Empty, ProjectConfiguration.AssemblyDir); + + var projectRules = rulesFileLoader.Load(); - var projectRules = rulesFileLoader.Load(); - - RulesAnalysis walker = new RulesAnalysis(_sourceFileResults, projectRules, ProjectConfiguration.ProjectType); - projectActions = walker.Analyze(); + HashSet projectTokens; + if (_projectLanguage == ProjectLanguage.VisualBasic) + { + _rulesAnalyzer = new VisualBasicRulesAnalysis(_sourceFileResults, projectRules.VisualBasicRootNodes, + ProjectConfiguration.ProjectType); + projectTokens = projectRules.VisualBasicRootNodes.ProjectTokens; + } + else + { + _rulesAnalyzer = new RulesAnalysis(_sourceFileResults, projectRules.CsharpRootNodes, ProjectConfiguration.ProjectType); + projectTokens = projectRules.CsharpRootNodes.ProjectTokens; + } + + _rulesAnalyzer = _projectLanguage == ProjectLanguage.VisualBasic ? new VisualBasicRulesAnalysis(_sourceFileResults, projectRules.VisualBasicRootNodes, ProjectConfiguration.ProjectType) : new + RulesAnalysis(_sourceFileResults, projectRules.CsharpRootNodes, ProjectConfiguration.ProjectType); + projectActions = _rulesAnalyzer.Analyze(); _projectReferences.ForEach(p => { projectActions.ProjectReferenceActions.Add(Config.Utils.GetRelativePath(ProjectConfiguration.ProjectPath, p)); @@ -110,11 +126,12 @@ public ProjectResult Initialize() } MergePackages(projectActions.PackageActions); - projectActions.ProjectLevelActions = projectRules.ProjectTokens.SelectMany(p => p.ProjectTypeActions).Distinct().ToList(); - projectActions.ProjectLevelActions.AddRange(projectRules.ProjectTokens.SelectMany(p => p.ProjectLevelActions).Distinct()); - projectActions.ProjectLevelActions.AddRange(projectRules.ProjectTokens.SelectMany(p => p.ProjectFileActions).Distinct()); + projectActions.ProjectLevelActions = projectTokens.SelectMany(p => p.ProjectTypeActions).Distinct().ToList(); + projectActions.ProjectLevelActions.AddRange(projectTokens.SelectMany(p => p.ProjectLevelActions).Distinct()); + projectActions.ProjectLevelActions.AddRange(projectTokens.SelectMany(p => p.ProjectFileActions).Distinct()); - projectActions.ProjectRules = projectRules; + projectActions.CsharpProjectRules = projectRules.CsharpRootNodes; + projectActions.VbProjectRules = projectRules.VisualBasicRootNodes; _projectResult.ProjectActions = projectActions; _projectResult.FeatureType = ProjectConfiguration.ProjectType; @@ -143,7 +160,7 @@ public virtual ProjectResult Run() public virtual ProjectResult Run(ProjectActions projectActions) { _projectResult.ProjectActions = projectActions; - CodeReplacer baseReplacer = new CodeReplacer(_sourceFileBuildResults, ProjectConfiguration, _metaReferences, _analyzerResult, projectResult: _projectResult); + CodeReplacer baseReplacer = new CodeReplacer(_sourceFileBuildResults, ProjectConfiguration, _metaReferences, _analyzerResult, _projectLanguage, projectResult: _projectResult); _projectResult.ExecutedActions = baseReplacer.Run(projectActions, ProjectConfiguration.ProjectType); return _projectResult; } @@ -154,12 +171,12 @@ public virtual List RunIncremental(List updatedFiles, Cs var allReferences = _sourceFileResults?.SelectMany(s => s.References).Distinct(); RulesFileLoader rulesFileLoader = new RulesFileLoader(allReferences, Constants.RulesDefaultPath, ProjectConfiguration.TargetVersions, _projectLanguage, string.Empty, ProjectConfiguration.AssemblyDir); - projectRules = rulesFileLoader.Load(); + projectRules = rulesFileLoader.Load().CsharpRootNodes; RulesAnalysis walker = new RulesAnalysis(_sourceFileResults, projectRules, ProjectConfiguration.ProjectType); var projectActions = walker.Analyze(); - CodeReplacer baseReplacer = new CodeReplacer(_sourceFileBuildResults, ProjectConfiguration, _metaReferences, _analyzerResult, updatedFiles, projectResult: _projectResult); + CodeReplacer baseReplacer = new CodeReplacer(_sourceFileBuildResults, ProjectConfiguration, _metaReferences, _analyzerResult, _projectLanguage, updatedFiles, projectResult: _projectResult); _projectResult.ExecutedActions = baseReplacer.Run(projectActions, ProjectConfiguration.ProjectType); ideFileActions = projectActions diff --git a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs new file mode 100644 index 00000000..bec39c9e --- /dev/null +++ b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs @@ -0,0 +1,442 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Codelyzer.Analysis.CSharp; +using CTA.Rules.Config; +using CTA.Rules.Models; +using CTA.Rules.Models.VisualBasic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using AttributeListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeListSyntax; +using AttributeSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeSyntax; +using CastExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.CastExpressionSyntax; +using CompilationUnitSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.CompilationUnitSyntax; +using ExpressionStatementSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionStatementSyntax; +using ExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax; +using IdentifierNameSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.IdentifierNameSyntax; +using InvocationExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.InvocationExpressionSyntax; +using MemberAccessExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.MemberAccessExpressionSyntax; +using ObjectCreationExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ObjectCreationExpressionSyntax; +using ParameterSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ParameterSyntax; +using QualifiedNameSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.QualifiedNameSyntax; +using TypeArgumentListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeArgumentListSyntax; +using TypeParameterListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeParameterListSyntax; + +namespace CTA.Rules.Update; + +public class VisualBasicActionsRewriter : VisualBasicSyntaxRewriter, ISyntaxRewriter +{ + private readonly SemanticModel _semanticModel; + private readonly SemanticModel _preportSemanticModel; + private readonly SyntaxGenerator _syntaxGenerator; + + private readonly string _filePath; + private readonly List _allActions; + + public List AllExecutedActions { get; set; } + + private static readonly Type[] identifierNameTypes = new Type[] + { + typeof(MethodDeclarationSyntax), + typeof(ConstructorDeclarationSyntax), + typeof(ClassDeclarationSyntax), + typeof(VariableDeclarationSyntax), + typeof(TypeArgumentListSyntax), + typeof(TypeParameterListSyntax), + typeof(ParameterSyntax), + typeof(ObjectCreationExpressionSyntax), + typeof(QualifiedNameSyntax), + typeof(CastExpressionSyntax) + }; + + public VisualBasicActionsRewriter(SemanticModel semanticModel, SemanticModel preportSemanticModel, + SyntaxGenerator syntaxGenerator, string filePath, List allActions) + { + _semanticModel = semanticModel; + _preportSemanticModel = preportSemanticModel; + _syntaxGenerator = syntaxGenerator; + _filePath = filePath; + _allActions = allActions; + AllExecutedActions = new List(); + } + + public VisualBasicActionsRewriter(SemanticModel semanticModel, SemanticModel preportSemanticModel, + SyntaxGenerator syntaxGenerator, string filePath, GenericAction runningAction) + { + _semanticModel = semanticModel; + _preportSemanticModel = preportSemanticModel; + _syntaxGenerator = syntaxGenerator; + _filePath = filePath; + _allActions = new List() { runningAction }; + AllExecutedActions = new List(); + } + + public override SyntaxNode VisitAttributeList(AttributeListSyntax node) + { + AttributeListSyntax attributeListSyntax = (AttributeListSyntax)base.VisitAttributeList(node); + + foreach (var attributeSyntax in attributeListSyntax.Attributes) + { + foreach (var action in _allActions.OfType()) + { + if (action.Key == attributeSyntax.Name.ToString()) + { + if (action.AttributeListActionFunc != null) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + //todo: attributeslistfunc + //attributeListSyntax = action.AttributeListActionFunc(_syntaxGenerator, attributeListSyntax); + LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + } + } + } + + return attributeListSyntax; + } + + public override SyntaxNode VisitAttribute(AttributeSyntax node) + { + AttributeSyntax attributeSyntax = (AttributeSyntax)base.VisitAttribute(node); + + foreach (var action in _allActions.OfType()) + { + if (action.Key == node.Name.ToString()) + { + if (action.AttributeActionFunc != null) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + //todo: attributesactionfunc + //attributeSyntax = action.AttributeActionFunc(_syntaxGenerator, attributeSyntax); + LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + } + } + + return attributeSyntax; + } + + public override SyntaxNode VisitClassBlock(ClassBlockSyntax node) + { + var classSymbol = SemanticHelper.GetDeclaredSymbol(node, _semanticModel, _preportSemanticModel); + ClassDeclarationSyntax newNode = (ClassDeclarationSyntax)base.VisitClassBlock(node); + + foreach (var action in _allActions.OfType()) + { + if (action.Key == node.ClassStatement.Identifier.Text.Trim()) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + newNode = action.ClassDeclarationActionFunc(_syntaxGenerator, newNode); + LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + } + + return newNode; + } + + public override SyntaxNode VisitInterfaceBlock(InterfaceBlockSyntax node) + { + var classSymbol = SemanticHelper.GetDeclaredSymbol(node, _semanticModel, _preportSemanticModel); + InterfaceDeclarationSyntax newNode = (InterfaceDeclarationSyntax)base.VisitInterfaceBlock(node); + + foreach (var action in _allActions.OfType()) + { + if (action.Key == node.InterfaceStatement.Identifier.Text.Trim()) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + newNode = action.InterfaceDeclarationActionFunc(_syntaxGenerator, newNode); + LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + } + + return newNode; + } + + public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) + { + var symbol = SemanticHelper.GetSemanticSymbol(node, _semanticModel, _preportSemanticModel); + + var identifierNameSyntax = (IdentifierNameSyntax)base.VisitIdentifierName(node); + if (symbol != null) + { + var nodeKey = symbol.OriginalDefinition != null ? symbol.OriginalDefinition.ToString() : symbol.ToString(); + foreach (var action in _allActions.OfType()) + { + if (nodeKey == action.Key && identifierNameTypes.Contains(identifierNameSyntax.Parent?.GetType())) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + //todo: identifiernamefunc + //identifierNameSyntax = action.IdentifierNameActionFunc(_syntaxGenerator, identifierNameSyntax); + LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + } + } + + return identifierNameSyntax; + } + + public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax node) + { + var newNode = base.VisitExpressionStatement(node); + SyntaxNode modifiedNode = newNode; + + var invocationExpressionNodes = node.DescendantNodes().OfType().ToList(); + if (invocationExpressionNodes.Count <= 0) + { + return newNode; + } + + var invocationExpressionNode = invocationExpressionNodes.First(); + + var symbol = SemanticHelper.GetSemanticSymbol(invocationExpressionNode, _semanticModel, _preportSemanticModel); + if (symbol == null) + { + return newNode; + } + + var nodeKey = symbol.OriginalDefinition.ToString(); + + foreach (var action in _allActions.OfType()) + { + if (nodeKey == action.Key) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + modifiedNode = action.ExpressionActionFunc(_syntaxGenerator, newNode); + LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + } + + return modifiedNode; + } + + public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node) + { + var symbol = SemanticHelper.GetSemanticSymbol(node, _semanticModel, _preportSemanticModel); + var newNode = base.VisitInvocationExpression(node); + + if (symbol == null) + { + return node; + } + + var nodeKey = symbol.OriginalDefinition.ToString(); + + foreach (var action in _allActions.OfType>()) + { + if (nodeKey == action.Key) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + newNode = action.InvocationExpressionActionFunc(_syntaxGenerator, + (InvocationExpressionSyntax)newNode); + LogHelper.LogInformation($"{node.SpanStart}: {action.Description}"); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + } + + return newNode; + } + + public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) + { + var symbol = SemanticHelper.GetSemanticSymbol(node, _semanticModel, _preportSemanticModel); + var newNode = base.VisitMemberAccessExpression(node); + + if (symbol != null) + { + var nodeKey = $"{symbol.ContainingType}.{node.Name}"; + + foreach (var action in _allActions.OfType()) + { + if (nodeKey == action.Key) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + newNode = action.MemberAccessActionFunc(_syntaxGenerator, newNode); + LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + } + } + + return newNode; + } + + public override SyntaxNode VisitCompilationUnit(CompilationUnitSyntax node) + { + CompilationUnitSyntax newNode = (CompilationUnitSyntax)base.VisitCompilationUnit(node); + //Applying using actions + foreach (var action in _allActions.OfType()) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + newNode = action.ImportActionFunc(_syntaxGenerator, newNode); + LogHelper.LogInformation(string.Format("{0} in CompilationUnit.", action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + + return newNode; + } + + public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) + { + var symbol = SemanticHelper.GetSemanticSymbol(node, _semanticModel, _preportSemanticModel); + ExpressionSyntax newNode = node; + var + skipChildren = + false; // This is here to skip actions on children node when the main identifier was changed. Just use new expression for the subsequent children actions. + foreach (var action in _allActions.OfType()) + { + if (newNode.ToString() == action.Key || symbol?.OriginalDefinition.ToDisplayString() == action.Key) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + skipChildren = true; + //todo: objectcreationexpressionsyntaxfunc + //newNode = action.ObjectCreationExpressionGenericActionFunc(_syntaxGenerator, + //(ObjectCreationExpressionSyntax)newNode); + AllExecutedActions.Add(actionExecution); + LogHelper.LogInformation(string.Format("{0}", action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + } + } + + if (!skipChildren) + { + newNode = (ObjectCreationExpressionSyntax)base.VisitObjectCreationExpression(node); + } + + return newNode; + } + + public override SyntaxNode VisitNamespaceBlock(NamespaceBlockSyntax node) + { + NamespaceBlockSyntax newNode = (NamespaceBlockSyntax)base.VisitNamespaceBlock(node); + // Handle namespace renaming actions etc. + foreach (var action in _allActions.OfType>()) + { + if (action.Key == newNode.NamespaceStatement.Name.ToString()) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + newNode = action.NamespaceActionFunc(_syntaxGenerator, newNode); + LogHelper.LogInformation(string.Format("{0}", action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + } + //VB doesn't allow for imports within a namespace. + return newNode; + } +} From fb68046d5cb1f551e184b1eb5293cfe83a4d83b1 Mon Sep 17 00:00:00 2001 From: longachr Date: Tue, 17 May 2022 17:58:18 -0700 Subject: [PATCH 09/61] Add identifier name action for vb --- .../VisualBasic/IdentifierNameActions.cs | 66 ++++++++++++++ .../VisualBasicActionsLoader.cs | 17 +++- src/CTA.Rules.Analysis/RulesAnalysis.cs | 12 +-- .../VisualBasicRulesAnalysis.cs | 20 ++++- src/CTA.Rules.Models/Actions/GenericAction.cs | 13 +++ .../Actions/Identifiernameaction.cs | 14 ++- .../FileActions/FileActions.cs | 14 +-- src/CTA.Rules.Models/RulesInput.cs | 2 + .../Tokens/Csharp/CsharpNodeToken.cs | 27 ++---- src/CTA.Rules.Models/Tokens/NodeToken.cs | 9 +- .../Tokens/VisualBasic/IdentifierNameToken.cs | 19 ++++ .../VisualBasic/VisualBasicNodeToken.cs | 15 ++-- .../VisualBasic/VisualBasicRootNodes.cs | 2 + src/CTA.Rules.RuleFiles/RulesFileParser.cs | 2 +- .../VisualBasicRulesFileParser.cs | 89 +++++++++++++++++-- src/CTA.Rules.Update/ActionsRewriter.cs | 2 +- .../VisualBasicActionsRewriter.cs | 2 +- .../VisualBasic/IdentifierNameActionsTests.cs | 71 +++++++++++++++ .../Actions/VisualBasicActionsLoaderTest.cs | 10 +++ 19 files changed, 333 insertions(+), 73 deletions(-) create mode 100644 src/CTA.Rules.Actions/VisualBasic/IdentifierNameActions.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/IdentifierNameToken.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/IdentifierNameActionsTests.cs diff --git a/src/CTA.Rules.Actions/VisualBasic/IdentifierNameActions.cs b/src/CTA.Rules.Actions/VisualBasic/IdentifierNameActions.cs new file mode 100644 index 00000000..d030b9cc --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/IdentifierNameActions.cs @@ -0,0 +1,66 @@ +using System; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Actions.VisualBasic +{ + /// + /// List of actions that can run on Identifier Names + /// + public class IdentifierNameActions + { + public Func GetReplaceIdentifierAction(string identifierName) + { + IdentifierNameSyntax ReplaceIdentifier(SyntaxGenerator syntaxGenerator, IdentifierNameSyntax node) + { + var leadingTrivia = node.GetLeadingTrivia(); + var trailingTrivia = node.GetTrailingTrivia(); + node = node.WithIdentifier(SyntaxFactory.Identifier(identifierName)).NormalizeWhitespace(); + node = node.WithLeadingTrivia(leadingTrivia); + node = node.WithTrailingTrivia(trailingTrivia); + return node; + } + return ReplaceIdentifier; + } + + public Func GetReplaceIdentifierInsideClassAction(string identifier, string classFullKey) + { + IdentifierNameSyntax ReplaceIdentifier2(SyntaxGenerator syntaxGenerator, IdentifierNameSyntax node) + { + var currentNode = node.Parent; + while (currentNode != null && currentNode.GetType() != typeof(ClassBlockSyntax)) + { + currentNode = currentNode.Parent; + } + var classNode = currentNode as ClassBlockSyntax; + + while (currentNode != null && currentNode.GetType() != typeof(NamespaceBlockSyntax)) + { + currentNode = currentNode.Parent; + } + + if (classNode == null || !(currentNode is NamespaceBlockSyntax namespaceNode)) { return node; } + + var fullName = string.Concat(namespaceNode.NamespaceStatement.Name, ".", classNode.ClassStatement.Identifier.Text); + + if (fullName == classFullKey) + { + var leadingTrivia = node.GetLeadingTrivia(); + var trailingTrivia = node.GetTrailingTrivia(); + node = node.WithIdentifier(SyntaxFactory.Identifier(identifier)).NormalizeWhitespace(); + node = node.WithLeadingTrivia(leadingTrivia); + node = node.WithTrailingTrivia(trailingTrivia); + return node; + } + else + { + return node; + } + + } + return ReplaceIdentifier2; + } + } +} diff --git a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs index a498c85e..e70a2c1f 100644 --- a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs +++ b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs @@ -14,12 +14,14 @@ public class VisualBasicActionsLoader : ActionLoaderBase { private readonly List _compilationUnitActions, _invocationExpressionActions, - _namespaceActions; + _namespaceActions, + _identifierNameActions; private readonly object _compilationUnitObject, _invocationExpressionObject, - _namespaceObject; + _namespaceObject, + _identifierNameObject; /// /// Initializes a new ActionLoader that loads the default actions @@ -30,6 +32,7 @@ public VisualBasicActionsLoader(List assemblyPaths) _compilationUnitActions = new List(); _invocationExpressionActions = new List(); _namespaceActions = new List(); + _identifierNameActions = new List (); projectLevelActions = new List(); projectFileActions = new List(); projectTypeActions = new List(); @@ -53,8 +56,8 @@ public VisualBasicActionsLoader(List assemblyPaths) TryCreateInstance(Constants.ProjectLevelActions, types, out projectLevelObject); TryCreateInstance(Constants.ProjectFileActions, types, out projectFileObject); TryCreateInstance(Constants.ProjectTypeActions, types, out projectTypeObject); + TryCreateInstance(Constants.IdentifierNameActions, types, out _identifierNameObject); - foreach (var t in types) { switch (t.Name) @@ -89,6 +92,11 @@ public VisualBasicActionsLoader(List assemblyPaths) projectTypeActions.AddRange(GetFuncMethods(t)); break; } + case Constants.IdentifierNameActions: + { + _identifierNameActions.AddRange(GetFuncMethods(t)); + break; + } default: { LogHelper.LogError($"Action type {t.Name} is not found"); @@ -142,7 +150,8 @@ public Func GetIdentifierNameAction(string name, dynamic value) { - throw new NotImplementedException(); + return GetAction> + (_identifierNameActions, _identifierNameObject, name, value); } public Func GetExpressionAction(string name, dynamic value) diff --git a/src/CTA.Rules.Analysis/RulesAnalysis.cs b/src/CTA.Rules.Analysis/RulesAnalysis.cs index cab27176..d1a5293d 100644 --- a/src/CTA.Rules.Analysis/RulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/RulesAnalysis.cs @@ -465,17 +465,7 @@ private void AddActions(FileActions fileAction, CsharpNodeToken token, TextSpan AttributeListActionFunc = a.AttributeListActionFunc }).ToList()); - fileAction.IdentifierNameActions.UnionWith(token.IdentifierNameActions.Select(a => new IdentifierNameAction() - { - Key = a.Key, - Description = a.Description, - Value = a.Value, - Name = a.Name, - Type = a.Type, - TextSpan = textSpan, - ActionValidation = a.ActionValidation, - IdentifierNameActionFunc = a.IdentifierNameActionFunc, - }).ToList()); + fileAction.IdentifierNameActions.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); fileAction.InvocationExpressionActions.UnionWith(token.InvocationExpressionActions.Select(a => new InvocationExpressionAction() { diff --git a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs index 2a21b222..5fea802c 100644 --- a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs @@ -6,10 +6,10 @@ using CTA.Rules.Common.Extensions; using CTA.Rules.Config; using CTA.Rules.Models; -using CTA.Rules.Models.Tokens; using CTA.Rules.Models.Tokens.VisualBasic; using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using IdentifierNameToken = CTA.Rules.Models.VisualBasic.IdentifierNameToken; using InvocationExpressionToken = CTA.Rules.Models.Tokens.VisualBasic.InvocationExpressionToken; using NamespaceToken = CTA.Rules.Models.Tokens.VisualBasic.NamespaceToken; @@ -253,6 +253,15 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, } case IdConstants.DeclarationNodeIdName: { + var declarationNode = (DeclarationNode)child; + var compareToken = new IdentifierNameToken() { Key = string.Concat(declarationNode.Reference.Namespace, ".", declarationNode.Identifier), Namespace = declarationNode.Reference.Namespace }; + _visualBasicRootNodes.IdentifierNameTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } break; } case IdConstants.ObjectCreationIdName: @@ -326,9 +335,12 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text NamespaceActionFunc = a.NamespaceActionFunc }).ToList()); + fileAction.VbIdentifierNameAction.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); + if (fileAction.InvocationExpressionActions.Any() || fileAction.VbImportActions.Any() - || fileAction.NamespaceActions.Any()) + || fileAction.NamespaceActions.Any() + || fileAction.IdentifierNameActions.Any()) { var nodeToken = token.Clone(); nodeToken.TextSpan = textSpan; @@ -365,7 +377,7 @@ private void AddPackages(List packageActions, TextSpan textSpan) /// /// /// - private void AddNamedActions(FileActions fileAction, CsharpNodeToken token, string identifier, TextSpan textSpan) + private void AddNamedActions(FileActions fileAction, VisualBasicNodeToken token, string identifier, TextSpan textSpan) { fileAction.ClassDeclarationActions.UnionWith(token.ClassDeclarationActions .Select(c => new ClassDeclarationAction @@ -415,7 +427,7 @@ private void AddNamedActions(FileActions fileAction, CsharpNodeToken token, stri { action.Key = identifier; }); - fileAction.NodeTokens.Add(nodeToken); + fileAction.VbNodeTokens.Add(nodeToken); } } } diff --git a/src/CTA.Rules.Models/Actions/GenericAction.cs b/src/CTA.Rules.Models/Actions/GenericAction.cs index 2acdeea8..b38bfc97 100644 --- a/src/CTA.Rules.Models/Actions/GenericAction.cs +++ b/src/CTA.Rules.Models/Actions/GenericAction.cs @@ -18,5 +18,18 @@ public GenericAction() public ActionValidation ActionValidation { get; set; } public T Clone() => (T)this.MemberwiseClone(); + + public virtual GenericAction Copy() + { + GenericAction copy = new GenericAction(); + copy.Name = this.Name; + copy.Type = this.Type; + copy.Key = this.Key; + copy.Value = this.Value; + copy.Description = this.Description; + copy.TextSpan = this.TextSpan; + copy.ActionValidation = this.ActionValidation; + return copy; + } } } diff --git a/src/CTA.Rules.Models/Actions/Identifiernameaction.cs b/src/CTA.Rules.Models/Actions/Identifiernameaction.cs index ea361bdf..0cf0718d 100644 --- a/src/CTA.Rules.Models/Actions/Identifiernameaction.cs +++ b/src/CTA.Rules.Models/Actions/Identifiernameaction.cs @@ -1,17 +1,16 @@  using System; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; namespace CTA.Rules.Models { - public class IdentifierNameAction : GenericAction + public class IdentifierNameAction : GenericAction { - public Func IdentifierNameActionFunc { get; set; } + public Func IdentifierNameActionFunc { get; set; } public override bool Equals(object obj) { - var action = (IdentifierNameAction)obj; + var action = (IdentifierNameAction)obj; return action?.Key == this.Key && action?.Value == this.Value && action?.IdentifierNameActionFunc.Method.Name == this.IdentifierNameActionFunc.Method.Name; @@ -21,5 +20,12 @@ public override int GetHashCode() { return HashCode.Combine(Key, Value, IdentifierNameActionFunc?.Method.Name); } + + public IdentifierNameAction Copy() + { + IdentifierNameAction copy = (IdentifierNameAction)base.Copy(); + copy.IdentifierNameActionFunc = this.IdentifierNameActionFunc; + return copy; + } } } diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index 244a6bd6..be1de1c4 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -4,7 +4,6 @@ using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using InvocationExpressionSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax; namespace CTA.Rules.Models { @@ -16,8 +15,8 @@ public FileActions() ClassDeclarationActions = new HashSet(); MethodDeclarationActions = new HashSet(); ElementAccessActions = new HashSet(); - IdentifierNameActions = new HashSet(); - InvocationExpressionActions = new HashSet>(); + IdentifierNameActions = new HashSet>(); + InvocationExpressionActions = new HashSet>(); ExpressionActions = new HashSet(); MemberAccessActions = new HashSet(); Usingactions = new HashSet(); @@ -38,7 +37,10 @@ public FileActions() public HashSet> VbNamespaceActions { get; set; } public HashSet VbImportActions { get; set; } - public HashSet> VbInvocationExpressionActions { get; set; } + public HashSet> + VbInvocationExpressionActions { get; set; } + public HashSet> + VbIdentifierNameAction { get; set; } public List VbNodeTokens { get; set; } public List NodeTokens { get; set; } @@ -48,8 +50,8 @@ public FileActions() public HashSet ClassDeclarationActions { get; set; } public HashSet InterfaceDeclarationActions { get; set; } public HashSet ElementAccessActions { get; set; } - public HashSet IdentifierNameActions { get; set; } - public HashSet> InvocationExpressionActions { get; set; } + public HashSet> IdentifierNameActions { get; set; } + public HashSet> InvocationExpressionActions { get; set; } public HashSet ExpressionActions { get; set; } public HashSet MemberAccessActions { get; set; } public HashSet ObjectCreationExpressionActions { get; set; } diff --git a/src/CTA.Rules.Models/RulesInput.cs b/src/CTA.Rules.Models/RulesInput.cs index de82cde1..e10557f3 100644 --- a/src/CTA.Rules.Models/RulesInput.cs +++ b/src/CTA.Rules.Models/RulesInput.cs @@ -78,8 +78,10 @@ public class Action public string Name { get; set; } public string Type { get; set; } public dynamic Value { get; set; } + public dynamic VbValue { get; set; } public string Description { get; set; } public ActionValidation ActionValidation { get; set; } + public ActionValidation VbActionValidation { get; set; } } public class Attribute diff --git a/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs b/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs index aee7c8ad..6680db5e 100644 --- a/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs @@ -1,8 +1,6 @@ using System.Linq; using System.Collections.Generic; -using CTA.Rules.Config; using Microsoft.CodeAnalysis.CSharp.Syntax; -using TextSpan = Codelyzer.Analysis.Model.TextSpan; namespace CTA.Rules.Models.Tokens { @@ -13,34 +11,22 @@ public CsharpNodeToken() UsingActions = new List(); InvocationExpressionActions = new List>(); NamespaceActions = new List>(); + IdentifierNameActions = new List>(); } public List UsingActions { get; set; } public List> InvocationExpressionActions { get; set; } public List> NamespaceActions { get; set; } + public List> IdentifierNameActions { get; set; } - public CsharpNodeToken Clone() + public override CsharpNodeToken Clone() { - CsharpNodeToken cloned = (CsharpNodeToken)this.MemberwiseClone(); - cloned.TextChanges = cloned.TextChanges?.Select(textChange => textChange.Clone()).ToList(); - cloned.TargetCPU = cloned.TargetCPU?.ToList(); - cloned.AttributeActions = cloned.AttributeActions?.Select(action => action.Clone())?.ToList(); - cloned.AttributeListActions = cloned.AttributeListActions?.Select(action => action.Clone())?.ToList(); - cloned.ClassDeclarationActions = cloned.ClassDeclarationActions?.Select(action => action.Clone())?.ToList(); - cloned.InterfaceDeclarationActions = cloned.InterfaceDeclarationActions.Select(action => action.Clone()).ToList(); - cloned.MethodDeclarationActions = cloned.MethodDeclarationActions.Select(action => action.Clone()).ToList(); - cloned.ElementAccessActions = cloned.ElementAccessActions.Select(action => action.Clone()).ToList(); - cloned.MemberAccessActions = cloned.MemberAccessActions.Select(action => action.Clone()).ToList(); + CsharpNodeToken cloned = (CsharpNodeToken)base.Clone(); cloned.UsingActions = cloned.UsingActions.Select(action => action.Clone()).ToList(); - cloned.IdentifierNameActions = cloned.IdentifierNameActions.Select(action => action.Clone()).ToList(); + cloned.IdentifierNameActions = cloned.IdentifierNameActions.Select(action => action.Clone>()).ToList(); cloned.InvocationExpressionActions = cloned.InvocationExpressionActions.Select(action => action.Clone>()).ToList(); - cloned.ExpressionActions = cloned.ExpressionActions.Select(action => action.Clone()).ToList(); cloned.NamespaceActions = cloned.NamespaceActions.Select(action => action.Clone>()).ToList(); - cloned.ObjectCreationExpressionActions = cloned.ObjectCreationExpressionActions.Select(action => action.Clone()).ToList(); - cloned.PackageActions = cloned.PackageActions.Select(action => action.Clone()).ToList(); - cloned.ProjectLevelActions = cloned.ProjectLevelActions.Select(action => action.Clone()).ToList(); - cloned.ProjectFileActions = cloned.ProjectFileActions.Select(action => action.Clone()).ToList(); - cloned.ProjectTypeActions = cloned.ProjectTypeActions.Select(action => action.Clone()).ToList(); + return cloned; } @@ -52,6 +38,7 @@ public override List AllActions allActions.AddRange(InvocationExpressionActions); allActions.AddRange(UsingActions); allActions.AddRange(NamespaceActions); + allActions.AddRange(IdentifierNameActions); allActions.AddRange(base.AllActions); return allActions; } diff --git a/src/CTA.Rules.Models/Tokens/NodeToken.cs b/src/CTA.Rules.Models/Tokens/NodeToken.cs index ede98f24..95f77609 100644 --- a/src/CTA.Rules.Models/Tokens/NodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/NodeToken.cs @@ -1,7 +1,6 @@ using System.Linq; using System.Collections.Generic; using CTA.Rules.Config; -using Microsoft.CodeAnalysis.CSharp.Syntax; using TextSpan = Codelyzer.Analysis.Model.TextSpan; namespace CTA.Rules.Models.Tokens @@ -13,7 +12,6 @@ public NodeToken() AttributeActions = new List(); AttributeListActions = new List(); ClassDeclarationActions = new List(); - IdentifierNameActions = new List(); ExpressionActions = new List(); MethodDeclarationActions = new List(); ElementAccessActions = new List(); @@ -43,7 +41,6 @@ public NodeToken() public List MethodDeclarationActions { get; set; } public List ElementAccessActions { get; set; } public List MemberAccessActions { get; set; } - public List IdentifierNameActions { get; set; } public List ExpressionActions { get; set; } public List ObjectCreationExpressionActions { get; set; } public List PackageActions { get; set; } @@ -51,9 +48,9 @@ public NodeToken() public List ProjectFileActions { get; set; } public List ProjectTypeActions { get; set; } - public CsharpNodeToken Clone() + public virtual NodeToken Clone() { - CsharpNodeToken cloned = (CsharpNodeToken)this.MemberwiseClone(); + NodeToken cloned = (NodeToken)this.MemberwiseClone(); cloned.TextChanges = cloned.TextChanges?.Select(textChange => textChange.Clone()).ToList(); cloned.TargetCPU = cloned.TargetCPU?.ToList(); cloned.AttributeActions = cloned.AttributeActions?.Select(action => action.Clone())?.ToList(); @@ -63,7 +60,6 @@ public CsharpNodeToken Clone() cloned.MethodDeclarationActions = cloned.MethodDeclarationActions.Select(action => action.Clone()).ToList(); cloned.ElementAccessActions = cloned.ElementAccessActions.Select(action => action.Clone()).ToList(); cloned.MemberAccessActions = cloned.MemberAccessActions.Select(action => action.Clone()).ToList(); - cloned.IdentifierNameActions = cloned.IdentifierNameActions.Select(action => action.Clone()).ToList(); cloned.ExpressionActions = cloned.ExpressionActions.Select(action => action.Clone()).ToList(); cloned.ObjectCreationExpressionActions = cloned.ObjectCreationExpressionActions.Select(action => action.Clone()).ToList(); cloned.PackageActions = cloned.PackageActions.Select(action => action.Clone()).ToList(); @@ -85,7 +81,6 @@ public virtual List AllActions allActions.AddRange(InterfaceDeclarationActions); allActions.AddRange(ElementAccessActions); allActions.AddRange(MemberAccessActions); - allActions.AddRange(IdentifierNameActions); allActions.AddRange(ExpressionActions); allActions.AddRange(MemberAccessActions); allActions.AddRange(ObjectCreationExpressionActions); diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/IdentifierNameToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/IdentifierNameToken.cs new file mode 100644 index 00000000..d9701fd5 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/IdentifierNameToken.cs @@ -0,0 +1,19 @@ + +using System; +using CTA.Rules.Models.Tokens.VisualBasic; + +namespace CTA.Rules.Models.VisualBasic +{ + public class IdentifierNameToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (IdentifierNameToken)obj; + return token?.Key == this.Key && token?.Namespace == this.Namespace; + } + public override int GetHashCode() + { + return HashCode.Combine(Key, Namespace); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs index c5a2ee0c..edf664a2 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs @@ -1,10 +1,8 @@ using System.Linq; using System.Collections.Generic; -using CTA.Rules.Config; +using System.Configuration; using CTA.Rules.Models.VisualBasic; -using Microsoft.Build.Logging.StructuredLogger; using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using TextSpan = Codelyzer.Analysis.Model.TextSpan; namespace CTA.Rules.Models.Tokens.VisualBasic { @@ -15,23 +13,25 @@ public VisualBasicNodeToken() InvocationExpressionActions = new List>(); ImportActions = new List(); NamespaceActions = new List>(); + IdentifierNameActions = new List>(); } public List> InvocationExpressionActions { get; set; } public List ImportActions { get; set; } public List> NamespaceActions { get; set; } + public List> IdentifierNameActions { get; set; } - public VisualBasicNodeToken Clone() + public override VisualBasicNodeToken Clone() { - VisualBasicNodeToken cloned = (VisualBasicNodeToken)this.MemberwiseClone(); - cloned.TextChanges = cloned.TextChanges?.Select(textChange => textChange.Clone()).ToList(); - cloned.TargetCPU = cloned.TargetCPU?.ToList(); + VisualBasicNodeToken cloned = (VisualBasicNodeToken)base.Clone(); cloned.InvocationExpressionActions = cloned.InvocationExpressionActions .Select(action => action.Clone>()).ToList(); cloned.ImportActions = cloned.ImportActions .Select(action => action.Clone()).ToList(); cloned.NamespaceActions = cloned.NamespaceActions .Select(action => action.Clone>()).ToList(); + cloned.IdentifierNameActions = cloned.IdentifierNameActions + .Select(action => action.Clone>()).ToList(); return cloned; } @@ -43,6 +43,7 @@ public override List AllActions allActions.AddRange(InvocationExpressionActions); allActions.AddRange(NamespaceActions); allActions.AddRange(ImportActions); + allActions.AddRange(IdentifierNameActions); allActions.AddRange(base.AllActions); return allActions; } diff --git a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs index 946b2682..e06ef563 100644 --- a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs +++ b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs @@ -15,11 +15,13 @@ public VisualBasicRootNodes() ImportStatementTokens = new HashSet(); NamespaceTokens = new HashSet(); ProjectTokens = new HashSet(); + IdentifierNameTokens = new HashSet(); } public HashSet InvocationExpressionTokens { get; set; } public HashSet ImportStatementTokens { get; set; } public HashSet NamespaceTokens { get; set; } public HashSet ProjectTokens { get; set; } + public HashSet IdentifierNameTokens { get; set; } } } diff --git a/src/CTA.Rules.RuleFiles/RulesFileParser.cs b/src/CTA.Rules.RuleFiles/RulesFileParser.cs index 811a5d48..edd82131 100644 --- a/src/CTA.Rules.RuleFiles/RulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/RulesFileParser.cs @@ -511,7 +511,7 @@ public void ParseActions(CsharpNodeToken csharpNodeToken, List actions) var actionFunc = actionsLoader.GetIdentifierNameAction(action.Name, action.Value); if (actionFunc != null) { - csharpNodeToken.IdentifierNameActions.Add(new IdentifierNameAction() + csharpNodeToken.IdentifierNameActions.Add(new IdentifierNameAction() { Key = csharpNodeToken.Key, Value = GetActionValue(action.Value), diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs index 6abcbd51..f599823d 100644 --- a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -10,7 +10,7 @@ using Microsoft.Build.Logging.StructuredLogger; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using Newtonsoft.Json; - +using IdentifierNameToken = CTA.Rules.Models.VisualBasic.IdentifierNameToken; namespace CTA.Rules.RuleFiles @@ -146,22 +146,31 @@ public void ProcessObject(Rootobject rootobject) } foreach (var @class in @namespace.Classes) { - /* if (@class.Actions != null && @class.Actions.Count > 0) { + /* if (@class.KeyType == CTA.Rules.Config.Constants.BaseClass || @class.KeyType == CTA.Rules.Config.Constants.ClassName) { var token = new ClassDeclarationToken() { Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace }; if (!_rootNodes.Classdeclarationtokens.Contains(token)) { _rootNodes.Classdeclarationtokens.Add(token); } ParseActions(token, @class.Actions); } - else if (@class.KeyType == CTA.Rules.Config.Constants.Identifier) + */ + if (@class.KeyType == CTA.Rules.Config.Constants.Identifier) { - var token = new IdentifierNameToken() { Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace }; - if (!_rootNodes.Identifiernametokens.Contains(token)) { _rootNodes.Identifiernametokens.Add(token); } + var token = new IdentifierNameToken + { + Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace + }; + if (!_visualBasicRootNodes.IdentifierNameTokens.Contains(token)) + { + _visualBasicRootNodes.IdentifierNameTokens.Add(token); + } + ParseActions(token, @class.Actions); } } + /* foreach (var attribute in @class.Attributes) { if (attribute.Actions != null && attribute.Actions.Count > 0) @@ -203,6 +212,18 @@ public void ProcessObject(Rootobject rootobject) } else if (@interface.KeyType == CTA.Rules.Config.Constants.Identifier) { + var token = new IdentifierNameToken + { + Key = @interface.FullKey, + FullKey = @interface.FullKey, + Namespace = @namespace.@namespace + }; + if (!_visualBasicRootNodes.IdentifierNameTokens.Contains(token)) + { + _visualBasicRootNodes.IdentifierNameTokens.Add(token); + } + + ParseActions(token, @interface.Actions); } } foreach (var attribute in @interface.Attributes) @@ -282,12 +303,52 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) } case ActionTypes.Class: { - throw new NotImplementedException(); + if (recommendation.KeyType == CTA.Rules.Config.Constants.BaseClass || recommendation.KeyType == CTA.Rules.Config.Constants.ClassName) + { + } + else if (recommendation.KeyType == CTA.Rules.Config.Constants.Identifier) + { + var token = new IdentifierNameToken + { + Key = recommendation.Value, + Description = recommendedActions.Description, + TargetCPU = targetCPUs, + FullKey = recommendation.Value, + Namespace = @namespace.Name + }; + if (!_visualBasicRootNodes.IdentifierNameTokens.Contains(token)) + { + _visualBasicRootNodes.IdentifierNameTokens.Add(token); + } + + ParseActions(token, recommendedActions.Actions); + } + break; } case ActionTypes.Interface: { - throw new NotImplementedException(); + if (recommendation.KeyType == CTA.Rules.Config.Constants.BaseClass || recommendation.KeyType == CTA.Rules.Config.Constants.ClassName) + { + } + else if (recommendation.KeyType == CTA.Rules.Config.Constants.Identifier) + { + var token = new IdentifierNameToken + { + Key = recommendation.Value, + Description = recommendedActions.Description, + TargetCPU = targetCPUs, + FullKey = recommendation.Value, + Namespace = @namespace.Name + }; + if (!_visualBasicRootNodes.IdentifierNameTokens.Contains(token)) + { + _visualBasicRootNodes.IdentifierNameTokens.Add(token); + } + + ParseActions(token, recommendedActions.Actions); + } + break; } case ActionTypes.Method: @@ -442,6 +503,20 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Identifier: { + var actionFunc = _actionsLoader.GetIdentifierNameAction(action.Name, action.Value); + if (actionFunc != null) + { + visualBasicNodeToken.IdentifierNameActions.Add(new IdentifierNameAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(action.Value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = action.Name, + Type = action.Type, + IdentifierNameActionFunc = actionFunc + }); + } break; } case ActionTypes.Attribute: diff --git a/src/CTA.Rules.Update/ActionsRewriter.cs b/src/CTA.Rules.Update/ActionsRewriter.cs index 3e393e3e..2999293f 100644 --- a/src/CTA.Rules.Update/ActionsRewriter.cs +++ b/src/CTA.Rules.Update/ActionsRewriter.cs @@ -188,7 +188,7 @@ public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) if (symbol != null) { var nodeKey = symbol.OriginalDefinition != null ? symbol.OriginalDefinition.ToString() : symbol.ToString(); - foreach (var action in _allActions.OfType()) + foreach (var action in _allActions.OfType>()) { if (nodeKey == action.Key && identifierNameTypes.Contains(identifierNameSyntax.Parent?.GetType())) { diff --git a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs index bec39c9e..97bd01cd 100644 --- a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs +++ b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs @@ -207,7 +207,7 @@ public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) if (symbol != null) { var nodeKey = symbol.OriginalDefinition != null ? symbol.OriginalDefinition.ToString() : symbol.ToString(); - foreach (var action in _allActions.OfType()) + foreach (var action in _allActions.OfType>()) { if (nodeKey == action.Key && identifierNameTypes.Contains(identifierNameSyntax.Parent?.GetType())) { diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/IdentifierNameActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/IdentifierNameActionsTests.cs new file mode 100644 index 00000000..3d5b53b7 --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/IdentifierNameActionsTests.cs @@ -0,0 +1,71 @@ +using CTA.Rules.Actions.VisualBasic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; +using System.Collections.Generic; +using System.Linq; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class IdentifierNameActionsTests + { + private SyntaxGenerator _syntaxGenerator; + private IdentifierNameActions _identifierNameActions; + private IdentifierNameSyntax _node; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _identifierNameActions = new IdentifierNameActions(); + _node = (IdentifierNameSyntax)_syntaxGenerator.IdentifierName("MusicStoreEntities"); + } + + [Test] + public void ReplaceIdentifierInsideClassActionTest() + { + string newIdentifier = "SuperAwesomeClass.SomethingElse"; + string originalIdentifier = "SuperAwesomeClass.MusicStoreEntities"; + string namespaceName = "MvcMusicStore.Controllers"; + string className = "ShoppingCartController"; + SyntaxNode customNode = _syntaxGenerator.NamespaceDeclaration(namespaceName, + _syntaxGenerator.ClassDeclaration(className, null, Accessibility.NotApplicable, + DeclarationModifiers.None, _syntaxGenerator.IdentifierName("Controller"), null, + new List() + { + _syntaxGenerator.FieldDeclaration("storeDB", + _syntaxGenerator.IdentifierName(originalIdentifier), Accessibility.Public, + DeclarationModifiers.None, + _syntaxGenerator.ObjectCreationExpression(SyntaxFactory.ParseTypeName(originalIdentifier))) + })).NormalizeWhitespace(); + + var replaceIdentifierFunc = + _identifierNameActions.GetReplaceIdentifierInsideClassAction(newIdentifier, + namespaceName + "." + className); + var variableDeclaration = (FieldDeclarationSyntax)customNode.ChildNodes() + .FirstOrDefault(c => c.IsKind(SyntaxKind.ClassBlock)).ChildNodes() + .FirstOrDefault(f => f.IsKind(SyntaxKind.FieldDeclaration)); + + var newNode = replaceIdentifierFunc(_syntaxGenerator, + (IdentifierNameSyntax)variableDeclaration.Declarators.First().AsClause.ChildNodes() + .FirstOrDefault(c => c.IsKind(SyntaxKind.IdentifierName))); + + Assert.AreEqual(newIdentifier, newNode.ToFullString().Trim()); + } + + [Test] + public void ReplaceIdentifierActionTest() + { + string newIdentifier = "SomethingElse"; + var removeAttributeFunc = + _identifierNameActions.GetReplaceIdentifierAction(newIdentifier); + var newNode = removeAttributeFunc(_syntaxGenerator, _node); + + Assert.AreEqual(newIdentifier, newNode.ToFullString()); + } + } +} diff --git a/tst/CTA.Rules.Test/Actions/VisualBasicActionsLoaderTest.cs b/tst/CTA.Rules.Test/Actions/VisualBasicActionsLoaderTest.cs index 11c90106..1173a116 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasicActionsLoaderTest.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasicActionsLoaderTest.cs @@ -53,5 +53,15 @@ public void InvocationExpressionActionsTest() Assert.IsNotNull(appendMethod); Assert.IsNotNull(addComment); } + + [Test] + public void IdentifierNameActionsTest() + { + var replaceIdentifier = _actionLoader.GetIdentifierNameAction("ReplaceIdentifier", "identifierName"); + var replaceIdentifierInsideClass = _actionLoader.GetIdentifierNameAction("ReplaceIdentifierInsideClass", "{ identifier: \"identifier\", classFullKey: \"classKey\" }"); + + Assert.IsNotNull(replaceIdentifier); + Assert.IsNotNull(replaceIdentifierInsideClass); + } } } \ No newline at end of file From 9995db1dfddf5bd1c5c0b543e68b7da76a4b6cd4 Mon Sep 17 00:00:00 2001 From: longachr Date: Mon, 23 May 2022 14:45:16 -0700 Subject: [PATCH 10/61] Add method block actions and unit tests --- .../VisualBasic/MethodBlockActions.cs | 178 ++++++++++++++++++ src/CTA.Rules.Config/Constants.cs | 1 + .../VisualBasic/MethodBlockActionsTests.cs | 157 +++++++++++++++ 3 files changed, 336 insertions(+) create mode 100644 src/CTA.Rules.Actions/VisualBasic/MethodBlockActions.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs diff --git a/src/CTA.Rules.Actions/VisualBasic/MethodBlockActions.cs b/src/CTA.Rules.Actions/VisualBasic/MethodBlockActions.cs new file mode 100644 index 00000000..b7a33092 --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/MethodBlockActions.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using CTA.Rules.Config; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Actions.VisualBasic +{ + /// + /// List of actions that can run on Method Declarations + /// + public class MethodBlockActions + { + public Func GetAddCommentAction(string comment, string dontUseCTAPrefix = null) + { + MethodBlockSyntax AddComment(SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) + { + SyntaxTriviaList currentTrivia = node.GetLeadingTrivia(); + var commentFormat = !string.IsNullOrEmpty(dontUseCTAPrefix) ? Constants.VbCommentFormatBlank : Constants.VbCommentFormat; + currentTrivia = currentTrivia.Insert(0, SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, string.Format(commentFormat, comment))); + node = node.WithLeadingTrivia(currentTrivia).NormalizeWhitespace(); + return node; + } + return AddComment; + } + + public Func GetAppendExpressionAction(string expression) + { + // TODO: This will add an expression at the bottom of a method body, in the future we should add granularity for where to add the expression within a method body + Func appendExpression = (SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) => + { + StatementSyntax statementExpression = SyntaxFactory.ParseExecutableStatement(expression); + if(!statementExpression.FullSpan.IsEmpty) + { + node = node.AddStatements(statementExpression).NormalizeWhitespace(); + } + return node; + }; + return appendExpression; + } + + public Func GetChangeMethodNameAction(string newMethodName) + { + MethodBlockSyntax ChangeMethodName(SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) + { + var newMethodStatement = node.SubOrFunctionStatement.WithIdentifier(SyntaxFactory.Identifier(newMethodName)); + var newMethodNode = node.WithSubOrFunctionStatement(newMethodStatement).NormalizeWhitespace(); + return newMethodNode; + } + return ChangeMethodName; + } + + public Func GetChangeMethodToReturnTaskTypeAction() + { + MethodBlockSyntax ChangeMethodToReturnTaskType(SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) + { + var methodStatement = node.SubOrFunctionStatement; + SimpleAsClauseSyntax oldAsClause = methodStatement.AsClause; + if (methodStatement.IsKind(SyntaxKind.SubStatement)) + { + // if sub, convert to function and return task + var functionStatement = SyntaxFactory.FunctionStatement(methodStatement.Identifier); + functionStatement = + functionStatement.WithAsClause( + SyntaxFactory.SimpleAsClause(SyntaxFactory.IdentifierName("Task"))) + .WithModifiers(methodStatement.Modifiers); + + var newNode = SyntaxFactory.MethodBlock(SyntaxKind.FunctionBlock, + functionStatement, node.Statements, SyntaxFactory.EndFunctionStatement()); + return newNode.NormalizeWhitespace(); + } + + // already function, need to wrap return in task + var genericName = + SyntaxFactory.GenericName("Task", SyntaxFactory.TypeArgumentList(oldAsClause.Type)); + methodStatement = methodStatement.WithAsClause(SyntaxFactory.SimpleAsClause(genericName)); + return node.WithSubOrFunctionStatement(methodStatement).NormalizeWhitespace(); + } + return ChangeMethodToReturnTaskType; + } + + public Func GetRemoveMethodParametersAction() + { + MethodBlockSyntax RemoveMethodParametersAction(SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) + { + var parameters = new List(); + var newMethodStatement = + node.SubOrFunctionStatement + .WithParameterList(SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters))) + .NormalizeWhitespace(); + return node.WithSubOrFunctionStatement(newMethodStatement); + } + return RemoveMethodParametersAction; + } + + public Func GetAddParametersToMethodAction(string types, string identifiers) + { + MethodBlockSyntax AddParametersToMethodAction(SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) + { + var newMethodStatement = node.SubOrFunctionStatement; + if (!string.IsNullOrWhiteSpace(identifiers) && !string.IsNullOrWhiteSpace(types)) + { + var identifiersArray = identifiers.Split(',', StringSplitOptions.RemoveEmptyEntries); + var typesArray = types.Split(',', StringSplitOptions.RemoveEmptyEntries); + + if (identifiersArray.Length == typesArray.Length) + { + var parameters = new List(); + for (var i = 0; i < identifiersArray.Length; i++) + { + parameters.Add(SyntaxFactory + .Parameter(SyntaxFactory.ModifiedIdentifier(identifiersArray[i])) + .WithAsClause( + SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName(typesArray[i]))) + .NormalizeWhitespace()); + } + + var separatedSyntaxList = SyntaxFactory.SeparatedList(parameters); + newMethodStatement = + newMethodStatement.WithParameterList(SyntaxFactory.ParameterList(separatedSyntaxList)) + .NormalizeWhitespace(); + } + } + + return node.WithSubOrFunctionStatement(newMethodStatement).NormalizeWhitespace(); + } + + return AddParametersToMethodAction; + } + + public Func GetCommentMethodAction( + string comment = null, + string dontUseCTAPrefix = null) + { + MethodBlockSyntax CommentMethodAction(SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) + { + var bodyStatments = node.Statements; + var newBody = new SyntaxTriviaList(); + foreach (var statement in bodyStatments) + { + var newLine = SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, @$"' {statement.ToFullString()}"); + newBody = newBody.Add(newLine).Add(SyntaxFactory.SyntaxTrivia(SyntaxKind.EndOfLineTrivia, "")); + } + + var endStatement = node.EndSubOrFunctionStatement.WithLeadingTrivia(newBody); + var newMethodNode = node.WithEndSubOrFunctionStatement(endStatement) + .WithStatements(new SyntaxList()); + + if (!string.IsNullOrWhiteSpace(comment)) + { + var addCommentsToMethodFunc = GetAddCommentAction(comment, dontUseCTAPrefix); + return addCommentsToMethodFunc(syntaxGenerator, newMethodNode); + } + + return newMethodNode; + } + return CommentMethodAction; + } + + public Func GetAddExpressionToMethodAction(string expression) + { + MethodBlockSyntax AddExpressionToMethodAction(SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) + { + var newMethodNode = node; + StatementSyntax parsedExpression = SyntaxFactory.ParseExecutableStatement(expression); + if (!parsedExpression.FullSpan.IsEmpty) + { + newMethodNode = node.AddStatements(new StatementSyntax[] { parsedExpression }).NormalizeWhitespace(); + } + return newMethodNode; + } + return AddExpressionToMethodAction; + } + } +} diff --git a/src/CTA.Rules.Config/Constants.cs b/src/CTA.Rules.Config/Constants.cs index fa846fa5..4b0fcb44 100644 --- a/src/CTA.Rules.Config/Constants.cs +++ b/src/CTA.Rules.Config/Constants.cs @@ -52,6 +52,7 @@ public class Constants public const string CommentFormat = @"/* Added by CTA: {0} */"; public const string VbCommentFormat = @"' Added by CTA: {0}"; public const string CommentFormatBlank = @"/* {0} */"; + public const string VbCommentFormatBlank = @"' {0}"; public const string WebSdkName = "Microsoft.NET.Sdk.Web"; public const string ClassLibrarySdkName = "Microsoft.NET.Sdk"; diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs new file mode 100644 index 00000000..2390bf8f --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs @@ -0,0 +1,157 @@ +using System; +using CTA.Rules.Actions.VisualBasic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; +using System.Collections.Generic; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class MethodBlockActionsTests + { + private MethodBlockActions _methodBlockActions; + private SyntaxGenerator _syntaxGenerator; + private MethodBlockSyntax _subNode; + private MethodBlockSyntax _functionNode; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _methodBlockActions = new MethodBlockActions(); + + var body = new SyntaxList().Add( + SyntaxFactory.ParseExecutableStatement(@"' Nothing to see here")); + _subNode = SyntaxFactory.MethodBlock(SyntaxKind.SubBlock, + SyntaxFactory + .MethodStatement(SyntaxKind.SubStatement, SyntaxFactory.Token(SyntaxKind.SubKeyword), "Authorize") + .WithModifiers(SyntaxFactory.TokenList().Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword))), + SyntaxFactory.EndSubStatement()).WithStatements(body); + + body = body.Add(SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression("0"))); + _functionNode = SyntaxFactory.MethodBlock(SyntaxKind.FunctionBlock, + SyntaxFactory.MethodStatement(SyntaxKind.FunctionStatement, + SyntaxFactory.Token(SyntaxKind.FunctionKeyword), "TestFunction") + .WithModifiers(SyntaxFactory.TokenList().Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword))) + .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName("Integer"))), + SyntaxFactory.EndFunctionStatement()).WithStatements(body); + } + + [Test] + public void MethodDeclarationAddComment() + { + const string comment = "This is a comment"; + var addCommentFunction = _methodBlockActions.GetAddCommentAction(comment); + var newNode = addCommentFunction(_syntaxGenerator, _subNode); + + StringAssert.Contains(comment, newNode.ToFullString()); + } + + [Test] + public void MethodDeclarationAddExpression() + { + var nodeBody = _subNode.Statements; + nodeBody = nodeBody.Add(SyntaxFactory.ParseExecutableStatement("Dim testing as String = \"Testing\"")); + _subNode = _subNode.WithStatements(nodeBody); + + const string expression = "Dim i as Integer = 5"; + var addExpressionFunction = _methodBlockActions.GetAppendExpressionAction(expression); + var newNode = addExpressionFunction(_syntaxGenerator, _subNode); + + StringAssert.Contains(expression, newNode.ToFullString()); + } + + [Test] + public void MethodDeclarationActionComparison() + { + throw new NotImplementedException(); + // var methodDeclarationAction = new MethodDeclarationAction() + // { + // Key = "Test", + // Value = "Test2", + // MethodDeclarationActionFunc = _methodDeclarationActions.GetAddCommentAction("NewAttribute") + // }; + // + // var cloned = methodDeclarationAction.Clone(); + // + // Assert.True(methodDeclarationAction.Equals(cloned)); + // cloned.Value = "DifferentValue"; + // Assert.False(methodDeclarationAction.Equals(cloned)); + } + + [Test] + public void CommentMethodAction() + { + var expressions = new List + { + "Dim testing as String = \"Testing\"", + "Dim testing2 as String = \"Testing2\"" + }; + var nodeBody = _subNode.Statements; + foreach (var e in expressions) + { + nodeBody = nodeBody.Add(SyntaxFactory.ParseExecutableStatement(e)); + } + _subNode = _subNode.WithStatements(nodeBody); + + var commentMethodFunc = _methodBlockActions.GetCommentMethodAction("this is a comment"); + var newNode = commentMethodFunc(_syntaxGenerator, _subNode); + + foreach (var e in expressions) + { + StringAssert.Contains($"' {e}", newNode.ToFullString()); + } + } + + [Test] + public void AddExpressionToMethod() + { + var nodeBody = _subNode.Statements; + nodeBody = nodeBody.Add(SyntaxFactory.ParseExecutableStatement("Dim testing as String = \"Testing\"")); + _subNode = _subNode.WithStatements(nodeBody); + + const string expression = "Dim i as Integer = 5"; + var addExpressionFunction = _methodBlockActions.GetAddExpressionToMethodAction(expression); + var newNode = addExpressionFunction(_syntaxGenerator, _subNode); + + StringAssert.Contains(expression, newNode.ToFullString()); + } + + [Test] + public void AddParametersToMethod() + { + var addParamsAction = _methodBlockActions.GetAddParametersToMethodAction("String,String", "param1,param2"); + var newNode = addParamsAction(_syntaxGenerator, _subNode); + StringAssert.Contains("param1 As String", newNode.ToFullString()); + } + + [Test] + public void ChangeMethodToReturnTask() + { + var changeReturnToTaskFunc = _methodBlockActions.GetChangeMethodToReturnTaskTypeAction(); + var newNode = changeReturnToTaskFunc(_syntaxGenerator, _subNode); + + StringAssert.Contains("Task", newNode.ToFullString()); + Assert.True(newNode.SubOrFunctionStatement.IsKind(SyntaxKind.FunctionStatement)); + + var newFunction = changeReturnToTaskFunc(_syntaxGenerator, _functionNode); + StringAssert.Contains("Task(Of Integer)", newFunction.ToFullString()); + } + + [Test] + public void ChangeMethodName() + { + var changeMethodNameFunc = _methodBlockActions.GetChangeMethodNameAction("NewName"); + + var newNode = changeMethodNameFunc(_syntaxGenerator, _subNode); + var newFunction = changeMethodNameFunc(_syntaxGenerator, _functionNode); + + StringAssert.Contains("Sub NewName", newNode.ToFullString()); + StringAssert.Contains("Function NewName", newFunction.ToFullString()); + } + } +} \ No newline at end of file From 6107ab7c510b15d3260fc99e28ed4beb29e8f965 Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 25 May 2022 11:19:10 -0700 Subject: [PATCH 11/61] Fix issue parsing await expression in method actions --- .../VisualBasic/MethodBlockActions.cs | 47 +++++++++++++++---- .../VisualBasic/MethodBlockActionsTests.cs | 13 +++++ 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/CTA.Rules.Actions/VisualBasic/MethodBlockActions.cs b/src/CTA.Rules.Actions/VisualBasic/MethodBlockActions.cs index b7a33092..5cc50b31 100644 --- a/src/CTA.Rules.Actions/VisualBasic/MethodBlockActions.cs +++ b/src/CTA.Rules.Actions/VisualBasic/MethodBlockActions.cs @@ -32,11 +32,14 @@ public Func GetAppendExpr // TODO: This will add an expression at the bottom of a method body, in the future we should add granularity for where to add the expression within a method body Func appendExpression = (SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) => { - StatementSyntax statementExpression = SyntaxFactory.ParseExecutableStatement(expression); - if(!statementExpression.FullSpan.IsEmpty) + StatementSyntax statementExpression = expression.Contains("Await") + ? ParseAwaitExpression(expression) + : SyntaxFactory.ParseExecutableStatement(expression); + if (!statementExpression.FullSpan.IsEmpty) { node = node.AddStatements(statementExpression).NormalizeWhitespace(); } + return node; }; return appendExpression; @@ -58,7 +61,7 @@ public Func GetChangeMeth MethodBlockSyntax ChangeMethodToReturnTaskType(SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) { var methodStatement = node.SubOrFunctionStatement; - SimpleAsClauseSyntax oldAsClause = methodStatement.AsClause; + var oldAsClause = methodStatement.AsClause; if (methodStatement.IsKind(SyntaxKind.SubStatement)) { // if sub, convert to function and return task @@ -66,7 +69,7 @@ MethodBlockSyntax ChangeMethodToReturnTaskType(SyntaxGenerator syntaxGenerator, functionStatement = functionStatement.WithAsClause( SyntaxFactory.SimpleAsClause(SyntaxFactory.IdentifierName("Task"))) - .WithModifiers(methodStatement.Modifiers); + .WithModifiers(methodStatement.Modifiers.Add(SyntaxFactory.Token(SyntaxKind.AsyncKeyword))); var newNode = SyntaxFactory.MethodBlock(SyntaxKind.FunctionBlock, functionStatement, node.Statements, SyntaxFactory.EndFunctionStatement()); @@ -76,7 +79,8 @@ MethodBlockSyntax ChangeMethodToReturnTaskType(SyntaxGenerator syntaxGenerator, // already function, need to wrap return in task var genericName = SyntaxFactory.GenericName("Task", SyntaxFactory.TypeArgumentList(oldAsClause.Type)); - methodStatement = methodStatement.WithAsClause(SyntaxFactory.SimpleAsClause(genericName)); + methodStatement = methodStatement.WithAsClause(SyntaxFactory.SimpleAsClause(genericName)) + .WithModifiers(methodStatement.Modifiers.Add(SyntaxFactory.Token(SyntaxKind.AsyncKeyword))); return node.WithSubOrFunctionStatement(methodStatement).NormalizeWhitespace(); } return ChangeMethodToReturnTaskType; @@ -91,7 +95,7 @@ MethodBlockSyntax RemoveMethodParametersAction(SyntaxGenerator syntaxGenerator, node.SubOrFunctionStatement .WithParameterList(SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters))) .NormalizeWhitespace(); - return node.WithSubOrFunctionStatement(newMethodStatement); + return node.WithSubOrFunctionStatement(newMethodStatement).NormalizeWhitespace(); } return RemoveMethodParametersAction; } @@ -155,7 +159,7 @@ MethodBlockSyntax CommentMethodAction(SyntaxGenerator syntaxGenerator, MethodBlo return addCommentsToMethodFunc(syntaxGenerator, newMethodNode); } - return newMethodNode; + return newMethodNode.NormalizeWhitespace(); } return CommentMethodAction; } @@ -165,14 +169,37 @@ public Func GetAddExpress MethodBlockSyntax AddExpressionToMethodAction(SyntaxGenerator syntaxGenerator, MethodBlockSyntax node) { var newMethodNode = node; - StatementSyntax parsedExpression = SyntaxFactory.ParseExecutableStatement(expression); + var parsedExpression = expression.Contains("Await") + ? ParseAwaitExpression(expression) + : SyntaxFactory.ParseExecutableStatement(expression); if (!parsedExpression.FullSpan.IsEmpty) { - newMethodNode = node.AddStatements(new StatementSyntax[] { parsedExpression }).NormalizeWhitespace(); + var body = node.Statements; + int returnIndex = body.IndexOf(s => s.IsKind(SyntaxKind.ReturnStatement)); + if (returnIndex >= 0) + { + // insert new statement before return + body = body.Insert(returnIndex, parsedExpression); + newMethodNode = node.WithStatements(body); + } + else + { + newMethodNode = node.AddStatements(parsedExpression); + } } - return newMethodNode; + + return newMethodNode.NormalizeWhitespace(); } + return AddExpressionToMethodAction; } + + private StatementSyntax ParseAwaitExpression(string expression) + { + expression = expression.Replace("Await", "", StringComparison.OrdinalIgnoreCase); + var parsedExpression = SyntaxFactory.ParseExpression(expression); + var awaitExpression = SyntaxFactory.AwaitExpression(parsedExpression); + return SyntaxFactory.ExpressionStatement(awaitExpression); + } } } diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs index 2390bf8f..1c7b4220 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs @@ -121,6 +121,17 @@ public void AddExpressionToMethod() StringAssert.Contains(expression, newNode.ToFullString()); } + [Test] + public void AddExpressionToFunction() + { + const string expression = "Await Task.Delay(1000)"; + var addExpressionFunc = _methodBlockActions.GetAddExpressionToMethodAction(expression); + var newNode = addExpressionFunc(_syntaxGenerator, _functionNode); + + StringAssert.Contains(expression, newNode.ToFullString()); + Assert.IsTrue(newNode.Statements.Last().IsKind(SyntaxKind.ReturnStatement)); + } + [Test] public void AddParametersToMethod() { @@ -136,9 +147,11 @@ public void ChangeMethodToReturnTask() var newNode = changeReturnToTaskFunc(_syntaxGenerator, _subNode); StringAssert.Contains("Task", newNode.ToFullString()); + StringAssert.Contains("Async", newNode.ToFullString()); Assert.True(newNode.SubOrFunctionStatement.IsKind(SyntaxKind.FunctionStatement)); var newFunction = changeReturnToTaskFunc(_syntaxGenerator, _functionNode); + StringAssert.Contains("Async", newFunction.ToFullString()); StringAssert.Contains("Task(Of Integer)", newFunction.ToFullString()); } From bfc8ad67c394f9df345b86721fd9c92bb3a2c7c9 Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 25 May 2022 11:43:18 -0700 Subject: [PATCH 12/61] Add class actions for vb --- .../VisualBasic/ClassActions.cs | 523 ++++++++++++++++++ .../Actions/VisualBasic/ClassActionsTests.cs | 462 ++++++++++++++++ 2 files changed, 985 insertions(+) create mode 100644 src/CTA.Rules.Actions/VisualBasic/ClassActions.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs diff --git a/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs b/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs new file mode 100644 index 00000000..e00d2a21 --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs @@ -0,0 +1,523 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using CTA.Rules.Config; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Actions.VisualBasic +{ + /// + /// List of actions that can run on Class Blocks + /// + public class ClassActions + { + public Func GetRemoveBaseClassAction(string baseClass) + { + ClassBlockSyntax RemoveBaseClass(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + var currentBaseTypes = node.Inherits.FirstOrDefault()?.Types ?? new SeparatedSyntaxList(); + SeparatedSyntaxList newBaseTypes = new SeparatedSyntaxList(); + + foreach (var baseTypeSyntax in currentBaseTypes) + { + if (!baseTypeSyntax.GetText().ToString().Trim().Equals(baseClass)) + { + newBaseTypes.Add(baseTypeSyntax); + } + } + + node = node.WithInherits(new SyntaxList + { + SyntaxFactory.InheritsStatement().WithTypes(newBaseTypes) + }); + + return node; + } + + return RemoveBaseClass; + } + + public Func GetAddBaseClassAction(string baseClass) + { + ClassBlockSyntax AddBaseClass(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + if (syntaxGenerator != null) + { + node = (ClassBlockSyntax)syntaxGenerator.AddBaseType(node, SyntaxFactory.ParseName(baseClass)); + } + else + { + var baseType = SyntaxFactory.InheritsStatement(SyntaxFactory.ParseTypeName(baseClass)); + node = node.WithInherits(new SyntaxList(baseType)); + } + return node; + } + return AddBaseClass; + } + + public Func GetChangeNameAction(string className) + { + ClassBlockSyntax ChangeName(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + node = node.WithClassStatement(SyntaxFactory.ClassStatement(SyntaxFactory.Identifier(className))) + .NormalizeWhitespace(); + return node; + } + return ChangeName; + } + + public Func GetRemoveAttributeAction(string attributeName) + { + ClassBlockSyntax RemoveAttribute(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + var attributeLists = node.ClassStatement.AttributeLists; + AttributeListSyntax attributeToRemove = null; + + foreach (var attributeList in attributeLists) + { + foreach (var attribute in attributeList.Attributes) + { + if (attribute.Name.ToString() == attributeName) + { + attributeToRemove = attributeList; + break; + } + } + } + + if (attributeToRemove != null) + { + attributeLists = attributeLists.Remove(attributeToRemove); + } + + node = node.WithClassStatement(node.ClassStatement.WithAttributeLists(attributeLists)) + .NormalizeWhitespace(); + return node; + } + + return RemoveAttribute; + } + public Func GetAddAttributeAction(string attribute) + { + ClassBlockSyntax AddAttribute(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + var attributeLists = node.ClassStatement.AttributeLists; + attributeLists = attributeLists.Add( + SyntaxFactory.AttributeList( + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.Attribute(SyntaxFactory.ParseName(attribute))))); + + node = node.WithClassStatement(node.ClassStatement.WithAttributeLists(attributeLists)) + .NormalizeWhitespace(); + return node; + } + return AddAttribute; + } + public Func GetAddCommentAction(string comment, string dontUseCTAPrefix = null) + { + ClassBlockSyntax AddComment(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + SyntaxTriviaList currentTrivia = node.GetLeadingTrivia(); + var commentFormat = dontUseCTAPrefix != null ? Constants.VbCommentFormatBlank : Constants.VbCommentFormat; + currentTrivia = currentTrivia.Add(SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, string.Format(commentFormat, comment))); + node = node.WithLeadingTrivia(currentTrivia).NormalizeWhitespace(); + return node; + } + return AddComment; + } + public Func GetAddMethodAction(string expression) + { + ClassBlockSyntax AddMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + var methodSyntax = SyntaxFactory.ParseSyntaxTree(expression).GetRoot().DescendantNodes() + .OfType().FirstOrDefault(); + var methodBlockSyntax = SyntaxFactory.ParseSyntaxTree(expression).GetRoot().DescendantNodes() + .OfType().FirstOrDefault(); + if (methodBlockSyntax != null) + { + node = node.AddMembers(methodBlockSyntax.SubOrFunctionStatement); + foreach (var statement in methodBlockSyntax.Statements) + { + node = node.AddMembers(statement); + } + } + return node.NormalizeWhitespace(); + } + return AddMethod; + } + public Func GetRemoveMethodAction(string methodName) + { + //TODO what if there is operator overloading + ClassBlockSyntax RemoveMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + var allMembers = node.Members.ToList(); + var allMethods = allMembers.OfType(); + if (allMethods.Any()) + { + var removeMethod = allMethods.FirstOrDefault(m => m.Identifier.ToString() == methodName); + if (removeMethod != null) + { + node = node.RemoveNode(removeMethod, SyntaxRemoveOptions.KeepNoTrivia).NormalizeWhitespace(); + } + } + + return node; + } + return RemoveMethod; + } + public Func GetRenameClassAction(string newClassName) + { + ClassBlockSyntax RenameClass(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + node = node.WithClassStatement(node.ClassStatement.WithIdentifier(SyntaxFactory.Identifier(newClassName))).NormalizeWhitespace(); + return node; + } + return RenameClass; + } + public Func GetReplaceMethodModifiersAction(string methodName, string modifiers) + { + ClassBlockSyntax ReplaceMethodModifiers(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + var allMembers = node.Members.ToList(); + var allMethods = allMembers.OfType(); + if (allMethods.Any()) + { + var replaceMethod = allMethods.FirstOrDefault(m => m.Identifier.ToString() == methodName); + if (replaceMethod != null) + { + var allModifiersAreValid = modifiers.Split(new char[] { ' ', ',' }).All(m => Constants.SupportedMethodModifiers.Contains(m)); + if (allModifiersAreValid) + { + SyntaxTokenList tokenList = new SyntaxTokenList(SyntaxFactory.ParseTokens(modifiers)); + var newMethod = replaceMethod.WithModifiers(tokenList); + + node = node.WithMembers(node.Members.Replace(replaceMethod, newMethod)).NormalizeWhitespace(); + } + } + } + + return node; + } + return ReplaceMethodModifiers; + } + public Func GetAddExpressionAction(string expression) + { + ClassBlockSyntax AddExpression(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + var parsedExpression = SyntaxFactory.ParseExecutableStatement(expression); + if (!parsedExpression.FullSpan.IsEmpty) + { + var nodeDeclarations = node.Members; + nodeDeclarations = nodeDeclarations.Insert(0, parsedExpression); + node = node.WithMembers(nodeDeclarations).NormalizeWhitespace(); + } + return node; + } + return AddExpression; + } + public Func GetRemoveConstructorInitializerAction(string initializerArgument) + { + ClassBlockSyntax RemoveConstructorInitializer(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + var constructor = node.ChildNodes().FirstOrDefault(c => c.IsKind(SyntaxKind.ConstructorBlock)); + if (constructor != null) + { + var constructorNode = (ConstructorBlockSyntax)constructor; + var newArguments = new SeparatedSyntaxList(); + // base initializers should be the first statement + var firstStatement = constructorNode.Statements.FirstOrDefault(); + if (firstStatement != null && + firstStatement.DescendantNodes().Any(s => s.IsKind(SyntaxKind.MyBaseExpression))) + { + var arguments = firstStatement.DescendantNodes().OfType() + .FirstOrDefault(); + if (arguments != null) + { + foreach (var arg in arguments.Arguments) + { + if (!arg.GetText().ToString().Trim().Equals(initializerArgument)) + { + newArguments = newArguments.Add(arg); + } + } + + if (newArguments.Any()) + { + node = node.ReplaceNode(arguments, SyntaxFactory.ArgumentList(newArguments)) + .NormalizeWhitespace(); + } + } + } + } + return node; + } + + return RemoveConstructorInitializer; + } + public Func GetAppendConstructorExpressionAction(string expression) + { + ClassBlockSyntax AppendConstructorExpression(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + var constructor = node.Members.FirstOrDefault(c => c.IsKind(SyntaxKind.ConstructorBlock)); + if (constructor != null) + { + ConstructorBlockSyntax constructorNode = (ConstructorBlockSyntax)constructor; + StatementSyntax statementExpression = SyntaxFactory.ParseExecutableStatement(expression); + if (!statementExpression.FullSpan.IsEmpty) + { + constructorNode = constructorNode.AddStatements(statementExpression); + node = node.ReplaceNode(constructor, constructorNode).NormalizeWhitespace(); + } + } + return node; + } + return AppendConstructorExpression; + } + + public Func GetCreateConstructorAction(string types, string identifiers) + { + ClassBlockSyntax CreateConstructor(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + // constructors in vb are just named new + var constructorStatementNode = SyntaxFactory.SubNewStatement() + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)); + + // Add constructor parameters if provided + if (!string.IsNullOrWhiteSpace(identifiers) && !string.IsNullOrWhiteSpace(types)) + { + var identifiersArray = identifiers.Split(',', StringSplitOptions.RemoveEmptyEntries); + var typesArray = types.Split(',', StringSplitOptions.RemoveEmptyEntries); + + if (identifiersArray.Length == typesArray.Length) + { + List parameters = new List(); + for (var i = 0; i < identifiersArray.Length; i++) + { + parameters.Add(SyntaxFactory + .Parameter(SyntaxFactory.ModifiedIdentifier(identifiersArray[i])) + .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName(typesArray[i])))); + } + + constructorStatementNode = constructorStatementNode.AddParameterListParameters(parameters.ToArray()); + } + } + + var constructorBlock = SyntaxFactory.ConstructorBlock(constructorStatementNode); + node = node.AddMembers(constructorBlock).NormalizeWhitespace(); + + return node; + } + return CreateConstructor; + } + + public Func GetChangeMethodNameAction(string existingMethodName, string newMethodName) + { + ClassBlockSyntax ChangeMethodName(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + // if we have more than one method with same name return without making changes + var methodNode = GetMethodNode(node, existingMethodName); + if (methodNode != null) + { + var methodActions = new MethodBlockActions(); + var changeMethodNameFunc = methodActions.GetChangeMethodNameAction(newMethodName); + var newMethodNode = changeMethodNameFunc(syntaxGenerator, methodNode); + node = node.ReplaceNode(methodNode, newMethodNode); + } + return node; + } + return ChangeMethodName; + } + + public Func GetChangeMethodToReturnTaskTypeAction(string methodName) + { + ClassBlockSyntax ChangeMethodToReturnTaskType(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + // if we have more than one method with same name return without making changes + var methodNode = GetMethodNode(node, methodName); + if (methodNode != null) + { + var methodActions = new MethodBlockActions(); + var changeMethodToReturnTaskTypeActionFunc = methodActions.GetChangeMethodToReturnTaskTypeAction(); + var newMethodNode = changeMethodToReturnTaskTypeActionFunc(syntaxGenerator, methodNode); + node = node.ReplaceNode(methodNode, newMethodNode); + } + return node; + } + return ChangeMethodToReturnTaskType; + } + + public Func GetRemoveMethodParametersAction(string methodName) + { + ClassBlockSyntax RemoveMethodParameters(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + // if we have more than one method with same name return without making changes + var methodNode = GetMethodNode(node, methodName); + if (methodNode != null) + { + var parameters = methodNode.SubOrFunctionStatement.ParameterList.Parameters; + MethodBlockActions methodActions = new MethodBlockActions(); + var removeMethodParametersActionFunc = methodActions.GetRemoveMethodParametersAction(); + var newMethodNode = removeMethodParametersActionFunc(syntaxGenerator, methodNode); + node = node.ReplaceNode(methodNode, newMethodNode); + } + return node.NormalizeWhitespace(); + } + return RemoveMethodParameters; + } + + public Func GetCommentMethodAction(string methodName, string comment = null, string dontUseCTAPrefix = null) + { + ClassBlockSyntax CommentMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + // if we have more than one method with same name return without making changes + var methodNode = GetMethodNode(node, methodName); + + if (methodNode != null) + { + var methodActions = new MethodBlockActions(); + var commentMethodAction = methodActions.GetCommentMethodAction(comment, dontUseCTAPrefix); + var newMethodNode = commentMethodAction(syntaxGenerator, methodNode); + + var methodStatementComment = + SyntaxFactory.CommentTrivia($"' {newMethodNode.SubOrFunctionStatement.ToFullString()}"); + var methodBodyComment = newMethodNode.EndSubOrFunctionStatement.GetLeadingTrivia(); + var methodEndStatementComment = + SyntaxFactory.CommentTrivia($"' {newMethodNode.EndSubOrFunctionStatement.ToString()}"); + + var trivia = new SyntaxTriviaList(); + trivia = trivia.Add(methodStatementComment); + trivia = trivia.AddRange(methodBodyComment); + trivia = trivia.Add(methodEndStatementComment); + + node = node.RemoveNode(methodNode, SyntaxRemoveOptions.KeepNoTrivia); + node = node.WithEndClassStatement(node.EndClassStatement.WithLeadingTrivia(trivia)); + } + return node.NormalizeWhitespace(); + } + return CommentMethod; + } + + public Func GetAddCommentsToMethodAction(string methodName, string comment, string dontUseCTAPrefix = null) + { + ClassBlockSyntax AddCommentsToMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + // if we have more than one method with same name return without making changes + var methodNode = GetMethodNode(node, methodName); + if (methodNode != null) + { + if (!string.IsNullOrWhiteSpace(comment)) + { + var methodActions = new MethodBlockActions(); + var addCommentActionFunc = methodActions.GetAddCommentAction(comment, dontUseCTAPrefix); + var newMethodNode = addCommentActionFunc(syntaxGenerator, methodNode); + node = node.ReplaceNode(methodNode, newMethodNode); + } + } + return node; + } + return AddCommentsToMethod; + } + + public Func GetAddExpressionToMethodAction(string methodName, string expression) + { + ClassBlockSyntax AddExpressionToMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + // if we have more than one method with same name return without making changes + var methodNode = GetMethodNode(node, methodName); + if (methodNode != null) + { + var methodActions = new MethodBlockActions(); + var addExpressionToMethodAction = methodActions.GetAddExpressionToMethodAction(expression); + var newMethodNode = addExpressionToMethodAction(syntaxGenerator, methodNode); + node = node.ReplaceNode(methodNode, newMethodNode); + } + return node; + } + return AddExpressionToMethod; + } + + public Func GetAddParametersToMethodAction(string methodName, string types, string identifiers) + { + ClassBlockSyntax AddParametersToMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + // if we have more than one method with same name return without making changes + var methodNode = GetMethodNode(node, methodName); + if (methodNode != null) + { + var methodActions = new MethodBlockActions(); + var addParametersToMethodAction = methodActions.GetAddParametersToMethodAction(types, identifiers); + var newMethodNode = addParametersToMethodAction(syntaxGenerator, methodNode); + node = node.ReplaceNode(methodNode, newMethodNode).NormalizeWhitespace(); + } + return node; + } + return AddParametersToMethod; + } + + public Func GetReplaceMvcControllerMethodsBodyAction(string expression) + { + throw new NotImplementedException(); + } + + public Func GetReplaceWebApiControllerMethodsBodyAction(string expression) + { + ClassBlockSyntax ReplaceMethodBodyFunc(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + return AddCommentToPublicMethods(node, expression); + } + return ReplaceMethodBodyFunc; + } + public Func GetReplaceCoreControllerMethodsBodyAction(string expression) + { + ClassBlockSyntax ReplaceMethodModifiers(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + { + return AddCommentToPublicMethods(node, expression); + } + return ReplaceMethodModifiers; + } + + private ClassBlockSyntax AddCommentToPublicMethods(ClassBlockSyntax node, string expression) + { + var comment = $"' Replace method body with {expression}"; + + var allMembers = node.Members.ToList(); + var allMethods = allMembers.OfType() + .Where(m => m.SubOrFunctionStatement.Modifiers.Any(mod => mod.IsKind(SyntaxKind.PublicKeyword))) + .Select(mb => GetMethodId(mb.SubOrFunctionStatement)).ToList(); + + foreach (var method in allMethods) + { + var currentMethodStatement = node.DescendantNodes().OfType() + .FirstOrDefault(m => GetMethodId(m) == method); + var originalMethod = currentMethodStatement; + if (currentMethodStatement != null) + { + var trivia = currentMethodStatement.GetLeadingTrivia(); + trivia = trivia.Add(SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, comment)); + currentMethodStatement = currentMethodStatement.WithLeadingTrivia(trivia).NormalizeWhitespace(); + node = node.ReplaceNode(originalMethod, currentMethodStatement); + } + } + return node; + } + + private string GetMethodId(MethodStatementSyntax method) + { + return $"{method.Identifier}{method.ParameterList}"; + } + + private MethodBlockSyntax GetMethodNode(ClassBlockSyntax node, string methodName) + { + var methodNodeList = node.DescendantNodes().OfType() + .Where(method => method.SubOrFunctionStatement.Identifier.Text == methodName); + if (methodNodeList != null && methodNodeList.Count() > 1) + { + return null; + } + return methodNodeList.FirstOrDefault(); + } + } +} diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs new file mode 100644 index 00000000..0e8c385b --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs @@ -0,0 +1,462 @@ +using System; +using CTA.Rules.Actions.VisualBasic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; +using System.Collections.Generic; +using System.Linq; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class ClassActionsTests + { + private SyntaxGenerator _syntaxGenerator; + private ClassActions _classActions; + private ClassBlockSyntax _node; + private MethodBlockSyntax _subNode; + private MethodBlockSyntax _functionNode; + + [SetUp] + public void SetUp() + { + + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _classActions = new ClassActions(); + SyntaxTree tree = VisualBasicSyntaxTree.ParseText(@$"Class MyClass +End Class"); + _node = tree.GetRoot() + .DescendantNodes() + .OfType() + .FirstOrDefault(); + + _subNode = CreateMethodNode("Invoke", + new List() + { + SyntaxFactory.ParseExecutableStatement(@"' Nothing to see here") + }, + true, + new List() + { + SyntaxKind.PublicKeyword + }); + + _functionNode = CreateMethodNode("TestFunction", + new List() + { + SyntaxFactory.ParseExecutableStatement(@"' Nothing to see here"), + SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression("\"hello world\"")) + }, false, + new List() + { + SyntaxKind.PublicKeyword + }, + "String"); + } + + [Test] + public void GetAddCommentAction_Adds_Leading_Comment_To_Class_Declaration() + { + const string commentToAdd = "This is a comment"; + var addCommentFunc = _classActions.GetAddCommentAction(commentToAdd); + var newNode = addCommentFunc(_syntaxGenerator, _node); + + var expectedResult = @$"' Added by CTA: {commentToAdd} +Class MyClass +End Class"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetChangeNameAction_Changes_Class_Name_To_Specified_Value() + { + const string newClassName = "NewClassName"; + var changeNameFunc = _classActions.GetChangeNameAction(newClassName); + var newNode = changeNameFunc(_syntaxGenerator, _node); + + var expectedResult = @$"Class {newClassName} +End Class"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetRenameClassAction_Changes_Class_Name_To_Specified_Value() + { + const string newClassName = "NewClassName"; + var changeNameFunc = _classActions.GetRenameClassAction(newClassName); + var newNode = changeNameFunc(_syntaxGenerator, _node); + + var expectedResult = @$"Class {newClassName} +End Class"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetRemoveAttributeAction_Removes_Specified_Attribute() + { + const string attributeToRemove = "Serializable"; + var nodeWithAttributes = (ClassBlockSyntax)_syntaxGenerator.AddAttributes(_node, + _syntaxGenerator.Attribute("Serializable"), + _syntaxGenerator.Attribute("SecurityCritical")); + + var removeAttributeFunc = _classActions.GetRemoveAttributeAction(attributeToRemove); + var newNode = removeAttributeFunc(_syntaxGenerator, nodeWithAttributes); + + var expectedResult = @$" +Class MyClass +End Class"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetAddAttributeAction_Adds_Attribute() + { + const string attributeToAdd = "Serializable"; + var addAttributeFunc = _classActions.GetAddAttributeAction(attributeToAdd); + var newNode = addAttributeFunc(_syntaxGenerator, _node); + var expectedResult = @$" +Class MyClass +End Class"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + [TestCase("\r\n Public Sub MySub(i as Integer) Console .WriteLine(i) End Sub ")] + [TestCase("\r\n Public Function MyFunction(i as Integer) Console .WriteLine(i) : Return i End Function ")] + public void GetAddMethodAction_Adds_Method(string expression) + { + var addMethodFunc = _classActions.GetAddMethodAction(expression); + + var newNode = addMethodFunc(_syntaxGenerator, _node); + + var expectedResult = @$"Class MyClass +{expression} +End Class"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetRemoveMethodAction_Removes_Specified_Method() + { + const string methodName = "MyMethod"; + var methodNode = SyntaxFactory.MethodStatement(SyntaxKind.SubStatement, + SyntaxFactory.Token(SyntaxKind.SubKeyword), methodName); + var nodeWithMethod = _node.AddMembers(methodNode); + + var removeMethodFunc = _classActions.GetRemoveMethodAction(methodName); + var newNode = removeMethodFunc(_syntaxGenerator, nodeWithMethod); + + var expectedResult = @$"Class MyClass +End Class"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void RemoveLastBaseClass() + { + var baseClassname = "ControllerBase"; + var addBaseClass = _classActions.GetAddBaseClassAction(baseClassname); + var removeBaseClassMethod = _classActions.GetRemoveBaseClassAction(baseClassname); + + var nodeWithClass = addBaseClass(_syntaxGenerator, _node); + nodeWithClass = removeBaseClassMethod(_syntaxGenerator, nodeWithClass); + + //Make sure the inheritance symbol is removed when last base class is removed: + StringAssert.DoesNotContain(":", nodeWithClass.ToFullString()); + } + + [Test] + public void ReplaceMethodModifiers() + { + const string methodName = "MyMethod"; + var methodNode = SyntaxFactory.MethodStatement(SyntaxKind.SubStatement, + SyntaxFactory.Token(SyntaxKind.SubKeyword), methodName); + var nodeWithMethod = _node.AddMembers(methodNode); + + var modifier = "private async extern"; + var replaceModifier = _classActions.GetReplaceMethodModifiersAction(methodName, modifier); + + var node = replaceModifier(_syntaxGenerator, nodeWithMethod); + + StringAssert.Contains(modifier, node.ToFullString()); + } + + [Test] + public void AddExpression() + { + string expression = "Dim _next As RequestDelegate"; + + var addBaseClass = _classActions.GetAddExpressionAction(expression); + + var nodeWithExpression = addBaseClass(_syntaxGenerator, _node); + + StringAssert.Contains(expression, nodeWithExpression.ToFullString()); + } + + [Test] + public void AppendConstructorExpression() + { + var constructorStatements = new SyntaxList(); + constructorStatements = constructorStatements.Add( + SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("_breadcrumb = breadcrumb"))); + var methodNode = SyntaxFactory.ConstructorBlock( + SyntaxFactory.SubNewStatement(), + constructorStatements, + SyntaxFactory.EndSubStatement()); + var nodeWithMethod = _node.AddMembers(methodNode); + string expression = "_next = [next]"; + + var addBaseClass = _classActions.GetAppendConstructorExpressionAction(expression); + + var nodeWithExpression = addBaseClass(_syntaxGenerator, nodeWithMethod); + + StringAssert.Contains(expression, nodeWithExpression.ToFullString()); + } + + [Test] + public void RemoveConstructorBaseInitializer() + { + var constructorStatements = new SyntaxList(); + constructorStatements = constructorStatements.Add( + SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("MyBase.New(next, testing)"))); + constructorStatements = constructorStatements.Add( + SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("_breadcrumb = breadcrumb"))); + + var methodNode = SyntaxFactory.ConstructorBlock( + SyntaxFactory.SubNewStatement(), + constructorStatements, + SyntaxFactory.EndSubStatement()); + + var nodeWithMethod = _node.AddMembers(methodNode); + string expression = "next"; + + var addBaseClass = _classActions.GetRemoveConstructorInitializerAction(expression); + + var nodeWithExpression = addBaseClass(_syntaxGenerator, nodeWithMethod); + + StringAssert.DoesNotContain(expression, nodeWithExpression.ToFullString()); + } + + [Test] + public void CreateConstructor() + { + string types = "RequestDelegate, string"; + string identifiers = "[next], value"; + + var createConstructorFunc = _classActions.GetCreateConstructorAction(types: types, identifiers: identifiers); + var nodeWithExpression = createConstructorFunc(_syntaxGenerator, _node); + + StringAssert.Contains(types.Split(',')[0], nodeWithExpression.ToFullString()); + StringAssert.Contains(identifiers.Split(',')[0], nodeWithExpression.ToFullString()); + } + + + [Test] + [TestCase(true)] + [TestCase(false)] + public void ChangeMethodName(bool isSubMethod) + { + string existingMethodName = "ProcessRequest"; + string newMethodName = "Invoke"; + + MethodBlockSyntax methodNode; + if (isSubMethod) + { + methodNode = SyntaxFactory.MethodBlock(SyntaxKind.SubBlock, + SyntaxFactory.MethodStatement(SyntaxKind.SubStatement, SyntaxFactory.Token(SyntaxKind.SubKeyword), + existingMethodName), + SyntaxFactory.EndSubStatement()); + } + else + { + methodNode = SyntaxFactory.MethodBlock(SyntaxKind.FunctionBlock, + SyntaxFactory.MethodStatement(SyntaxKind.FunctionStatement, + SyntaxFactory.Token(SyntaxKind.FunctionKeyword), + existingMethodName), + SyntaxFactory.EndFunctionStatement()); + } + + var nodeWithMethod = _node.AddMembers(methodNode); + + var changeMethodNameFunc = _classActions.GetChangeMethodNameAction(existingMethodName, newMethodName); + var nodeWithExpression = changeMethodNameFunc(_syntaxGenerator, nodeWithMethod); + + StringAssert.Contains(newMethodName, nodeWithExpression.ToFullString()); + } + + [Test] + public void RemoveMethodParameters() + { + var parameters = new List + { + SyntaxFactory.Parameter(SyntaxFactory.ModifiedIdentifier("context")) + .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName("HttpContext"))), + SyntaxFactory.Parameter(SyntaxFactory.ModifiedIdentifier("value")) + .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName("string"))) + }; + var methodName = "Invoke"; + var methodNode = _subNode.WithSubOrFunctionStatement( + _subNode.SubOrFunctionStatement.WithParameterList( + SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters)))); + var nodeWithMethod = _node.AddMembers(methodNode); + var removeMethodParametersFunc = _classActions.GetRemoveMethodParametersAction(methodName); + var nodeWithExpression = removeMethodParametersFunc(_syntaxGenerator, nodeWithMethod); + StringAssert.DoesNotContain("HttpContext", nodeWithExpression.ToFullString()); + } + + [Test] + public void ChangeMethodReturnTaskTypeVoid() + { + string methodName = "Invoke"; + var nodeWithMethod = _node.AddMembers(_subNode); + var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); + var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); + StringAssert.Contains("Task", nodeWithExpression.ToFullString()); + } + + [Test] + public void ChangeMethodReturnTaskTypeString() + { + string methodName = "TestFunction"; + var nodeWithMethod = _node.AddMembers(_functionNode); + var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); + var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); + StringAssert.Contains("Task(Of String)", nodeWithExpression.ToFullString()); + } + + [Test] + public void CommentMethod() + { + string methodName = "Invoke"; + var nodeWithMethod = _node.AddMembers(_subNode); + + var commentMethodeFunc = _classActions.GetCommentMethodAction(methodName); + var nodeWithExpression = commentMethodeFunc(_syntaxGenerator, nodeWithMethod); + + StringAssert.Contains("' Public Sub Invoke", nodeWithExpression.ToFullString()); + } + + [Test] + public void AddCommentsToMethod() + { + string methodName = "Invoke"; + string comment = "This method is deprecated"; + var nodeWithMethod = _node.AddMembers(_subNode); + + var addCommentsToMethodFunc = _classActions.GetAddCommentsToMethodAction(methodName, comment); + var nodeWithExpression = addCommentsToMethodFunc(_syntaxGenerator, nodeWithMethod); + + StringAssert.Contains("' Added by CTA: This method is deprecated", nodeWithExpression.ToFullString()); + } + + [Test] + public void AddExpressionToMethod() + { + string methodName = "TestFunction"; + string expression = "Await _next.Invoke(context)"; + var nodeWithMethod = _node.AddMembers(_functionNode); + var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); + var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); + + var addExpressionToMethodFunc = _classActions.GetAddExpressionToMethodAction(methodName, expression); + nodeWithExpression = addExpressionToMethodFunc(_syntaxGenerator, nodeWithExpression); + + StringAssert.Contains("Await _next.Invoke(context)", nodeWithExpression.ToFullString()); + } + + [Test] + public void AddParametersToMethod() + { + string methodName = "Invoke"; + string types = "HttpContext,String"; + string identifiers = "context,value"; + + var nodeWithMethod = _node.AddMembers(_subNode); + + var addParametersToMethodFunc = + _classActions.GetAddParametersToMethodAction(methodName, types, identifiers); + var nodeWithExpression = addParametersToMethodFunc(_syntaxGenerator, nodeWithMethod); + + var expectedString = @"Public Sub Invoke(context As HttpContext, value As String)"; + StringAssert.Contains(expectedString, nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("WebApiController")] + [TestCase("CoreController")] + public void ReplacePublicMethodsBody(string controller) + { + string newBody = "Return Content(MonolithService.CreateRequest())"; + var nodeWithMethods = _node.AddMembers(CreateMethodNode("SuperStringAsyncMethod", + new List() + { + SyntaxFactory.ParseExecutableStatement(@"Dim hello = ""hello world""") + }, + false, new List() { SyntaxKind.PublicKeyword, SyntaxKind.AsyncKeyword }, + "Task(Of String)")); + nodeWithMethods = nodeWithMethods.AddMembers(CreateMethodNode("SuperStringMethod", + new List() + { + SyntaxFactory.ParseExecutableStatement(@"Dim hello = ""hello world again?!""") + }, + false, new List() { SyntaxKind.PublicKeyword }, + "String")); + nodeWithMethods = nodeWithMethods.AddMembers(CreateMethodNode("SuperStringAsyncMethod", + new List() + { + SyntaxFactory.ParseExecutableStatement(@"Dim hello = ""not hello world!"""), + }, + false, new List() { SyntaxKind.PrivateKeyword}, + "String")); + + var replacePublicMethodsBodyFunc = controller == "WebApiController" + ? _classActions.GetReplaceWebApiControllerMethodsBodyAction(newBody) + : _classActions.GetReplaceCoreControllerMethodsBodyAction(newBody); + var newNode = replacePublicMethodsBodyFunc(_syntaxGenerator, nodeWithMethods.NormalizeWhitespace()); + + var publicMembers = newNode.Members.OfType().Where(m => + m.Modifiers.Any(modifier => modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PublicKeyword))); + var privateMembers = newNode.Members.OfType().Where(m => + m.Modifiers.Any(modifier => modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PrivateKeyword))); + + Assert.IsTrue(publicMembers.All(m => m.ToFullString().Contains($"' Replace method body with {newBody}"))); + Assert.IsTrue(privateMembers.All(m => !m.ToFullString().Contains($"' Replace method body with {newBody}"))); + } + + [Test] + public void ClassDeclarationEquals() + { + throw new NotImplementedException(); + // var classAction = new ClassDeclarationAction() { Key = "Test", Value = "Test2", ClassDeclarationActionFunc = _classActions.GetAddAttributeAction("Test") }; + // var cloned = classAction.Clone(); + // Assert.True(classAction.Equals(cloned)); + // + // cloned.Value = "DifferentValue"; + // Assert.False(classAction.Equals(cloned)); + } + + private MethodBlockSyntax CreateMethodNode(string identifier, + List bodyExpressions, + bool isSub, + List modifiers, + string returnType = "") + { + var body = new SyntaxList(bodyExpressions); + var modifiersSyntax = new SyntaxTokenList(modifiers.Select(m => SyntaxFactory.Token(m))); + var blockKind = isSub ? SyntaxKind.SubBlock: SyntaxKind.FunctionBlock; + var statementKind = isSub ? SyntaxKind.SubStatement : SyntaxKind.FunctionStatement; + var keyword = isSub? SyntaxKind.SubKeyword : SyntaxKind.FunctionKeyword; + var endStatement = isSub ? SyntaxFactory.EndSubStatement() : SyntaxFactory.EndFunctionStatement(); + + return SyntaxFactory.MethodBlock(blockKind, + SyntaxFactory.MethodStatement(statementKind, + SyntaxFactory.Token(keyword), identifier) + .WithModifiers(modifiersSyntax) + .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName(returnType))), + endStatement).WithStatements(body).NormalizeWhitespace(); + } + } +} \ No newline at end of file From ac5430c51ad25a4c527a9ced752f56976542c9de Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 25 May 2022 13:07:03 -0700 Subject: [PATCH 13/61] Add attribute and attribute list actions for vb --- .../VisualBasic/AttributeActions.cs | 24 ++++++++ .../VisualBasic/AttributeListActions.cs | 30 ++++++++++ .../VisualBasic/AttributeActionsTests.cs | 59 +++++++++++++++++++ .../VisualBasic/AttributeListActionsTests.cs | 58 ++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 src/CTA.Rules.Actions/VisualBasic/AttributeActions.cs create mode 100644 src/CTA.Rules.Actions/VisualBasic/AttributeListActions.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/AttributeActionsTests.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/AttributeListActionsTests.cs diff --git a/src/CTA.Rules.Actions/VisualBasic/AttributeActions.cs b/src/CTA.Rules.Actions/VisualBasic/AttributeActions.cs new file mode 100644 index 00000000..255e4630 --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/AttributeActions.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Actions.VisualBasic +{ + /// + /// List of actions that can run on attributes + /// + public class AttributeActions + { + public Func GetChangeAttributeAction(string attributeName) + { + AttributeSyntax ChangeAttribute(SyntaxGenerator syntaxGenerator, AttributeSyntax node) + { + node = node.WithName(SyntaxFactory.ParseName(attributeName)).NormalizeWhitespace(); + return node; + } + return ChangeAttribute; + } + } +} diff --git a/src/CTA.Rules.Actions/VisualBasic/AttributeListActions.cs b/src/CTA.Rules.Actions/VisualBasic/AttributeListActions.cs new file mode 100644 index 00000000..1a1f45d5 --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/AttributeListActions.cs @@ -0,0 +1,30 @@ +using System; +using CTA.Rules.Config; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Actions.VisualBasic +{ + /// + /// List of actions that can run on attribute lists + /// + public class AttributeListActions + { + public Func GetAddCommentAction(string comment) + { + AttributeListSyntax AddComment(SyntaxGenerator syntaxGenerator, AttributeListSyntax node) + { + //TODO IS there possibility of NPE , if there are no Trivia or it always returns a node... + var currentTrivia = node.GetLeadingTrivia(); + currentTrivia = currentTrivia.Insert(0, + SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, + string.Format(Constants.CommentFormat, comment))); + node = node.WithLeadingTrivia(currentTrivia).NormalizeWhitespace(); + return node; + } + return AddComment; + } + } +} diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeActionsTests.cs new file mode 100644 index 00000000..9f80e34b --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeActionsTests.cs @@ -0,0 +1,59 @@ +using System; +using CTA.Rules.Actions.VisualBasic; +using CTA.Rules.Models; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class AttributeActionsTests + { + private const string OriginalAttribute = "Serializable"; + private AttributeActions _attributeActions; + private SyntaxGenerator _syntaxGenerator; + private AttributeSyntax _node; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _attributeActions = new AttributeActions(); + _node = SyntaxFactory.Attribute(SyntaxFactory.IdentifierName(SyntaxFactory.ParseToken(OriginalAttribute))); + } + + [Test] + public void GetChangeAttributeAction_Changes_Attribute_To_Specified_Value() + { + const string newAttributeName = "NewAttribute"; + var changeAttributeFunc = _attributeActions.GetChangeAttributeAction(newAttributeName); + var newNode = changeAttributeFunc(_syntaxGenerator, _node); + + Assert.AreEqual(OriginalAttribute, _node.ToString()); + Assert.AreEqual(newAttributeName, newNode.ToString()); + } + + [Test] + public void AttributeActionComparison() + { + throw new NotImplementedException(); + // + // var attributeAction = new AttributeAction() + // { + // Key = "Test", + // Value = "Test2", + // AttributeActionFunc = _attributeActions.GetChangeAttributeAction("NewAttribute") + // }; + // + // var cloned = attributeAction.Clone(); + // + // Assert.True(attributeAction.Equals(cloned)); + // cloned.Value = "DifferentValue"; + // Assert.False(attributeAction.Equals(cloned)); + } + } +} \ No newline at end of file diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeListActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeListActionsTests.cs new file mode 100644 index 00000000..137652ea --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeListActionsTests.cs @@ -0,0 +1,58 @@ +using System; +using CTA.Rules.Actions.VisualBasic; +using CTA.Rules.Models; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class AttributeListActionsTests + { + private AttributeListActions _attributeListActions; + private SyntaxGenerator _syntaxGenerator; + private AttributeListSyntax _node; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _attributeListActions = new AttributeListActions(); + var seperatedList = SyntaxFactory.SeparatedList(); + seperatedList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("Test"))); + _node = SyntaxFactory.AttributeList(seperatedList); + } + + [Test] + public void AttributeListAddComment() + { + const string comment = "This is a comment"; + var changeAttributeFunc = _attributeListActions.GetAddCommentAction(comment); + var newNode = changeAttributeFunc(_syntaxGenerator, _node); + + StringAssert.Contains(comment, newNode.ToFullString()); + } + + [Test] + public void AttributeListActionComparison() + { + throw new NotImplementedException(); + // var attributeAction = new AttributeAction() + // { + // Key = "Test", + // Value = "Test2", + // AttributeListActionFunc = _attributeListActions.GetAddCommentAction("NewAttribute") + // }; + // + // var cloned = attributeAction.Clone(); + // + // Assert.True(attributeAction.Equals(cloned)); + // cloned.Value = "DifferentValue"; + // Assert.False(attributeAction.Equals(cloned)); + } + } +} \ No newline at end of file From 696e11e603e4bc8fe8cc22c4186c2350a5d93575 Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 25 May 2022 15:19:39 -0700 Subject: [PATCH 14/61] Fix missing CTA tag on comment --- src/CTA.Rules.Actions/VisualBasic/ClassActions.cs | 2 +- tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs b/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs index e00d2a21..1d720594 100644 --- a/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs +++ b/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs @@ -481,7 +481,7 @@ ClassBlockSyntax ReplaceMethodModifiers(SyntaxGenerator syntaxGenerator, ClassBl private ClassBlockSyntax AddCommentToPublicMethods(ClassBlockSyntax node, string expression) { - var comment = $"' Replace method body with {expression}"; + var comment = string.Format(Constants.VbCommentFormat, $"Replace method body with {expression}"); var allMembers = node.Members.ToList(); var allMethods = allMembers.OfType() diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs index 0e8c385b..5d7baacb 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs @@ -422,8 +422,8 @@ public void ReplacePublicMethodsBody(string controller) var privateMembers = newNode.Members.OfType().Where(m => m.Modifiers.Any(modifier => modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PrivateKeyword))); - Assert.IsTrue(publicMembers.All(m => m.ToFullString().Contains($"' Replace method body with {newBody}"))); - Assert.IsTrue(privateMembers.All(m => !m.ToFullString().Contains($"' Replace method body with {newBody}"))); + Assert.IsTrue(publicMembers.All(m => m.ToFullString().Contains($"'Added by CTA: Replace method body with {newBody}"))); + Assert.IsTrue(privateMembers.All(m => !m.ToFullString().Contains($"'Added by CTA: Replace method body with {newBody}"))); } [Test] From c5e4b82ebd8a483306aba7643ed49e8c9bd55125 Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 25 May 2022 15:19:52 -0700 Subject: [PATCH 15/61] Add element access actions for vb --- .../VisualBasic/ElementAccessActions.cs | 37 ++++++++++ .../VisualBasic/ElementAccessActionsTests.cs | 67 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 src/CTA.Rules.Actions/VisualBasic/ElementAccessActions.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/ElementAccessActionsTests.cs diff --git a/src/CTA.Rules.Actions/VisualBasic/ElementAccessActions.cs b/src/CTA.Rules.Actions/VisualBasic/ElementAccessActions.cs new file mode 100644 index 00000000..dd75d01d --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/ElementAccessActions.cs @@ -0,0 +1,37 @@ +using System; +using CTA.Rules.Config; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Update.VisualBasic +{ + /// + /// List of actions that can run on Element Accesses + /// + public class ElementAccessActions + { + public Func GetAddCommentAction(string comment) + { + MemberAccessExpressionSyntax AddComment(SyntaxGenerator syntaxGenerator, MemberAccessExpressionSyntax node) + { + SyntaxTriviaList currentTrivia = node.GetLeadingTrivia(); + currentTrivia = currentTrivia.Insert(0, SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, string.Format(Constants.VbCommentFormat, comment))); + node = node.WithLeadingTrivia(currentTrivia).NormalizeWhitespace(); + return node; + } + return AddComment; + } + public Func GetReplaceElementAccessAction(string newExpression) + { + // todo: for VB rules that invoke this action probably need to be converted to invocation expressions because + MemberAccessExpressionSyntax ReplaceElement(SyntaxGenerator syntaxGenerator, MemberAccessExpressionSyntax node) + { + var addCommentFunc = GetAddCommentAction($"Replace with {newExpression}"); + return addCommentFunc(syntaxGenerator, node); + } + return ReplaceElement; + } + } +} diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ElementAccessActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ElementAccessActionsTests.cs new file mode 100644 index 00000000..4780c716 --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ElementAccessActionsTests.cs @@ -0,0 +1,67 @@ +using System; +using CTA.Rules.Models; +using CTA.Rules.Update.VisualBasic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class ElementAccessActionsTests + { + private ElementAccessActions _elementAccessActions; + private SyntaxGenerator _syntaxGenerator; + private MemberAccessExpressionSyntax _node; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _elementAccessActions = new ElementAccessActions(); + _node = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.ParseExpression("Expression"), SyntaxFactory.Token(SyntaxKind.DotToken), + (SimpleNameSyntax)SyntaxFactory.ParseName("ElementAccess")); + } + + [Test] + public void ElementAccessAddComment() + { + const string comment = "This is a comment"; + var addCommentFunc = _elementAccessActions.GetAddCommentAction(comment); + var newNode = addCommentFunc(_syntaxGenerator, _node); + StringAssert.Contains(comment, newNode.ToFullString()); + } + + [Test] + public void ReplaceElementAccess() + { + const string expression = "ConfigurationManager.Configuration.GetSection(\"ConnectionStrings\")"; + var replaceElementAccessFunc = _elementAccessActions.GetReplaceElementAccessAction(expression); + var newNode = replaceElementAccessFunc(_syntaxGenerator, _node); + StringAssert.Contains($"' Added by CTA: Replace with {expression}", newNode.ToFullString()); + } + + [Test] + public void ElementAccessActionComparison() + { + throw new NotImplementedException(); + // var elementAccessAction = new ElementAccessAction() + // { + // Key = "Test", + // Value = "Test2", + // ElementAccessExpressionActionFunc = _elementAccessActions.GetAddCommentAction("Test") + // + // }; + // + // var cloned = elementAccessAction.Clone(); + // + // Assert.True(elementAccessAction.Equals(cloned)); + // cloned.Value = "DifferentValue"; + // Assert.False(elementAccessAction.Equals(cloned)); + } + } +} \ No newline at end of file From 491ce669aed65945c002d9fb49b51d4d2eb75bb7 Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 25 May 2022 17:10:18 -0700 Subject: [PATCH 16/61] Add expression actions for vb --- .../VisualBasic/ExpressionActions.cs | 41 +++++++++ .../VisualBasic/ExpressionActionsTests.cs | 90 +++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/CTA.Rules.Actions/VisualBasic/ExpressionActions.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/ExpressionActionsTests.cs diff --git a/src/CTA.Rules.Actions/VisualBasic/ExpressionActions.cs b/src/CTA.Rules.Actions/VisualBasic/ExpressionActions.cs new file mode 100644 index 00000000..b4902bdf --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/ExpressionActions.cs @@ -0,0 +1,41 @@ +using System; +using System.Linq; +using CTA.Rules.Config; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Actions.VisualBasic +{ + public class ExpressionActions + { + /// + /// This Method adds an await operator to the invocation expression. For example, Math.Round(5.5) invocation expression would return await Math.Abs(5.5). + /// + /// + public Func GetAddAwaitOperatorAction(string _) + { + SyntaxNode AddAwaitOperator(SyntaxGenerator syntaxGenerator, SyntaxNode node) + { + var newNode = SyntaxFactory.AwaitExpression( + SyntaxFactory.ParseExpression(node.WithoutTrivia().NormalizeWhitespace().ToFullString())); + newNode = newNode.WithTriviaFrom(node).NormalizeWhitespace(); + return SyntaxFactory.ExpressionStatement(newNode); + } + return AddAwaitOperator; + } + + public Func GetAddCommentAction(string comment) + { + SyntaxNode AddComment(SyntaxGenerator syntaxGenerator, SyntaxNode node) + { + var currentTrivia = node.GetLeadingTrivia(); + currentTrivia = currentTrivia.Add(SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, + string.Format(Constants.VbCommentFormat, comment))); + node = node.WithLeadingTrivia(currentTrivia).NormalizeWhitespace(); + return node; + } + return AddComment; + } + } +} diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ExpressionActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ExpressionActionsTests.cs new file mode 100644 index 00000000..cb6abb2a --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ExpressionActionsTests.cs @@ -0,0 +1,90 @@ +using CTA.Rules.Actions.VisualBasic; +using CTA.Rules.Models; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class ExpressionActionsTests + { + private SyntaxGenerator _syntaxGenerator; + private ExpressionActions _expressionActions; + private ExpressionStatementSyntax _node; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _expressionActions = new ExpressionActions(); + _node = SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("Math.Abs(-1)") + .WithLeadingTrivia(SyntaxFactory.CommentTrivia("' Super Comment"))); + } + + [Test] + public void GetAddAwaitOperatorAction() + { + var addAwaitFunc = + _expressionActions.GetAddAwaitOperatorAction(""); + var newNode = addAwaitFunc(_syntaxGenerator, _node); + + var expectedResult = "' Super Comment\r\nAwait Math.Abs(-1)"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + + [Test] + public void ExpressionActionAddComment() + { + var comment = "Super comment"; + var expressionAction = SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("var t = 1+5")); + + var addCommentFunc = _expressionActions.GetAddCommentAction(comment); + var newNode = addCommentFunc(_syntaxGenerator, expressionAction); + + var expectedResult = @"' Added by CTA: Super comment +var t = 1 + 5"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void ObjectCreationAddComment() + { + var comment = "Super comment"; + var objectNode = _syntaxGenerator.ObjectCreationExpression(SyntaxFactory.ParseTypeName("StringBuilder")) + .NormalizeWhitespace() as ObjectCreationExpressionSyntax; + + objectNode = + objectNode.AddArgumentListArguments( + SyntaxFactory.SimpleArgument(SyntaxFactory.ParseExpression(@"""SomeText"""))); + + var addCommentFunc = _expressionActions.GetAddCommentAction(comment); + var newNode = addCommentFunc(_syntaxGenerator, objectNode); + + var expectedResult = @"' Added by CTA: Super comment +New StringBuilder(""SomeText"")"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void InvocationExpressionAddComment() + { + var comment = "Super comment"; + var invocationNode = + SyntaxFactory.ParseExpression("Math.Abs(-1)") + .WithLeadingTrivia(SyntaxFactory.CommentTrivia("' Comment")) as InvocationExpressionSyntax; + + var addCommentFunc = _expressionActions.GetAddCommentAction(comment); + var newNode = addCommentFunc(_syntaxGenerator, invocationNode); + + var expectedResult = @"' Comment +' Added by CTA: Super comment +Math.Abs(-1)"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + } +} \ No newline at end of file From 8337de57713ef1b7c0b67ee562424fa05c52ee9c Mon Sep 17 00:00:00 2001 From: longachr Date: Thu, 26 May 2022 09:42:52 -0700 Subject: [PATCH 17/61] Add interface actions for vb --- .../VisualBasic/InterfaceActions.cs | 120 ++++++++++++++++++ .../VisualBasic/InterfaceActionsTests.cs | 105 +++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 src/CTA.Rules.Actions/VisualBasic/InterfaceActions.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/InterfaceActionsTests.cs diff --git a/src/CTA.Rules.Actions/VisualBasic/InterfaceActions.cs b/src/CTA.Rules.Actions/VisualBasic/InterfaceActions.cs new file mode 100644 index 00000000..406d0d6a --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/InterfaceActions.cs @@ -0,0 +1,120 @@ +using System; +using System.Linq; +using CTA.Rules.Config; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Actions.VisualBasic +{ + /// + /// List of actions that can run on Interface Declarations + /// + public class InterfaceActions + { + public Func GetChangeNameAction(string newName) + { + InterfaceBlockSyntax ChangeName(SyntaxGenerator syntaxGenerator, InterfaceBlockSyntax node) + { + node = node.WithInterfaceStatement( + node.InterfaceStatement.WithIdentifier(SyntaxFactory.Identifier(newName))); + return node.NormalizeWhitespace(); + } + return ChangeName; + } + public Func GetRemoveAttributeAction(string attributeName) + { + InterfaceBlockSyntax RemoveAttribute(SyntaxGenerator syntaxGenerator, InterfaceBlockSyntax node) + { + var attributeLists = node.InterfaceStatement.AttributeLists; + AttributeListSyntax attributeToRemove = null; + + foreach (var attributeList in attributeLists) + { + foreach (var attribute in attributeList.Attributes) + { + if (attribute.Name.ToString() == attributeName) + { + attributeToRemove = attributeList; + break; + } + } + } + + if (attributeToRemove != null) + { + attributeLists = attributeLists.Remove(attributeToRemove); + } + + var newStatement = node.InterfaceStatement.WithAttributeLists(attributeLists); + return node.WithInterfaceStatement(newStatement).NormalizeWhitespace(); + } + + return RemoveAttribute; + } + public Func GetAddAttributeAction(string attribute) + { + InterfaceBlockSyntax AddAttribute(SyntaxGenerator syntaxGenerator, InterfaceBlockSyntax node) + { + var attributeLists = node.InterfaceStatement.AttributeLists; + attributeLists = attributeLists.Add( + SyntaxFactory.AttributeList( + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.Attribute(SyntaxFactory.ParseName(attribute))))); + + var newStatement = node.InterfaceStatement.WithAttributeLists(attributeLists).NormalizeWhitespace(); + return node.WithInterfaceStatement(newStatement).NormalizeWhitespace(); + } + return AddAttribute; + } + public Func GetAddCommentAction(string comment) + { + InterfaceBlockSyntax AddComment(SyntaxGenerator syntaxGenerator, InterfaceBlockSyntax node) + { + var currentTrivia = node.GetLeadingTrivia(); + //TODO see if this will lead NPE + currentTrivia = currentTrivia.Add(SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, + string.Format(Constants.VbCommentFormat, comment))); + node = node.WithLeadingTrivia(currentTrivia).NormalizeWhitespace(); + return node; + } + return AddComment; + } + public Func GetAddMethodAction(string expression) + { + InterfaceBlockSyntax AddMethod(SyntaxGenerator syntaxGenerator, InterfaceBlockSyntax node) + { + var allMembers = node.Members; + var methodStatement = ParseMethodStatement(expression); + allMembers = allMembers.Add(methodStatement); + node = node.WithMembers(allMembers).NormalizeWhitespace(); + return node; + } + return AddMethod; + } + public Func GetRemoveMethodAction(string methodName) + { + //TODO what if there is operator overloading + InterfaceBlockSyntax AddMethod(SyntaxGenerator syntaxGenerator, InterfaceBlockSyntax node) + { + var allMethods = node.Members.OfType().ToList(); + var removeMethod = + allMethods.FirstOrDefault(m => m.Identifier.ToString() == methodName); + if (removeMethod != null) + { + node = node.RemoveNode(removeMethod, SyntaxRemoveOptions.KeepNoTrivia).NormalizeWhitespace(); + } + + return node; + } + return AddMethod; + } + + private MethodStatementSyntax ParseMethodStatement(string expression) + { + var tree = SyntaxFactory.ParseSyntaxTree(expression); + return tree.GetRoot().DescendantNodes().OfType().FirstOrDefault(); + } + } +} diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/InterfaceActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/InterfaceActionsTests.cs new file mode 100644 index 00000000..2efe625f --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/InterfaceActionsTests.cs @@ -0,0 +1,105 @@ +using System; +using CTA.Rules.Actions.VisualBasic; +using CTA.Rules.Models; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class InterfaceActionsTests + { + private SyntaxGenerator _syntaxGenerator; + private InterfaceActions _interfaceActions; + private InterfaceBlockSyntax _node; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _interfaceActions = new InterfaceActions(); + _node = _syntaxGenerator.InterfaceDeclaration("ISomeInterface") + .NormalizeWhitespace() as InterfaceBlockSyntax; + } + + [Test] + public void ChangeName() + { + string newName = "INewInterface"; + var changeNameFunc = _interfaceActions.GetChangeNameAction(newName); + var newNode = changeNameFunc(_syntaxGenerator, _node); + StringAssert.Contains(newName, newNode.ToFullString()); + } + + [Test] + public void GetAddRemoveAttributeAction() + { + var addAttributeFunc = _interfaceActions.GetAddAttributeAction("SomeAttribute"); + var nodeWithAttribute = addAttributeFunc(_syntaxGenerator, _node); + + StringAssert.Contains("SomeAttribute", nodeWithAttribute.ToFullString()); + + var removeAttributeFunc = + _interfaceActions.GetRemoveAttributeAction("SomeAttribute"); + var newNode = removeAttributeFunc(_syntaxGenerator, nodeWithAttribute); + + var expectedResult = _node.ToFullString(); + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void GetAddCommentAction_Appends_Comment_To_Interface_Declaration() + { + const string commentToAdd = "This is a comment"; + var addCommentFunc = _interfaceActions.GetAddCommentAction(commentToAdd); + var newNode = addCommentFunc(_syntaxGenerator, _node); + + var expectedResult = @$"' Added by CTA: {commentToAdd} +Interface ISomeInterface +End Interface"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + public void AddAndRemoveMethod() + { + string newMethod = @"Public Function NewMethod As String"; + var addMethodFunc = _interfaceActions.GetAddMethodAction(newMethod); + var newNode = addMethodFunc(_syntaxGenerator, _node); + + var addSubFunc = _interfaceActions.GetAddMethodAction("Public Sub NewSub As Integer"); + + Assert.IsTrue(newNode.Members.Count == 1); + Assert.IsTrue(newNode.ToFullString().Contains("NewMethod")); + + newNode = addSubFunc(_syntaxGenerator, newNode); + Assert.IsTrue(newNode.Members.Count == 2); + + var removeMethodFunc = _interfaceActions.GetRemoveMethodAction("NewMethod"); + newNode = removeMethodFunc(_syntaxGenerator, newNode); + + Assert.IsTrue(newNode.Members.Count == 1); + Assert.IsTrue(!newNode.ToFullString().Contains("NewMethod")); + Assert.IsTrue(newNode.ToFullString().Contains("NewSub")); + } + + [Test] + public void InterfaceDeclarationEquals() + { + throw new NotImplementedException(); + // var interfaceAction = new InterfaceDeclarationAction + // { + // Key = "Test", Value = "Test2", + // InterfaceDeclarationActionFunc = _interfaceActions.GetAddAttributeAction("Test") + // }; + // var cloned = interfaceAction.Clone(); + // Assert.True(interfaceAction.Equals(cloned)); + // + // cloned.Value = "DifferentValue"; + // Assert.False(interfaceAction.Equals(cloned)); + } + } +} \ No newline at end of file From 6352a710891b0ff10b04d741142bfa521d55bcaa Mon Sep 17 00:00:00 2001 From: longachr Date: Thu, 26 May 2022 10:58:22 -0700 Subject: [PATCH 18/61] Add vb handling to member access expression actions --- .../{Csharp => }/MemberAccessActions.cs | 21 ++++++++++++-- .../Actions/MemberAccessActionsTests.cs | 28 +++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) rename src/CTA.Rules.Actions/{Csharp => }/MemberAccessActions.cs (55%) diff --git a/src/CTA.Rules.Actions/Csharp/MemberAccessActions.cs b/src/CTA.Rules.Actions/MemberAccessActions.cs similarity index 55% rename from src/CTA.Rules.Actions/Csharp/MemberAccessActions.cs rename to src/CTA.Rules.Actions/MemberAccessActions.cs index ea981c03..5a81e24c 100644 --- a/src/CTA.Rules.Actions/Csharp/MemberAccessActions.cs +++ b/src/CTA.Rules.Actions/MemberAccessActions.cs @@ -4,9 +4,8 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -using System.Linq; -namespace CTA.Rules.Update.Csharp +namespace CTA.Rules.Update { /// /// List of actions that can run on Member Accesses @@ -18,7 +17,19 @@ public Func GetAddCommentAction(string SyntaxNode AddComment(SyntaxGenerator syntaxGenerator, SyntaxNode node) { SyntaxTriviaList currentTrivia = node.GetLeadingTrivia(); - currentTrivia = currentTrivia.Insert(0, SyntaxFactory.SyntaxTrivia(SyntaxKind.MultiLineCommentTrivia, string.Format(Constants.CommentFormat, comment))); + if (node is Microsoft.CodeAnalysis.VisualBasic.Syntax.MemberAccessExpressionSyntax) + { + currentTrivia = currentTrivia.Insert(0, + Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.SyntaxTrivia( + Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.CommentTrivia, + string.Format(Constants.VbCommentFormat, comment))); + } + else + { + currentTrivia = currentTrivia.Insert(0, + SyntaxFactory.SyntaxTrivia(SyntaxKind.MultiLineCommentTrivia, + string.Format(Constants.CommentFormat, comment))); + } node = node.WithLeadingTrivia(currentTrivia).NormalizeWhitespace(); return node; } @@ -33,6 +44,10 @@ static SyntaxNode RemoveMemberAccess(SyntaxGenerator syntaxGenerator, SyntaxNode { return (node as MemberAccessExpressionSyntax).Expression; } + if (node is Microsoft.CodeAnalysis.VisualBasic.Syntax.MemberAccessExpressionSyntax) + { + return (node as Microsoft.CodeAnalysis.VisualBasic.Syntax.MemberAccessExpressionSyntax).Expression; + } return node; } return RemoveMemberAccess; diff --git a/tst/CTA.Rules.Test/Actions/MemberAccessActionsTests.cs b/tst/CTA.Rules.Test/Actions/MemberAccessActionsTests.cs index a80be9d0..a4eb1048 100644 --- a/tst/CTA.Rules.Test/Actions/MemberAccessActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/MemberAccessActionsTests.cs @@ -1,10 +1,13 @@ using CTA.Rules.Models; -using CTA.Rules.Update.Csharp; +using CTA.Rules.Update; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using NUnit.Framework; +using SimpleNameSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.SimpleNameSyntax; +using VbMemberAccessExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.MemberAccessExpressionSyntax; +using VbSyntaxFactory = Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory; namespace CTA.Rules.Test.Actions { @@ -14,6 +17,9 @@ public class MemberAccessActionsTests private SyntaxGenerator _syntaxGenerator; private MemberAccessExpressionSyntax _node; + private SyntaxGenerator _vbGenerator; + private VbMemberAccessExpressionSyntax _vbNode; + [SetUp] public void SetUp() { @@ -21,7 +27,14 @@ public void SetUp() var language = LanguageNames.CSharp; _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); _memberAccessActions = new MemberAccessActions(); - _node = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName("value")); + _node = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName("value")); + _vbGenerator = SyntaxGenerator.GetGenerator(workspace, LanguageNames.VisualBasic); + _vbNode = VbSyntaxFactory.MemberAccessExpression( + Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.SimpleMemberAccessExpression, + VbSyntaxFactory.ParseExpression("Math.Abs(-1)"), + VbSyntaxFactory.Token(Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.DotToken), + (SimpleNameSyntax)VbSyntaxFactory.ParseName("Value")); } [Test] @@ -50,5 +63,16 @@ public void MemberAccessActionComparison() cloned.Value = "DifferentValue"; Assert.False(memberAccessAction.Equals(cloned)); } + + [Test] + public void RemoveMemberAccess() + { + var removeMemberAccessFunc = _memberAccessActions.GetRemoveMemberAccessAction(""); + var newCsharpNode = removeMemberAccessFunc(_syntaxGenerator, _node); + var newVbNode = removeMemberAccessFunc(_vbGenerator, _vbNode); + + Assert.AreEqual("this", newCsharpNode.ToFullString()); + Assert.AreEqual("Math.Abs(-1)", newVbNode.ToFullString()); + } } } \ No newline at end of file From 2aa09d0db24a2c5b97560abe0fcf7715221e00a1 Mon Sep 17 00:00:00 2001 From: longachr Date: Thu, 26 May 2022 15:40:32 -0700 Subject: [PATCH 19/61] Update class actions to TypeBlockSyntax for modules --- .../VisualBasic/ClassActions.cs | 145 +-- src/CTA.Rules.Config/Constants.cs | 13 + .../Actions/VisualBasic/ClassActionsTests.cs | 969 +++++++++--------- 3 files changed, 596 insertions(+), 531 deletions(-) diff --git a/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs b/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs index 1d720594..f04ff862 100644 --- a/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs +++ b/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs @@ -14,9 +14,9 @@ namespace CTA.Rules.Actions.VisualBasic /// public class ClassActions { - public Func GetRemoveBaseClassAction(string baseClass) + public Func GetRemoveBaseClassAction(string baseClass) { - ClassBlockSyntax RemoveBaseClass(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax RemoveBaseClass(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { var currentBaseTypes = node.Inherits.FirstOrDefault()?.Types ?? new SeparatedSyntaxList(); SeparatedSyntaxList newBaseTypes = new SeparatedSyntaxList(); @@ -40,13 +40,13 @@ ClassBlockSyntax RemoveBaseClass(SyntaxGenerator syntaxGenerator, ClassBlockSynt return RemoveBaseClass; } - public Func GetAddBaseClassAction(string baseClass) + public Func GetAddBaseClassAction(string baseClass) { - ClassBlockSyntax AddBaseClass(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax AddBaseClass(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { if (syntaxGenerator != null) { - node = (ClassBlockSyntax)syntaxGenerator.AddBaseType(node, SyntaxFactory.ParseName(baseClass)); + node = (TypeBlockSyntax)syntaxGenerator.AddBaseType(node, SyntaxFactory.ParseName(baseClass)); } else { @@ -58,22 +58,22 @@ ClassBlockSyntax AddBaseClass(SyntaxGenerator syntaxGenerator, ClassBlockSyntax return AddBaseClass; } - public Func GetChangeNameAction(string className) + public Func GetChangeNameAction(string className) { - ClassBlockSyntax ChangeName(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax ChangeName(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { - node = node.WithClassStatement(SyntaxFactory.ClassStatement(SyntaxFactory.Identifier(className))) + node = node.WithBlockStatement(node.BlockStatement.WithIdentifier(SyntaxFactory.Identifier(className))) .NormalizeWhitespace(); return node; } return ChangeName; } - public Func GetRemoveAttributeAction(string attributeName) + public Func GetRemoveAttributeAction(string attributeName) { - ClassBlockSyntax RemoveAttribute(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax RemoveAttribute(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { - var attributeLists = node.ClassStatement.AttributeLists; + var attributeLists = node.BlockStatement.AttributeLists; AttributeListSyntax attributeToRemove = null; foreach (var attributeList in attributeLists) @@ -93,32 +93,32 @@ ClassBlockSyntax RemoveAttribute(SyntaxGenerator syntaxGenerator, ClassBlockSynt attributeLists = attributeLists.Remove(attributeToRemove); } - node = node.WithClassStatement(node.ClassStatement.WithAttributeLists(attributeLists)) + node = node.WithBlockStatement(node.BlockStatement.WithAttributeLists(attributeLists)) .NormalizeWhitespace(); return node; } return RemoveAttribute; } - public Func GetAddAttributeAction(string attribute) + public Func GetAddAttributeAction(string attribute) { - ClassBlockSyntax AddAttribute(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax AddAttribute(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { - var attributeLists = node.ClassStatement.AttributeLists; + var attributeLists = node.BlockStatement.AttributeLists; attributeLists = attributeLists.Add( SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Attribute(SyntaxFactory.ParseName(attribute))))); - node = node.WithClassStatement(node.ClassStatement.WithAttributeLists(attributeLists)) + node = node.WithBlockStatement(node.BlockStatement.WithAttributeLists(attributeLists)) .NormalizeWhitespace(); return node; } return AddAttribute; } - public Func GetAddCommentAction(string comment, string dontUseCTAPrefix = null) + public Func GetAddCommentAction(string comment, string dontUseCTAPrefix = null) { - ClassBlockSyntax AddComment(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax AddComment(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { SyntaxTriviaList currentTrivia = node.GetLeadingTrivia(); var commentFormat = dontUseCTAPrefix != null ? Constants.VbCommentFormatBlank : Constants.VbCommentFormat; @@ -128,30 +128,24 @@ ClassBlockSyntax AddComment(SyntaxGenerator syntaxGenerator, ClassBlockSyntax no } return AddComment; } - public Func GetAddMethodAction(string expression) + public Func GetAddMethodAction(string expression) { - ClassBlockSyntax AddMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax AddMethod(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { - var methodSyntax = SyntaxFactory.ParseSyntaxTree(expression).GetRoot().DescendantNodes() - .OfType().FirstOrDefault(); var methodBlockSyntax = SyntaxFactory.ParseSyntaxTree(expression).GetRoot().DescendantNodes() .OfType().FirstOrDefault(); if (methodBlockSyntax != null) { - node = node.AddMembers(methodBlockSyntax.SubOrFunctionStatement); - foreach (var statement in methodBlockSyntax.Statements) - { - node = node.AddMembers(statement); - } + node = node.AddMembers(methodBlockSyntax); } return node.NormalizeWhitespace(); } return AddMethod; } - public Func GetRemoveMethodAction(string methodName) + public Func GetRemoveMethodAction(string methodName) { //TODO what if there is operator overloading - ClassBlockSyntax RemoveMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax RemoveMethod(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { var allMembers = node.Members.ToList(); var allMethods = allMembers.OfType(); @@ -168,30 +162,41 @@ ClassBlockSyntax RemoveMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax } return RemoveMethod; } - public Func GetRenameClassAction(string newClassName) + public Func GetRenameClassAction(string newClassName) { - ClassBlockSyntax RenameClass(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax RenameClass(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { - node = node.WithClassStatement(node.ClassStatement.WithIdentifier(SyntaxFactory.Identifier(newClassName))).NormalizeWhitespace(); + node = node.WithBlockStatement(node.BlockStatement.WithIdentifier(SyntaxFactory.Identifier(newClassName))).NormalizeWhitespace(); return node; } return RenameClass; } - public Func GetReplaceMethodModifiersAction(string methodName, string modifiers) + public Func GetReplaceMethodModifiersAction(string methodName, string modifiers) { - ClassBlockSyntax ReplaceMethodModifiers(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax ReplaceMethodModifiers(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { - var allMembers = node.Members.ToList(); - var allMethods = allMembers.OfType(); + var allMethods = node.Members.OfType(); if (allMethods.Any()) { var replaceMethod = allMethods.FirstOrDefault(m => m.Identifier.ToString() == methodName); if (replaceMethod != null) { - var allModifiersAreValid = modifiers.Split(new char[] { ' ', ',' }).All(m => Constants.SupportedMethodModifiers.Contains(m)); - if (allModifiersAreValid) + var allModifiers = modifiers.Split(new char[] { ' ', ',' }); + if (allModifiers.All(m => Constants.SupportedVbMethodModifiers.Contains(m))) { - SyntaxTokenList tokenList = new SyntaxTokenList(SyntaxFactory.ParseTokens(modifiers)); + SyntaxTokenList tokenList = new SyntaxTokenList(); + foreach (string m in allModifiers) + { + if (m == "Async") + { + // for some reason syntax factory can't parse that async is a keyword + tokenList = tokenList.Add(SyntaxFactory.Token(SyntaxKind.AsyncKeyword)); + } + else + { + tokenList = tokenList.Add(SyntaxFactory.ParseToken(m)); + } + } var newMethod = replaceMethod.WithModifiers(tokenList); node = node.WithMembers(node.Members.Replace(replaceMethod, newMethod)).NormalizeWhitespace(); @@ -203,9 +208,9 @@ ClassBlockSyntax ReplaceMethodModifiers(SyntaxGenerator syntaxGenerator, ClassBl } return ReplaceMethodModifiers; } - public Func GetAddExpressionAction(string expression) + public Func GetAddExpressionAction(string expression) { - ClassBlockSyntax AddExpression(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax AddExpression(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { var parsedExpression = SyntaxFactory.ParseExecutableStatement(expression); if (!parsedExpression.FullSpan.IsEmpty) @@ -218,9 +223,9 @@ ClassBlockSyntax AddExpression(SyntaxGenerator syntaxGenerator, ClassBlockSyntax } return AddExpression; } - public Func GetRemoveConstructorInitializerAction(string initializerArgument) + public Func GetRemoveConstructorInitializerAction(string initializerArgument) { - ClassBlockSyntax RemoveConstructorInitializer(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax RemoveConstructorInitializer(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { var constructor = node.ChildNodes().FirstOrDefault(c => c.IsKind(SyntaxKind.ConstructorBlock)); if (constructor != null) @@ -257,9 +262,9 @@ ClassBlockSyntax RemoveConstructorInitializer(SyntaxGenerator syntaxGenerator, C return RemoveConstructorInitializer; } - public Func GetAppendConstructorExpressionAction(string expression) + public Func GetAppendConstructorExpressionAction(string expression) { - ClassBlockSyntax AppendConstructorExpression(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax AppendConstructorExpression(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { var constructor = node.Members.FirstOrDefault(c => c.IsKind(SyntaxKind.ConstructorBlock)); if (constructor != null) @@ -277,9 +282,9 @@ ClassBlockSyntax AppendConstructorExpression(SyntaxGenerator syntaxGenerator, Cl return AppendConstructorExpression; } - public Func GetCreateConstructorAction(string types, string identifiers) + public Func GetCreateConstructorAction(string types, string identifiers) { - ClassBlockSyntax CreateConstructor(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax CreateConstructor(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { // constructors in vb are just named new var constructorStatementNode = SyntaxFactory.SubNewStatement() @@ -313,9 +318,9 @@ ClassBlockSyntax CreateConstructor(SyntaxGenerator syntaxGenerator, ClassBlockSy return CreateConstructor; } - public Func GetChangeMethodNameAction(string existingMethodName, string newMethodName) + public Func GetChangeMethodNameAction(string existingMethodName, string newMethodName) { - ClassBlockSyntax ChangeMethodName(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax ChangeMethodName(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { // if we have more than one method with same name return without making changes var methodNode = GetMethodNode(node, existingMethodName); @@ -331,9 +336,9 @@ ClassBlockSyntax ChangeMethodName(SyntaxGenerator syntaxGenerator, ClassBlockSyn return ChangeMethodName; } - public Func GetChangeMethodToReturnTaskTypeAction(string methodName) + public Func GetChangeMethodToReturnTaskTypeAction(string methodName) { - ClassBlockSyntax ChangeMethodToReturnTaskType(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax ChangeMethodToReturnTaskType(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { // if we have more than one method with same name return without making changes var methodNode = GetMethodNode(node, methodName); @@ -349,9 +354,9 @@ ClassBlockSyntax ChangeMethodToReturnTaskType(SyntaxGenerator syntaxGenerator, C return ChangeMethodToReturnTaskType; } - public Func GetRemoveMethodParametersAction(string methodName) + public Func GetRemoveMethodParametersAction(string methodName) { - ClassBlockSyntax RemoveMethodParameters(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax RemoveMethodParameters(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { // if we have more than one method with same name return without making changes var methodNode = GetMethodNode(node, methodName); @@ -368,9 +373,9 @@ ClassBlockSyntax RemoveMethodParameters(SyntaxGenerator syntaxGenerator, ClassBl return RemoveMethodParameters; } - public Func GetCommentMethodAction(string methodName, string comment = null, string dontUseCTAPrefix = null) + public Func GetCommentMethodAction(string methodName, string comment = null, string dontUseCTAPrefix = null) { - ClassBlockSyntax CommentMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax CommentMethod(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { // if we have more than one method with same name return without making changes var methodNode = GetMethodNode(node, methodName); @@ -393,16 +398,16 @@ ClassBlockSyntax CommentMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax trivia = trivia.Add(methodEndStatementComment); node = node.RemoveNode(methodNode, SyntaxRemoveOptions.KeepNoTrivia); - node = node.WithEndClassStatement(node.EndClassStatement.WithLeadingTrivia(trivia)); + node = node.WithEndBlockStatement(node.EndBlockStatement.WithLeadingTrivia(trivia)); } return node.NormalizeWhitespace(); } return CommentMethod; } - public Func GetAddCommentsToMethodAction(string methodName, string comment, string dontUseCTAPrefix = null) + public Func GetAddCommentsToMethodAction(string methodName, string comment, string dontUseCTAPrefix = null) { - ClassBlockSyntax AddCommentsToMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax AddCommentsToMethod(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { // if we have more than one method with same name return without making changes var methodNode = GetMethodNode(node, methodName); @@ -421,9 +426,9 @@ ClassBlockSyntax AddCommentsToMethod(SyntaxGenerator syntaxGenerator, ClassBlock return AddCommentsToMethod; } - public Func GetAddExpressionToMethodAction(string methodName, string expression) + public Func GetAddExpressionToMethodAction(string methodName, string expression) { - ClassBlockSyntax AddExpressionToMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax AddExpressionToMethod(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { // if we have more than one method with same name return without making changes var methodNode = GetMethodNode(node, methodName); @@ -439,9 +444,9 @@ ClassBlockSyntax AddExpressionToMethod(SyntaxGenerator syntaxGenerator, ClassBlo return AddExpressionToMethod; } - public Func GetAddParametersToMethodAction(string methodName, string types, string identifiers) + public Func GetAddParametersToMethodAction(string methodName, string types, string identifiers) { - ClassBlockSyntax AddParametersToMethod(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax AddParametersToMethod(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { // if we have more than one method with same name return without making changes var methodNode = GetMethodNode(node, methodName); @@ -457,29 +462,29 @@ ClassBlockSyntax AddParametersToMethod(SyntaxGenerator syntaxGenerator, ClassBlo return AddParametersToMethod; } - public Func GetReplaceMvcControllerMethodsBodyAction(string expression) + public Func GetReplaceMvcControllerMethodsBodyAction(string expression) { throw new NotImplementedException(); } - public Func GetReplaceWebApiControllerMethodsBodyAction(string expression) + public Func GetReplaceWebApiControllerMethodsBodyAction(string expression) { - ClassBlockSyntax ReplaceMethodBodyFunc(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax ReplaceMethodBodyFunc(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { return AddCommentToPublicMethods(node, expression); } return ReplaceMethodBodyFunc; } - public Func GetReplaceCoreControllerMethodsBodyAction(string expression) + public Func GetReplaceCoreControllerMethodsBodyAction(string expression) { - ClassBlockSyntax ReplaceMethodModifiers(SyntaxGenerator syntaxGenerator, ClassBlockSyntax node) + TypeBlockSyntax ReplaceCoreControllerMethodsBody(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) { return AddCommentToPublicMethods(node, expression); } - return ReplaceMethodModifiers; + return ReplaceCoreControllerMethodsBody; } - private ClassBlockSyntax AddCommentToPublicMethods(ClassBlockSyntax node, string expression) + private TypeBlockSyntax AddCommentToPublicMethods(TypeBlockSyntax node, string expression) { var comment = string.Format(Constants.VbCommentFormat, $"Replace method body with {expression}"); @@ -509,7 +514,7 @@ private string GetMethodId(MethodStatementSyntax method) return $"{method.Identifier}{method.ParameterList}"; } - private MethodBlockSyntax GetMethodNode(ClassBlockSyntax node, string methodName) + private MethodBlockSyntax GetMethodNode(TypeBlockSyntax node, string methodName) { var methodNodeList = node.DescendantNodes().OfType() .Where(method => method.SubOrFunctionStatement.Identifier.Text == methodName); diff --git a/src/CTA.Rules.Config/Constants.cs b/src/CTA.Rules.Config/Constants.cs index 4b0fcb44..0105f266 100644 --- a/src/CTA.Rules.Config/Constants.cs +++ b/src/CTA.Rules.Config/Constants.cs @@ -121,6 +121,19 @@ public class Constants public static readonly List SupportedMethodModifiers = new List() { "public", "internal", "protected", "private", "abstract", "extern", "override", "static", "unsafe", "virtual", "async" }; + public static readonly List SupportedVbMethodModifiers = new() + { + "Public", + "Internal", + "Protected", + "Private", + "Friend", + "Overrides", + "Shared", + "Overridable", + "Async" + }; + //Monolith code constants public const string Await = "await"; public const string TaskActionResult = "Task"; diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs index 5d7baacb..dbe59ccf 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs @@ -1,462 +1,509 @@ -using System; -using CTA.Rules.Actions.VisualBasic; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.VisualBasic; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using Microsoft.CodeAnalysis.Editing; -using NUnit.Framework; -using System.Collections.Generic; -using System.Linq; - -namespace CTA.Rules.Test.Actions.VisualBasic -{ - public class ClassActionsTests - { - private SyntaxGenerator _syntaxGenerator; - private ClassActions _classActions; - private ClassBlockSyntax _node; - private MethodBlockSyntax _subNode; - private MethodBlockSyntax _functionNode; - - [SetUp] - public void SetUp() - { - - var workspace = new AdhocWorkspace(); - var language = LanguageNames.VisualBasic; - _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); - _classActions = new ClassActions(); - SyntaxTree tree = VisualBasicSyntaxTree.ParseText(@$"Class MyClass -End Class"); - _node = tree.GetRoot() - .DescendantNodes() - .OfType() - .FirstOrDefault(); - - _subNode = CreateMethodNode("Invoke", - new List() - { - SyntaxFactory.ParseExecutableStatement(@"' Nothing to see here") - }, - true, - new List() - { - SyntaxKind.PublicKeyword - }); - - _functionNode = CreateMethodNode("TestFunction", - new List() - { - SyntaxFactory.ParseExecutableStatement(@"' Nothing to see here"), - SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression("\"hello world\"")) - }, false, - new List() - { - SyntaxKind.PublicKeyword - }, - "String"); - } - - [Test] - public void GetAddCommentAction_Adds_Leading_Comment_To_Class_Declaration() - { - const string commentToAdd = "This is a comment"; - var addCommentFunc = _classActions.GetAddCommentAction(commentToAdd); - var newNode = addCommentFunc(_syntaxGenerator, _node); - - var expectedResult = @$"' Added by CTA: {commentToAdd} -Class MyClass -End Class"; - Assert.AreEqual(expectedResult, newNode.ToFullString()); - } - - [Test] - public void GetChangeNameAction_Changes_Class_Name_To_Specified_Value() - { - const string newClassName = "NewClassName"; - var changeNameFunc = _classActions.GetChangeNameAction(newClassName); - var newNode = changeNameFunc(_syntaxGenerator, _node); - - var expectedResult = @$"Class {newClassName} -End Class"; - Assert.AreEqual(expectedResult, newNode.ToFullString()); - } - - [Test] - public void GetRenameClassAction_Changes_Class_Name_To_Specified_Value() - { - const string newClassName = "NewClassName"; - var changeNameFunc = _classActions.GetRenameClassAction(newClassName); - var newNode = changeNameFunc(_syntaxGenerator, _node); - - var expectedResult = @$"Class {newClassName} -End Class"; - Assert.AreEqual(expectedResult, newNode.ToFullString()); - } - - [Test] - public void GetRemoveAttributeAction_Removes_Specified_Attribute() - { - const string attributeToRemove = "Serializable"; - var nodeWithAttributes = (ClassBlockSyntax)_syntaxGenerator.AddAttributes(_node, - _syntaxGenerator.Attribute("Serializable"), - _syntaxGenerator.Attribute("SecurityCritical")); - - var removeAttributeFunc = _classActions.GetRemoveAttributeAction(attributeToRemove); - var newNode = removeAttributeFunc(_syntaxGenerator, nodeWithAttributes); - - var expectedResult = @$" -Class MyClass -End Class"; - Assert.AreEqual(expectedResult, newNode.ToFullString()); - } - - [Test] - public void GetAddAttributeAction_Adds_Attribute() - { - const string attributeToAdd = "Serializable"; - var addAttributeFunc = _classActions.GetAddAttributeAction(attributeToAdd); - var newNode = addAttributeFunc(_syntaxGenerator, _node); - var expectedResult = @$" -Class MyClass -End Class"; - Assert.AreEqual(expectedResult, newNode.ToFullString()); - } - - [Test] - [TestCase("\r\n Public Sub MySub(i as Integer) Console .WriteLine(i) End Sub ")] - [TestCase("\r\n Public Function MyFunction(i as Integer) Console .WriteLine(i) : Return i End Function ")] - public void GetAddMethodAction_Adds_Method(string expression) - { - var addMethodFunc = _classActions.GetAddMethodAction(expression); - - var newNode = addMethodFunc(_syntaxGenerator, _node); - - var expectedResult = @$"Class MyClass -{expression} -End Class"; - Assert.AreEqual(expectedResult, newNode.ToFullString()); - } - - [Test] - public void GetRemoveMethodAction_Removes_Specified_Method() - { - const string methodName = "MyMethod"; - var methodNode = SyntaxFactory.MethodStatement(SyntaxKind.SubStatement, - SyntaxFactory.Token(SyntaxKind.SubKeyword), methodName); - var nodeWithMethod = _node.AddMembers(methodNode); - - var removeMethodFunc = _classActions.GetRemoveMethodAction(methodName); - var newNode = removeMethodFunc(_syntaxGenerator, nodeWithMethod); - - var expectedResult = @$"Class MyClass -End Class"; - Assert.AreEqual(expectedResult, newNode.ToFullString()); - } - - [Test] - public void RemoveLastBaseClass() - { - var baseClassname = "ControllerBase"; - var addBaseClass = _classActions.GetAddBaseClassAction(baseClassname); - var removeBaseClassMethod = _classActions.GetRemoveBaseClassAction(baseClassname); - - var nodeWithClass = addBaseClass(_syntaxGenerator, _node); - nodeWithClass = removeBaseClassMethod(_syntaxGenerator, nodeWithClass); - - //Make sure the inheritance symbol is removed when last base class is removed: - StringAssert.DoesNotContain(":", nodeWithClass.ToFullString()); - } - - [Test] - public void ReplaceMethodModifiers() - { - const string methodName = "MyMethod"; - var methodNode = SyntaxFactory.MethodStatement(SyntaxKind.SubStatement, - SyntaxFactory.Token(SyntaxKind.SubKeyword), methodName); - var nodeWithMethod = _node.AddMembers(methodNode); - - var modifier = "private async extern"; - var replaceModifier = _classActions.GetReplaceMethodModifiersAction(methodName, modifier); - - var node = replaceModifier(_syntaxGenerator, nodeWithMethod); - - StringAssert.Contains(modifier, node.ToFullString()); - } - - [Test] - public void AddExpression() - { - string expression = "Dim _next As RequestDelegate"; - - var addBaseClass = _classActions.GetAddExpressionAction(expression); - - var nodeWithExpression = addBaseClass(_syntaxGenerator, _node); - - StringAssert.Contains(expression, nodeWithExpression.ToFullString()); - } - - [Test] - public void AppendConstructorExpression() - { - var constructorStatements = new SyntaxList(); - constructorStatements = constructorStatements.Add( - SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("_breadcrumb = breadcrumb"))); - var methodNode = SyntaxFactory.ConstructorBlock( - SyntaxFactory.SubNewStatement(), - constructorStatements, - SyntaxFactory.EndSubStatement()); - var nodeWithMethod = _node.AddMembers(methodNode); - string expression = "_next = [next]"; - - var addBaseClass = _classActions.GetAppendConstructorExpressionAction(expression); - - var nodeWithExpression = addBaseClass(_syntaxGenerator, nodeWithMethod); - - StringAssert.Contains(expression, nodeWithExpression.ToFullString()); - } - - [Test] - public void RemoveConstructorBaseInitializer() - { - var constructorStatements = new SyntaxList(); - constructorStatements = constructorStatements.Add( - SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("MyBase.New(next, testing)"))); - constructorStatements = constructorStatements.Add( - SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("_breadcrumb = breadcrumb"))); - - var methodNode = SyntaxFactory.ConstructorBlock( - SyntaxFactory.SubNewStatement(), - constructorStatements, - SyntaxFactory.EndSubStatement()); - - var nodeWithMethod = _node.AddMembers(methodNode); - string expression = "next"; - - var addBaseClass = _classActions.GetRemoveConstructorInitializerAction(expression); - - var nodeWithExpression = addBaseClass(_syntaxGenerator, nodeWithMethod); - - StringAssert.DoesNotContain(expression, nodeWithExpression.ToFullString()); - } - - [Test] - public void CreateConstructor() - { - string types = "RequestDelegate, string"; - string identifiers = "[next], value"; - - var createConstructorFunc = _classActions.GetCreateConstructorAction(types: types, identifiers: identifiers); - var nodeWithExpression = createConstructorFunc(_syntaxGenerator, _node); - - StringAssert.Contains(types.Split(',')[0], nodeWithExpression.ToFullString()); - StringAssert.Contains(identifiers.Split(',')[0], nodeWithExpression.ToFullString()); - } - - - [Test] - [TestCase(true)] - [TestCase(false)] - public void ChangeMethodName(bool isSubMethod) - { - string existingMethodName = "ProcessRequest"; - string newMethodName = "Invoke"; - - MethodBlockSyntax methodNode; - if (isSubMethod) - { - methodNode = SyntaxFactory.MethodBlock(SyntaxKind.SubBlock, - SyntaxFactory.MethodStatement(SyntaxKind.SubStatement, SyntaxFactory.Token(SyntaxKind.SubKeyword), - existingMethodName), - SyntaxFactory.EndSubStatement()); - } - else - { - methodNode = SyntaxFactory.MethodBlock(SyntaxKind.FunctionBlock, - SyntaxFactory.MethodStatement(SyntaxKind.FunctionStatement, - SyntaxFactory.Token(SyntaxKind.FunctionKeyword), - existingMethodName), - SyntaxFactory.EndFunctionStatement()); - } - - var nodeWithMethod = _node.AddMembers(methodNode); - - var changeMethodNameFunc = _classActions.GetChangeMethodNameAction(existingMethodName, newMethodName); - var nodeWithExpression = changeMethodNameFunc(_syntaxGenerator, nodeWithMethod); - - StringAssert.Contains(newMethodName, nodeWithExpression.ToFullString()); - } - - [Test] - public void RemoveMethodParameters() - { - var parameters = new List - { - SyntaxFactory.Parameter(SyntaxFactory.ModifiedIdentifier("context")) - .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName("HttpContext"))), - SyntaxFactory.Parameter(SyntaxFactory.ModifiedIdentifier("value")) - .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName("string"))) - }; - var methodName = "Invoke"; - var methodNode = _subNode.WithSubOrFunctionStatement( - _subNode.SubOrFunctionStatement.WithParameterList( - SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters)))); - var nodeWithMethod = _node.AddMembers(methodNode); - var removeMethodParametersFunc = _classActions.GetRemoveMethodParametersAction(methodName); - var nodeWithExpression = removeMethodParametersFunc(_syntaxGenerator, nodeWithMethod); - StringAssert.DoesNotContain("HttpContext", nodeWithExpression.ToFullString()); - } - - [Test] - public void ChangeMethodReturnTaskTypeVoid() - { - string methodName = "Invoke"; - var nodeWithMethod = _node.AddMembers(_subNode); - var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); - var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); - StringAssert.Contains("Task", nodeWithExpression.ToFullString()); - } - - [Test] - public void ChangeMethodReturnTaskTypeString() - { - string methodName = "TestFunction"; - var nodeWithMethod = _node.AddMembers(_functionNode); - var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); - var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); - StringAssert.Contains("Task(Of String)", nodeWithExpression.ToFullString()); - } - - [Test] - public void CommentMethod() - { - string methodName = "Invoke"; - var nodeWithMethod = _node.AddMembers(_subNode); - - var commentMethodeFunc = _classActions.GetCommentMethodAction(methodName); - var nodeWithExpression = commentMethodeFunc(_syntaxGenerator, nodeWithMethod); - - StringAssert.Contains("' Public Sub Invoke", nodeWithExpression.ToFullString()); - } - - [Test] - public void AddCommentsToMethod() - { - string methodName = "Invoke"; - string comment = "This method is deprecated"; - var nodeWithMethod = _node.AddMembers(_subNode); - - var addCommentsToMethodFunc = _classActions.GetAddCommentsToMethodAction(methodName, comment); - var nodeWithExpression = addCommentsToMethodFunc(_syntaxGenerator, nodeWithMethod); - - StringAssert.Contains("' Added by CTA: This method is deprecated", nodeWithExpression.ToFullString()); - } - - [Test] - public void AddExpressionToMethod() - { - string methodName = "TestFunction"; - string expression = "Await _next.Invoke(context)"; - var nodeWithMethod = _node.AddMembers(_functionNode); - var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); - var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); - - var addExpressionToMethodFunc = _classActions.GetAddExpressionToMethodAction(methodName, expression); - nodeWithExpression = addExpressionToMethodFunc(_syntaxGenerator, nodeWithExpression); - - StringAssert.Contains("Await _next.Invoke(context)", nodeWithExpression.ToFullString()); - } - - [Test] - public void AddParametersToMethod() - { - string methodName = "Invoke"; - string types = "HttpContext,String"; - string identifiers = "context,value"; - - var nodeWithMethod = _node.AddMembers(_subNode); - - var addParametersToMethodFunc = - _classActions.GetAddParametersToMethodAction(methodName, types, identifiers); - var nodeWithExpression = addParametersToMethodFunc(_syntaxGenerator, nodeWithMethod); - - var expectedString = @"Public Sub Invoke(context As HttpContext, value As String)"; - StringAssert.Contains(expectedString, nodeWithExpression.ToFullString()); - } - - [Test] - [TestCase("WebApiController")] - [TestCase("CoreController")] - public void ReplacePublicMethodsBody(string controller) - { - string newBody = "Return Content(MonolithService.CreateRequest())"; - var nodeWithMethods = _node.AddMembers(CreateMethodNode("SuperStringAsyncMethod", - new List() - { - SyntaxFactory.ParseExecutableStatement(@"Dim hello = ""hello world""") - }, - false, new List() { SyntaxKind.PublicKeyword, SyntaxKind.AsyncKeyword }, - "Task(Of String)")); - nodeWithMethods = nodeWithMethods.AddMembers(CreateMethodNode("SuperStringMethod", - new List() - { - SyntaxFactory.ParseExecutableStatement(@"Dim hello = ""hello world again?!""") - }, - false, new List() { SyntaxKind.PublicKeyword }, - "String")); - nodeWithMethods = nodeWithMethods.AddMembers(CreateMethodNode("SuperStringAsyncMethod", - new List() - { - SyntaxFactory.ParseExecutableStatement(@"Dim hello = ""not hello world!"""), - }, - false, new List() { SyntaxKind.PrivateKeyword}, - "String")); - - var replacePublicMethodsBodyFunc = controller == "WebApiController" - ? _classActions.GetReplaceWebApiControllerMethodsBodyAction(newBody) - : _classActions.GetReplaceCoreControllerMethodsBodyAction(newBody); - var newNode = replacePublicMethodsBodyFunc(_syntaxGenerator, nodeWithMethods.NormalizeWhitespace()); - - var publicMembers = newNode.Members.OfType().Where(m => - m.Modifiers.Any(modifier => modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PublicKeyword))); - var privateMembers = newNode.Members.OfType().Where(m => - m.Modifiers.Any(modifier => modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PrivateKeyword))); - - Assert.IsTrue(publicMembers.All(m => m.ToFullString().Contains($"'Added by CTA: Replace method body with {newBody}"))); - Assert.IsTrue(privateMembers.All(m => !m.ToFullString().Contains($"'Added by CTA: Replace method body with {newBody}"))); - } - - [Test] - public void ClassDeclarationEquals() - { - throw new NotImplementedException(); - // var classAction = new ClassDeclarationAction() { Key = "Test", Value = "Test2", ClassDeclarationActionFunc = _classActions.GetAddAttributeAction("Test") }; - // var cloned = classAction.Clone(); - // Assert.True(classAction.Equals(cloned)); - // - // cloned.Value = "DifferentValue"; - // Assert.False(classAction.Equals(cloned)); - } - - private MethodBlockSyntax CreateMethodNode(string identifier, - List bodyExpressions, - bool isSub, - List modifiers, - string returnType = "") - { - var body = new SyntaxList(bodyExpressions); - var modifiersSyntax = new SyntaxTokenList(modifiers.Select(m => SyntaxFactory.Token(m))); - var blockKind = isSub ? SyntaxKind.SubBlock: SyntaxKind.FunctionBlock; - var statementKind = isSub ? SyntaxKind.SubStatement : SyntaxKind.FunctionStatement; - var keyword = isSub? SyntaxKind.SubKeyword : SyntaxKind.FunctionKeyword; - var endStatement = isSub ? SyntaxFactory.EndSubStatement() : SyntaxFactory.EndFunctionStatement(); - - return SyntaxFactory.MethodBlock(blockKind, - SyntaxFactory.MethodStatement(statementKind, - SyntaxFactory.Token(keyword), identifier) - .WithModifiers(modifiersSyntax) - .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName(returnType))), - endStatement).WithStatements(body).NormalizeWhitespace(); - } - } +using System; +using CTA.Rules.Actions.VisualBasic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; +using System.Collections.Generic; +using System.Linq; +using AttributeSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class ClassActionsTests + { + private SyntaxGenerator _syntaxGenerator; + private ClassActions _classActions; + private ClassBlockSyntax _node; + private MethodBlockSyntax _subNode; + private MethodBlockSyntax _functionNode; + + private Dictionary _blockNodes; + + [SetUp] + public void SetUp() + { + + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _classActions = new ClassActions(); + SyntaxTree tree = VisualBasicSyntaxTree.ParseText(@$"Class MyClass +End Class + +Module MyModule +EndModule +"); + _node = tree.GetRoot() + .DescendantNodes() + .OfType() + .FirstOrDefault(); + + _blockNodes = new Dictionary(); + _blockNodes.Add("class", _node); + _blockNodes.Add("module", tree.GetRoot().DescendantNodes().OfType().FirstOrDefault()); + + _subNode = CreateMethodNode("Invoke", + new List() + { + SyntaxFactory.ParseExecutableStatement(@"' Nothing to see here") + }, + true, + new List() + { + SyntaxKind.PublicKeyword + }); + + _functionNode = CreateMethodNode("TestFunction", + new List() + { + SyntaxFactory.ParseExecutableStatement(@"' Nothing to see here"), + SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression("\"hello world\"")) + }, false, + new List() + { + SyntaxKind.PublicKeyword + }, + "String"); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void GetAddCommentAction_Adds_Leading_Comment_To_Class_Declaration(string blockType) + { + const string commentToAdd = "This is a comment"; + var addCommentFunc = _classActions.GetAddCommentAction(commentToAdd); + var newNode = addCommentFunc(_syntaxGenerator, _blockNodes[blockType]); + + var expectedResult = @$"' Added by CTA: {commentToAdd} +"; + Assert.AreEqual(expectedResult, newNode.GetLeadingTrivia().ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void GetChangeNameAction_Changes_Class_Name_To_Specified_Value(string blockType) + { + const string newClassName = "NewClassName"; + var changeNameFunc = _classActions.GetChangeNameAction(newClassName); + var newNode = changeNameFunc(_syntaxGenerator, _blockNodes[blockType]); + Assert.AreEqual(newClassName, newNode.BlockStatement.Identifier.ToString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void GetRenameClassAction_Changes_Class_Name_To_Specified_Value(string blockType) + { + const string newClassName = "NewClassName"; + var changeNameFunc = _classActions.GetRenameClassAction(newClassName); + var newNode = changeNameFunc(_syntaxGenerator, _blockNodes[blockType]); + Assert.AreEqual(newClassName, newNode.BlockStatement.Identifier.ToString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void GetRemoveAttributeAction_Removes_Specified_Attribute(string blockType) + { + const string attributeToRemove = "Serializable"; + var node = _blockNodes[blockType]; + var addAttributeFunc1 = _classActions.GetAddAttributeAction("Serializable"); + var addAttributeFunc2 = _classActions.GetAddAttributeAction("SecurityCritical"); + + var nodeWithAttributes = addAttributeFunc1(_syntaxGenerator, node); + nodeWithAttributes = addAttributeFunc2(_syntaxGenerator, nodeWithAttributes); + + var removeAttributeFunc = _classActions.GetRemoveAttributeAction(attributeToRemove); + var newNode = removeAttributeFunc(_syntaxGenerator, nodeWithAttributes); + Assert.IsTrue(newNode.BlockStatement.AttributeLists.ToFullString().Contains("")); + Assert.IsTrue(!newNode.BlockStatement.AttributeLists.ToFullString().Contains("", newNode.BlockStatement.AttributeLists.ToString()); + } + + [Test] + [TestCase(@"Public Sub MySub(i as Integer) + Console.WriteLine(i) + End Sub", "class")] + [TestCase(@"Public Function MyFunction(i as Integer) As Integer + Console.WriteLine(i) + Return i + End Function", "class")] + [TestCase(@"Public Sub MySub(i as Integer) + Console.WriteLine(i) + End Sub", "module")] + [TestCase(@"Public Function MyFunction(i as Integer) As Integer + Console.WriteLine(i) + Return i + End Function", "module")] + public void GetAddMethodAction_Adds_Method(string expression, string blockType) + { + var addMethodFunc = _classActions.GetAddMethodAction(expression); + var newNode = addMethodFunc(_syntaxGenerator, _blockNodes[blockType]); + Assert.AreEqual(expression, newNode.Members.OfType().FirstOrDefault()?.ToString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void GetRemoveMethodAction_Removes_Specified_Method(string blockType) + { + const string methodName = "MyMethod"; + var methodNode = SyntaxFactory.MethodStatement(SyntaxKind.SubStatement, + SyntaxFactory.Token(SyntaxKind.SubKeyword), methodName); + var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); + + var removeMethodFunc = _classActions.GetRemoveMethodAction(methodName); + var newNode = removeMethodFunc(_syntaxGenerator, nodeWithMethod); + + var expectedResult = _blockNodes[blockType].NormalizeWhitespace().ToFullString(); + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void RemoveLastBaseClass(string blockType) + { + var baseClassname = "ControllerBase"; + var addBaseClass = _classActions.GetAddBaseClassAction(baseClassname); + var removeBaseClassMethod = _classActions.GetRemoveBaseClassAction(baseClassname); + + var nodeWithClass = addBaseClass(_syntaxGenerator, _blockNodes[blockType]); + nodeWithClass = removeBaseClassMethod(_syntaxGenerator, nodeWithClass); + + //Make sure the inheritance symbol is removed when last base class is removed: + StringAssert.DoesNotContain(":", nodeWithClass.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void ReplaceMethodModifiers(string blockType) + { + const string methodName = "MyMethod"; + var methodNode = SyntaxFactory.MethodStatement(SyntaxKind.SubStatement, + SyntaxFactory.Token(SyntaxKind.SubKeyword), methodName); + var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); + + var modifier = "Private Async"; + var replaceModifier = _classActions.GetReplaceMethodModifiersAction(methodName, modifier); + + var node = replaceModifier(_syntaxGenerator, nodeWithMethod); + + StringAssert.Contains(modifier, node.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void AddExpression(string blockType) + { + string expression = "Dim _next As RequestDelegate"; + + var addBaseClass = _classActions.GetAddExpressionAction(expression); + + var nodeWithExpression = addBaseClass(_syntaxGenerator, _blockNodes[blockType]); + + StringAssert.Contains(expression, nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void AppendConstructorExpression(string blockType) + { + var constructorStatements = new SyntaxList(); + constructorStatements = constructorStatements.Add( + SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("_breadcrumb = breadcrumb"))); + var methodNode = SyntaxFactory.ConstructorBlock( + SyntaxFactory.SubNewStatement(), + constructorStatements, + SyntaxFactory.EndSubStatement()); + var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); + string expression = "_next = [next]"; + + var addBaseClass = _classActions.GetAppendConstructorExpressionAction(expression); + + var nodeWithExpression = addBaseClass(_syntaxGenerator, nodeWithMethod); + + StringAssert.Contains(expression, nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void RemoveConstructorBaseInitializer(string blockType) + { + var constructorStatements = new SyntaxList(); + constructorStatements = constructorStatements.Add( + SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("MyBase.New(next, testing)"))); + constructorStatements = constructorStatements.Add( + SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression("_breadcrumb = breadcrumb"))); + + var methodNode = SyntaxFactory.ConstructorBlock( + SyntaxFactory.SubNewStatement(), + constructorStatements, + SyntaxFactory.EndSubStatement()); + + var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); + string expression = "next"; + + var addBaseClass = _classActions.GetRemoveConstructorInitializerAction(expression); + + var nodeWithExpression = addBaseClass(_syntaxGenerator, nodeWithMethod); + + StringAssert.DoesNotContain(expression, nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void CreateConstructor(string blockType) + { + string types = "RequestDelegate, string"; + string identifiers = "[next], value"; + + var createConstructorFunc = _classActions.GetCreateConstructorAction(types: types, identifiers: identifiers); + var nodeWithExpression = createConstructorFunc(_syntaxGenerator, _blockNodes[blockType]); + + StringAssert.Contains(types.Split(',')[0], nodeWithExpression.ToFullString()); + StringAssert.Contains(identifiers.Split(',')[0], nodeWithExpression.ToFullString()); + } + + + [Test] + [TestCase(true, "class")] + [TestCase(false, "module")] + [TestCase(true, "module")] + [TestCase(false, "class")] + public void ChangeMethodName(bool isSubMethod, string blockType) + { + string existingMethodName = "ProcessRequest"; + string newMethodName = "Invoke"; + + MethodBlockSyntax methodNode; + if (isSubMethod) + { + methodNode = SyntaxFactory.MethodBlock(SyntaxKind.SubBlock, + SyntaxFactory.MethodStatement(SyntaxKind.SubStatement, SyntaxFactory.Token(SyntaxKind.SubKeyword), + existingMethodName), + SyntaxFactory.EndSubStatement()); + } + else + { + methodNode = SyntaxFactory.MethodBlock(SyntaxKind.FunctionBlock, + SyntaxFactory.MethodStatement(SyntaxKind.FunctionStatement, + SyntaxFactory.Token(SyntaxKind.FunctionKeyword), + existingMethodName), + SyntaxFactory.EndFunctionStatement()); + } + + var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); + + var changeMethodNameFunc = _classActions.GetChangeMethodNameAction(existingMethodName, newMethodName); + var nodeWithExpression = changeMethodNameFunc(_syntaxGenerator, nodeWithMethod); + + StringAssert.Contains(newMethodName, nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void RemoveMethodParameters(string blockType) + { + var parameters = new List + { + SyntaxFactory.Parameter(SyntaxFactory.ModifiedIdentifier("context")) + .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName("HttpContext"))), + SyntaxFactory.Parameter(SyntaxFactory.ModifiedIdentifier("value")) + .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName("string"))) + }; + var methodName = "Invoke"; + var methodNode = _subNode.WithSubOrFunctionStatement( + _subNode.SubOrFunctionStatement.WithParameterList( + SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters)))); + var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); + var removeMethodParametersFunc = _classActions.GetRemoveMethodParametersAction(methodName); + var nodeWithExpression = removeMethodParametersFunc(_syntaxGenerator, nodeWithMethod); + StringAssert.DoesNotContain("HttpContext", nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void ChangeMethodReturnTaskTypeVoid(string blockType) + { + string methodName = "Invoke"; + var nodeWithMethod = _blockNodes[blockType].AddMembers(_subNode); + var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); + var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); + StringAssert.Contains("Task", nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void ChangeMethodReturnTaskTypeString(string blockType) + { + string methodName = "TestFunction"; + var nodeWithMethod = _blockNodes[blockType].AddMembers(_functionNode); + var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); + var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); + StringAssert.Contains("Task(Of String)", nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void CommentMethod(string blockType) + { + string methodName = "Invoke"; + var nodeWithMethod = _blockNodes[blockType].AddMembers(_subNode); + + var commentMethodeFunc = _classActions.GetCommentMethodAction(methodName); + var nodeWithExpression = commentMethodeFunc(_syntaxGenerator, nodeWithMethod); + + StringAssert.Contains("' Public Sub Invoke", nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void AddCommentsToMethod(string blockType) + { + string methodName = "Invoke"; + string comment = "This method is deprecated"; + var nodeWithMethod = _blockNodes[blockType].AddMembers(_subNode); + + var addCommentsToMethodFunc = _classActions.GetAddCommentsToMethodAction(methodName, comment); + var nodeWithExpression = addCommentsToMethodFunc(_syntaxGenerator, nodeWithMethod); + + StringAssert.Contains("' Added by CTA: This method is deprecated", nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void AddExpressionToMethod(string blockType) + { + string methodName = "TestFunction"; + string expression = "Await _next.Invoke(context)"; + var nodeWithMethod = _blockNodes[blockType].AddMembers(_functionNode); + var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); + var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); + + var addExpressionToMethodFunc = _classActions.GetAddExpressionToMethodAction(methodName, expression); + nodeWithExpression = addExpressionToMethodFunc(_syntaxGenerator, nodeWithExpression); + + StringAssert.Contains("Await _next.Invoke(context)", nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("class")] + [TestCase("module")] + public void AddParametersToMethod(string blockType) + { + string methodName = "Invoke"; + string types = "HttpContext,String"; + string identifiers = "context,value"; + + var nodeWithMethod = _blockNodes[blockType].AddMembers(_subNode); + + var addParametersToMethodFunc = + _classActions.GetAddParametersToMethodAction(methodName, types, identifiers); + var nodeWithExpression = addParametersToMethodFunc(_syntaxGenerator, nodeWithMethod); + + var expectedString = @"Public Sub Invoke(context As HttpContext, value As String)"; + StringAssert.Contains(expectedString, nodeWithExpression.ToFullString()); + } + + [Test] + [TestCase("WebApiController")] + [TestCase("CoreController")] + public void ReplacePublicMethodsBody(string controller) + { + string newBody = "Return Content(MonolithService.CreateRequest())"; + var nodeWithMethods = _node.AddMembers(CreateMethodNode("SuperStringAsyncMethod", + new List() + { + SyntaxFactory.ParseExecutableStatement(@"Dim hello = ""hello world""") + }, + false, new List() { SyntaxKind.PublicKeyword, SyntaxKind.AsyncKeyword }, + "Task(Of String)")); + nodeWithMethods = nodeWithMethods.AddMembers(CreateMethodNode("SuperStringMethod", + new List() + { + SyntaxFactory.ParseExecutableStatement(@"Dim hello = ""hello world again?!""") + }, + false, new List() { SyntaxKind.PublicKeyword }, + "String")); + nodeWithMethods = nodeWithMethods.AddMembers(CreateMethodNode("SuperStringAsyncMethod", + new List() + { + SyntaxFactory.ParseExecutableStatement(@"Dim hello = ""not hello world!"""), + }, + false, new List() { SyntaxKind.PrivateKeyword}, + "String")); + + var replacePublicMethodsBodyFunc = controller == "WebApiController" + ? _classActions.GetReplaceWebApiControllerMethodsBodyAction(newBody) + : _classActions.GetReplaceCoreControllerMethodsBodyAction(newBody); + var newNode = replacePublicMethodsBodyFunc(_syntaxGenerator, nodeWithMethods.NormalizeWhitespace()); + + var publicMembers = newNode.Members.OfType().Where(m => + m.Modifiers.Any(modifier => modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PublicKeyword))); + var privateMembers = newNode.Members.OfType().Where(m => + m.Modifiers.Any(modifier => modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PrivateKeyword))); + + Assert.IsTrue(publicMembers.All(m => m.ToFullString().Contains($"'Added by CTA: Replace method body with {newBody}"))); + Assert.IsTrue(privateMembers.All(m => !m.ToFullString().Contains($"'Added by CTA: Replace method body with {newBody}"))); + } + + [Test] + public void ClassDeclarationEquals() + { + throw new NotImplementedException(); + // var classAction = new ClassDeclarationAction() { Key = "Test", Value = "Test2", ClassDeclarationActionFunc = _classActions.GetAddAttributeAction("Test") }; + // var cloned = classAction.Clone(); + // Assert.True(classAction.Equals(cloned)); + // + // cloned.Value = "DifferentValue"; + // Assert.False(classAction.Equals(cloned)); + } + + private MethodBlockSyntax CreateMethodNode(string identifier, + List bodyExpressions, + bool isSub, + List modifiers, + string returnType = "") + { + var body = new SyntaxList(bodyExpressions); + var modifiersSyntax = new SyntaxTokenList(modifiers.Select(m => SyntaxFactory.Token(m))); + var blockKind = isSub ? SyntaxKind.SubBlock: SyntaxKind.FunctionBlock; + var statementKind = isSub ? SyntaxKind.SubStatement : SyntaxKind.FunctionStatement; + var keyword = isSub? SyntaxKind.SubKeyword : SyntaxKind.FunctionKeyword; + var endStatement = isSub ? SyntaxFactory.EndSubStatement() : SyntaxFactory.EndFunctionStatement(); + + return SyntaxFactory.MethodBlock(blockKind, + SyntaxFactory.MethodStatement(statementKind, + SyntaxFactory.Token(keyword), identifier) + .WithModifiers(modifiersSyntax) + .WithAsClause(SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName(returnType))), + endStatement).WithStatements(body).NormalizeWhitespace(); + } + } } \ No newline at end of file From 0b486456b57dcea3ec92dc5883801643fbfef62d Mon Sep 17 00:00:00 2001 From: longachr Date: Tue, 31 May 2022 13:17:51 -0700 Subject: [PATCH 20/61] update vb action loader with more actions --- .../VisualBasicActionsLoader.cs | 139 ++++++++++--- src/CTA.Rules.Config/Constants.cs | 2 + .../Actions/VisualBasic/ActionsLoaderTests.cs | 188 ++++++++++++++++++ 3 files changed, 296 insertions(+), 33 deletions(-) diff --git a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs index e70a2c1f..1525ac60 100644 --- a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs +++ b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using Codelyzer.Analysis.Model; using CTA.Rules.Config; using CTA.Rules.Models; using Microsoft.CodeAnalysis; @@ -15,13 +16,27 @@ public class VisualBasicActionsLoader : ActionLoaderBase private readonly List _compilationUnitActions, _invocationExpressionActions, _namespaceActions, - _identifierNameActions; + _identifierNameActions, + _attributeActions, + _attributeListActions, + _typeBlockActions, + _elementAccessActions, + _expressionActions, + _interfaceActions, + _methodBlockActions; private readonly object _compilationUnitObject, _invocationExpressionObject, _namespaceObject, - _identifierNameObject; + _identifierNameObject, + _attributeObject, + _attributeListObject, + _typeBlockObject, + _elementAccessObject, + _expressionObject, + _interfaceObject, + _methodBlockObject; /// /// Initializes a new ActionLoader that loads the default actions @@ -33,6 +48,13 @@ public VisualBasicActionsLoader(List assemblyPaths) _invocationExpressionActions = new List(); _namespaceActions = new List(); _identifierNameActions = new List (); + _attributeActions = new List (); + _attributeListActions = new List (); + _typeBlockActions = new List (); + _elementAccessActions = new List (); + _expressionActions = new List (); + _interfaceActions = new List (); + _methodBlockActions = new List (); projectLevelActions = new List(); projectFileActions = new List(); projectTypeActions = new List(); @@ -53,6 +75,20 @@ public VisualBasicActionsLoader(List assemblyPaths) out _invocationExpressionObject); TryCreateInstance(Constants.NamespaceActions, types, out _namespaceObject); + TryCreateInstance(Constants.AttributeActions, types, + out _attributeObject); + TryCreateInstance(Constants.AttributeListActions, types, + out _attributeListObject); + TryCreateInstance(Constants.TypeBlockActions, types, + out _typeBlockObject); + TryCreateInstance(Constants.ElementAccessActions, types, + out _elementAccessObject); + TryCreateInstance(Constants.ExpressionActions, types, + out _expressionObject); + TryCreateInstance(Constants.InterfaceActions, types, + out _interfaceObject); + TryCreateInstance(Constants.MethodBlockActions, types, + out _methodBlockObject); TryCreateInstance(Constants.ProjectLevelActions, types, out projectLevelObject); TryCreateInstance(Constants.ProjectFileActions, types, out projectFileObject); TryCreateInstance(Constants.ProjectTypeActions, types, out projectTypeObject); @@ -97,6 +133,46 @@ public VisualBasicActionsLoader(List assemblyPaths) _identifierNameActions.AddRange(GetFuncMethods(t)); break; } + case Constants.AttributeActions: + { + _attributeActions.AddRange(GetFuncMethods(t)); + break; + } + case Constants.AttributeListActions: + { + _attributeListActions.AddRange(GetFuncMethods(t)); + break; + } + case Constants.TypeBlockActions: + { + _typeBlockActions.AddRange(GetFuncMethods(t)); + break; + } + case Constants.InterfaceActions: + { + _interfaceActions.AddRange(GetFuncMethods(t)); + break; + } + case Constants.ExpressionActions: + { + _expressionActions.AddRange(GetFuncMethods(t)); + break; + } + case Constants.MethodBlockActions: + { + _methodBlockActions.AddRange(GetFuncMethods(t)); + break; + } + case Constants.ElementAccessActions: + { + _elementAccessActions.AddRange(GetFuncMethods(t)); + break; + } + case Constants.ObjectCreationExpressionActions: + { + //_objectCreationExpressionActions.AddRange(GetFuncMethods(t)); + break; + } default: { LogHelper.LogError($"Action type {t.Name} is not found"); @@ -127,27 +203,28 @@ public Func GetCo public Func GetAttributeAction(string name, dynamic value) { - throw new NotImplementedException(); + return GetAction> + (_attributeActions, _attributeObject, name, value); } public Func GetAttributeListAction(string name, dynamic value) { - throw new NotImplementedException(); + return GetAction> + (_attributeListActions, _attributeListObject, name, value); } - - /* - public Func GetClassAction(string name, dynamic value) + + public Func GetClassAction(string name, dynamic value) { - throw new NotImplementedException(); + return GetAction> + (_typeBlockActions, _typeBlockObject, name, value); } - */ - /* - public Func GetInterfaceAction(string name, dynamic value) + + public Func GetInterfaceAction(string name, dynamic value) { - throw new NotImplementedException(); + return GetAction> + (_interfaceActions, _interfaceObject, name, value); } - */ - + public Func GetIdentifierNameAction(string name, dynamic value) { return GetAction> @@ -156,37 +233,33 @@ public Func GetIden public Func GetExpressionAction(string name, dynamic value) { - throw new NotImplementedException(); + return GetAction> + (_expressionActions, _expressionObject, name, value); } - - /* - public Func GetMethodDeclarationAction(string name, dynamic value) - { - throw new NotImplementedException(); - } - */ - public Func GetNamespaceActions(string name, dynamic value) + public Func GetMethodDeclarationAction(string name, dynamic value) { - return GetAction> - (_namespaceActions, _namespaceObject, name, value); + return GetAction> + (_methodBlockActions, _methodBlockObject, name, value); } - - public Func GetObjectCreationExpressionActions(string name, dynamic value) + public Func GetNamespaceActions(string name, + dynamic value) { - throw new NotImplementedException(); + return GetAction> + (_namespaceActions, _namespaceObject, name, value); } - /* - public Func GetElementAccessExpressionActions(string name, dynamic value) + public Func GetObjectCreationExpressionActions( + string name, dynamic value) { throw new NotImplementedException(); } - */ - public Func GetMemberAccessExpressionActions(string name, dynamic value) + public Func + GetElementAccessExpressionActions(string name, dynamic value) { - throw new NotImplementedException(); + return GetAction> + (_elementAccessActions, _elementAccessObject, name, value); } } diff --git a/src/CTA.Rules.Config/Constants.cs b/src/CTA.Rules.Config/Constants.cs index 0105f266..95e8da0b 100644 --- a/src/CTA.Rules.Config/Constants.cs +++ b/src/CTA.Rules.Config/Constants.cs @@ -84,6 +84,8 @@ public class Constants public const string InterfaceActions = "InterfaceActions"; public const string ProjectFileActions = "ProjectFileActions"; public const string ProjectTypeActions = "ProjectTypeActions"; + public const string TypeBlockActions = "TypeBlockActions"; + public const string MethodBlockActions = "MethodBlockActions"; public const string ProjectRecommendationFile = "project.all"; diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs index 57fdb061..43a13788 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs @@ -55,5 +55,193 @@ public void NamespaceActionsTest() Assert.IsNotNull(renameNamespace); } + + [Test] + public void AttributeActionsTest() + { + var changeAttribute = _actionLoader.GetAttributeAction("ChangeAttribute", "attributeName"); + + Assert.IsNotNull(changeAttribute); + } + + [Test] + public void AttributeListActionsTest() + { + var addComment = _actionLoader.GetAttributeListAction("AddComment", "comment"); + + Assert.IsNotNull(addComment); + } + + [Test] + public void ClassActionsTest() + { + var removeBaseClass = _actionLoader.GetClassAction("RemoveBaseClass", "baseClass"); + var addBaseClass = _actionLoader.GetClassAction("AddBaseClass", "baseClass"); + var changeName = _actionLoader.GetClassAction("ChangeName", "className"); + var removeAttribute = _actionLoader.GetClassAction("RemoveAttribute", "attributeName"); + var addAttribute = _actionLoader.GetClassAction("AddAttribute", "attribute"); + var addComment = _actionLoader.GetClassAction("AddComment", "{comment: \"comment here\", dontUseCTAPrefix: \"true\"}"); + var addComment2 = _actionLoader.GetClassAction("AddComment", "comment"); + var addMethod = _actionLoader.GetClassAction("AddMethod", "expression"); + var removeMethod = _actionLoader.GetClassAction("RemoveMethod", "methodName"); + var renameClass = _actionLoader.GetClassAction("RenameClass", "newClassName"); + var replaceMethodModifiers = _actionLoader.GetClassAction("ReplaceMethodModifiers", "{ methodName: \"\", modifiers: \"\"}"); + var addExpression = _actionLoader.GetClassAction("AddExpression", "expression"); + var removeConstructorInitializer = _actionLoader.GetClassAction("RemoveConstructorInitializer", "baseClass"); + var appendConstructorExpression = _actionLoader.GetClassAction("AppendConstructorExpression", "expression"); + var createConstructor = _actionLoader.GetClassAction("CreateConstructor", "{ types: \"type\", identifiers: \"identify\"}"); + var changeMethodName = _actionLoader.GetClassAction("ChangeMethodName", "{ existingMethodName: \"method\", newMethodName: \"newMethod\"}"); + var changeMethodToReturnTaskType = _actionLoader.GetClassAction("ChangeMethodToReturnTaskType", "methodName"); + var removeMethodParameters = _actionLoader.GetClassAction("RemoveMethodParameters", "methodName"); + var commentMethod = _actionLoader.GetClassAction("CommentMethod", "{ methodName: \"SuperMethod\", comment: \"comment here\", dontUseCTAPrefix: \"true\"}"); + var addCommentsToMethod = _actionLoader.GetClassAction("AddCommentsToMethod", "{ methodName: \"SuperMethod\", comment: \"comments here\", dontUseCTAPrefix: \"false\"}"); + var addCommentsToMethod2 = _actionLoader.GetClassAction("AddCommentsToMethod", "{ methodName: \"SuperMethod\", comment: \"comments here\" }"); + var addExpressionToMethod = _actionLoader.GetClassAction("AddExpressionToMethod", "{ methodName: \"DuperMethod\", expression: \"var maths = 1+1;\"}"); + var addParametersToMethod = _actionLoader.GetClassAction("AddParametersToMethod", "{ methodName: \"MethodHere\", types: \"type\", identifiers: \"identifier\"}"); + var replaceWebApiControllerMethodsBody = _actionLoader.GetClassAction("ReplaceWebApiControllerMethodsBody", "expression"); + + Assert.IsNotNull(removeBaseClass); + Assert.IsNotNull(addBaseClass); + Assert.IsNotNull(changeName); + Assert.IsNotNull(removeAttribute); + Assert.IsNotNull(addAttribute); + Assert.IsNotNull(addComment); + Assert.IsNotNull(addComment2); + Assert.IsNotNull(addMethod); + Assert.IsNotNull(removeMethod); + Assert.IsNotNull(renameClass); + Assert.IsNotNull(replaceMethodModifiers); + Assert.IsNotNull(addExpression); + Assert.IsNotNull(removeConstructorInitializer); + Assert.IsNotNull(appendConstructorExpression); + Assert.IsNotNull(createConstructor); + Assert.IsNotNull(changeMethodName); + Assert.IsNotNull(changeMethodToReturnTaskType); + Assert.IsNotNull(removeMethodParameters); + Assert.IsNotNull(commentMethod); + Assert.IsNotNull(addCommentsToMethod); + Assert.IsNotNull(addCommentsToMethod2); + Assert.IsNotNull(addExpressionToMethod); + Assert.IsNotNull(addParametersToMethod); + Assert.IsNotNull(replaceWebApiControllerMethodsBody); + } + + [Test] + public void ElementAccessActionsTest() + { + var replaceElementAccess = _actionLoader.GetElementAccessExpressionActions("ReplaceElementAccess", "newExpression"); + var addComment = _actionLoader.GetElementAccessExpressionActions("AddComment", "comment"); + + Assert.IsNotNull(replaceElementAccess); + Assert.IsNotNull(addComment); + } + + [Test] + public void ExpressionActionsTest() + { + var addAwaitOperator = _actionLoader.GetExpressionAction("AddAwaitOperator", "string"); + var addComment = _actionLoader.GetExpressionAction("AddComment", "comment"); + + Assert.IsNotNull(addAwaitOperator); + Assert.IsNotNull(addComment); + } + + [Test] + public void IdentifierNameActionsTest() + { + var replaceIdentifier = _actionLoader.GetIdentifierNameAction("ReplaceIdentifier", "identifierName"); + var replaceIdentifierInsideClass = _actionLoader.GetIdentifierNameAction("ReplaceIdentifierInsideClass", "{ identifier: \"identifier\", classFullKey: \"classKey\" }"); + + Assert.IsNotNull(replaceIdentifier); + Assert.IsNotNull(replaceIdentifierInsideClass); + } + + [Test] + public void InterfaceActionsTest() + { + var changeName = _actionLoader.GetInterfaceAction("ChangeName", "newName"); + var removeAttribute = _actionLoader.GetInterfaceAction("RemoveAttribute", "attributeName"); + var addAttribute = _actionLoader.GetInterfaceAction("AddAttribute", "attribute"); + var addComment = _actionLoader.GetInterfaceAction("AddComment", "comment"); + var addMethod = _actionLoader.GetInterfaceAction("AddMethod", "expression"); + var removeMethod = _actionLoader.GetInterfaceAction("RemoveMethod", "methodName"); + + Assert.IsNotNull(changeName); + Assert.IsNotNull(addComment); + Assert.IsNotNull(removeAttribute); + Assert.IsNotNull(addAttribute); + Assert.IsNotNull(addMethod); + Assert.IsNotNull(removeMethod); + } + + [Test] + public void MethodBlockActionsTest() + { + var addComment = _actionLoader.GetClassAction("AddComment", "{comment: \"comment here\", dontUseCTAPrefix: \"true\"}"); + var addComment2 = _actionLoader.GetClassAction("AddComment", "comment"); + var appendExpression = _actionLoader.GetMethodDeclarationAction("AppendExpression", "expression"); + var changeMethodName = _actionLoader.GetMethodDeclarationAction("ChangeMethodName", "newMethodName"); + var changeMethodToReturnTaskType = _actionLoader.GetMethodDeclarationAction("ChangeMethodToReturnTaskType", "{}"); + var removeMethodParameters = _actionLoader.GetMethodDeclarationAction("RemoveMethodParameters", null); + var addParametersToMethod = _actionLoader.GetMethodDeclarationAction("AddParametersToMethod", "{ types: \"type\", identifiers: \"identifiers\" }"); + var commentMethod = _actionLoader.GetMethodDeclarationAction("CommentMethod", "{ comment: \"comment\", dontUseCTAPrefix: \"true\" }"); + var commentMethod2 = _actionLoader.GetMethodDeclarationAction("CommentMethod", "{ comment: \"comment\" }"); + var addExpressionToMethod = _actionLoader.GetMethodDeclarationAction("AddExpressionToMethod", "expression"); + + Assert.IsNotNull(addComment); + Assert.IsNotNull(addComment2); + Assert.IsNotNull(appendExpression); + Assert.IsNotNull(changeMethodName); + Assert.IsNotNull(changeMethodToReturnTaskType); + Assert.IsNotNull(removeMethodParameters); + Assert.IsNotNull(addParametersToMethod); + Assert.IsNotNull(commentMethod); + Assert.IsNotNull(commentMethod2); + Assert.IsNotNull(addExpressionToMethod); + } + + [Test] + public void ObjectCreationExpressionActionsTest() + { + var replaceObjectinitialization = _actionLoader.GetObjectCreationExpressionActions("ReplaceObjectinitialization", "newStatement"); + var replaceObjectWithInvocation = _actionLoader.GetObjectCreationExpressionActions("ReplaceObjectWithInvocation", "{ NewExpression: \"expression\", UseParameters: \"params\" }"); + var replaceOrAddObjectPropertyIdentifier = _actionLoader.GetObjectCreationExpressionActions("ReplaceOrAddObjectPropertyIdentifier", "{ oldMember: \"old\", newMember: \"new\", newValueIfAdding: \"value\" }"); + var replaceOrAddObjectPropertyIdentifier2 = _actionLoader.GetObjectCreationExpressionActions("ReplaceOrAddObjectPropertyIdentifier", "{ oldMember: \"old\", newMember: \"new\" }"); + var replaceObjectPropertyValue = _actionLoader.GetObjectCreationExpressionActions("ReplaceObjectPropertyValue", "{ oldMember: \"old\", newMember: \"new\" }"); + var addComment = _actionLoader.GetObjectCreationExpressionActions("AddComment", "comment"); + + Assert.IsNotNull(replaceObjectinitialization); + Assert.IsNotNull(replaceObjectWithInvocation); + Assert.IsNotNull(replaceOrAddObjectPropertyIdentifier); + Assert.IsNotNull(replaceOrAddObjectPropertyIdentifier2); + Assert.IsNotNull(replaceObjectPropertyValue); + Assert.IsNotNull(addComment); + } + + [Test] + public void ProjectFileActionsTest() + { + var migrateProjectFile = _actionLoader.GetProjectFileActions("MigrateProjectFile", "string"); + + Assert.IsNotNull(migrateProjectFile); + } + + [Test] + public void ProjectLevelActionsTest() + { + var archiveFiles = _actionLoader.GetProjectLevelActions("ArchiveFiles", "archiveFiles"); + var createNet3FolderHierarchy = _actionLoader.GetProjectLevelActions("CreateNet3FolderHierarchy", "string"); + var createNet5FolderHierarchy = _actionLoader.GetProjectLevelActions("CreateNet5FolderHierarchy", "string"); + var createNet6FolderHierarchy = _actionLoader.GetProjectLevelActions("CreateNet6FolderHierarchy", "string"); + var migrateConfig = _actionLoader.GetProjectLevelActions("MigrateConfig", "string"); + var createMonolithService = _actionLoader.GetProjectLevelActions("CreateMonolithService", "{ namespaceString: \"namespace\", projectName: \"project\" }"); + + Assert.IsNotNull(archiveFiles); + Assert.IsNotNull(createNet3FolderHierarchy); + Assert.IsNotNull(createNet5FolderHierarchy); + Assert.IsNotNull(createNet6FolderHierarchy); + Assert.IsNotNull(migrateConfig); + Assert.IsNotNull(createMonolithService); + } } } \ No newline at end of file From 9ab3926e18ed277b2c631d211dea65dcad6efe94 Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 1 Jun 2022 19:58:37 -0700 Subject: [PATCH 21/61] rename class action to type block for modules --- .../Actions/VisualBasic/ClassActionsTests.cs | 73 +++++++++---------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs index dbe59ccf..6ce6ba0c 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs @@ -7,14 +7,14 @@ using NUnit.Framework; using System.Collections.Generic; using System.Linq; -using AttributeSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax; +using CTA.Rules.Models.VisualBasic; namespace CTA.Rules.Test.Actions.VisualBasic { public class ClassActionsTests { private SyntaxGenerator _syntaxGenerator; - private ClassActions _classActions; + private TypeBlockActions _typeBlockActions; private ClassBlockSyntax _node; private MethodBlockSyntax _subNode; private MethodBlockSyntax _functionNode; @@ -28,7 +28,7 @@ public void SetUp() var workspace = new AdhocWorkspace(); var language = LanguageNames.VisualBasic; _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); - _classActions = new ClassActions(); + _typeBlockActions = new TypeBlockActions(); SyntaxTree tree = VisualBasicSyntaxTree.ParseText(@$"Class MyClass End Class @@ -74,7 +74,7 @@ Module MyModule public void GetAddCommentAction_Adds_Leading_Comment_To_Class_Declaration(string blockType) { const string commentToAdd = "This is a comment"; - var addCommentFunc = _classActions.GetAddCommentAction(commentToAdd); + var addCommentFunc = _typeBlockActions.GetAddCommentAction(commentToAdd); var newNode = addCommentFunc(_syntaxGenerator, _blockNodes[blockType]); var expectedResult = @$"' Added by CTA: {commentToAdd} @@ -88,7 +88,7 @@ public void GetAddCommentAction_Adds_Leading_Comment_To_Class_Declaration(string public void GetChangeNameAction_Changes_Class_Name_To_Specified_Value(string blockType) { const string newClassName = "NewClassName"; - var changeNameFunc = _classActions.GetChangeNameAction(newClassName); + var changeNameFunc = _typeBlockActions.GetChangeNameAction(newClassName); var newNode = changeNameFunc(_syntaxGenerator, _blockNodes[blockType]); Assert.AreEqual(newClassName, newNode.BlockStatement.Identifier.ToString()); } @@ -99,7 +99,7 @@ public void GetChangeNameAction_Changes_Class_Name_To_Specified_Value(string blo public void GetRenameClassAction_Changes_Class_Name_To_Specified_Value(string blockType) { const string newClassName = "NewClassName"; - var changeNameFunc = _classActions.GetRenameClassAction(newClassName); + var changeNameFunc = _typeBlockActions.GetRenameClassAction(newClassName); var newNode = changeNameFunc(_syntaxGenerator, _blockNodes[blockType]); Assert.AreEqual(newClassName, newNode.BlockStatement.Identifier.ToString()); } @@ -111,13 +111,13 @@ public void GetRemoveAttributeAction_Removes_Specified_Attribute(string blockTyp { const string attributeToRemove = "Serializable"; var node = _blockNodes[blockType]; - var addAttributeFunc1 = _classActions.GetAddAttributeAction("Serializable"); - var addAttributeFunc2 = _classActions.GetAddAttributeAction("SecurityCritical"); + var addAttributeFunc1 = _typeBlockActions.GetAddAttributeAction("Serializable"); + var addAttributeFunc2 = _typeBlockActions.GetAddAttributeAction("SecurityCritical"); var nodeWithAttributes = addAttributeFunc1(_syntaxGenerator, node); nodeWithAttributes = addAttributeFunc2(_syntaxGenerator, nodeWithAttributes); - var removeAttributeFunc = _classActions.GetRemoveAttributeAction(attributeToRemove); + var removeAttributeFunc = _typeBlockActions.GetRemoveAttributeAction(attributeToRemove); var newNode = removeAttributeFunc(_syntaxGenerator, nodeWithAttributes); Assert.IsTrue(newNode.BlockStatement.AttributeLists.ToFullString().Contains("")); Assert.IsTrue(!newNode.BlockStatement.AttributeLists.ToFullString().Contains("", newNode.BlockStatement.AttributeLists.ToString()); } @@ -151,7 +151,7 @@ Return i End Function", "module")] public void GetAddMethodAction_Adds_Method(string expression, string blockType) { - var addMethodFunc = _classActions.GetAddMethodAction(expression); + var addMethodFunc = _typeBlockActions.GetAddMethodAction(expression); var newNode = addMethodFunc(_syntaxGenerator, _blockNodes[blockType]); Assert.AreEqual(expression, newNode.Members.OfType().FirstOrDefault()?.ToString()); } @@ -166,7 +166,7 @@ public void GetRemoveMethodAction_Removes_Specified_Method(string blockType) SyntaxFactory.Token(SyntaxKind.SubKeyword), methodName); var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); - var removeMethodFunc = _classActions.GetRemoveMethodAction(methodName); + var removeMethodFunc = _typeBlockActions.GetRemoveMethodAction(methodName); var newNode = removeMethodFunc(_syntaxGenerator, nodeWithMethod); var expectedResult = _blockNodes[blockType].NormalizeWhitespace().ToFullString(); @@ -179,8 +179,8 @@ public void GetRemoveMethodAction_Removes_Specified_Method(string blockType) public void RemoveLastBaseClass(string blockType) { var baseClassname = "ControllerBase"; - var addBaseClass = _classActions.GetAddBaseClassAction(baseClassname); - var removeBaseClassMethod = _classActions.GetRemoveBaseClassAction(baseClassname); + var addBaseClass = _typeBlockActions.GetAddBaseClassAction(baseClassname); + var removeBaseClassMethod = _typeBlockActions.GetRemoveBaseClassAction(baseClassname); var nodeWithClass = addBaseClass(_syntaxGenerator, _blockNodes[blockType]); nodeWithClass = removeBaseClassMethod(_syntaxGenerator, nodeWithClass); @@ -200,7 +200,7 @@ public void ReplaceMethodModifiers(string blockType) var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); var modifier = "Private Async"; - var replaceModifier = _classActions.GetReplaceMethodModifiersAction(methodName, modifier); + var replaceModifier = _typeBlockActions.GetReplaceMethodModifiersAction(methodName, modifier); var node = replaceModifier(_syntaxGenerator, nodeWithMethod); @@ -214,7 +214,7 @@ public void AddExpression(string blockType) { string expression = "Dim _next As RequestDelegate"; - var addBaseClass = _classActions.GetAddExpressionAction(expression); + var addBaseClass = _typeBlockActions.GetAddExpressionAction(expression); var nodeWithExpression = addBaseClass(_syntaxGenerator, _blockNodes[blockType]); @@ -236,7 +236,7 @@ public void AppendConstructorExpression(string blockType) var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); string expression = "_next = [next]"; - var addBaseClass = _classActions.GetAppendConstructorExpressionAction(expression); + var addBaseClass = _typeBlockActions.GetAppendConstructorExpressionAction(expression); var nodeWithExpression = addBaseClass(_syntaxGenerator, nodeWithMethod); @@ -262,7 +262,7 @@ public void RemoveConstructorBaseInitializer(string blockType) var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); string expression = "next"; - var addBaseClass = _classActions.GetRemoveConstructorInitializerAction(expression); + var addBaseClass = _typeBlockActions.GetRemoveConstructorInitializerAction(expression); var nodeWithExpression = addBaseClass(_syntaxGenerator, nodeWithMethod); @@ -277,7 +277,7 @@ public void CreateConstructor(string blockType) string types = "RequestDelegate, string"; string identifiers = "[next], value"; - var createConstructorFunc = _classActions.GetCreateConstructorAction(types: types, identifiers: identifiers); + var createConstructorFunc = _typeBlockActions.GetCreateConstructorAction(types: types, identifiers: identifiers); var nodeWithExpression = createConstructorFunc(_syntaxGenerator, _blockNodes[blockType]); StringAssert.Contains(types.Split(',')[0], nodeWithExpression.ToFullString()); @@ -314,7 +314,7 @@ public void ChangeMethodName(bool isSubMethod, string blockType) var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); - var changeMethodNameFunc = _classActions.GetChangeMethodNameAction(existingMethodName, newMethodName); + var changeMethodNameFunc = _typeBlockActions.GetChangeMethodNameAction(existingMethodName, newMethodName); var nodeWithExpression = changeMethodNameFunc(_syntaxGenerator, nodeWithMethod); StringAssert.Contains(newMethodName, nodeWithExpression.ToFullString()); @@ -337,7 +337,7 @@ public void RemoveMethodParameters(string blockType) _subNode.SubOrFunctionStatement.WithParameterList( SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters)))); var nodeWithMethod = _blockNodes[blockType].AddMembers(methodNode); - var removeMethodParametersFunc = _classActions.GetRemoveMethodParametersAction(methodName); + var removeMethodParametersFunc = _typeBlockActions.GetRemoveMethodParametersAction(methodName); var nodeWithExpression = removeMethodParametersFunc(_syntaxGenerator, nodeWithMethod); StringAssert.DoesNotContain("HttpContext", nodeWithExpression.ToFullString()); } @@ -349,7 +349,7 @@ public void ChangeMethodReturnTaskTypeVoid(string blockType) { string methodName = "Invoke"; var nodeWithMethod = _blockNodes[blockType].AddMembers(_subNode); - var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); + var changeMethodToReturnTaskTypeFunc = _typeBlockActions.GetChangeMethodToReturnTaskTypeAction(methodName); var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); StringAssert.Contains("Task", nodeWithExpression.ToFullString()); } @@ -361,7 +361,7 @@ public void ChangeMethodReturnTaskTypeString(string blockType) { string methodName = "TestFunction"; var nodeWithMethod = _blockNodes[blockType].AddMembers(_functionNode); - var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); + var changeMethodToReturnTaskTypeFunc = _typeBlockActions.GetChangeMethodToReturnTaskTypeAction(methodName); var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); StringAssert.Contains("Task(Of String)", nodeWithExpression.ToFullString()); } @@ -374,7 +374,7 @@ public void CommentMethod(string blockType) string methodName = "Invoke"; var nodeWithMethod = _blockNodes[blockType].AddMembers(_subNode); - var commentMethodeFunc = _classActions.GetCommentMethodAction(methodName); + var commentMethodeFunc = _typeBlockActions.GetCommentMethodAction(methodName); var nodeWithExpression = commentMethodeFunc(_syntaxGenerator, nodeWithMethod); StringAssert.Contains("' Public Sub Invoke", nodeWithExpression.ToFullString()); @@ -389,7 +389,7 @@ public void AddCommentsToMethod(string blockType) string comment = "This method is deprecated"; var nodeWithMethod = _blockNodes[blockType].AddMembers(_subNode); - var addCommentsToMethodFunc = _classActions.GetAddCommentsToMethodAction(methodName, comment); + var addCommentsToMethodFunc = _typeBlockActions.GetAddCommentsToMethodAction(methodName, comment); var nodeWithExpression = addCommentsToMethodFunc(_syntaxGenerator, nodeWithMethod); StringAssert.Contains("' Added by CTA: This method is deprecated", nodeWithExpression.ToFullString()); @@ -403,10 +403,10 @@ public void AddExpressionToMethod(string blockType) string methodName = "TestFunction"; string expression = "Await _next.Invoke(context)"; var nodeWithMethod = _blockNodes[blockType].AddMembers(_functionNode); - var changeMethodToReturnTaskTypeFunc = _classActions.GetChangeMethodToReturnTaskTypeAction(methodName); + var changeMethodToReturnTaskTypeFunc = _typeBlockActions.GetChangeMethodToReturnTaskTypeAction(methodName); var nodeWithExpression = changeMethodToReturnTaskTypeFunc(_syntaxGenerator, nodeWithMethod); - var addExpressionToMethodFunc = _classActions.GetAddExpressionToMethodAction(methodName, expression); + var addExpressionToMethodFunc = _typeBlockActions.GetAddExpressionToMethodAction(methodName, expression); nodeWithExpression = addExpressionToMethodFunc(_syntaxGenerator, nodeWithExpression); StringAssert.Contains("Await _next.Invoke(context)", nodeWithExpression.ToFullString()); @@ -424,7 +424,7 @@ public void AddParametersToMethod(string blockType) var nodeWithMethod = _blockNodes[blockType].AddMembers(_subNode); var addParametersToMethodFunc = - _classActions.GetAddParametersToMethodAction(methodName, types, identifiers); + _typeBlockActions.GetAddParametersToMethodAction(methodName, types, identifiers); var nodeWithExpression = addParametersToMethodFunc(_syntaxGenerator, nodeWithMethod); var expectedString = @"Public Sub Invoke(context As HttpContext, value As String)"; @@ -460,8 +460,8 @@ public void ReplacePublicMethodsBody(string controller) "String")); var replacePublicMethodsBodyFunc = controller == "WebApiController" - ? _classActions.GetReplaceWebApiControllerMethodsBodyAction(newBody) - : _classActions.GetReplaceCoreControllerMethodsBodyAction(newBody); + ? _typeBlockActions.GetReplaceWebApiControllerMethodsBodyAction(newBody) + : _typeBlockActions.GetReplaceCoreControllerMethodsBodyAction(newBody); var newNode = replacePublicMethodsBodyFunc(_syntaxGenerator, nodeWithMethods.NormalizeWhitespace()); var publicMembers = newNode.Members.OfType().Where(m => @@ -476,13 +476,12 @@ public void ReplacePublicMethodsBody(string controller) [Test] public void ClassDeclarationEquals() { - throw new NotImplementedException(); - // var classAction = new ClassDeclarationAction() { Key = "Test", Value = "Test2", ClassDeclarationActionFunc = _classActions.GetAddAttributeAction("Test") }; - // var cloned = classAction.Clone(); - // Assert.True(classAction.Equals(cloned)); - // - // cloned.Value = "DifferentValue"; - // Assert.False(classAction.Equals(cloned)); + var classAction = new TypeBlockAction() { Key = "Test", Value = "Test2", TypeBlockActionFunc = _typeBlockActions.GetAddAttributeAction("Test") }; + var cloned = classAction.Clone(); + Assert.True(classAction.Equals(cloned)); + + cloned.Value = "DifferentValue"; + Assert.False(classAction.Equals(cloned)); } private MethodBlockSyntax CreateMethodNode(string identifier, From 636429e800cc6dc87742bd1409d3cf40a23a356f Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 1 Jun 2022 20:05:25 -0700 Subject: [PATCH 22/61] rename class action to type block action --- .../VisualBasic/{ClassActions.cs => TypeBlockActions.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/CTA.Rules.Actions/VisualBasic/{ClassActions.cs => TypeBlockActions.cs} (99%) diff --git a/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs b/src/CTA.Rules.Actions/VisualBasic/TypeBlockActions.cs similarity index 99% rename from src/CTA.Rules.Actions/VisualBasic/ClassActions.cs rename to src/CTA.Rules.Actions/VisualBasic/TypeBlockActions.cs index f04ff862..47aecf12 100644 --- a/src/CTA.Rules.Actions/VisualBasic/ClassActions.cs +++ b/src/CTA.Rules.Actions/VisualBasic/TypeBlockActions.cs @@ -12,7 +12,7 @@ namespace CTA.Rules.Actions.VisualBasic /// /// List of actions that can run on Class Blocks /// - public class ClassActions + public class TypeBlockActions { public Func GetRemoveBaseClassAction(string baseClass) { From 58ec8418d0cabba50fdc9f4379d157a95a48975d Mon Sep 17 00:00:00 2001 From: longachr Date: Thu, 2 Jun 2022 08:59:49 -0700 Subject: [PATCH 23/61] Add type block, class and module, to rule analysis --- .../VisualBasicRulesAnalysis.cs | 96 ++++++++++++------- .../Actions/VisualBasic/TypeBlockAction.cs | 24 +++++ .../FileActions/FileActions.cs | 15 +-- .../VisualBasic/ImportStatementToken.cs | 1 - .../Tokens/VisualBasic/TypeBlockToken.cs | 19 ++++ .../VisualBasic/VisualBasicNodeToken.cs | 7 ++ .../VisualBasic/VisualBasicRootNodes.cs | 2 + .../VisualBasicRulesFileParser.cs | 24 +++-- .../VisualBasicActionsRewriter.cs | 6 +- 9 files changed, 141 insertions(+), 53 deletions(-) create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/TypeBlockAction.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/TypeBlockToken.cs diff --git a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs index 5fea802c..509d0dcb 100644 --- a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs @@ -111,7 +111,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { break; } - case IdConstants.UsingDirectiveIdName: + case IdConstants.ImportsStatementName: { var overrideKey = string.Empty; @@ -123,7 +123,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, containsActions = true; } - //Attempt a wildcard search, if applicable. This is using directive specific because it might want to include all sub-namespaces + //Attempt a wildcard search, if applicable. This is import specific because it might want to include all sub-namespaces if (token == null) { var wildcardMatches = _visualBasicRootNodes.ImportStatementTokens @@ -146,7 +146,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, } break; } - case IdConstants.NamespaceIdName: + case IdConstants.NamespaceBlockIdName: { var compareToken = new NamespaceToken { Key = child.Identifier }; _visualBasicRootNodes.NamespaceTokens.TryGetValue(compareToken, out var token); @@ -161,8 +161,60 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, } break; } - case IdConstants.ClassIdName: + case IdConstants.ModuleBlockName: { + var moduleType = (ModuleBlock)child; + var name = string.Concat( + moduleType.Reference != null + ? string.Concat(moduleType.Reference.Namespace, ".") + : string.Empty, moduleType.Identifier); + var nameToken = new TypeBlockToken() { FullKey = name }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out var token)) + { + AddNamedActions(fileAction, token, moduleType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + break; + } + case IdConstants.ClassBlockName: + { + var classType = (ClassBlock)child; + var baseToken = new TypeBlockToken() { FullKey = classType.BaseType }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseToken, out var token)) + { + AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + token = null; + var name = string.Concat( + classType.Reference != null + ? string.Concat(classType.Reference.Namespace, ".") + : string.Empty, classType.Identifier); + var nameToken = new TypeBlockToken() { FullKey = name }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out token)) + { + AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + token = null; + foreach (string interfaceName in classType.Inherits) + { + var baseListToken = new TypeBlockToken() { FullKey = interfaceName }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseListToken, out token)) + { + AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + token = null; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, classType.Identifier)) { containsActions = true; } break; } case IdConstants.InterfaceIdName: @@ -234,12 +286,10 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, AddActions(fileAction, token, child.TextSpan, overrideKey); containsActions = true; } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } - break; } case IdConstants.ElementAccessIdName: @@ -379,34 +429,8 @@ private void AddPackages(List packageActions, TextSpan textSpan) /// private void AddNamedActions(FileActions fileAction, VisualBasicNodeToken token, string identifier, TextSpan textSpan) { - fileAction.ClassDeclarationActions.UnionWith(token.ClassDeclarationActions - .Select(c => new ClassDeclarationAction - { - Key = identifier, - Value = c.Value, - Description = c.Description, - Name = c.Name, - Type = c.Type, - TextSpan = textSpan, - ActionValidation = c.ActionValidation, - ClassDeclarationActionFunc = c.ClassDeclarationActionFunc - })); - - fileAction.InterfaceDeclarationActions.UnionWith(token.InterfaceDeclarationActions - .Select(c => new InterfaceDeclarationAction - { - Key = identifier, - Value = c.Value, - Name = c.Name, - Type = c.Type, - Description = c.Description, - TextSpan = textSpan, - ActionValidation = c.ActionValidation, - InterfaceDeclarationActionFunc = c.InterfaceDeclarationActionFunc - })); - - fileAction.MethodDeclarationActions.UnionWith(token.MethodDeclarationActions - .Select(c => new MethodDeclarationAction + fileAction.VbTypeBlockActions.UnionWith(token.TypeBlockActions + .Select(c => new TypeBlockAction() { Key = identifier, Value = c.Value, @@ -415,9 +439,9 @@ private void AddNamedActions(FileActions fileAction, VisualBasicNodeToken token, Type = c.Type, TextSpan = textSpan, ActionValidation = c.ActionValidation, - MethodDeclarationActionFunc = c.MethodDeclarationActionFunc + TypeBlockActionFunc = c.TypeBlockActionFunc })); - + if (fileAction.ClassDeclarationActions.Any() || fileAction.InterfaceDeclarationActions.Any() || fileAction.MethodDeclarationActions.Any() || fileAction.ObjectCreationExpressionActions.Any()) { diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/TypeBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/TypeBlockAction.cs new file mode 100644 index 00000000..43460904 --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/TypeBlockAction.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; + +namespace CTA.Rules.Models.VisualBasic +{ + public class TypeBlockAction : GenericAction + { + public Func TypeBlockActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (TypeBlockAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action?.TypeBlockActionFunc.Method.Name == this.TypeBlockActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, TypeBlockActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index be1de1c4..e7a23d06 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -15,8 +15,11 @@ public FileActions() ClassDeclarationActions = new HashSet(); MethodDeclarationActions = new HashSet(); ElementAccessActions = new HashSet(); - IdentifierNameActions = new HashSet>(); - InvocationExpressionActions = new HashSet>(); + IdentifierNameActions = + new HashSet>(); + InvocationExpressionActions = + new HashSet>(); ExpressionActions = new HashSet(); MemberAccessActions = new HashSet(); Usingactions = new HashSet(); @@ -33,6 +36,7 @@ public FileActions() VbImportActions = new HashSet(); VbNamespaceActions = new HashSet>(); + VbTypeBlockActions = new HashSet(); } public HashSet> VbNamespaceActions { get; set; } @@ -41,6 +45,8 @@ public HashSet> VbIdentifierNameAction { get; set; } + public HashSet + VbTypeBlockActions { get; set; } public List VbNodeTokens { get; set; } public List NodeTokens { get; set; } @@ -64,11 +70,7 @@ public List AllActions get { var allActions = new List(); - allActions.AddRange(AttributeActions); - allActions.AddRange(MethodDeclarationActions); allActions.AddRange(ClassDeclarationActions); - allActions.AddRange(InterfaceDeclarationActions); - allActions.AddRange(ElementAccessActions); allActions.AddRange(MemberAccessActions); allActions.AddRange(IdentifierNameActions); allActions.AddRange(InvocationExpressionActions); @@ -82,6 +84,7 @@ public List AllActions allActions.AddRange(VbImportActions); allActions.AddRange(VbNamespaceActions); allActions.AddRange(VbInvocationExpressionActions); + allActions.AddRange(VbTypeBlockActions); return allActions; } } diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs index 23da982d..257c8112 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs @@ -1,5 +1,4 @@ using System; -using Microsoft.Build.Logging.StructuredLogger; namespace CTA.Rules.Models.Tokens.VisualBasic; diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/TypeBlockToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/TypeBlockToken.cs new file mode 100644 index 00000000..3cc78d53 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/TypeBlockToken.cs @@ -0,0 +1,19 @@ + +using System; +using CTA.Rules.Models.Tokens.VisualBasic; + +namespace CTA.Rules.Models.VisualBasic +{ + public class TypeBlockToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (ClassDeclarationToken)obj; + return token?.FullKey == this.FullKey; + } + public override int GetHashCode() + { + return HashCode.Combine(FullKey); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs index edf664a2..b341d34f 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs @@ -14,12 +14,16 @@ public VisualBasicNodeToken() ImportActions = new List(); NamespaceActions = new List>(); IdentifierNameActions = new List>(); + TypeBlockActions = new List(); + } public List> InvocationExpressionActions { get; set; } public List ImportActions { get; set; } public List> NamespaceActions { get; set; } public List> IdentifierNameActions { get; set; } + public List TypeBlockActions { get; set; } + public override VisualBasicNodeToken Clone() { @@ -32,6 +36,8 @@ public override VisualBasicNodeToken Clone() .Select(action => action.Clone>()).ToList(); cloned.IdentifierNameActions = cloned.IdentifierNameActions .Select(action => action.Clone>()).ToList(); + cloned.TypeBlockActions = cloned.TypeBlockActions + .Select(action => action.Clone()).ToList(); return cloned; } @@ -44,6 +50,7 @@ public override List AllActions allActions.AddRange(NamespaceActions); allActions.AddRange(ImportActions); allActions.AddRange(IdentifierNameActions); + allActions.AddRange(TypeBlockActions); allActions.AddRange(base.AllActions); return allActions; } diff --git a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs index e06ef563..50498832 100644 --- a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs +++ b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs @@ -16,6 +16,7 @@ public VisualBasicRootNodes() NamespaceTokens = new HashSet(); ProjectTokens = new HashSet(); IdentifierNameTokens = new HashSet(); + TypeBlockTokens = new HashSet(); } public HashSet InvocationExpressionTokens { get; set; } @@ -23,5 +24,6 @@ public VisualBasicRootNodes() public HashSet NamespaceTokens { get; set; } public HashSet ProjectTokens { get; set; } public HashSet IdentifierNameTokens { get; set; } + public HashSet TypeBlockTokens { get; set; } } } diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs index f599823d..10748a6d 100644 --- a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -7,7 +7,6 @@ using CTA.Rules.Models; using CTA.Rules.Models.VisualBasic; using CTA.Rules.Models.Tokens.VisualBasic; -using Microsoft.Build.Logging.StructuredLogger; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using Newtonsoft.Json; using IdentifierNameToken = CTA.Rules.Models.VisualBasic.IdentifierNameToken; @@ -148,14 +147,12 @@ public void ProcessObject(Rootobject rootobject) { if (@class.Actions != null && @class.Actions.Count > 0) { - /* - if (@class.KeyType == CTA.Rules.Config.Constants.BaseClass || @class.KeyType == CTA.Rules.Config.Constants.ClassName) + if (@class.KeyType is Constants.BaseClass or Constants.ClassName) { - var token = new ClassDeclarationToken() { Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace }; - if (!_rootNodes.Classdeclarationtokens.Contains(token)) { _rootNodes.Classdeclarationtokens.Add(token); } + var token = new TypeBlockToken() { Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace }; + if (!_visualBasicRootNodes.TypeBlockTokens.Contains(token)) { _visualBasicRootNodes.TypeBlockTokens.Add(token); } ParseActions(token, @class.Actions); } - */ if (@class.KeyType == CTA.Rules.Config.Constants.Identifier) { var token = new IdentifierNameToken @@ -453,9 +450,22 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Class: { + var actionFunc = _actionsLoader.GetClassAction(action.Name, action.Value); + if (actionFunc != null) + { + visualBasicNodeToken.TypeBlockActions.Add(new TypeBlockAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(action.Value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = action.Name, + Type = action.Type, + TypeBlockActionFunc = actionFunc + }); + } break; } - case ActionTypes.Interface: { break; diff --git a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs index 97bd01cd..5345572c 100644 --- a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs +++ b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs @@ -144,16 +144,16 @@ public override SyntaxNode VisitAttribute(AttributeSyntax node) public override SyntaxNode VisitClassBlock(ClassBlockSyntax node) { var classSymbol = SemanticHelper.GetDeclaredSymbol(node, _semanticModel, _preportSemanticModel); - ClassDeclarationSyntax newNode = (ClassDeclarationSyntax)base.VisitClassBlock(node); + ClassBlockSyntax newNode = (ClassBlockSyntax)base.VisitClassBlock(node); - foreach (var action in _allActions.OfType()) + foreach (var action in _allActions.OfType()) { if (action.Key == node.ClassStatement.Identifier.Text.Trim()) { var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; try { - newNode = action.ClassDeclarationActionFunc(_syntaxGenerator, newNode); + newNode = (ClassBlockSyntax)action.TypeBlockActionFunc(_syntaxGenerator, newNode); LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); } catch (Exception ex) From 89c3c444c74d42ae6fa10c42c51d5533b7e5c08e Mon Sep 17 00:00:00 2001 From: longachr Date: Thu, 2 Jun 2022 13:55:24 -0700 Subject: [PATCH 24/61] Put back project level actions in rule analysis --- src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs index 10748a6d..bfda08fd 100644 --- a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -65,7 +65,7 @@ public VisualBasicRulesFileParser( /// Runs the parser to merge the rules /// /// RootNodes object that contains the tokens and their associated actions - public Models.VisualBasic.VisualBasicRootNodes Process() + public VisualBasicRootNodes Process() { //Process overrides first: if (_overrideObject.NameSpaces != null) @@ -123,10 +123,8 @@ public void ProcessObject(Rootobject rootobject) //Global Actions: if (@namespace.@namespace == Constants.Project && @namespace.Assembly == Constants.Project) { - /* - var projectToken = _rootNodes.ProjectTokens.FirstOrDefault(); - ParseActions(projectToken, @namespace.Actions); - */ + var projectToken = _visualBasicRootNodes.ProjectTokens.FirstOrDefault(); + ParseActions((VisualBasicNodeToken)projectToken, @namespace.Actions); } //Namespace specific actions: else @@ -401,7 +399,7 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) var token = new ProjectToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value }; if (!_visualBasicRootNodes.ProjectTokens.Contains(token)) { _visualBasicRootNodes.ProjectTokens.Add(token); } ParseActions(token, recommendedActions.Actions); - throw new NotImplementedException(); + break; } } } From d889e627384d352064229fbbc18a5d64b2ee423f Mon Sep 17 00:00:00 2001 From: xueningl Date: Fri, 3 Jun 2022 11:40:01 -0700 Subject: [PATCH 25/61] fix build error format issue --- .../Actions/VisualBasic/ImportAction.cs | 3 ++- .../RulesFiles/RulesFileLoaderResponse.cs | 11 +++++----- .../VisualBasic/ImportStatementToken.cs | 21 ++++++++++--------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs index d0fa593d..57b639d4 100644 --- a/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs +++ b/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis.VisualBasic.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Models.VisualBasic; +namespace CTA.Rules.Models.VisualBasic { public class ImportAction : GenericAction { @@ -21,4 +21,5 @@ public override int GetHashCode() { return HashCode.Combine(Value, ImportActionFunc?.Method.Name); } +} } diff --git a/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs b/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs index 20223762..40ea0794 100644 --- a/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs +++ b/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs @@ -1,9 +1,10 @@ using CTA.Rules.Models.VisualBasic; -namespace CTA.Rules.Models.RulesFiles; - -public class RulesFileLoaderResponse +namespace CTA.Rules.Models.RulesFiles { - public CsharpRootNodes CsharpRootNodes { get; set; } - public VisualBasicRootNodes VisualBasicRootNodes { get; set; } + public class RulesFileLoaderResponse + { + public CsharpRootNodes CsharpRootNodes { get; set; } + public VisualBasicRootNodes VisualBasicRootNodes { get; set; } + } } diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs index 257c8112..3d05eafb 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/ImportStatementToken.cs @@ -1,16 +1,17 @@ using System; -namespace CTA.Rules.Models.Tokens.VisualBasic; - -public class ImportStatementToken : VisualBasicNodeToken +namespace CTA.Rules.Models.Tokens.VisualBasic { - public override bool Equals(object obj) - { - var token = (ImportStatementToken)obj; - return token?.Key == this.Key; - } - public override int GetHashCode() + public class ImportStatementToken : VisualBasicNodeToken { - return HashCode.Combine(Key); + public override bool Equals(object obj) + { + var token = (ImportStatementToken)obj; + return token?.Key == this.Key; + } + public override int GetHashCode() + { + return HashCode.Combine(Key); + } } } From c4559f2fbed99c8dd8d99ade72fdb3976d7f752b Mon Sep 17 00:00:00 2001 From: Aniruddha Dave Date: Mon, 6 Jun 2022 14:53:18 -0400 Subject: [PATCH 26/61] feat: add object creation action and test --- .../ObjectCreationExpressionActions.cs | 111 ++++++++++++++ .../ObjectCreationExpressionAction.cs | 24 +++ .../VisualBasicActionsRewriter.cs | 2 +- .../ObjectCreationExpressionActionsTests.cs | 145 ++++++++++++++++++ 4 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 src/CTA.Rules.Actions/VisualBasic/ObjectCreationExpressionActions.cs create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/ObjectCreationExpressionAction.cs create mode 100644 tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs diff --git a/src/CTA.Rules.Actions/VisualBasic/ObjectCreationExpressionActions.cs b/src/CTA.Rules.Actions/VisualBasic/ObjectCreationExpressionActions.cs new file mode 100644 index 00000000..63126ed8 --- /dev/null +++ b/src/CTA.Rules.Actions/VisualBasic/ObjectCreationExpressionActions.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis; +using CTA.Rules.Config; + + +namespace CTA.Rules.Actions.VisualBasic +{ + public class ObjectCreationExpressionActions + { + public Func GetReplaceObjectinitializationAction(string newStatement) + { + ExpressionSyntax action(SyntaxGenerator syntaxGenerator, ObjectCreationExpressionSyntax node) + { + var newNode = SyntaxFactory.ParseExpression(newStatement).NormalizeWhitespace(); + return newNode; + } + return action; + } + + public Func GetReplaceObjectWithInvocationAction(string NewExpression, string UseParameters) + { + ExpressionSyntax action(SyntaxGenerator syntaxGenerator, ObjectCreationExpressionSyntax node) + { + bool.TryParse(UseParameters, out var useParam); + + var newNode = SyntaxFactory.ParseExpression(NewExpression) as InvocationExpressionSyntax; + if (useParam) + { + newNode = newNode.WithArgumentList(node.ArgumentList); + } + return newNode.NormalizeWhitespace(); + } + return action; + } + + public Func GetReplaceOrAddObjectPropertyIdentifierAction(string oldMember, string newMember, string newValueIfAdding = null) + { + ObjectMemberInitializerSyntax action(SyntaxGenerator syntaxGenerator, ObjectMemberInitializerSyntax node) + { + if (node.Initializers.Count > 0) + { + var memberList = node.Initializers.Where(n => n.Kind() == SyntaxKind.NamedFieldInitializer); + if (memberList.Count() > 0) + { + var assignMemberList = memberList.Select(n => (NamedFieldInitializerSyntax)n); + var member = assignMemberList.Where(n => n.Name.ToFullString().Contains(oldMember)).FirstOrDefault(); + if (member != null) + { + var newExpression = SyntaxFactory.NamedFieldInitializer((IdentifierNameSyntax)syntaxGenerator.IdentifierName(newMember), member.Expression); + var newNode = node.Initializers.Replace(member, newExpression); + node = node.WithInitializers(newNode).NormalizeWhitespace(); + } + else + { + var newExpression = SyntaxFactory.NamedFieldInitializer((IdentifierNameSyntax)syntaxGenerator.IdentifierName(newMember), (IdentifierNameSyntax)syntaxGenerator.IdentifierName(newValueIfAdding)); + var newNode = node.Initializers.Add(newExpression); + node = node.WithInitializers(newNode).NormalizeWhitespace(); + } + } + } + return node; + } + return action; + } + + public Func GetReplaceObjectPropertyValueAction(string oldMember, string newMember) + { + ObjectMemberInitializerSyntax action(SyntaxGenerator syntaxGenerator, ObjectMemberInitializerSyntax node) + { + if (node.Initializers.Count > 0) + { + var memberList = node.Initializers.Where(n => n.Kind() == SyntaxKind.NamedFieldInitializer); + if (memberList.Count() > 0) + { + var assignMemberList = memberList.Select(n => (NamedFieldInitializerSyntax)n); + var member = assignMemberList.Where(n => n.Expression.ToFullString().Contains(oldMember)).FirstOrDefault(); + if (member != null) + { + var right = SyntaxFactory.ParseExpression(member.Expression.ToFullString().Replace(oldMember, newMember)); + var newExpression = SyntaxFactory.NamedFieldInitializer(member.Name, right); + var newNode = node.Initializers.Replace(member, newExpression); + node = node.WithInitializers(newNode).NormalizeWhitespace(); + } + } + } + return node; + } + return action; + } + + public Func GetAddCommentAction(string comment) + { + ObjectCreationExpressionSyntax AddComment(SyntaxGenerator syntaxGenerator, ObjectCreationExpressionSyntax node) + { + SyntaxTriviaList currentTrivia = node.GetLeadingTrivia(); + currentTrivia = currentTrivia.Add(SyntaxFactory.SyntaxTrivia(SyntaxKind.CommentTrivia, string.Format(Constants.CommentFormat, comment))); + node = node.WithLeadingTrivia(currentTrivia).NormalizeWhitespace(); + return node; + } + return AddComment; + } + + } +} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/ObjectCreationExpressionAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/ObjectCreationExpressionAction.cs new file mode 100644 index 00000000..78e3fa32 --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/ObjectCreationExpressionAction.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Models.VisualBasic +{ + public class ObjectCreationExpressionAction : GenericAction + { + public Func ObjectCreationExpressionGenericActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (ObjectCreationExpressionAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action?.ObjectCreationExpressionGenericActionFunc.Method.Name == this.ObjectCreationExpressionGenericActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Value, ObjectCreationExpressionGenericActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs index 97bd01cd..ab06eb84 100644 --- a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs +++ b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs @@ -381,7 +381,7 @@ public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressio var skipChildren = false; // This is here to skip actions on children node when the main identifier was changed. Just use new expression for the subsequent children actions. - foreach (var action in _allActions.OfType()) + foreach (var action in _allActions.OfType()) { if (newNode.ToString() == action.Key || symbol?.OriginalDefinition.ToDisplayString() == action.Key) { diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs new file mode 100644 index 00000000..4f3c417c --- /dev/null +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs @@ -0,0 +1,145 @@ +using CTA.Rules.Actions.VisualBasic; +using CTA.Rules.Models.VisualBasic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; +using NUnit.Framework; +using System; + +namespace CTA.Rules.Test.Actions.VisualBasic +{ + public class ObjectCreationExpressionActionsTests + { + private SyntaxGenerator _syntaxGenerator; + private ObjectCreationExpressionActions _objectCreationExpressionActions; + private ObjectCreationExpressionSyntax _node; + private ObjectMemberInitializerSyntax _objectMemberNode; + + [SetUp] + public void SetUp() + { + var workspace = new AdhocWorkspace(); + var language = LanguageNames.VisualBasic; + _syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, language); + _objectCreationExpressionActions = new ObjectCreationExpressionActions(); + _node = _syntaxGenerator.ObjectCreationExpression(SyntaxFactory.ParseTypeName("StringBuilder")) + .NormalizeWhitespace() as ObjectCreationExpressionSyntax; + + _node = _node.AddArgumentListArguments(SyntaxFactory.SimpleArgument( + SyntaxFactory.LiteralExpression( + SyntaxKind.StringLiteralExpression, + SyntaxFactory.Literal( + SyntaxFactory.TriviaList(), + "\"SomeText\"", + "\"SomeText\"", + SyntaxFactory.TriviaList())))); + } + + [Test] + public void GetReplaceObjectWithInvocationAction_Replaces_Constructor_With_New_Invocation_And_Preserves_Args() + { + const string newStatement = "Console.WriteLine()"; + var replaceObjectWithInvocationFunc = + _objectCreationExpressionActions.GetReplaceObjectWithInvocationAction(newStatement, "true"); + var newNode = replaceObjectWithInvocationFunc(_syntaxGenerator, _node); + + var expectedResult = "Console.WriteLine(\"SomeText\")"; + Assert.AreEqual(expectedResult, newNode.ToFullString()); + } + + + [Test] + public void ObjectCreationExpressionActionEquals() + { + var objectCreationExpressionAction = new ObjectCreationExpressionAction() { Key = "Test", Value = "Test2", ObjectCreationExpressionGenericActionFunc = _objectCreationExpressionActions.GetReplaceObjectinitializationAction("Test") }; + var cloned = objectCreationExpressionAction.Clone(); + Assert.True(objectCreationExpressionAction.Equals(cloned)); + + cloned.Value = "DifferentValue"; + Assert.False(objectCreationExpressionAction.Equals(cloned)); + } + + [Test] + public void GetReplaceObjectPropertyIdentifier() + { + string oldIdentifier = "FileSystem", newIdentifier = "FileProvider"; + _objectMemberNode = + SyntaxFactory.ObjectMemberInitializer( + SyntaxFactory.SeparatedList( + new SyntaxNodeOrToken[] { + SyntaxFactory.NamedFieldInitializer( + SyntaxFactory.IdentifierName("RequestPath"), + SyntaxFactory.ParseExpression("PathString.Empty")), + SyntaxFactory.Token(SyntaxKind.CommaToken), + SyntaxFactory.NamedFieldInitializer( + SyntaxFactory.IdentifierName("FileSystem"), + SyntaxFactory.ParseExpression("new PhysicalFileSystem(@\".\\defaults\")")), + SyntaxFactory.Token(SyntaxKind.CommaToken)})) + .NormalizeWhitespace(); + var replaceObjectWithInvocationFunc = _objectCreationExpressionActions.GetReplaceOrAddObjectPropertyIdentifierAction(oldIdentifier, newIdentifier, string.Empty); + var newNode = replaceObjectWithInvocationFunc(_syntaxGenerator, _objectMemberNode); + StringAssert.Contains(newIdentifier, newNode.ToFullString()); + } + + [Test] + public void GetAddObjectPropertyIdentifier() + { + string oldIdentifier = "FileSystem", newIdentifier = "FileProvider", newValue = @"new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), @""""))"; + + _objectMemberNode = SyntaxFactory.ObjectMemberInitializer( + SyntaxFactory.SeparatedList( + new SyntaxNodeOrToken[]{ + SyntaxFactory.NamedFieldInitializer( + SyntaxFactory.IdentifierName("RequestPath"), + SyntaxFactory.ParseExpression("PathString.Empty")), + SyntaxFactory.Token(SyntaxKind.CommaToken), + SyntaxFactory.NamedFieldInitializer( + SyntaxFactory.IdentifierName("EnableDirectoryBrowsing"), + SyntaxFactory.ParseExpression("true")), + SyntaxFactory.Token(SyntaxKind.CommaToken)})) + .NormalizeWhitespace(); + + var replaceObjectWithInvocationFunc = _objectCreationExpressionActions.GetReplaceOrAddObjectPropertyIdentifierAction(oldIdentifier, newIdentifier, newValue); + var newNode = replaceObjectWithInvocationFunc(_syntaxGenerator, _objectMemberNode); + + StringAssert.Contains(newIdentifier, newNode.ToFullString()); + StringAssert.Contains(newValue, newNode.ToFullString()); + } + + [Test] + public void GetReplaceObjectPropertyValue() + { + string oldIdentifier = "PhysicalFileSystem", newIdentifier = "PhysicalFileProvider"; + + _objectMemberNode = SyntaxFactory.ObjectMemberInitializer( + SyntaxFactory.SeparatedList( + new SyntaxNodeOrToken[]{ + SyntaxFactory.NamedFieldInitializer( + SyntaxFactory.IdentifierName("RequestPath"), + SyntaxFactory.ParseExpression("PathString.Empty")), + SyntaxFactory.Token(SyntaxKind.CommaToken), + SyntaxFactory.NamedFieldInitializer( + SyntaxFactory.IdentifierName("FileSystem"), + SyntaxFactory.ParseExpression("new PhysicalFileSystem(@\".\\defaults\")")), + SyntaxFactory.Token(SyntaxKind.CommaToken)})) + .NormalizeWhitespace(); + + var replaceObjectWithInvocationFunc = _objectCreationExpressionActions.GetReplaceObjectPropertyValueAction(oldIdentifier, newIdentifier); + var newNode = replaceObjectWithInvocationFunc(_syntaxGenerator, _objectMemberNode); + StringAssert.Contains(newIdentifier, newNode.ToFullString()); + StringAssert.DoesNotContain(oldIdentifier, newNode.ToFullString()); + } + + [Test] + public void ObjectCreationExpressionEquals() + { + var objectCreationExpressionAction = new ObjectCreationExpressionAction() { Key = "Test", Value = "Test2", ObjectCreationExpressionGenericActionFunc = _objectCreationExpressionActions.GetAddCommentAction("Test") }; + var cloned = objectCreationExpressionAction.Clone(); + Assert.True(objectCreationExpressionAction.Equals(cloned)); + + cloned.Value = "DifferentValue"; + Assert.False(objectCreationExpressionAction.Equals(cloned)); + } + } +} \ No newline at end of file From 6f924d50d6daed943aacbcc815e2963a3959420b Mon Sep 17 00:00:00 2001 From: dongzw-amz Date: Wed, 8 Jun 2022 11:57:34 -0700 Subject: [PATCH 27/61] Add several syntax nodes to rules analysis --- .../packages.lock.json | 208 ++++++++++++------ .../VisualBasicRulesAnalysis.cs | 194 +++++++++++++++- src/CTA.Rules.Config/CTA.Rules.Config.csproj | 7 +- .../VisualBasic/AccessorBlockAction.cs | 24 ++ .../VisualBasic/AttributeListAction.cs | 25 +++ .../VisualBasic/InterfaceBlockAction.cs | 24 ++ .../Actions/VisualBasic/MethodBlockAction.cs | 24 ++ .../FileActions/FileActions.cs | 17 +- .../Tokens/VisualBasic/AccessorBlockToken.cs | 18 ++ .../Tokens/VisualBasic/AttributeListToken.cs | 18 ++ .../Tokens/VisualBasic/InterfaceBlockToken.cs | 18 ++ .../Tokens/VisualBasic/MethodBlockToken.cs | 17 ++ .../Tokens/VisualBasic/VBMemberAccessToken.cs | 18 ++ .../VisualBasic/VisualBasicNodeToken.cs | 23 +- .../VisualBasic/VisualBasicRootNodes.cs | 10 + src/CTA.Rules.Models/packages.lock.json | 208 ++++++++++++------ src/CTA.Rules.sln | 12 + 17 files changed, 708 insertions(+), 157 deletions(-) create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs diff --git a/src/CTA.FeatureDetection.Common/packages.lock.json b/src/CTA.FeatureDetection.Common/packages.lock.json index 6740c0df..06e9798a 100644 --- a/src/CTA.FeatureDetection.Common/packages.lock.json +++ b/src/CTA.FeatureDetection.Common/packages.lock.json @@ -20,10 +20,10 @@ }, "Buildalyzer": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "25NJRnGgYBOC3OPgFDj/KeJwSldXPFZl5jDXjqP7Vsy6vC+MPapcJ687/dOjUeS4t4aVuYrMyWdaezkZgs+Rdw==", + "resolved": "4.1.4", + "contentHash": "O6KGKPeCAe+Ujhd2sl66nu7rrEAM2hBUbi3n79BVBOj9YxuUlbxviOfy3Cq22iIp9rUDPOqOL8E2AYiQwxpUHQ==", "dependencies": { - "Buildalyzer.Logger": "4.1.3", + "Buildalyzer.Logger": "4.1.4", "MSBuild.StructuredLogger": "2.1.507", "Microsoft.Build": "16.9.0", "Microsoft.Build.Framework": "16.9.0", @@ -39,75 +39,19 @@ }, "Buildalyzer.Logger": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "9qq5VfFO/cvasetqJpj+V5sc8Ng5EQjCkYi3COOvzyqNLivYIp+4Cf1ddfbcye3X3i89z9oHIEmF3iNQspFSDw==" + "resolved": "4.1.4", + "contentHash": "2C2FR877slFBYM/usMkGnmOZlLKejV0uag0IzmARkKkBD75jNPM6q2WLaFAW/yRLPyyArpunYzQ+4AaDyEImHQ==" }, "Buildalyzer.Workspaces": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "rZGc9XTd0RzLa3tMG9HfNzhxLKGNerCzW3f+nG/Mau0ucpRENWn7OH9Nz9ZxD3k4oWweOw9kfGfw4VvbcNP43w==", + "resolved": "4.1.4", + "contentHash": "fU4I3dmFDTickARibqYYJb+uDYUxlHM32a0CQgY2dVBJKnf9DFnVkiQjxbhdxGOylHI6lTZm+EdAEqXcjIe4xg==", "dependencies": { - "Buildalyzer": "4.1.3", + "Buildalyzer": "4.1.4", "Microsoft.CodeAnalysis.CSharp.Workspaces": "4.1.0", "Microsoft.CodeAnalysis.VisualBasic.Workspaces": "4.1.0" } }, - "Codelyzer.Analysis": { - "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "DxE+I7g3fcVRFmdIRQ78dOPso8BYUtvYSrGF0/7wak1iitGLLaColSqoRfQEGeM5//77jWP/qAxKwBHsKEVKBg==", - "dependencies": { - "Codelyzer.Analysis.Build": "2.3.45", - "Codelyzer.Analysis.CSharp": "2.3.45", - "CommandLineParser": "2.8.0", - "Microsoft.Extensions.Logging.Console": "6.0.0", - "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196" - } - }, - "Codelyzer.Analysis.Build": { - "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "8Bm/UBtunuhTZCg+osoAas2uYRM2VEunBQUVjOrn26+mIflgucEjvCWogEDH4UOiQKRcqhlSN/6lLlkoWuEqtw==", - "dependencies": { - "Buildalyzer": "4.1.3", - "Buildalyzer.Logger": "4.1.3", - "Buildalyzer.Workspaces": "4.1.3", - "Codelyzer.Analysis.CSharp": "2.3.45", - "Microsoft.Extensions.Logging": "6.0.0", - "NuGet.Packaging": "6.0.0" - } - }, - "Codelyzer.Analysis.Common": { - "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "mNRMSFSoVqCFnQ1GkJx1dmQ79xYjivtrGbi9TWA+F+mA1wh0AEy/folP7r5ykydEVH2sKyjBvUhjuVtNP4GzIg==", - "dependencies": { - "Codelyzer.Analysis.Model": "2.3.45", - "Microsoft.Build": "17.0.0", - "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", - "Newtonsoft.Json": "13.0.1" - } - }, - "Codelyzer.Analysis.CSharp": { - "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "KIwFpFTjx4vP3DeA3oObUA4/ZBTwyPpcvzNxuYrVbmWebtxk8H1Fhhi6HCMp7XRDtTClw/SOg9OJJGOBtuEo8A==", - "dependencies": { - "Codelyzer.Analysis.Common": "2.3.45", - "Codelyzer.Analysis.Model": "2.3.45" - } - }, - "Codelyzer.Analysis.Model": { - "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "c5BQYmHrbMt72EJ8eG3VFLzBAoZVUM1eDBJoJRRKkif0JlkP31iEE12SeotoGuBthm5M1soDNEw2FsxWuqJcWA==", - "dependencies": { - "Microsoft.CodeAnalysis": "4.1.0", - "Microsoft.CodeAnalysis.CSharp": "4.1.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Newtonsoft.Json": "13.0.1" - } - }, "CommandLineParser": { "type": "Transitive", "resolved": "2.8.0", @@ -145,9 +89,10 @@ }, "Microsoft.Build.Framework": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "XbFA0z+6Ws2pNeRXYcDF3lKlNgRoSGMm2Q5HKzZD+EbwYMKPKrl/BJnnkMuDJHU0KravYHfhzBnLLJpPeZ3E7A==", + "resolved": "17.1.0", + "contentHash": "7PPEbjuL/lKQ8ftblxwBZKf5alZCA4GDvBTiO3UAVxtRe52a2jL3mc8TpKNiJZzytGz7fKdR5ClDCs7+Uw4hMg==", "dependencies": { + "Microsoft.Win32.Registry": "4.3.0", "System.Security.Permissions": "4.7.0" } }, @@ -178,12 +123,14 @@ }, "Microsoft.Build.Utilities.Core": { "type": "Transitive", - "resolved": "16.9.0", - "contentHash": "rpxfQlBo2hkFODFJZKPYxMsl5QGIqQ6GlSYnQGKhl+Fu65cvJDk4jRi/R9i+X5/+lSeHhRlQbo+UUhg6cqMkRw==", + "resolved": "17.1.0", + "contentHash": "JqhQ4q6L4IyA0Wh3PrDrxHHYMVHyOLIusyC4imAnhcnZiOC4+CwgVRSdo8fLsQmvz0Jab8FFrU1NPZFbDoxRng==", "dependencies": { - "Microsoft.Build.Framework": "16.9.0", + "Microsoft.Build.Framework": "17.1.0", + "Microsoft.NET.StringTools": "1.0.0", "Microsoft.Win32.Registry": "4.3.0", "System.Collections.Immutable": "5.0.0", + "System.Configuration.ConfigurationManager": "4.7.0", "System.Security.Permissions": "4.7.0", "System.Text.Encoding.CodePages": "4.0.1" } @@ -498,6 +445,15 @@ "Microsoft.Build.Utilities.Core": "16.4.0" } }, + "MsBuildPipeLogger.Logger": { + "type": "Transitive", + "resolved": "1.1.6", + "contentHash": "yUnnZQJfRkp+tSyBVFJSpobU6nRrR063l5GJLKWo9fl+GMx9BW+OzV4umqhoHRrmz22xsRBYhCNpoSQR6q0u0Q==", + "dependencies": { + "System.IO.Pipes": "4.3.0", + "System.Threading.Thread": "4.3.0" + } + }, "MsBuildPipeLogger.Server": { "type": "Transitive", "resolved": "1.1.6", @@ -1083,6 +1039,32 @@ "resolved": "5.0.1", "contentHash": "qEePWsaq9LoEEIqhbGe6D5J8c9IqQOUuTzzV6wn1POlfdLkJliZY3OlB0j0f17uMWlqZYjH7txj+2YbyrIA8Yg==" }, + "System.IO.Pipes": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "wpGJuACA6r8+KRckXoI6ghGTwgPRiICI6T7kgHI/m7S5eMqV/8jH37fzAUhTwIe9RwlH/j1sWwm2Q2zyXwZGHw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Buffers": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Net.Sockets": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Principal": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Overlapped": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, "System.Linq": { "type": "Transitive", "resolved": "4.3.0", @@ -1529,6 +1511,14 @@ "System.Windows.Extensions": "6.0.0" } }, + "System.Security.Principal": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, "System.Security.Principal.Windows": { "type": "Transitive", "resolved": "4.7.0", @@ -1598,6 +1588,17 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.Threading.Overlapped": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "m3HQ2dPiX/DSTpf+yJt8B0c+SRvzfqAJKx+QDWi+VLhz8svLT23MVjEOHPF/KiSLeArKU/iHescrbLd3yVgyNg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, "System.Threading.Tasks": { "type": "Transitive", "resolved": "4.3.0", @@ -1618,6 +1619,14 @@ "resolved": "4.5.4", "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" }, + "System.Threading.Thread": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, "System.Threading.Timer": { "type": "Transitive", "resolved": "4.3.0", @@ -1677,6 +1686,63 @@ "System.Xml.ReaderWriter": "4.3.0" } }, + "codelyzer.analysis": { + "type": "Project", + "dependencies": { + "Codelyzer.Analysis.Build": "1.0.0", + "Codelyzer.Analysis.CSharp": "1.0.0", + "Codelyzer.Analysis.VisualBasic": "1.0.0", + "CommandLineParser": "2.8.0", + "Microsoft.Build.Utilities.Core": "17.1.0", + "Microsoft.Extensions.Logging.Console": "6.0.0", + "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", + "MsBuildPipeLogger.Logger": "1.1.6" + } + }, + "codelyzer.analysis.build": { + "type": "Project", + "dependencies": { + "Buildalyzer": "4.1.4", + "Buildalyzer.Logger": "4.1.4", + "Buildalyzer.Workspaces": "4.1.4", + "Codelyzer.Analysis.CSharp": "1.0.0", + "Microsoft.Extensions.Logging": "6.0.0", + "NuGet.Packaging": "6.0.0" + } + }, + "codelyzer.analysis.common": { + "type": "Project", + "dependencies": { + "Codelyzer.Analysis.Model": "1.0.0", + "Microsoft.Build": "17.0.0", + "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", + "Newtonsoft.Json": "13.0.1" + } + }, + "codelyzer.analysis.csharp": { + "type": "Project", + "dependencies": { + "Codelyzer.Analysis.Common": "1.0.0", + "Codelyzer.Analysis.Model": "1.0.0" + } + }, + "codelyzer.analysis.model": { + "type": "Project", + "dependencies": { + "Microsoft.CodeAnalysis": "4.1.0", + "Microsoft.CodeAnalysis.CSharp": "4.1.0", + "Microsoft.CodeAnalysis.VisualBasic": "4.1.0", + "Microsoft.Extensions.Logging": "6.0.0", + "Newtonsoft.Json": "13.0.1" + } + }, + "codelyzer.analysis.visualbasic": { + "type": "Project", + "dependencies": { + "Codelyzer.Analysis.Common": "1.0.0", + "Codelyzer.Analysis.Model": "1.0.0" + } + }, "cta.rules.common": { "type": "Project", "dependencies": { @@ -1687,8 +1753,8 @@ "cta.rules.config": { "type": "Project", "dependencies": { - "Codelyzer.Analysis": "2.3.45", - "Codelyzer.Analysis.Model": "2.3.45", + "Codelyzer.Analysis": "1.0.0", + "Codelyzer.Analysis.Model": "1.0.0", "Microsoft.Extensions.Logging": "6.0.0", "Microsoft.Extensions.Logging.Abstractions": "6.0.0", "Microsoft.Extensions.Logging.Console": "6.0.0", diff --git a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs index 509d0dcb..51f9ed51 100644 --- a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs @@ -6,6 +6,7 @@ using CTA.Rules.Common.Extensions; using CTA.Rules.Config; using CTA.Rules.Models; +using CTA.Rules.Models.Actions.VisualBasic; using CTA.Rules.Models.Tokens.VisualBasic; using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; @@ -107,8 +108,16 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { switch (child.NodeType) { - case IdConstants.AnnotationIdName: + case IdConstants.AttributeListName: { + var attributeList = (AttributeList)child; + var compareToken = new AttributeListToken() { Key = attributeList.Identifier, Namespace = attributeList.Reference.Namespace, Type = attributeList.SemanticClassType }; + _visualBasicRootNodes.AttributeListTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } break; } case IdConstants.ImportsStatementName: @@ -217,12 +226,68 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, classType.Identifier)) { containsActions = true; } break; } - case IdConstants.InterfaceIdName: + case IdConstants.InterfaceBlockIdName: { + var interfaceType = (InterfaceBlock)child; + var baseToken = new InterfaceBlockToken() { FullKey = interfaceType.BaseType }; + InterfaceBlockToken token = null; + + if (!string.IsNullOrEmpty(interfaceType.BaseType)) + { + _visualBasicRootNodes.InterfaceBlockTokens.TryGetValue(baseToken, out token); + } + + if (token != null) + { + //In case of interface blocks, add actions on the interface by name, instead of property + AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + token = null; + string name = string.Concat(interfaceType.Reference != null ? string.Concat(interfaceType.Reference.Namespace, ".") : string.Empty, interfaceType.Identifier); + var nameToken = new InterfaceBlockToken() { FullKey = name }; + _visualBasicRootNodes.InterfaceBlockTokens.TryGetValue(baseToken, out token); + + if (token != null) + { + //In case of interface blocks, add actions on the interface by name, instead of property + AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace)) { containsActions = true; } break; } - case IdConstants.MethodIdName: + case IdConstants.AccessorBlockName: + { + var accessorType = (AccessorBlock)child; + var name = string.Concat( + accessorType.Reference != null + ? string.Concat(accessorType.Reference.Namespace, ".") + : string.Empty, accessorType.Identifier); + var nameToken = new AccessorBlockToken() { FullKey = name }; + if (_visualBasicRootNodes.AccessorBlockTokens.TryGetValue(nameToken, out var token)) + { + AddNamedActions(fileAction, token, accessorType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + break; + } + case IdConstants.SubBlockName: { + var compareToken = new MethodBlockToken() { FullKey = string.Concat(child.Identifier) }; + _visualBasicRootNodes.MethodBlockTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddNamedActions(fileAction, token, child.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } break; } case IdConstants.InvocationIdName: @@ -299,6 +364,21 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, case IdConstants.MemberAccessIdName: { + MemberAccess memberAccess = (MemberAccess)child; + var compareToken = new VBMemberAccessToken() + { + Key = memberAccess.Name, + FullKey = GetFullKey(memberAccess.Reference?.Namespace, memberAccess.SemanticClassType, memberAccess.Name), + Type = memberAccess.SemanticClassType, + Namespace = memberAccess.Reference?.Namespace + }; + _visualBasicRootNodes.VBMemberAccesstokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } break; } case IdConstants.DeclarationNodeIdName: @@ -338,7 +418,23 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, return containsActions; } - + + private string GetFullKey(string containingNamespace, string containingClass, string key) + { + if (string.IsNullOrEmpty(containingNamespace)) + { + return key; + } + else + { + if (!string.IsNullOrEmpty(containingClass)) + { + return $"{containingNamespace}.{containingClass}.{key}"; + } + return $"{containingNamespace}.{key}"; + } + } + /// /// Add actions matching the token /// @@ -385,12 +481,38 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text NamespaceActionFunc = a.NamespaceActionFunc }).ToList()); - fileAction.VbIdentifierNameAction.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); + fileAction.VbIdentifierNameActions.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); + + fileAction.VbAttributeListActions.UnionWith(token.VbAttributeListActions.Select(a => new AttributeListAction() + { + Key = a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + AttributeListActionFunc = a.AttributeListActionFunc + }).ToList()); + + fileAction.MemberAccessActions.UnionWith(token.MemberAccessActions.Select(a => new MemberAccessAction() + { + Key = (token is VBMemberAccessToken) ? token.FullKey : a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + MemberAccessActionFunc = a.MemberAccessActionFunc + }).ToList()); if (fileAction.InvocationExpressionActions.Any() || fileAction.VbImportActions.Any() - || fileAction.NamespaceActions.Any() - || fileAction.IdentifierNameActions.Any()) + || fileAction.VbNamespaceActions.Any() + || fileAction.VbIdentifierNameActions.Any() + || fileAction.VbAttributeListActions.Any() + || fileAction.MemberAccessActions.Any()) { var nodeToken = token.Clone(); nodeToken.TextSpan = textSpan; @@ -441,9 +563,61 @@ private void AddNamedActions(FileActions fileAction, VisualBasicNodeToken token, ActionValidation = c.ActionValidation, TypeBlockActionFunc = c.TypeBlockActionFunc })); - - if (fileAction.ClassDeclarationActions.Any() || fileAction.InterfaceDeclarationActions.Any() || - fileAction.MethodDeclarationActions.Any() || fileAction.ObjectCreationExpressionActions.Any()) + + fileAction.VbMethodBlockActions.UnionWith(token.MethodBlockActions + .Select(c => new MethodBlockAction() + { + Key = identifier, + Value = c.Value, + Description = c.Description, + Name = c.Name, + Type = c.Type, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + MethodBlockActionFunc = c.MethodBlockActionFunc + })); + + fileAction.VbInterfaceBlockActions.UnionWith(token.InterfaceBlockActions + .Select(c => new InterfaceBlockAction() + { + Key = identifier, + Value = c.Value, + Name = c.Name, + Type = c.Type, + Description = c.Description, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + InterfaceBlockActionFunc = c.InterfaceBlockActionFunc + })); + + fileAction.VbInterfaceBlockActions.UnionWith(token.InterfaceBlockActions + .Select(c => new InterfaceBlockAction() + { + Key = identifier, + Value = c.Value, + Name = c.Name, + Type = c.Type, + Description = c.Description, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + InterfaceBlockActionFunc = c.InterfaceBlockActionFunc + })); + + fileAction.VbAccessorBlockActions.UnionWith(token.AccessorBlockActions + .Select(c => new AccessorBlockAction() + { + Key = identifier, + Value = c.Value, + Name = c.Name, + Type = c.Type, + Description = c.Description, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + AccessorBlockActionFunc = c.AccessorBlockActionFunc + })); + + if (fileAction.VbTypeBlockActions.Any() || fileAction.VbMethodBlockActions.Any() + || fileAction.VbInterfaceBlockActions.Any() || fileAction.VbAccessorBlockActions.Any()) { var nodeToken = token.Clone(); nodeToken.TextSpan = textSpan; diff --git a/src/CTA.Rules.Config/CTA.Rules.Config.csproj b/src/CTA.Rules.Config/CTA.Rules.Config.csproj index 0da75399..7c44c625 100644 --- a/src/CTA.Rules.Config/CTA.Rules.Config.csproj +++ b/src/CTA.Rules.Config/CTA.Rules.Config.csproj @@ -5,14 +5,17 @@ - - + + + + + diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs new file mode 100644 index 00000000..30fe7449 --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; + +namespace CTA.Rules.Models.Actions.VisualBasic +{ + public class AccessorBlockAction : GenericAction + { + public Func AccessorBlockActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (AccessorBlockAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action?.AccessorBlockActionFunc.Method.Name == this.AccessorBlockActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, AccessorBlockActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs new file mode 100644 index 00000000..d27e6d7e --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs @@ -0,0 +1,25 @@ +using System; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Models.Actions.VisualBasic +{ + public class AttributeListAction : GenericAction + { + public Func AttributeListActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (AttributeAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action.AttributeListActionFunc != null && this.AttributeListActionFunc != null + && action.AttributeListActionFunc.Method.Name == this.AttributeListActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, AttributeListActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs new file mode 100644 index 00000000..f32cc85b --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Models.Actions.VisualBasic +{ + public class InterfaceBlockAction : GenericAction + { + public Func InterfaceBlockActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (InterfaceBlockAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action?.InterfaceBlockActionFunc.Method.Name == this.InterfaceBlockActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, InterfaceBlockActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs new file mode 100644 index 00000000..7703b3ee --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Models.Actions.VisualBasic +{ + public class MethodBlockAction : GenericAction + { + public Func MethodBlockActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (MethodBlockAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action?.MethodBlockActionFunc.Method.Name == this.MethodBlockActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, MethodBlockActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index e7a23d06..61651f39 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using CTA.Rules.Models.Actions.VisualBasic; using CTA.Rules.Models.Tokens; using CTA.Rules.Models.Tokens.VisualBasic; using CTA.Rules.Models.VisualBasic; @@ -37,6 +38,11 @@ public FileActions() VbNamespaceActions = new HashSet>(); VbTypeBlockActions = new HashSet(); + VbMethodBlockActions = new HashSet(); + VbInterfaceBlockActions = new HashSet(); + VbAttributeListActions = new HashSet(); + VbIdentifierNameActions = new HashSet>(); + VbAccessorBlockActions = new HashSet(); } public HashSet> VbNamespaceActions { get; set; } @@ -44,9 +50,13 @@ public FileActions() public HashSet> VbInvocationExpressionActions { get; set; } public HashSet> - VbIdentifierNameAction { get; set; } + VbIdentifierNameActions { get; set; } public HashSet VbTypeBlockActions { get; set; } + public HashSet VbMethodBlockActions { get; set; } + public HashSet VbInterfaceBlockActions { get; set; } + public HashSet VbAttributeListActions { get; set; } + public HashSet VbAccessorBlockActions { get; set; } public List VbNodeTokens { get; set; } public List NodeTokens { get; set; } @@ -85,6 +95,11 @@ public List AllActions allActions.AddRange(VbNamespaceActions); allActions.AddRange(VbInvocationExpressionActions); allActions.AddRange(VbTypeBlockActions); + allActions.AddRange(VbMethodBlockActions); + allActions.AddRange(VbInterfaceBlockActions); + allActions.AddRange(VbAttributeListActions); + allActions.AddRange(VbIdentifierNameActions); + allActions.AddRange(VbAccessorBlockActions); return allActions; } } diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs new file mode 100644 index 00000000..28057aed --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs @@ -0,0 +1,18 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class AccessorBlockToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (AccessorBlockToken)obj; + return token?.Type == this.Type && token?.Namespace == this.Namespace && token?.Key.Trim() == this.Key.Trim(); + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Namespace, Type); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs new file mode 100644 index 00000000..fd1c209f --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs @@ -0,0 +1,18 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class AttributeListToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (AttributeListToken)obj; + return token?.Type == this.Type && token?.Namespace == this.Namespace && token?.Key.Trim() == this.Key.Trim(); + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Namespace, Type); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs new file mode 100644 index 00000000..3dbc518e --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs @@ -0,0 +1,18 @@ +using System; +using CTA.Rules.Models.Tokens; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class InterfaceBlockToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (InterfaceBlockToken)obj; + return token?.FullKey == this.FullKey; + } + public override int GetHashCode() + { + return HashCode.Combine(FullKey); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs new file mode 100644 index 00000000..bead566e --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs @@ -0,0 +1,17 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class MethodBlockToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (MethodBlockToken)obj; + return token?.FullKey == this.FullKey; + } + public override int GetHashCode() + { + return HashCode.Combine(FullKey); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs new file mode 100644 index 00000000..39339d80 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs @@ -0,0 +1,18 @@ +using System; + + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class VBMemberAccessToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (VBMemberAccessToken)obj; + return token?.FullKey == this.FullKey; + } + public override int GetHashCode() + { + return HashCode.Combine(FullKey); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs index b341d34f..40e1506e 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs @@ -3,6 +3,7 @@ using System.Configuration; using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using CTA.Rules.Models.Actions.VisualBasic; namespace CTA.Rules.Models.Tokens.VisualBasic { @@ -15,7 +16,10 @@ public VisualBasicNodeToken() NamespaceActions = new List>(); IdentifierNameActions = new List>(); TypeBlockActions = new List(); - + MethodBlockActions = new List(); + InterfaceBlockActions = new List(); + VbAttributeListActions = new List(); + AccessorBlockActions = new List(); } public List> InvocationExpressionActions { get; set; } @@ -23,7 +27,10 @@ public VisualBasicNodeToken() public List> NamespaceActions { get; set; } public List> IdentifierNameActions { get; set; } public List TypeBlockActions { get; set; } - + public List MethodBlockActions { get; set; } + public List InterfaceBlockActions { get; set; } + public List VbAttributeListActions { get; set; } + public List AccessorBlockActions { get; set; } public override VisualBasicNodeToken Clone() { @@ -38,6 +45,14 @@ public override VisualBasicNodeToken Clone() .Select(action => action.Clone>()).ToList(); cloned.TypeBlockActions = cloned.TypeBlockActions .Select(action => action.Clone()).ToList(); + cloned.MethodBlockActions = cloned.MethodBlockActions + .Select(action => action.Clone()).ToList(); + cloned.InterfaceBlockActions = cloned.InterfaceBlockActions + .Select(action => action.Clone()).ToList(); + cloned.VbAttributeListActions = cloned.VbAttributeListActions + .Select(action => action.Clone()).ToList(); + cloned.AccessorBlockActions = cloned.AccessorBlockActions + .Select(action => action.Clone()).ToList(); return cloned; } @@ -51,6 +66,10 @@ public override List AllActions allActions.AddRange(ImportActions); allActions.AddRange(IdentifierNameActions); allActions.AddRange(TypeBlockActions); + allActions.AddRange(MethodBlockActions); + allActions.AddRange(InterfaceBlockActions); + allActions.AddRange(AttributeListActions); + allActions.AddRange(AccessorBlockActions); allActions.AddRange(base.AllActions); return allActions; } diff --git a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs index 50498832..79414d67 100644 --- a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs +++ b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs @@ -13,6 +13,11 @@ public VisualBasicRootNodes() { InvocationExpressionTokens = new HashSet(); ImportStatementTokens = new HashSet(); + InterfaceBlockTokens = new HashSet(); + MethodBlockTokens = new HashSet(); + AttributeListTokens = new HashSet(); + AccessorBlockTokens = new HashSet(); + VBMemberAccesstokens = new HashSet(); NamespaceTokens = new HashSet(); ProjectTokens = new HashSet(); IdentifierNameTokens = new HashSet(); @@ -21,6 +26,11 @@ public VisualBasicRootNodes() public HashSet InvocationExpressionTokens { get; set; } public HashSet ImportStatementTokens { get; set; } + public HashSet InterfaceBlockTokens { get; set; } + public HashSet MethodBlockTokens { get; set; } + public HashSet AttributeListTokens { get; set; } + public HashSet AccessorBlockTokens { get; set; } + public HashSet VBMemberAccesstokens { get; set; } public HashSet NamespaceTokens { get; set; } public HashSet ProjectTokens { get; set; } public HashSet IdentifierNameTokens { get; set; } diff --git a/src/CTA.Rules.Models/packages.lock.json b/src/CTA.Rules.Models/packages.lock.json index 5a3a47f3..69b06e4a 100644 --- a/src/CTA.Rules.Models/packages.lock.json +++ b/src/CTA.Rules.Models/packages.lock.json @@ -26,10 +26,10 @@ }, "Buildalyzer": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "25NJRnGgYBOC3OPgFDj/KeJwSldXPFZl5jDXjqP7Vsy6vC+MPapcJ687/dOjUeS4t4aVuYrMyWdaezkZgs+Rdw==", + "resolved": "4.1.4", + "contentHash": "O6KGKPeCAe+Ujhd2sl66nu7rrEAM2hBUbi3n79BVBOj9YxuUlbxviOfy3Cq22iIp9rUDPOqOL8E2AYiQwxpUHQ==", "dependencies": { - "Buildalyzer.Logger": "4.1.3", + "Buildalyzer.Logger": "4.1.4", "MSBuild.StructuredLogger": "2.1.507", "Microsoft.Build": "16.9.0", "Microsoft.Build.Framework": "16.9.0", @@ -45,75 +45,19 @@ }, "Buildalyzer.Logger": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "9qq5VfFO/cvasetqJpj+V5sc8Ng5EQjCkYi3COOvzyqNLivYIp+4Cf1ddfbcye3X3i89z9oHIEmF3iNQspFSDw==" + "resolved": "4.1.4", + "contentHash": "2C2FR877slFBYM/usMkGnmOZlLKejV0uag0IzmARkKkBD75jNPM6q2WLaFAW/yRLPyyArpunYzQ+4AaDyEImHQ==" }, "Buildalyzer.Workspaces": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "rZGc9XTd0RzLa3tMG9HfNzhxLKGNerCzW3f+nG/Mau0ucpRENWn7OH9Nz9ZxD3k4oWweOw9kfGfw4VvbcNP43w==", + "resolved": "4.1.4", + "contentHash": "fU4I3dmFDTickARibqYYJb+uDYUxlHM32a0CQgY2dVBJKnf9DFnVkiQjxbhdxGOylHI6lTZm+EdAEqXcjIe4xg==", "dependencies": { - "Buildalyzer": "4.1.3", + "Buildalyzer": "4.1.4", "Microsoft.CodeAnalysis.CSharp.Workspaces": "4.1.0", "Microsoft.CodeAnalysis.VisualBasic.Workspaces": "4.1.0" } }, - "Codelyzer.Analysis": { - "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "DxE+I7g3fcVRFmdIRQ78dOPso8BYUtvYSrGF0/7wak1iitGLLaColSqoRfQEGeM5//77jWP/qAxKwBHsKEVKBg==", - "dependencies": { - "Codelyzer.Analysis.Build": "2.3.45", - "Codelyzer.Analysis.CSharp": "2.3.45", - "CommandLineParser": "2.8.0", - "Microsoft.Extensions.Logging.Console": "6.0.0", - "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196" - } - }, - "Codelyzer.Analysis.Build": { - "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "8Bm/UBtunuhTZCg+osoAas2uYRM2VEunBQUVjOrn26+mIflgucEjvCWogEDH4UOiQKRcqhlSN/6lLlkoWuEqtw==", - "dependencies": { - "Buildalyzer": "4.1.3", - "Buildalyzer.Logger": "4.1.3", - "Buildalyzer.Workspaces": "4.1.3", - "Codelyzer.Analysis.CSharp": "2.3.45", - "Microsoft.Extensions.Logging": "6.0.0", - "NuGet.Packaging": "6.0.0" - } - }, - "Codelyzer.Analysis.Common": { - "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "mNRMSFSoVqCFnQ1GkJx1dmQ79xYjivtrGbi9TWA+F+mA1wh0AEy/folP7r5ykydEVH2sKyjBvUhjuVtNP4GzIg==", - "dependencies": { - "Codelyzer.Analysis.Model": "2.3.45", - "Microsoft.Build": "17.0.0", - "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", - "Newtonsoft.Json": "13.0.1" - } - }, - "Codelyzer.Analysis.CSharp": { - "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "KIwFpFTjx4vP3DeA3oObUA4/ZBTwyPpcvzNxuYrVbmWebtxk8H1Fhhi6HCMp7XRDtTClw/SOg9OJJGOBtuEo8A==", - "dependencies": { - "Codelyzer.Analysis.Common": "2.3.45", - "Codelyzer.Analysis.Model": "2.3.45" - } - }, - "Codelyzer.Analysis.Model": { - "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "c5BQYmHrbMt72EJ8eG3VFLzBAoZVUM1eDBJoJRRKkif0JlkP31iEE12SeotoGuBthm5M1soDNEw2FsxWuqJcWA==", - "dependencies": { - "Microsoft.CodeAnalysis": "4.1.0", - "Microsoft.CodeAnalysis.CSharp": "4.1.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Newtonsoft.Json": "13.0.1" - } - }, "CommandLineParser": { "type": "Transitive", "resolved": "2.8.0", @@ -151,9 +95,10 @@ }, "Microsoft.Build.Framework": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "XbFA0z+6Ws2pNeRXYcDF3lKlNgRoSGMm2Q5HKzZD+EbwYMKPKrl/BJnnkMuDJHU0KravYHfhzBnLLJpPeZ3E7A==", + "resolved": "17.1.0", + "contentHash": "7PPEbjuL/lKQ8ftblxwBZKf5alZCA4GDvBTiO3UAVxtRe52a2jL3mc8TpKNiJZzytGz7fKdR5ClDCs7+Uw4hMg==", "dependencies": { + "Microsoft.Win32.Registry": "4.3.0", "System.Security.Permissions": "4.7.0" } }, @@ -184,12 +129,14 @@ }, "Microsoft.Build.Utilities.Core": { "type": "Transitive", - "resolved": "16.9.0", - "contentHash": "rpxfQlBo2hkFODFJZKPYxMsl5QGIqQ6GlSYnQGKhl+Fu65cvJDk4jRi/R9i+X5/+lSeHhRlQbo+UUhg6cqMkRw==", + "resolved": "17.1.0", + "contentHash": "JqhQ4q6L4IyA0Wh3PrDrxHHYMVHyOLIusyC4imAnhcnZiOC4+CwgVRSdo8fLsQmvz0Jab8FFrU1NPZFbDoxRng==", "dependencies": { - "Microsoft.Build.Framework": "16.9.0", + "Microsoft.Build.Framework": "17.1.0", + "Microsoft.NET.StringTools": "1.0.0", "Microsoft.Win32.Registry": "4.3.0", "System.Collections.Immutable": "5.0.0", + "System.Configuration.ConfigurationManager": "4.7.0", "System.Security.Permissions": "4.7.0", "System.Text.Encoding.CodePages": "4.0.1" } @@ -504,6 +451,15 @@ "Microsoft.Build.Utilities.Core": "16.4.0" } }, + "MsBuildPipeLogger.Logger": { + "type": "Transitive", + "resolved": "1.1.6", + "contentHash": "yUnnZQJfRkp+tSyBVFJSpobU6nRrR063l5GJLKWo9fl+GMx9BW+OzV4umqhoHRrmz22xsRBYhCNpoSQR6q0u0Q==", + "dependencies": { + "System.IO.Pipes": "4.3.0", + "System.Threading.Thread": "4.3.0" + } + }, "MsBuildPipeLogger.Server": { "type": "Transitive", "resolved": "1.1.6", @@ -1089,6 +1045,32 @@ "resolved": "5.0.1", "contentHash": "qEePWsaq9LoEEIqhbGe6D5J8c9IqQOUuTzzV6wn1POlfdLkJliZY3OlB0j0f17uMWlqZYjH7txj+2YbyrIA8Yg==" }, + "System.IO.Pipes": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "wpGJuACA6r8+KRckXoI6ghGTwgPRiICI6T7kgHI/m7S5eMqV/8jH37fzAUhTwIe9RwlH/j1sWwm2Q2zyXwZGHw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Buffers": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Net.Sockets": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Principal": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Overlapped": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, "System.Linq": { "type": "Transitive", "resolved": "4.3.0", @@ -1535,6 +1517,14 @@ "System.Windows.Extensions": "6.0.0" } }, + "System.Security.Principal": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, "System.Security.Principal.Windows": { "type": "Transitive", "resolved": "4.7.0", @@ -1604,6 +1594,17 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.Threading.Overlapped": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "m3HQ2dPiX/DSTpf+yJt8B0c+SRvzfqAJKx+QDWi+VLhz8svLT23MVjEOHPF/KiSLeArKU/iHescrbLd3yVgyNg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, "System.Threading.Tasks": { "type": "Transitive", "resolved": "4.3.0", @@ -1624,6 +1625,14 @@ "resolved": "4.5.4", "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" }, + "System.Threading.Thread": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, "System.Threading.Timer": { "type": "Transitive", "resolved": "4.3.0", @@ -1683,6 +1692,63 @@ "System.Xml.ReaderWriter": "4.3.0" } }, + "codelyzer.analysis": { + "type": "Project", + "dependencies": { + "Codelyzer.Analysis.Build": "1.0.0", + "Codelyzer.Analysis.CSharp": "1.0.0", + "Codelyzer.Analysis.VisualBasic": "1.0.0", + "CommandLineParser": "2.8.0", + "Microsoft.Build.Utilities.Core": "17.1.0", + "Microsoft.Extensions.Logging.Console": "6.0.0", + "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", + "MsBuildPipeLogger.Logger": "1.1.6" + } + }, + "codelyzer.analysis.build": { + "type": "Project", + "dependencies": { + "Buildalyzer": "4.1.4", + "Buildalyzer.Logger": "4.1.4", + "Buildalyzer.Workspaces": "4.1.4", + "Codelyzer.Analysis.CSharp": "1.0.0", + "Microsoft.Extensions.Logging": "6.0.0", + "NuGet.Packaging": "6.0.0" + } + }, + "codelyzer.analysis.common": { + "type": "Project", + "dependencies": { + "Codelyzer.Analysis.Model": "1.0.0", + "Microsoft.Build": "17.0.0", + "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", + "Newtonsoft.Json": "13.0.1" + } + }, + "codelyzer.analysis.csharp": { + "type": "Project", + "dependencies": { + "Codelyzer.Analysis.Common": "1.0.0", + "Codelyzer.Analysis.Model": "1.0.0" + } + }, + "codelyzer.analysis.model": { + "type": "Project", + "dependencies": { + "Microsoft.CodeAnalysis": "4.1.0", + "Microsoft.CodeAnalysis.CSharp": "4.1.0", + "Microsoft.CodeAnalysis.VisualBasic": "4.1.0", + "Microsoft.Extensions.Logging": "6.0.0", + "Newtonsoft.Json": "13.0.1" + } + }, + "codelyzer.analysis.visualbasic": { + "type": "Project", + "dependencies": { + "Codelyzer.Analysis.Common": "1.0.0", + "Codelyzer.Analysis.Model": "1.0.0" + } + }, "cta.rules.common": { "type": "Project", "dependencies": { @@ -1693,8 +1759,8 @@ "cta.rules.config": { "type": "Project", "dependencies": { - "Codelyzer.Analysis": "2.3.45", - "Codelyzer.Analysis.Model": "2.3.45", + "Codelyzer.Analysis": "1.0.0", + "Codelyzer.Analysis.Model": "1.0.0", "Microsoft.Extensions.Logging": "6.0.0", "Microsoft.Extensions.Logging.Abstractions": "6.0.0", "Microsoft.Extensions.Logging.Console": "6.0.0", diff --git a/src/CTA.Rules.sln b/src/CTA.Rules.sln index d5153d1d..2b4a4b70 100644 --- a/src/CTA.Rules.sln +++ b/src/CTA.Rules.sln @@ -46,6 +46,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CTA.WebForms", "CTA.WebForm EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CTA.WebForms.Tests", "..\tst\CTA.WebForms.Tests\CTA.WebForms.Tests.csproj", "{A4F48CAF-6376-4929-9D64-CE123EBA6329}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Codelyzer.Analysis", "..\..\codelyzer\src\Analysis\Codelyzer.Analysis\Codelyzer.Analysis.csproj", "{786BBCC7-19FE-4641-B8B0-842DB52A09AC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Codelyzer.Analysis.Model", "..\..\codelyzer\src\Analysis\Codelyzer.Analysis.Model\Codelyzer.Analysis.Model.csproj", "{F9C39261-0BA2-4BA8-A0F2-FE3FF41F6E54}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -128,6 +132,14 @@ Global {A4F48CAF-6376-4929-9D64-CE123EBA6329}.Debug|Any CPU.Build.0 = Debug|Any CPU {A4F48CAF-6376-4929-9D64-CE123EBA6329}.Release|Any CPU.ActiveCfg = Release|Any CPU {A4F48CAF-6376-4929-9D64-CE123EBA6329}.Release|Any CPU.Build.0 = Release|Any CPU + {786BBCC7-19FE-4641-B8B0-842DB52A09AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {786BBCC7-19FE-4641-B8B0-842DB52A09AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {786BBCC7-19FE-4641-B8B0-842DB52A09AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {786BBCC7-19FE-4641-B8B0-842DB52A09AC}.Release|Any CPU.Build.0 = Release|Any CPU + {F9C39261-0BA2-4BA8-A0F2-FE3FF41F6E54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9C39261-0BA2-4BA8-A0F2-FE3FF41F6E54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9C39261-0BA2-4BA8-A0F2-FE3FF41F6E54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9C39261-0BA2-4BA8-A0F2-FE3FF41F6E54}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 9bc64b0d39d30b5776499db8a0a4d7a86392031e Mon Sep 17 00:00:00 2001 From: dongzw-amz Date: Wed, 8 Jun 2022 12:38:16 -0700 Subject: [PATCH 28/61] Revert "Add several syntax nodes to rules analysis" This reverts commit 6f924d50d6daed943aacbcc815e2963a3959420b. --- .../packages.lock.json | 208 ++++++------------ .../VisualBasicRulesAnalysis.cs | 194 +--------------- src/CTA.Rules.Config/CTA.Rules.Config.csproj | 7 +- .../VisualBasic/AccessorBlockAction.cs | 24 -- .../VisualBasic/AttributeListAction.cs | 25 --- .../VisualBasic/InterfaceBlockAction.cs | 24 -- .../Actions/VisualBasic/MethodBlockAction.cs | 24 -- .../FileActions/FileActions.cs | 17 +- .../Tokens/VisualBasic/AccessorBlockToken.cs | 18 -- .../Tokens/VisualBasic/AttributeListToken.cs | 18 -- .../Tokens/VisualBasic/InterfaceBlockToken.cs | 18 -- .../Tokens/VisualBasic/MethodBlockToken.cs | 17 -- .../Tokens/VisualBasic/VBMemberAccessToken.cs | 18 -- .../VisualBasic/VisualBasicNodeToken.cs | 23 +- .../VisualBasic/VisualBasicRootNodes.cs | 10 - src/CTA.Rules.Models/packages.lock.json | 208 ++++++------------ src/CTA.Rules.sln | 12 - 17 files changed, 157 insertions(+), 708 deletions(-) delete mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs delete mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs delete mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs delete mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs delete mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs delete mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs delete mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs delete mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs delete mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs diff --git a/src/CTA.FeatureDetection.Common/packages.lock.json b/src/CTA.FeatureDetection.Common/packages.lock.json index 06e9798a..6740c0df 100644 --- a/src/CTA.FeatureDetection.Common/packages.lock.json +++ b/src/CTA.FeatureDetection.Common/packages.lock.json @@ -20,10 +20,10 @@ }, "Buildalyzer": { "type": "Transitive", - "resolved": "4.1.4", - "contentHash": "O6KGKPeCAe+Ujhd2sl66nu7rrEAM2hBUbi3n79BVBOj9YxuUlbxviOfy3Cq22iIp9rUDPOqOL8E2AYiQwxpUHQ==", + "resolved": "4.1.3", + "contentHash": "25NJRnGgYBOC3OPgFDj/KeJwSldXPFZl5jDXjqP7Vsy6vC+MPapcJ687/dOjUeS4t4aVuYrMyWdaezkZgs+Rdw==", "dependencies": { - "Buildalyzer.Logger": "4.1.4", + "Buildalyzer.Logger": "4.1.3", "MSBuild.StructuredLogger": "2.1.507", "Microsoft.Build": "16.9.0", "Microsoft.Build.Framework": "16.9.0", @@ -39,19 +39,75 @@ }, "Buildalyzer.Logger": { "type": "Transitive", - "resolved": "4.1.4", - "contentHash": "2C2FR877slFBYM/usMkGnmOZlLKejV0uag0IzmARkKkBD75jNPM6q2WLaFAW/yRLPyyArpunYzQ+4AaDyEImHQ==" + "resolved": "4.1.3", + "contentHash": "9qq5VfFO/cvasetqJpj+V5sc8Ng5EQjCkYi3COOvzyqNLivYIp+4Cf1ddfbcye3X3i89z9oHIEmF3iNQspFSDw==" }, "Buildalyzer.Workspaces": { "type": "Transitive", - "resolved": "4.1.4", - "contentHash": "fU4I3dmFDTickARibqYYJb+uDYUxlHM32a0CQgY2dVBJKnf9DFnVkiQjxbhdxGOylHI6lTZm+EdAEqXcjIe4xg==", + "resolved": "4.1.3", + "contentHash": "rZGc9XTd0RzLa3tMG9HfNzhxLKGNerCzW3f+nG/Mau0ucpRENWn7OH9Nz9ZxD3k4oWweOw9kfGfw4VvbcNP43w==", "dependencies": { - "Buildalyzer": "4.1.4", + "Buildalyzer": "4.1.3", "Microsoft.CodeAnalysis.CSharp.Workspaces": "4.1.0", "Microsoft.CodeAnalysis.VisualBasic.Workspaces": "4.1.0" } }, + "Codelyzer.Analysis": { + "type": "Transitive", + "resolved": "2.3.45", + "contentHash": "DxE+I7g3fcVRFmdIRQ78dOPso8BYUtvYSrGF0/7wak1iitGLLaColSqoRfQEGeM5//77jWP/qAxKwBHsKEVKBg==", + "dependencies": { + "Codelyzer.Analysis.Build": "2.3.45", + "Codelyzer.Analysis.CSharp": "2.3.45", + "CommandLineParser": "2.8.0", + "Microsoft.Extensions.Logging.Console": "6.0.0", + "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196" + } + }, + "Codelyzer.Analysis.Build": { + "type": "Transitive", + "resolved": "2.3.45", + "contentHash": "8Bm/UBtunuhTZCg+osoAas2uYRM2VEunBQUVjOrn26+mIflgucEjvCWogEDH4UOiQKRcqhlSN/6lLlkoWuEqtw==", + "dependencies": { + "Buildalyzer": "4.1.3", + "Buildalyzer.Logger": "4.1.3", + "Buildalyzer.Workspaces": "4.1.3", + "Codelyzer.Analysis.CSharp": "2.3.45", + "Microsoft.Extensions.Logging": "6.0.0", + "NuGet.Packaging": "6.0.0" + } + }, + "Codelyzer.Analysis.Common": { + "type": "Transitive", + "resolved": "2.3.45", + "contentHash": "mNRMSFSoVqCFnQ1GkJx1dmQ79xYjivtrGbi9TWA+F+mA1wh0AEy/folP7r5ykydEVH2sKyjBvUhjuVtNP4GzIg==", + "dependencies": { + "Codelyzer.Analysis.Model": "2.3.45", + "Microsoft.Build": "17.0.0", + "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", + "Newtonsoft.Json": "13.0.1" + } + }, + "Codelyzer.Analysis.CSharp": { + "type": "Transitive", + "resolved": "2.3.45", + "contentHash": "KIwFpFTjx4vP3DeA3oObUA4/ZBTwyPpcvzNxuYrVbmWebtxk8H1Fhhi6HCMp7XRDtTClw/SOg9OJJGOBtuEo8A==", + "dependencies": { + "Codelyzer.Analysis.Common": "2.3.45", + "Codelyzer.Analysis.Model": "2.3.45" + } + }, + "Codelyzer.Analysis.Model": { + "type": "Transitive", + "resolved": "2.3.45", + "contentHash": "c5BQYmHrbMt72EJ8eG3VFLzBAoZVUM1eDBJoJRRKkif0JlkP31iEE12SeotoGuBthm5M1soDNEw2FsxWuqJcWA==", + "dependencies": { + "Microsoft.CodeAnalysis": "4.1.0", + "Microsoft.CodeAnalysis.CSharp": "4.1.0", + "Microsoft.Extensions.Logging": "6.0.0", + "Newtonsoft.Json": "13.0.1" + } + }, "CommandLineParser": { "type": "Transitive", "resolved": "2.8.0", @@ -89,10 +145,9 @@ }, "Microsoft.Build.Framework": { "type": "Transitive", - "resolved": "17.1.0", - "contentHash": "7PPEbjuL/lKQ8ftblxwBZKf5alZCA4GDvBTiO3UAVxtRe52a2jL3mc8TpKNiJZzytGz7fKdR5ClDCs7+Uw4hMg==", + "resolved": "17.0.0", + "contentHash": "XbFA0z+6Ws2pNeRXYcDF3lKlNgRoSGMm2Q5HKzZD+EbwYMKPKrl/BJnnkMuDJHU0KravYHfhzBnLLJpPeZ3E7A==", "dependencies": { - "Microsoft.Win32.Registry": "4.3.0", "System.Security.Permissions": "4.7.0" } }, @@ -123,14 +178,12 @@ }, "Microsoft.Build.Utilities.Core": { "type": "Transitive", - "resolved": "17.1.0", - "contentHash": "JqhQ4q6L4IyA0Wh3PrDrxHHYMVHyOLIusyC4imAnhcnZiOC4+CwgVRSdo8fLsQmvz0Jab8FFrU1NPZFbDoxRng==", + "resolved": "16.9.0", + "contentHash": "rpxfQlBo2hkFODFJZKPYxMsl5QGIqQ6GlSYnQGKhl+Fu65cvJDk4jRi/R9i+X5/+lSeHhRlQbo+UUhg6cqMkRw==", "dependencies": { - "Microsoft.Build.Framework": "17.1.0", - "Microsoft.NET.StringTools": "1.0.0", + "Microsoft.Build.Framework": "16.9.0", "Microsoft.Win32.Registry": "4.3.0", "System.Collections.Immutable": "5.0.0", - "System.Configuration.ConfigurationManager": "4.7.0", "System.Security.Permissions": "4.7.0", "System.Text.Encoding.CodePages": "4.0.1" } @@ -445,15 +498,6 @@ "Microsoft.Build.Utilities.Core": "16.4.0" } }, - "MsBuildPipeLogger.Logger": { - "type": "Transitive", - "resolved": "1.1.6", - "contentHash": "yUnnZQJfRkp+tSyBVFJSpobU6nRrR063l5GJLKWo9fl+GMx9BW+OzV4umqhoHRrmz22xsRBYhCNpoSQR6q0u0Q==", - "dependencies": { - "System.IO.Pipes": "4.3.0", - "System.Threading.Thread": "4.3.0" - } - }, "MsBuildPipeLogger.Server": { "type": "Transitive", "resolved": "1.1.6", @@ -1039,32 +1083,6 @@ "resolved": "5.0.1", "contentHash": "qEePWsaq9LoEEIqhbGe6D5J8c9IqQOUuTzzV6wn1POlfdLkJliZY3OlB0j0f17uMWlqZYjH7txj+2YbyrIA8Yg==" }, - "System.IO.Pipes": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "wpGJuACA6r8+KRckXoI6ghGTwgPRiICI6T7kgHI/m7S5eMqV/8jH37fzAUhTwIe9RwlH/j1sWwm2Q2zyXwZGHw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Buffers": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Net.Primitives": "4.3.0", - "System.Net.Sockets": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Principal": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Overlapped": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "runtime.native.System": "4.3.0" - } - }, "System.Linq": { "type": "Transitive", "resolved": "4.3.0", @@ -1511,14 +1529,6 @@ "System.Windows.Extensions": "6.0.0" } }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Security.Principal.Windows": { "type": "Transitive", "resolved": "4.7.0", @@ -1588,17 +1598,6 @@ "System.Threading.Tasks": "4.3.0" } }, - "System.Threading.Overlapped": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "m3HQ2dPiX/DSTpf+yJt8B0c+SRvzfqAJKx+QDWi+VLhz8svLT23MVjEOHPF/KiSLeArKU/iHescrbLd3yVgyNg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0" - } - }, "System.Threading.Tasks": { "type": "Transitive", "resolved": "4.3.0", @@ -1619,14 +1618,6 @@ "resolved": "4.5.4", "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" }, - "System.Threading.Thread": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Threading.Timer": { "type": "Transitive", "resolved": "4.3.0", @@ -1686,63 +1677,6 @@ "System.Xml.ReaderWriter": "4.3.0" } }, - "codelyzer.analysis": { - "type": "Project", - "dependencies": { - "Codelyzer.Analysis.Build": "1.0.0", - "Codelyzer.Analysis.CSharp": "1.0.0", - "Codelyzer.Analysis.VisualBasic": "1.0.0", - "CommandLineParser": "2.8.0", - "Microsoft.Build.Utilities.Core": "17.1.0", - "Microsoft.Extensions.Logging.Console": "6.0.0", - "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", - "MsBuildPipeLogger.Logger": "1.1.6" - } - }, - "codelyzer.analysis.build": { - "type": "Project", - "dependencies": { - "Buildalyzer": "4.1.4", - "Buildalyzer.Logger": "4.1.4", - "Buildalyzer.Workspaces": "4.1.4", - "Codelyzer.Analysis.CSharp": "1.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "NuGet.Packaging": "6.0.0" - } - }, - "codelyzer.analysis.common": { - "type": "Project", - "dependencies": { - "Codelyzer.Analysis.Model": "1.0.0", - "Microsoft.Build": "17.0.0", - "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", - "Newtonsoft.Json": "13.0.1" - } - }, - "codelyzer.analysis.csharp": { - "type": "Project", - "dependencies": { - "Codelyzer.Analysis.Common": "1.0.0", - "Codelyzer.Analysis.Model": "1.0.0" - } - }, - "codelyzer.analysis.model": { - "type": "Project", - "dependencies": { - "Microsoft.CodeAnalysis": "4.1.0", - "Microsoft.CodeAnalysis.CSharp": "4.1.0", - "Microsoft.CodeAnalysis.VisualBasic": "4.1.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Newtonsoft.Json": "13.0.1" - } - }, - "codelyzer.analysis.visualbasic": { - "type": "Project", - "dependencies": { - "Codelyzer.Analysis.Common": "1.0.0", - "Codelyzer.Analysis.Model": "1.0.0" - } - }, "cta.rules.common": { "type": "Project", "dependencies": { @@ -1753,8 +1687,8 @@ "cta.rules.config": { "type": "Project", "dependencies": { - "Codelyzer.Analysis": "1.0.0", - "Codelyzer.Analysis.Model": "1.0.0", + "Codelyzer.Analysis": "2.3.45", + "Codelyzer.Analysis.Model": "2.3.45", "Microsoft.Extensions.Logging": "6.0.0", "Microsoft.Extensions.Logging.Abstractions": "6.0.0", "Microsoft.Extensions.Logging.Console": "6.0.0", diff --git a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs index 51f9ed51..509d0dcb 100644 --- a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs @@ -6,7 +6,6 @@ using CTA.Rules.Common.Extensions; using CTA.Rules.Config; using CTA.Rules.Models; -using CTA.Rules.Models.Actions.VisualBasic; using CTA.Rules.Models.Tokens.VisualBasic; using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; @@ -108,16 +107,8 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { switch (child.NodeType) { - case IdConstants.AttributeListName: + case IdConstants.AnnotationIdName: { - var attributeList = (AttributeList)child; - var compareToken = new AttributeListToken() { Key = attributeList.Identifier, Namespace = attributeList.Reference.Namespace, Type = attributeList.SemanticClassType }; - _visualBasicRootNodes.AttributeListTokens.TryGetValue(compareToken, out var token); - if (token != null) - { - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } break; } case IdConstants.ImportsStatementName: @@ -226,68 +217,12 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, classType.Identifier)) { containsActions = true; } break; } - case IdConstants.InterfaceBlockIdName: + case IdConstants.InterfaceIdName: { - var interfaceType = (InterfaceBlock)child; - var baseToken = new InterfaceBlockToken() { FullKey = interfaceType.BaseType }; - InterfaceBlockToken token = null; - - if (!string.IsNullOrEmpty(interfaceType.BaseType)) - { - _visualBasicRootNodes.InterfaceBlockTokens.TryGetValue(baseToken, out token); - } - - if (token != null) - { - //In case of interface blocks, add actions on the interface by name, instead of property - AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - - token = null; - string name = string.Concat(interfaceType.Reference != null ? string.Concat(interfaceType.Reference.Namespace, ".") : string.Empty, interfaceType.Identifier); - var nameToken = new InterfaceBlockToken() { FullKey = name }; - _visualBasicRootNodes.InterfaceBlockTokens.TryGetValue(baseToken, out token); - - if (token != null) - { - //In case of interface blocks, add actions on the interface by name, instead of property - AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace)) { containsActions = true; } break; } - case IdConstants.AccessorBlockName: - { - var accessorType = (AccessorBlock)child; - var name = string.Concat( - accessorType.Reference != null - ? string.Concat(accessorType.Reference.Namespace, ".") - : string.Empty, accessorType.Identifier); - var nameToken = new AccessorBlockToken() { FullKey = name }; - if (_visualBasicRootNodes.AccessorBlockTokens.TryGetValue(nameToken, out var token)) - { - AddNamedActions(fileAction, token, accessorType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - break; - } - case IdConstants.SubBlockName: + case IdConstants.MethodIdName: { - var compareToken = new MethodBlockToken() { FullKey = string.Concat(child.Identifier) }; - _visualBasicRootNodes.MethodBlockTokens.TryGetValue(compareToken, out var token); - if (token != null) - { - AddNamedActions(fileAction, token, child.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } break; } case IdConstants.InvocationIdName: @@ -364,21 +299,6 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, case IdConstants.MemberAccessIdName: { - MemberAccess memberAccess = (MemberAccess)child; - var compareToken = new VBMemberAccessToken() - { - Key = memberAccess.Name, - FullKey = GetFullKey(memberAccess.Reference?.Namespace, memberAccess.SemanticClassType, memberAccess.Name), - Type = memberAccess.SemanticClassType, - Namespace = memberAccess.Reference?.Namespace - }; - _visualBasicRootNodes.VBMemberAccesstokens.TryGetValue(compareToken, out var token); - if (token != null) - { - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } break; } case IdConstants.DeclarationNodeIdName: @@ -418,23 +338,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, return containsActions; } - - private string GetFullKey(string containingNamespace, string containingClass, string key) - { - if (string.IsNullOrEmpty(containingNamespace)) - { - return key; - } - else - { - if (!string.IsNullOrEmpty(containingClass)) - { - return $"{containingNamespace}.{containingClass}.{key}"; - } - return $"{containingNamespace}.{key}"; - } - } - + /// /// Add actions matching the token /// @@ -481,38 +385,12 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text NamespaceActionFunc = a.NamespaceActionFunc }).ToList()); - fileAction.VbIdentifierNameActions.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); - - fileAction.VbAttributeListActions.UnionWith(token.VbAttributeListActions.Select(a => new AttributeListAction() - { - Key = a.Key, - Description = a.Description, - Value = a.Value, - Name = a.Name, - Type = a.Type, - TextSpan = textSpan, - ActionValidation = a.ActionValidation, - AttributeListActionFunc = a.AttributeListActionFunc - }).ToList()); - - fileAction.MemberAccessActions.UnionWith(token.MemberAccessActions.Select(a => new MemberAccessAction() - { - Key = (token is VBMemberAccessToken) ? token.FullKey : a.Key, - Description = a.Description, - Value = a.Value, - Name = a.Name, - Type = a.Type, - TextSpan = textSpan, - ActionValidation = a.ActionValidation, - MemberAccessActionFunc = a.MemberAccessActionFunc - }).ToList()); + fileAction.VbIdentifierNameAction.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); if (fileAction.InvocationExpressionActions.Any() || fileAction.VbImportActions.Any() - || fileAction.VbNamespaceActions.Any() - || fileAction.VbIdentifierNameActions.Any() - || fileAction.VbAttributeListActions.Any() - || fileAction.MemberAccessActions.Any()) + || fileAction.NamespaceActions.Any() + || fileAction.IdentifierNameActions.Any()) { var nodeToken = token.Clone(); nodeToken.TextSpan = textSpan; @@ -563,61 +441,9 @@ private void AddNamedActions(FileActions fileAction, VisualBasicNodeToken token, ActionValidation = c.ActionValidation, TypeBlockActionFunc = c.TypeBlockActionFunc })); - - fileAction.VbMethodBlockActions.UnionWith(token.MethodBlockActions - .Select(c => new MethodBlockAction() - { - Key = identifier, - Value = c.Value, - Description = c.Description, - Name = c.Name, - Type = c.Type, - TextSpan = textSpan, - ActionValidation = c.ActionValidation, - MethodBlockActionFunc = c.MethodBlockActionFunc - })); - - fileAction.VbInterfaceBlockActions.UnionWith(token.InterfaceBlockActions - .Select(c => new InterfaceBlockAction() - { - Key = identifier, - Value = c.Value, - Name = c.Name, - Type = c.Type, - Description = c.Description, - TextSpan = textSpan, - ActionValidation = c.ActionValidation, - InterfaceBlockActionFunc = c.InterfaceBlockActionFunc - })); - - fileAction.VbInterfaceBlockActions.UnionWith(token.InterfaceBlockActions - .Select(c => new InterfaceBlockAction() - { - Key = identifier, - Value = c.Value, - Name = c.Name, - Type = c.Type, - Description = c.Description, - TextSpan = textSpan, - ActionValidation = c.ActionValidation, - InterfaceBlockActionFunc = c.InterfaceBlockActionFunc - })); - - fileAction.VbAccessorBlockActions.UnionWith(token.AccessorBlockActions - .Select(c => new AccessorBlockAction() - { - Key = identifier, - Value = c.Value, - Name = c.Name, - Type = c.Type, - Description = c.Description, - TextSpan = textSpan, - ActionValidation = c.ActionValidation, - AccessorBlockActionFunc = c.AccessorBlockActionFunc - })); - - if (fileAction.VbTypeBlockActions.Any() || fileAction.VbMethodBlockActions.Any() - || fileAction.VbInterfaceBlockActions.Any() || fileAction.VbAccessorBlockActions.Any()) + + if (fileAction.ClassDeclarationActions.Any() || fileAction.InterfaceDeclarationActions.Any() || + fileAction.MethodDeclarationActions.Any() || fileAction.ObjectCreationExpressionActions.Any()) { var nodeToken = token.Clone(); nodeToken.TextSpan = textSpan; diff --git a/src/CTA.Rules.Config/CTA.Rules.Config.csproj b/src/CTA.Rules.Config/CTA.Rules.Config.csproj index 7c44c625..0da75399 100644 --- a/src/CTA.Rules.Config/CTA.Rules.Config.csproj +++ b/src/CTA.Rules.Config/CTA.Rules.Config.csproj @@ -5,17 +5,14 @@ + + - - - - - diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs deleted file mode 100644 index 30fe7449..00000000 --- a/src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; - -namespace CTA.Rules.Models.Actions.VisualBasic -{ - public class AccessorBlockAction : GenericAction - { - public Func AccessorBlockActionFunc { get; set; } - - public override bool Equals(object obj) - { - var action = (AccessorBlockAction)obj; - return action?.Key == this.Key - && action?.Value == this.Value - && action?.AccessorBlockActionFunc.Method.Name == this.AccessorBlockActionFunc.Method.Name; - } - - public override int GetHashCode() - { - return HashCode.Combine(Key, Value, AccessorBlockActionFunc?.Method.Name); - } - } -} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs deleted file mode 100644 index d27e6d7e..00000000 --- a/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using Microsoft.CodeAnalysis.Editing; - -namespace CTA.Rules.Models.Actions.VisualBasic -{ - public class AttributeListAction : GenericAction - { - public Func AttributeListActionFunc { get; set; } - - public override bool Equals(object obj) - { - var action = (AttributeAction)obj; - return action?.Key == this.Key - && action?.Value == this.Value - && action.AttributeListActionFunc != null && this.AttributeListActionFunc != null - && action.AttributeListActionFunc.Method.Name == this.AttributeListActionFunc.Method.Name; - } - - public override int GetHashCode() - { - return HashCode.Combine(Key, Value, AttributeListActionFunc?.Method.Name); - } - } -} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs deleted file mode 100644 index f32cc85b..00000000 --- a/src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using Microsoft.CodeAnalysis.Editing; - -namespace CTA.Rules.Models.Actions.VisualBasic -{ - public class InterfaceBlockAction : GenericAction - { - public Func InterfaceBlockActionFunc { get; set; } - - public override bool Equals(object obj) - { - var action = (InterfaceBlockAction)obj; - return action?.Key == this.Key - && action?.Value == this.Value - && action?.InterfaceBlockActionFunc.Method.Name == this.InterfaceBlockActionFunc.Method.Name; - } - - public override int GetHashCode() - { - return HashCode.Combine(Key, Value, InterfaceBlockActionFunc?.Method.Name); - } - } -} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs deleted file mode 100644 index 7703b3ee..00000000 --- a/src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using Microsoft.CodeAnalysis.Editing; - -namespace CTA.Rules.Models.Actions.VisualBasic -{ - public class MethodBlockAction : GenericAction - { - public Func MethodBlockActionFunc { get; set; } - - public override bool Equals(object obj) - { - var action = (MethodBlockAction)obj; - return action?.Key == this.Key - && action?.Value == this.Value - && action?.MethodBlockActionFunc.Method.Name == this.MethodBlockActionFunc.Method.Name; - } - - public override int GetHashCode() - { - return HashCode.Combine(Key, Value, MethodBlockActionFunc?.Method.Name); - } - } -} diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index 61651f39..e7a23d06 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using CTA.Rules.Models.Actions.VisualBasic; using CTA.Rules.Models.Tokens; using CTA.Rules.Models.Tokens.VisualBasic; using CTA.Rules.Models.VisualBasic; @@ -38,11 +37,6 @@ public FileActions() VbNamespaceActions = new HashSet>(); VbTypeBlockActions = new HashSet(); - VbMethodBlockActions = new HashSet(); - VbInterfaceBlockActions = new HashSet(); - VbAttributeListActions = new HashSet(); - VbIdentifierNameActions = new HashSet>(); - VbAccessorBlockActions = new HashSet(); } public HashSet> VbNamespaceActions { get; set; } @@ -50,13 +44,9 @@ public FileActions() public HashSet> VbInvocationExpressionActions { get; set; } public HashSet> - VbIdentifierNameActions { get; set; } + VbIdentifierNameAction { get; set; } public HashSet VbTypeBlockActions { get; set; } - public HashSet VbMethodBlockActions { get; set; } - public HashSet VbInterfaceBlockActions { get; set; } - public HashSet VbAttributeListActions { get; set; } - public HashSet VbAccessorBlockActions { get; set; } public List VbNodeTokens { get; set; } public List NodeTokens { get; set; } @@ -95,11 +85,6 @@ public List AllActions allActions.AddRange(VbNamespaceActions); allActions.AddRange(VbInvocationExpressionActions); allActions.AddRange(VbTypeBlockActions); - allActions.AddRange(VbMethodBlockActions); - allActions.AddRange(VbInterfaceBlockActions); - allActions.AddRange(VbAttributeListActions); - allActions.AddRange(VbIdentifierNameActions); - allActions.AddRange(VbAccessorBlockActions); return allActions; } } diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs deleted file mode 100644 index 28057aed..00000000 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace CTA.Rules.Models.Tokens.VisualBasic -{ - public class AccessorBlockToken : VisualBasicNodeToken - { - public override bool Equals(object obj) - { - var token = (AccessorBlockToken)obj; - return token?.Type == this.Type && token?.Namespace == this.Namespace && token?.Key.Trim() == this.Key.Trim(); - } - - public override int GetHashCode() - { - return HashCode.Combine(Key, Namespace, Type); - } - } -} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs deleted file mode 100644 index fd1c209f..00000000 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace CTA.Rules.Models.Tokens.VisualBasic -{ - public class AttributeListToken : VisualBasicNodeToken - { - public override bool Equals(object obj) - { - var token = (AttributeListToken)obj; - return token?.Type == this.Type && token?.Namespace == this.Namespace && token?.Key.Trim() == this.Key.Trim(); - } - - public override int GetHashCode() - { - return HashCode.Combine(Key, Namespace, Type); - } - } -} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs deleted file mode 100644 index 3dbc518e..00000000 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using CTA.Rules.Models.Tokens; - -namespace CTA.Rules.Models.Tokens.VisualBasic -{ - public class InterfaceBlockToken : VisualBasicNodeToken - { - public override bool Equals(object obj) - { - var token = (InterfaceBlockToken)obj; - return token?.FullKey == this.FullKey; - } - public override int GetHashCode() - { - return HashCode.Combine(FullKey); - } - } -} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs deleted file mode 100644 index bead566e..00000000 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace CTA.Rules.Models.Tokens.VisualBasic -{ - public class MethodBlockToken : VisualBasicNodeToken - { - public override bool Equals(object obj) - { - var token = (MethodBlockToken)obj; - return token?.FullKey == this.FullKey; - } - public override int GetHashCode() - { - return HashCode.Combine(FullKey); - } - } -} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs deleted file mode 100644 index 39339d80..00000000 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - - -namespace CTA.Rules.Models.Tokens.VisualBasic -{ - public class VBMemberAccessToken : VisualBasicNodeToken - { - public override bool Equals(object obj) - { - var token = (VBMemberAccessToken)obj; - return token?.FullKey == this.FullKey; - } - public override int GetHashCode() - { - return HashCode.Combine(FullKey); - } - } -} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs index 40e1506e..b341d34f 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs @@ -3,7 +3,6 @@ using System.Configuration; using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using CTA.Rules.Models.Actions.VisualBasic; namespace CTA.Rules.Models.Tokens.VisualBasic { @@ -16,10 +15,7 @@ public VisualBasicNodeToken() NamespaceActions = new List>(); IdentifierNameActions = new List>(); TypeBlockActions = new List(); - MethodBlockActions = new List(); - InterfaceBlockActions = new List(); - VbAttributeListActions = new List(); - AccessorBlockActions = new List(); + } public List> InvocationExpressionActions { get; set; } @@ -27,10 +23,7 @@ public VisualBasicNodeToken() public List> NamespaceActions { get; set; } public List> IdentifierNameActions { get; set; } public List TypeBlockActions { get; set; } - public List MethodBlockActions { get; set; } - public List InterfaceBlockActions { get; set; } - public List VbAttributeListActions { get; set; } - public List AccessorBlockActions { get; set; } + public override VisualBasicNodeToken Clone() { @@ -45,14 +38,6 @@ public override VisualBasicNodeToken Clone() .Select(action => action.Clone>()).ToList(); cloned.TypeBlockActions = cloned.TypeBlockActions .Select(action => action.Clone()).ToList(); - cloned.MethodBlockActions = cloned.MethodBlockActions - .Select(action => action.Clone()).ToList(); - cloned.InterfaceBlockActions = cloned.InterfaceBlockActions - .Select(action => action.Clone()).ToList(); - cloned.VbAttributeListActions = cloned.VbAttributeListActions - .Select(action => action.Clone()).ToList(); - cloned.AccessorBlockActions = cloned.AccessorBlockActions - .Select(action => action.Clone()).ToList(); return cloned; } @@ -66,10 +51,6 @@ public override List AllActions allActions.AddRange(ImportActions); allActions.AddRange(IdentifierNameActions); allActions.AddRange(TypeBlockActions); - allActions.AddRange(MethodBlockActions); - allActions.AddRange(InterfaceBlockActions); - allActions.AddRange(AttributeListActions); - allActions.AddRange(AccessorBlockActions); allActions.AddRange(base.AllActions); return allActions; } diff --git a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs index 79414d67..50498832 100644 --- a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs +++ b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs @@ -13,11 +13,6 @@ public VisualBasicRootNodes() { InvocationExpressionTokens = new HashSet(); ImportStatementTokens = new HashSet(); - InterfaceBlockTokens = new HashSet(); - MethodBlockTokens = new HashSet(); - AttributeListTokens = new HashSet(); - AccessorBlockTokens = new HashSet(); - VBMemberAccesstokens = new HashSet(); NamespaceTokens = new HashSet(); ProjectTokens = new HashSet(); IdentifierNameTokens = new HashSet(); @@ -26,11 +21,6 @@ public VisualBasicRootNodes() public HashSet InvocationExpressionTokens { get; set; } public HashSet ImportStatementTokens { get; set; } - public HashSet InterfaceBlockTokens { get; set; } - public HashSet MethodBlockTokens { get; set; } - public HashSet AttributeListTokens { get; set; } - public HashSet AccessorBlockTokens { get; set; } - public HashSet VBMemberAccesstokens { get; set; } public HashSet NamespaceTokens { get; set; } public HashSet ProjectTokens { get; set; } public HashSet IdentifierNameTokens { get; set; } diff --git a/src/CTA.Rules.Models/packages.lock.json b/src/CTA.Rules.Models/packages.lock.json index 69b06e4a..5a3a47f3 100644 --- a/src/CTA.Rules.Models/packages.lock.json +++ b/src/CTA.Rules.Models/packages.lock.json @@ -26,10 +26,10 @@ }, "Buildalyzer": { "type": "Transitive", - "resolved": "4.1.4", - "contentHash": "O6KGKPeCAe+Ujhd2sl66nu7rrEAM2hBUbi3n79BVBOj9YxuUlbxviOfy3Cq22iIp9rUDPOqOL8E2AYiQwxpUHQ==", + "resolved": "4.1.3", + "contentHash": "25NJRnGgYBOC3OPgFDj/KeJwSldXPFZl5jDXjqP7Vsy6vC+MPapcJ687/dOjUeS4t4aVuYrMyWdaezkZgs+Rdw==", "dependencies": { - "Buildalyzer.Logger": "4.1.4", + "Buildalyzer.Logger": "4.1.3", "MSBuild.StructuredLogger": "2.1.507", "Microsoft.Build": "16.9.0", "Microsoft.Build.Framework": "16.9.0", @@ -45,19 +45,75 @@ }, "Buildalyzer.Logger": { "type": "Transitive", - "resolved": "4.1.4", - "contentHash": "2C2FR877slFBYM/usMkGnmOZlLKejV0uag0IzmARkKkBD75jNPM6q2WLaFAW/yRLPyyArpunYzQ+4AaDyEImHQ==" + "resolved": "4.1.3", + "contentHash": "9qq5VfFO/cvasetqJpj+V5sc8Ng5EQjCkYi3COOvzyqNLivYIp+4Cf1ddfbcye3X3i89z9oHIEmF3iNQspFSDw==" }, "Buildalyzer.Workspaces": { "type": "Transitive", - "resolved": "4.1.4", - "contentHash": "fU4I3dmFDTickARibqYYJb+uDYUxlHM32a0CQgY2dVBJKnf9DFnVkiQjxbhdxGOylHI6lTZm+EdAEqXcjIe4xg==", + "resolved": "4.1.3", + "contentHash": "rZGc9XTd0RzLa3tMG9HfNzhxLKGNerCzW3f+nG/Mau0ucpRENWn7OH9Nz9ZxD3k4oWweOw9kfGfw4VvbcNP43w==", "dependencies": { - "Buildalyzer": "4.1.4", + "Buildalyzer": "4.1.3", "Microsoft.CodeAnalysis.CSharp.Workspaces": "4.1.0", "Microsoft.CodeAnalysis.VisualBasic.Workspaces": "4.1.0" } }, + "Codelyzer.Analysis": { + "type": "Transitive", + "resolved": "2.3.45", + "contentHash": "DxE+I7g3fcVRFmdIRQ78dOPso8BYUtvYSrGF0/7wak1iitGLLaColSqoRfQEGeM5//77jWP/qAxKwBHsKEVKBg==", + "dependencies": { + "Codelyzer.Analysis.Build": "2.3.45", + "Codelyzer.Analysis.CSharp": "2.3.45", + "CommandLineParser": "2.8.0", + "Microsoft.Extensions.Logging.Console": "6.0.0", + "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196" + } + }, + "Codelyzer.Analysis.Build": { + "type": "Transitive", + "resolved": "2.3.45", + "contentHash": "8Bm/UBtunuhTZCg+osoAas2uYRM2VEunBQUVjOrn26+mIflgucEjvCWogEDH4UOiQKRcqhlSN/6lLlkoWuEqtw==", + "dependencies": { + "Buildalyzer": "4.1.3", + "Buildalyzer.Logger": "4.1.3", + "Buildalyzer.Workspaces": "4.1.3", + "Codelyzer.Analysis.CSharp": "2.3.45", + "Microsoft.Extensions.Logging": "6.0.0", + "NuGet.Packaging": "6.0.0" + } + }, + "Codelyzer.Analysis.Common": { + "type": "Transitive", + "resolved": "2.3.45", + "contentHash": "mNRMSFSoVqCFnQ1GkJx1dmQ79xYjivtrGbi9TWA+F+mA1wh0AEy/folP7r5ykydEVH2sKyjBvUhjuVtNP4GzIg==", + "dependencies": { + "Codelyzer.Analysis.Model": "2.3.45", + "Microsoft.Build": "17.0.0", + "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", + "Newtonsoft.Json": "13.0.1" + } + }, + "Codelyzer.Analysis.CSharp": { + "type": "Transitive", + "resolved": "2.3.45", + "contentHash": "KIwFpFTjx4vP3DeA3oObUA4/ZBTwyPpcvzNxuYrVbmWebtxk8H1Fhhi6HCMp7XRDtTClw/SOg9OJJGOBtuEo8A==", + "dependencies": { + "Codelyzer.Analysis.Common": "2.3.45", + "Codelyzer.Analysis.Model": "2.3.45" + } + }, + "Codelyzer.Analysis.Model": { + "type": "Transitive", + "resolved": "2.3.45", + "contentHash": "c5BQYmHrbMt72EJ8eG3VFLzBAoZVUM1eDBJoJRRKkif0JlkP31iEE12SeotoGuBthm5M1soDNEw2FsxWuqJcWA==", + "dependencies": { + "Microsoft.CodeAnalysis": "4.1.0", + "Microsoft.CodeAnalysis.CSharp": "4.1.0", + "Microsoft.Extensions.Logging": "6.0.0", + "Newtonsoft.Json": "13.0.1" + } + }, "CommandLineParser": { "type": "Transitive", "resolved": "2.8.0", @@ -95,10 +151,9 @@ }, "Microsoft.Build.Framework": { "type": "Transitive", - "resolved": "17.1.0", - "contentHash": "7PPEbjuL/lKQ8ftblxwBZKf5alZCA4GDvBTiO3UAVxtRe52a2jL3mc8TpKNiJZzytGz7fKdR5ClDCs7+Uw4hMg==", + "resolved": "17.0.0", + "contentHash": "XbFA0z+6Ws2pNeRXYcDF3lKlNgRoSGMm2Q5HKzZD+EbwYMKPKrl/BJnnkMuDJHU0KravYHfhzBnLLJpPeZ3E7A==", "dependencies": { - "Microsoft.Win32.Registry": "4.3.0", "System.Security.Permissions": "4.7.0" } }, @@ -129,14 +184,12 @@ }, "Microsoft.Build.Utilities.Core": { "type": "Transitive", - "resolved": "17.1.0", - "contentHash": "JqhQ4q6L4IyA0Wh3PrDrxHHYMVHyOLIusyC4imAnhcnZiOC4+CwgVRSdo8fLsQmvz0Jab8FFrU1NPZFbDoxRng==", + "resolved": "16.9.0", + "contentHash": "rpxfQlBo2hkFODFJZKPYxMsl5QGIqQ6GlSYnQGKhl+Fu65cvJDk4jRi/R9i+X5/+lSeHhRlQbo+UUhg6cqMkRw==", "dependencies": { - "Microsoft.Build.Framework": "17.1.0", - "Microsoft.NET.StringTools": "1.0.0", + "Microsoft.Build.Framework": "16.9.0", "Microsoft.Win32.Registry": "4.3.0", "System.Collections.Immutable": "5.0.0", - "System.Configuration.ConfigurationManager": "4.7.0", "System.Security.Permissions": "4.7.0", "System.Text.Encoding.CodePages": "4.0.1" } @@ -451,15 +504,6 @@ "Microsoft.Build.Utilities.Core": "16.4.0" } }, - "MsBuildPipeLogger.Logger": { - "type": "Transitive", - "resolved": "1.1.6", - "contentHash": "yUnnZQJfRkp+tSyBVFJSpobU6nRrR063l5GJLKWo9fl+GMx9BW+OzV4umqhoHRrmz22xsRBYhCNpoSQR6q0u0Q==", - "dependencies": { - "System.IO.Pipes": "4.3.0", - "System.Threading.Thread": "4.3.0" - } - }, "MsBuildPipeLogger.Server": { "type": "Transitive", "resolved": "1.1.6", @@ -1045,32 +1089,6 @@ "resolved": "5.0.1", "contentHash": "qEePWsaq9LoEEIqhbGe6D5J8c9IqQOUuTzzV6wn1POlfdLkJliZY3OlB0j0f17uMWlqZYjH7txj+2YbyrIA8Yg==" }, - "System.IO.Pipes": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "wpGJuACA6r8+KRckXoI6ghGTwgPRiICI6T7kgHI/m7S5eMqV/8jH37fzAUhTwIe9RwlH/j1sWwm2Q2zyXwZGHw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Buffers": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Net.Primitives": "4.3.0", - "System.Net.Sockets": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Principal": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Overlapped": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "runtime.native.System": "4.3.0" - } - }, "System.Linq": { "type": "Transitive", "resolved": "4.3.0", @@ -1517,14 +1535,6 @@ "System.Windows.Extensions": "6.0.0" } }, - "System.Security.Principal": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Security.Principal.Windows": { "type": "Transitive", "resolved": "4.7.0", @@ -1594,17 +1604,6 @@ "System.Threading.Tasks": "4.3.0" } }, - "System.Threading.Overlapped": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "m3HQ2dPiX/DSTpf+yJt8B0c+SRvzfqAJKx+QDWi+VLhz8svLT23MVjEOHPF/KiSLeArKU/iHescrbLd3yVgyNg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0" - } - }, "System.Threading.Tasks": { "type": "Transitive", "resolved": "4.3.0", @@ -1625,14 +1624,6 @@ "resolved": "4.5.4", "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" }, - "System.Threading.Thread": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, "System.Threading.Timer": { "type": "Transitive", "resolved": "4.3.0", @@ -1692,63 +1683,6 @@ "System.Xml.ReaderWriter": "4.3.0" } }, - "codelyzer.analysis": { - "type": "Project", - "dependencies": { - "Codelyzer.Analysis.Build": "1.0.0", - "Codelyzer.Analysis.CSharp": "1.0.0", - "Codelyzer.Analysis.VisualBasic": "1.0.0", - "CommandLineParser": "2.8.0", - "Microsoft.Build.Utilities.Core": "17.1.0", - "Microsoft.Extensions.Logging.Console": "6.0.0", - "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", - "MsBuildPipeLogger.Logger": "1.1.6" - } - }, - "codelyzer.analysis.build": { - "type": "Project", - "dependencies": { - "Buildalyzer": "4.1.4", - "Buildalyzer.Logger": "4.1.4", - "Buildalyzer.Workspaces": "4.1.4", - "Codelyzer.Analysis.CSharp": "1.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "NuGet.Packaging": "6.0.0" - } - }, - "codelyzer.analysis.common": { - "type": "Project", - "dependencies": { - "Codelyzer.Analysis.Model": "1.0.0", - "Microsoft.Build": "17.0.0", - "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", - "Newtonsoft.Json": "13.0.1" - } - }, - "codelyzer.analysis.csharp": { - "type": "Project", - "dependencies": { - "Codelyzer.Analysis.Common": "1.0.0", - "Codelyzer.Analysis.Model": "1.0.0" - } - }, - "codelyzer.analysis.model": { - "type": "Project", - "dependencies": { - "Microsoft.CodeAnalysis": "4.1.0", - "Microsoft.CodeAnalysis.CSharp": "4.1.0", - "Microsoft.CodeAnalysis.VisualBasic": "4.1.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Newtonsoft.Json": "13.0.1" - } - }, - "codelyzer.analysis.visualbasic": { - "type": "Project", - "dependencies": { - "Codelyzer.Analysis.Common": "1.0.0", - "Codelyzer.Analysis.Model": "1.0.0" - } - }, "cta.rules.common": { "type": "Project", "dependencies": { @@ -1759,8 +1693,8 @@ "cta.rules.config": { "type": "Project", "dependencies": { - "Codelyzer.Analysis": "1.0.0", - "Codelyzer.Analysis.Model": "1.0.0", + "Codelyzer.Analysis": "2.3.45", + "Codelyzer.Analysis.Model": "2.3.45", "Microsoft.Extensions.Logging": "6.0.0", "Microsoft.Extensions.Logging.Abstractions": "6.0.0", "Microsoft.Extensions.Logging.Console": "6.0.0", diff --git a/src/CTA.Rules.sln b/src/CTA.Rules.sln index 2b4a4b70..d5153d1d 100644 --- a/src/CTA.Rules.sln +++ b/src/CTA.Rules.sln @@ -46,10 +46,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CTA.WebForms", "CTA.WebForm EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CTA.WebForms.Tests", "..\tst\CTA.WebForms.Tests\CTA.WebForms.Tests.csproj", "{A4F48CAF-6376-4929-9D64-CE123EBA6329}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Codelyzer.Analysis", "..\..\codelyzer\src\Analysis\Codelyzer.Analysis\Codelyzer.Analysis.csproj", "{786BBCC7-19FE-4641-B8B0-842DB52A09AC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Codelyzer.Analysis.Model", "..\..\codelyzer\src\Analysis\Codelyzer.Analysis.Model\Codelyzer.Analysis.Model.csproj", "{F9C39261-0BA2-4BA8-A0F2-FE3FF41F6E54}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -132,14 +128,6 @@ Global {A4F48CAF-6376-4929-9D64-CE123EBA6329}.Debug|Any CPU.Build.0 = Debug|Any CPU {A4F48CAF-6376-4929-9D64-CE123EBA6329}.Release|Any CPU.ActiveCfg = Release|Any CPU {A4F48CAF-6376-4929-9D64-CE123EBA6329}.Release|Any CPU.Build.0 = Release|Any CPU - {786BBCC7-19FE-4641-B8B0-842DB52A09AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {786BBCC7-19FE-4641-B8B0-842DB52A09AC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {786BBCC7-19FE-4641-B8B0-842DB52A09AC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {786BBCC7-19FE-4641-B8B0-842DB52A09AC}.Release|Any CPU.Build.0 = Release|Any CPU - {F9C39261-0BA2-4BA8-A0F2-FE3FF41F6E54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F9C39261-0BA2-4BA8-A0F2-FE3FF41F6E54}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F9C39261-0BA2-4BA8-A0F2-FE3FF41F6E54}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F9C39261-0BA2-4BA8-A0F2-FE3FF41F6E54}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From eb481500c08a6348d2b1f0f712d68a468ae33074 Mon Sep 17 00:00:00 2001 From: dongzw-amz Date: Wed, 8 Jun 2022 13:50:44 -0700 Subject: [PATCH 29/61] Add several syntax nodes to rules analysis --- .../VisualBasicRulesAnalysis.cs | 517 ++++++++++++------ src/CTA.Rules.Config/CTA.Rules.Config.csproj | 4 +- .../VisualBasic/AccessorBlockAction.cs | 24 + .../VisualBasic/AttributeListAction.cs | 25 + .../VisualBasic/InterfaceBlockAction.cs | 24 + .../Actions/VisualBasic/MethodBlockAction.cs | 24 + .../FileActions/FileActions.cs | 26 +- .../Tokens/VisualBasic/AccessorBlockToken.cs | 18 + .../Tokens/VisualBasic/AttributeListToken.cs | 18 + .../Tokens/VisualBasic/InterfaceBlockToken.cs | 18 + .../Tokens/VisualBasic/MethodBlockToken.cs | 17 + .../Tokens/VisualBasic/VBMemberAccessToken.cs | 18 + .../VisualBasic/VisualBasicNodeToken.cs | 25 +- .../VisualBasic/VisualBasicRootNodes.cs | 10 + 14 files changed, 582 insertions(+), 186 deletions(-) create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs diff --git a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs index 509d0dcb..69991cd0 100644 --- a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs @@ -6,6 +6,7 @@ using CTA.Rules.Common.Extensions; using CTA.Rules.Config; using CTA.Rules.Models; +using CTA.Rules.Models.Actions.VisualBasic; using CTA.Rules.Models.Tokens.VisualBasic; using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; @@ -21,7 +22,7 @@ public class VisualBasicRulesAnalysis : IRulesAnalysis private readonly List _sourceFileResults; private readonly ProjectActions _projectActions; private readonly ProjectType _projectType; - + /// /// Initializes a RulesAnalysis instance for Visual Basic projects /// @@ -36,7 +37,7 @@ public VisualBasicRulesAnalysis(List sourceFileResults, VisualBasic _visualBasicRootNodes = visualBasicRootNodes; _projectType = projectType; } - + public ProjectActions Analyze() { var options = new ParallelOptions { MaxDegreeOfParallelism = Constants.ThreadCount }; @@ -84,7 +85,7 @@ public ProjectActions AnalyzeFiles(ProjectActions projectActions, List u }); return _projectActions; } - + /// /// Analyzes children of nodes in a particular file /// @@ -107,105 +108,102 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { switch (child.NodeType) { - case IdConstants.AnnotationIdName: - { - break; - } - case IdConstants.ImportsStatementName: - { - var overrideKey = string.Empty; - - var compareToken = new ImportStatementToken { Key = child.Identifier }; - _visualBasicRootNodes.ImportStatementTokens.TryGetValue(compareToken, out var token); - if (token != null) + case IdConstants.AttributeListName: { - AddActions(fileAction, token, child.TextSpan); - containsActions = true; + var attributeList = (AttributeList)child; + var compareToken = new AttributeListToken() { Key = attributeList.Identifier, Namespace = attributeList.Reference.Namespace, Type = attributeList.SemanticClassType }; + _visualBasicRootNodes.AttributeListTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + break; } - - //Attempt a wildcard search, if applicable. This is import specific because it might want to include all sub-namespaces - if (token == null) + case IdConstants.ImportsStatementName: { - var wildcardMatches = _visualBasicRootNodes.ImportStatementTokens - .Where(i => i.Key.Contains("*")).ToList(); - if (wildcardMatches.Any()) + var overrideKey = string.Empty; + + var compareToken = new ImportStatementToken { Key = child.Identifier }; + _visualBasicRootNodes.ImportStatementTokens.TryGetValue(compareToken, out var token); + if (token != null) { - token = wildcardMatches.FirstOrDefault(i => compareToken.Key.WildcardEquals(i.Key)); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } - if (token != null) + //Attempt a wildcard search, if applicable. This is import specific because it might want to include all sub-namespaces + if (token == null) + { + var wildcardMatches = _visualBasicRootNodes.ImportStatementTokens + .Where(i => i.Key.Contains("*")).ToList(); + if (wildcardMatches.Any()) { - //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code - overrideKey = compareToken.Key; + token = wildcardMatches.FirstOrDefault(i => compareToken.Key.WildcardEquals(i.Key)); + + if (token != null) + { + //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code + overrideKey = compareToken.Key; + } } } + if (token != null) + { + AddActions(fileAction, token, child.TextSpan, overrideKey); + containsActions = true; + } + break; } - if (token != null) - { - AddActions(fileAction, token, child.TextSpan, overrideKey); - containsActions = true; - } - break; - } case IdConstants.NamespaceBlockIdName: - { - var compareToken = new NamespaceToken { Key = child.Identifier }; - _visualBasicRootNodes.NamespaceTokens.TryGetValue(compareToken, out var token); - if (token != null) { - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - if (AnalyzeChildren(fileAction, child.Children, ++level, child.Identifier)) - { - containsActions = true; + var compareToken = new NamespaceToken { Key = child.Identifier }; + _visualBasicRootNodes.NamespaceTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, child.Identifier)) + { + containsActions = true; + } + break; } - break; - } case IdConstants.ModuleBlockName: - { - var moduleType = (ModuleBlock)child; - var name = string.Concat( - moduleType.Reference != null - ? string.Concat(moduleType.Reference.Namespace, ".") - : string.Empty, moduleType.Identifier); - var nameToken = new TypeBlockToken() { FullKey = name }; - if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out var token)) { - AddNamedActions(fileAction, token, moduleType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; + var moduleType = (ModuleBlock)child; + var name = string.Concat( + moduleType.Reference != null + ? string.Concat(moduleType.Reference.Namespace, ".") + : string.Empty, moduleType.Identifier); + var nameToken = new TypeBlockToken() { FullKey = name }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out var token)) + { + AddNamedActions(fileAction, token, moduleType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + break; } - break; - } case IdConstants.ClassBlockName: - { - var classType = (ClassBlock)child; - var baseToken = new TypeBlockToken() { FullKey = classType.BaseType }; - if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseToken, out var token)) - { - AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - - token = null; - var name = string.Concat( - classType.Reference != null - ? string.Concat(classType.Reference.Namespace, ".") - : string.Empty, classType.Identifier); - var nameToken = new TypeBlockToken() { FullKey = name }; - if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out token)) { - AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } + var classType = (ClassBlock)child; + var baseToken = new TypeBlockToken() { FullKey = classType.BaseType }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseToken, out var token)) + { + AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } - token = null; - foreach (string interfaceName in classType.Inherits) - { - var baseListToken = new TypeBlockToken() { FullKey = interfaceName }; - if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseListToken, out token)) + token = null; + var name = string.Concat( + classType.Reference != null + ? string.Concat(classType.Reference.Namespace, ".") + : string.Empty, classType.Identifier); + var nameToken = new TypeBlockToken() { FullKey = name }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out token)) { AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); AddActions(fileAction, token, child.TextSpan); @@ -213,120 +211,202 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, } token = null; + foreach (string interfaceName in classType.Inherits) + { + var baseListToken = new TypeBlockToken() { FullKey = interfaceName }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseListToken, out token)) + { + AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + token = null; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, classType.Identifier)) { containsActions = true; } + break; } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, classType.Identifier)) { containsActions = true; } - break; - } - case IdConstants.InterfaceIdName: - { - break; - } - case IdConstants.MethodIdName: - { - break; - } - case IdConstants.InvocationIdName: - { - var overrideKey = string.Empty; + case IdConstants.InterfaceBlockIdName: + { + var interfaceType = (InterfaceBlock)child; + var baseToken = new InterfaceBlockToken() { FullKey = interfaceType.BaseType }; + InterfaceBlockToken token = null; - InvocationExpression invocationExpression = (InvocationExpression)child; + if (!string.IsNullOrEmpty(interfaceType.BaseType)) + { + _visualBasicRootNodes.InterfaceBlockTokens.TryGetValue(baseToken, out token); + } - ////If we don't have a semantic analysis, we dont want to replace invocation expressions, otherwise we'll be replacing expressions regardless of their class/namespace - if (string.IsNullOrEmpty(invocationExpression.SemanticOriginalDefinition)) - { + if (token != null) + { + //In case of interface blocks, add actions on the interface by name, instead of property + AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + token = null; + string name = string.Concat(interfaceType.Reference != null ? string.Concat(interfaceType.Reference.Namespace, ".") : string.Empty, interfaceType.Identifier); + var nameToken = new InterfaceBlockToken() { FullKey = name }; + _visualBasicRootNodes.InterfaceBlockTokens.TryGetValue(baseToken, out token); + + if (token != null) + { + //In case of interface blocks, add actions on the interface by name, instead of property + AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace)) { containsActions = true; } break; } - - var compareToken = new InvocationExpressionToken + case IdConstants.AccessorBlockName: { - Key = invocationExpression.SemanticOriginalDefinition, - Namespace = invocationExpression.Reference.Namespace, - Type = invocationExpression.SemanticClassType - }; - _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out var token); - - //Attempt a wildcard search, if applicable. This is invocation expression specific because it has to look inside the invocation expressions only - if (token == null) + var accessorType = (AccessorBlock)child; + var name = string.Concat( + accessorType.Reference != null + ? string.Concat(accessorType.Reference.Namespace, ".") + : string.Empty, accessorType.Identifier); + var nameToken = new AccessorBlockToken() { FullKey = name }; + if (_visualBasicRootNodes.AccessorBlockTokens.TryGetValue(nameToken, out var token)) + { + AddNamedActions(fileAction, token, accessorType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + break; + } + case IdConstants.SubBlockName: { - var wildcardMatches = - _visualBasicRootNodes.InvocationExpressionTokens.Where(i => i.Key.Contains("*")); - if (wildcardMatches.Any()) + var compareToken = new MethodBlockToken() { FullKey = string.Concat(child.Identifier) }; + _visualBasicRootNodes.MethodBlockTokens.TryGetValue(compareToken, out var token); + if (token != null) { - token = wildcardMatches.FirstOrDefault(i => - compareToken.Key.WildcardEquals(i.Key) && compareToken.Namespace == i.Namespace && - compareToken.Type == i.Type); + AddNamedActions(fileAction, token, child.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } + break; + } + case IdConstants.InvocationIdName: + { + var overrideKey = string.Empty; - if (token != null) - { - //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code - overrideKey = compareToken.Key; - } + InvocationExpression invocationExpression = (InvocationExpression)child; + + ////If we don't have a semantic analysis, we dont want to replace invocation expressions, otherwise we'll be replacing expressions regardless of their class/namespace + if (string.IsNullOrEmpty(invocationExpression.SemanticOriginalDefinition)) + { + break; } - //If the semanticClassType is too specific to apply to all TData types + var compareToken = new InvocationExpressionToken + { + Key = invocationExpression.SemanticOriginalDefinition, + Namespace = invocationExpression.Reference.Namespace, + Type = invocationExpression.SemanticClassType + }; + _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out var token); + + //Attempt a wildcard search, if applicable. This is invocation expression specific because it has to look inside the invocation expressions only if (token == null) { - if (invocationExpression.SemanticClassType.Contains('<')) + var wildcardMatches = + _visualBasicRootNodes.InvocationExpressionTokens.Where(i => i.Key.Contains("*")); + if (wildcardMatches.Any()) + { + token = wildcardMatches.FirstOrDefault(i => + compareToken.Key.WildcardEquals(i.Key) && compareToken.Namespace == i.Namespace && + compareToken.Type == i.Type); + + if (token != null) + { + //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code + overrideKey = compareToken.Key; + } + } + + //If the semanticClassType is too specific to apply to all TData types + if (token == null) { - string semanticClassType = invocationExpression.SemanticClassType.Substring(0, - invocationExpression.SemanticClassType.IndexOf('<')); - compareToken = new InvocationExpressionToken + if (invocationExpression.SemanticClassType.Contains('<')) { - Key = invocationExpression.SemanticOriginalDefinition, - Namespace = invocationExpression.Reference.Namespace, - Type = semanticClassType - }; - _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out token); + string semanticClassType = invocationExpression.SemanticClassType.Substring(0, + invocationExpression.SemanticClassType.IndexOf('<')); + compareToken = new InvocationExpressionToken + { + Key = invocationExpression.SemanticOriginalDefinition, + Namespace = invocationExpression.Reference.Namespace, + Type = semanticClassType + }; + _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out token); + } } } - } - if (token != null) - { - AddActions(fileAction, token, child.TextSpan, overrideKey); - containsActions = true; + if (token != null) + { + AddActions(fileAction, token, child.TextSpan, overrideKey); + containsActions = true; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + { + containsActions = true; + } + break; } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + case IdConstants.ElementAccessIdName: { - containsActions = true; + break; } - break; - } - case IdConstants.ElementAccessIdName: - { - break; - } case IdConstants.MemberAccessIdName: - { - break; - } + { + MemberAccess memberAccess = (MemberAccess)child; + var compareToken = new VBMemberAccessToken() + { + Key = memberAccess.Name, + FullKey = GetFullKey(memberAccess.Reference?.Namespace, memberAccess.SemanticClassType, memberAccess.Name), + Type = memberAccess.SemanticClassType, + Namespace = memberAccess.Reference?.Namespace + }; + _visualBasicRootNodes.VBMemberAccesstokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } + break; + } case IdConstants.DeclarationNodeIdName: - { - var declarationNode = (DeclarationNode)child; - var compareToken = new IdentifierNameToken() { Key = string.Concat(declarationNode.Reference.Namespace, ".", declarationNode.Identifier), Namespace = declarationNode.Reference.Namespace }; - _visualBasicRootNodes.IdentifierNameTokens.TryGetValue(compareToken, out var token); - if (token != null) { - AddActions(fileAction, token, child.TextSpan); - containsActions = true; + var declarationNode = (DeclarationNode)child; + var compareToken = new IdentifierNameToken() { Key = string.Concat(declarationNode.Reference.Namespace, ".", declarationNode.Identifier), Namespace = declarationNode.Reference.Namespace }; + _visualBasicRootNodes.IdentifierNameTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } + break; } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } - break; - } case IdConstants.ObjectCreationIdName: - { - break; - } - default: - { - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { - containsActions = true; + break; } + default: + { + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + { + containsActions = true; + } - break; - } + break; + } } } catch (Exception ex) @@ -338,7 +418,23 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, return containsActions; } - + + private string GetFullKey(string containingNamespace, string containingClass, string key) + { + if (string.IsNullOrEmpty(containingNamespace)) + { + return key; + } + else + { + if (!string.IsNullOrEmpty(containingClass)) + { + return $"{containingNamespace}.{containingClass}.{key}"; + } + return $"{containingNamespace}.{key}"; + } + } + /// /// Add actions matching the token /// @@ -368,7 +464,7 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text Type = a.Type, TextSpan = textSpan, ActionValidation = a.ActionValidation, - ImportActionFunc= a.ImportActionFunc, + ImportActionFunc = a.ImportActionFunc, ImportsClauseActionFunc = a.ImportsClauseActionFunc }).ToList()); @@ -385,12 +481,38 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text NamespaceActionFunc = a.NamespaceActionFunc }).ToList()); - fileAction.VbIdentifierNameAction.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); + fileAction.VbIdentifierNameActions.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); + + fileAction.VbAttributeListActions.UnionWith(token.VbAttributeListActions.Select(a => new AttributeListAction() + { + Key = a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + AttributeListActionFunc = a.AttributeListActionFunc + }).ToList()); + + fileAction.MemberAccessActions.UnionWith(token.MemberAccessActions.Select(a => new MemberAccessAction() + { + Key = (token is VBMemberAccessToken) ? token.FullKey : a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + MemberAccessActionFunc = a.MemberAccessActionFunc + }).ToList()); if (fileAction.InvocationExpressionActions.Any() || fileAction.VbImportActions.Any() - || fileAction.NamespaceActions.Any() - || fileAction.IdentifierNameActions.Any()) + || fileAction.VbNamespaceActions.Any() + || fileAction.VbIdentifierNameActions.Any() + || fileAction.VbAttributeListActions.Any() + || fileAction.MemberAccessActions.Any()) { var nodeToken = token.Clone(); nodeToken.TextSpan = textSpan; @@ -414,7 +536,9 @@ private void AddPackages(List packageActions, TextSpan textSpan) { _projectActions.PackageActions.Add(new PackageAction { - Name = p.Name, Version = p.Version, TextSpan = textSpan + Name = p.Name, + Version = p.Version, + TextSpan = textSpan }); } }); @@ -441,9 +565,48 @@ private void AddNamedActions(FileActions fileAction, VisualBasicNodeToken token, ActionValidation = c.ActionValidation, TypeBlockActionFunc = c.TypeBlockActionFunc })); - - if (fileAction.ClassDeclarationActions.Any() || fileAction.InterfaceDeclarationActions.Any() || - fileAction.MethodDeclarationActions.Any() || fileAction.ObjectCreationExpressionActions.Any()) + + fileAction.VbMethodBlockActions.UnionWith(token.MethodBlockActions + .Select(c => new MethodBlockAction() + { + Key = identifier, + Value = c.Value, + Description = c.Description, + Name = c.Name, + Type = c.Type, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + MethodBlockActionFunc = c.MethodBlockActionFunc + })); + + fileAction.VbInterfaceBlockActions.UnionWith(token.InterfaceBlockActions + .Select(c => new InterfaceBlockAction() + { + Key = identifier, + Value = c.Value, + Name = c.Name, + Type = c.Type, + Description = c.Description, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + InterfaceBlockActionFunc = c.InterfaceBlockActionFunc + })); + + fileAction.VbAccessorBlockActions.UnionWith(token.AccessorBlockActions + .Select(c => new AccessorBlockAction() + { + Key = identifier, + Value = c.Value, + Name = c.Name, + Type = c.Type, + Description = c.Description, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + AccessorBlockActionFunc = c.AccessorBlockActionFunc + })); + + if (fileAction.VbTypeBlockActions.Any() || fileAction.VbMethodBlockActions.Any() + || fileAction.VbInterfaceBlockActions.Any() || fileAction.VbAccessorBlockActions.Any()) { var nodeToken = token.Clone(); nodeToken.TextSpan = textSpan; diff --git a/src/CTA.Rules.Config/CTA.Rules.Config.csproj b/src/CTA.Rules.Config/CTA.Rules.Config.csproj index 0da75399..9081378b 100644 --- a/src/CTA.Rules.Config/CTA.Rules.Config.csproj +++ b/src/CTA.Rules.Config/CTA.Rules.Config.csproj @@ -5,8 +5,8 @@ - - + + diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs new file mode 100644 index 00000000..30fe7449 --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/AccessorBlockAction.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; + +namespace CTA.Rules.Models.Actions.VisualBasic +{ + public class AccessorBlockAction : GenericAction + { + public Func AccessorBlockActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (AccessorBlockAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action?.AccessorBlockActionFunc.Method.Name == this.AccessorBlockActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, AccessorBlockActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs new file mode 100644 index 00000000..c138490f --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs @@ -0,0 +1,25 @@ +using System; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Models.Actions.VisualBasic +{ + public class AttributeListAction : GenericAction + { + public Func AttributeListActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (AttributeAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action.AttributeListActionFunc != null && this.AttributeListActionFunc != null + && action.AttributeListActionFunc.Method.Name == this.AttributeListActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, AttributeListActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs new file mode 100644 index 00000000..f32cc85b --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/InterfaceBlockAction.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Models.Actions.VisualBasic +{ + public class InterfaceBlockAction : GenericAction + { + public Func InterfaceBlockActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (InterfaceBlockAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action?.InterfaceBlockActionFunc.Method.Name == this.InterfaceBlockActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, InterfaceBlockActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs new file mode 100644 index 00000000..7703b3ee --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/MethodBlockAction.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Models.Actions.VisualBasic +{ + public class MethodBlockAction : GenericAction + { + public Func MethodBlockActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (MethodBlockAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action?.MethodBlockActionFunc.Method.Name == this.MethodBlockActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, MethodBlockActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index e7a23d06..d650f992 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using CTA.Rules.Models.Actions.VisualBasic; using CTA.Rules.Models.Tokens; using CTA.Rules.Models.Tokens.VisualBasic; using CTA.Rules.Models.VisualBasic; @@ -37,16 +38,28 @@ public FileActions() VbNamespaceActions = new HashSet>(); VbTypeBlockActions = new HashSet(); + VbMethodBlockActions = new HashSet(); + VbInterfaceBlockActions = new HashSet(); + VbAttributeListActions = new HashSet(); + VbIdentifierNameActions = new HashSet>(); + VbAccessorBlockActions = new HashSet(); } public HashSet> VbNamespaceActions { get; set; } public HashSet VbImportActions { get; set; } public HashSet> - VbInvocationExpressionActions { get; set; } + VbInvocationExpressionActions + { get; set; } public HashSet> - VbIdentifierNameAction { get; set; } + VbIdentifierNameActions + { get; set; } public HashSet - VbTypeBlockActions { get; set; } + VbTypeBlockActions + { get; set; } + public HashSet VbMethodBlockActions { get; set; } + public HashSet VbInterfaceBlockActions { get; set; } + public HashSet VbAttributeListActions { get; set; } + public HashSet VbAccessorBlockActions { get; set; } public List VbNodeTokens { get; set; } public List NodeTokens { get; set; } @@ -79,12 +92,17 @@ public List AllActions allActions.AddRange(Usingactions); allActions.AddRange(ObjectCreationExpressionActions); allActions.AddRange(NamespaceActions); - + // visual basic actions allActions.AddRange(VbImportActions); allActions.AddRange(VbNamespaceActions); allActions.AddRange(VbInvocationExpressionActions); allActions.AddRange(VbTypeBlockActions); + allActions.AddRange(VbMethodBlockActions); + allActions.AddRange(VbInterfaceBlockActions); + allActions.AddRange(VbAttributeListActions); + allActions.AddRange(VbIdentifierNameActions); + allActions.AddRange(VbAccessorBlockActions); return allActions; } } diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs new file mode 100644 index 00000000..28057aed --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/AccessorBlockToken.cs @@ -0,0 +1,18 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class AccessorBlockToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (AccessorBlockToken)obj; + return token?.Type == this.Type && token?.Namespace == this.Namespace && token?.Key.Trim() == this.Key.Trim(); + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Namespace, Type); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs new file mode 100644 index 00000000..fd1c209f --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeListToken.cs @@ -0,0 +1,18 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class AttributeListToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (AttributeListToken)obj; + return token?.Type == this.Type && token?.Namespace == this.Namespace && token?.Key.Trim() == this.Key.Trim(); + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Namespace, Type); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs new file mode 100644 index 00000000..3dbc518e --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/InterfaceBlockToken.cs @@ -0,0 +1,18 @@ +using System; +using CTA.Rules.Models.Tokens; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class InterfaceBlockToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (InterfaceBlockToken)obj; + return token?.FullKey == this.FullKey; + } + public override int GetHashCode() + { + return HashCode.Combine(FullKey); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs new file mode 100644 index 00000000..bead566e --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/MethodBlockToken.cs @@ -0,0 +1,17 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class MethodBlockToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (MethodBlockToken)obj; + return token?.FullKey == this.FullKey; + } + public override int GetHashCode() + { + return HashCode.Combine(FullKey); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs new file mode 100644 index 00000000..39339d80 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs @@ -0,0 +1,18 @@ +using System; + + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class VBMemberAccessToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (VBMemberAccessToken)obj; + return token?.FullKey == this.FullKey; + } + public override int GetHashCode() + { + return HashCode.Combine(FullKey); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs index b341d34f..b0f0856d 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs @@ -3,6 +3,7 @@ using System.Configuration; using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using CTA.Rules.Models.Actions.VisualBasic; namespace CTA.Rules.Models.Tokens.VisualBasic { @@ -15,15 +16,21 @@ public VisualBasicNodeToken() NamespaceActions = new List>(); IdentifierNameActions = new List>(); TypeBlockActions = new List(); - + MethodBlockActions = new List(); + InterfaceBlockActions = new List(); + VbAttributeListActions = new List(); + AccessorBlockActions = new List(); } - + public List> InvocationExpressionActions { get; set; } public List ImportActions { get; set; } public List> NamespaceActions { get; set; } public List> IdentifierNameActions { get; set; } public List TypeBlockActions { get; set; } - + public List MethodBlockActions { get; set; } + public List InterfaceBlockActions { get; set; } + public List VbAttributeListActions { get; set; } + public List AccessorBlockActions { get; set; } public override VisualBasicNodeToken Clone() { @@ -38,6 +45,14 @@ public override VisualBasicNodeToken Clone() .Select(action => action.Clone>()).ToList(); cloned.TypeBlockActions = cloned.TypeBlockActions .Select(action => action.Clone()).ToList(); + cloned.MethodBlockActions = cloned.MethodBlockActions + .Select(action => action.Clone()).ToList(); + cloned.InterfaceBlockActions = cloned.InterfaceBlockActions + .Select(action => action.Clone()).ToList(); + cloned.VbAttributeListActions = cloned.VbAttributeListActions + .Select(action => action.Clone()).ToList(); + cloned.AccessorBlockActions = cloned.AccessorBlockActions + .Select(action => action.Clone()).ToList(); return cloned; } @@ -51,6 +66,10 @@ public override List AllActions allActions.AddRange(ImportActions); allActions.AddRange(IdentifierNameActions); allActions.AddRange(TypeBlockActions); + allActions.AddRange(MethodBlockActions); + allActions.AddRange(InterfaceBlockActions); + allActions.AddRange(AttributeListActions); + allActions.AddRange(AccessorBlockActions); allActions.AddRange(base.AllActions); return allActions; } diff --git a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs index 50498832..79414d67 100644 --- a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs +++ b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs @@ -13,6 +13,11 @@ public VisualBasicRootNodes() { InvocationExpressionTokens = new HashSet(); ImportStatementTokens = new HashSet(); + InterfaceBlockTokens = new HashSet(); + MethodBlockTokens = new HashSet(); + AttributeListTokens = new HashSet(); + AccessorBlockTokens = new HashSet(); + VBMemberAccesstokens = new HashSet(); NamespaceTokens = new HashSet(); ProjectTokens = new HashSet(); IdentifierNameTokens = new HashSet(); @@ -21,6 +26,11 @@ public VisualBasicRootNodes() public HashSet InvocationExpressionTokens { get; set; } public HashSet ImportStatementTokens { get; set; } + public HashSet InterfaceBlockTokens { get; set; } + public HashSet MethodBlockTokens { get; set; } + public HashSet AttributeListTokens { get; set; } + public HashSet AccessorBlockTokens { get; set; } + public HashSet VBMemberAccesstokens { get; set; } public HashSet NamespaceTokens { get; set; } public HashSet ProjectTokens { get; set; } public HashSet IdentifierNameTokens { get; set; } From 316aec7e275b2f2afaa52e5164f6bb9ec05ad012 Mon Sep 17 00:00:00 2001 From: longachr Date: Mon, 6 Jun 2022 14:16:29 -0700 Subject: [PATCH 30/61] add object creation expression to vb action loader --- .../VisualBasicActionsLoader.cs | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs index 1525ac60..5d6dda15 100644 --- a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs +++ b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs @@ -23,7 +23,8 @@ public class VisualBasicActionsLoader : ActionLoaderBase _elementAccessActions, _expressionActions, _interfaceActions, - _methodBlockActions; + _methodBlockActions, + _objectCreationExpressionActions; private readonly object _compilationUnitObject, @@ -36,7 +37,8 @@ public class VisualBasicActionsLoader : ActionLoaderBase _elementAccessObject, _expressionObject, _interfaceObject, - _methodBlockObject; + _methodBlockObject, + _objectExpressionObject; /// /// Initializes a new ActionLoader that loads the default actions @@ -55,6 +57,7 @@ public VisualBasicActionsLoader(List assemblyPaths) _expressionActions = new List (); _interfaceActions = new List (); _methodBlockActions = new List (); + _objectCreationExpressionActions = new List(); projectLevelActions = new List(); projectFileActions = new List(); projectTypeActions = new List(); @@ -69,30 +72,21 @@ public VisualBasicActionsLoader(List assemblyPaths) .Where(t => t.Name.EndsWith("Actions") && (t.Namespace.EndsWith(ProjectLanguage.VisualBasic.ToString()) || t.Name.StartsWith("Project"))).ToList(); - TryCreateInstance(Constants.CompilationUnitActions, types, - out _compilationUnitObject); - TryCreateInstance(Constants.InvocationExpressionActions, types, - out _invocationExpressionObject); - TryCreateInstance(Constants.NamespaceActions, types, - out _namespaceObject); - TryCreateInstance(Constants.AttributeActions, types, - out _attributeObject); - TryCreateInstance(Constants.AttributeListActions, types, - out _attributeListObject); - TryCreateInstance(Constants.TypeBlockActions, types, - out _typeBlockObject); - TryCreateInstance(Constants.ElementAccessActions, types, - out _elementAccessObject); - TryCreateInstance(Constants.ExpressionActions, types, - out _expressionObject); - TryCreateInstance(Constants.InterfaceActions, types, - out _interfaceObject); - TryCreateInstance(Constants.MethodBlockActions, types, - out _methodBlockObject); + TryCreateInstance(Constants.CompilationUnitActions, types, out _compilationUnitObject); + TryCreateInstance(Constants.InvocationExpressionActions, types, out _invocationExpressionObject); + TryCreateInstance(Constants.NamespaceActions, types, out _namespaceObject); + TryCreateInstance(Constants.AttributeActions, types, out _attributeObject); + TryCreateInstance(Constants.AttributeListActions, types, out _attributeListObject); + TryCreateInstance(Constants.TypeBlockActions, types, out _typeBlockObject); + TryCreateInstance(Constants.ElementAccessActions, types, out _elementAccessObject); + TryCreateInstance(Constants.ExpressionActions, types, out _expressionObject); + TryCreateInstance(Constants.InterfaceActions, types, out _interfaceObject); + TryCreateInstance(Constants.MethodBlockActions, types, out _methodBlockObject); TryCreateInstance(Constants.ProjectLevelActions, types, out projectLevelObject); TryCreateInstance(Constants.ProjectFileActions, types, out projectFileObject); TryCreateInstance(Constants.ProjectTypeActions, types, out projectTypeObject); TryCreateInstance(Constants.IdentifierNameActions, types, out _identifierNameObject); + TryCreateInstance(Constants.ObjectCreationExpressionActions, types, out _objectExpressionObject); foreach (var t in types) { @@ -170,7 +164,7 @@ public VisualBasicActionsLoader(List assemblyPaths) } case Constants.ObjectCreationExpressionActions: { - //_objectCreationExpressionActions.AddRange(GetFuncMethods(t)); + _objectCreationExpressionActions.AddRange(GetFuncMethods(t)); break; } default: @@ -253,7 +247,8 @@ public Func GetName public Func GetObjectCreationExpressionActions( string name, dynamic value) { - throw new NotImplementedException(); + return GetAction> + (_objectCreationExpressionActions, _objectExpressionObject, name, value); } public Func From 8d625862ffbcb6658e71cb371858bf94b8dcdb33 Mon Sep 17 00:00:00 2001 From: longachr Date: Mon, 6 Jun 2022 14:23:54 -0700 Subject: [PATCH 31/61] fix object creation expression actions inconsistent types and naming --- .../ObjectCreationExpressionActions.cs | 58 ++++++++++--------- .../Actions/VisualBasic/ActionsLoaderTests.cs | 2 +- .../ObjectCreationExpressionActionsTests.cs | 17 +++--- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/CTA.Rules.Actions/VisualBasic/ObjectCreationExpressionActions.cs b/src/CTA.Rules.Actions/VisualBasic/ObjectCreationExpressionActions.cs index 63126ed8..46560162 100644 --- a/src/CTA.Rules.Actions/VisualBasic/ObjectCreationExpressionActions.cs +++ b/src/CTA.Rules.Actions/VisualBasic/ObjectCreationExpressionActions.cs @@ -16,83 +16,87 @@ public class ObjectCreationExpressionActions { public Func GetReplaceObjectinitializationAction(string newStatement) { - ExpressionSyntax action(SyntaxGenerator syntaxGenerator, ObjectCreationExpressionSyntax node) + ExpressionSyntax Action(SyntaxGenerator syntaxGenerator, ObjectCreationExpressionSyntax node) { var newNode = SyntaxFactory.ParseExpression(newStatement).NormalizeWhitespace(); return newNode; } - return action; + return Action; } - public Func GetReplaceObjectWithInvocationAction(string NewExpression, string UseParameters) + public Func GetReplaceObjectWithInvocationAction(string newExpression, string useParameters) { - ExpressionSyntax action(SyntaxGenerator syntaxGenerator, ObjectCreationExpressionSyntax node) + ExpressionSyntax Action(SyntaxGenerator syntaxGenerator, ObjectCreationExpressionSyntax node) { - bool.TryParse(UseParameters, out var useParam); + bool.TryParse(useParameters, out var useParam); - var newNode = SyntaxFactory.ParseExpression(NewExpression) as InvocationExpressionSyntax; + var newNode = SyntaxFactory.ParseExpression(newExpression) as InvocationExpressionSyntax; if (useParam) { newNode = newNode.WithArgumentList(node.ArgumentList); } return newNode.NormalizeWhitespace(); } - return action; + return Action; } - public Func GetReplaceOrAddObjectPropertyIdentifierAction(string oldMember, string newMember, string newValueIfAdding = null) + public Func GetReplaceOrAddObjectPropertyIdentifierAction(string oldMember, string newMember, string newValueIfAdding = null) { - ObjectMemberInitializerSyntax action(SyntaxGenerator syntaxGenerator, ObjectMemberInitializerSyntax node) + ExpressionSyntax Action(SyntaxGenerator syntaxGenerator, ObjectCreationExpressionSyntax node) { - if (node.Initializers.Count > 0) + if (node.Initializer != null && node.Initializer.IsKind(SyntaxKind.ObjectMemberInitializer)) { - var memberList = node.Initializers.Where(n => n.Kind() == SyntaxKind.NamedFieldInitializer); - if (memberList.Count() > 0) + var initializer = (ObjectMemberInitializerSyntax)node.Initializer; + var memberList = initializer.Initializers.Where(n => n.Kind() == SyntaxKind.NamedFieldInitializer).ToList(); + if (memberList.Any()) { var assignMemberList = memberList.Select(n => (NamedFieldInitializerSyntax)n); - var member = assignMemberList.Where(n => n.Name.ToFullString().Contains(oldMember)).FirstOrDefault(); + var member = assignMemberList.FirstOrDefault(n => n.Name.ToFullString().Contains(oldMember)); + SeparatedSyntaxList newInitializers; if (member != null) { var newExpression = SyntaxFactory.NamedFieldInitializer((IdentifierNameSyntax)syntaxGenerator.IdentifierName(newMember), member.Expression); - var newNode = node.Initializers.Replace(member, newExpression); - node = node.WithInitializers(newNode).NormalizeWhitespace(); + newInitializers = initializer.Initializers.Replace(member, newExpression); } else { var newExpression = SyntaxFactory.NamedFieldInitializer((IdentifierNameSyntax)syntaxGenerator.IdentifierName(newMember), (IdentifierNameSyntax)syntaxGenerator.IdentifierName(newValueIfAdding)); - var newNode = node.Initializers.Add(newExpression); - node = node.WithInitializers(newNode).NormalizeWhitespace(); + newInitializers = initializer.Initializers.Add(newExpression); } + var newInitializer = initializer.WithInitializers(newInitializers); + node = node.WithInitializer(newInitializer).NormalizeWhitespace(); } } return node; } - return action; + return Action; } - public Func GetReplaceObjectPropertyValueAction(string oldMember, string newMember) + public Func GetReplaceObjectPropertyValueAction(string oldMember, string newMember) { - ObjectMemberInitializerSyntax action(SyntaxGenerator syntaxGenerator, ObjectMemberInitializerSyntax node) + ExpressionSyntax Action(SyntaxGenerator syntaxGenerator, ObjectCreationExpressionSyntax node) { - if (node.Initializers.Count > 0) + if (node.Initializer != null && node.Initializer.IsKind(SyntaxKind.ObjectMemberInitializer)) { - var memberList = node.Initializers.Where(n => n.Kind() == SyntaxKind.NamedFieldInitializer); - if (memberList.Count() > 0) + var initializer = (ObjectMemberInitializerSyntax)node.Initializer; + var memberList = initializer.Initializers.Where(n => n.Kind() == SyntaxKind.NamedFieldInitializer).ToList(); + if (memberList.Any()) { var assignMemberList = memberList.Select(n => (NamedFieldInitializerSyntax)n); - var member = assignMemberList.Where(n => n.Expression.ToFullString().Contains(oldMember)).FirstOrDefault(); + var member = assignMemberList.FirstOrDefault(n => n.Expression.ToFullString().Contains(oldMember)); if (member != null) { var right = SyntaxFactory.ParseExpression(member.Expression.ToFullString().Replace(oldMember, newMember)); var newExpression = SyntaxFactory.NamedFieldInitializer(member.Name, right); - var newNode = node.Initializers.Replace(member, newExpression); - node = node.WithInitializers(newNode).NormalizeWhitespace(); + var newInitializers = initializer.Initializers.Replace(member, newExpression); + var newInitializer = initializer.WithInitializers(newInitializers); + node = node.WithInitializer(newInitializer).NormalizeWhitespace(); } } } return node; } - return action; + return Action; } public Func GetAddCommentAction(string comment) diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs index 43a13788..9df676f8 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ActionsLoaderTests.cs @@ -204,7 +204,7 @@ public void MethodBlockActionsTest() public void ObjectCreationExpressionActionsTest() { var replaceObjectinitialization = _actionLoader.GetObjectCreationExpressionActions("ReplaceObjectinitialization", "newStatement"); - var replaceObjectWithInvocation = _actionLoader.GetObjectCreationExpressionActions("ReplaceObjectWithInvocation", "{ NewExpression: \"expression\", UseParameters: \"params\" }"); + var replaceObjectWithInvocation = _actionLoader.GetObjectCreationExpressionActions("ReplaceObjectWithInvocation", "{ newExpression: \"expression\", useParameters: \"params\" }"); var replaceOrAddObjectPropertyIdentifier = _actionLoader.GetObjectCreationExpressionActions("ReplaceOrAddObjectPropertyIdentifier", "{ oldMember: \"old\", newMember: \"new\", newValueIfAdding: \"value\" }"); var replaceOrAddObjectPropertyIdentifier2 = _actionLoader.GetObjectCreationExpressionActions("ReplaceOrAddObjectPropertyIdentifier", "{ oldMember: \"old\", newMember: \"new\" }"); var replaceObjectPropertyValue = _actionLoader.GetObjectCreationExpressionActions("ReplaceObjectPropertyValue", "{ oldMember: \"old\", newMember: \"new\" }"); diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs index 4f3c417c..899ed3ab 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs @@ -5,7 +5,6 @@ using Microsoft.CodeAnalysis.VisualBasic.Syntax; using Microsoft.CodeAnalysis.Editing; using NUnit.Framework; -using System; namespace CTA.Rules.Test.Actions.VisualBasic { @@ -77,8 +76,12 @@ public void GetReplaceObjectPropertyIdentifier() SyntaxFactory.ParseExpression("new PhysicalFileSystem(@\".\\defaults\")")), SyntaxFactory.Token(SyntaxKind.CommaToken)})) .NormalizeWhitespace(); - var replaceObjectWithInvocationFunc = _objectCreationExpressionActions.GetReplaceOrAddObjectPropertyIdentifierAction(oldIdentifier, newIdentifier, string.Empty); - var newNode = replaceObjectWithInvocationFunc(_syntaxGenerator, _objectMemberNode); + _node = _node.WithArgumentList(SyntaxFactory.ArgumentList()).WithInitializer(_objectMemberNode) + .NormalizeWhitespace(); + var replaceObjectWithInvocationFunc = + _objectCreationExpressionActions.GetReplaceOrAddObjectPropertyIdentifierAction(oldIdentifier, + newIdentifier, string.Empty); + var newNode = replaceObjectWithInvocationFunc(_syntaxGenerator, _node); StringAssert.Contains(newIdentifier, newNode.ToFullString()); } @@ -99,9 +102,9 @@ public void GetAddObjectPropertyIdentifier() SyntaxFactory.ParseExpression("true")), SyntaxFactory.Token(SyntaxKind.CommaToken)})) .NormalizeWhitespace(); - + _node = _node.WithArgumentList(SyntaxFactory.ArgumentList()).WithInitializer(_objectMemberNode); var replaceObjectWithInvocationFunc = _objectCreationExpressionActions.GetReplaceOrAddObjectPropertyIdentifierAction(oldIdentifier, newIdentifier, newValue); - var newNode = replaceObjectWithInvocationFunc(_syntaxGenerator, _objectMemberNode); + var newNode = replaceObjectWithInvocationFunc(_syntaxGenerator, _node); StringAssert.Contains(newIdentifier, newNode.ToFullString()); StringAssert.Contains(newValue, newNode.ToFullString()); @@ -124,9 +127,9 @@ public void GetReplaceObjectPropertyValue() SyntaxFactory.ParseExpression("new PhysicalFileSystem(@\".\\defaults\")")), SyntaxFactory.Token(SyntaxKind.CommaToken)})) .NormalizeWhitespace(); - + _node = _node.WithArgumentList(SyntaxFactory.ArgumentList()).WithInitializer(_objectMemberNode); var replaceObjectWithInvocationFunc = _objectCreationExpressionActions.GetReplaceObjectPropertyValueAction(oldIdentifier, newIdentifier); - var newNode = replaceObjectWithInvocationFunc(_syntaxGenerator, _objectMemberNode); + var newNode = replaceObjectWithInvocationFunc(_syntaxGenerator, _node); StringAssert.Contains(newIdentifier, newNode.ToFullString()); StringAssert.DoesNotContain(oldIdentifier, newNode.ToFullString()); } From 33427f29aa1c786eb78c6b6af95eca8131aeb714 Mon Sep 17 00:00:00 2001 From: longachr Date: Mon, 6 Jun 2022 15:49:26 -0700 Subject: [PATCH 32/61] add rule file processing for object creation expression actions --- .../VisualBasicRulesAnalysis.cs | 364 ++++++++++-------- .../FileActions/FileActions.cs | 16 +- .../Tokens/Csharp/CsharpNodeToken.cs | 4 + src/CTA.Rules.Models/Tokens/NodeToken.cs | 4 - .../ObjectCreationExpressionToken.cs | 16 + .../VisualBasic/VisualBasicNodeToken.cs | 7 +- .../VisualBasic/VisualBasicRootNodes.cs | 7 +- src/CTA.Rules.RuleFiles/RulesFileLoader.cs | 2 +- .../VisualBasicRulesFileParser.cs | 70 +++- 9 files changed, 306 insertions(+), 184 deletions(-) create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/ObjectCreationExpressionToken.cs diff --git a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs index 69991cd0..7d26bcbe 100644 --- a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs @@ -13,6 +13,7 @@ using IdentifierNameToken = CTA.Rules.Models.VisualBasic.IdentifierNameToken; using InvocationExpressionToken = CTA.Rules.Models.Tokens.VisualBasic.InvocationExpressionToken; using NamespaceToken = CTA.Rules.Models.Tokens.VisualBasic.NamespaceToken; +using ObjectCreationExpressionAction = CTA.Rules.Models.VisualBasic.ObjectCreationExpressionAction; namespace CTA.Rules.Analyzer; @@ -49,14 +50,11 @@ public ProjectActions Analyze() _projectActions.FileActions.Add(fileAction); } }); - - //todo: project tokens - /* + AddPackages( _visualBasicRootNodes.ProjectTokens.Where(p => p.FullKey == _projectType.ToString()) ?.SelectMany(p => p.PackageActions)?.Distinct()?.ToList(), null); - */ - + return _projectActions; } @@ -121,106 +119,106 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, break; } case IdConstants.ImportsStatementName: + { + var overrideKey = string.Empty; + + var compareToken = new ImportStatementToken { Key = child.Identifier }; + _visualBasicRootNodes.ImportStatementTokens.TryGetValue(compareToken, out var token); + if (token != null) { - var overrideKey = string.Empty; + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } - var compareToken = new ImportStatementToken { Key = child.Identifier }; - _visualBasicRootNodes.ImportStatementTokens.TryGetValue(compareToken, out var token); - if (token != null) + //Attempt a wildcard search, if applicable. This is import specific because it might want to include all sub-namespaces + if (token == null) + { + var wildcardMatches = _visualBasicRootNodes.ImportStatementTokens + .Where(i => i.Key.Contains("*")).ToList(); + if (wildcardMatches.Any()) { - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } + token = wildcardMatches.FirstOrDefault(i => compareToken.Key.WildcardEquals(i.Key)); - //Attempt a wildcard search, if applicable. This is import specific because it might want to include all sub-namespaces - if (token == null) - { - var wildcardMatches = _visualBasicRootNodes.ImportStatementTokens - .Where(i => i.Key.Contains("*")).ToList(); - if (wildcardMatches.Any()) + if (token != null) { - token = wildcardMatches.FirstOrDefault(i => compareToken.Key.WildcardEquals(i.Key)); - - if (token != null) - { - //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code - overrideKey = compareToken.Key; - } + //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code + overrideKey = compareToken.Key; } } - if (token != null) - { - AddActions(fileAction, token, child.TextSpan, overrideKey); - containsActions = true; - } - break; } + if (token != null) + { + AddActions(fileAction, token, child.TextSpan, overrideKey); + containsActions = true; + } + break; + } case IdConstants.NamespaceBlockIdName: + { + var compareToken = new NamespaceToken { Key = child.Identifier }; + _visualBasicRootNodes.NamespaceTokens.TryGetValue(compareToken, out var token); + if (token != null) { - var compareToken = new NamespaceToken { Key = child.Identifier }; - _visualBasicRootNodes.NamespaceTokens.TryGetValue(compareToken, out var token); - if (token != null) - { - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - if (AnalyzeChildren(fileAction, child.Children, ++level, child.Identifier)) - { - containsActions = true; - } - break; + AddActions(fileAction, token, child.TextSpan); + containsActions = true; } + if (AnalyzeChildren(fileAction, child.Children, ++level, child.Identifier)) + { + containsActions = true; + } + break; + } case IdConstants.ModuleBlockName: + { + var moduleType = (ModuleBlock)child; + var name = string.Concat( + moduleType.Reference != null + ? string.Concat(moduleType.Reference.Namespace, ".") + : string.Empty, moduleType.Identifier); + var nameToken = new TypeBlockToken() { FullKey = name }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out var token)) { - var moduleType = (ModuleBlock)child; - var name = string.Concat( - moduleType.Reference != null - ? string.Concat(moduleType.Reference.Namespace, ".") - : string.Empty, moduleType.Identifier); - var nameToken = new TypeBlockToken() { FullKey = name }; - if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out var token)) - { - AddNamedActions(fileAction, token, moduleType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - break; + AddNamedActions(fileAction, token, moduleType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; } + break; + } case IdConstants.ClassBlockName: + { + var classType = (ClassBlock)child; + var baseToken = new TypeBlockToken() { FullKey = classType.BaseType }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseToken, out var token)) { - var classType = (ClassBlock)child; - var baseToken = new TypeBlockToken() { FullKey = classType.BaseType }; - if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseToken, out var token)) - { - AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } + AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } - token = null; - var name = string.Concat( - classType.Reference != null - ? string.Concat(classType.Reference.Namespace, ".") - : string.Empty, classType.Identifier); - var nameToken = new TypeBlockToken() { FullKey = name }; - if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out token)) + token = null; + var name = string.Concat( + classType.Reference != null + ? string.Concat(classType.Reference.Namespace, ".") + : string.Empty, classType.Identifier); + var nameToken = new TypeBlockToken() { FullKey = name }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out token)) + { + AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + token = null; + foreach (string interfaceName in classType.Inherits) + { + var baseListToken = new TypeBlockToken() { FullKey = interfaceName }; + if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseListToken, out token)) { AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); AddActions(fileAction, token, child.TextSpan); containsActions = true; } - token = null; - foreach (string interfaceName in classType.Inherits) - { - var baseListToken = new TypeBlockToken() { FullKey = interfaceName }; - if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseListToken, out token)) - { - AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - token = null; } if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, classType.Identifier)) { containsActions = true; } @@ -291,76 +289,76 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, break; } case IdConstants.InvocationIdName: - { - var overrideKey = string.Empty; + { + var overrideKey = string.Empty; - InvocationExpression invocationExpression = (InvocationExpression)child; + InvocationExpression invocationExpression = (InvocationExpression)child; - ////If we don't have a semantic analysis, we dont want to replace invocation expressions, otherwise we'll be replacing expressions regardless of their class/namespace - if (string.IsNullOrEmpty(invocationExpression.SemanticOriginalDefinition)) - { - break; - } + ////If we don't have a semantic analysis, we dont want to replace invocation expressions, otherwise we'll be replacing expressions regardless of their class/namespace + if (string.IsNullOrEmpty(invocationExpression.SemanticOriginalDefinition)) + { + break; + } - var compareToken = new InvocationExpressionToken + var compareToken = new InvocationExpressionToken + { + Key = invocationExpression.SemanticOriginalDefinition, + Namespace = invocationExpression.Reference.Namespace, + Type = invocationExpression.SemanticClassType + }; + _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out var token); + + //Attempt a wildcard search, if applicable. This is invocation expression specific because it has to look inside the invocation expressions only + if (token == null) + { + var wildcardMatches = + _visualBasicRootNodes.InvocationExpressionTokens.Where(i => i.Key.Contains("*")); + if (wildcardMatches.Any()) { - Key = invocationExpression.SemanticOriginalDefinition, - Namespace = invocationExpression.Reference.Namespace, - Type = invocationExpression.SemanticClassType - }; - _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out var token); + token = wildcardMatches.FirstOrDefault(i => + compareToken.Key.WildcardEquals(i.Key) && compareToken.Namespace == i.Namespace && + compareToken.Type == i.Type); - //Attempt a wildcard search, if applicable. This is invocation expression specific because it has to look inside the invocation expressions only - if (token == null) - { - var wildcardMatches = - _visualBasicRootNodes.InvocationExpressionTokens.Where(i => i.Key.Contains("*")); - if (wildcardMatches.Any()) + if (token != null) { - token = wildcardMatches.FirstOrDefault(i => - compareToken.Key.WildcardEquals(i.Key) && compareToken.Namespace == i.Namespace && - compareToken.Type == i.Type); - - if (token != null) - { - //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code - overrideKey = compareToken.Key; - } + //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code + overrideKey = compareToken.Key; } + } - //If the semanticClassType is too specific to apply to all TData types - if (token == null) + //If the semanticClassType is too specific to apply to all TData types + if (token == null) + { + if (invocationExpression.SemanticClassType.Contains('<')) { - if (invocationExpression.SemanticClassType.Contains('<')) + string semanticClassType = invocationExpression.SemanticClassType.Substring(0, + invocationExpression.SemanticClassType.IndexOf('<')); + compareToken = new InvocationExpressionToken { - string semanticClassType = invocationExpression.SemanticClassType.Substring(0, - invocationExpression.SemanticClassType.IndexOf('<')); - compareToken = new InvocationExpressionToken - { - Key = invocationExpression.SemanticOriginalDefinition, - Namespace = invocationExpression.Reference.Namespace, - Type = semanticClassType - }; - _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out token); - } + Key = invocationExpression.SemanticOriginalDefinition, + Namespace = invocationExpression.Reference.Namespace, + Type = semanticClassType + }; + _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out token); } } + } - if (token != null) - { - AddActions(fileAction, token, child.TextSpan, overrideKey); - containsActions = true; - } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) - { - containsActions = true; - } - break; + if (token != null) + { + AddActions(fileAction, token, child.TextSpan, overrideKey); + containsActions = true; } - case IdConstants.ElementAccessIdName: + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { - break; + containsActions = true; } + break; + } + case IdConstants.ElementAccessIdName: + { + break; + } case IdConstants.MemberAccessIdName: { @@ -382,31 +380,77 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, break; } case IdConstants.DeclarationNodeIdName: + { + var declarationNode = (DeclarationNode)child; + var compareToken = new IdentifierNameToken() { Key = string.Concat(declarationNode.Reference.Namespace, ".", declarationNode.Identifier), Namespace = declarationNode.Reference.Namespace }; + _visualBasicRootNodes.IdentifierNameTokens.TryGetValue(compareToken, out var token); + if (token != null) { - var declarationNode = (DeclarationNode)child; - var compareToken = new IdentifierNameToken() { Key = string.Concat(declarationNode.Reference.Namespace, ".", declarationNode.Identifier), Namespace = declarationNode.Reference.Namespace }; - _visualBasicRootNodes.IdentifierNameTokens.TryGetValue(compareToken, out var token); - if (token != null) - { - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } - break; + AddActions(fileAction, token, child.TextSpan); + containsActions = true; } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } + break; + } case IdConstants.ObjectCreationIdName: + { + var objectCreationNode = (ObjectCreationExpression)child; + //Rules based on Object Creation Parent Hierarchy + var compareToken = new ObjectCreationExpressionToken { - break; + Key = objectCreationNode.Identifier, + Namespace = objectCreationNode.Reference?.Namespace, + Type = objectCreationNode.SemanticClassType + }; + _visualBasicRootNodes.ObjectCreationExpressionTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; } - default: + + //Rules based on Object Creation location within code + var compareTokenLocation = new ObjectCreationExpressionToken + { + Key = objectCreationNode.Identifier, Namespace = parentNamespace, Type = parentClass + }; + _visualBasicRootNodes.ObjectCreationExpressionTokens.TryGetValue(compareTokenLocation, + out var tokenLocation); + if (tokenLocation != null) { - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + AddActions(fileAction, tokenLocation, child.TextSpan); + containsActions = true; + } + + token = null; + if (!string.IsNullOrEmpty(objectCreationNode.SemanticOriginalDefinition)) + { + var nameToken = new ObjectCreationExpressionToken + { + Key = objectCreationNode.SemanticOriginalDefinition, + Namespace = objectCreationNode.SemanticNamespace, + Type = objectCreationNode.SemanticClassType + }; + _visualBasicRootNodes.ObjectCreationExpressionTokens.TryGetValue(nameToken, out token); + if (token != null) { + AddActions(fileAction, token, child.TextSpan); containsActions = true; } + } - break; + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } + break; + } + default: + { + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + { + containsActions = true; } + + break; + } } } catch (Exception ex) @@ -507,19 +551,35 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text MemberAccessActionFunc = a.MemberAccessActionFunc }).ToList()); + fileAction.VbObjectCreationExpressionActions.UnionWith(token.ObjectCreationExpressionActions.Select(a => + new ObjectCreationExpressionAction + { + Key = a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + ObjectCreationExpressionGenericActionFunc = a.ObjectCreationExpressionGenericActionFunc + }).ToList()); + if (fileAction.InvocationExpressionActions.Any() || fileAction.VbImportActions.Any() || fileAction.VbNamespaceActions.Any() || fileAction.VbIdentifierNameActions.Any() || fileAction.VbAttributeListActions.Any() - || fileAction.MemberAccessActions.Any()) + || fileAction.MemberAccessActions.Any() + || fileAction.NamespaceActions.Any() + || fileAction.IdentifierNameActions.Any() + || fileAction.ObjectCreationExpressionActions.Any()) { var nodeToken = token.Clone(); nodeToken.TextSpan = textSpan; fileAction.VbNodeTokens.Add(nodeToken); } - //AddPackages(token.PackageActions, textSpan); + AddPackages(token.PackageActions, textSpan); } /// diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index d650f992..9806f81c 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -43,23 +43,22 @@ public FileActions() VbAttributeListActions = new HashSet(); VbIdentifierNameActions = new HashSet>(); VbAccessorBlockActions = new HashSet(); + VbObjectCreationExpressionActions = new HashSet(); } public HashSet> VbNamespaceActions { get; set; } public HashSet VbImportActions { get; set; } public HashSet> - VbInvocationExpressionActions - { get; set; } + VbInvocationExpressionActions { get; set; } public HashSet> - VbIdentifierNameActions - { get; set; } - public HashSet - VbTypeBlockActions - { get; set; } + VbIdentifierNameActions { get; set; } + public HashSet VbTypeBlockActions { get; set; } public HashSet VbMethodBlockActions { get; set; } public HashSet VbInterfaceBlockActions { get; set; } public HashSet VbAttributeListActions { get; set; } public HashSet VbAccessorBlockActions { get; set; } + public HashSet VbObjectCreationExpressionActions + { get; set; } public List VbNodeTokens { get; set; } public List NodeTokens { get; set; } @@ -92,7 +91,7 @@ public List AllActions allActions.AddRange(Usingactions); allActions.AddRange(ObjectCreationExpressionActions); allActions.AddRange(NamespaceActions); - + // visual basic actions allActions.AddRange(VbImportActions); allActions.AddRange(VbNamespaceActions); @@ -103,6 +102,7 @@ public List AllActions allActions.AddRange(VbAttributeListActions); allActions.AddRange(VbIdentifierNameActions); allActions.AddRange(VbAccessorBlockActions); + allActions.AddRange(VbObjectCreationExpressionActions); return allActions; } } diff --git a/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs b/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs index 6680db5e..cbea1a7d 100644 --- a/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs @@ -12,12 +12,14 @@ public CsharpNodeToken() InvocationExpressionActions = new List>(); NamespaceActions = new List>(); IdentifierNameActions = new List>(); + ObjectCreationExpressionActions = new List(); } public List UsingActions { get; set; } public List> InvocationExpressionActions { get; set; } public List> NamespaceActions { get; set; } public List> IdentifierNameActions { get; set; } + public List ObjectCreationExpressionActions{ get; set; } public override CsharpNodeToken Clone() { @@ -26,6 +28,7 @@ public override CsharpNodeToken Clone() cloned.IdentifierNameActions = cloned.IdentifierNameActions.Select(action => action.Clone>()).ToList(); cloned.InvocationExpressionActions = cloned.InvocationExpressionActions.Select(action => action.Clone>()).ToList(); cloned.NamespaceActions = cloned.NamespaceActions.Select(action => action.Clone>()).ToList(); + cloned.ObjectCreationExpressionActions = cloned.ObjectCreationExpressionActions.Select(action => action.Clone()).ToList(); return cloned; } @@ -39,6 +42,7 @@ public override List AllActions allActions.AddRange(UsingActions); allActions.AddRange(NamespaceActions); allActions.AddRange(IdentifierNameActions); + allActions.AddRange(ObjectCreationExpressionActions); allActions.AddRange(base.AllActions); return allActions; } diff --git a/src/CTA.Rules.Models/Tokens/NodeToken.cs b/src/CTA.Rules.Models/Tokens/NodeToken.cs index 95f77609..b18b16ee 100644 --- a/src/CTA.Rules.Models/Tokens/NodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/NodeToken.cs @@ -16,7 +16,6 @@ public NodeToken() MethodDeclarationActions = new List(); ElementAccessActions = new List(); MemberAccessActions = new List(); - ObjectCreationExpressionActions = new List(); PackageActions = new List(); InterfaceDeclarationActions = new List(); ProjectLevelActions = new List(); @@ -42,7 +41,6 @@ public NodeToken() public List ElementAccessActions { get; set; } public List MemberAccessActions { get; set; } public List ExpressionActions { get; set; } - public List ObjectCreationExpressionActions { get; set; } public List PackageActions { get; set; } public List ProjectLevelActions { get; set; } public List ProjectFileActions { get; set; } @@ -61,7 +59,6 @@ public virtual NodeToken Clone() cloned.ElementAccessActions = cloned.ElementAccessActions.Select(action => action.Clone()).ToList(); cloned.MemberAccessActions = cloned.MemberAccessActions.Select(action => action.Clone()).ToList(); cloned.ExpressionActions = cloned.ExpressionActions.Select(action => action.Clone()).ToList(); - cloned.ObjectCreationExpressionActions = cloned.ObjectCreationExpressionActions.Select(action => action.Clone()).ToList(); cloned.PackageActions = cloned.PackageActions.Select(action => action.Clone()).ToList(); cloned.ProjectLevelActions = cloned.ProjectLevelActions.Select(action => action.Clone()).ToList(); cloned.ProjectFileActions = cloned.ProjectFileActions.Select(action => action.Clone()).ToList(); @@ -83,7 +80,6 @@ public virtual List AllActions allActions.AddRange(MemberAccessActions); allActions.AddRange(ExpressionActions); allActions.AddRange(MemberAccessActions); - allActions.AddRange(ObjectCreationExpressionActions); return allActions; } } diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/ObjectCreationExpressionToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/ObjectCreationExpressionToken.cs new file mode 100644 index 00000000..7a180334 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/ObjectCreationExpressionToken.cs @@ -0,0 +1,16 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic; + +public class ObjectCreationExpressionToken : VisualBasicNodeToken +{ + public override bool Equals(object obj) + { + var token = (ObjectCreationExpressionToken)obj; + return token?.Key == this.Key; + } + public override int GetHashCode() + { + return HashCode.Combine(Key, Namespace, Type); + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs index b0f0856d..b2d03b46 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs @@ -1,6 +1,5 @@ using System.Linq; using System.Collections.Generic; -using System.Configuration; using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using CTA.Rules.Models.Actions.VisualBasic; @@ -20,6 +19,7 @@ public VisualBasicNodeToken() InterfaceBlockActions = new List(); VbAttributeListActions = new List(); AccessorBlockActions = new List(); + ObjectCreationExpressionActions = new List(); } public List> InvocationExpressionActions { get; set; } @@ -31,6 +31,8 @@ public VisualBasicNodeToken() public List InterfaceBlockActions { get; set; } public List VbAttributeListActions { get; set; } public List AccessorBlockActions { get; set; } + public List ObjectCreationExpressionActions{ get; set; } + public override VisualBasicNodeToken Clone() { @@ -53,6 +55,8 @@ public override VisualBasicNodeToken Clone() .Select(action => action.Clone()).ToList(); cloned.AccessorBlockActions = cloned.AccessorBlockActions .Select(action => action.Clone()).ToList(); + cloned.ObjectCreationExpressionActions = cloned.ObjectCreationExpressionActions + .Select(action => action.Clone()).ToList(); return cloned; } @@ -70,6 +74,7 @@ public override List AllActions allActions.AddRange(InterfaceBlockActions); allActions.AddRange(AttributeListActions); allActions.AddRange(AccessorBlockActions); + allActions.AddRange(ObjectCreationExpressionActions); allActions.AddRange(base.AllActions); return allActions; } diff --git a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs index 79414d67..347b5b2c 100644 --- a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs +++ b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs @@ -1,9 +1,6 @@ using System.Collections.Generic; -using CTA.Rules.Models.Tokens; using CTA.Rules.Models.Tokens.VisualBasic; -using InvocationExpressionToken = CTA.Rules.Models.Tokens.VisualBasic.InvocationExpressionToken; -using NamespaceToken = CTA.Rules.Models.Tokens.VisualBasic.NamespaceToken; -using ProjectToken = CTA.Rules.Models.Tokens.VisualBasic.ProjectToken; +using NodeToken = CTA.Rules.Models.Tokens.NodeToken; namespace CTA.Rules.Models.VisualBasic { @@ -22,6 +19,7 @@ public VisualBasicRootNodes() ProjectTokens = new HashSet(); IdentifierNameTokens = new HashSet(); TypeBlockTokens = new HashSet(); + ObjectCreationExpressionTokens = new HashSet(); } public HashSet InvocationExpressionTokens { get; set; } @@ -35,5 +33,6 @@ public VisualBasicRootNodes() public HashSet ProjectTokens { get; set; } public HashSet IdentifierNameTokens { get; set; } public HashSet TypeBlockTokens { get; set; } + public HashSet ObjectCreationExpressionTokens { get; set; } } } diff --git a/src/CTA.Rules.RuleFiles/RulesFileLoader.cs b/src/CTA.Rules.RuleFiles/RulesFileLoader.cs index a1c8ccb8..96ceb64e 100644 --- a/src/CTA.Rules.RuleFiles/RulesFileLoader.cs +++ b/src/CTA.Rules.RuleFiles/RulesFileLoader.cs @@ -143,7 +143,7 @@ public RulesFileLoaderResponse Load() } - private NamespaceRecommendations LoadNamespaceFile(string pathToLoad) + public NamespaceRecommendations LoadNamespaceFile(string pathToLoad) { NamespaceRecommendations nr = new NamespaceRecommendations(); diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs index bfda08fd..e04040e4 100644 --- a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -8,8 +8,8 @@ using CTA.Rules.Models.VisualBasic; using CTA.Rules.Models.Tokens.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using Newtonsoft.Json; using IdentifierNameToken = CTA.Rules.Models.VisualBasic.IdentifierNameToken; +using ObjectCreationExpressionAction = CTA.Rules.Models.VisualBasic.ObjectCreationExpressionAction; namespace CTA.Rules.RuleFiles @@ -19,7 +19,7 @@ namespace CTA.Rules.RuleFiles /// public class VisualBasicRulesFileParser { - private readonly Models.VisualBasic.VisualBasicRootNodes _visualBasicRootNodes; + private readonly VisualBasicRootNodes _visualBasicRootNodes; private readonly string _assembliesDir; private readonly string _targetFramework; @@ -39,7 +39,6 @@ public class VisualBasicRulesFileParser /// Directory containing additional actions assemblies /// Namespace recommendations /// Framework version being targeted for porting - /// Project language, C# or VB /// public VisualBasicRulesFileParser( NamespaceRecommendations namespaceRecommendations, @@ -49,8 +48,8 @@ public VisualBasicRulesFileParser( string assembliesDir, string targetFramework) { - _visualBasicRootNodes = new Models.VisualBasic.VisualBasicRootNodes(); - //_visualBasicRootNodes.ProjectTokens.Add(new ProjectToken() { Key = "Project" }); + _visualBasicRootNodes = new VisualBasicRootNodes(); + _visualBasicRootNodes.ProjectTokens.Add(new ProjectToken() { Key = "Project" }); _rulesObject = rulesObject; _overrideObject = overrideObject; _assembliesDir = assembliesDir; @@ -129,16 +128,21 @@ public void ProcessObject(Rootobject rootobject) //Namespace specific actions: else { - /* - var usingToken = new UsingDirectiveToken() { Key = @namespace.@namespace }; + var usingToken = new ImportStatementToken() { Key = @namespace.@namespace }; var namespaceToken = new NamespaceToken() { Key = @namespace.@namespace }; - if (!_rootNodes.Usingdirectivetokens.Contains(usingToken)) { _rootNodes.Usingdirectivetokens.Add(usingToken); } - if (!_rootNodes.NamespaceTokens.Contains(namespaceToken)) { _rootNodes.NamespaceTokens.Add(namespaceToken); } + if (!_visualBasicRootNodes.ImportStatementTokens.Contains(usingToken)) + { + _visualBasicRootNodes.ImportStatementTokens.Add(usingToken); + } + + if (!_visualBasicRootNodes.NamespaceTokens.Contains(namespaceToken)) + { + _visualBasicRootNodes.NamespaceTokens.Add(namespaceToken); + } ParseActions(usingToken, @namespace.Actions); ParseActions(namespaceToken, @namespace.Actions); - */ } } foreach (var @class in @namespace.Classes) @@ -175,16 +179,26 @@ public void ProcessObject(Rootobject rootobject) ParseActions(token, attribute.Actions); } } + */ foreach (var objectCreation in @class.ObjectCreations) { if (objectCreation.Actions != null && objectCreation.Actions.Count > 0) { - var token = new ObjectCreationExpressionToken() { Key = objectCreation.Key, Namespace = @namespace.@namespace, FullKey = objectCreation.FullKey, Type = @class.Key }; - if (!_rootNodes.ObjectCreationExpressionTokens.Contains(token)) { _rootNodes.ObjectCreationExpressionTokens.Add(token); } + var token = new ObjectCreationExpressionToken + { + Key = objectCreation.Key, + Namespace = @namespace.@namespace, + FullKey = objectCreation.FullKey, + Type = @class.Key + }; + if (!_visualBasicRootNodes.ObjectCreationExpressionTokens.Contains(token)) + { + _visualBasicRootNodes.ObjectCreationExpressionTokens.Add(token); + } + ParseActions(token, objectCreation.Actions); } } - */ foreach (var method in @class.Methods) { @@ -376,7 +390,21 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.ObjectCreation: { - throw new NotImplementedException(); + var token = new ObjectCreationExpressionToken + { + Key = recommendation.Name, + Description = recommendedActions.Description, + TargetCPU = targetCPUs, + Namespace = @namespace.Name, + FullKey = recommendation.Value, + Type = recommendation.ContainingType + }; + if (!_visualBasicRootNodes.ObjectCreationExpressionTokens.Contains(token)) + { + _visualBasicRootNodes.ObjectCreationExpressionTokens.Add(token); + } + ParseActions(token, recommendedActions.Actions); + break; } case ActionTypes.MethodDeclaration: @@ -537,6 +565,20 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.ObjectCreation: { + var actionFunc = _actionsLoader.GetObjectCreationExpressionActions(action.Name, action.Value); + if (actionFunc != null) + { + visualBasicNodeToken.ObjectCreationExpressionActions.Add(new ObjectCreationExpressionAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(action.Value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = action.Name, + Type = action.Type, + ObjectCreationExpressionGenericActionFunc = actionFunc + }); + } break; } case ActionTypes.MethodDeclaration: From c1f95a3ee66f67bff8c3bc96af54cf4779af5ae1 Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 8 Jun 2022 12:04:07 -0700 Subject: [PATCH 33/61] use vb values from rule file if available, and add vb action name for metrics --- .../VisualBasicRulesFileParser.cs | 75 ++++++++++--------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs index e04040e4..e0d0ecbc 100644 --- a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -448,21 +448,26 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List try { var actionType = Enum.Parse(typeof(ActionTypes), action.Type); + + dynamic value = action.VbValue ?? action.Value; + ActionValidation validation = action.VbActionValidation ?? action.ActionValidation; + string vbActionName = "Vb" + action.Name; + switch (actionType) { case ActionTypes.Method: { - var actionFunc = _actionsLoader.GetInvocationExpressionAction(action.Name, action.Value); + var actionFunc = _actionsLoader.GetInvocationExpressionAction(action.Name, value); if (actionFunc != null) { visualBasicNodeToken.InvocationExpressionActions.Add( new InvocationExpressionAction { Key = visualBasicNodeToken.Key, - Value = GetActionValue(action.Value), + Value = GetActionValue(value), Description = action.Description, - ActionValidation = action.ActionValidation, - Name = action.Name, + ActionValidation = validation, + Name = vbActionName, Type = action.Type, InvocationExpressionActionFunc = actionFunc }); @@ -476,16 +481,16 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Class: { - var actionFunc = _actionsLoader.GetClassAction(action.Name, action.Value); + var actionFunc = _actionsLoader.GetClassAction(action.Name, value); if (actionFunc != null) { visualBasicNodeToken.TypeBlockActions.Add(new TypeBlockAction() { Key = visualBasicNodeToken.Key, - Value = GetActionValue(action.Value), + Value = GetActionValue(value), Description = action.Description, - ActionValidation = action.ActionValidation, - Name = action.Name, + ActionValidation = validation, + Name = vbActionName, Type = action.Type, TypeBlockActionFunc = actionFunc }); @@ -498,20 +503,20 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Using: { - var actionFunc = _actionsLoader.GetCompilationUnitAction(action.Name, action.Value); + var actionFunc = _actionsLoader.GetCompilationUnitAction(action.Name, value); // Using directives can be found in both ComplilationUnit and inside Namespace. // Need to make sure remove action is taken if it's inside Namespace block. // Only add using directives in the CompilationUnit as our convention, so it's not added twice. - var namespaceActionFunc = _actionsLoader.GetNamespaceActions(action.Name, action.Value); + var namespaceActionFunc = _actionsLoader.GetNamespaceActions(action.Name, value); if (actionFunc != null) { visualBasicNodeToken.ImportActions.Add(new ImportAction() { Key = visualBasicNodeToken.Key, - Value = GetActionValue(action.Value), + Value = GetActionValue(value), Description = action.Description, - ActionValidation = action.ActionValidation, - Name = action.Name, + ActionValidation = validation, + Name = vbActionName, Type = action.Type, ImportActionFunc = actionFunc, ImportsClauseActionFunc = namespaceActionFunc @@ -521,16 +526,16 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Namespace: { - var actionFunc = _actionsLoader.GetNamespaceActions(action.Name, action.Value); + var actionFunc = _actionsLoader.GetNamespaceActions(action.Name, value); if (actionFunc != null) { visualBasicNodeToken.NamespaceActions.Add(new NamespaceAction() { Key = visualBasicNodeToken.Key, - Value = GetActionValue(action.Value), + Value = GetActionValue(value), Description = action.Description, - ActionValidation = action.ActionValidation, - Name = action.Name, + ActionValidation = validation, + Name = vbActionName, Type = action.Type, NamespaceActionFunc = actionFunc }); @@ -539,16 +544,16 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Identifier: { - var actionFunc = _actionsLoader.GetIdentifierNameAction(action.Name, action.Value); + var actionFunc = _actionsLoader.GetIdentifierNameAction(action.Name, value); if (actionFunc != null) { visualBasicNodeToken.IdentifierNameActions.Add(new IdentifierNameAction() { Key = visualBasicNodeToken.Key, - Value = GetActionValue(action.Value), + Value = GetActionValue(value), Description = action.Description, - ActionValidation = action.ActionValidation, - Name = action.Name, + ActionValidation = validation, + Name = vbActionName, Type = action.Type, IdentifierNameActionFunc = actionFunc }); @@ -565,16 +570,16 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.ObjectCreation: { - var actionFunc = _actionsLoader.GetObjectCreationExpressionActions(action.Name, action.Value); + var actionFunc = _actionsLoader.GetObjectCreationExpressionActions(action.Name, value); if (actionFunc != null) { visualBasicNodeToken.ObjectCreationExpressionActions.Add(new ObjectCreationExpressionAction() { Key = visualBasicNodeToken.Key, - Value = GetActionValue(action.Value), + Value = GetActionValue(value), Description = action.Description, - ActionValidation = action.ActionValidation, - Name = action.Name, + ActionValidation = validation, + Name = vbActionName, Type = action.Type, ObjectCreationExpressionGenericActionFunc = actionFunc }); @@ -595,16 +600,16 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Project: { - var actionFunc = _actionsLoader.GetProjectLevelActions(action.Name, action.Value); + var actionFunc = _actionsLoader.GetProjectLevelActions(action.Name, value); if (actionFunc != null) { visualBasicNodeToken.ProjectLevelActions.Add(new ProjectLevelAction() { Key = visualBasicNodeToken.Key, - Value = GetActionValue(action.Value), + Value = GetActionValue(value), Description = action.Description, - ActionValidation = action.ActionValidation, - Name = action.Name, + ActionValidation = validation, + Name = vbActionName, Type = action.Type, ProjectLevelActionFunc = actionFunc }); @@ -613,16 +618,16 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.ProjectFile: { - var actionFunc = _actionsLoader.GetProjectFileActions(action.Name, action.Value); + var actionFunc = _actionsLoader.GetProjectFileActions(action.Name, value); if (actionFunc != null) { visualBasicNodeToken.ProjectFileActions.Add(new ProjectLevelAction() { Key = visualBasicNodeToken.Key, - Value = GetActionValue(action.Value), + Value = GetActionValue(value), Description = action.Description, ActionValidation = action.ActionValidation, - Name = action.Name, + Name = vbActionName, Type = action.Type, ProjectFileActionFunc = actionFunc }); @@ -631,16 +636,16 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.ProjectType: { - var actionFunc = _actionsLoader.GetProjectTypeActions(action.Name, action.Value); + var actionFunc = _actionsLoader.GetProjectTypeActions(action.Name, value); if (actionFunc != null) { visualBasicNodeToken.ProjectTypeActions.Add(new ProjectLevelAction() { Key = visualBasicNodeToken.Key, - Value = GetActionValue(action.Value), + Value = GetActionValue(value), Description = action.Description, ActionValidation = action.ActionValidation, - Name = action.Name, + Name = vbActionName, Type = action.Type, ProjectTypeActionFunc = actionFunc }); From 257e83e989a3dd3ff0550db7642854a717374d68 Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 8 Jun 2022 12:04:31 -0700 Subject: [PATCH 34/61] add missing override modifier --- src/CTA.Rules.Models/Actions/Identifiernameaction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CTA.Rules.Models/Actions/Identifiernameaction.cs b/src/CTA.Rules.Models/Actions/Identifiernameaction.cs index 0cf0718d..d962cd37 100644 --- a/src/CTA.Rules.Models/Actions/Identifiernameaction.cs +++ b/src/CTA.Rules.Models/Actions/Identifiernameaction.cs @@ -21,7 +21,7 @@ public override int GetHashCode() return HashCode.Combine(Key, Value, IdentifierNameActionFunc?.Method.Name); } - public IdentifierNameAction Copy() + public override IdentifierNameAction Copy() { IdentifierNameAction copy = (IdentifierNameAction)base.Copy(); copy.IdentifierNameActionFunc = this.IdentifierNameActionFunc; From d7df0f57b0e1e9d8af028ab8e3243f5ed802263c Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 8 Jun 2022 16:23:20 -0700 Subject: [PATCH 35/61] update action loaders move member access to base since shared --- src/CTA.Rules.Actions/ActionLoaderBase.cs | 11 +++++++++-- src/CTA.Rules.Actions/ActionsLoader.cs | 8 ++------ src/CTA.Rules.Actions/VisualBasicActionsLoader.cs | 9 ++++++++- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/CTA.Rules.Actions/ActionLoaderBase.cs b/src/CTA.Rules.Actions/ActionLoaderBase.cs index af6c5f23..e12b8275 100644 --- a/src/CTA.Rules.Actions/ActionLoaderBase.cs +++ b/src/CTA.Rules.Actions/ActionLoaderBase.cs @@ -6,6 +6,8 @@ using CTA.Rules.Models; using Codelyzer.Analysis; using CTA.Rules.Config; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editing; using Newtonsoft.Json; namespace CTA.Rules.Actions; @@ -14,11 +16,13 @@ public class ActionLoaderBase { protected List projectLevelActions, projectFileActions, - projectTypeActions; + projectTypeActions, + memberAccessActions; protected object projectLevelObject, projectFileObject, - projectTypeObject; + projectTypeObject, + memberAccessObject; public Func GetProjectLevelActions(string name, dynamic value) => GetAction> @@ -29,6 +33,9 @@ public Func, Dictionary, List< public Func GetProjectTypeActions(string name, dynamic value) => GetAction> (projectTypeActions, projectTypeObject, name, value); + public Func GetMemberAccessExpressionActions(string name, dynamic value) => + GetAction> + (memberAccessActions, memberAccessObject, name, value); #region helper functions diff --git a/src/CTA.Rules.Actions/ActionsLoader.cs b/src/CTA.Rules.Actions/ActionsLoader.cs index 391cbdef..2f59a64d 100644 --- a/src/CTA.Rules.Actions/ActionsLoader.cs +++ b/src/CTA.Rules.Actions/ActionsLoader.cs @@ -27,7 +27,6 @@ public class ActionsLoader : ActionLoaderBase methodDeclarationActions, elementAccessActions, objectCreationExpressionActions, - memberAccessActions, namespaceActions, interfaceActions; @@ -41,7 +40,6 @@ public class ActionsLoader : ActionLoaderBase expressionObject, methodDeclarationObject, elementAccessObject, - memberAccessObject, objectExpressionObject, namespaceObject; @@ -95,7 +93,8 @@ public ActionsLoader(List assemblyPaths) var types = assembly.GetTypes() .Where(t => t.Name.EndsWith("Actions") && (t.Namespace.EndsWith(ProjectLanguage.Csharp.ToString()) || - t.Name.StartsWith("Project"))).ToList(); + t.Name.StartsWith("Project") || + t.Name.StartsWith("MemberAccess"))).ToList(); attributeObject = Activator.CreateInstance(types.FirstOrDefault(t => t.Name == Constants.AttributeActions)); attributeListObject = Activator.CreateInstance(types.FirstOrDefault(t => t.Name == Constants.AttributeListActions)); @@ -248,9 +247,6 @@ public Func G public Func GetElementAccessExpressionActions(string name, dynamic value) => GetAction> (elementAccessActions, elementAccessObject, name, value); - public Func GetMemberAccessExpressionActions(string name, dynamic value) => - GetAction> - (memberAccessActions, memberAccessObject, name, value); } } diff --git a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs index 5d6dda15..d5022612 100644 --- a/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs +++ b/src/CTA.Rules.Actions/VisualBasicActionsLoader.cs @@ -58,6 +58,7 @@ public VisualBasicActionsLoader(List assemblyPaths) _interfaceActions = new List (); _methodBlockActions = new List (); _objectCreationExpressionActions = new List(); + memberAccessActions = new List(); projectLevelActions = new List(); projectFileActions = new List(); projectTypeActions = new List(); @@ -87,7 +88,8 @@ public VisualBasicActionsLoader(List assemblyPaths) TryCreateInstance(Constants.ProjectTypeActions, types, out projectTypeObject); TryCreateInstance(Constants.IdentifierNameActions, types, out _identifierNameObject); TryCreateInstance(Constants.ObjectCreationExpressionActions, types, out _objectExpressionObject); - + TryCreateInstance(Constants.MemberAccessActions, types, out memberAccessObject); + foreach (var t in types) { switch (t.Name) @@ -167,6 +169,11 @@ public VisualBasicActionsLoader(List assemblyPaths) _objectCreationExpressionActions.AddRange(GetFuncMethods(t)); break; } + case Constants.MemberAccessActions: + { + memberAccessActions.AddRange(GetFuncMethods(t)); + break; + } default: { LogHelper.LogError($"Action type {t.Name} is not found"); From 2c9f56653f80e06b5dad197fab34eda458c46940 Mon Sep 17 00:00:00 2001 From: longachr Date: Wed, 8 Jun 2022 16:24:49 -0700 Subject: [PATCH 36/61] add remaining nodes for rule file processing --- .../VisualBasicRulesAnalysis.cs | 406 +++++++++++------- .../Actions/ExpressionAction.cs | 1 - .../Actions/VisualBasic/AttributeAction.cs | 32 ++ .../VisualBasic/AttributeListAction.cs | 2 +- .../VisualBasic/ElementAccessAction.cs | 24 ++ .../FileActions/FileActions.cs | 7 + .../Tokens/Csharp/CsharpNodeToken.cs | 24 ++ src/CTA.Rules.Models/Tokens/NodeToken.cs | 27 +- .../Tokens/VisualBasic/AttributeToken.cs | 18 + .../Tokens/VisualBasic/ElementAccessToken.cs | 17 + .../Tokens/VisualBasic/ExpressionToken.cs | 17 + ...berAccessToken.cs => MemberAccessToken.cs} | 4 +- .../VisualBasic/VisualBasicNodeToken.cs | 13 +- .../VisualBasic/VisualBasicRootNodes.cs | 10 +- .../VisualBasicRulesFileParser.cs | 227 +++++++++- 15 files changed, 635 insertions(+), 194 deletions(-) create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/AttributeAction.cs create mode 100644 src/CTA.Rules.Models/Actions/VisualBasic/ElementAccessAction.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/AttributeToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/ElementAccessToken.cs create mode 100644 src/CTA.Rules.Models/Tokens/VisualBasic/ExpressionToken.cs rename src/CTA.Rules.Models/Tokens/VisualBasic/{VBMemberAccessToken.cs => MemberAccessToken.cs} (73%) diff --git a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs index 7d26bcbe..b4847581 100644 --- a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs @@ -10,9 +10,11 @@ using CTA.Rules.Models.Tokens.VisualBasic; using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using AttributeAction = CTA.Rules.Models.Actions.VisualBasic.AttributeAction; +using ElementAccessAction = CTA.Rules.Models.VisualBasic.ElementAccessAction; +using ElementAccessToken = CTA.Rules.Models.Tokens.VisualBasic.ElementAccessToken; using IdentifierNameToken = CTA.Rules.Models.VisualBasic.IdentifierNameToken; -using InvocationExpressionToken = CTA.Rules.Models.Tokens.VisualBasic.InvocationExpressionToken; -using NamespaceToken = CTA.Rules.Models.Tokens.VisualBasic.NamespaceToken; +using MemberAccessToken = CTA.Rules.Models.Tokens.VisualBasic.MemberAccessToken; using ObjectCreationExpressionAction = CTA.Rules.Models.VisualBasic.ObjectCreationExpressionAction; namespace CTA.Rules.Analyzer; @@ -25,7 +27,7 @@ public class VisualBasicRulesAnalysis : IRulesAnalysis private readonly ProjectType _projectType; /// - /// Initializes a RulesAnalysis instance for Visual Basic projects + /// Initializes a RulesAnalysis instance for Visual Basic projects /// /// List of analyzed code files /// List of rules to be applied to the code files @@ -50,11 +52,11 @@ public ProjectActions Analyze() _projectActions.FileActions.Add(fileAction); } }); - + AddPackages( _visualBasicRootNodes.ProjectTokens.Where(p => p.FullKey == _projectType.ToString()) ?.SelectMany(p => p.PackageActions)?.Distinct()?.ToList(), null); - + return _projectActions; } @@ -107,17 +109,23 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, switch (child.NodeType) { case IdConstants.AttributeListName: + { + var attributeList = (AttributeList)child; + var compareToken = new AttributeListToken { - var attributeList = (AttributeList)child; - var compareToken = new AttributeListToken() { Key = attributeList.Identifier, Namespace = attributeList.Reference.Namespace, Type = attributeList.SemanticClassType }; - _visualBasicRootNodes.AttributeListTokens.TryGetValue(compareToken, out var token); - if (token != null) - { - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - break; + Key = attributeList.Identifier, + Namespace = attributeList.Reference.Namespace, + Type = attributeList.SemanticClassType + }; + _visualBasicRootNodes.AttributeListTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; } + + break; + } case IdConstants.ImportsStatementName: { var overrideKey = string.Empty; @@ -146,11 +154,13 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, } } } + if (token != null) { AddActions(fileAction, token, child.TextSpan, overrideKey); containsActions = true; } + break; } case IdConstants.NamespaceBlockIdName: @@ -162,10 +172,12 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, AddActions(fileAction, token, child.TextSpan); containsActions = true; } + if (AnalyzeChildren(fileAction, child.Children, ++level, child.Identifier)) { containsActions = true; } + break; } case IdConstants.ModuleBlockName: @@ -175,19 +187,20 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, moduleType.Reference != null ? string.Concat(moduleType.Reference.Namespace, ".") : string.Empty, moduleType.Identifier); - var nameToken = new TypeBlockToken() { FullKey = name }; + var nameToken = new TypeBlockToken { FullKey = name }; if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out var token)) { AddNamedActions(fileAction, token, moduleType.Identifier, child.TextSpan); AddActions(fileAction, token, child.TextSpan); containsActions = true; } + break; } case IdConstants.ClassBlockName: { var classType = (ClassBlock)child; - var baseToken = new TypeBlockToken() { FullKey = classType.BaseType }; + var baseToken = new TypeBlockToken { FullKey = classType.BaseType }; if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseToken, out var token)) { AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); @@ -200,7 +213,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, classType.Reference != null ? string.Concat(classType.Reference.Namespace, ".") : string.Empty, classType.Identifier); - var nameToken = new TypeBlockToken() { FullKey = name }; + var nameToken = new TypeBlockToken { FullKey = name }; if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(nameToken, out token)) { AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); @@ -209,9 +222,9 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, } token = null; - foreach (string interfaceName in classType.Inherits) + foreach (var interfaceName in classType.Inherits) { - var baseListToken = new TypeBlockToken() { FullKey = interfaceName }; + var baseListToken = new TypeBlockToken { FullKey = interfaceName }; if (_visualBasicRootNodes.TypeBlockTokens.TryGetValue(baseListToken, out token)) { AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan); @@ -219,80 +232,98 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, containsActions = true; } - token = null; - } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, classType.Identifier)) { containsActions = true; } - break; + token = null; } - case IdConstants.InterfaceBlockIdName: - { - var interfaceType = (InterfaceBlock)child; - var baseToken = new InterfaceBlockToken() { FullKey = interfaceType.BaseType }; - InterfaceBlockToken token = null; - if (!string.IsNullOrEmpty(interfaceType.BaseType)) - { - _visualBasicRootNodes.InterfaceBlockTokens.TryGetValue(baseToken, out token); - } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, classType.Identifier)) + { + containsActions = true; + } - if (token != null) - { - //In case of interface blocks, add actions on the interface by name, instead of property - AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } + break; + } + case IdConstants.InterfaceBlockIdName: + { + var interfaceType = (InterfaceBlock)child; + var baseToken = new InterfaceBlockToken { FullKey = interfaceType.BaseType }; + InterfaceBlockToken token = null; - token = null; - string name = string.Concat(interfaceType.Reference != null ? string.Concat(interfaceType.Reference.Namespace, ".") : string.Empty, interfaceType.Identifier); - var nameToken = new InterfaceBlockToken() { FullKey = name }; + if (!string.IsNullOrEmpty(interfaceType.BaseType)) + { _visualBasicRootNodes.InterfaceBlockTokens.TryGetValue(baseToken, out token); + } - if (token != null) - { - //In case of interface blocks, add actions on the interface by name, instead of property - AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } + if (token != null) + { + //In case of interface blocks, add actions on the interface by name, instead of property + AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace)) { containsActions = true; } - break; + token = null; + var name = string.Concat( + interfaceType.Reference != null + ? string.Concat(interfaceType.Reference.Namespace, ".") + : string.Empty, interfaceType.Identifier); + var nameToken = new InterfaceBlockToken { FullKey = name }; + _visualBasicRootNodes.InterfaceBlockTokens.TryGetValue(baseToken, out token); + + if (token != null) + { + //In case of interface blocks, add actions on the interface by name, instead of property + AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace)) + { + containsActions = true; } + + break; + } case IdConstants.AccessorBlockName: + { + var accessorType = (AccessorBlock)child; + var name = string.Concat( + accessorType.Reference != null + ? string.Concat(accessorType.Reference.Namespace, ".") + : string.Empty, accessorType.Identifier); + var nameToken = new AccessorBlockToken { FullKey = name }; + if (_visualBasicRootNodes.AccessorBlockTokens.TryGetValue(nameToken, out var token)) { - var accessorType = (AccessorBlock)child; - var name = string.Concat( - accessorType.Reference != null - ? string.Concat(accessorType.Reference.Namespace, ".") - : string.Empty, accessorType.Identifier); - var nameToken = new AccessorBlockToken() { FullKey = name }; - if (_visualBasicRootNodes.AccessorBlockTokens.TryGetValue(nameToken, out var token)) - { - AddNamedActions(fileAction, token, accessorType.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - break; + AddNamedActions(fileAction, token, accessorType.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; } + + break; + } case IdConstants.SubBlockName: + { + var compareToken = new MethodBlockToken { FullKey = string.Concat(child.Identifier) }; + _visualBasicRootNodes.MethodBlockTokens.TryGetValue(compareToken, out var token); + if (token != null) { - var compareToken = new MethodBlockToken() { FullKey = string.Concat(child.Identifier) }; - _visualBasicRootNodes.MethodBlockTokens.TryGetValue(compareToken, out var token); - if (token != null) - { - AddNamedActions(fileAction, token, child.Identifier, child.TextSpan); - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } - break; + AddNamedActions(fileAction, token, child.Identifier, child.TextSpan); + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + { + containsActions = true; } + + break; + } case IdConstants.InvocationIdName: { var overrideKey = string.Empty; - InvocationExpression invocationExpression = (InvocationExpression)child; + var invocationExpression = (InvocationExpression)child; ////If we don't have a semantic analysis, we dont want to replace invocation expressions, otherwise we'll be replacing expressions regardless of their class/namespace if (string.IsNullOrEmpty(invocationExpression.SemanticOriginalDefinition)) @@ -331,7 +362,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { if (invocationExpression.SemanticClassType.Contains('<')) { - string semanticClassType = invocationExpression.SemanticClassType.Substring(0, + var semanticClassType = invocationExpression.SemanticClassType.Substring(0, invocationExpression.SemanticClassType.IndexOf('<')); compareToken = new InvocationExpressionToken { @@ -339,7 +370,8 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, Namespace = invocationExpression.Reference.Namespace, Type = semanticClassType }; - _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, out token); + _visualBasicRootNodes.InvocationExpressionTokens.TryGetValue(compareToken, + out token); } } } @@ -349,47 +381,80 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, AddActions(fileAction, token, child.TextSpan, overrideKey); containsActions = true; } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } + break; } case IdConstants.ElementAccessIdName: { + ElementAccess elementAccess = (ElementAccess)child; + var compareToken = new ElementAccessToken() + { + Key = elementAccess.Expression, + FullKey = GetFullKey(elementAccess.Reference?.Namespace, elementAccess.SemanticClassType, elementAccess.Expression), + Type = elementAccess.SemanticClassType, + Namespace = elementAccess.Reference?.Namespace + }; + _visualBasicRootNodes.ElementAccessTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; + } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } break; } case IdConstants.MemberAccessIdName: + { + var memberAccess = (MemberAccess)child; + var compareToken = new MemberAccessToken { - MemberAccess memberAccess = (MemberAccess)child; - var compareToken = new VBMemberAccessToken() - { - Key = memberAccess.Name, - FullKey = GetFullKey(memberAccess.Reference?.Namespace, memberAccess.SemanticClassType, memberAccess.Name), - Type = memberAccess.SemanticClassType, - Namespace = memberAccess.Reference?.Namespace - }; - _visualBasicRootNodes.VBMemberAccesstokens.TryGetValue(compareToken, out var token); - if (token != null) - { - AddActions(fileAction, token, child.TextSpan); - containsActions = true; - } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } - break; + Key = memberAccess.Name, + FullKey = GetFullKey(memberAccess.Reference?.Namespace, memberAccess.SemanticClassType, + memberAccess.Name), + Type = memberAccess.SemanticClassType, + Namespace = memberAccess.Reference?.Namespace + }; + _visualBasicRootNodes.MemberAccessTokens.TryGetValue(compareToken, out var token); + if (token != null) + { + AddActions(fileAction, token, child.TextSpan); + containsActions = true; } + + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + { + containsActions = true; + } + + break; + } case IdConstants.DeclarationNodeIdName: { var declarationNode = (DeclarationNode)child; - var compareToken = new IdentifierNameToken() { Key = string.Concat(declarationNode.Reference.Namespace, ".", declarationNode.Identifier), Namespace = declarationNode.Reference.Namespace }; + var compareToken = new IdentifierNameToken + { + Key = string.Concat(declarationNode.Reference.Namespace, ".", + declarationNode.Identifier), + Namespace = declarationNode.Reference.Namespace + }; _visualBasicRootNodes.IdentifierNameTokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); containsActions = true; } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } + + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + { + containsActions = true; + } + break; } case IdConstants.ObjectCreationIdName: @@ -439,7 +504,11 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, } } - if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; } + if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) + { + containsActions = true; + } + break; } default: @@ -469,14 +538,13 @@ private string GetFullKey(string containingNamespace, string containingClass, st { return key; } - else + + if (!string.IsNullOrEmpty(containingClass)) { - if (!string.IsNullOrEmpty(containingClass)) - { - return $"{containingNamespace}.{containingClass}.{key}"; - } - return $"{containingNamespace}.{key}"; + return $"{containingNamespace}.{containingClass}.{key}"; } + + return $"{containingNamespace}.{key}"; } /// @@ -484,7 +552,8 @@ private string GetFullKey(string containingNamespace, string containingClass, st /// /// The file to run actions on /// The token that matched the file - private void AddActions(FileActions fileAction, VisualBasicNodeToken token, TextSpan textSpan, string overrideKey = "") + private void AddActions(FileActions fileAction, VisualBasicNodeToken token, TextSpan textSpan, + string overrideKey = "") { fileAction.VbInvocationExpressionActions.UnionWith(token.InvocationExpressionActions.Select(a => new InvocationExpressionAction @@ -499,7 +568,7 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text InvocationExpressionActionFunc = a.InvocationExpressionActionFunc }).ToList()); - fileAction.VbImportActions.UnionWith(token.ImportActions.Select(a => new ImportAction() + fileAction.VbImportActions.UnionWith(token.ImportActions.Select(a => new ImportAction { Key = a.Key, Description = a.Description, @@ -527,7 +596,20 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text fileAction.VbIdentifierNameActions.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); - fileAction.VbAttributeListActions.UnionWith(token.VbAttributeListActions.Select(a => new AttributeListAction() + fileAction.VbAttributeActions.UnionWith(token.AttributeActions.Select(a => new AttributeAction() + { + Key = a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + AttributeActionFunc = a.AttributeActionFunc, + AttributeListActionFunc = a.AttributeListActionFunc + }).ToList()); + + fileAction.VbAttributeListActions.UnionWith(token.VbAttributeListActions.Select(a => new AttributeListAction { Key = a.Key, Description = a.Description, @@ -539,9 +621,21 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text AttributeListActionFunc = a.AttributeListActionFunc }).ToList()); - fileAction.MemberAccessActions.UnionWith(token.MemberAccessActions.Select(a => new MemberAccessAction() + fileAction.VbElementAccessActions.UnionWith(token.ElementAccessActions.Select(a => new ElementAccessAction() + { + Key = (token is ElementAccessToken) ? token.FullKey : a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + ElementAccessExpressionActionFunc = a.ElementAccessExpressionActionFunc + }).ToList()); + + fileAction.MemberAccessActions.UnionWith(token.MemberAccessActions.Select(a => new MemberAccessAction { - Key = (token is VBMemberAccessToken) ? token.FullKey : a.Key, + Key = token is MemberAccessToken ? token.FullKey : a.Key, Description = a.Description, Value = a.Value, Name = a.Name, @@ -563,6 +657,18 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text ActionValidation = a.ActionValidation, ObjectCreationExpressionGenericActionFunc = a.ObjectCreationExpressionGenericActionFunc }).ToList()); + + fileAction.ExpressionActions.UnionWith(token.ExpressionActions.Select(a => new ExpressionAction() + { + Key = !string.IsNullOrEmpty(overrideKey) ? overrideKey : a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + ExpressionActionFunc = a.ExpressionActionFunc + }).ToList()); if (fileAction.InvocationExpressionActions.Any() || fileAction.VbImportActions.Any() @@ -570,9 +676,11 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text || fileAction.VbIdentifierNameActions.Any() || fileAction.VbAttributeListActions.Any() || fileAction.MemberAccessActions.Any() - || fileAction.NamespaceActions.Any() - || fileAction.IdentifierNameActions.Any() - || fileAction.ObjectCreationExpressionActions.Any()) + || fileAction.VbNamespaceActions.Any() + || fileAction.VbIdentifierNameActions.Any() + || fileAction.VbObjectCreationExpressionActions.Any() + || fileAction.VbElementAccessActions.Any() + || fileAction.ExpressionActions.Any()) { var nodeToken = token.Clone(); nodeToken.TextSpan = textSpan; @@ -596,9 +704,7 @@ private void AddPackages(List packageActions, TextSpan textSpan) { _projectActions.PackageActions.Add(new PackageAction { - Name = p.Name, - Version = p.Version, - TextSpan = textSpan + Name = p.Name, Version = p.Version, TextSpan = textSpan }); } }); @@ -611,10 +717,11 @@ private void AddPackages(List packageActions, TextSpan textSpan) /// /// /// - private void AddNamedActions(FileActions fileAction, VisualBasicNodeToken token, string identifier, TextSpan textSpan) + private void AddNamedActions(FileActions fileAction, VisualBasicNodeToken token, string identifier, + TextSpan textSpan) { fileAction.VbTypeBlockActions.UnionWith(token.TypeBlockActions - .Select(c => new TypeBlockAction() + .Select(c => new TypeBlockAction { Key = identifier, Value = c.Value, @@ -627,46 +734,47 @@ private void AddNamedActions(FileActions fileAction, VisualBasicNodeToken token, })); fileAction.VbMethodBlockActions.UnionWith(token.MethodBlockActions - .Select(c => new MethodBlockAction() - { - Key = identifier, - Value = c.Value, - Description = c.Description, - Name = c.Name, - Type = c.Type, - TextSpan = textSpan, - ActionValidation = c.ActionValidation, - MethodBlockActionFunc = c.MethodBlockActionFunc - })); + .Select(c => new MethodBlockAction + { + Key = identifier, + Value = c.Value, + Description = c.Description, + Name = c.Name, + Type = c.Type, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + MethodBlockActionFunc = c.MethodBlockActionFunc + })); fileAction.VbInterfaceBlockActions.UnionWith(token.InterfaceBlockActions - .Select(c => new InterfaceBlockAction() - { - Key = identifier, - Value = c.Value, - Name = c.Name, - Type = c.Type, - Description = c.Description, - TextSpan = textSpan, - ActionValidation = c.ActionValidation, - InterfaceBlockActionFunc = c.InterfaceBlockActionFunc - })); + .Select(c => new InterfaceBlockAction + { + Key = identifier, + Value = c.Value, + Name = c.Name, + Type = c.Type, + Description = c.Description, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + InterfaceBlockActionFunc = c.InterfaceBlockActionFunc + })); fileAction.VbAccessorBlockActions.UnionWith(token.AccessorBlockActions - .Select(c => new AccessorBlockAction() - { - Key = identifier, - Value = c.Value, - Name = c.Name, - Type = c.Type, - Description = c.Description, - TextSpan = textSpan, - ActionValidation = c.ActionValidation, - AccessorBlockActionFunc = c.AccessorBlockActionFunc - })); + .Select(c => new AccessorBlockAction + { + Key = identifier, + Value = c.Value, + Name = c.Name, + Type = c.Type, + Description = c.Description, + TextSpan = textSpan, + ActionValidation = c.ActionValidation, + AccessorBlockActionFunc = c.AccessorBlockActionFunc + })); if (fileAction.VbTypeBlockActions.Any() || fileAction.VbMethodBlockActions.Any() - || fileAction.VbInterfaceBlockActions.Any() || fileAction.VbAccessorBlockActions.Any()) + || fileAction.VbInterfaceBlockActions.Any() || + fileAction.VbAccessorBlockActions.Any()) { var nodeToken = token.Clone(); nodeToken.TextSpan = textSpan; diff --git a/src/CTA.Rules.Models/Actions/ExpressionAction.cs b/src/CTA.Rules.Models/Actions/ExpressionAction.cs index 04bf8647..b939e590 100644 --- a/src/CTA.Rules.Models/Actions/ExpressionAction.cs +++ b/src/CTA.Rules.Models/Actions/ExpressionAction.cs @@ -1,6 +1,5 @@ using System; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; namespace CTA.Rules.Models diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/AttributeAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/AttributeAction.cs new file mode 100644 index 00000000..f1b17efb --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/AttributeAction.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Models.Actions.VisualBasic +{ + public class AttributeAction : GenericAction + { + public Func AttributeActionFunc { get; set; } + public Func AttributeListActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (AttributeAction)obj; + return action?.Key == Key + && action?.Value == Value + && + ( + (action.AttributeActionFunc != null && AttributeActionFunc != null && + action.AttributeActionFunc.Method.Name == AttributeActionFunc.Method.Name) + || + (action.AttributeListActionFunc != null && AttributeListActionFunc != null && + action.AttributeListActionFunc.Method.Name == AttributeListActionFunc.Method.Name) + ); + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, AttributeActionFunc?.Method.Name, AttributeListActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs index c138490f..8d2d7df8 100644 --- a/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs +++ b/src/CTA.Rules.Models/Actions/VisualBasic/AttributeListAction.cs @@ -10,7 +10,7 @@ public class AttributeListAction : GenericAction public override bool Equals(object obj) { - var action = (AttributeAction)obj; + var action = (Models.AttributeAction)obj; return action?.Key == this.Key && action?.Value == this.Value && action.AttributeListActionFunc != null && this.AttributeListActionFunc != null diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/ElementAccessAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/ElementAccessAction.cs new file mode 100644 index 00000000..c408bfcc --- /dev/null +++ b/src/CTA.Rules.Models/Actions/VisualBasic/ElementAccessAction.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Microsoft.CodeAnalysis.Editing; + +namespace CTA.Rules.Models.VisualBasic +{ + public class ElementAccessAction : GenericAction + { + public Func ElementAccessExpressionActionFunc { get; set; } + + public override bool Equals(object obj) + { + var action = (ElementAccessAction)obj; + return action?.Key == this.Key + && action?.Value == this.Value + && action?.ElementAccessExpressionActionFunc.Method.Name == this.ElementAccessExpressionActionFunc.Method.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Value, ElementAccessExpressionActionFunc?.Method.Name); + } + } +} diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index 9806f81c..377da9dc 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -21,6 +21,7 @@ public FileActions() InvocationExpressionActions = new HashSet>(); + // Member and Expression Actions do not need separate Vb models because they act on shared SyntaxNode object ExpressionActions = new HashSet(); MemberAccessActions = new HashSet(); Usingactions = new HashSet(); @@ -43,7 +44,9 @@ public FileActions() VbAttributeListActions = new HashSet(); VbIdentifierNameActions = new HashSet>(); VbAccessorBlockActions = new HashSet(); + VbElementAccessActions = new HashSet(); VbObjectCreationExpressionActions = new HashSet(); + VbAttributeActions = new HashSet(); } public HashSet> VbNamespaceActions { get; set; } @@ -59,6 +62,8 @@ public HashSet VbAccessorBlockActions { get; set; } public HashSet VbObjectCreationExpressionActions { get; set; } + public HashSet VbElementAccessActions { get; set; } + public HashSet VbAttributeActions { get; set; } public List VbNodeTokens { get; set; } public List NodeTokens { get; set; } @@ -103,6 +108,8 @@ public List AllActions allActions.AddRange(VbIdentifierNameActions); allActions.AddRange(VbAccessorBlockActions); allActions.AddRange(VbObjectCreationExpressionActions); + allActions.AddRange(VbElementAccessActions); + allActions.AddRange(VbAttributeActions); return allActions; } } diff --git a/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs b/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs index cbea1a7d..69dc1161 100644 --- a/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/Csharp/CsharpNodeToken.cs @@ -13,6 +13,12 @@ public CsharpNodeToken() NamespaceActions = new List>(); IdentifierNameActions = new List>(); ObjectCreationExpressionActions = new List(); + ElementAccessActions = new List(); + AttributeActions = new List(); + AttributeListActions = new List(); + ClassDeclarationActions = new List(); + MethodDeclarationActions = new List(); + InterfaceDeclarationActions = new List(); } public List UsingActions { get; set; } @@ -20,6 +26,12 @@ public CsharpNodeToken() public List> NamespaceActions { get; set; } public List> IdentifierNameActions { get; set; } public List ObjectCreationExpressionActions{ get; set; } + public List ElementAccessActions { get; set; } + public List AttributeActions { get; set; } + public List AttributeListActions { get; set; } + public List ClassDeclarationActions { get; set; } + public List InterfaceDeclarationActions { get; set; } + public List MethodDeclarationActions { get; set; } public override CsharpNodeToken Clone() { @@ -29,6 +41,12 @@ public override CsharpNodeToken Clone() cloned.InvocationExpressionActions = cloned.InvocationExpressionActions.Select(action => action.Clone>()).ToList(); cloned.NamespaceActions = cloned.NamespaceActions.Select(action => action.Clone>()).ToList(); cloned.ObjectCreationExpressionActions = cloned.ObjectCreationExpressionActions.Select(action => action.Clone()).ToList(); + cloned.ElementAccessActions = cloned.ElementAccessActions.Select(action => action.Clone()).ToList(); + cloned.AttributeActions = cloned.AttributeActions?.Select(action => action.Clone())?.ToList(); + cloned.AttributeListActions = cloned.AttributeListActions?.Select(action => action.Clone())?.ToList(); + cloned.ClassDeclarationActions = cloned.ClassDeclarationActions?.Select(action => action.Clone())?.ToList(); + cloned.InterfaceDeclarationActions = cloned.InterfaceDeclarationActions.Select(action => action.Clone()).ToList(); + cloned.MethodDeclarationActions = cloned.MethodDeclarationActions.Select(action => action.Clone()).ToList(); return cloned; } @@ -38,11 +56,17 @@ public override List AllActions get { var allActions = new List(); + allActions.AddRange(AttributeActions); + allActions.AddRange(AttributeListActions); allActions.AddRange(InvocationExpressionActions); allActions.AddRange(UsingActions); allActions.AddRange(NamespaceActions); allActions.AddRange(IdentifierNameActions); allActions.AddRange(ObjectCreationExpressionActions); + allActions.AddRange(ElementAccessActions); + allActions.AddRange(MethodDeclarationActions); + allActions.AddRange(ClassDeclarationActions); + allActions.AddRange(InterfaceDeclarationActions); allActions.AddRange(base.AllActions); return allActions; } diff --git a/src/CTA.Rules.Models/Tokens/NodeToken.cs b/src/CTA.Rules.Models/Tokens/NodeToken.cs index b18b16ee..6b5d5d9b 100644 --- a/src/CTA.Rules.Models/Tokens/NodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/NodeToken.cs @@ -9,15 +9,9 @@ public class NodeToken { public NodeToken() { - AttributeActions = new List(); - AttributeListActions = new List(); - ClassDeclarationActions = new List(); ExpressionActions = new List(); - MethodDeclarationActions = new List(); - ElementAccessActions = new List(); MemberAccessActions = new List(); PackageActions = new List(); - InterfaceDeclarationActions = new List(); ProjectLevelActions = new List(); ProjectFileActions = new List(); ProjectTypeActions = new List(); @@ -33,12 +27,7 @@ public NodeToken() public string Description { get; set; } public IList TextChanges { get; set; } public List TargetCPU { get; set; } - public List AttributeActions { get; set; } - public List AttributeListActions { get; set; } - public List ClassDeclarationActions { get; set; } - public List InterfaceDeclarationActions { get; set; } - public List MethodDeclarationActions { get; set; } - public List ElementAccessActions { get; set; } + public List MemberAccessActions { get; set; } public List ExpressionActions { get; set; } public List PackageActions { get; set; } @@ -50,13 +39,7 @@ public virtual NodeToken Clone() { NodeToken cloned = (NodeToken)this.MemberwiseClone(); cloned.TextChanges = cloned.TextChanges?.Select(textChange => textChange.Clone()).ToList(); - cloned.TargetCPU = cloned.TargetCPU?.ToList(); - cloned.AttributeActions = cloned.AttributeActions?.Select(action => action.Clone())?.ToList(); - cloned.AttributeListActions = cloned.AttributeListActions?.Select(action => action.Clone())?.ToList(); - cloned.ClassDeclarationActions = cloned.ClassDeclarationActions?.Select(action => action.Clone())?.ToList(); - cloned.InterfaceDeclarationActions = cloned.InterfaceDeclarationActions.Select(action => action.Clone()).ToList(); - cloned.MethodDeclarationActions = cloned.MethodDeclarationActions.Select(action => action.Clone()).ToList(); - cloned.ElementAccessActions = cloned.ElementAccessActions.Select(action => action.Clone()).ToList(); + cloned.TargetCPU = cloned.TargetCPU?.ToList(); cloned.MemberAccessActions = cloned.MemberAccessActions.Select(action => action.Clone()).ToList(); cloned.ExpressionActions = cloned.ExpressionActions.Select(action => action.Clone()).ToList(); cloned.PackageActions = cloned.PackageActions.Select(action => action.Clone()).ToList(); @@ -71,12 +54,6 @@ public virtual List AllActions get { var allActions = new List(); - allActions.AddRange(AttributeActions); - allActions.AddRange(AttributeListActions); - allActions.AddRange(MethodDeclarationActions); - allActions.AddRange(ClassDeclarationActions); - allActions.AddRange(InterfaceDeclarationActions); - allActions.AddRange(ElementAccessActions); allActions.AddRange(MemberAccessActions); allActions.AddRange(ExpressionActions); allActions.AddRange(MemberAccessActions); diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeToken.cs new file mode 100644 index 00000000..98d10de3 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/AttributeToken.cs @@ -0,0 +1,18 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class AttributeToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (AttributeToken)obj; + return token?.Type == this.Type && token?.Namespace == this.Namespace && token?.Key.Trim() == this.Key.Trim(); + } + + public override int GetHashCode() + { + return HashCode.Combine(Key, Namespace, Type); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/ElementAccessToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/ElementAccessToken.cs new file mode 100644 index 00000000..9b4c1ce7 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/ElementAccessToken.cs @@ -0,0 +1,17 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class ElementAccessToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (ElementAccessToken)obj; + return token?.FullKey == this.FullKey; + } + public override int GetHashCode() + { + return HashCode.Combine(FullKey); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/ExpressionToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/ExpressionToken.cs new file mode 100644 index 00000000..02135f46 --- /dev/null +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/ExpressionToken.cs @@ -0,0 +1,17 @@ +using System; + +namespace CTA.Rules.Models.Tokens.VisualBasic +{ + public class ExpressionToken : VisualBasicNodeToken + { + public override bool Equals(object obj) + { + var token = (ExpressionToken)obj; + return token?.Key == this.Key && token?.Namespace == this.Namespace && token?.Type == this.Type; + } + public override int GetHashCode() + { + return HashCode.Combine(Key, Namespace, Type); + } + } +} diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/MemberAccessToken.cs similarity index 73% rename from src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs rename to src/CTA.Rules.Models/Tokens/VisualBasic/MemberAccessToken.cs index 39339d80..e8e5ce82 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/VBMemberAccessToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/MemberAccessToken.cs @@ -3,11 +3,11 @@ namespace CTA.Rules.Models.Tokens.VisualBasic { - public class VBMemberAccessToken : VisualBasicNodeToken + public class MemberAccessToken : VisualBasicNodeToken { public override bool Equals(object obj) { - var token = (VBMemberAccessToken)obj; + var token = (MemberAccessToken)obj; return token?.FullKey == this.FullKey; } public override int GetHashCode() diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs index b2d03b46..6317184f 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs @@ -20,6 +20,9 @@ public VisualBasicNodeToken() VbAttributeListActions = new List(); AccessorBlockActions = new List(); ObjectCreationExpressionActions = new List(); + ElementAccessActions = new List(); + AttributeActions = new List(); + } public List> InvocationExpressionActions { get; set; } @@ -32,6 +35,8 @@ public VisualBasicNodeToken() public List VbAttributeListActions { get; set; } public List AccessorBlockActions { get; set; } public List ObjectCreationExpressionActions{ get; set; } + public List ElementAccessActions { get; set; } + public List AttributeActions { get; set; } public override VisualBasicNodeToken Clone() @@ -57,6 +62,10 @@ public override VisualBasicNodeToken Clone() .Select(action => action.Clone()).ToList(); cloned.ObjectCreationExpressionActions = cloned.ObjectCreationExpressionActions .Select(action => action.Clone()).ToList(); + cloned.ElementAccessActions = cloned.ElementAccessActions + .Select(action => action.Clone()).ToList(); + cloned.AttributeActions = cloned.AttributeActions + .Select(action => action.Clone()).ToList(); return cloned; } @@ -72,9 +81,11 @@ public override List AllActions allActions.AddRange(TypeBlockActions); allActions.AddRange(MethodBlockActions); allActions.AddRange(InterfaceBlockActions); - allActions.AddRange(AttributeListActions); + allActions.AddRange(VbAttributeListActions); allActions.AddRange(AccessorBlockActions); allActions.AddRange(ObjectCreationExpressionActions); + allActions.AddRange(ElementAccessActions); + allActions.AddRange(AttributeActions); allActions.AddRange(base.AllActions); return allActions; } diff --git a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs index 347b5b2c..03111bba 100644 --- a/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs +++ b/src/CTA.Rules.Models/VisualBasic/VisualBasicRootNodes.cs @@ -12,10 +12,13 @@ public VisualBasicRootNodes() ImportStatementTokens = new HashSet(); InterfaceBlockTokens = new HashSet(); MethodBlockTokens = new HashSet(); + AttributeTokens = new HashSet(); AttributeListTokens = new HashSet(); AccessorBlockTokens = new HashSet(); - VBMemberAccesstokens = new HashSet(); + MemberAccessTokens = new HashSet(); NamespaceTokens = new HashSet(); + ExpressionTokens = new HashSet(); + ElementAccessTokens = new HashSet(); ProjectTokens = new HashSet(); IdentifierNameTokens = new HashSet(); TypeBlockTokens = new HashSet(); @@ -26,10 +29,13 @@ public VisualBasicRootNodes() public HashSet ImportStatementTokens { get; set; } public HashSet InterfaceBlockTokens { get; set; } public HashSet MethodBlockTokens { get; set; } + public HashSet AttributeTokens { get; set; } public HashSet AttributeListTokens { get; set; } public HashSet AccessorBlockTokens { get; set; } - public HashSet VBMemberAccesstokens { get; set; } + public HashSet MemberAccessTokens { get; set; } public HashSet NamespaceTokens { get; set; } + public HashSet ExpressionTokens { get; set; } + public HashSet ElementAccessTokens { get; set; } public HashSet ProjectTokens { get; set; } public HashSet IdentifierNameTokens { get; set; } public HashSet TypeBlockTokens { get; set; } diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs index e0d0ecbc..8424444b 100644 --- a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -5,10 +5,15 @@ using CTA.Rules.Actions; using CTA.Rules.Config; using CTA.Rules.Models; +using CTA.Rules.Models.Actions.VisualBasic; using CTA.Rules.Models.VisualBasic; using CTA.Rules.Models.Tokens.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using AttributeToken = CTA.Rules.Models.Tokens.VisualBasic.AttributeToken; +using ElementAccessAction = CTA.Rules.Models.VisualBasic.ElementAccessAction; +using ElementAccessToken = CTA.Rules.Models.Tokens.VisualBasic.ElementAccessToken; using IdentifierNameToken = CTA.Rules.Models.VisualBasic.IdentifierNameToken; +using MemberAccessToken = CTA.Rules.Models.Tokens.VisualBasic.MemberAccessToken; using ObjectCreationExpressionAction = CTA.Rules.Models.VisualBasic.ObjectCreationExpressionAction; @@ -169,17 +174,27 @@ public void ProcessObject(Rootobject rootobject) ParseActions(token, @class.Actions); } } - /* + foreach (var attribute in @class.Attributes) { if (attribute.Actions != null && attribute.Actions.Count > 0) { - var token = new AttributeToken() { Key = attribute.Key, Namespace = @namespace.@namespace, FullKey = attribute.FullKey, Type = @class.Key }; - if (!_rootNodes.Attributetokens.Contains(token)) { _rootNodes.Attributetokens.Add(token); } + var token = new AttributeToken + { + Key = attribute.Key, + Namespace = @namespace.@namespace, + FullKey = attribute.FullKey, + Type = @class.Key + }; + if (!_visualBasicRootNodes.AttributeTokens.Contains(token)) + { + _visualBasicRootNodes.AttributeTokens.Add(token); + } + ParseActions(token, attribute.Actions); } } - */ + foreach (var objectCreation in @class.ObjectCreations) { if (objectCreation.Actions != null && objectCreation.Actions.Count > 0) @@ -216,10 +231,10 @@ public void ProcessObject(Rootobject rootobject) { if (@interface.Actions != null && @interface.Actions.Count > 0) { - if (@interface.KeyType == CTA.Rules.Config.Constants.BaseClass || @interface.KeyType == CTA.Rules.Config.Constants.InterfaceName) + if (@interface.KeyType == Constants.BaseClass || @interface.KeyType == CTA.Rules.Config.Constants.InterfaceName) { } - else if (@interface.KeyType == CTA.Rules.Config.Constants.Identifier) + else if (@interface.KeyType == Constants.Identifier) { var token = new IdentifierNameToken { @@ -239,6 +254,19 @@ public void ProcessObject(Rootobject rootobject) { if (attribute.Actions != null && attribute.Actions.Count > 0) { + var token = new AttributeToken + { + Key = attribute.Key, + Namespace = @namespace.@namespace, + FullKey = attribute.FullKey, + Type = @interface.Key + }; + if (!_visualBasicRootNodes.AttributeTokens.Contains(token)) + { + _visualBasicRootNodes.AttributeTokens.Add(token); + } + + ParseActions(token, attribute.Actions); } } @@ -259,8 +287,8 @@ public void ProcessObject(Rootobject rootobject) /// /// Processes each rule object by creating tokens and associated actions /// - /// An object containing tokens and actions to run on these tokens - public void ProcessObject(NamespaceRecommendations namespaceRecommendations) + /// An object containing tokens and actions to run on these tokens + private void ProcessObject(NamespaceRecommendations namespaceRecommendations) { var namespaces = namespaceRecommendations.NameSpaces; @@ -381,11 +409,41 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) } case ActionTypes.Expression: { - throw new NotImplementedException(); + var token = new ExpressionToken + { + Key = recommendation.Name, + Description = recommendedActions.Description, + TargetCPU = targetCPUs, + Namespace = @namespace.Name, + FullKey = recommendation.Value, + Type = recommendation.ContainingType + }; + if (!_visualBasicRootNodes.ExpressionTokens.Contains(token)) + { + _visualBasicRootNodes.ExpressionTokens.Add(token); + } + + ParseActions(token, recommendedActions.Actions); + break; } case ActionTypes.Attribute: { - throw new NotImplementedException(); + var token = new AttributeToken() + { + Key = recommendation.Name, + Description = recommendedActions.Description, + TargetCPU = targetCPUs, + Namespace = @namespace.Name, + FullKey = recommendation.Value, + Type = recommendation.ContainingType + }; + if (!_visualBasicRootNodes.AttributeTokens.Contains(token)) + { + _visualBasicRootNodes.AttributeTokens.Add(token); + } + + ParseActions(token, recommendedActions.Actions); + break; } case ActionTypes.ObjectCreation: @@ -409,17 +467,62 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.MethodDeclaration: { - throw new NotImplementedException(); + var token = new MethodBlockToken + { + Key = recommendation.Name, + Description = recommendedActions.Description, + TargetCPU = targetCPUs, + Namespace = @namespace.Name, + FullKey = recommendation.Value, + Type = recommendation.ContainingType + }; + if (!_visualBasicRootNodes.MethodBlockTokens.Contains(token)) + { + _visualBasicRootNodes.MethodBlockTokens.Add(token); + } + + ParseActions(token, recommendedActions.Actions); + break; } case ActionTypes.ElementAccess: { - throw new NotImplementedException(); + var token = new ElementAccessToken + { + Key = recommendation.Name, + Description = recommendedActions.Description, + TargetCPU = targetCPUs, + Namespace = @namespace.Name, + FullKey = recommendation.Value, + Type = recommendation.ContainingType + }; + if (!_visualBasicRootNodes.ElementAccessTokens.Contains(token)) + { + _visualBasicRootNodes.ElementAccessTokens.Add(token); + } + + ParseActions(token, recommendedActions.Actions); + break; } case ActionTypes.MemberAccess: { - throw new NotImplementedException(); + var token = new MemberAccessToken + { + Key = recommendation.Name, + Description = recommendedActions.Description, + TargetCPU = targetCPUs, + Namespace = @namespace.Name, + FullKey = recommendation.Value, + Type = recommendation.ContainingType + }; + if (!_visualBasicRootNodes.MemberAccessTokens.Contains(token)) + { + _visualBasicRootNodes.MemberAccessTokens.Add(token); + } + + ParseActions(token, recommendedActions.Actions); + break; } case ActionTypes.Project: @@ -477,6 +580,20 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Expression: { + var actionFunc = _actionsLoader.GetExpressionAction(action.Name, value); + if (actionFunc != null) + { + visualBasicNodeToken.ExpressionActions.Add(new ExpressionAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = vbActionName, + Type = action.Type, + ExpressionActionFunc = actionFunc + }); + } break; } case ActionTypes.Class: @@ -499,6 +616,20 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Interface: { + var actionFunc = _actionsLoader.GetInterfaceAction(action.Name, value); + if (actionFunc != null) + { + visualBasicNodeToken.InterfaceBlockActions.Add(new InterfaceBlockAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = vbActionName, + Type = action.Type, + InterfaceBlockActionFunc = actionFunc + }); + } break; } case ActionTypes.Using: @@ -562,10 +693,38 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Attribute: { + var actionFunc = _actionsLoader.GetAttributeAction(action.Name, value); + if (actionFunc != null) + { + visualBasicNodeToken.AttributeActions.Add(new Models.Actions.VisualBasic.AttributeAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = vbActionName, + Type = action.Type, + AttributeActionFunc = actionFunc + }); + } break; } case ActionTypes.AttributeList: { + var actionFunc = _actionsLoader.GetAttributeListAction(action.Name, value); + if (actionFunc != null) + { + visualBasicNodeToken.VbAttributeListActions.Add(new Models.Actions.VisualBasic.AttributeListAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = vbActionName, + Type = action.Type, + AttributeListActionFunc = actionFunc + }); + } break; } case ActionTypes.ObjectCreation: @@ -588,14 +747,56 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.MethodDeclaration: { + var actionFunc = _actionsLoader.GetMethodDeclarationAction(action.Name, value); + if (actionFunc != null) + { + visualBasicNodeToken.MethodBlockActions.Add(new MethodBlockAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = vbActionName, + Type = action.Type, + MethodBlockActionFunc = actionFunc + }); + } break; } case ActionTypes.ElementAccess: { + var actionFunc = _actionsLoader.GetElementAccessExpressionActions(action.Name, value); + if (actionFunc != null) + { + visualBasicNodeToken.ElementAccessActions.Add(new ElementAccessAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = vbActionName, + Type = action.Type, + ElementAccessExpressionActionFunc = actionFunc + }); + } break; } case ActionTypes.MemberAccess: { + var actionFunc = _actionsLoader.GetMemberAccessExpressionActions(action.Name, value); + if (actionFunc != null) + { + visualBasicNodeToken.MemberAccessActions.Add(new MemberAccessAction() + { + Key = visualBasicNodeToken.Key, + Value = GetActionValue(value), + Description = action.Description, + ActionValidation = action.ActionValidation, + Name = vbActionName, + Type = action.Type, + MemberAccessActionFunc = actionFunc + }); + } break; } case ActionTypes.Project: From ae07642da189b1c08e1e49ddee55627bf47800e1 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Thu, 9 Jun 2022 16:37:45 -0700 Subject: [PATCH 37/61] Move model files to csharp folder and update some namespaces --- .../packages.lock.json | 98 ++++++++++++------- .../VisualBasicRulesAnalysis.cs | 4 +- .../Actions/{ => Csharp}/Attributeaction.cs | 0 .../{ => Csharp}/Classdeclarationaction.cs | 0 .../{ => Csharp}/Elementaccessaction.cs | 0 .../{ => Csharp}/Identifiernameaction.cs | 0 .../InterfaceDeclarationAction.cs | 0 .../{ => Csharp}/MethodDeclarationAction.cs | 0 .../ObjectCreationExpressionAction.cs | 0 .../Actions/{ => Csharp}/Usingaction.cs | 0 .../VisualBasic/ElementAccessAction.cs | 4 +- .../Actions/VisualBasic/ImportAction.cs | 36 +++---- .../ObjectCreationExpressionAction.cs | 2 +- .../Actions/VisualBasic/TypeBlockAction.cs | 2 +- .../FileActions/FileActions.cs | 11 +-- .../Tokens/{ => Csharp}/Attributetoken.cs | 0 .../{ => Csharp}/Classdeclarationtoken.cs | 0 .../Tokens/{ => Csharp}/Elementaccesstoken.cs | 0 .../Tokens/{ => Csharp}/ExpressionToken.cs | 0 .../{ => Csharp}/Identifiernametoken.cs | 0 .../{ => Csharp}/InterfaceDeclarationToken.cs | 0 .../{ => Csharp}/Invocationexpressiontoken.cs | 0 .../Tokens/{ => Csharp}/Memberaccesstoken.cs | 0 .../{ => Csharp}/MethodDeclarationToken.cs | 0 .../Tokens/{ => Csharp}/NamespaceToken.cs | 0 .../ObjectCreationExpressionToken.cs | 0 .../Tokens/{ => Csharp}/ProjectToken.cs | 0 .../{ => Csharp}/Usingdirectivetoken.cs | 0 .../VisualBasic/VisualBasicNodeToken.cs | 15 ++- src/CTA.Rules.Models/packages.lock.json | 98 ++++++++++++------- .../VisualBasicRulesFileParser.cs | 4 +- .../Actions/VisualBasic/ClassActionsTests.cs | 2 +- .../ObjectCreationExpressionActionsTests.cs | 4 +- 33 files changed, 163 insertions(+), 117 deletions(-) rename src/CTA.Rules.Models/Actions/{ => Csharp}/Attributeaction.cs (100%) rename src/CTA.Rules.Models/Actions/{ => Csharp}/Classdeclarationaction.cs (100%) rename src/CTA.Rules.Models/Actions/{ => Csharp}/Elementaccessaction.cs (100%) rename src/CTA.Rules.Models/Actions/{ => Csharp}/Identifiernameaction.cs (100%) rename src/CTA.Rules.Models/Actions/{ => Csharp}/InterfaceDeclarationAction.cs (100%) rename src/CTA.Rules.Models/Actions/{ => Csharp}/MethodDeclarationAction.cs (100%) rename src/CTA.Rules.Models/Actions/{ => Csharp}/ObjectCreationExpressionAction.cs (100%) rename src/CTA.Rules.Models/Actions/{ => Csharp}/Usingaction.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/Attributetoken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/Classdeclarationtoken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/Elementaccesstoken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/ExpressionToken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/Identifiernametoken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/InterfaceDeclarationToken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/Invocationexpressiontoken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/Memberaccesstoken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/MethodDeclarationToken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/NamespaceToken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/ObjectCreationExpressionToken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/ProjectToken.cs (100%) rename src/CTA.Rules.Models/Tokens/{ => Csharp}/Usingdirectivetoken.cs (100%) diff --git a/src/CTA.FeatureDetection.Common/packages.lock.json b/src/CTA.FeatureDetection.Common/packages.lock.json index 6740c0df..3dfbd96b 100644 --- a/src/CTA.FeatureDetection.Common/packages.lock.json +++ b/src/CTA.FeatureDetection.Common/packages.lock.json @@ -20,10 +20,10 @@ }, "Buildalyzer": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "25NJRnGgYBOC3OPgFDj/KeJwSldXPFZl5jDXjqP7Vsy6vC+MPapcJ687/dOjUeS4t4aVuYrMyWdaezkZgs+Rdw==", + "resolved": "4.1.4", + "contentHash": "O6KGKPeCAe+Ujhd2sl66nu7rrEAM2hBUbi3n79BVBOj9YxuUlbxviOfy3Cq22iIp9rUDPOqOL8E2AYiQwxpUHQ==", "dependencies": { - "Buildalyzer.Logger": "4.1.3", + "Buildalyzer.Logger": "4.1.4", "MSBuild.StructuredLogger": "2.1.507", "Microsoft.Build": "16.9.0", "Microsoft.Build.Framework": "16.9.0", @@ -39,50 +39,53 @@ }, "Buildalyzer.Logger": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "9qq5VfFO/cvasetqJpj+V5sc8Ng5EQjCkYi3COOvzyqNLivYIp+4Cf1ddfbcye3X3i89z9oHIEmF3iNQspFSDw==" + "resolved": "4.1.4", + "contentHash": "2C2FR877slFBYM/usMkGnmOZlLKejV0uag0IzmARkKkBD75jNPM6q2WLaFAW/yRLPyyArpunYzQ+4AaDyEImHQ==" }, "Buildalyzer.Workspaces": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "rZGc9XTd0RzLa3tMG9HfNzhxLKGNerCzW3f+nG/Mau0ucpRENWn7OH9Nz9ZxD3k4oWweOw9kfGfw4VvbcNP43w==", + "resolved": "4.1.4", + "contentHash": "fU4I3dmFDTickARibqYYJb+uDYUxlHM32a0CQgY2dVBJKnf9DFnVkiQjxbhdxGOylHI6lTZm+EdAEqXcjIe4xg==", "dependencies": { - "Buildalyzer": "4.1.3", + "Buildalyzer": "4.1.4", "Microsoft.CodeAnalysis.CSharp.Workspaces": "4.1.0", "Microsoft.CodeAnalysis.VisualBasic.Workspaces": "4.1.0" } }, "Codelyzer.Analysis": { "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "DxE+I7g3fcVRFmdIRQ78dOPso8BYUtvYSrGF0/7wak1iitGLLaColSqoRfQEGeM5//77jWP/qAxKwBHsKEVKBg==", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "g15preRlEQ6TrQUYjd9kQ1zM5xcmTKplvAoNqnPq5HMbp71Bf3vZlKFSM9tYzbxi+QkmcuEBhN3WpNoWOuPKQQ==", "dependencies": { - "Codelyzer.Analysis.Build": "2.3.45", - "Codelyzer.Analysis.CSharp": "2.3.45", + "Codelyzer.Analysis.Build": "2.4.39-alpha-gea125ae8dd", + "Codelyzer.Analysis.CSharp": "2.4.39-alpha-gea125ae8dd", + "Codelyzer.Analysis.VisualBasic": "2.4.39-alpha-gea125ae8dd", "CommandLineParser": "2.8.0", + "Microsoft.Build.Utilities.Core": "17.1.0", "Microsoft.Extensions.Logging.Console": "6.0.0", - "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196" + "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", + "System.Linq.Async": "6.0.1" } }, "Codelyzer.Analysis.Build": { "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "8Bm/UBtunuhTZCg+osoAas2uYRM2VEunBQUVjOrn26+mIflgucEjvCWogEDH4UOiQKRcqhlSN/6lLlkoWuEqtw==", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "OpkZdrHs/U98muHOlzWAWbhjYzDjPae53iQ7ha6k1u3F4+Z7OZh9h8zyMTHx5A65qZ5y3ODUYjTfks5fswer0g==", "dependencies": { - "Buildalyzer": "4.1.3", - "Buildalyzer.Logger": "4.1.3", - "Buildalyzer.Workspaces": "4.1.3", - "Codelyzer.Analysis.CSharp": "2.3.45", + "Buildalyzer": "4.1.4", + "Buildalyzer.Logger": "4.1.4", + "Buildalyzer.Workspaces": "4.1.4", + "Codelyzer.Analysis.Common": "2.4.39-alpha-gea125ae8dd", "Microsoft.Extensions.Logging": "6.0.0", "NuGet.Packaging": "6.0.0" } }, "Codelyzer.Analysis.Common": { "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "mNRMSFSoVqCFnQ1GkJx1dmQ79xYjivtrGbi9TWA+F+mA1wh0AEy/folP7r5ykydEVH2sKyjBvUhjuVtNP4GzIg==", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "J9zO+CYKyNamo9t8Y42kJB8ayqFzaWHFEPEGj1eAgueAaK5T4xRtEpoH3mxHeGUAYQWoFFbf3aAuKuboByqzaA==", "dependencies": { - "Codelyzer.Analysis.Model": "2.3.45", + "Codelyzer.Analysis.Model": "2.4.39-alpha-gea125ae8dd", "Microsoft.Build": "17.0.0", "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", "Newtonsoft.Json": "13.0.1" @@ -90,24 +93,34 @@ }, "Codelyzer.Analysis.CSharp": { "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "KIwFpFTjx4vP3DeA3oObUA4/ZBTwyPpcvzNxuYrVbmWebtxk8H1Fhhi6HCMp7XRDtTClw/SOg9OJJGOBtuEo8A==", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "gWVHc/S1JCQqVdjW4qxgB3z5I3aF2isR8rvpvBtdrELIixQpgP6KqVqcW+cIi4Q9rC7LC4sStmM9L3q4rycgIw==", "dependencies": { - "Codelyzer.Analysis.Common": "2.3.45", - "Codelyzer.Analysis.Model": "2.3.45" + "Codelyzer.Analysis.Common": "2.4.39-alpha-gea125ae8dd", + "Codelyzer.Analysis.Model": "2.4.39-alpha-gea125ae8dd" } }, "Codelyzer.Analysis.Model": { "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "c5BQYmHrbMt72EJ8eG3VFLzBAoZVUM1eDBJoJRRKkif0JlkP31iEE12SeotoGuBthm5M1soDNEw2FsxWuqJcWA==", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "HD/dWPzkMcgzwXo1Y8ahT7Rkntidg7Vg31Pp///z9o3LqyJEzXM1gfHCR/kxfhWDQn0VS2VZRc+leC+VvGB7Lw==", "dependencies": { "Microsoft.CodeAnalysis": "4.1.0", "Microsoft.CodeAnalysis.CSharp": "4.1.0", + "Microsoft.CodeAnalysis.VisualBasic": "4.1.0", "Microsoft.Extensions.Logging": "6.0.0", "Newtonsoft.Json": "13.0.1" } }, + "Codelyzer.Analysis.VisualBasic": { + "type": "Transitive", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "zfqgx4ltgQ8r0yu9Q4f+9VCVL4ona9m6ARKySKkTG6sdkh5Wkf3m0oBCFnoherI7zbt62kBcnPsDCemXXRs9jw==", + "dependencies": { + "Codelyzer.Analysis.Common": "2.4.39-alpha-gea125ae8dd", + "Codelyzer.Analysis.Model": "2.4.39-alpha-gea125ae8dd" + } + }, "CommandLineParser": { "type": "Transitive", "resolved": "2.8.0", @@ -123,8 +136,8 @@ }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==" + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" }, "Microsoft.Build": { "type": "Transitive", @@ -145,9 +158,10 @@ }, "Microsoft.Build.Framework": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "XbFA0z+6Ws2pNeRXYcDF3lKlNgRoSGMm2Q5HKzZD+EbwYMKPKrl/BJnnkMuDJHU0KravYHfhzBnLLJpPeZ3E7A==", + "resolved": "17.1.0", + "contentHash": "7PPEbjuL/lKQ8ftblxwBZKf5alZCA4GDvBTiO3UAVxtRe52a2jL3mc8TpKNiJZzytGz7fKdR5ClDCs7+Uw4hMg==", "dependencies": { + "Microsoft.Win32.Registry": "4.3.0", "System.Security.Permissions": "4.7.0" } }, @@ -178,12 +192,14 @@ }, "Microsoft.Build.Utilities.Core": { "type": "Transitive", - "resolved": "16.9.0", - "contentHash": "rpxfQlBo2hkFODFJZKPYxMsl5QGIqQ6GlSYnQGKhl+Fu65cvJDk4jRi/R9i+X5/+lSeHhRlQbo+UUhg6cqMkRw==", + "resolved": "17.1.0", + "contentHash": "JqhQ4q6L4IyA0Wh3PrDrxHHYMVHyOLIusyC4imAnhcnZiOC4+CwgVRSdo8fLsQmvz0Jab8FFrU1NPZFbDoxRng==", "dependencies": { - "Microsoft.Build.Framework": "16.9.0", + "Microsoft.Build.Framework": "17.1.0", + "Microsoft.NET.StringTools": "1.0.0", "Microsoft.Win32.Registry": "4.3.0", "System.Collections.Immutable": "5.0.0", + "System.Configuration.ConfigurationManager": "4.7.0", "System.Security.Permissions": "4.7.0", "System.Text.Encoding.CodePages": "4.0.1" } @@ -1095,6 +1111,14 @@ "System.Runtime.Extensions": "4.3.0" } }, + "System.Linq.Async": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, "System.Linq.Expressions": { "type": "Transitive", "resolved": "4.3.0", @@ -1687,8 +1711,8 @@ "cta.rules.config": { "type": "Project", "dependencies": { - "Codelyzer.Analysis": "2.3.45", - "Codelyzer.Analysis.Model": "2.3.45", + "Codelyzer.Analysis": "2.4.39-alpha-gea125ae8dd", + "Codelyzer.Analysis.Model": "2.4.39-alpha-gea125ae8dd", "Microsoft.Extensions.Logging": "6.0.0", "Microsoft.Extensions.Logging.Abstractions": "6.0.0", "Microsoft.Extensions.Logging.Console": "6.0.0", diff --git a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs index b4847581..0dcf1334 100644 --- a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs @@ -11,11 +11,11 @@ using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using AttributeAction = CTA.Rules.Models.Actions.VisualBasic.AttributeAction; -using ElementAccessAction = CTA.Rules.Models.VisualBasic.ElementAccessAction; +using ElementAccessAction = CTA.Rules.Models.Actions.VisualBasic.ElementAccessAction; using ElementAccessToken = CTA.Rules.Models.Tokens.VisualBasic.ElementAccessToken; using IdentifierNameToken = CTA.Rules.Models.VisualBasic.IdentifierNameToken; using MemberAccessToken = CTA.Rules.Models.Tokens.VisualBasic.MemberAccessToken; -using ObjectCreationExpressionAction = CTA.Rules.Models.VisualBasic.ObjectCreationExpressionAction; +using ObjectCreationExpressionAction = CTA.Rules.Models.Actions.VisualBasic.ObjectCreationExpressionAction; namespace CTA.Rules.Analyzer; diff --git a/src/CTA.Rules.Models/Actions/Attributeaction.cs b/src/CTA.Rules.Models/Actions/Csharp/Attributeaction.cs similarity index 100% rename from src/CTA.Rules.Models/Actions/Attributeaction.cs rename to src/CTA.Rules.Models/Actions/Csharp/Attributeaction.cs diff --git a/src/CTA.Rules.Models/Actions/Classdeclarationaction.cs b/src/CTA.Rules.Models/Actions/Csharp/Classdeclarationaction.cs similarity index 100% rename from src/CTA.Rules.Models/Actions/Classdeclarationaction.cs rename to src/CTA.Rules.Models/Actions/Csharp/Classdeclarationaction.cs diff --git a/src/CTA.Rules.Models/Actions/Elementaccessaction.cs b/src/CTA.Rules.Models/Actions/Csharp/Elementaccessaction.cs similarity index 100% rename from src/CTA.Rules.Models/Actions/Elementaccessaction.cs rename to src/CTA.Rules.Models/Actions/Csharp/Elementaccessaction.cs diff --git a/src/CTA.Rules.Models/Actions/Identifiernameaction.cs b/src/CTA.Rules.Models/Actions/Csharp/Identifiernameaction.cs similarity index 100% rename from src/CTA.Rules.Models/Actions/Identifiernameaction.cs rename to src/CTA.Rules.Models/Actions/Csharp/Identifiernameaction.cs diff --git a/src/CTA.Rules.Models/Actions/InterfaceDeclarationAction.cs b/src/CTA.Rules.Models/Actions/Csharp/InterfaceDeclarationAction.cs similarity index 100% rename from src/CTA.Rules.Models/Actions/InterfaceDeclarationAction.cs rename to src/CTA.Rules.Models/Actions/Csharp/InterfaceDeclarationAction.cs diff --git a/src/CTA.Rules.Models/Actions/MethodDeclarationAction.cs b/src/CTA.Rules.Models/Actions/Csharp/MethodDeclarationAction.cs similarity index 100% rename from src/CTA.Rules.Models/Actions/MethodDeclarationAction.cs rename to src/CTA.Rules.Models/Actions/Csharp/MethodDeclarationAction.cs diff --git a/src/CTA.Rules.Models/Actions/ObjectCreationExpressionAction.cs b/src/CTA.Rules.Models/Actions/Csharp/ObjectCreationExpressionAction.cs similarity index 100% rename from src/CTA.Rules.Models/Actions/ObjectCreationExpressionAction.cs rename to src/CTA.Rules.Models/Actions/Csharp/ObjectCreationExpressionAction.cs diff --git a/src/CTA.Rules.Models/Actions/Usingaction.cs b/src/CTA.Rules.Models/Actions/Csharp/Usingaction.cs similarity index 100% rename from src/CTA.Rules.Models/Actions/Usingaction.cs rename to src/CTA.Rules.Models/Actions/Csharp/Usingaction.cs diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/ElementAccessAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/ElementAccessAction.cs index c408bfcc..b5926265 100644 --- a/src/CTA.Rules.Models/Actions/VisualBasic/ElementAccessAction.cs +++ b/src/CTA.Rules.Models/Actions/VisualBasic/ElementAccessAction.cs @@ -1,8 +1,8 @@ using System; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; -namespace CTA.Rules.Models.VisualBasic +namespace CTA.Rules.Models.Actions.VisualBasic { public class ElementAccessAction : GenericAction { diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs index 57b639d4..2103f9b0 100644 --- a/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs +++ b/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs @@ -1,25 +1,25 @@ using System; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; -namespace CTA.Rules.Models.VisualBasic { - -public class ImportAction : GenericAction -{ - public Func ImportActionFunc { get; set; } - public Func ImportsClauseActionFunc { get; set; } +namespace CTA.Rules.Models.Actions.VisualBasic { - public override bool Equals(object obj) + public class ImportAction : GenericAction { - var action = (UsingAction)obj; - return action?.Value == Value && - (action?.UsingActionFunc.Method.Name == ImportActionFunc.Method.Name || - action?.NamespaceUsingActionFunc.Method.Name == ImportsClauseActionFunc.Method.Name); - } + public Func ImportActionFunc { get; set; } + public Func ImportsClauseActionFunc { get; set; } - public override int GetHashCode() - { - return HashCode.Combine(Value, ImportActionFunc?.Method.Name); - } -} + public override bool Equals(object obj) + { + var action = (UsingAction)obj; + return action?.Value == Value && + (action?.UsingActionFunc.Method.Name == ImportActionFunc.Method.Name || + action?.NamespaceUsingActionFunc.Method.Name == ImportsClauseActionFunc.Method.Name); + } + + public override int GetHashCode() + { + return HashCode.Combine(Value, ImportActionFunc?.Method.Name); + } + } } diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/ObjectCreationExpressionAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/ObjectCreationExpressionAction.cs index 78e3fa32..c4f1b669 100644 --- a/src/CTA.Rules.Models/Actions/VisualBasic/ObjectCreationExpressionAction.cs +++ b/src/CTA.Rules.Models/Actions/VisualBasic/ObjectCreationExpressionAction.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis.VisualBasic.Syntax; using Microsoft.CodeAnalysis.Editing; -namespace CTA.Rules.Models.VisualBasic +namespace CTA.Rules.Models.Actions.VisualBasic { public class ObjectCreationExpressionAction : GenericAction { diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/TypeBlockAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/TypeBlockAction.cs index 43460904..8cffb914 100644 --- a/src/CTA.Rules.Models/Actions/VisualBasic/TypeBlockAction.cs +++ b/src/CTA.Rules.Models/Actions/VisualBasic/TypeBlockAction.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.VisualBasic.Syntax; -namespace CTA.Rules.Models.VisualBasic +namespace CTA.Rules.Models.Actions.VisualBasic { public class TypeBlockAction : GenericAction { diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index 377da9dc..52c1c531 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -2,7 +2,6 @@ using CTA.Rules.Models.Actions.VisualBasic; using CTA.Rules.Models.Tokens; using CTA.Rules.Models.Tokens.VisualBasic; -using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.VisualBasic.Syntax; @@ -44,8 +43,8 @@ public FileActions() VbAttributeListActions = new HashSet(); VbIdentifierNameActions = new HashSet>(); VbAccessorBlockActions = new HashSet(); - VbElementAccessActions = new HashSet(); - VbObjectCreationExpressionActions = new HashSet(); + VbElementAccessActions = new HashSet(); + VbObjectCreationExpressionActions = new HashSet(); VbAttributeActions = new HashSet(); } @@ -60,10 +59,10 @@ public HashSet VbInterfaceBlockActions { get; set; } public HashSet VbAttributeListActions { get; set; } public HashSet VbAccessorBlockActions { get; set; } - public HashSet VbObjectCreationExpressionActions + public HashSet VbObjectCreationExpressionActions { get; set; } - public HashSet VbElementAccessActions { get; set; } - public HashSet VbAttributeActions { get; set; } + public HashSet VbElementAccessActions { get; set; } + public HashSet VbAttributeActions { get; set; } public List VbNodeTokens { get; set; } public List NodeTokens { get; set; } diff --git a/src/CTA.Rules.Models/Tokens/Attributetoken.cs b/src/CTA.Rules.Models/Tokens/Csharp/Attributetoken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/Attributetoken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/Attributetoken.cs diff --git a/src/CTA.Rules.Models/Tokens/Classdeclarationtoken.cs b/src/CTA.Rules.Models/Tokens/Csharp/Classdeclarationtoken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/Classdeclarationtoken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/Classdeclarationtoken.cs diff --git a/src/CTA.Rules.Models/Tokens/Elementaccesstoken.cs b/src/CTA.Rules.Models/Tokens/Csharp/Elementaccesstoken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/Elementaccesstoken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/Elementaccesstoken.cs diff --git a/src/CTA.Rules.Models/Tokens/ExpressionToken.cs b/src/CTA.Rules.Models/Tokens/Csharp/ExpressionToken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/ExpressionToken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/ExpressionToken.cs diff --git a/src/CTA.Rules.Models/Tokens/Identifiernametoken.cs b/src/CTA.Rules.Models/Tokens/Csharp/Identifiernametoken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/Identifiernametoken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/Identifiernametoken.cs diff --git a/src/CTA.Rules.Models/Tokens/InterfaceDeclarationToken.cs b/src/CTA.Rules.Models/Tokens/Csharp/InterfaceDeclarationToken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/InterfaceDeclarationToken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/InterfaceDeclarationToken.cs diff --git a/src/CTA.Rules.Models/Tokens/Invocationexpressiontoken.cs b/src/CTA.Rules.Models/Tokens/Csharp/Invocationexpressiontoken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/Invocationexpressiontoken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/Invocationexpressiontoken.cs diff --git a/src/CTA.Rules.Models/Tokens/Memberaccesstoken.cs b/src/CTA.Rules.Models/Tokens/Csharp/Memberaccesstoken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/Memberaccesstoken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/Memberaccesstoken.cs diff --git a/src/CTA.Rules.Models/Tokens/MethodDeclarationToken.cs b/src/CTA.Rules.Models/Tokens/Csharp/MethodDeclarationToken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/MethodDeclarationToken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/MethodDeclarationToken.cs diff --git a/src/CTA.Rules.Models/Tokens/NamespaceToken.cs b/src/CTA.Rules.Models/Tokens/Csharp/NamespaceToken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/NamespaceToken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/NamespaceToken.cs diff --git a/src/CTA.Rules.Models/Tokens/ObjectCreationExpressionToken.cs b/src/CTA.Rules.Models/Tokens/Csharp/ObjectCreationExpressionToken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/ObjectCreationExpressionToken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/ObjectCreationExpressionToken.cs diff --git a/src/CTA.Rules.Models/Tokens/ProjectToken.cs b/src/CTA.Rules.Models/Tokens/Csharp/ProjectToken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/ProjectToken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/ProjectToken.cs diff --git a/src/CTA.Rules.Models/Tokens/Usingdirectivetoken.cs b/src/CTA.Rules.Models/Tokens/Csharp/Usingdirectivetoken.cs similarity index 100% rename from src/CTA.Rules.Models/Tokens/Usingdirectivetoken.cs rename to src/CTA.Rules.Models/Tokens/Csharp/Usingdirectivetoken.cs diff --git a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs index 6317184f..2e80213a 100644 --- a/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs +++ b/src/CTA.Rules.Models/Tokens/VisualBasic/VisualBasicNodeToken.cs @@ -1,6 +1,5 @@ using System.Linq; using System.Collections.Generic; -using CTA.Rules.Models.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using CTA.Rules.Models.Actions.VisualBasic; @@ -19,8 +18,8 @@ public VisualBasicNodeToken() InterfaceBlockActions = new List(); VbAttributeListActions = new List(); AccessorBlockActions = new List(); - ObjectCreationExpressionActions = new List(); - ElementAccessActions = new List(); + ObjectCreationExpressionActions = new List(); + ElementAccessActions = new List(); AttributeActions = new List(); } @@ -34,8 +33,8 @@ public VisualBasicNodeToken() public List InterfaceBlockActions { get; set; } public List VbAttributeListActions { get; set; } public List AccessorBlockActions { get; set; } - public List ObjectCreationExpressionActions{ get; set; } - public List ElementAccessActions { get; set; } + public List ObjectCreationExpressionActions{ get; set; } + public List ElementAccessActions { get; set; } public List AttributeActions { get; set; } @@ -61,11 +60,11 @@ public override VisualBasicNodeToken Clone() cloned.AccessorBlockActions = cloned.AccessorBlockActions .Select(action => action.Clone()).ToList(); cloned.ObjectCreationExpressionActions = cloned.ObjectCreationExpressionActions - .Select(action => action.Clone()).ToList(); + .Select(action => action.Clone()).ToList(); cloned.ElementAccessActions = cloned.ElementAccessActions - .Select(action => action.Clone()).ToList(); + .Select(action => action.Clone()).ToList(); cloned.AttributeActions = cloned.AttributeActions - .Select(action => action.Clone()).ToList(); + .Select(action => action.Clone()).ToList(); return cloned; } diff --git a/src/CTA.Rules.Models/packages.lock.json b/src/CTA.Rules.Models/packages.lock.json index 5a3a47f3..e553d473 100644 --- a/src/CTA.Rules.Models/packages.lock.json +++ b/src/CTA.Rules.Models/packages.lock.json @@ -26,10 +26,10 @@ }, "Buildalyzer": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "25NJRnGgYBOC3OPgFDj/KeJwSldXPFZl5jDXjqP7Vsy6vC+MPapcJ687/dOjUeS4t4aVuYrMyWdaezkZgs+Rdw==", + "resolved": "4.1.4", + "contentHash": "O6KGKPeCAe+Ujhd2sl66nu7rrEAM2hBUbi3n79BVBOj9YxuUlbxviOfy3Cq22iIp9rUDPOqOL8E2AYiQwxpUHQ==", "dependencies": { - "Buildalyzer.Logger": "4.1.3", + "Buildalyzer.Logger": "4.1.4", "MSBuild.StructuredLogger": "2.1.507", "Microsoft.Build": "16.9.0", "Microsoft.Build.Framework": "16.9.0", @@ -45,50 +45,53 @@ }, "Buildalyzer.Logger": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "9qq5VfFO/cvasetqJpj+V5sc8Ng5EQjCkYi3COOvzyqNLivYIp+4Cf1ddfbcye3X3i89z9oHIEmF3iNQspFSDw==" + "resolved": "4.1.4", + "contentHash": "2C2FR877slFBYM/usMkGnmOZlLKejV0uag0IzmARkKkBD75jNPM6q2WLaFAW/yRLPyyArpunYzQ+4AaDyEImHQ==" }, "Buildalyzer.Workspaces": { "type": "Transitive", - "resolved": "4.1.3", - "contentHash": "rZGc9XTd0RzLa3tMG9HfNzhxLKGNerCzW3f+nG/Mau0ucpRENWn7OH9Nz9ZxD3k4oWweOw9kfGfw4VvbcNP43w==", + "resolved": "4.1.4", + "contentHash": "fU4I3dmFDTickARibqYYJb+uDYUxlHM32a0CQgY2dVBJKnf9DFnVkiQjxbhdxGOylHI6lTZm+EdAEqXcjIe4xg==", "dependencies": { - "Buildalyzer": "4.1.3", + "Buildalyzer": "4.1.4", "Microsoft.CodeAnalysis.CSharp.Workspaces": "4.1.0", "Microsoft.CodeAnalysis.VisualBasic.Workspaces": "4.1.0" } }, "Codelyzer.Analysis": { "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "DxE+I7g3fcVRFmdIRQ78dOPso8BYUtvYSrGF0/7wak1iitGLLaColSqoRfQEGeM5//77jWP/qAxKwBHsKEVKBg==", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "g15preRlEQ6TrQUYjd9kQ1zM5xcmTKplvAoNqnPq5HMbp71Bf3vZlKFSM9tYzbxi+QkmcuEBhN3WpNoWOuPKQQ==", "dependencies": { - "Codelyzer.Analysis.Build": "2.3.45", - "Codelyzer.Analysis.CSharp": "2.3.45", + "Codelyzer.Analysis.Build": "2.4.39-alpha-gea125ae8dd", + "Codelyzer.Analysis.CSharp": "2.4.39-alpha-gea125ae8dd", + "Codelyzer.Analysis.VisualBasic": "2.4.39-alpha-gea125ae8dd", "CommandLineParser": "2.8.0", + "Microsoft.Build.Utilities.Core": "17.1.0", "Microsoft.Extensions.Logging.Console": "6.0.0", - "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196" + "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", + "System.Linq.Async": "6.0.1" } }, "Codelyzer.Analysis.Build": { "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "8Bm/UBtunuhTZCg+osoAas2uYRM2VEunBQUVjOrn26+mIflgucEjvCWogEDH4UOiQKRcqhlSN/6lLlkoWuEqtw==", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "OpkZdrHs/U98muHOlzWAWbhjYzDjPae53iQ7ha6k1u3F4+Z7OZh9h8zyMTHx5A65qZ5y3ODUYjTfks5fswer0g==", "dependencies": { - "Buildalyzer": "4.1.3", - "Buildalyzer.Logger": "4.1.3", - "Buildalyzer.Workspaces": "4.1.3", - "Codelyzer.Analysis.CSharp": "2.3.45", + "Buildalyzer": "4.1.4", + "Buildalyzer.Logger": "4.1.4", + "Buildalyzer.Workspaces": "4.1.4", + "Codelyzer.Analysis.Common": "2.4.39-alpha-gea125ae8dd", "Microsoft.Extensions.Logging": "6.0.0", "NuGet.Packaging": "6.0.0" } }, "Codelyzer.Analysis.Common": { "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "mNRMSFSoVqCFnQ1GkJx1dmQ79xYjivtrGbi9TWA+F+mA1wh0AEy/folP7r5ykydEVH2sKyjBvUhjuVtNP4GzIg==", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "J9zO+CYKyNamo9t8Y42kJB8ayqFzaWHFEPEGj1eAgueAaK5T4xRtEpoH3mxHeGUAYQWoFFbf3aAuKuboByqzaA==", "dependencies": { - "Codelyzer.Analysis.Model": "2.3.45", + "Codelyzer.Analysis.Model": "2.4.39-alpha-gea125ae8dd", "Microsoft.Build": "17.0.0", "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", "Newtonsoft.Json": "13.0.1" @@ -96,24 +99,34 @@ }, "Codelyzer.Analysis.CSharp": { "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "KIwFpFTjx4vP3DeA3oObUA4/ZBTwyPpcvzNxuYrVbmWebtxk8H1Fhhi6HCMp7XRDtTClw/SOg9OJJGOBtuEo8A==", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "gWVHc/S1JCQqVdjW4qxgB3z5I3aF2isR8rvpvBtdrELIixQpgP6KqVqcW+cIi4Q9rC7LC4sStmM9L3q4rycgIw==", "dependencies": { - "Codelyzer.Analysis.Common": "2.3.45", - "Codelyzer.Analysis.Model": "2.3.45" + "Codelyzer.Analysis.Common": "2.4.39-alpha-gea125ae8dd", + "Codelyzer.Analysis.Model": "2.4.39-alpha-gea125ae8dd" } }, "Codelyzer.Analysis.Model": { "type": "Transitive", - "resolved": "2.3.45", - "contentHash": "c5BQYmHrbMt72EJ8eG3VFLzBAoZVUM1eDBJoJRRKkif0JlkP31iEE12SeotoGuBthm5M1soDNEw2FsxWuqJcWA==", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "HD/dWPzkMcgzwXo1Y8ahT7Rkntidg7Vg31Pp///z9o3LqyJEzXM1gfHCR/kxfhWDQn0VS2VZRc+leC+VvGB7Lw==", "dependencies": { "Microsoft.CodeAnalysis": "4.1.0", "Microsoft.CodeAnalysis.CSharp": "4.1.0", + "Microsoft.CodeAnalysis.VisualBasic": "4.1.0", "Microsoft.Extensions.Logging": "6.0.0", "Newtonsoft.Json": "13.0.1" } }, + "Codelyzer.Analysis.VisualBasic": { + "type": "Transitive", + "resolved": "2.4.39-alpha-gea125ae8dd", + "contentHash": "zfqgx4ltgQ8r0yu9Q4f+9VCVL4ona9m6ARKySKkTG6sdkh5Wkf3m0oBCFnoherI7zbt62kBcnPsDCemXXRs9jw==", + "dependencies": { + "Codelyzer.Analysis.Common": "2.4.39-alpha-gea125ae8dd", + "Codelyzer.Analysis.Model": "2.4.39-alpha-gea125ae8dd" + } + }, "CommandLineParser": { "type": "Transitive", "resolved": "2.8.0", @@ -129,8 +142,8 @@ }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==" + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" }, "Microsoft.Build": { "type": "Transitive", @@ -151,9 +164,10 @@ }, "Microsoft.Build.Framework": { "type": "Transitive", - "resolved": "17.0.0", - "contentHash": "XbFA0z+6Ws2pNeRXYcDF3lKlNgRoSGMm2Q5HKzZD+EbwYMKPKrl/BJnnkMuDJHU0KravYHfhzBnLLJpPeZ3E7A==", + "resolved": "17.1.0", + "contentHash": "7PPEbjuL/lKQ8ftblxwBZKf5alZCA4GDvBTiO3UAVxtRe52a2jL3mc8TpKNiJZzytGz7fKdR5ClDCs7+Uw4hMg==", "dependencies": { + "Microsoft.Win32.Registry": "4.3.0", "System.Security.Permissions": "4.7.0" } }, @@ -184,12 +198,14 @@ }, "Microsoft.Build.Utilities.Core": { "type": "Transitive", - "resolved": "16.9.0", - "contentHash": "rpxfQlBo2hkFODFJZKPYxMsl5QGIqQ6GlSYnQGKhl+Fu65cvJDk4jRi/R9i+X5/+lSeHhRlQbo+UUhg6cqMkRw==", + "resolved": "17.1.0", + "contentHash": "JqhQ4q6L4IyA0Wh3PrDrxHHYMVHyOLIusyC4imAnhcnZiOC4+CwgVRSdo8fLsQmvz0Jab8FFrU1NPZFbDoxRng==", "dependencies": { - "Microsoft.Build.Framework": "16.9.0", + "Microsoft.Build.Framework": "17.1.0", + "Microsoft.NET.StringTools": "1.0.0", "Microsoft.Win32.Registry": "4.3.0", "System.Collections.Immutable": "5.0.0", + "System.Configuration.ConfigurationManager": "4.7.0", "System.Security.Permissions": "4.7.0", "System.Text.Encoding.CodePages": "4.0.1" } @@ -1101,6 +1117,14 @@ "System.Runtime.Extensions": "4.3.0" } }, + "System.Linq.Async": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, "System.Linq.Expressions": { "type": "Transitive", "resolved": "4.3.0", @@ -1693,8 +1717,8 @@ "cta.rules.config": { "type": "Project", "dependencies": { - "Codelyzer.Analysis": "2.3.45", - "Codelyzer.Analysis.Model": "2.3.45", + "Codelyzer.Analysis": "2.4.39-alpha-gea125ae8dd", + "Codelyzer.Analysis.Model": "2.4.39-alpha-gea125ae8dd", "Microsoft.Extensions.Logging": "6.0.0", "Microsoft.Extensions.Logging.Abstractions": "6.0.0", "Microsoft.Extensions.Logging.Console": "6.0.0", diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs index 8424444b..4ab8a3c8 100644 --- a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -10,11 +10,11 @@ using CTA.Rules.Models.Tokens.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using AttributeToken = CTA.Rules.Models.Tokens.VisualBasic.AttributeToken; -using ElementAccessAction = CTA.Rules.Models.VisualBasic.ElementAccessAction; +using ElementAccessAction = CTA.Rules.Models.Actions.VisualBasic.ElementAccessAction; using ElementAccessToken = CTA.Rules.Models.Tokens.VisualBasic.ElementAccessToken; using IdentifierNameToken = CTA.Rules.Models.VisualBasic.IdentifierNameToken; using MemberAccessToken = CTA.Rules.Models.Tokens.VisualBasic.MemberAccessToken; -using ObjectCreationExpressionAction = CTA.Rules.Models.VisualBasic.ObjectCreationExpressionAction; +using ObjectCreationExpressionAction = CTA.Rules.Models.Actions.VisualBasic.ObjectCreationExpressionAction; namespace CTA.Rules.RuleFiles diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs index 6ce6ba0c..095108d3 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ClassActionsTests.cs @@ -7,7 +7,7 @@ using NUnit.Framework; using System.Collections.Generic; using System.Linq; -using CTA.Rules.Models.VisualBasic; +using CTA.Rules.Models.Actions.VisualBasic; namespace CTA.Rules.Test.Actions.VisualBasic { diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs index 899ed3ab..e859e8c8 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ObjectCreationExpressionActionsTests.cs @@ -1,5 +1,5 @@ using CTA.Rules.Actions.VisualBasic; -using CTA.Rules.Models.VisualBasic; +using CTA.Rules.Models.Actions.VisualBasic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; @@ -51,7 +51,7 @@ public void GetReplaceObjectWithInvocationAction_Replaces_Constructor_With_New_I [Test] public void ObjectCreationExpressionActionEquals() { - var objectCreationExpressionAction = new ObjectCreationExpressionAction() { Key = "Test", Value = "Test2", ObjectCreationExpressionGenericActionFunc = _objectCreationExpressionActions.GetReplaceObjectinitializationAction("Test") }; + var objectCreationExpressionAction = new ObjectCreationExpressionAction() {Key = "Test", Value = "Test2", ObjectCreationExpressionGenericActionFunc = _objectCreationExpressionActions.GetReplaceObjectinitializationAction("Test")}; var cloned = objectCreationExpressionAction.Clone(); Assert.True(objectCreationExpressionAction.Equals(cloned)); From 14b64f0b27fe2e5b0ade1ca98039835829b084bf Mon Sep 17 00:00:00 2001 From: Chris Long Date: Thu, 9 Jun 2022 20:21:35 -0700 Subject: [PATCH 38/61] add missing action comparison unit tests --- .../VisualBasic/AttributeActionsTests.cs | 31 +++++++++---------- .../VisualBasic/AttributeListActionsTests.cs | 30 +++++++++--------- .../VisualBasic/ElementAccessActionsTests.cs | 30 +++++++++--------- .../VisualBasic/InterfaceActionsTests.cs | 29 +++++++++-------- .../VisualBasic/MethodBlockActionsTests.cs | 31 +++++++++---------- 5 files changed, 71 insertions(+), 80 deletions(-) diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeActionsTests.cs index 9f80e34b..6856d0b3 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeActionsTests.cs @@ -1,6 +1,5 @@ -using System; -using CTA.Rules.Actions.VisualBasic; -using CTA.Rules.Models; +using CTA.Rules.Actions.VisualBasic; +using CTA.Rules.Models.Actions.VisualBasic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; @@ -40,20 +39,18 @@ public void GetChangeAttributeAction_Changes_Attribute_To_Specified_Value() [Test] public void AttributeActionComparison() { - throw new NotImplementedException(); - // - // var attributeAction = new AttributeAction() - // { - // Key = "Test", - // Value = "Test2", - // AttributeActionFunc = _attributeActions.GetChangeAttributeAction("NewAttribute") - // }; - // - // var cloned = attributeAction.Clone(); - // - // Assert.True(attributeAction.Equals(cloned)); - // cloned.Value = "DifferentValue"; - // Assert.False(attributeAction.Equals(cloned)); + var attributeAction = new AttributeAction() + { + Key = "Test", + Value = "Test2", + AttributeActionFunc = _attributeActions.GetChangeAttributeAction("NewAttribute") + }; + + var cloned = attributeAction.Clone(); + + Assert.True(attributeAction.Equals(cloned)); + cloned.Value = "DifferentValue"; + Assert.False(attributeAction.Equals(cloned)); } } } \ No newline at end of file diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeListActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeListActionsTests.cs index 137652ea..18782439 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeListActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/AttributeListActionsTests.cs @@ -1,6 +1,5 @@ -using System; -using CTA.Rules.Actions.VisualBasic; -using CTA.Rules.Models; +using CTA.Rules.Actions.VisualBasic; +using CTA.Rules.Models.Actions.VisualBasic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; @@ -40,19 +39,18 @@ public void AttributeListAddComment() [Test] public void AttributeListActionComparison() { - throw new NotImplementedException(); - // var attributeAction = new AttributeAction() - // { - // Key = "Test", - // Value = "Test2", - // AttributeListActionFunc = _attributeListActions.GetAddCommentAction("NewAttribute") - // }; - // - // var cloned = attributeAction.Clone(); - // - // Assert.True(attributeAction.Equals(cloned)); - // cloned.Value = "DifferentValue"; - // Assert.False(attributeAction.Equals(cloned)); + var attributeAction = new AttributeAction() + { + Key = "Test", + Value = "Test2", + AttributeListActionFunc = _attributeListActions.GetAddCommentAction("NewAttribute") + }; + + var cloned = attributeAction.Clone(); + + Assert.True(attributeAction.Equals(cloned)); + cloned.Value = "DifferentValue"; + Assert.False(attributeAction.Equals(cloned)); } } } \ No newline at end of file diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/ElementAccessActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/ElementAccessActionsTests.cs index 4780c716..6070793c 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/ElementAccessActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/ElementAccessActionsTests.cs @@ -1,5 +1,4 @@ -using System; -using CTA.Rules.Models; +using CTA.Rules.Models.Actions.VisualBasic; using CTA.Rules.Update.VisualBasic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic; @@ -48,20 +47,19 @@ public void ReplaceElementAccess() [Test] public void ElementAccessActionComparison() { - throw new NotImplementedException(); - // var elementAccessAction = new ElementAccessAction() - // { - // Key = "Test", - // Value = "Test2", - // ElementAccessExpressionActionFunc = _elementAccessActions.GetAddCommentAction("Test") - // - // }; - // - // var cloned = elementAccessAction.Clone(); - // - // Assert.True(elementAccessAction.Equals(cloned)); - // cloned.Value = "DifferentValue"; - // Assert.False(elementAccessAction.Equals(cloned)); + var elementAccessAction = new ElementAccessAction() + { + Key = "Test", + Value = "Test2", + ElementAccessExpressionActionFunc = _elementAccessActions.GetAddCommentAction("Test") + + }; + + var cloned = elementAccessAction.Clone(); + + Assert.True(elementAccessAction.Equals(cloned)); + cloned.Value = "DifferentValue"; + Assert.False(elementAccessAction.Equals(cloned)); } } } \ No newline at end of file diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/InterfaceActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/InterfaceActionsTests.cs index 2efe625f..a9881bef 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/InterfaceActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/InterfaceActionsTests.cs @@ -1,6 +1,5 @@ -using System; -using CTA.Rules.Actions.VisualBasic; -using CTA.Rules.Models; +using CTA.Rules.Actions.VisualBasic; +using CTA.Rules.Models.Actions.VisualBasic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using Microsoft.CodeAnalysis.Editing; @@ -87,19 +86,19 @@ public void AddAndRemoveMethod() } [Test] - public void InterfaceDeclarationEquals() + public void InterfaceBlockEquals() { - throw new NotImplementedException(); - // var interfaceAction = new InterfaceDeclarationAction - // { - // Key = "Test", Value = "Test2", - // InterfaceDeclarationActionFunc = _interfaceActions.GetAddAttributeAction("Test") - // }; - // var cloned = interfaceAction.Clone(); - // Assert.True(interfaceAction.Equals(cloned)); - // - // cloned.Value = "DifferentValue"; - // Assert.False(interfaceAction.Equals(cloned)); + var interfaceAction = new InterfaceBlockAction() + { + Key = "Test", + Value = "Test2", + InterfaceBlockActionFunc = _interfaceActions.GetAddAttributeAction("Test") + }; + var cloned = interfaceAction.Clone(); + Assert.True(interfaceAction.Equals(cloned)); + + cloned.Value = "DifferentValue"; + Assert.False(interfaceAction.Equals(cloned)); } } } \ No newline at end of file diff --git a/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs b/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs index 1c7b4220..9f7ca5f4 100644 --- a/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs +++ b/tst/CTA.Rules.Test/Actions/VisualBasic/MethodBlockActionsTests.cs @@ -1,11 +1,11 @@ -using System; -using CTA.Rules.Actions.VisualBasic; +using CTA.Rules.Actions.VisualBasic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using Microsoft.CodeAnalysis.Editing; using NUnit.Framework; using System.Collections.Generic; +using CTA.Rules.Models.Actions.VisualBasic; namespace CTA.Rules.Test.Actions.VisualBasic { @@ -66,21 +66,20 @@ public void MethodDeclarationAddExpression() } [Test] - public void MethodDeclarationActionComparison() + public void MethodBlockActionComparison() { - throw new NotImplementedException(); - // var methodDeclarationAction = new MethodDeclarationAction() - // { - // Key = "Test", - // Value = "Test2", - // MethodDeclarationActionFunc = _methodDeclarationActions.GetAddCommentAction("NewAttribute") - // }; - // - // var cloned = methodDeclarationAction.Clone(); - // - // Assert.True(methodDeclarationAction.Equals(cloned)); - // cloned.Value = "DifferentValue"; - // Assert.False(methodDeclarationAction.Equals(cloned)); + var methodDeclarationAction = new MethodBlockAction() + { + Key = "Test", + Value = "Test2", + MethodBlockActionFunc = _methodBlockActions.GetAddCommentAction("NewAttribute") + }; + + var cloned = methodDeclarationAction.Clone(); + + Assert.True(methodDeclarationAction.Equals(cloned)); + cloned.Value = "DifferentValue"; + Assert.False(methodDeclarationAction.Equals(cloned)); } [Test] From b3a072ab679335b3ac10076e5cdff2ad1e5fc06d Mon Sep 17 00:00:00 2001 From: Chris Long Date: Thu, 9 Jun 2022 20:27:48 -0700 Subject: [PATCH 39/61] fix missing actions in file actions model also remove extra member access actions added to all actions --- src/CTA.Rules.Models/FileActions/FileActions.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/CTA.Rules.Models/FileActions/FileActions.cs b/src/CTA.Rules.Models/FileActions/FileActions.cs index 52c1c531..d438f6e9 100644 --- a/src/CTA.Rules.Models/FileActions/FileActions.cs +++ b/src/CTA.Rules.Models/FileActions/FileActions.cs @@ -86,16 +86,19 @@ public List AllActions get { var allActions = new List(); + allActions.AddRange(AttributeActions); + allActions.AddRange(MethodDeclarationActions); allActions.AddRange(ClassDeclarationActions); + allActions.AddRange(InterfaceDeclarationActions); + allActions.AddRange(ElementAccessActions); allActions.AddRange(MemberAccessActions); allActions.AddRange(IdentifierNameActions); allActions.AddRange(InvocationExpressionActions); allActions.AddRange(ExpressionActions); - allActions.AddRange(MemberAccessActions); allActions.AddRange(Usingactions); allActions.AddRange(ObjectCreationExpressionActions); allActions.AddRange(NamespaceActions); - + // visual basic actions allActions.AddRange(VbImportActions); allActions.AddRange(VbNamespaceActions); From eaef56d37ec8f3a60fe5160e255b0cd9b15d40d6 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Thu, 9 Jun 2022 20:28:43 -0700 Subject: [PATCH 40/61] add actions to vb rewriter add remaining action executions to vb rewriter class --- .../VisualBasicActionsRewriter.cs | 84 +++++++++++-------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs index 1ce42789..b384074a 100644 --- a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs +++ b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs @@ -1,29 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; -using Codelyzer.Analysis.CSharp; +using Codelyzer.Analysis.VisualBasic; using CTA.Rules.Config; using CTA.Rules.Models; -using CTA.Rules.Models.VisualBasic; +using CTA.Rules.Models.Actions.VisualBasic; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using AttributeListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeListSyntax; -using AttributeSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeSyntax; -using CastExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.CastExpressionSyntax; -using CompilationUnitSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.CompilationUnitSyntax; -using ExpressionStatementSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionStatementSyntax; -using ExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax; -using IdentifierNameSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.IdentifierNameSyntax; -using InvocationExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.InvocationExpressionSyntax; -using MemberAccessExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.MemberAccessExpressionSyntax; -using ObjectCreationExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ObjectCreationExpressionSyntax; -using ParameterSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ParameterSyntax; -using QualifiedNameSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.QualifiedNameSyntax; -using TypeArgumentListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeArgumentListSyntax; -using TypeParameterListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeParameterListSyntax; +using GenericAction = CTA.Rules.Models.GenericAction; +using GenericActionExecution = CTA.Rules.Models.GenericActionExecution; +using ActionExecutionException = CTA.Rules.Models.ActionExecutionException; +using AttributeAction = CTA.Rules.Models.Actions.VisualBasic.AttributeAction; namespace CTA.Rules.Update; @@ -40,10 +29,10 @@ public class VisualBasicActionsRewriter : VisualBasicSyntaxRewriter, ISyntaxRewr private static readonly Type[] identifierNameTypes = new Type[] { - typeof(MethodDeclarationSyntax), - typeof(ConstructorDeclarationSyntax), - typeof(ClassDeclarationSyntax), - typeof(VariableDeclarationSyntax), + typeof(MethodBlockSyntax), + typeof(ConstructorBlockSyntax), + typeof(TypeBlockSyntax), + typeof(VariableDeclaratorSyntax), typeof(TypeArgumentListSyntax), typeof(TypeParameterListSyntax), typeof(ParameterSyntax), @@ -89,8 +78,7 @@ public override SyntaxNode VisitAttributeList(AttributeListSyntax node) var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; try { - //todo: attributeslistfunc - //attributeListSyntax = action.AttributeListActionFunc(_syntaxGenerator, attributeListSyntax); + attributeListSyntax = action.AttributeListActionFunc(_syntaxGenerator, attributeListSyntax); LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); } catch (Exception ex) @@ -122,8 +110,7 @@ public override SyntaxNode VisitAttribute(AttributeSyntax node) var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; try { - //todo: attributesactionfunc - //attributeSyntax = action.AttributeActionFunc(_syntaxGenerator, attributeSyntax); + attributeSyntax = action.AttributeActionFunc(_syntaxGenerator, attributeSyntax); LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); } catch (Exception ex) @@ -141,6 +128,35 @@ public override SyntaxNode VisitAttribute(AttributeSyntax node) return attributeSyntax; } + public override SyntaxNode VisitModuleBlock(ModuleBlockSyntax node) + { + var moduleSymbol = SemanticHelper.GetDeclaredSymbol(node, _semanticModel, _preportSemanticModel); + var newNode = (ModuleBlockSyntax)base.VisitModuleBlock(node); + + foreach (var action in _allActions.OfType()) + { + if (action.Key == node.ModuleStatement.Identifier.Text.Trim()) + { + var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; + try + { + newNode = (ModuleBlockSyntax)action.TypeBlockActionFunc(_syntaxGenerator, newNode); + LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); + } + catch (Exception ex) + { + var actionExecutionException = new ActionExecutionException(action.Name, action.Key, ex); + actionExecution.InvalidExecutions = 1; + LogHelper.LogError(actionExecutionException); + } + + AllExecutedActions.Add(actionExecution); + } + } + + return newNode; + } + public override SyntaxNode VisitClassBlock(ClassBlockSyntax node) { var classSymbol = SemanticHelper.GetDeclaredSymbol(node, _semanticModel, _preportSemanticModel); @@ -169,20 +185,20 @@ public override SyntaxNode VisitClassBlock(ClassBlockSyntax node) return newNode; } - + public override SyntaxNode VisitInterfaceBlock(InterfaceBlockSyntax node) { var classSymbol = SemanticHelper.GetDeclaredSymbol(node, _semanticModel, _preportSemanticModel); - InterfaceDeclarationSyntax newNode = (InterfaceDeclarationSyntax)base.VisitInterfaceBlock(node); + InterfaceBlockSyntax newNode = (InterfaceBlockSyntax)base.VisitInterfaceBlock(node); - foreach (var action in _allActions.OfType()) + foreach (var action in _allActions.OfType()) { if (action.Key == node.InterfaceStatement.Identifier.Text.Trim()) { var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; try { - newNode = action.InterfaceDeclarationActionFunc(_syntaxGenerator, newNode); + newNode = action.InterfaceBlockActionFunc(_syntaxGenerator, newNode); LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); } catch (Exception ex) @@ -214,8 +230,7 @@ public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) var actionExecution = new GenericActionExecution(action, _filePath) { TimesRun = 1 }; try { - //todo: identifiernamefunc - //identifierNameSyntax = action.IdentifierNameActionFunc(_syntaxGenerator, identifierNameSyntax); + identifierNameSyntax = action.IdentifierNameActionFunc(_syntaxGenerator, identifierNameSyntax); LogHelper.LogInformation(string.Format("{0}: {1}", node.SpanStart, action.Description)); } catch (Exception ex) @@ -381,7 +396,7 @@ public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressio var skipChildren = false; // This is here to skip actions on children node when the main identifier was changed. Just use new expression for the subsequent children actions. - foreach (var action in _allActions.OfType()) + foreach (var action in _allActions.OfType()) { if (newNode.ToString() == action.Key || symbol?.OriginalDefinition.ToDisplayString() == action.Key) { @@ -389,9 +404,8 @@ public override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressio try { skipChildren = true; - //todo: objectcreationexpressionsyntaxfunc - //newNode = action.ObjectCreationExpressionGenericActionFunc(_syntaxGenerator, - //(ObjectCreationExpressionSyntax)newNode); + newNode = action.ObjectCreationExpressionGenericActionFunc(_syntaxGenerator, + (ObjectCreationExpressionSyntax)newNode); AllExecutedActions.Add(actionExecution); LogHelper.LogInformation(string.Format("{0}", action.Description)); } From fe16e0a9c56a942d3566701e97b6e02ef4329c89 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Thu, 9 Jun 2022 21:18:52 -0700 Subject: [PATCH 41/61] fix identifier name action remove copy function that wasn't working --- src/CTA.Rules.Analysis/RulesAnalysis.cs | 12 +++++++++++- src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/CTA.Rules.Analysis/RulesAnalysis.cs b/src/CTA.Rules.Analysis/RulesAnalysis.cs index d1a5293d..3c3592ac 100644 --- a/src/CTA.Rules.Analysis/RulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/RulesAnalysis.cs @@ -465,7 +465,17 @@ private void AddActions(FileActions fileAction, CsharpNodeToken token, TextSpan AttributeListActionFunc = a.AttributeListActionFunc }).ToList()); - fileAction.IdentifierNameActions.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); + fileAction.IdentifierNameActions.UnionWith(token.IdentifierNameActions.Select(a => new IdentifierNameAction() + { + Key = a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + IdentifierNameActionFunc = a.IdentifierNameActionFunc, + }).ToList()); fileAction.InvocationExpressionActions.UnionWith(token.InvocationExpressionActions.Select(a => new InvocationExpressionAction() { diff --git a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs index 0dcf1334..315a89a5 100644 --- a/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/VisualBasicRulesAnalysis.cs @@ -594,8 +594,18 @@ private void AddActions(FileActions fileAction, VisualBasicNodeToken token, Text NamespaceActionFunc = a.NamespaceActionFunc }).ToList()); - fileAction.VbIdentifierNameActions.UnionWith(token.IdentifierNameActions.Select(a => a.Copy()).ToList()); - + fileAction.VbIdentifierNameActions.UnionWith(token.IdentifierNameActions.Select(a => new IdentifierNameAction() + { + Key = a.Key, + Description = a.Description, + Value = a.Value, + Name = a.Name, + Type = a.Type, + TextSpan = textSpan, + ActionValidation = a.ActionValidation, + IdentifierNameActionFunc = a.IdentifierNameActionFunc, + }).ToList()); + fileAction.VbAttributeActions.UnionWith(token.AttributeActions.Select(a => new AttributeAction() { Key = a.Key, From 425847350fd436e8b20256ad94209ce0d6776881 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Thu, 9 Jun 2022 21:19:25 -0700 Subject: [PATCH 42/61] fix folder update test include missing vb template file constants --- src/CTA.Rules.Config/Constants.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CTA.Rules.Config/Constants.cs b/src/CTA.Rules.Config/Constants.cs index 95e8da0b..eb85ecad 100644 --- a/src/CTA.Rules.Config/Constants.cs +++ b/src/CTA.Rules.Config/Constants.cs @@ -172,7 +172,9 @@ public class Constants new List {"wcfcodebasedservice","Startup.cs"}, new List {"wcfconfigbasedservice","Program.cs"}, new List {"wcfconfigbasedservice","Startup.cs"}, - new List {"webforms","appsettings.json"} + new List {"webforms","appsettings.json"}, + new List {"webapi", "Program.vb"}, + new List {"webapi", "Startup.vb"} }; public const string WCFErrorTag = "WCF Porting Error: "; From 29b019c5a3cb8324474d3d2cc04ec759c95c5e6d Mon Sep 17 00:00:00 2001 From: Chris Long Date: Fri, 17 Jun 2022 08:41:52 -0700 Subject: [PATCH 43/61] fix: incorrect cast for import action model --- src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs b/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs index 2103f9b0..452e8f59 100644 --- a/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs +++ b/src/CTA.Rules.Models/Actions/VisualBasic/ImportAction.cs @@ -11,10 +11,10 @@ public class ImportAction : GenericAction public override bool Equals(object obj) { - var action = (UsingAction)obj; + var action = (ImportAction)obj; return action?.Value == Value && - (action?.UsingActionFunc.Method.Name == ImportActionFunc.Method.Name || - action?.NamespaceUsingActionFunc.Method.Name == ImportsClauseActionFunc.Method.Name); + (action?.ImportActionFunc.Method.Name == ImportActionFunc.Method.Name || + action?.ImportsClauseActionFunc.Method.Name == ImportsClauseActionFunc.Method.Name); } public override int GetHashCode() From 9f3d4d18d4c13172f73bebca515dd8e3653c453f Mon Sep 17 00:00:00 2001 From: Chris Long Date: Fri, 17 Jun 2022 08:45:17 -0700 Subject: [PATCH 44/61] fix: skipped as clause identifier during rewriter also add package action to vb rule file parser --- .../VisualBasicRulesFileParser.cs | 37 +++++++++++++++---- .../VisualBasicActionsRewriter.cs | 3 +- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs index 4ab8a3c8..2025d399 100644 --- a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -9,6 +9,7 @@ using CTA.Rules.Models.VisualBasic; using CTA.Rules.Models.Tokens.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Newtonsoft.Json; using AttributeToken = CTA.Rules.Models.Tokens.VisualBasic.AttributeToken; using ElementAccessAction = CTA.Rules.Models.Actions.VisualBasic.ElementAccessAction; using ElementAccessToken = CTA.Rules.Models.Tokens.VisualBasic.ElementAccessToken; @@ -634,11 +635,8 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Using: { - var actionFunc = _actionsLoader.GetCompilationUnitAction(action.Name, value); - // Using directives can be found in both ComplilationUnit and inside Namespace. - // Need to make sure remove action is taken if it's inside Namespace block. - // Only add using directives in the CompilationUnit as our convention, so it's not added twice. - var namespaceActionFunc = _actionsLoader.GetNamespaceActions(action.Name, value); + var actionName = action.Name.Replace("Directive", "Statement"); + var actionFunc = _actionsLoader.GetCompilationUnitAction(actionName, value); if (actionFunc != null) { visualBasicNodeToken.ImportActions.Add(new ImportAction() @@ -649,8 +647,7 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List ActionValidation = validation, Name = vbActionName, Type = action.Type, - ImportActionFunc = actionFunc, - ImportsClauseActionFunc = namespaceActionFunc + ImportActionFunc = actionFunc }); } break; @@ -855,6 +852,32 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List } case ActionTypes.Package: { + PackageAction packageAction = new PackageAction(); + + if (action.Value is string) + { + packageAction.Name = action.Value; + } + else + { + Dictionary jsonParameters = JsonConvert.DeserializeObject>(action.Value.ToString()); + if (jsonParameters.ContainsKey(CTA.Rules.Config.Constants.PackageName)) + { + packageAction.Name = jsonParameters[CTA.Rules.Config.Constants.PackageName]; + } + else + { + LogHelper.LogDebug( + $"Parameter {Config.Constants.PackageName} is not available for action {action.Name}"); + continue; + } + + if (jsonParameters.ContainsKey(CTA.Rules.Config.Constants.PackageVersion)) + { + packageAction.Version = jsonParameters[CTA.Rules.Config.Constants.PackageVersion]; + } + } + visualBasicNodeToken.PackageActions.Add(packageAction); break; } } diff --git a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs index b384074a..2832dd6d 100644 --- a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs +++ b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs @@ -38,7 +38,8 @@ public class VisualBasicActionsRewriter : VisualBasicSyntaxRewriter, ISyntaxRewr typeof(ParameterSyntax), typeof(ObjectCreationExpressionSyntax), typeof(QualifiedNameSyntax), - typeof(CastExpressionSyntax) + typeof(CastExpressionSyntax), + typeof(SimpleAsClauseSyntax) }; public VisualBasicActionsRewriter(SemanticModel semanticModel, SemanticModel preportSemanticModel, From 156d27c2a44e8574297628880f628c99e1211d6a Mon Sep 17 00:00:00 2001 From: Chris Long Date: Fri, 17 Jun 2022 09:52:13 -0700 Subject: [PATCH 45/61] fix: udpate vb action rewriter to match method key to codelyzer --- src/CTA.Rules.Update/VisualBasicActionsRewriter.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs index 2832dd6d..340e2fc3 100644 --- a/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs +++ b/src/CTA.Rules.Update/VisualBasicActionsRewriter.cs @@ -296,7 +296,7 @@ public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax no public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node) { - var symbol = SemanticHelper.GetSemanticSymbol(node, _semanticModel, _preportSemanticModel); + var symbol = (IMethodSymbol)SemanticHelper.GetSemanticSymbol(node, _semanticModel, _preportSemanticModel); var newNode = base.VisitInvocationExpression(node); if (symbol == null) @@ -304,7 +304,8 @@ public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax return node; } - var nodeKey = symbol.OriginalDefinition.ToString(); + var prefix = symbol.IsExtensionMethod ? symbol.ReceiverType?.ToString() ?? "" : symbol.ContainingType?.ToString() ?? ""; + var nodeKey = $"{prefix}.{symbol.Name}({string.Join(", ", symbol.Parameters.Select(p => p.Type))})"; foreach (var action in _allActions.OfType>()) { From bfc8884e3715f4c7b014a97097eb57eab502e128 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Fri, 17 Jun 2022 09:54:56 -0700 Subject: [PATCH 46/61] test: add test vb owin case --- tst/CTA.Rules.Test/AwsRulesBaseTest.cs | 2 +- tst/CTA.Rules.Test/VisualBasicTests.cs | 120 +++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 tst/CTA.Rules.Test/VisualBasicTests.cs diff --git a/tst/CTA.Rules.Test/AwsRulesBaseTest.cs b/tst/CTA.Rules.Test/AwsRulesBaseTest.cs index 43486b3d..16a0208d 100644 --- a/tst/CTA.Rules.Test/AwsRulesBaseTest.cs +++ b/tst/CTA.Rules.Test/AwsRulesBaseTest.cs @@ -202,7 +202,7 @@ internal TestSolutionAnalysis GenerateSolutionResult(string solutionPath, Soluti return result; } - private void CopyTestRules() + protected void CopyTestRules() { // Project configured to copy TempRules folder to output directory // so no extra action necessary here diff --git a/tst/CTA.Rules.Test/VisualBasicTests.cs b/tst/CTA.Rules.Test/VisualBasicTests.cs new file mode 100644 index 00000000..2fcad5ac --- /dev/null +++ b/tst/CTA.Rules.Test/VisualBasicTests.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Codelyzer.Analysis; +using CTA.Rules.Config; +using CTA.Rules.Models; +using CTA.Rules.Update; +using NUnit.Framework; + +namespace CTA.Rules.Test +{ + internal class VisualBasicTests : AwsRulesBaseTest + { + public string downloadLocation; + public List ctaFiles; + public string version = "net5.0"; //We don't care about version for CTA-only rules: + + [SetUp] + public void Setup() + { + downloadLocation = SetupTests.DownloadLocation; + ctaFiles = Directory.EnumerateFiles(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "CTAFiles")), "*.json") + .Select(s => Path.GetFileNameWithoutExtension(s)) + .ToList(); + } + + private TestSolutionAnalysis runCTAFile(string solutionName, string projectName = null) + { + var solutionPath = CopySolutionFolderToTemp(solutionName, downloadLocation); + var solutionDir = Directory.GetParent(solutionPath).FullName; + + FileAssert.Exists(solutionPath); + + //Sample Web API has only one project: + string projectFile = (projectName == null ? Utils.GetProjectPaths(Path.Combine(solutionDir, solutionName)).FirstOrDefault() : Directory.EnumerateFiles(solutionDir, projectName, SearchOption.AllDirectories).FirstOrDefault()); + FileAssert.Exists(projectFile); + + ProjectConfiguration projectConfiguration = new ProjectConfiguration() + { + SolutionPath = solutionPath, + ProjectPath = projectFile, + TargetVersions = new List { version }, + RulesDir = Constants.RulesDefaultPath, + AdditionalReferences = ctaFiles + }; + + List solutionConfiguration = new List + { + projectConfiguration + }; + CopyTestRules(); + + SolutionRewriter solutionRewriter = new SolutionRewriter(solutionPath, solutionConfiguration, language: LanguageOptions.Vb); + var analysisRunResult = solutionRewriter.AnalysisRun(); + StringBuilder str = new StringBuilder(); + foreach (var projectResult in analysisRunResult.ProjectResults) + { + str.AppendLine(projectResult.ProjectFile); + str.AppendLine(projectResult.ProjectActions.ToString()); + } + var analysisResult = str.ToString(); + solutionRewriter.Run(analysisRunResult.ProjectResults.ToDictionary(p => p.ProjectFile, p => p.ProjectActions)); + + TestSolutionAnalysis result = new TestSolutionAnalysis() + { + SolutionAnalysisResult = analysisResult, + ProjectResults = new List() + { + new ProjectResult() + { + ProjectAnalysisResult = analysisResult, + CsProjectPath = projectFile, + ProjectDirectory = Directory.GetParent(projectFile).FullName, + CsProjectContent = File.ReadAllText(projectFile) + } + } + }; + + return result; + } + + [Test] + public void TestOwinParadiseVb() + { + var slnResults = runCTAFile("OwinParadiseVb.sln"); + var projresults = slnResults.ProjectResults.FirstOrDefault(); + Assert.IsTrue(projresults != null); + + StringAssert.Contains("Microsoft.AspNetCore.Hosting", projresults.ProjectAnalysisResult); + + var signalR = File.ReadAllText(Path.Combine(projresults.ProjectDirectory, "SignalR.vb")); + var startUp = File.ReadAllText(Path.Combine(projresults.ProjectDirectory, "Startup.vb")); + + //Check that namespace has been added + StringAssert.Contains(@"Microsoft.AspNetCore.Owin", startUp); + StringAssert.DoesNotContain("Imports Owin", startUp); + StringAssert.Contains("Imports Microsoft.AspNetCore.Hosting", signalR); + StringAssert.DoesNotContain("Imports Microsoft.Owin.Hosting", signalR); + + //Check identifier actions + StringAssert.Contains("IApplicationBuilder", startUp); + StringAssert.DoesNotContain("IAppBuilder", startUp); + StringAssert.Contains("IApplicationBuilder", signalR); + StringAssert.DoesNotContain("IAppBuilder", signalR); + + //Check method actions + StringAssert.Contains("UseEndpoints", signalR); + } + + public void TestVbNetMvc() + { + var results = runCTAFile("VBNetMvc.sln").ProjectResults.FirstOrDefault(); + // Check that nothing is ported. + } + } +} From 5ea73569b0b984cf4c40bd394f88f4c8c1b5841a Mon Sep 17 00:00:00 2001 From: Chris Long Date: Fri, 17 Jun 2022 10:13:43 -0700 Subject: [PATCH 47/61] fix: get references from imports as well as usings --- src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs index c989a41e..c726db49 100644 --- a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs +++ b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs @@ -91,6 +91,7 @@ public ProjectResult Initialize() { var allReferences = _sourceFileResults?.SelectMany(s => s.References) .Union(_sourceFileResults.SelectMany(s => s.Children.OfType())?.Select(u => new Reference() { Namespace = u.Identifier, Assembly = u.Identifier }).Distinct()) + .Union(_sourceFileResults.SelectMany(s => s.Children.OfType())?.Select(u => new Reference() {Namespace = u.Identifier, Assembly = u.Identifier }).Distinct()) .Union(ProjectConfiguration.AdditionalReferences.Select(r => new Reference { Assembly = r, Namespace = r })); RulesFileLoader rulesFileLoader = new RulesFileLoader(allReferences, ProjectConfiguration.RulesDir, ProjectConfiguration.TargetVersions, _projectLanguage, string.Empty, ProjectConfiguration.AssemblyDir); From cb5b3f3ea156ce6c309f0f48003a7d7aa91df6de Mon Sep 17 00:00:00 2001 From: Chris Long Date: Fri, 17 Jun 2022 10:14:01 -0700 Subject: [PATCH 48/61] fix: remove old parameter --- tst/CTA.Rules.Test/VisualBasicTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tst/CTA.Rules.Test/VisualBasicTests.cs b/tst/CTA.Rules.Test/VisualBasicTests.cs index 2fcad5ac..9b574e97 100644 --- a/tst/CTA.Rules.Test/VisualBasicTests.cs +++ b/tst/CTA.Rules.Test/VisualBasicTests.cs @@ -54,7 +54,7 @@ private TestSolutionAnalysis runCTAFile(string solutionName, string projectName }; CopyTestRules(); - SolutionRewriter solutionRewriter = new SolutionRewriter(solutionPath, solutionConfiguration, language: LanguageOptions.Vb); + SolutionRewriter solutionRewriter = new SolutionRewriter(solutionPath, solutionConfiguration); var analysisRunResult = solutionRewriter.AnalysisRun(); StringBuilder str = new StringBuilder(); foreach (var projectResult in analysisRunResult.ProjectResults) From 1b8356aba90919f7eab71999bdb80427bdce0dc9 Mon Sep 17 00:00:00 2001 From: Sai Kiran Akula Date: Mon, 20 Jun 2022 13:01:36 -0700 Subject: [PATCH 49/61] fix: exclude porting of unsupported projects --- .../PortCoreProjectRewriterFactory.cs | 8 ++ .../VisualBasicProjectRewriter.cs | 79 +++++++++++++++++++ .../ProjectRewriters/WCFProjectRewriter.cs | 4 +- 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/VisualBasicProjectRewriter.cs diff --git a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/PortCoreProjectRewriterFactory.cs b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/PortCoreProjectRewriterFactory.cs index 00985b69..60ea8366 100644 --- a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/PortCoreProjectRewriterFactory.cs +++ b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/PortCoreProjectRewriterFactory.cs @@ -14,6 +14,10 @@ public ProjectRewriter GetInstance(AnalyzerResult analyzerResult, ProjectConfigu { ProjectType.WCFCodeBasedService => new WCFProjectRewriter(analyzerResult, projectConfiguration), ProjectType.WCFConfigBasedService => new WCFProjectRewriter(analyzerResult, projectConfiguration), + ProjectType.VBClassLibrary => new VisualBasicProjectRewriter(analyzerResult, projectConfiguration), + ProjectType.VBWebApi => new VisualBasicProjectRewriter(analyzerResult, projectConfiguration), + ProjectType.VBWebForms => new VisualBasicProjectRewriter(analyzerResult, projectConfiguration), + ProjectType.VBNetMvc => new VisualBasicProjectRewriter(analyzerResult, projectConfiguration), _ => new ProjectRewriter(analyzerResult, projectConfiguration) }; return projectRewriter; @@ -26,6 +30,10 @@ public ProjectRewriter GetInstance(IDEProjectResult ideProjectResult, ProjectCon { ProjectType.WCFCodeBasedService => new WCFProjectRewriter(ideProjectResult, projectConfiguration), ProjectType.WCFConfigBasedService => new WCFProjectRewriter(ideProjectResult, projectConfiguration), + ProjectType.VBClassLibrary => new VisualBasicProjectRewriter(ideProjectResult, projectConfiguration), + ProjectType.VBWebApi => new VisualBasicProjectRewriter(ideProjectResult, projectConfiguration), + ProjectType.VBWebForms => new VisualBasicProjectRewriter(ideProjectResult, projectConfiguration), + ProjectType.VBNetMvc => new VisualBasicProjectRewriter(ideProjectResult, projectConfiguration), _ => new ProjectRewriter(ideProjectResult, projectConfiguration) }; return projectRewriter; diff --git a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/VisualBasicProjectRewriter.cs b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/VisualBasicProjectRewriter.cs new file mode 100644 index 00000000..fe60429c --- /dev/null +++ b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/VisualBasicProjectRewriter.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using Codelyzer.Analysis; +using Codelyzer.Analysis.Build; +using CTA.Rules.Models; +using CTA.Rules.Update; + +namespace CTA.Rules.PortCore +{ + public class VisualBasicProjectRewriter : ProjectRewriter + { + public readonly ProjectType _projectType; + + /// + /// Initializes a new instance of ProjectRewriter using an existing analysis + /// + /// The analysis results of the project + /// ProjectConfiguration for this project + public VisualBasicProjectRewriter(AnalyzerResult analyzerResult, ProjectConfiguration projectConfiguration) + : base(analyzerResult, projectConfiguration) + { + _projectType = projectConfiguration.ProjectType; + } + + /// + /// Initializes a new instance of ProjectRewriter using an existing analysis + /// + /// The analysis results of the project + /// ProjectConfiguration for this project + public VisualBasicProjectRewriter(IDEProjectResult projectResult, ProjectConfiguration projectConfiguration) + : base(projectResult, projectConfiguration) + { + _projectType = projectConfiguration.ProjectType; + } + + /// + /// Initializes the ProjectRewriter then runs it + /// + public override ProjectResult Run() + { + if (isExludedFromPorting(_projectType)) + return _projectResult; + + var projectResult = Initialize(); + return Run(projectResult.ProjectActions); + } + + /// + /// Runs the project rewriter using a previously initialized analysis + /// + /// + public override ProjectResult Run(ProjectActions projectActions) + { + if (isExludedFromPorting(_projectType)) + return _projectResult; + + base.Run(projectActions); + return _projectResult; + } + + /// + /// Runs the project rewriter using an incremental analysis + /// + /// + /// + public override List RunIncremental(List updatedFiles, CsharpRootNodes projectRules) + { + List ideFileActions = new List(); + if(!isExludedFromPorting(_projectType)) + ideFileActions = base.RunIncremental(updatedFiles, projectRules); + return ideFileActions; + } + + + private bool isExludedFromPorting(ProjectType projectType) + { + return projectType == ProjectType.VBWebForms || projectType == ProjectType.VBNetMvc; + } + } +} diff --git a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs index 9cbd6338..15e01b5a 100644 --- a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs +++ b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs @@ -5,10 +5,10 @@ using Codelyzer.Analysis.Build; using CTA.Rules.Config; using CTA.Rules.Models; -using CTA.Rules.PortCore; +using CTA.Rules.Update; using Microsoft.CodeAnalysis.CSharp; -namespace CTA.Rules.Update +namespace CTA.Rules.PortCore { /// /// Runs rule updates on a Project From bfbdc2ad2ecff4eda1c75123cf2951d659293483 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Tue, 21 Jun 2022 10:26:56 -0700 Subject: [PATCH 50/61] update codelyzer version --- .../packages.lock.json | 46 +++++++++---------- src/CTA.Rules.Config/CTA.Rules.Config.csproj | 4 +- src/CTA.Rules.Models/packages.lock.json | 46 +++++++++---------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/CTA.FeatureDetection.Common/packages.lock.json b/src/CTA.FeatureDetection.Common/packages.lock.json index 91b782be..5d62cef8 100644 --- a/src/CTA.FeatureDetection.Common/packages.lock.json +++ b/src/CTA.FeatureDetection.Common/packages.lock.json @@ -54,12 +54,12 @@ }, "Codelyzer.Analysis": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "3u40R9jXqCZ3pLyY3cEFB2WbZIjvF/I+xQcT83oFbJXFAE5n7g1txDjzrv4Vyb9YHQJtlkAIUMkkiFn8dUNt7Q==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "8ocAQHFpL7NIVSQ8i518EQWUFujXcHqS/AuQfxHbX64PA6wNAkrBWTsjhKTvI05dLWZ6iHUZm3wQ5uxXU2gPlA==", "dependencies": { - "Codelyzer.Analysis.Build": "2.4.56-alpha-g89b570063c", - "Codelyzer.Analysis.CSharp": "2.4.56-alpha-g89b570063c", - "Codelyzer.Analysis.VisualBasic": "2.4.56-alpha-g89b570063c", + "Codelyzer.Analysis.Build": "2.4.65-alpha-gd06dae876d", + "Codelyzer.Analysis.CSharp": "2.4.65-alpha-gd06dae876d", + "Codelyzer.Analysis.VisualBasic": "2.4.65-alpha-gd06dae876d", "CommandLineParser": "2.8.0", "Microsoft.Build.Utilities.Core": "17.1.0", "Microsoft.Extensions.Logging.Console": "6.0.0", @@ -69,23 +69,23 @@ }, "Codelyzer.Analysis.Build": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "hvxLNqVU9Yh/hdTNsmT+qtLgy7J+0Nm1diRjHGKH/FI6ymZkvgAkYB2UWge1JkRAWyRm4WNF4ukgwUlB8WboPA==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "1EqRE2hIKMtkzzKpTyzDZrqCDcSjr9iJlM8WYQ7evQ1gT9YOGaUB/iO+/DdW4CsKNbFqhq6RvCeyhu32x272hw==", "dependencies": { "Buildalyzer": "4.1.4", "Buildalyzer.Logger": "4.1.4", "Buildalyzer.Workspaces": "4.1.4", - "Codelyzer.Analysis.Common": "2.4.56-alpha-g89b570063c", + "Codelyzer.Analysis.Common": "2.4.65-alpha-gd06dae876d", "Microsoft.Extensions.Logging": "6.0.0", "NuGet.Packaging": "6.0.0" } }, "Codelyzer.Analysis.Common": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "ZflwAG3tOHPfqHmfnkUTl5RKuCzN7HqhVF7aw6fwUD1uE93HTdB4VBvkm0n3Nj6Ucv6Mv8UK3bYoYGr0+EYYIQ==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "igze76koUw5Ao9XrpjjdyLPobF5CCi9uSb26zLcnrnQsiS1k8m58CQJZKCfsP2mAsGb7HhC5IHmkzxUqGIu29g==", "dependencies": { - "Codelyzer.Analysis.Model": "2.4.56-alpha-g89b570063c", + "Codelyzer.Analysis.Model": "2.4.65-alpha-gd06dae876d", "Microsoft.Build": "17.0.0", "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", "Newtonsoft.Json": "13.0.1" @@ -93,17 +93,17 @@ }, "Codelyzer.Analysis.CSharp": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "68Z3EFQpRG7OJk3ImRVXjKxRcqZl9nk7E8rrD5fdfy64qd/I9KD8/eJ0xyEPwhwTzv+OsnZQyZ5YidOd9WLIEg==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "HlxgpiPQUw53w1c25F3WpO2NMEm+9ZekHmhxNcspy+P2pIHmhRLvmAhkQGYerk+J6teS7oJTHG31w6NgrxgdqA==", "dependencies": { - "Codelyzer.Analysis.Common": "2.4.56-alpha-g89b570063c", - "Codelyzer.Analysis.Model": "2.4.56-alpha-g89b570063c" + "Codelyzer.Analysis.Common": "2.4.65-alpha-gd06dae876d", + "Codelyzer.Analysis.Model": "2.4.65-alpha-gd06dae876d" } }, "Codelyzer.Analysis.Model": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "CJCJsGouBGuFe0MCJD3zinuaKQQXfLxT81oqpz2Z+yaTEi420fiHNLvlRzHILnaT3Uu1pBnbkCix5hxHRDWF0A==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "E0pzEAkmo1znKadLMIsrINDAffA+7wHaRhSV+IGjayvYx77XAjb54j2U61ysATOz2YXHqU3wQfWU2KhIgGHdZw==", "dependencies": { "Microsoft.CodeAnalysis": "4.1.0", "Microsoft.CodeAnalysis.CSharp": "4.1.0", @@ -114,11 +114,11 @@ }, "Codelyzer.Analysis.VisualBasic": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "oZ2tGbAMHPjegveNz2hXLEJYxJvOOMjb27W7KNMKpynwLDm+Ck9GloGiGZi/ADpSvrxelYl6JQtYIeACJBu+Iw==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "92Y5YpPXOXvlNe8g3ipZ1MQ54yZwl8Ah91OGJEZSTnnb6CwFkgqiIp/mIlFtor/AyUCO/+MEKdqJ7Q/fOgogVQ==", "dependencies": { - "Codelyzer.Analysis.Common": "2.4.56-alpha-g89b570063c", - "Codelyzer.Analysis.Model": "2.4.56-alpha-g89b570063c" + "Codelyzer.Analysis.Common": "2.4.65-alpha-gd06dae876d", + "Codelyzer.Analysis.Model": "2.4.65-alpha-gd06dae876d" } }, "CommandLineParser": { @@ -1711,8 +1711,8 @@ "cta.rules.config": { "type": "Project", "dependencies": { - "Codelyzer.Analysis": "2.4.56-alpha-g89b570063c", - "Codelyzer.Analysis.Model": "2.4.56-alpha-g89b570063c", + "Codelyzer.Analysis": "2.4.65-alpha-gd06dae876d", + "Codelyzer.Analysis.Model": "2.4.65-alpha-gd06dae876d", "Microsoft.Extensions.Logging": "6.0.0", "Microsoft.Extensions.Logging.Abstractions": "6.0.0", "Microsoft.Extensions.Logging.Console": "6.0.0", diff --git a/src/CTA.Rules.Config/CTA.Rules.Config.csproj b/src/CTA.Rules.Config/CTA.Rules.Config.csproj index cae46c35..6e8548a4 100644 --- a/src/CTA.Rules.Config/CTA.Rules.Config.csproj +++ b/src/CTA.Rules.Config/CTA.Rules.Config.csproj @@ -5,8 +5,8 @@ - - + + diff --git a/src/CTA.Rules.Models/packages.lock.json b/src/CTA.Rules.Models/packages.lock.json index a4185289..aaf1f2e4 100644 --- a/src/CTA.Rules.Models/packages.lock.json +++ b/src/CTA.Rules.Models/packages.lock.json @@ -60,12 +60,12 @@ }, "Codelyzer.Analysis": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "3u40R9jXqCZ3pLyY3cEFB2WbZIjvF/I+xQcT83oFbJXFAE5n7g1txDjzrv4Vyb9YHQJtlkAIUMkkiFn8dUNt7Q==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "8ocAQHFpL7NIVSQ8i518EQWUFujXcHqS/AuQfxHbX64PA6wNAkrBWTsjhKTvI05dLWZ6iHUZm3wQ5uxXU2gPlA==", "dependencies": { - "Codelyzer.Analysis.Build": "2.4.56-alpha-g89b570063c", - "Codelyzer.Analysis.CSharp": "2.4.56-alpha-g89b570063c", - "Codelyzer.Analysis.VisualBasic": "2.4.56-alpha-g89b570063c", + "Codelyzer.Analysis.Build": "2.4.65-alpha-gd06dae876d", + "Codelyzer.Analysis.CSharp": "2.4.65-alpha-gd06dae876d", + "Codelyzer.Analysis.VisualBasic": "2.4.65-alpha-gd06dae876d", "CommandLineParser": "2.8.0", "Microsoft.Build.Utilities.Core": "17.1.0", "Microsoft.Extensions.Logging.Console": "6.0.0", @@ -75,23 +75,23 @@ }, "Codelyzer.Analysis.Build": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "hvxLNqVU9Yh/hdTNsmT+qtLgy7J+0Nm1diRjHGKH/FI6ymZkvgAkYB2UWge1JkRAWyRm4WNF4ukgwUlB8WboPA==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "1EqRE2hIKMtkzzKpTyzDZrqCDcSjr9iJlM8WYQ7evQ1gT9YOGaUB/iO+/DdW4CsKNbFqhq6RvCeyhu32x272hw==", "dependencies": { "Buildalyzer": "4.1.4", "Buildalyzer.Logger": "4.1.4", "Buildalyzer.Workspaces": "4.1.4", - "Codelyzer.Analysis.Common": "2.4.56-alpha-g89b570063c", + "Codelyzer.Analysis.Common": "2.4.65-alpha-gd06dae876d", "Microsoft.Extensions.Logging": "6.0.0", "NuGet.Packaging": "6.0.0" } }, "Codelyzer.Analysis.Common": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "ZflwAG3tOHPfqHmfnkUTl5RKuCzN7HqhVF7aw6fwUD1uE93HTdB4VBvkm0n3Nj6Ucv6Mv8UK3bYoYGr0+EYYIQ==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "igze76koUw5Ao9XrpjjdyLPobF5CCi9uSb26zLcnrnQsiS1k8m58CQJZKCfsP2mAsGb7HhC5IHmkzxUqGIu29g==", "dependencies": { - "Codelyzer.Analysis.Model": "2.4.56-alpha-g89b570063c", + "Codelyzer.Analysis.Model": "2.4.65-alpha-gd06dae876d", "Microsoft.Build": "17.0.0", "Microsoft.VisualStudio.Setup.Configuration.Interop": "3.1.2196", "Newtonsoft.Json": "13.0.1" @@ -99,17 +99,17 @@ }, "Codelyzer.Analysis.CSharp": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "68Z3EFQpRG7OJk3ImRVXjKxRcqZl9nk7E8rrD5fdfy64qd/I9KD8/eJ0xyEPwhwTzv+OsnZQyZ5YidOd9WLIEg==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "HlxgpiPQUw53w1c25F3WpO2NMEm+9ZekHmhxNcspy+P2pIHmhRLvmAhkQGYerk+J6teS7oJTHG31w6NgrxgdqA==", "dependencies": { - "Codelyzer.Analysis.Common": "2.4.56-alpha-g89b570063c", - "Codelyzer.Analysis.Model": "2.4.56-alpha-g89b570063c" + "Codelyzer.Analysis.Common": "2.4.65-alpha-gd06dae876d", + "Codelyzer.Analysis.Model": "2.4.65-alpha-gd06dae876d" } }, "Codelyzer.Analysis.Model": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "CJCJsGouBGuFe0MCJD3zinuaKQQXfLxT81oqpz2Z+yaTEi420fiHNLvlRzHILnaT3Uu1pBnbkCix5hxHRDWF0A==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "E0pzEAkmo1znKadLMIsrINDAffA+7wHaRhSV+IGjayvYx77XAjb54j2U61ysATOz2YXHqU3wQfWU2KhIgGHdZw==", "dependencies": { "Microsoft.CodeAnalysis": "4.1.0", "Microsoft.CodeAnalysis.CSharp": "4.1.0", @@ -120,11 +120,11 @@ }, "Codelyzer.Analysis.VisualBasic": { "type": "Transitive", - "resolved": "2.4.56-alpha-g89b570063c", - "contentHash": "oZ2tGbAMHPjegveNz2hXLEJYxJvOOMjb27W7KNMKpynwLDm+Ck9GloGiGZi/ADpSvrxelYl6JQtYIeACJBu+Iw==", + "resolved": "2.4.65-alpha-gd06dae876d", + "contentHash": "92Y5YpPXOXvlNe8g3ipZ1MQ54yZwl8Ah91OGJEZSTnnb6CwFkgqiIp/mIlFtor/AyUCO/+MEKdqJ7Q/fOgogVQ==", "dependencies": { - "Codelyzer.Analysis.Common": "2.4.56-alpha-g89b570063c", - "Codelyzer.Analysis.Model": "2.4.56-alpha-g89b570063c" + "Codelyzer.Analysis.Common": "2.4.65-alpha-gd06dae876d", + "Codelyzer.Analysis.Model": "2.4.65-alpha-gd06dae876d" } }, "CommandLineParser": { @@ -1717,8 +1717,8 @@ "cta.rules.config": { "type": "Project", "dependencies": { - "Codelyzer.Analysis": "2.4.56-alpha-g89b570063c", - "Codelyzer.Analysis.Model": "2.4.56-alpha-g89b570063c", + "Codelyzer.Analysis": "2.4.65-alpha-gd06dae876d", + "Codelyzer.Analysis.Model": "2.4.65-alpha-gd06dae876d", "Microsoft.Extensions.Logging": "6.0.0", "Microsoft.Extensions.Logging.Abstractions": "6.0.0", "Microsoft.Extensions.Logging.Console": "6.0.0", From cc715678fe757f36d011e1cf5c82811915c89f43 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Tue, 21 Jun 2022 12:50:05 -0700 Subject: [PATCH 51/61] fix: undo rename to csharp root nodes minimize changes to help maintain backwards compatibility --- src/CTA.Rules.Analysis/RulesAnalysis.cs | 54 ++++++++-------- src/CTA.Rules.Models/ProjectActions.cs | 3 +- src/CTA.Rules.Models/RootNodes.cs | 6 +- .../RulesFiles/RulesFileLoaderResponse.cs | 2 +- .../VisualBasicProjectRewriter.cs | 2 +- .../ProjectRewriters/WCFProjectRewriter.cs | 2 +- src/CTA.Rules.PortCore/SolutionPort.cs | 4 +- src/CTA.Rules.RuleFiles/RulesFileParser.cs | 62 +++++++++---------- .../ProjectRewriters/ProjectRewriter.cs | 2 +- src/CTA.Rules.Update/SolutionRewriter.cs | 2 +- 10 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/CTA.Rules.Analysis/RulesAnalysis.cs b/src/CTA.Rules.Analysis/RulesAnalysis.cs index 05f63fec..e985445a 100644 --- a/src/CTA.Rules.Analysis/RulesAnalysis.cs +++ b/src/CTA.Rules.Analysis/RulesAnalysis.cs @@ -17,7 +17,7 @@ namespace CTA.Rules.Analyzer /// public class RulesAnalysis : IRulesAnalysis { - private readonly CsharpRootNodes _csharpRootNodes; + private readonly RootNodes _rootNodes; private readonly List _sourceFileResults; private readonly ProjectActions _projectActions; private readonly ProjectType _projectType; @@ -26,12 +26,12 @@ public class RulesAnalysis : IRulesAnalysis /// Initializes an RulesAnalysis instance /// /// List of analyzed code files - /// List of rules to be applied to the code files - public RulesAnalysis(List sourceFileResults, CsharpRootNodes csharpRootNodes) + /// List of rules to be applied to the code files + public RulesAnalysis(List sourceFileResults, RootNodes rootNodes) { _projectActions = new ProjectActions(); _sourceFileResults = sourceFileResults; - _csharpRootNodes = csharpRootNodes; + _rootNodes = rootNodes; _projectType = ProjectType.ClassLibrary; } @@ -39,13 +39,13 @@ public RulesAnalysis(List sourceFileResults, CsharpRootNodes csharp /// Initializes a RulesAnalysis instance /// /// List of analyzed code files - /// List of rules to be applied to the code files + /// List of rules to be applied to the code files /// Type of project - public RulesAnalysis(List sourceFileResults, CsharpRootNodes csharpRootNodes, ProjectType projectType = ProjectType.ClassLibrary) + public RulesAnalysis(List sourceFileResults, RootNodes rootNodes, ProjectType projectType = ProjectType.ClassLibrary) { _projectActions = new ProjectActions(); _sourceFileResults = sourceFileResults; - _csharpRootNodes = csharpRootNodes; + _rootNodes = rootNodes; _projectType = projectType; } @@ -65,7 +65,7 @@ public ProjectActions Analyze() } }); - AddPackages(_csharpRootNodes.ProjectTokens.Where(p => p.FullKey == _projectType.ToString())?.SelectMany(p => p.PackageActions)?.Distinct()?.ToList(), null); + AddPackages(_rootNodes.ProjectTokens.Where(p => p.FullKey == _projectType.ToString())?.SelectMany(p => p.PackageActions)?.Distinct()?.ToList(), null); return _projectActions; } @@ -120,7 +120,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { var annotation = (Annotation)child; var compareToken = new AttributeToken() { Key = annotation.Identifier, Namespace = annotation.Reference.Namespace, Type = annotation.SemanticClassType }; - _csharpRootNodes.Attributetokens.TryGetValue(compareToken, out var token); + _rootNodes.Attributetokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -133,7 +133,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, string overrideKey = string.Empty; var compareToken = new UsingDirectiveToken() { Key = child.Identifier }; - _csharpRootNodes.Usingdirectivetokens.TryGetValue(compareToken, out var token); + _rootNodes.Usingdirectivetokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -143,7 +143,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, //Attempt a wildcard search, if applicable. This is using directive specific because it might want to include all sub-namespaces if (token == null) { - var wildcardMatches = _csharpRootNodes.Usingdirectivetokens.Where(i => i.Key.Contains("*")); + var wildcardMatches = _rootNodes.Usingdirectivetokens.Where(i => i.Key.Contains("*")); if (wildcardMatches.Any()) { token = wildcardMatches.FirstOrDefault(i => compareToken.Key.WildcardEquals(i.Key)); @@ -165,7 +165,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, case IdConstants.NamespaceIdName: { var compareToken = new NamespaceToken() { Key = child.Identifier }; - _csharpRootNodes.NamespaceTokens.TryGetValue(compareToken, out var token); + _rootNodes.NamespaceTokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -178,7 +178,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { var classType = (ClassDeclaration)child; var baseToken = new ClassDeclarationToken() { FullKey = classType.BaseType }; - _csharpRootNodes.Classdeclarationtokens.TryGetValue(baseToken, out var token); + _rootNodes.Classdeclarationtokens.TryGetValue(baseToken, out var token); if (token != null) { @@ -191,7 +191,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, token = null; string name = string.Concat(classType.Reference != null ? string.Concat(classType.Reference.Namespace, ".") : string.Empty, classType.Identifier); var nameToken = new ClassDeclarationToken() { FullKey = name }; - _csharpRootNodes.Classdeclarationtokens.TryGetValue(nameToken, out token); + _rootNodes.Classdeclarationtokens.TryGetValue(nameToken, out token); if (token != null) { @@ -207,7 +207,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, foreach (string interfaceName in classType.BaseList ?? Enumerable.Empty()) { var baseListToken = new ClassDeclarationToken() { FullKey = interfaceName }; - _csharpRootNodes.Classdeclarationtokens.TryGetValue(baseListToken, out token); + _rootNodes.Classdeclarationtokens.TryGetValue(baseListToken, out token); if (token != null) { @@ -229,7 +229,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, if (!string.IsNullOrEmpty(interfaceType.BaseType)) { - _csharpRootNodes.InterfaceDeclarationTokens.TryGetValue(baseToken, out token); + _rootNodes.InterfaceDeclarationTokens.TryGetValue(baseToken, out token); } if (token != null) @@ -243,7 +243,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, token = null; string name = string.Concat(interfaceType.Reference != null ? string.Concat(interfaceType.Reference.Namespace, ".") : string.Empty, interfaceType.Identifier); var nameToken = new InterfaceDeclarationToken() { FullKey = name }; - _csharpRootNodes.InterfaceDeclarationTokens.TryGetValue(nameToken, out token); + _rootNodes.InterfaceDeclarationTokens.TryGetValue(nameToken, out token); if (token != null) { @@ -259,7 +259,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, case IdConstants.MethodIdName: { var compareToken = new MethodDeclarationToken() { FullKey = string.Concat(child.Identifier) }; - _csharpRootNodes.MethodDeclarationTokens.TryGetValue(compareToken, out var token); + _rootNodes.MethodDeclarationTokens.TryGetValue(compareToken, out var token); if (token != null) { AddNamedActions(fileAction, token, child.Identifier, child.TextSpan); @@ -279,12 +279,12 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, if (string.IsNullOrEmpty(invocationExpression.SemanticOriginalDefinition)) break; var compareToken = new InvocationExpressionToken() { Key = invocationExpression.SemanticOriginalDefinition, Namespace = invocationExpression.Reference.Namespace, Type = invocationExpression.SemanticClassType }; - _csharpRootNodes.Invocationexpressiontokens.TryGetValue(compareToken, out var token); + _rootNodes.Invocationexpressiontokens.TryGetValue(compareToken, out var token); //Attempt a wildcard search, if applicable. This is invocation expression specific because it has to look inside the invocation expressions only if(token == null) { - var wildcardMatches = _csharpRootNodes.Invocationexpressiontokens.Where(i => i.Key.Contains("*")); + var wildcardMatches = _rootNodes.Invocationexpressiontokens.Where(i => i.Key.Contains("*")); if (wildcardMatches.Any()) { token = wildcardMatches.FirstOrDefault(i => compareToken.Key.WildcardEquals(i.Key) && compareToken.Namespace == i.Namespace && compareToken.Type == i.Type); @@ -302,7 +302,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { string semanticClassType = invocationExpression.SemanticClassType.Substring(0,invocationExpression.SemanticClassType.IndexOf('<')); compareToken = new InvocationExpressionToken() { Key = invocationExpression.SemanticOriginalDefinition, Namespace = invocationExpression.Reference.Namespace, Type = semanticClassType }; - _csharpRootNodes.Invocationexpressiontokens.TryGetValue(compareToken, out token); + _rootNodes.Invocationexpressiontokens.TryGetValue(compareToken, out token); } } } @@ -325,7 +325,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, Type = elementAccess.SemanticClassType, Namespace = elementAccess.Reference?.Namespace }; - _csharpRootNodes.ElementAccesstokens.TryGetValue(compareToken, out var token); + _rootNodes.ElementAccesstokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -345,7 +345,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, Type = memberAccess.SemanticClassType, Namespace = memberAccess.Reference?.Namespace }; - _csharpRootNodes.MemberAccesstokens.TryGetValue(compareToken, out var token); + _rootNodes.MemberAccesstokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -358,7 +358,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, { var declarationNode = (DeclarationNode)child; var compareToken = new IdentifierNameToken() { Key = string.Concat(declarationNode.Reference.Namespace, ".", declarationNode.Identifier), Namespace = declarationNode.Reference.Namespace }; - _csharpRootNodes.Identifiernametokens.TryGetValue(compareToken, out var token); + _rootNodes.Identifiernametokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -372,7 +372,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, var objectCreationNode = (ObjectCreationExpression)child; //Rules based on Object Creation Parent Hierarchy var compareToken = new ObjectCreationExpressionToken() { Key = objectCreationNode.Identifier, Namespace = objectCreationNode.Reference?.Namespace, Type = objectCreationNode.SemanticClassType }; - _csharpRootNodes.ObjectCreationExpressionTokens.TryGetValue(compareToken, out var token); + _rootNodes.ObjectCreationExpressionTokens.TryGetValue(compareToken, out var token); if (token != null) { AddActions(fileAction, token, child.TextSpan); @@ -381,7 +381,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, //Rules based on Object Creation location within code var compareTokenLocation = new ObjectCreationExpressionToken() { Key = objectCreationNode.Identifier, Namespace = parentNamespace, Type = parentClass }; - _csharpRootNodes.ObjectCreationExpressionTokens.TryGetValue(compareTokenLocation, out var tokenLocation); + _rootNodes.ObjectCreationExpressionTokens.TryGetValue(compareTokenLocation, out var tokenLocation); if (tokenLocation != null) { AddActions(fileAction, tokenLocation, child.TextSpan); @@ -392,7 +392,7 @@ private bool AnalyzeChildren(FileActions fileAction, UstList children, if(!string.IsNullOrEmpty(objectCreationNode.SemanticOriginalDefinition)) { var nameToken = new ObjectCreationExpressionToken() { Key = objectCreationNode.SemanticOriginalDefinition, Namespace = objectCreationNode.SemanticNamespace, Type = objectCreationNode.SemanticClassType }; - _csharpRootNodes.ObjectCreationExpressionTokens.TryGetValue(nameToken, out token); + _rootNodes.ObjectCreationExpressionTokens.TryGetValue(nameToken, out token); if (token != null) { AddActions(fileAction, token, child.TextSpan); diff --git a/src/CTA.Rules.Models/ProjectActions.cs b/src/CTA.Rules.Models/ProjectActions.cs index cb2e2077..961694d2 100644 --- a/src/CTA.Rules.Models/ProjectActions.cs +++ b/src/CTA.Rules.Models/ProjectActions.cs @@ -21,7 +21,8 @@ public ProjectActions() public BlockingCollection PackageActions { get; set; } public BlockingCollection ProjectReferenceActions { get; set; } public List ProjectLevelActions { get; set; } - public CsharpRootNodes CsharpProjectRules { get; set; } + public RootNodes ProjectRules { get; set; } + public RootNodes CsharpProjectRules { get; set; } public VisualBasicRootNodes VbProjectRules { get; set; } public override string ToString() diff --git a/src/CTA.Rules.Models/RootNodes.cs b/src/CTA.Rules.Models/RootNodes.cs index c43f10ad..cd355eea 100644 --- a/src/CTA.Rules.Models/RootNodes.cs +++ b/src/CTA.Rules.Models/RootNodes.cs @@ -14,11 +14,12 @@ public RootNodes() Invocationexpressiontokens = new HashSet(); Expressiontokens = new HashSet(); MemberAccesstokens = new HashSet(); + Usingdirectivetokens = new HashSet(); MethodDeclarationTokens = new HashSet(); ObjectCreationExpressionTokens = new HashSet(); InterfaceDeclarationTokens = new HashSet(); NamespaceTokens = new HashSet(); - ProjectTokens = new HashSet(); + ProjectTokens = new HashSet(); } @@ -30,9 +31,10 @@ public RootNodes() public HashSet Invocationexpressiontokens { get; set; } public HashSet Expressiontokens { get; set; } public HashSet MemberAccesstokens { get; set; } + public HashSet Usingdirectivetokens { get; set; } public HashSet MethodDeclarationTokens { get; set; } public HashSet NamespaceTokens { get; set; } public HashSet ObjectCreationExpressionTokens { get; set; } - public HashSet ProjectTokens { get; set; } + public HashSet ProjectTokens { get; set; } } } diff --git a/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs b/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs index 40ea0794..2bc130cb 100644 --- a/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs +++ b/src/CTA.Rules.Models/RulesFiles/RulesFileLoaderResponse.cs @@ -4,7 +4,7 @@ namespace CTA.Rules.Models.RulesFiles { public class RulesFileLoaderResponse { - public CsharpRootNodes CsharpRootNodes { get; set; } + public RootNodes CsharpRootNodes { get; set; } public VisualBasicRootNodes VisualBasicRootNodes { get; set; } } } diff --git a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/VisualBasicProjectRewriter.cs b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/VisualBasicProjectRewriter.cs index fe60429c..f59c4b0d 100644 --- a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/VisualBasicProjectRewriter.cs +++ b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/VisualBasicProjectRewriter.cs @@ -62,7 +62,7 @@ public override ProjectResult Run(ProjectActions projectActions) /// /// /// - public override List RunIncremental(List updatedFiles, CsharpRootNodes projectRules) + public override List RunIncremental(List updatedFiles, RootNodes projectRules) { List ideFileActions = new List(); if(!isExludedFromPorting(_projectType)) diff --git a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs index 15e01b5a..4a5f1fe6 100644 --- a/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs +++ b/src/CTA.Rules.PortCore/ProjectSpecificPort/ProjectRewriters/WCFProjectRewriter.cs @@ -56,7 +56,7 @@ public override ProjectResult Run(ProjectActions projectActions) return _projectResult; } - public override List RunIncremental(List updatedFiles, CsharpRootNodes projectRules) + public override List RunIncremental(List updatedFiles, RootNodes projectRules) { base.RunIncremental(updatedFiles, projectRules); var ideFileActions = new List(); diff --git a/src/CTA.Rules.PortCore/SolutionPort.cs b/src/CTA.Rules.PortCore/SolutionPort.cs index 54148500..436dfd14 100644 --- a/src/CTA.Rules.PortCore/SolutionPort.cs +++ b/src/CTA.Rules.PortCore/SolutionPort.cs @@ -352,7 +352,7 @@ public PortSolutionResult GenerateResults() /// The rules list to be used /// The files to be analyzed /// - public List RunIncremental(CsharpRootNodes projectRules, List updatedFiles) + public List RunIncremental(RootNodes projectRules, List updatedFiles) { return _solutionRewriter.RunIncremental(projectRules, updatedFiles); } @@ -362,7 +362,7 @@ public List RunIncremental(CsharpRootNodes projectRules, ListThe rules list to be used /// The file to be analyzed /// - public List RunIncremental(CsharpRootNodes projectRules, string updatedFile) + public List RunIncremental(RootNodes projectRules, string updatedFile) { return _solutionRewriter.RunIncremental(projectRules, new List { updatedFile }); } diff --git a/src/CTA.Rules.RuleFiles/RulesFileParser.cs b/src/CTA.Rules.RuleFiles/RulesFileParser.cs index edd82131..77a2a79d 100644 --- a/src/CTA.Rules.RuleFiles/RulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/RulesFileParser.cs @@ -16,7 +16,7 @@ namespace CTA.Rules.RuleFiles /// public class RulesFileParser { - private readonly CsharpRootNodes _csharpRootNodes; + private readonly RootNodes _rootNodes; private readonly string _assembliesDir; private readonly string _targetFramework; @@ -45,8 +45,8 @@ public RulesFileParser( string assembliesDir, string targetFramework) { - _csharpRootNodes = new CsharpRootNodes(); - _csharpRootNodes.ProjectTokens.Add(new ProjectToken() { Key = "Project" }); + _rootNodes = new RootNodes(); + _rootNodes.ProjectTokens.Add(new ProjectToken() { Key = "Project" }); _rulesObject = rulesObject; _overrideObject = overrideObject; _assembliesDir = assembliesDir; @@ -61,7 +61,7 @@ public RulesFileParser( /// Runs the parser to merge the rules /// /// RootNodes object that contains the tokens and their associated actions - public CsharpRootNodes Process() + public RootNodes Process() { //Process overrides first: if (_overrideObject.NameSpaces != null) @@ -88,7 +88,7 @@ public CsharpRootNodes Process() ProcessObject(_namespaceRecommendations); } - return _csharpRootNodes; + return _rootNodes; } /// @@ -119,7 +119,7 @@ public void ProcessObject(Rootobject rootobject) //Global Actions: if (@namespace.@namespace == Constants.Project && @namespace.Assembly == Constants.Project) { - var projectToken = _csharpRootNodes.ProjectTokens.FirstOrDefault(); + var projectToken = _rootNodes.ProjectTokens.FirstOrDefault(); ParseActions((ProjectToken)projectToken, @namespace.Actions); } //Namespace specific actions: @@ -128,8 +128,8 @@ public void ProcessObject(Rootobject rootobject) var usingToken = new UsingDirectiveToken() { Key = @namespace.@namespace }; var namespaceToken = new NamespaceToken() { Key = @namespace.@namespace }; - if (!_csharpRootNodes.Usingdirectivetokens.Contains(usingToken)) { _csharpRootNodes.Usingdirectivetokens.Add(usingToken); } - if (!_csharpRootNodes.NamespaceTokens.Contains(namespaceToken)) { _csharpRootNodes.NamespaceTokens.Add(namespaceToken); } + if (!_rootNodes.Usingdirectivetokens.Contains(usingToken)) { _rootNodes.Usingdirectivetokens.Add(usingToken); } + if (!_rootNodes.NamespaceTokens.Contains(namespaceToken)) { _rootNodes.NamespaceTokens.Add(namespaceToken); } ParseActions(usingToken, @namespace.Actions); ParseActions(namespaceToken, @namespace.Actions); @@ -142,13 +142,13 @@ public void ProcessObject(Rootobject rootobject) if (@class.KeyType == CTA.Rules.Config.Constants.BaseClass || @class.KeyType == CTA.Rules.Config.Constants.ClassName) { var token = new ClassDeclarationToken() { Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace }; - if (!_csharpRootNodes.Classdeclarationtokens.Contains(token)) { _csharpRootNodes.Classdeclarationtokens.Add(token); } + if (!_rootNodes.Classdeclarationtokens.Contains(token)) { _rootNodes.Classdeclarationtokens.Add(token); } ParseActions(token, @class.Actions); } else if (@class.KeyType == CTA.Rules.Config.Constants.Identifier) { var token = new IdentifierNameToken() { Key = @class.FullKey, FullKey = @class.FullKey, Namespace = @namespace.@namespace }; - if (!_csharpRootNodes.Identifiernametokens.Contains(token)) { _csharpRootNodes.Identifiernametokens.Add(token); } + if (!_rootNodes.Identifiernametokens.Contains(token)) { _rootNodes.Identifiernametokens.Add(token); } ParseActions(token, @class.Actions); } } @@ -157,7 +157,7 @@ public void ProcessObject(Rootobject rootobject) if (attribute.Actions != null && attribute.Actions.Count > 0) { var token = new AttributeToken() { Key = attribute.Key, Namespace = @namespace.@namespace, FullKey = attribute.FullKey, Type = @class.Key }; - if (!_csharpRootNodes.Attributetokens.Contains(token)) { _csharpRootNodes.Attributetokens.Add(token); } + if (!_rootNodes.Attributetokens.Contains(token)) { _rootNodes.Attributetokens.Add(token); } ParseActions(token, attribute.Actions); } } @@ -167,7 +167,7 @@ public void ProcessObject(Rootobject rootobject) if (method.Actions != null && method.Actions.Count > 0) { var token = new InvocationExpressionToken() { Key = method.Key, Namespace = @namespace.@namespace, FullKey = method.FullKey, Type = @class.Key }; - if (!_csharpRootNodes.Invocationexpressiontokens.Contains(token)) { _csharpRootNodes.Invocationexpressiontokens.Add(token); } + if (!_rootNodes.Invocationexpressiontokens.Contains(token)) { _rootNodes.Invocationexpressiontokens.Add(token); } ParseActions(token, method.Actions); } } @@ -177,7 +177,7 @@ public void ProcessObject(Rootobject rootobject) if (objectCreation.Actions != null && objectCreation.Actions.Count > 0) { var token = new ObjectCreationExpressionToken() { Key = objectCreation.Key, Namespace = @namespace.@namespace, FullKey = objectCreation.FullKey, Type = @class.Key }; - if (!_csharpRootNodes.ObjectCreationExpressionTokens.Contains(token)) { _csharpRootNodes.ObjectCreationExpressionTokens.Add(token); } + if (!_rootNodes.ObjectCreationExpressionTokens.Contains(token)) { _rootNodes.ObjectCreationExpressionTokens.Add(token); } ParseActions(token, objectCreation.Actions); } } @@ -190,13 +190,13 @@ public void ProcessObject(Rootobject rootobject) if (@interface.KeyType == CTA.Rules.Config.Constants.BaseClass || @interface.KeyType == CTA.Rules.Config.Constants.InterfaceName) { var token = new InterfaceDeclarationToken() { Key = @interface.FullKey, FullKey = @interface.FullKey, Namespace = @namespace.@namespace }; - if (!_csharpRootNodes.InterfaceDeclarationTokens.Contains(token)) { _csharpRootNodes.InterfaceDeclarationTokens.Add(token); } + if (!_rootNodes.InterfaceDeclarationTokens.Contains(token)) { _rootNodes.InterfaceDeclarationTokens.Add(token); } ParseActions(token, @interface.Actions); } else if (@interface.KeyType == CTA.Rules.Config.Constants.Identifier) { var token = new IdentifierNameToken() { Key = @interface.FullKey, FullKey = @interface.FullKey, Namespace = @namespace.@namespace }; - if (!_csharpRootNodes.Identifiernametokens.Contains(token)) { _csharpRootNodes.Identifiernametokens.Add(token); } + if (!_rootNodes.Identifiernametokens.Contains(token)) { _rootNodes.Identifiernametokens.Add(token); } ParseActions(token, @interface.Actions); } } @@ -205,7 +205,7 @@ public void ProcessObject(Rootobject rootobject) if (attribute.Actions != null && attribute.Actions.Count > 0) { var token = new AttributeToken() { Key = attribute.Key, Namespace = @namespace.@namespace, FullKey = attribute.FullKey, Type = @interface.Key }; - if (!_csharpRootNodes.Attributetokens.Contains(token)) { _csharpRootNodes.Attributetokens.Add(token); } + if (!_rootNodes.Attributetokens.Contains(token)) { _rootNodes.Attributetokens.Add(token); } ParseActions(token, attribute.Actions); } } @@ -215,7 +215,7 @@ public void ProcessObject(Rootobject rootobject) if (method.Actions != null && method.Actions.Count > 0) { var token = new InvocationExpressionToken() { Key = method.Key, Namespace = @namespace.@namespace, FullKey = method.FullKey, Type = @interface.Key }; - if (!_csharpRootNodes.Invocationexpressiontokens.Contains(token)) { _csharpRootNodes.Invocationexpressiontokens.Add(token); } + if (!_rootNodes.Invocationexpressiontokens.Contains(token)) { _rootNodes.Invocationexpressiontokens.Add(token); } ParseActions(token, method.Actions); } } @@ -266,8 +266,8 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) var usingToken = new UsingDirectiveToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs }; var namespaceToken = new NamespaceToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs }; - if (!_csharpRootNodes.Usingdirectivetokens.Contains(usingToken)) { _csharpRootNodes.Usingdirectivetokens.Add(usingToken); } - if (!_csharpRootNodes.NamespaceTokens.Contains(namespaceToken)) { _csharpRootNodes.NamespaceTokens.Add(namespaceToken); } + if (!_rootNodes.Usingdirectivetokens.Contains(usingToken)) { _rootNodes.Usingdirectivetokens.Add(usingToken); } + if (!_rootNodes.NamespaceTokens.Contains(namespaceToken)) { _rootNodes.NamespaceTokens.Add(namespaceToken); } ParseActions(usingToken, recommendedActions.Actions); ParseActions(namespaceToken, recommendedActions.Actions); @@ -278,13 +278,13 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) if (recommendation.KeyType == CTA.Rules.Config.Constants.BaseClass || recommendation.KeyType == CTA.Rules.Config.Constants.ClassName) { var token = new ClassDeclarationToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs, FullKey = recommendation.Value, Namespace = @namespace.Name }; - if (!_csharpRootNodes.Classdeclarationtokens.Contains(token)) { _csharpRootNodes.Classdeclarationtokens.Add(token); } + if (!_rootNodes.Classdeclarationtokens.Contains(token)) { _rootNodes.Classdeclarationtokens.Add(token); } ParseActions(token, recommendedActions.Actions); } else if (recommendation.KeyType == CTA.Rules.Config.Constants.Identifier) { var token = new IdentifierNameToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs, FullKey = recommendation.Value, Namespace = @namespace.Name }; - if (!_csharpRootNodes.Identifiernametokens.Contains(token)) { _csharpRootNodes.Identifiernametokens.Add(token); } + if (!_rootNodes.Identifiernametokens.Contains(token)) { _rootNodes.Identifiernametokens.Add(token); } ParseActions(token, recommendedActions.Actions); } break; @@ -295,13 +295,13 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) if (recommendation.KeyType == CTA.Rules.Config.Constants.BaseClass || recommendation.KeyType == CTA.Rules.Config.Constants.ClassName) { var token = new InterfaceDeclarationToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs, FullKey = recommendation.Value, Namespace = @namespace.Name }; - if (!_csharpRootNodes.InterfaceDeclarationTokens.Contains(token)) { _csharpRootNodes.InterfaceDeclarationTokens.Add(token); } + if (!_rootNodes.InterfaceDeclarationTokens.Contains(token)) { _rootNodes.InterfaceDeclarationTokens.Add(token); } ParseActions(token, recommendedActions.Actions); } else if (recommendation.KeyType == CTA.Rules.Config.Constants.Identifier) { var token = new IdentifierNameToken() { Key = recommendation.Value, Description = recommendedActions.Description, TargetCPU = targetCPUs, FullKey = recommendation.Value, Namespace = @namespace.Name }; - if (!_csharpRootNodes.Identifiernametokens.Contains(token)) { _csharpRootNodes.Identifiernametokens.Add(token); } + if (!_rootNodes.Identifiernametokens.Contains(token)) { _rootNodes.Identifiernametokens.Add(token); } ParseActions(token, recommendedActions.Actions); } break; @@ -310,21 +310,21 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.Method: { var token = new InvocationExpressionToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_csharpRootNodes.Invocationexpressiontokens.Contains(token)) { _csharpRootNodes.Invocationexpressiontokens.Add(token); } + if (!_rootNodes.Invocationexpressiontokens.Contains(token)) { _rootNodes.Invocationexpressiontokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } case ActionTypes.Expression: { var token = new ExpressionToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_csharpRootNodes.Expressiontokens.Contains(token)) { _csharpRootNodes.Expressiontokens.Add(token); } + if (!_rootNodes.Expressiontokens.Contains(token)) { _rootNodes.Expressiontokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } case ActionTypes.Attribute: { var token = new AttributeToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_csharpRootNodes.Attributetokens.Contains(token)) { _csharpRootNodes.Attributetokens.Add(token); } + if (!_rootNodes.Attributetokens.Contains(token)) { _rootNodes.Attributetokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -332,7 +332,7 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.ObjectCreation: { var token = new ObjectCreationExpressionToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_csharpRootNodes.ObjectCreationExpressionTokens.Contains(token)) { _csharpRootNodes.ObjectCreationExpressionTokens.Add(token); } + if (!_rootNodes.ObjectCreationExpressionTokens.Contains(token)) { _rootNodes.ObjectCreationExpressionTokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -340,7 +340,7 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.MethodDeclaration: { var token = new MethodDeclarationToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_csharpRootNodes.MethodDeclarationTokens.Contains(token)) { _csharpRootNodes.MethodDeclarationTokens.Add(token); } + if (!_rootNodes.MethodDeclarationTokens.Contains(token)) { _rootNodes.MethodDeclarationTokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -348,7 +348,7 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.ElementAccess: { var token = new ElementAccessToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_csharpRootNodes.ElementAccesstokens.Contains(token)) { _csharpRootNodes.ElementAccesstokens.Add(token); } + if (!_rootNodes.ElementAccesstokens.Contains(token)) { _rootNodes.ElementAccesstokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -356,7 +356,7 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.MemberAccess: { var token = new MemberAccessToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value, Type = recommendation.ContainingType }; - if (!_csharpRootNodes.MemberAccesstokens.Contains(token)) { _csharpRootNodes.MemberAccesstokens.Add(token); } + if (!_rootNodes.MemberAccesstokens.Contains(token)) { _rootNodes.MemberAccesstokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } @@ -364,7 +364,7 @@ public void ProcessObject(NamespaceRecommendations namespaceRecommendations) case ActionTypes.Project: { var token = new ProjectToken() { Key = recommendation.Name, Description = recommendedActions.Description, TargetCPU = targetCPUs, Namespace = @namespace.Name, FullKey = recommendation.Value }; - if (!_csharpRootNodes.ProjectTokens.Contains(token)) { _csharpRootNodes.ProjectTokens.Add(token); } + if (!_rootNodes.ProjectTokens.Contains(token)) { _rootNodes.ProjectTokens.Add(token); } ParseActions(token, recommendedActions.Actions); break; } diff --git a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs index c726db49..72c1686b 100644 --- a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs +++ b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs @@ -166,7 +166,7 @@ public virtual ProjectResult Run(ProjectActions projectActions) return _projectResult; } - public virtual List RunIncremental(List updatedFiles, CsharpRootNodes projectRules) + public virtual List RunIncremental(List updatedFiles, RootNodes projectRules) { var ideFileActions = new List(); diff --git a/src/CTA.Rules.Update/SolutionRewriter.cs b/src/CTA.Rules.Update/SolutionRewriter.cs index 364b80c4..d6ae745e 100644 --- a/src/CTA.Rules.Update/SolutionRewriter.cs +++ b/src/CTA.Rules.Update/SolutionRewriter.cs @@ -111,7 +111,7 @@ public SolutionResult Run(Dictionary projectActions) return _solutionResult; } - public List RunIncremental(CsharpRootNodes projectRules, List updatedFiles) + public List RunIncremental(RootNodes projectRules, List updatedFiles) { var ideFileActions = new BlockingCollection(); var options = new ParallelOptions { MaxDegreeOfParallelism = Constants.ThreadCount }; From 18bf247050fdb2d11840644a113dab0cedd6c0fb Mon Sep 17 00:00:00 2001 From: Chris Long Date: Tue, 21 Jun 2022 13:39:12 -0700 Subject: [PATCH 52/61] fix: remove csharprootnodes models --- .../Csharp/CsharpRootNodes.cs | 40 ------------------- 1 file changed, 40 deletions(-) delete mode 100644 src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs diff --git a/src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs b/src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs deleted file mode 100644 index 97894e1b..00000000 --- a/src/CTA.Rules.Models/Csharp/CsharpRootNodes.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Collections.Generic; -using CTA.Rules.Models.Tokens; - -namespace CTA.Rules.Models -{ - public class CsharpRootNodes - { - public CsharpRootNodes() - { - Attributetokens = new HashSet(); - Classdeclarationtokens = new HashSet(); - ElementAccesstokens = new HashSet(); - Identifiernametokens = new HashSet(); - Invocationexpressiontokens = new HashSet(); - Expressiontokens = new HashSet(); - MemberAccesstokens = new HashSet(); - Usingdirectivetokens = new HashSet(); - MethodDeclarationTokens = new HashSet(); - ObjectCreationExpressionTokens = new HashSet(); - InterfaceDeclarationTokens = new HashSet(); - NamespaceTokens = new HashSet(); - ProjectTokens = new HashSet(); - } - - - public HashSet Attributetokens { get; set; } - public HashSet Classdeclarationtokens { get; set; } - public HashSet InterfaceDeclarationTokens { get; set; } - public HashSet ElementAccesstokens { get; set; } - public HashSet Identifiernametokens { get; set; } - public HashSet Invocationexpressiontokens { get; set; } - public HashSet Expressiontokens { get; set; } - public HashSet MemberAccesstokens { get; set; } - public HashSet Usingdirectivetokens { get; set; } - public HashSet MethodDeclarationTokens { get; set; } - public HashSet NamespaceTokens { get; set; } - public HashSet ObjectCreationExpressionTokens { get; set; } - public HashSet ProjectTokens { get; set; } - } -} From e8d0dfa028c4703b293ade4aa19c5577cb2895d3 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Tue, 21 Jun 2022 14:51:56 -0700 Subject: [PATCH 53/61] update project rewriter for vb rules and actions --- .../ProjectRewriters/ProjectRewriter.cs | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs index 72c1686b..da07376f 100644 --- a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs +++ b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs @@ -168,19 +168,38 @@ public virtual ProjectResult Run(ProjectActions projectActions) public virtual List RunIncremental(List updatedFiles, RootNodes projectRules) { - var ideFileActions = new List(); - var allReferences = _sourceFileResults?.SelectMany(s => s.References).Distinct(); RulesFileLoader rulesFileLoader = new RulesFileLoader(allReferences, Constants.RulesDefaultPath, ProjectConfiguration.TargetVersions, _projectLanguage, string.Empty, ProjectConfiguration.AssemblyDir); - projectRules = rulesFileLoader.Load().CsharpRootNodes; - RulesAnalysis walker = new RulesAnalysis(_sourceFileResults, projectRules, ProjectConfiguration.ProjectType); - var projectActions = walker.Analyze(); + var rules = rulesFileLoader.Load(); + + HashSet projectTokens; + if (_projectLanguage == ProjectLanguage.VisualBasic) + { + _rulesAnalyzer = new VisualBasicRulesAnalysis(_sourceFileResults, rules.VisualBasicRootNodes, + ProjectConfiguration.ProjectType); + projectTokens = rules.VisualBasicRootNodes.ProjectTokens; + } + else + { + _rulesAnalyzer = new RulesAnalysis(_sourceFileResults, rules.CsharpRootNodes, ProjectConfiguration.ProjectType); + projectTokens = rules.CsharpRootNodes.ProjectTokens; + } + + _rulesAnalyzer = _projectLanguage == ProjectLanguage.VisualBasic + ? new VisualBasicRulesAnalysis(_sourceFileResults, + rules.VisualBasicRootNodes, + ProjectConfiguration.ProjectType) + : new + RulesAnalysis(_sourceFileResults, + rules.CsharpRootNodes, + ProjectConfiguration.ProjectType); + var projectActions = _rulesAnalyzer.Analyze(); CodeReplacer baseReplacer = new CodeReplacer(_sourceFileBuildResults, ProjectConfiguration, _metaReferences, _analyzerResult, _projectLanguage, updatedFiles, projectResult: _projectResult); _projectResult.ExecutedActions = baseReplacer.Run(projectActions, ProjectConfiguration.ProjectType); - ideFileActions = projectActions + List ideFileActions = projectActions .FileActions .SelectMany(f => f.NodeTokens.Select(n => new IDEFileActions() { TextSpan = n.TextSpan, Description = n.Description, FilePath = f.FilePath, TextChanges = n.TextChanges })) .ToList(); From 62d2afd3c3a32de9763d232229200578f8ebb0bf Mon Sep 17 00:00:00 2001 From: Chris Long Date: Thu, 23 Jun 2022 11:21:03 -0700 Subject: [PATCH 54/61] fix: add language field to action metric instead of appending vb to action name --- src/CTA.Rules.Metrics/Models/GenericActionMetric.cs | 10 ++++++++++ src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs b/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs index 008f8991..31f36247 100644 --- a/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs +++ b/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs @@ -28,6 +28,9 @@ public class GenericActionMetric : CTAMetric [JsonProperty("filePath", Order = 18)] public string FilePath { get; set; } + [JsonProperty("language", Order = 19)] + public string Language { get; set; } + public GenericActionMetric(MetricsContext context, GenericAction action, string filePath, string projectPath) { ActionName = action.Name; @@ -44,6 +47,13 @@ public GenericActionMetric(MetricsContext context, GenericAction action, string { FilePath = string.IsNullOrEmpty(filePath) ? "N/A" : EncryptionHelper.ConvertToSHA256Hex(filePath); } + + Language = GetLanguage(filePath); + } + + private string GetLanguage(string filePath) + { + return filePath.EndsWith(".cs") ? "csharp" : filePath.EndsWith(".vb") ? "vb" : "unknown"; } } } diff --git a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs index 2025d399..498a4bc2 100644 --- a/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs +++ b/src/CTA.Rules.RuleFiles/VisualBasicRulesFileParser.cs @@ -555,7 +555,7 @@ public void ParseActions(VisualBasicNodeToken visualBasicNodeToken, List dynamic value = action.VbValue ?? action.Value; ActionValidation validation = action.VbActionValidation ?? action.ActionValidation; - string vbActionName = "Vb" + action.Name; + string vbActionName = action.Name; switch (actionType) { From b18bdf2fc35b75859d1758405bc48e774f8b7c89 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Fri, 24 Jun 2022 11:13:51 -0700 Subject: [PATCH 55/61] fix: metrics test and get language from project file --- src/CTA.Rules.Metrics/Models/GenericActionMetric.cs | 4 ++-- .../PortSolutionResultReportGeneratorTests.cs | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs b/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs index 31f36247..fa51c76c 100644 --- a/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs +++ b/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs @@ -48,12 +48,12 @@ public GenericActionMetric(MetricsContext context, GenericAction action, string FilePath = string.IsNullOrEmpty(filePath) ? "N/A" : EncryptionHelper.ConvertToSHA256Hex(filePath); } - Language = GetLanguage(filePath); + Language = GetLanguage(projectPath); } private string GetLanguage(string filePath) { - return filePath.EndsWith(".cs") ? "csharp" : filePath.EndsWith(".vb") ? "vb" : "unknown"; + return filePath.EndsWith(".csproj") ? "csharp" : filePath.EndsWith(".vbproj") ? "vb" : "unknown"; } } } diff --git a/tst/CTA.Rules.Test/Metrics/PortSolutionResultReportGeneratorTests.cs b/tst/CTA.Rules.Test/Metrics/PortSolutionResultReportGeneratorTests.cs index fe443c4a..cbb56409 100644 --- a/tst/CTA.Rules.Test/Metrics/PortSolutionResultReportGeneratorTests.cs +++ b/tst/CTA.Rules.Test/Metrics/PortSolutionResultReportGeneratorTests.cs @@ -202,7 +202,8 @@ public void GenerateAnalysisReport() ""actionValue"": ""GA1 Value"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", ""projectGuid"": ""1234-5678"", - ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"" + ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"", + ""language"": ""csharp"" }, { ""metricsType"": ""CTA"", @@ -212,7 +213,8 @@ public void GenerateAnalysisReport() ""actionValue"": ""GA2 Value"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", ""projectGuid"": ""1234-5678"", - ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"" + ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"", + ""language"": ""csharp"" }, { ""metricsType"": ""CTA"", @@ -254,7 +256,8 @@ public void GenerateAnalysisReportWithFeatureDetection() ""actionValue"": ""GA1 Value"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", ""projectGuid"": ""1234-5678"", - ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"" + ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"", + ""language"": ""csharp"" }, { ""metricsType"": ""CTA"", @@ -264,7 +267,8 @@ public void GenerateAnalysisReportWithFeatureDetection() ""actionValue"": ""GA2 Value"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", ""projectGuid"": ""1234-5678"", - ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"" + ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"", + ""language"": ""csharp"" }, { ""metricsType"": ""CTA"", From 1cdb98ea3be6b97f677908dd4f8b9b7833d045a7 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Fri, 24 Jun 2022 21:09:37 -0700 Subject: [PATCH 56/61] fix: remove duplicate code --- .../ProjectRewriters/ProjectRewriter.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs index da07376f..5e074137 100644 --- a/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs +++ b/src/CTA.Rules.Update/ProjectRewriters/ProjectRewriter.cs @@ -110,8 +110,6 @@ public ProjectResult Initialize() projectTokens = projectRules.CsharpRootNodes.ProjectTokens; } - _rulesAnalyzer = _projectLanguage == ProjectLanguage.VisualBasic ? new VisualBasicRulesAnalysis(_sourceFileResults, projectRules.VisualBasicRootNodes, ProjectConfiguration.ProjectType) : new - RulesAnalysis(_sourceFileResults, projectRules.CsharpRootNodes, ProjectConfiguration.ProjectType); projectActions = _rulesAnalyzer.Analyze(); _projectReferences.ForEach(p => { @@ -186,14 +184,6 @@ public virtual List RunIncremental(List updatedFiles, Ro projectTokens = rules.CsharpRootNodes.ProjectTokens; } - _rulesAnalyzer = _projectLanguage == ProjectLanguage.VisualBasic - ? new VisualBasicRulesAnalysis(_sourceFileResults, - rules.VisualBasicRootNodes, - ProjectConfiguration.ProjectType) - : new - RulesAnalysis(_sourceFileResults, - rules.CsharpRootNodes, - ProjectConfiguration.ProjectType); var projectActions = _rulesAnalyzer.Analyze(); CodeReplacer baseReplacer = new CodeReplacer(_sourceFileBuildResults, ProjectConfiguration, _metaReferences, _analyzerResult, _projectLanguage, updatedFiles, projectResult: _projectResult); From 5feb0f3a6c86127138210a457e393fd556ce7eb5 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Sat, 25 Jun 2022 14:32:56 -0700 Subject: [PATCH 57/61] test: more tests for code coverage --- .../VisualBasic/TypeBlockActions.cs | 7 +- tst/CTA.Rules.Test/CTA.Rules.Test.csproj | 3 + .../CTAFiles/vb.rules.test.json | 167 ++++++++++++++++++ .../VisualBasicRulesLoaderTest.cs | 39 ++++ tst/CTA.Rules.Test/VisualBasicTests.cs | 31 +++- 5 files changed, 237 insertions(+), 10 deletions(-) create mode 100644 tst/CTA.Rules.Test/CTAFiles/vb.rules.test.json create mode 100644 tst/CTA.Rules.Test/VisualBasicRulesLoaderTest.cs diff --git a/src/CTA.Rules.Actions/VisualBasic/TypeBlockActions.cs b/src/CTA.Rules.Actions/VisualBasic/TypeBlockActions.cs index 47aecf12..57d6f8ee 100644 --- a/src/CTA.Rules.Actions/VisualBasic/TypeBlockActions.cs +++ b/src/CTA.Rules.Actions/VisualBasic/TypeBlockActions.cs @@ -464,7 +464,12 @@ TypeBlockSyntax AddParametersToMethod(SyntaxGenerator syntaxGenerator, TypeBlock public Func GetReplaceMvcControllerMethodsBodyAction(string expression) { - throw new NotImplementedException(); + TypeBlockSyntax ReplaceMvcControllerMethodsBodyFunc(SyntaxGenerator syntaxGenerator, TypeBlockSyntax node) + { + return node; + } + + return ReplaceMvcControllerMethodsBodyFunc; } public Func GetReplaceWebApiControllerMethodsBodyAction(string expression) diff --git a/tst/CTA.Rules.Test/CTA.Rules.Test.csproj b/tst/CTA.Rules.Test/CTA.Rules.Test.csproj index 3d043628..d716884f 100644 --- a/tst/CTA.Rules.Test/CTA.Rules.Test.csproj +++ b/tst/CTA.Rules.Test/CTA.Rules.Test.csproj @@ -31,6 +31,9 @@ + + PreserveNewest + diff --git a/tst/CTA.Rules.Test/CTAFiles/vb.rules.test.json b/tst/CTA.Rules.Test/CTAFiles/vb.rules.test.json new file mode 100644 index 00000000..75fc5589 --- /dev/null +++ b/tst/CTA.Rules.Test/CTAFiles/vb.rules.test.json @@ -0,0 +1,167 @@ +{ + "Name": "VbWebApi", + "Version": "1.0.0", + "Packages": [ + { + "Name": "VbWebApi", + "Type": "Project" + } + ], + "Recommendations": [ + { + "Type": "ElementAccess", + "Name": "MigrateShoppingCart", + "Value": "MvcMusicStore.Controllers.AccountController.MigrateShoppingCart", + "RecommendedActions": [ + { + "Source": "Amazon", + "Preferred": "Yes", + "TargetFrameworks": [ + { + "Name": "netcoreapp3.1", + "TargetCPU": [ "x86", "x64", "ARM64" ] + }, + { + "Name": "net5.0", + "TargetCPU": [ "x86", "x64", "ARM64" ] + } + ], + "Description": "Add a comment", + "Actions": [ + { + "Name": "AddComment", + "Type": "ElementAccess", + "Value": "The text of the comment", + "Description": "Add a comment to an element access statement" + } + ] + } + ] + }, + { + "Type": "Namespace", + "Name": "MvcMusicStore.ViewModels", + "Value": "MvcMusicStore.ViewModels", + "KeyType": "Name", + "ContainingType": "", + "RecommendedActions": [ + { + "Source": "Amazon", + "Preferred": "Yes", + "TargetFrameworks": [ + { + "Name": "netcoreapp3.1", + "TargetCPU": [ "x86", "x64", "ARM64" ] + }, + { + "Name": "net5.0", + "TargetCPU": [ "x86", "x64", "ARM64" ] + } + ], + "Description": "Replace namespacee with a new namespace", + "Actions": [ + { + "Name": "RenameNamespace", + "Type": "Namespace", + "Value": "MvcMusicStore.ChangedViewModels", + "Description": "Replace namespace with a new namespace", + "ActionValidation": { + "Contains": "notvalid;", + "NotContains": "notvalidtoo" + } + } + ] + } + ] + }, + { + "Type": "MethodDeclaration", + "Name": "MigrateShoppingCart", + "Value": "MvcMusicStore.Controllers.AccountController.MigrateShoppingCart", + "RecommendedActions": [ + { + "Source": "Amazon", + "Preferred": "Yes", + "TargetFrameworks": [ + { + "Name": "netcoreapp3.1", + "TargetCPU": [ "x86", "x64", "ARM64" ] + }, + { + "Name": "net5.0", + "TargetCPU": [ "x86", "x64", "ARM64" ] + } + ], + "Description": "Add a comment", + "Actions": [ + { + "Name": "AddComment", + "Type": "MethodDeclaration", + "Value": "The text of the comment", + "Description": "Add a comment to a method declaration" + } + ] + } + ] + }, + { + "Type": "Attribute", + "Name": "RoutePrefix", + "Value": "System.Web.Http.RoutePrefixAttribute.RoutePrefixAttribute(string)", + "KeyType": "Name", + "ContainingType": "RoutePrefixAttribute", + "RecommendedActions": [ + { + "Source": "Amazon", + "Preferred": "Yes", + "TargetFrameworks": [ + { + "Name": "netcoreapp3.1", + "TargetCPU": [ + "x86", + "x64", + "ARM32", + "ARM64" + ] + }, + { + "Name": "net5.0", + "TargetCPU": [ + "x86", + "x64", + "ARM32", + "ARM64" + ] + }, + { + "Name": "net6.0", + "TargetCPU": [ + "x86", + "x64", + "ARM32", + "ARM64" + ] + } + ], + "Description": "Add a comment: RoutePrefix attribute is no longer supported.", + "Actions": [ + { + "Name": "AddComment", + "Type": "AttributeList", + "Value": { + "comment": "RoutePrefix attribute is no longer supported", + "dontUseCTAPrefix": "" + }, + "Description": "RoutePrefix attribute is no longer supported", + "ActionValidation": { + "Contains": "RoutePrefix attribute is no longer supported", + "NotContains": "", + "CheckComments": "True" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/tst/CTA.Rules.Test/VisualBasicRulesLoaderTest.cs b/tst/CTA.Rules.Test/VisualBasicRulesLoaderTest.cs new file mode 100644 index 00000000..4b3f96e2 --- /dev/null +++ b/tst/CTA.Rules.Test/VisualBasicRulesLoaderTest.cs @@ -0,0 +1,39 @@ +using System.IO; +using System.Reflection; +using CTA.Rules.Config; +using CTA.Rules.RuleFiles; +using NUnit.Framework; +using Newtonsoft.Json; + +namespace CTA.Rules.Test; + +public class VisualBasicRulesLoaderTest : AwsRulesBaseTest +{ + [Test] + public void TestRulesFileParser() + { + var ctaFilesDir = Path.GetFullPath(Path.Combine(Path.GetDirectoryName( + Assembly.GetExecutingAssembly().Location), + "CTAFiles")); + var rootObject = JsonConvert.DeserializeObject( + File.ReadAllText(Path.Combine(ctaFilesDir, + "consolidated.json"))); + + var overrideObject = JsonConvert.DeserializeObject( + File.ReadAllText(Path.Combine(ctaFilesDir, "project.specific.json"))); + + var namespaceRecommendations = JsonConvert.DeserializeObject( + File.ReadAllText(Path.Combine(ctaFilesDir, + "vb.rules.test.json"))); + + var fileParser = new VisualBasicRulesFileParser( + namespaceRecommendations, + new NamespaceRecommendations(), + rootObject, + overrideObject, + "", + "netcoreapp3.1"); + var nodes = fileParser.Process(); + Assert.IsNotNull(nodes); + } +} \ No newline at end of file diff --git a/tst/CTA.Rules.Test/VisualBasicTests.cs b/tst/CTA.Rules.Test/VisualBasicTests.cs index 9b574e97..7fc10fc5 100644 --- a/tst/CTA.Rules.Test/VisualBasicTests.cs +++ b/tst/CTA.Rules.Test/VisualBasicTests.cs @@ -15,22 +15,25 @@ namespace CTA.Rules.Test { internal class VisualBasicTests : AwsRulesBaseTest { - public string downloadLocation; - public List ctaFiles; - public string version = "net5.0"; //We don't care about version for CTA-only rules: + private string _tempDir; + private string _downloadLocation; + private List _ctaFiles; + private readonly string _version = "net5.0"; + //We don't care about version for CTA-only rules: [SetUp] public void Setup() { - downloadLocation = SetupTests.DownloadLocation; - ctaFiles = Directory.EnumerateFiles(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "CTAFiles")), "*.json") + _tempDir = SetupTests.TempDir; + _downloadLocation = SetupTests.DownloadLocation; + _ctaFiles = Directory.EnumerateFiles(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "CTAFiles")), "*.json") .Select(s => Path.GetFileNameWithoutExtension(s)) .ToList(); } private TestSolutionAnalysis runCTAFile(string solutionName, string projectName = null) { - var solutionPath = CopySolutionFolderToTemp(solutionName, downloadLocation); + var solutionPath = CopySolutionFolderToTemp(solutionName, _downloadLocation); var solutionDir = Directory.GetParent(solutionPath).FullName; FileAssert.Exists(solutionPath); @@ -43,9 +46,9 @@ private TestSolutionAnalysis runCTAFile(string solutionName, string projectName { SolutionPath = solutionPath, ProjectPath = projectFile, - TargetVersions = new List { version }, + TargetVersions = new List { _version }, RulesDir = Constants.RulesDefaultPath, - AdditionalReferences = ctaFiles + AdditionalReferences = _ctaFiles }; List solutionConfiguration = new List @@ -111,10 +114,20 @@ public void TestOwinParadiseVb() StringAssert.Contains("UseEndpoints", signalR); } + [Test] public void TestVbNetMvc() { - var results = runCTAFile("VBNetMvc.sln").ProjectResults.FirstOrDefault(); + var results = AnalyzeSolution("VBNetMvc.sln", + _tempDir, + _downloadLocation, + _version) + .ProjectResults.FirstOrDefault(); // Check that nothing is ported. + + // uncomment once template in datastore is merged. + // StringAssert.Contains( + // "v4.7.2", + // results.CsProjectContent); } } } From b88bda8e991920e9f1e482f1e23ee4443d00daa6 Mon Sep 17 00:00:00 2001 From: dongzw-amz Date: Mon, 27 Jun 2022 09:15:05 -0700 Subject: [PATCH 58/61] Added test for webapi solution --- tst/CTA.Rules.Test/CTATests.cs | 43 ++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tst/CTA.Rules.Test/CTATests.cs b/tst/CTA.Rules.Test/CTATests.cs index aeb4956b..9f10c300 100644 --- a/tst/CTA.Rules.Test/CTATests.cs +++ b/tst/CTA.Rules.Test/CTATests.cs @@ -241,6 +241,49 @@ public void ConvertHierarchicalToNamespaceFile() FileAssert.Exists(Path.Combine(dir, "system.web.mvc.json")); } + [Test] + public void VBTestWebApiSolution() + { + var results = runCTAFile("VBWebApi.sln").ProjectResults.FirstOrDefault(); + Assert.IsTrue(results != null); + StringAssert.Contains("Create service class.", results.ProjectAnalysisResult); + + var homeControllerText = File.ReadAllText(Path.Combine(results.ProjectDirectory, "Controllers", "HomeController.vb")); + var valuesControllerText = File.ReadAllText(Path.Combine(results.ProjectDirectory, "Controllers", "ValuesController.vb")); + + //Check that attribute has been added to class and inherits has been added: + StringAssert.Contains(@"Public Class HomeController", homeControllerText); + StringAssert.Contains(@"Inherits", homeControllerText); + StringAssert.Contains(@"End Class", homeControllerText); + + //Check that function has been added to class: + StringAssert.Contains(@"Function", homeControllerText); + StringAssert.Contains(@"End Function", homeControllerText); + + //Check that identifier as replaced: + StringAssert.Contains(@"As ActionResult", homeControllerText); + + //Check that import statement has been added: + StringAssert.Contains(@"Imports System.Net", valuesControllerText); + + //Check that attribute has been added to class and inherits has been added: + StringAssert.Contains(@"Public Class ValuesController", valuesControllerText); + StringAssert.Contains(@"ByVal id As Integer", valuesControllerText); + StringAssert.Contains(@"Inherits", valuesControllerText); + StringAssert.Contains(@"End Class", valuesControllerText); + + //Check that function has been added to class: + StringAssert.Contains(@"Function", valuesControllerText); + StringAssert.Contains(@"End Function", valuesControllerText); + + //Check that sub statement has been added to class: + StringAssert.Contains(@"Public Sub", valuesControllerText); + StringAssert.Contains(@"End Sub", valuesControllerText); + + //Check that identifier as replaced: + StringAssert.Contains(@"As String", valuesControllerText); + } + [Test] public void LoggerTest() { From 30a84a93d97332aa4f780f44caa7c553947e3531 Mon Sep 17 00:00:00 2001 From: Chris Long Date: Mon, 27 Jun 2022 14:51:22 -0700 Subject: [PATCH 59/61] fix: issues from code reivew remove comment, add string comparison to vb project check and add test case --- src/CTA.Rules.Actions/VisualBasic/ElementAccessActions.cs | 1 - src/CTA.Rules.Common/Utils/VisualBasicUtils.cs | 4 ++-- tst/CTA.Rules.Test/UtilsTest.cs | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CTA.Rules.Actions/VisualBasic/ElementAccessActions.cs b/src/CTA.Rules.Actions/VisualBasic/ElementAccessActions.cs index dd75d01d..aed80102 100644 --- a/src/CTA.Rules.Actions/VisualBasic/ElementAccessActions.cs +++ b/src/CTA.Rules.Actions/VisualBasic/ElementAccessActions.cs @@ -25,7 +25,6 @@ MemberAccessExpressionSyntax AddComment(SyntaxGenerator syntaxGenerator, MemberA } public Func GetReplaceElementAccessAction(string newExpression) { - // todo: for VB rules that invoke this action probably need to be converted to invocation expressions because MemberAccessExpressionSyntax ReplaceElement(SyntaxGenerator syntaxGenerator, MemberAccessExpressionSyntax node) { var addCommentFunc = GetAddCommentAction($"Replace with {newExpression}"); diff --git a/src/CTA.Rules.Common/Utils/VisualBasicUtils.cs b/src/CTA.Rules.Common/Utils/VisualBasicUtils.cs index 70e83c81..135b361d 100644 --- a/src/CTA.Rules.Common/Utils/VisualBasicUtils.cs +++ b/src/CTA.Rules.Common/Utils/VisualBasicUtils.cs @@ -1,4 +1,4 @@ - +using System; namespace CTA.Rules.Common.Helpers { @@ -11,7 +11,7 @@ public class VisualBasicUtils /// True if the file path contains the visual basic project extension public static bool IsVisualBasicProject(string projectFilePath) { - return projectFilePath.Contains("vbproj"); + return projectFilePath.EndsWith(".vbproj", StringComparison.InvariantCultureIgnoreCase); } } } diff --git a/tst/CTA.Rules.Test/UtilsTest.cs b/tst/CTA.Rules.Test/UtilsTest.cs index a8e526a6..7f0a5750 100644 --- a/tst/CTA.Rules.Test/UtilsTest.cs +++ b/tst/CTA.Rules.Test/UtilsTest.cs @@ -119,6 +119,7 @@ public void Test_Is_VisualBasic_Project() { Assert.IsFalse(VisualBasicUtils.IsVisualBasicProject("test.csproj")); Assert.IsTrue(VisualBasicUtils.IsVisualBasicProject("C://user/john/repos/test.vbproj")); + Assert.IsFalse(VisualBasicUtils.IsVisualBasicProject("vbprojproject.cs")); } } } \ No newline at end of file From 9808daac8eb1371f692a75c181369fffa71fdccb Mon Sep 17 00:00:00 2001 From: Chris Long Date: Mon, 27 Jun 2022 16:28:00 -0700 Subject: [PATCH 60/61] add language to other relevant cta metrics --- .../Models/ActionPackageMetric.cs | 1 + .../Models/BuildErrorMetric.cs | 1 + src/CTA.Rules.Metrics/Models/CTAMetric.cs | 17 ++++++++++++++++- .../Models/FeatureDetectionMetric.cs | 1 + .../Models/GenericActionExecutionMetric.cs | 1 + .../Models/GenericActionMetric.cs | 9 +-------- .../Models/MissingMetaReferenceMetric.cs | 1 + .../Models/TargetVersionMetric.cs | 1 + .../Models/UpgradePackageMetric.cs | 1 + .../Models/WebForms/WebFormsActionMetric.cs | 1 + 10 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/CTA.Rules.Metrics/Models/ActionPackageMetric.cs b/src/CTA.Rules.Metrics/Models/ActionPackageMetric.cs index e7bea90d..f5474215 100644 --- a/src/CTA.Rules.Metrics/Models/ActionPackageMetric.cs +++ b/src/CTA.Rules.Metrics/Models/ActionPackageMetric.cs @@ -27,6 +27,7 @@ public ActionPackageMetric(MetricsContext context, PackageAction packageAction, PackageVersion = packageAction.Version; SolutionPathHash = context.SolutionPathHash; ProjectGuid = context.ProjectGuidMap.GetValueOrDefault(projectPath, "N/A"); + Language = GetLanguage(projectPath); } } } diff --git a/src/CTA.Rules.Metrics/Models/BuildErrorMetric.cs b/src/CTA.Rules.Metrics/Models/BuildErrorMetric.cs index 941e74db..c7bb4aab 100644 --- a/src/CTA.Rules.Metrics/Models/BuildErrorMetric.cs +++ b/src/CTA.Rules.Metrics/Models/BuildErrorMetric.cs @@ -37,6 +37,7 @@ public BuildErrorMetric(MetricsContext context, string buildError, int count, st Count = count; SolutionPathHash = context.SolutionPathHash; ProjectGuid = context.ProjectGuidMap.GetValueOrDefault(projectPath, "N/A"); + Language = GetLanguage(projectPath); } private string ExtractBuildErrorCode(string buildError) diff --git a/src/CTA.Rules.Metrics/Models/CTAMetric.cs b/src/CTA.Rules.Metrics/Models/CTAMetric.cs index 4f3b28ca..a813c034 100644 --- a/src/CTA.Rules.Metrics/Models/CTAMetric.cs +++ b/src/CTA.Rules.Metrics/Models/CTAMetric.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; namespace CTA.Rules.Metrics { @@ -6,5 +7,19 @@ public abstract class CTAMetric { [JsonProperty("metricsType", Order = 1)] public string MetricsType => "CTA"; + + [JsonProperty("language", Order = 2)] + public string Language { get; set; } + + protected static string GetLanguage(string projectPath) + { + return projectPath.EndsWith(".csproj", + StringComparison.InvariantCultureIgnoreCase) + ? "csharp" + : projectPath.EndsWith(".vbproj", + StringComparison.InvariantCultureIgnoreCase) + ? "visualbasic" + : "unknown"; + } } } diff --git a/src/CTA.Rules.Metrics/Models/FeatureDetectionMetric.cs b/src/CTA.Rules.Metrics/Models/FeatureDetectionMetric.cs index a1d9fcec..bdc4b338 100644 --- a/src/CTA.Rules.Metrics/Models/FeatureDetectionMetric.cs +++ b/src/CTA.Rules.Metrics/Models/FeatureDetectionMetric.cs @@ -22,6 +22,7 @@ public FeatureDetectionMetric(MetricsContext context, string featureName, string FeatureName = featureName; SolutionPath = context.SolutionPathHash; ProjectGuid = context.ProjectGuidMap.GetValueOrDefault(projectPath, "N/A"); + Language = GetLanguage(projectPath); } } } diff --git a/src/CTA.Rules.Metrics/Models/GenericActionExecutionMetric.cs b/src/CTA.Rules.Metrics/Models/GenericActionExecutionMetric.cs index b1f11c4f..0399fc16 100644 --- a/src/CTA.Rules.Metrics/Models/GenericActionExecutionMetric.cs +++ b/src/CTA.Rules.Metrics/Models/GenericActionExecutionMetric.cs @@ -52,6 +52,7 @@ public GenericActionExecutionMetric(MetricsContext context, GenericActionExecuti { FilePath = string.IsNullOrEmpty(action.FilePath) ? "N/A" : EncryptionHelper.ConvertToSHA256Hex(action.FilePath); } + Language = GetLanguage(projectPath); } } } diff --git a/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs b/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs index fa51c76c..dc346b26 100644 --- a/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs +++ b/src/CTA.Rules.Metrics/Models/GenericActionMetric.cs @@ -28,9 +28,6 @@ public class GenericActionMetric : CTAMetric [JsonProperty("filePath", Order = 18)] public string FilePath { get; set; } - [JsonProperty("language", Order = 19)] - public string Language { get; set; } - public GenericActionMetric(MetricsContext context, GenericAction action, string filePath, string projectPath) { ActionName = action.Name; @@ -47,13 +44,9 @@ public GenericActionMetric(MetricsContext context, GenericAction action, string { FilePath = string.IsNullOrEmpty(filePath) ? "N/A" : EncryptionHelper.ConvertToSHA256Hex(filePath); } - Language = GetLanguage(projectPath); } - private string GetLanguage(string filePath) - { - return filePath.EndsWith(".csproj") ? "csharp" : filePath.EndsWith(".vbproj") ? "vb" : "unknown"; - } + } } diff --git a/src/CTA.Rules.Metrics/Models/MissingMetaReferenceMetric.cs b/src/CTA.Rules.Metrics/Models/MissingMetaReferenceMetric.cs index 166716f4..9ded1784 100644 --- a/src/CTA.Rules.Metrics/Models/MissingMetaReferenceMetric.cs +++ b/src/CTA.Rules.Metrics/Models/MissingMetaReferenceMetric.cs @@ -24,6 +24,7 @@ public MissingMetaReferenceMetric(MetricsContext context, string metaReference, MetaReference = metaReference; SolutionPathHash = context.SolutionPathHash; ProjectGuid = context.ProjectGuidMap.GetValueOrDefault(projectPath, "N/A"); + Language = GetLanguage(projectPath); } } } diff --git a/src/CTA.Rules.Metrics/Models/TargetVersionMetric.cs b/src/CTA.Rules.Metrics/Models/TargetVersionMetric.cs index 5e1c064c..14cd53ba 100644 --- a/src/CTA.Rules.Metrics/Models/TargetVersionMetric.cs +++ b/src/CTA.Rules.Metrics/Models/TargetVersionMetric.cs @@ -26,6 +26,7 @@ public TargetVersionMetric(MetricsContext context, string targetVersion, string SourceVersion = sourceVersion; SolutionPathHash = context.SolutionPathHash; ProjectGuid = context.ProjectGuidMap.GetValueOrDefault(projectPath, "N/A"); + Language = GetLanguage(projectPath); } } } diff --git a/src/CTA.Rules.Metrics/Models/UpgradePackageMetric.cs b/src/CTA.Rules.Metrics/Models/UpgradePackageMetric.cs index 55aecc5e..973a9064 100644 --- a/src/CTA.Rules.Metrics/Models/UpgradePackageMetric.cs +++ b/src/CTA.Rules.Metrics/Models/UpgradePackageMetric.cs @@ -31,6 +31,7 @@ public UpgradePackageMetric(MetricsContext context, PackageAction packageAction, PackageOriginalVersion = packageAction.OriginalVersion; SolutionPathHash = context.SolutionPathHash; ProjectGuid = context.ProjectGuidMap.GetValueOrDefault(projectPath, "N/A"); + Language = GetLanguage(projectPath); } } } diff --git a/src/CTA.Rules.Metrics/Models/WebForms/WebFormsActionMetric.cs b/src/CTA.Rules.Metrics/Models/WebForms/WebFormsActionMetric.cs index 575d6232..611003d5 100644 --- a/src/CTA.Rules.Metrics/Models/WebForms/WebFormsActionMetric.cs +++ b/src/CTA.Rules.Metrics/Models/WebForms/WebFormsActionMetric.cs @@ -28,6 +28,7 @@ public WebFormsActionMetric(MetricsContext context, string childActionName, stri ChildActionName = childActionName; SolutionPathHash = context.SolutionPathHash; ProjectGuid = context.ProjectGuidMap.GetValueOrDefault(projectPath, "N/A"); + Language = GetLanguage(projectPath); } } } From 9efb63c0df66502d519e9932f78597ecea63861f Mon Sep 17 00:00:00 2001 From: Chris Long Date: Mon, 27 Jun 2022 17:14:55 -0700 Subject: [PATCH 61/61] update metrics tests --- .../PortSolutionResultReportGeneratorTests.cs | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/tst/CTA.Rules.Test/Metrics/PortSolutionResultReportGeneratorTests.cs b/tst/CTA.Rules.Test/Metrics/PortSolutionResultReportGeneratorTests.cs index cbb56409..2c6c4dc6 100644 --- a/tst/CTA.Rules.Test/Metrics/PortSolutionResultReportGeneratorTests.cs +++ b/tst/CTA.Rules.Test/Metrics/PortSolutionResultReportGeneratorTests.cs @@ -187,6 +187,7 @@ public void GenerateAnalysisReport() var expectedAnalysisReport = @"[ { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""UpgradePackage"", ""packageName"": ""Newtonsoft.Json"", ""packageVersion"": ""12.0.0"", @@ -196,28 +197,29 @@ public void GenerateAnalysisReport() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""GenericAction"", ""actionName"": ""GA1 Name"", ""actionType"": ""GA1 Type"", ""actionValue"": ""GA1 Value"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", ""projectGuid"": ""1234-5678"", - ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"", - ""language"": ""csharp"" + ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"" }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""GenericAction"", ""actionName"": ""GA2 Name"", ""actionType"": ""GA2 Type"", ""actionValue"": ""GA2 Value"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", ""projectGuid"": ""1234-5678"", - ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"", - ""language"": ""csharp"" + ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"" }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""MissingMetaReference"", ""metaReference"": ""C://reference1.dll"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", @@ -225,6 +227,7 @@ public void GenerateAnalysisReport() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""MissingMetaReference"", ""metaReference"": ""C://reference2.dll"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", @@ -241,6 +244,7 @@ public void GenerateAnalysisReportWithFeatureDetection() var expectedAnalysisReport = @"[ { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""UpgradePackage"", ""packageName"": ""Newtonsoft.Json"", ""packageVersion"": ""12.0.0"", @@ -250,28 +254,29 @@ public void GenerateAnalysisReportWithFeatureDetection() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""GenericAction"", ""actionName"": ""GA1 Name"", ""actionType"": ""GA1 Type"", ""actionValue"": ""GA1 Value"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", ""projectGuid"": ""1234-5678"", - ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"", - ""language"": ""csharp"" + ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"" }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""GenericAction"", ""actionName"": ""GA2 Name"", ""actionType"": ""GA2 Type"", ""actionValue"": ""GA2 Value"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", ""projectGuid"": ""1234-5678"", - ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"", - ""language"": ""csharp"" + ""filePath"": ""eb98c1d648bc61064bdeaca9523a49e51bb3312f28f59376fb385e1569c77822"" }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""DetectedFeature"", ""featureName"": ""Feature 1"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", @@ -279,6 +284,7 @@ public void GenerateAnalysisReportWithFeatureDetection() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""DetectedFeature"", ""featureName"": ""Feature 1a"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", @@ -286,6 +292,7 @@ public void GenerateAnalysisReportWithFeatureDetection() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""MissingMetaReference"", ""metaReference"": ""C://reference1.dll"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", @@ -293,6 +300,7 @@ public void GenerateAnalysisReportWithFeatureDetection() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""MissingMetaReference"", ""metaReference"": ""C://reference2.dll"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", @@ -389,24 +397,28 @@ public void GenerateAndExportReports_Creates_Expected_Json_Report() var expectedJsonReport = @"[ { ""metricsType"": ""CTA"", + ""language"": null, ""metricName"": ""Namespace"", ""reference"": ""System.Web"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"" }, { ""metricsType"": ""CTA"", + ""language"": null, ""metricName"": ""Namespace"", ""reference"": ""System.Web.Mvc"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"" }, { ""metricsType"": ""CTA"", + ""language"": null, ""metricName"": ""RulesFile"", ""downloadedFile"": ""project.all.json"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"" }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""TargetVersion"", ""targetVersion"": ""netcoreapp3.1"", ""sourceVersion"": ""net48"", @@ -415,6 +427,7 @@ public void GenerateAndExportReports_Creates_Expected_Json_Report() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""UpgradePackage"", ""packageName"": ""Newtonsoft.Json"", ""packageVersion"": ""12.0.0"", @@ -424,6 +437,7 @@ public void GenerateAndExportReports_Creates_Expected_Json_Report() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""ActionExecution"", ""actionName"": ""GA1 Name"", ""actionType"": ""GA1 Type"", @@ -436,6 +450,7 @@ public void GenerateAndExportReports_Creates_Expected_Json_Report() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""ActionExecution"", ""actionName"": ""GA2 Name"", ""actionType"": ""GA2 Type"", @@ -448,6 +463,7 @@ public void GenerateAndExportReports_Creates_Expected_Json_Report() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""BuildError"", ""buildErrorCode"": ""CS0000"", ""buildError"": ""CS0000: BuildError1"", @@ -457,6 +473,7 @@ public void GenerateAndExportReports_Creates_Expected_Json_Report() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""BuildError"", ""buildErrorCode"": ""OTHER"", ""buildError"": ""BuildError2"", @@ -466,6 +483,7 @@ public void GenerateAndExportReports_Creates_Expected_Json_Report() }, { ""metricsType"": ""CTA"", + ""language"": ""unknown"", ""metricName"": ""BuildError"", ""buildErrorCode"": ""OTHER"", ""buildError"": ""BuildError3"", @@ -475,6 +493,7 @@ public void GenerateAndExportReports_Creates_Expected_Json_Report() }, { ""metricsType"": ""CTA"", + ""language"": ""unknown"", ""metricName"": ""BuildError"", ""buildErrorCode"": ""OTHER"", ""buildError"": ""BuildError4"", @@ -484,6 +503,7 @@ public void GenerateAndExportReports_Creates_Expected_Json_Report() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""MissingMetaReference"", ""metaReference"": ""C://reference1.dll"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"", @@ -491,6 +511,7 @@ public void GenerateAndExportReports_Creates_Expected_Json_Report() }, { ""metricsType"": ""CTA"", + ""language"": ""csharp"", ""metricName"": ""MissingMetaReference"", ""metaReference"": ""C://reference2.dll"", ""solutionPath"": ""5fa9de0cb5af2d468dfb1702b1e342f47de2df9a195dabb3be2d04f9c2767482"",