DEV Community

Hsin-Chieh Cheng
Hsin-Chieh Cheng

Posted on

程式碼定位、追蹤與修改操作筆記

程式碼定位、追蹤與修改操作筆記

這份筆記整理一套不用 AI 時也能照著做的工作流程:如何定位函式定義、找引用、追資料流、確認行為,並安全修改檔案。

核心原則

  • 先用最快的工具縮小範圍,再用更精準的工具確認語意。
  • 先找「定義」與「引用」,再讀上下文,不要只看單行。
  • 修改前先確認資料流與呼叫順序,修改後用 git diff、build、test 驗證。
  • 對 Xcode project 管理的 Swift 檔案,新增、刪除、搬移時要注意 .xcodeproj reference。

工具選擇

需求 優先工具 何時使用
快速找文字、函式、變數 rg 第一輪定位,速度最快
看檔案行號與上下文 nl -ba + sed 找到結果後閱讀附近程式
找 Swift 定義、引用、型別 Xcode index / SourceKit-LSP 同名函式、overload、protocol extension 較多時
Swift 語法結構分析或安全改寫 SwiftSyntax 需要 AST/CST 等級分析或批次 rewrite
通用語法樹查詢 tree-sitter 想找特定語法形狀,但不需要完整型別解析
C/C++/Obj-C symbol index ctags / cscope 老專案或 C-family code 較多時
修改既有檔案內容 apply_patch 小到中型人工修改
新增 Xcode project 內 Swift 檔 Xcode MCP XcodeWrite 需要加入 project structure / compile sources
刪除 Xcode project 檔案 Xcode MCP XcodeRM 避免只刪檔案但 project reference 還留著
搬移或 rename Xcode 檔案 Xcode MCP XcodeMV 避免 Xcode project reference 壞掉

定位函式定義

假設要找 presentWebView 的定義:

rg -n 'func\s+presentWebView\b' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode

說明:

  • func:找 Swift function declaration。
  • \s+:一個或多個空白,允許 func presentWebView
  • \b:單字邊界,避免誤中 presentWebViewController
  • -n:顯示行號。
  • -g '*.swift':只查 Swift 檔。

如果函式可能是 property、closure、protocol requirement,也可以放寬:

rg -n '\bpresentWebView\b' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode

找函式引用

找呼叫點:

rg -n '\bpresentWebView\s*\(' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode

