Skip to content

fix: native/forward multilinha e doc comment após #pragma deprecated - #37

Open
NullSablex wants to merge 13 commits into
masterfrom
fix/multiline-native-e-doc-apos-pragma
Open

fix: native/forward multilinha e doc comment após #pragma deprecated#37
NullSablex wants to merge 13 commits into
masterfrom
fix/multiline-native-e-doc-apos-pragma

Conversation

@NullSablex

Copy link
Copy Markdown
Owner

Duas correções de parsing que se somavam justamente nos includes do open.mp.

native/forward com assinatura multilinha eram ignorados

Ao fechar o ), o parser só criava o símbolo se o resto da linha trouxesse {; sem isso, guardava em pending_plain esperando um corpo na linha seguinte. Mas native e forward declaram sem corpo e terminam em ; — a espera nunca terminava e o símbolo se perdia por completo: sem hover, sem autocomplete, sem signature help.

O impacto é grande nos includes do open.mp, onde assinaturas longas quebradas em várias linhas são a norma. Um ApplyActorAnimation do omp_actor, com nove parâmetros em nove linhas, era simplesmente invisível para a engine.

native bool:ApplyActorAnimation(
    actorid,
    const animationLibrary[],
    ...
    time);

Doc comment perdido quando #pragma deprecated ficava no meio

extract_doc caminha para cima a partir da declaração e para na primeira linha que não é comentário — a diretiva cortava o caminho:

/**
 * Bane com motivo.
 */
#pragma deprecated Use BanPlayerFor
native BanEx(playerid, const reason[]);   // doc: None

Regressão da mudança anterior, que trouxe o #pragma: com @DEPRECATED o marcador era um comentário e não interrompia a varredura. Passa a pular a diretiva.

Verificação

202 testes (5 novos cobrindo os dois defeitos), cargo fmt limpo, clippy pedantic sem avisos. Validado contra uma amostra real do omp-stdlib: o símbolo multilinha é reconhecido, com os 9 parâmetros e o doc preservado.

Entra na 1.4.0, que ainda não foi lançada — o changelog dela já registra as duas correções.

Dois defeitos que se somavam justamente nos includes do open.mp, onde
assinaturas longas quebradas em várias linhas são comuns.

**Assinatura multilinha descartada.** Ao fechar o `)`, o parser só criava o
símbolo se o resto da linha trouxesse `{`; sem isso, guardava em
`pending_plain` à espera de um corpo na linha seguinte. `native` e `forward`
declaram sem corpo e terminam em `;`, então a espera nunca terminava e o
símbolo se perdia — sem hover, sem autocomplete, sem signature help. Um
`ApplyActorAnimation` do omp_actor, com nove parâmetros em nove linhas, era
invisível para a engine.

**Doc perdido quando a diretiva estava no meio.** `extract_doc` caminha para
cima a partir da declaração e para na primeira linha que não é comentário —
`#pragma deprecated` entre o bloco e a declaração cortava o caminho. Passa a
pular a diretiva. Regressão da mudança anterior, que trouxe o `#pragma`: com
`@DEPRECATED` o marcador era um comentário e não interrompia a varredura.
`pragma_deprecated_message` monta uma `String` e era chamada em toda linha do
arquivo — tanto no laço principal quanto na varredura para cima do
`extract_doc` — só para responder se a linha é a diretiva.

Separa o reconhecimento (`is_pragma_deprecated`, sem alocação) da extração da
mensagem, e faz o `extract_doc` acumular fatias em vez de `String` por linha.

Num arquivo com 600 nativas documentadas, ~2,5 ms → ~2,1 ms; com a diretiva e
sem doc, ~2,1 ms → ~1,96 ms. Medido com 20 repetições após aquecimento —
medições únicas variam demais para servir de base.
O compilador rejeita uma diretiva que não conheça (erro 207), mas só na
compilação. O diagnóstico antecipa isso e oferece a correção.

Dois casos, ambos com quick fix:

- **nome não reconhecido** — comparado com a lista de `sc2.c`; havendo uma
  diretiva próxima (distância de edição pequena, mais estrita para nomes
  curtos), ela é sugerida;
- **mensagem de `deprecated` entre aspas** — a diretiva toma o resto da linha
  como texto livre (`strdupwithouta` sobre `lptr`, em `sc2.c:1240`), então as
  aspas entrariam na mensagem em vez de delimitá-la. Aspas no meio do texto
  são literais legítimas e não são sinalizadas.

A forma correta, confirmada no compilador, é sem aspas:

    #pragma deprecated Use BanPlayerFor
Estende as correções rápidas aos diagnósticos cuja correção é
determinística:

- `PP0002`/`PP0003` — remove o corpo `{ … }` que o compilador não aceita em
  `native`/`forward`. Por ser erro de sintaxe, é oferecido também em `.inc`,
  ao contrário das remoções por "não utilizado";
- `PP0004` — duas ações: dar um corpo vazio, ou converter `public`/`stock`
  em `forward`, que é a forma de declarar sem corpo;
- `PP0010` — troca por um símbolo conhecido de nome parecido, entre os do
  arquivo e de todos os includes transitivos. É o mesmo universo do
  autocomplete, então a sugestão nunca aponta para algo invisível ao arquivo;
- `PP0011`/`PP0012` — remove a linha da diretiva, arrastando continuações
  com `\` no fim;
- `PP0017` — reindenta a linha pelo formatador, com o estilo configurado no
  workspace (preset e overrides), em vez de uma indentação fixa.

`PP0014`/`PP0015` ficam de fora de propósito: remover uma `native` ou um
`forward` de uma include quebraria quem a consome.

A distância de edição que o PP0019 usava sai de `pragmas.rs` para
`similar.rs`, agora compartilhada com o PP0010, com tolerância proporcional
ao tamanho do nome — um `max` fixo trata mal os extremos.
O `sort_text` punha os símbolos globais em `0_` e as variáveis locais em
`1_`: dentro de uma função, os parâmetros e as locais apareciam **abaixo** de
milhares de nativas dos includes — o inverso do útil.

A ordem passa a ser explícita, num `Rank`: locais e parâmetros, símbolos do
próprio arquivo, símbolos dos includes, palavras-chave, e por último os
marcados com `#pragma deprecated`. Um descontinuado continua na lista, mas
nunca à frente de uma alternativa viva. Dentro do grupo, a ordem é alfabética
sem diferenciar caixa — sem isso "Zebra" viria antes de "alfa".

A lista também era enviada inteira a cada tecla. Passa a ser cortada em 1000
itens com `isIncomplete`, o mecanismo do LSP para listas grandes: o editor
pede de novo conforme o prefixo cresce. A ordenação acontece antes do corte,
então o que se descarta são os itens mais distantes do cursor.
**Doc de um símbolo no hover de outro.** Ao ver uma linha terminada em `*/`,
`extract_doc` empurrava a linha e procurava o `/*` de abertura a partir da
**anterior** — mas um bloco de uma linha (`/** … */`) já está completo. A
busca então atravessava o código acima até casar com o `/**` de outro
comentário, e o hover de um `#define` saía com a documentação da função
anterior mais o código do meio.

Um bloco de uma linha passa a encerrar ali mesmo, e um `*/` sem abertura
devolve `None` em vez de arrastar o arquivo até o topo.

**Hover desalinhado.** O aviso de depreciado era um blockquote (`> …`): o
editor recuava o bloco e lia o `---` seguinte como continuação, desalinhando
a documentação. Vira texto normal, e passa a mostrar a mensagem do
`#pragma deprecated` — que até então só aparecia no aviso de uso.
Um cabeçalho de seção acima de uma função era tratado como documentação
dela, e o hover mostrava a régua mais o texto da seção:

    // ---------------------------------------------------
    // 9. Símbolos vindos dos includes
    // ---------------------------------------------------

    stock TesteIncludes(playerid)   // hover exibia o bloco acima

Uma linha de comentário composta só de ornamento (`-`, `=`, `*`, `_`, `#`,
`~`) encerra a varredura: além de não documentar nada, o que está acima dela
pertence a outra seção do arquivo.

Comentários `//` com texto seguem valendo como documentação — é convenção
legítima em Pawn, e só a régua sai.
Explicavam o mecanismo onde bastava dizer o que fazer.

  "`#pragma x` não é reconhecido pelo compilador"  → "`#pragma x` não existe"
  "… — você quis dizer `deprecated`?"              → "… — use `deprecated`"
  "toma o resto da linha como texto — as aspas
   entrariam na mensagem"                          → "A mensagem não leva
                                                      aspas — elas entrariam
                                                      no texto"
  "\"x\" está marcado como depreciado"             → "\"x\" está depreciado"

Nos títulos das ações, o alvo já está no contexto do cursor: "Remover o corpo
da declaração" → "Remover o corpo"; "Corrigir a indentação desta linha" →
"Corrigir a indentação"; "Renomear \"a\" para \"b\"" → "Renomear para \"b\"".

Nos cinco idiomas.
A correção anterior só reconhecia a régua pura (`// --------`). O cabeçalho
que traz texto entre ornamentos continuava virando documentação:

    // --- PP0004: `stock` sem corpo ---------------------
    stock FuncaoSemCorpo(playerid);   // hover exibia a linha acima

Passa a valer também quando a linha abre e fecha com uma corrida de três ou
mais ornamentos. O limite de três é o que separa cabeçalho de prosa: um
hífen isolado é comum em texto (`// vale -1 quando ausente`) e segue sendo
documentação.
A varredura subia o arquivo acumulando linhas de comentário, e trazia para o
hover réguas, cabeçalhos de seção e o texto de outras funções. As correções
anteriores atacavam cada sintoma — reconhecer régua pura, depois cabeçalho
com texto entre ornamentos — quando o problema era a varredura não ter fim.

Passa a valer a regra do Javadoc/PHPDoc: **um bloco só, o imediatamente
acima da declaração**. Um `/* … */` colado nela, ou uma sequência contígua
de linhas `//`. Linha em branco ou código entre os dois separa.

Com isso saem `is_comment_rule` e a heurística de ornamentos: não é mais
preciso adivinhar o que é separador, porque nada além do bloco vizinho é
lido. O `#pragma deprecated` entre o comentário e a declaração continua
sendo pulado — é a diretiva que marca aquele símbolo.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant