gpt4 book ai didi

c# - 如何找到 C# 项目中的所有硬编码值(解决方案)?

转载 作者:太空狗 更新时间:2023-10-29 20:27:19 26 4
gpt4 key购买 nike

这个问题不只问硬编码字符串,还问魔数(Magic Number)等。

有没有办法找到所有硬编码值,即字符串、魔数(Magic Number)以及 VS 中的 C# 项目/解决方案中没有的东西?

提出这个问题的是我正在查看的一个项目,我刚刚发现一个字符串值被硬编码重复了 174 次!

最佳答案

你可以做的是编程Roslyn ,镇上(不是这样)的新酷 child 。它允许您非常轻松地解析 C#(或 VB.NET)项目。然后您可以访问检测到的节点并检查您真正想要检查的内容。检测机器的魔法文字并不总是像人类看起来那么容易。例如,1 真的是一个神奇的数字吗?我个人认为不是,但 2 更值得怀疑......

无论如何,这是一个小示例,我相信它可以完成大部分工作,但它可以/应该改进,也许可以定制您的确切业务需求或规则(这非常有趣)。

注意 Roslyn 也可以直接在 Visual Studio 上下文中使用,因此您可以将此示例转换为所谓的诊断(Visual Studio 的扩展),它可以帮助您直接在 IDE 中运行。有这方面的样本:Samples and Walkthroughs

class Program
{
static void Main(string[] args)
{
var text = @"
public class MyClass
{
public void MyMethod()
{
const int i = 0; // this is ok
decimal d = 11; // this is not ok
string s = ""magic"";
if (i == 29) // another magic
{
}
else if (s != ""again another magic"")
{
}
}
}";
ScanHardcodedFromText("test.cs", text, (n, s) =>
{
Console.WriteLine(" " + n.SyntaxTree.GetLineSpan(n.FullSpan) + ": " + s);
}).Wait();
}

public static async Task ScanHardcodedFromText(string documentName, string text, Action<SyntaxNodeOrToken, string> scannedFunction)
{
if (text == null)
throw new ArgumentNullException("text");

AdhocWorkspace ws = new AdhocWorkspace();
var project = ws.AddProject(documentName + "Project", LanguageNames.CSharp);
ws.AddDocument(project.Id, documentName, SourceText.From(text));
await ScanHardcoded(ws, scannedFunction);
}

public static async Task ScanHardcodedFromSolution(string solutionFilePath, Action<SyntaxNodeOrToken, string> scannedFunction)
{
if (solutionFilePath == null)
throw new ArgumentNullException("solutionFilePath");

var ws = MSBuildWorkspace.Create();
await ws.OpenSolutionAsync(solutionFilePath);
await ScanHardcoded(ws, scannedFunction);
}

public static async Task ScanHardcodedFromProject(string solutionFilePath, Action<SyntaxNodeOrToken, string> scannedFunction)
{
if (solutionFilePath == null)
throw new ArgumentNullException("solutionFilePath");

var ws = MSBuildWorkspace.Create();
await ws.OpenProjectAsync(solutionFilePath);
await ScanHardcoded(ws, scannedFunction);
}

public static async Task ScanHardcoded(Workspace workspace, Action<SyntaxNodeOrToken, string> scannedFunction)
{
if (workspace == null)
throw new ArgumentNullException("workspace");

if (scannedFunction == null)
throw new ArgumentNullException("scannedFunction");

foreach (var project in workspace.CurrentSolution.Projects)
{
foreach (var document in project.Documents)
{
var tree = await document.GetSyntaxTreeAsync();
var root = await tree.GetRootAsync();
foreach (var n in root.DescendantNodesAndTokens())
{
if (!CanBeMagic(n.Kind()))
continue;

if (IsWellKnownConstant(n))
continue;

string suggestion;
if (IsMagic(n, out suggestion))
{
scannedFunction(n, suggestion);
}
}
}
}
}

public static bool IsMagic(SyntaxNodeOrToken kind, out string suggestion)
{
var vdec = kind.Parent.Ancestors().OfType<VariableDeclarationSyntax>().FirstOrDefault();
if (vdec != null)
{
var dec = vdec.Parent as MemberDeclarationSyntax;
if (dec != null)
{
if (!HasConstOrEquivalent(dec))
{
suggestion = "member declaration could be const: " + dec.ToFullString();
return true;
}
}
else
{
var ldec = vdec.Parent as LocalDeclarationStatementSyntax;
if (ldec != null)
{
if (!HasConstOrEquivalent(ldec))
{
suggestion = "local declaration contains at least one non const value: " + ldec.ToFullString();
return true;
}
}
}
}
else
{
var expr = kind.Parent.Ancestors().OfType<ExpressionSyntax>().FirstOrDefault();
if (expr != null)
{
suggestion = "expression uses a non const value: " + expr.ToFullString();
return true;
}
}

// TODO: add other cases?

suggestion = null;
return false;
}

private static bool IsWellKnownConstant(SyntaxNodeOrToken node)
{
if (!node.IsToken)
return false;

string text = node.AsToken().Text;
if (text == null)
return false;

// note: this is naïve. we also should add 0d, 0f, 0m, etc.
if (text == "1" || text == "-1" || text == "0")
return true;

// ok for '\0' or '\r', etc.
if (text.Length == 4 && text.StartsWith("'\\") && text.EndsWith("'"))
return true;

if (text == "' '")
return true;

// TODO add more of these? or make it configurable...

return false;
}

private static bool HasConstOrEquivalent(SyntaxNode node)
{
bool hasStatic = false;
bool hasReadOnly = false;
foreach (var tok in node.ChildTokens())
{
switch (tok.Kind())
{
case SyntaxKind.ReadOnlyKeyword:
hasReadOnly = true;
if (hasStatic)
return true;
break;

case SyntaxKind.StaticKeyword:
hasStatic = true;
if (hasReadOnly)
return true;
break;

case SyntaxKind.ConstKeyword:
return true;
}
}
return false;
}

private static bool CanBeMagic(SyntaxKind kind)
{
return kind == SyntaxKind.CharacterLiteralToken ||
kind == SyntaxKind.NumericLiteralToken ||
kind == SyntaxKind.StringLiteralToken;
}
}

如果您运行这个小程序(我还提供了在解决方案或项目中使用它的辅助方法),它将输出:

 test.cs: (6,20)-(6,22): local declaration contains at least one non const value:         decimal d = 11; // this is not ok

test.cs: (7,19)-(7,26): local declaration contains at least one non const value: string s = "magic";

test.cs: (8,17)-(8,19): expression uses a non const value: i == 29
test.cs: (11,22)-(11,43): expression uses a non const value: s != "again another magic"

关于c# - 如何找到 C# 项目中的所有硬编码值(解决方案)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29533905/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com