-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
imp - Used analyzer code to revamp cleaner
--- We've used analyzer code from the string analyzer to make a cleaner. --- Type: imp Breaking: False Doc Required: False Backport Required: False Part: 1/1
- Loading branch information
Showing
8 changed files
with
581 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// | ||
// Nitrocid KS Copyright (C) 2018-2024 Aptivi | ||
// | ||
// This file is part of Nitrocid KS | ||
// | ||
// Nitrocid KS is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Nitrocid KS is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY, without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
// | ||
|
||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Nitrocid.LocaleClean.Analyzers | ||
{ | ||
internal interface IAnalyzer | ||
{ | ||
bool Analyze(Document document, out string[] localized); | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
private/Nitrocid.LocaleClean/Analyzers/LocalizableResourcesAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// | ||
// Nitrocid KS Copyright (C) 2018-2024 Aptivi | ||
// | ||
// This file is part of Nitrocid KS | ||
// | ||
// Nitrocid KS is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Nitrocid KS is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY, without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
// | ||
|
||
using Newtonsoft.Json; | ||
using Newtonsoft.Json.Linq; | ||
using Nitrocid.LocaleClean; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Terminaux.Colors.Data; | ||
using Terminaux.Writer.ConsoleWriters; | ||
using Terminaux.Writer.MiscWriters; | ||
|
||
namespace Nitrocid.LocaleClean.Analyzers | ||
{ | ||
internal static class LocalizableResourcesAnalyzer | ||
{ | ||
internal static string[] GetLocalizedStrings() | ||
{ | ||
List<string> localizedStrings = []; | ||
|
||
// Open every resource except the English translations file | ||
var resourceNames = EntryPoint.thisAssembly.GetManifestResourceNames().Except([ | ||
"Nitrocid.LocaleClean.eng.json", | ||
]); | ||
foreach (var resourceName in resourceNames) | ||
{ | ||
// Open the resource and load it to a JSON token instance | ||
var stream = EntryPoint.thisAssembly.GetManifestResourceStream(resourceName) ?? | ||
throw new Exception($"Opening the {resourceName} resource stream has failed."); | ||
var reader = new StreamReader(stream); | ||
var jsonReader = new JsonTextReader(reader); | ||
var document = JToken.Load(jsonReader) ?? | ||
throw new Exception($"Unable to parse JSON for {resourceName}."); | ||
|
||
// Determine if this is a theme or a settings entries list | ||
var themeMetadata = document.Type == JTokenType.Array ? null : document["Metadata"]; | ||
if (themeMetadata is not null) | ||
{ | ||
// It's a theme. Get its description and its localizable boolean value | ||
string description = ((string?)themeMetadata["Description"] ?? "").Replace("\\\"", "\""); | ||
bool localizable = (bool?)themeMetadata["Localizable"] ?? false; | ||
if (!string.IsNullOrEmpty(description) && localizable && EntryPoint.localizationList.Contains(description)) | ||
localizedStrings.Add(description); | ||
} | ||
else if (document.Type == JTokenType.Array) | ||
{ | ||
// It's likely a settings entry list, but verify | ||
foreach (var settingsEntryList in document) | ||
{ | ||
// Check the description and the display | ||
string description = ((string?)settingsEntryList["Desc"] ?? "").Replace("\\\"", "\""); | ||
string displayAs = ((string?)settingsEntryList["DisplayAs"] ?? "").Replace("\\\"", "\""); | ||
if (!string.IsNullOrEmpty(description) && EntryPoint.localizationList.Contains(description)) | ||
localizedStrings.Add(description); | ||
if (!string.IsNullOrEmpty(displayAs) && EntryPoint.localizationList.Contains(displayAs)) | ||
localizedStrings.Add(displayAs); | ||
|
||
// Now, check the keys | ||
JArray? keys = (JArray?)settingsEntryList["Keys"]; | ||
if (keys is null || keys.Count == 0) | ||
continue; | ||
foreach (var key in keys) | ||
{ | ||
string keyName = ((string?)key["Name"] ?? "").Replace("\\\"", "\""); | ||
string keyDesc = ((string?)key["Description"] ?? "").Replace("\\\"", "\""); | ||
if (!string.IsNullOrEmpty(keyName) && EntryPoint.localizationList.Contains(keyName)) | ||
localizedStrings.Add(keyName); | ||
if (!string.IsNullOrEmpty(keyDesc) && EntryPoint.localizationList.Contains(keyDesc)) | ||
localizedStrings.Add(keyDesc); | ||
} | ||
} | ||
} | ||
} | ||
return [.. localizedStrings]; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// | ||
// Nitrocid KS Copyright (C) 2018-2024 Aptivi | ||
// | ||
// This file is part of Nitrocid KS | ||
// | ||
// Nitrocid KS is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Nitrocid KS is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY, without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
// | ||
|
||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Terminaux.Colors.Data; | ||
using Terminaux.Writer.ConsoleWriters; | ||
using Terminaux.Writer.MiscWriters; | ||
|
||
namespace Nitrocid.LocaleClean.Analyzers | ||
{ | ||
internal class ReverseNLOC0001 : IAnalyzer | ||
{ | ||
public bool Analyze(Document document, out string[] localized) | ||
{ | ||
localized = []; | ||
var tree = document.GetSyntaxTreeAsync().Result; | ||
if (tree is null) | ||
return false; | ||
var syntaxNodeNodes = tree.GetRoot().DescendantNodesAndSelf().OfType<SyntaxNode>().ToList(); | ||
bool found = false; | ||
List<string> localizedStrings = []; | ||
foreach (var syntaxNode in syntaxNodeNodes) | ||
{ | ||
// Check for argument | ||
if (syntaxNode is not InvocationExpressionSyntax exp) | ||
continue; | ||
var args = exp.ArgumentList.Arguments; | ||
if (args.Count < 1) | ||
continue; | ||
var localizableStringArgument = args[0] ?? | ||
throw new Exception("Can't get localizable string"); | ||
|
||
// Now, check for the Translate.DoTranslation() call | ||
if (exp.Expression is not MemberAccessExpressionSyntax expMaes) | ||
continue; | ||
if (expMaes.Expression is IdentifierNameSyntax expIdentifier && expMaes.Name is IdentifierNameSyntax identifier) | ||
{ | ||
// Verify that we're dealing with Translate.DoTranslation() | ||
var location = syntaxNode.GetLocation(); | ||
var idExpression = expIdentifier.Identifier.Text; | ||
var idName = identifier.Identifier.Text; | ||
if (idExpression == "Translate" && idName == "DoTranslation") | ||
{ | ||
// Now, get the string representation from the argument count and compare it with the list of translations. | ||
// You'll notice that we sometimes call Translate.DoTranslation() with a variable instead of a string, so | ||
// check that first, because they're usually obtained from a string representation usually prefixed with | ||
// either the /* Localizable */ comment or in individual kernel resources. However, the resources don't | ||
// have a prefix, so the key names alone are enough. | ||
if (localizableStringArgument.Expression is LiteralExpressionSyntax literalText) | ||
{ | ||
string text = literalText.ToString(); | ||
text = text[1..^1].Replace("\\\"", "\""); | ||
if (EntryPoint.localizationList.Contains(text)) | ||
{ | ||
found = true; | ||
localizedStrings.Add(text); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
localized = [.. localizedStrings]; | ||
return found; | ||
} | ||
} | ||
} |
109 changes: 109 additions & 0 deletions
109
private/Nitrocid.LocaleClean/Analyzers/ReverseNLOC0001Implicit.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// | ||
// Nitrocid KS Copyright (C) 2018-2024 Aptivi | ||
// | ||
// This file is part of Nitrocid KS | ||
// | ||
// Nitrocid KS is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Nitrocid KS is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY, without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
// | ||
|
||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Terminaux.Colors.Data; | ||
using Terminaux.Writer.ConsoleWriters; | ||
using Terminaux.Writer.MiscWriters; | ||
|
||
namespace Nitrocid.LocaleClean.Analyzers | ||
{ | ||
internal class ReverseNLOC0001Implicit : IAnalyzer | ||
{ | ||
public bool Analyze(Document document, out string[] localized) | ||
{ | ||
localized = []; | ||
var tree = document.GetSyntaxTreeAsync().Result; | ||
if (tree is null) | ||
return false; | ||
var syntaxNodeNodes = tree.GetRoot().DescendantNodesAndSelf().OfType<SyntaxNode>().ToList(); | ||
bool found = false; | ||
List<string> localizedStrings = []; | ||
foreach (var syntaxNode in syntaxNodeNodes) | ||
{ | ||
// Check for argument | ||
if (syntaxNode is not CompilationUnitSyntax exp) | ||
continue; | ||
var triviaList = exp.DescendantTrivia(); | ||
var multiLineComments = triviaList.Where((trivia) => trivia.IsKind(SyntaxKind.MultiLineCommentTrivia)); | ||
foreach (var multiLineComment in multiLineComments) | ||
{ | ||
string comment = multiLineComment.ToString(); | ||
if (comment == "/* Localizable */") | ||
{ | ||
// We found a localizable string, but we need to find the string itself, so get all the possible | ||
// tokens. | ||
var node = exp.FindNode(multiLineComment.Span); | ||
var tokens = node.DescendantTokens() | ||
.Where(token => token.GetAllTrivia() | ||
.Where((trivia) => trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) && trivia.ToString() == "/* Localizable */").Any()); | ||
|
||
// Now, enumerate them to find the string | ||
foreach (var token in tokens) | ||
{ | ||
void Process(LiteralExpressionSyntax literalText) | ||
{ | ||
// Process it. | ||
var location = literalText.GetLocation(); | ||
string text = literalText.ToString(); | ||
text = text.Substring(1, text.Length - 2).Replace("\\\"", "\""); | ||
if (EntryPoint.localizationList.Contains(text)) | ||
{ | ||
found = true; | ||
localizedStrings.Add(text); | ||
} | ||
} | ||
|
||
// Try to get a child | ||
int start = token.FullSpan.End; | ||
var parent = token.Parent; | ||
if (parent is null) | ||
continue; | ||
if (parent is LiteralExpressionSyntax literalParent) | ||
{ | ||
Process(literalParent); | ||
continue; | ||
} | ||
if (parent is NameColonSyntax) | ||
parent = parent.Parent; | ||
if (parent is null) | ||
continue; | ||
var child = (SyntaxNode?)parent.ChildThatContainsPosition(start); | ||
if (child is null) | ||
continue; | ||
|
||
// Now, check to see if it's a literal string | ||
if (child is LiteralExpressionSyntax literalText) | ||
Process(literalText); | ||
else if (child is ArgumentSyntax argument && argument.Expression is LiteralExpressionSyntax literalArgText) | ||
Process(literalArgText); | ||
} | ||
} | ||
} | ||
} | ||
localized = [.. localizedStrings]; | ||
return found; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// | ||
// Nitrocid KS Copyright (C) 2018-2024 Aptivi | ||
// | ||
// This file is part of Nitrocid KS | ||
// | ||
// Nitrocid KS is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Nitrocid KS is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY, without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
// | ||
|
||
|
||
// | ||
// Nitrocid KS Copyright (C) 2018-2024 Aptivi | ||
// | ||
// This file is part of Nitrocid KS | ||
// | ||
// Nitrocid KS is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Nitrocid KS is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY, without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
// | ||
|
||
using Nitrocid.LocaleClean.Analyzers; | ||
|
||
namespace Nitrocid.LocaleClean | ||
{ | ||
internal static class AnalyzersList | ||
{ | ||
// For contributors: If you're going to add a new analyzer, you need to copy the implementation from Analyzers to here, | ||
// and make a dedicated diagnostic class for the standalone analyzer to recognize your new analyzer. | ||
internal static readonly IAnalyzer[] analyzers = | ||
[ | ||
new ReverseNLOC0001(), | ||
new ReverseNLOC0001Implicit(), | ||
]; | ||
} | ||
} |
Oops, something went wrong.