說明:

  • \bpresentWebView:要求是完整名稱。
  • \s*:允許函式名和 ( 中間有空白。
  • \(:找真正的左括號。

如果有 trailing closure 或不同語法,也可先放寬:

rg -n '\bpresentWebView\b' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode

再人工排除不是呼叫的結果。

閱讀上下文

找到檔案與行號後,用 nl -ba 顯示行號,再用 sed 切範圍:

nl -ba AppPOS/Common/WebView/WebViewCoordinator.swift | sed -n '30,75p'
Enter fullscreen mode Exit fullscreen mode

常見用法:

nl -ba path/to/File.swift | sed -n '起始行,結束行p'
Enter fullscreen mode Exit fullscreen mode

例:

nl -ba AppPOS/Payment/Payment/QRScan/QRScanViewController.swift | sed -n '24,45p;190,225p;250,265p'
Enter fullscreen mode Exit fullscreen mode

這可以一次看:

  • property 宣告
  • delegate callback
  • setup camera

追資料流的方法

以 QR/barcode 掃描為例,確認是否支援 Code 128 時,追三段:

  1. 支援格式宣告
rg -n 'AVMetadataObject.ObjectType|vaildObjectTypes|code128' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode

看到:

private let vaildObjectTypes: [AVMetadataObject.ObjectType] = [.qr, .code93, .code128]
Enter fullscreen mode Exit fullscreen mode
  1. 是否真的套用到相機 output
rg -n 'metadataObjectTypes\s*=' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode

看到:

output.metadataObjectTypes = vaildObjectTypes
Enter fullscreen mode Exit fullscreen mode
  1. delegate 收到後是否放行
rg -n 'metadataOutput|contains\(data.type\)|scanCodeSubject.send' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode

看到:

if vaildObjectTypes.contains(data.type) {
    scanCodeSubject.send(symbolData)
}
Enter fullscreen mode Exit fullscreen mode

這三段都成立時,才能說「相機掃描層支援 Code 128」。

接著要追後續業務是否接受:

rg -n 'scanCodeSubject|scanCode|paymentRequest|voucherScan|voucherInquiry|isFormatValid' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode

例:

input.scanCode
    .map {
        self.useCase.paymentRequest(..., oneTimeKey: $0)
    }
Enter fullscreen mode Exit fullscreen mode

或:

if !VoucherCodeChecker.isFormatValid(text: $0) {
    return ""
}
Enter fullscreen mode Exit fullscreen mode

這代表掃描層支援不等於業務層一定接受。

Regex 常用片段

Regex 意思
\s 空白字元,包含 space、tab、換行
\s+ 一個或多個空白
\s* 零個或多個空白
\b 單字邊界
\( 左括號 (
. 任意字元
.* 任意字元重複零次以上
`foo bar`

建議 shell 裡用單引號包 regex:

rg -n 'func\s+presentWebView\b' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode

比雙引號少處理一層 escape。

AST、LSP、rg 的差別

工具 解決問題 適合情境
rg 找文字 pattern 快速定位、第一輪搜尋
AST/CST 理解語法形狀 找所有 function declaration、assignment、call expression
LSP 理解 symbol 語意 go to definition、find references、hover type、diagnostics

簡單判斷:

  • 想找「文字在哪裡」:用 rg
  • 想找「這段 code 是什麼語法結構」:用 AST/CST。
  • 想找「這個名字實際指的是哪個 symbol」:用 LSP / Xcode index。

Swift 專案裡:

  • AST/CST:SwiftSyntax、swiftc -dump-ast
  • LSP:SourceKit-LSP、Xcode index。
  • 通用 CST:tree-sitter。

SourceKit-LSP 怎麼用

確認路徑:

xcrun --find sourcekit-lsp
Enter fullscreen mode Exit fullscreen mode

通常會得到類似:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp
Enter fullscreen mode Exit fullscreen mode

實務上通常不手動呼叫 raw LSP JSON,而是透過 editor:

  • Xcode:Jump to Definition、Find Call Hierarchy、Find References。
  • VS Code / Neovim:設定 LSP server 為 xcrun sourcekit-lsp

對 Xcode app 專案,先 build 過會讓 index 比較完整:

xcodebuild build \
  -project AppPOS.xcodeproj \
  -scheme "AppPOS Dev" \
  -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.5'
Enter fullscreen mode Exit fullscreen mode

Xcode MCP 常用操作

如果在有 Xcode MCP 的環境,可以用:

指令 用途
XcodeGrep 在 Xcode project structure 裡搜尋
XcodeRead 讀 Xcode project 裡的檔案
XcodeGlob 用 wildcard 找 project 檔案
XcodeGetCurrentFile 讀目前 editor 開啟檔案
BuildProject build 目前 active scheme
GetBuildLog 讀 build log
XcodeRefreshCodeIssuesInFile 查單檔 compiler diagnostics
GetTestList 列出 tests
RunSomeTests 跑指定 tests
XcodeWrite 新增/覆寫檔案並加入 project
XcodeUpdate 用 old/new string 修改檔案
XcodeRM 刪除 project 檔案
XcodeMV move / rename project 檔案

注意:Xcode MCP 看的是 Xcode project organization,不完全等同 filesystem。

修改檔案:apply_patch

修改既有檔案:

*** Begin Patch
*** Update File: AppPOS/Foo.swift
@@
-    let title = "Old"
+    let title = "New"
*** End Patch
Enter fullscreen mode Exit fullscreen mode

新增檔案:

*** Begin Patch
*** Add File: docs/example.md
+# Example
+
+This is a new file.
*** End Patch
Enter fullscreen mode Exit fullscreen mode

刪除檔案:

*** Begin Patch
*** Delete File: docs/old.md
*** End Patch
Enter fullscreen mode Exit fullscreen mode

使用原則:

  • 小到中型人工修改:用 apply_patch
  • 新增 Swift 檔且要進 Xcode target:優先 XcodeWrite,或同步改 .xcodeproj
  • 刪除/搬移 Xcode project 檔:優先 XcodeRM / XcodeMV
  • 修改完一定看 git diff

修改後驗證

基本檢查:

git diff --stat
git diff
Enter fullscreen mode Exit fullscreen mode

找是否有漏改:

rg -n 'OldName|NewName' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode

跑測試或 build:

xcodebuild test \
  -project AppPOS.xcodeproj \
  -scheme "AppPOS Dev" \
  -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.5' \
  -only-testing:AppPOSTests/SomeTests
Enter fullscreen mode Exit fullscreen mode

如果只是確認 project schemes:

xcodebuild -list -project AppPOS.xcodeproj
Enter fullscreen mode Exit fullscreen mode

實戰流程模板

  1. 先找入口:
rg -n '目標關鍵字|目標函式|目標型別' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode
  1. 找定義:
rg -n 'func\s+函式名\b|class\s+型別名\b|struct\s+型別名\b|enum\s+型別名\b' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode
  1. 找引用:
rg -n '\b函式名\s*\(|\b變數名\b|\b型別名\b' AppPOS -g '*.swift'
Enter fullscreen mode Exit fullscreen mode
  1. 讀上下文:
nl -ba path/to/File.swift | sed -n 'start,endp'
Enter fullscreen mode Exit fullscreen mode
  1. 追資料流:
  • UI event / delegate callback
  • Subject / publisher send
  • ViewModel input
  • UseCase
  • API request
  • Model / validation
  • Output / navigation
  1. 修改:
  • 既有內容:apply_patch
  • Xcode 新增檔:XcodeWrite
  • Xcode 刪除檔:XcodeRM
  • Xcode 搬移檔:XcodeMV
  1. 驗證:
git diff
xcodebuild build/test ...
Enter fullscreen mode Exit fullscreen mode

常見陷阱

  • 只看到 .code128 宣告,不代表有套用到 metadataObjectTypes
  • 掃描層支援格式,不代表業務層接受內容。
  • rg 找到同名函式,不代表是同一個 overload。
  • protocol extension / dynamic dispatch 需要 LSP 或人工確認型別。
  • 新增 Swift 檔只放到 filesystem,不代表 Xcode target 會編譯。
  • 刪檔只用 rm,可能留下 .xcodeproj broken reference。
  • build/test 失敗要分清楚是本次修改造成,還是既有環境問題。

Top comments (0)