Delphi Code Review by delphicleancode/delphi-spec-kit
npx skills add https://github.com/delphicleancode/delphi-spec-kit --skill 'Delphi Code Review'Format 或拼接导致的 SQL 注入TObjectList 的 OwnsObjects 配置正确try/finally 配合 广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
FreeAssigned()Destroy 使用 override 释放拥有的字段T,接口前缀为 I,异常前缀为 EF,参数前缀为 A,局部变量前缀为 LProjeto.Camada.Dominio.Funcionalidade.pasbtn、edt、lbl 等)//❌ 魔法数字
if ACustomer.Age > 18 then
//✅ 命名常量
const MINIMUM_AGE = 18;
if ACustomer.Age > MINIMUM_AGE then
//❌ with 语句
with AQuery do begin
SQL.Text := '...';
Open;
end;
//✅ 显式引用
AQuery.SQL.Text := '...';
AQuery.Open;
//❌ 通用捕获
except
on E: Exception do ShowMessage(E.Message);
//✅ 特定异常
except
on E: EFDDBEngineException do
raise EDatabaseException.Create('Falha: ' + E.Message);
//❌ 在 OnClick 中编写逻辑
procedure TfrmMain.btnSaveClick(Sender: TObject);
begin
//此处有50行业务逻辑
end;
//✅ 委托给服务
procedure TfrmMain.btnSaveClick(Sender: TObject);
begin
FService.SaveCustomer(GetFormData);
end;
// ❌ 内存泄漏
function GetItems: TStringList;
begin
Result := TStringList.Create;
LoadItems(Result); //如果 LoadItems 抛出异常,则泄漏!
end;
//✅ 安全版本
function GetItems: TStringList;
begin
Result := TStringList.Create;
try
LoadItems(Result);
except
Result.Free;
raise;
end;
end;
🔴 阻塞性问题:内存泄漏 — 异常情况下对象未释放
🔴 阻塞性问题:SQL 注入 — 查询使用了字符串拼接
🟡 建议:提取方法 — 此代码块有 35 行
🟡 建议:使用接口代替具体类(DIP)
🟢 细节:将变量 'S' 重命名为描述性名称
🟢 细节:优先使用卫语句而非嵌套
❓ 问题:如果 ACustomer 为 nil 这里会发生什么?
❓ 问题:这个对象由谁释放?
| 原则 | 检查项 |
|---|---|
| SRP | 类是否只有一个职责?服务是否不直接访问数据? |
| OCP | 新功能是否通过添加类而非修改现有类来实现? |
| LSP | 接口的任一实现是否都能在对方的位置正常工作? |
| ISP | 接口是否没有实现者不使用的方法? |
| DIP | 构造函数是否接收接口而非具体类? |
每周安装量
–
代码仓库
GitHub 星标数
19
首次出现时间
–
安全审计
Format or concatenation in queriesTObjectList with OwnsObjects configured correctlytry/finally with Free for temporary objectsAssigned() before accessing references that may be nilDestroy with override freeing owned fieldsT in classes, I in interfaces, E in exceptionsF in private fields, A in parameters, L in local variablesProjeto.Camada.Dominio.Funcionalidade.pasbtn, edt, lbl, etc.)//❌ Magic numbers
if ACustomer.Age > 18 then
//✅ Named constants
const MINIMUM_AGE = 18;
if ACustomer.Age > MINIMUM_AGE then
//❌ with statement
with AQuery do begin
SQL.Text := '...';
Open;
end;
//✅ Explicit reference
AQuery.SQL.Text := '...';
AQuery.Open;
//❌ Generic Catch
except
on E: Exception do ShowMessage(E.Message);
//✅ Specific exceptions
except
on E: EFDDBEngineException do
raise EDatabaseException.Create('Falha: ' + E.Message);
//❌ Logic in OnClick
procedure TfrmMain.btnSaveClick(Sender: TObject);
begin
//50 lines of business logic here
end;
//✅ Delegate for Service
procedure TfrmMain.btnSaveClick(Sender: TObject);
begin
FService.SaveCustomer(GetFormData);
end;
// ❌ Memory leak
function GetItems: TStringList;
begin
Result := TStringList.Create;
LoadItems(Result); //if LoadItems throws exception, leak!
end;
//✅ Safe
function GetItems: TStringList;
begin
Result := TStringList.Create;
try
LoadItems(Result);
except
Result.Free;
raise;
end;
end;
🔴 BLOQUEANTE: Memory leak — objeto não liberado em caso de exception
🔴 BLOQUEANTE: SQL injection — query usando concatenação de string
🟡 SUGESTÃO: Extrair método — este bloco tem 35 linhas
🟡 SUGESTÃO: Usar interface em vez de classe concreta (DIP)
🟢 NIT: Renomear variável 'S' para nome descritivo
🟢 NIT: Preferir guard clause a nesting
❓ PERGUNTA: O que acontece se ACustomer for nil aqui?
❓ PERGUNTA: Este objeto é liberado por quem?
| Principle | Check |
|---|---|
| SRP | Does class have ONE responsibility? Service does not access data? |
| OCP | Do new features add classes, not modify existing ones? |
| LSP | Does either implementation of the interface work in place of the other? |
| ISP | Doesn't interface have methods that implementers don't use? |
| DIP | Constructor takes interfaces, not concrete classes? |
Weekly Installs
–
Repository
GitHub Stars
19
First Seen
–
Security Audits
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
111,800 周安装