É terça-feira, 14h. Caixa de entrada: "Pode revisar esse fonte rapidinho? Cliente reclamando que lock fica aberto às vezes." Anexo: ALCMAIL.prw, 935 linhas, 7 User Functions, customização de 2018 que ninguém olha há anos.
Antes da v0.2.0 da claude-advpl-skill, eu faria assim:
- Abrir no VSCode
- Buscar todas ocorrências de
RecLocke cruzar comMsUnlockuma por uma - Procurar todos os
TCQuerye ver se temD_E_L_E_T_ = ' ' - Olhar declarações
Localvs variáveis usadas (variasFor i := 1 toescondidas) - Conferir se
GetMVtem default — senão quebra em produção
Tempo estimado: 2 horas. Tempo real: provavelmente 3, porque sempre tem distração.
Hoje, com a v0.2.0 que acabei de lançar:
$ /advpl-find-issues ALCMAIL.prw
=== ADVPL FIND-ISSUES ===
Arquivos analisados: 1
Issues encontradas: 16
Resumo: 2 error · 14 warn · 0 info30 segundos. 16 problemas reais detectados. Vou mostrar cada regra que disparou — e o que cada uma significa em produção.
O que a /advpl-find-issues encontrou
2 ERROS: For sem Local (variável vira PUBLIC implícita)
ALCMAIL.prw:679 ERR for-i-not-declared
Variavel For "i" sem Local declarado — vira PUBLIC implicita
ALCMAIL.prw:730 ERR for-i-not-declared
Variavel For "i" sem Local declarado — vira PUBLIC implicitaO dev original escreveu:
User Function AlcPxNiv(c_Filial, c_Solic)
l_ProxNiv := .F.
For i := 1 to 10
...
Next i
Return l_ProxNivSem Local i := 0, o i vira PUBLIC implícita. Polui o escopo do chamador, conflita entre threads, e em produção pode dar resultado errado se outra rotina também usar i. Mesmo problema com l_ProxNiv. Aconteceu 2 vezes nesse fonte.
4 WARNs: SQL sem D_E_L_E_T_ e sem xFilial
ALCMAIL.prw:823 WRN sql-no-deleted
ALCMAIL.prw:823 WRN sql-no-filial
ALCMAIL.prw:904 WRN sql-no-deleted
ALCMAIL.prw:904 WRN sql-no-filialOlhando a linha 823:
cQry := "SELECT XCR1.XCR_FILIAL, XCR1.XCR_NUM, ... "
cQry += "FROM " + RetSqlName("SAK") + " SAK (NOLOCK)"
cQry += "INNER JOIN " + RetSqlName("XCR") + " XCR1 (NOLOCK)"
cQry += " ON AK_USER = XCR1.XCR_USER"
cQry += " AND AK_FILIAL = XCR1.XCR_FILIAL"
cQry += " AND XCR1.D_E_L_E_T_ = ''"Olha o detalhe: o filtro é D_E_L_E_T_ = '' (string vazia), não ' ' (espaço). Não funciona. Protheus marca registro ativo com ' ' (espaço) e deletado com '*'. '' retorna zero linhas — a query inteira tava bugada.
O linter pegou isso porque não encontrou a string exata D_E_L_E_T_ com filtro adequado.
6 WARNs: GetMV sem default
ALCMAIL.prw:71 WRN getmv-no-default
ALCMAIL.prw:157 WRN getmv-no-default
ALCMAIL.prw:236 WRN getmv-no-default
ALCMAIL.prw:324 WRN getmv-no-default
ALCMAIL.prw:491 WRN getmv-no-default
ALCMAIL.prw:639 WRN getmv-no-defaultTodas as 6 linhas têm padrão tipo:
c_HTML += '
'Se MV_XLOGO não existe (ambiente novo, cópia de empresa), GetMV() retorna NIL. NIL + string quebra a concatenação. Email sai sem imagem (best case) ou rotina explode (worst case).
Fix: GetMV("MV_XLOGO", .F., "") com default string vazia.
2 WARNs: MemoWrite esquecido em produção
ALCMAIL.prw:821 WRN memowrite-debug
ALCMAIL.prw:902 WRN memowrite-debug
MemoWrite grava arquivo em disco a cada execucao — pode ser debug esquecidoLinha 821:
MemoWrite("XCRAPROV.sql", c_Qry)Toda vez que essa função roda, grava um arquivo XCRAPROV.sql no disco do AppServer. Isso é código de debug que ficou. Provavelmente foi usado uma vez pra inspecionar a query, e nunca foi removido.
Em volume baixo: ninguém percebe. Em rotina batch processando 10k aprovações: 10k I/O writes desnecessários por execução. Diz pra alguém isso e essa rotina passou anos assim.
2 WARNs: RecLock inclusão sem xFilial
ALCMAIL.prw:827 WRN reclock-no-xfilial (alias XCR)
ALCMAIL.prw:909 WRN reclock-no-xfilial (alias SCR)Linha 827:
RecLock("XCR", .T.)
XCR->XCR_FILIAL := QRYXCR->XCR_FILIAL
XCR->XCR_NUM := QRYXCR->XCR_NUMEsse caso é falso positivo parcial — o dev tá setando XCR_FILIAL, só que pega da query QRYXCR. A skill alertou porque não encontrou xFilial("XCR") literal. Vale revisar pra garantir que QRYXCR->XCR_FILIAL tem o valor certo — mas não é bug grave.
As 9 regras implementadas
| Regra | Severidade | O que detecta |
|---|---|---|
no-msunlock | ERROR | RecLock aberto sem MsUnlock antes do Return |
sql-no-deleted | WARN | Query SQL sem filtro D_E_L_E_T_ = ' ' |
sql-no-filial | WARN | Query SQL sem filtro de filial |
getmv-no-default | WARN | GetMV sem 3º param |
function-not-user | ERROR | Function nua — RPO Token moderno rejeita |
memowrite-debug | WARN | MemoWrite esquecido em código |
for-i-not-declared | ERROR | For com variável sem Local |
reclock-no-xfilial | WARN | Inclusão sem setar _FILIAL := xFilial() |
old-msg-yesno | INFO | MsgYesNo legado (substituir por ApMsgYesNo) |
Como uso isso no dia-a-dia
Três cenários reais:
- Revisão de PR: dev manda fonte, rodo
/advpl-find-issuesantes de olhar. Pego o trivial automatizado, foco na revisão semântica do código. - Auditoria de cliente novo: recebo customização legada de cliente que migrou pra gente.
/advpl-find-issues src/customizacoes/em pasta inteira me dá mapa do que tem que prioritizar. - Gate de CI/CD:
--severity=errorem pipeline GitHub Actions / Azure DevOps. Erros graves (Functionnua,Forsem Local) bloqueiam o merge.
Limitações honestas
- Falsos positivos em SQL: query muito complexa em múltiplas linhas pode escapar do detector incremental. Se filtro
D_E_L_E_T_está em fragmento longe, pode não pegar. - Cross-arquivo: não detecta função chamada em outro fonte (chamada não declarada). Cada arquivo é analisado isolado.
- Macros (
#xcommand): se a SX3 ou um header customizado define expansão, o analyzer analisa o fonte literal — pode ter falso positivo dentro de bloco que expande.
Roadmap v0.2.1+
- Mais regras:
SaldoTit/Posicioneem loop (performance), array em ponteiro de função, transação aninhada - Output JSON pra integração CI/CD
- Auto-fix flag (
--fix) pra correções triviais (adicionarLocal i := 0, default emGetMV) - Whitelist de regras por
.advpllintrc
Download e instalação
v0.2.0 com a skill /advpl-find-issues está liberada. Pacote MIT, 64 KB, instala em 30 segundos:
curl -O https://archtecgroup.com.br/downloads/claude-advpl-skill-v0.2.0.zip
unzip claude-advpl-skill-v0.2.0.zip
cd claude-advpl-skill
bash install.sh # ou .\install.ps1 no WindowsDepois disso, em qualquer sessão Claude Code:
/advpl-find-issues caminho/do/fonte.prw
/advpl-find-issues caminho/pasta/ # recursivo
/advpl-find-issues caminho/pasta/ --severity=error # so erros gravesPra fechar
Auditar fonte AdvPL legado deixou de ser tarefa de uma tarde inteira. Vira 30 segundos + julgamento humano sobre o que priorizar. Esse é o tipo de ganho real que IA bem aplicada traz — não substitui você, automatiza o que é mecânico e repetitivo.
Se você é dev Protheus ou líder técnico, baixa, testa, manda feedback. Open source, MIT, no post principal da skill.
Próximo lançamento: catálogo de 69 funções AdvPL/TLPP documentadas (já no ar — /docs).
Comentarios 0