[GFX-591] 去除 IllegalWordDetection 的 unsafe 指针并拆分 DetectIllegalWords 消除 Sonar S6640 与 S3776 - #368
Conversation
…ds 消除 Sonar S6640 与 S3776 Linear: GFX-591
📝 WalkthroughWalkthrough本次变更移除敏感词缓存初始化中的 unsafe 指针操作,并拆分检测扫描流程。多字符敏感词命中后立即返回。 Changes敏感词检测重构
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@GameFrameX.Utility/IllegalWordDetection.cs`:
- Around line 534-580: Update ScanFromPosition so that when TryScanForward finds
a multi-character match and returnWhenFindFirst is false, it does not leave
aitorIdx at the match end or increment past the next overlapping start; preserve
the original scan start for the outer loop while continuing forward matching.
Keep the immediate return behavior unchanged when returnWhenFindFirst is true,
and apply the same cursor handling to the corresponding logic near the other
ScanFromPosition call site.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: d97e0b3c-1015-44f0-a752-9988b0f356a1
📒 Files selected for processing (1)
GameFrameX.Utility/IllegalWordDetection.cs
| if (ScanFromPosition(text, textLength, ref aitorIdx, returnWhenFindFirst, findResult)) | ||
| { | ||
| while (aitorIdx < textLength - 1 && (FastCheck[text[++aitorIdx]] & 0x01) == 0) | ||
| { | ||
| ; | ||
| } | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return findResult.Count > 0; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// 在主扫描循环的当前位置执行一次敏感词检测:推进游标到下一个候选首字符、记录单字符敏感词、向后扫描多字符敏感词。 | ||
| /// 命中且需要首个即返回时返回 true;否则通过 ref 推进 aitorIdx 并返回 false。 | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// Performs one detection pass at the current cursor: advances to the next candidate start character, | ||
| /// records single-character bad words, then scans forward for multi-character bad words. | ||
| /// Returns true when a match is found and returnWhenFindFirst is set; otherwise advances aitorIdx via ref and returns false. | ||
| /// </remarks> | ||
| /// <param name="text">敏感词查询文本 / The text to check for sensitive words</param> | ||
| /// <param name="textLength">文本长度 / The text length</param> | ||
| /// <param name="aitorIdx">当前游标位置(引用),会被推进 / The current cursor (by ref), advanced by this call</param> | ||
| /// <param name="returnWhenFindFirst">是否找到第一个就返回 / Whether to return when the first match is found</param> | ||
| /// <param name="findResult">查找到的敏感词结果(键为起始位置,值为长度) / The found sensitive words (key is start position, value is length)</param> | ||
| /// <returns>是否找到敏感词并需立即返回 / Whether a match was found and the caller should return immediately</returns> | ||
| private static bool ScanFromPosition(string text, int textLength, ref int aitorIdx, bool returnWhenFindFirst, Dictionary<int, int> findResult) | ||
| { | ||
| aitorIdx = AdvanceToNextStartChar(text, textLength, aitorIdx); | ||
|
|
||
| //如果有只有一个词的敏感词,且当前的字符串的“非第一个词”满足这个敏感词,则先加入已检测到的敏感词列表 | ||
| if (StartCache[text[aitorIdx]] != 0 && (FastLength[text[aitorIdx]] & 0x01) > 0) | ||
| //如果有只有一个词的敏感词,且当前的字符串的“非第一个词”满足这个敏感词,则先加入已检测到的敏感词列表 | ||
| if (StartCache[text[aitorIdx]] != 0 && (FastLength[text[aitorIdx]] & 0x01) > 0) | ||
| { | ||
| //返回敏感词在text中的位置,以及敏感词的长度,供过滤功能用 | ||
| findResult.Add(aitorIdx, 1); | ||
| if (returnWhenFindFirst) | ||
| { | ||
| //返回敏感词在text中的位置,以及敏感词的长度,供过滤功能用 | ||
| findResult.Add(aitorIdx, 1); | ||
| if (returnWhenFindFirst) | ||
| { | ||
| return true; | ||
| } | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| //此时已经检测到一个敏感词的“首词”了,记录下第一个检测到的敏感词的位置 | ||
| //从当前的位置检测到字符串末尾 | ||
| if (TryScanForward(text, textLength, ref aitorIdx, findResult) && returnWhenFindFirst) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| ++aitorIdx; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
当 returnWhenFindFirst 为 false 时,不要在首次多字符命中后跳过后续起始位置。
TryScanForward 在首次命中后把 aitorIdx 推进到匹配末尾。ScanFromPosition 随后再次递增该游标。此流程会跳过重叠敏感词。
例如,敏感词为 ab 和 bc,文本为 abc 时,当前代码只记录 ab。Filter 会产生 **c,而不会屏蔽 bc。
仅当 returnWhenFindFirst 为 true 时立即返回。否则,保持当前起始游标,并继续前向匹配和外层扫描。
建议修改
- if (TryScanForward(text, textLength, ref aitorIdx, findResult) && returnWhenFindFirst)
+ if (TryScanForward(text, textLength, aitorIdx, returnWhenFindFirst, findResult))
{
return true;
}
- private static bool TryScanForward(string text, int textLength, ref int aitorIdx, Dictionary<int, int> findResult)
+ private static bool TryScanForward(string text, int textLength, int aitorIdx, bool returnWhenFindFirst, Dictionary<int, int> findResult)
{
// ...
if (WordsSet.Contains(new string(_dectectedBuffer, 0, strIgorIdx)))
{
findResult[aitorIdx] = i + 1;
- aitorIdx = subItoIdx;
- return true;
+ if (returnWhenFindFirst)
+ {
+ return true;
+ }
}
}Also applies to: 647-651
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@GameFrameX.Utility/IllegalWordDetection.cs` around lines 534 - 580, Update
ScanFromPosition so that when TryScanForward finds a multi-character match and
returnWhenFindFirst is false, it does not leave aitorIdx at the match end or
increment past the next overlapping start; preserve the original scan start for
the outer loop while continuing forward matching. Keep the immediate return
behavior unchanged when returnWhenFindFirst is true, and apply the same cursor
handling to the corresponding logic near the other ScanFromPosition call site.
|



Linear: GFX-591
Summary by CodeRabbit