Pular para o conteúdo

Pesquisa de AST indexada

A pesquisa de AST indexada é a versão com cache aquecido de Pesquisa de AST. Na primeira chamada, fatos no nível dos nós (nomes de chamadas, instanciações, declarações de classes e declarações de métodos) são extraídos para um armazenamento em disco; nas chamadas seguintes, o armazenamento permite ignorar arquivos que claramente não podem conter uma correspondência estrutural. Em seguida, o mecanismo de correspondência verifica novamente os candidatos usando o código-fonte.

O índice de fatos está disponível pelo subcomando greph-index ast-index CLI e pelos métodos de fachada Greph::buildAstIndex() / Greph::searchAstIndexed(). Ele também participa de fluxos de trabalho aquecidos com vários índices e conjuntos respaldados por manifestos.

Criar o índice

Shell
# Full build at the current directory
./vendor/bin/greph-index ast-index build .

# Full build at an explicit root
./vendor/bin/greph-index ast-index build path/to/repo

# Use a non-default index directory
./vendor/bin/greph-index ast-index build . --index-dir /tmp/greph-ast-index

# Build a mutable overlay that can refresh cheaply on demand
./vendor/bin/greph-index ast-index build . \
  --lifecycle opportunistic-refresh \
  --auto-refresh-max-files 32 \
  --auto-refresh-max-bytes 1048576

Por padrão, o índice de fatos é armazenado em <root>/.greph-ast-index/.

Uma criação bem-sucedida exibe um resumo de uma linha:

Text
Built AST index for 2547 files in .greph-ast-index (84931 fact rows, +2547 ~0 -0 =0)

Os quatro contadores registram arquivos adicionados, atualizados, excluídos e inalterados desde a última criação.

Atualizar o índice

Shell
./vendor/bin/greph-index ast-index refresh .

refresh percorre novamente a raiz indexada, analisa outra vez os arquivos alterados e regrava apenas as linhas de fatos que mudaram. A saída usa os mesmos quatro contadores do índice de texto.

Os perfis de ciclo de vida funcionam da mesma forma que nos índices de texto aquecidos:

  • static: nunca verifica a atualidade nem modifica automaticamente
  • manual-refresh: informa o estado obsoleto em stats, mas nunca atualiza durante a pesquisa
  • opportunistic-refresh: atualiza durante a pesquisa somente quando o conjunto de alterações ainda é pequeno o bastante
  • strict-stale-check: rejeita pesquisas obsoletas em vez de atualizar

Consultar o índice

Shell
./vendor/bin/greph-index ast-index search 'new $CLASS()' src
./vendor/bin/greph-index ast-index search '$obj->$method($$$ARGS)' src
./vendor/bin/greph-index ast-index search --json 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-index search -l 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-index search --trace-plan 'new $CLASS()' src

A sintaxe das metavariáveis é idêntica à da pesquisa nativa de AST. Consulte Modos / Pesquisa de AST para ver a gramática completa.

Opções

Opção Significado
--lang NAME Linguagem da AST. Padrão: php
-j N, --jobs N Número de processos de trabalho paralelos
-l, --files-with-matches Listar apenas arquivos correspondentes
--glob GLOB Incluir apenas arquivos cujos caminhos correspondam a GLOB
--type NAME / --type-not NAME Filtro de tipo de arquivo
--json Emitir saída JSON
--no-ignore Ignorar .gitignore e .grephignore
--hidden Incluir arquivos ocultos
--strict-parse Falhar em erros de análise em vez de ignorá-los
--fallback MODE Comportamento para índice ausente: fail (padrão) ou scan
--index-dir DIR Usar um diretório de índice diferente do padrão
--trace-plan Emitir diagnósticos do planejador de AST aquecido em stderr
--show-index-origin Prefixar a saída com o rótulo do índice correspondente no modo de vários índices ou conjuntos

Alternativa para índice ausente

Por padrão, ast-index search gera um erro quando não há índice no local solicitado. Passe --fallback scan para recorrer a uma varredura nativa de AST. Essa opção é adequada para ferramentas que querem usar a pesquisa indexada quando disponível, mas ainda precisam produzir resultados quando o índice não foi criado.

Shell
./vendor/bin/greph-index ast-index search --fallback scan 'new $CLASS()' src

Você pode pesquisar em vários índices aquecidos de AST com um único comando repetindo --index-dir. Isso é útil para configurações como o núcleo WordPress junto com um plugin ou tema.

Shell
./vendor/bin/greph-index ast-index search \
  --index-dir ../wordpress/.greph-ast-index \
  --index-dir ./.greph-ast-index \
  --show-index-origin \
  'new $CLASS()' .

Quando --show-index-origin está habilitado, a saída recebe como prefixo o nome da entrada do índice aquecido correspondente, para que você possa ver qual raiz gerou o resultado.

Conjuntos de índices respaldados por manifesto

Para configurações estáveis com índices aquecidos, defina um manifesto e deixe greph-index set operar nos índices agrupados:

Shell
./vendor/bin/greph-index set build
./vendor/bin/greph-index set stats --mode ast-index --dry-refresh
./vendor/bin/greph-index set search --mode ast-index --show-index-origin 'new $CLASS()' .

Os subcomandos de conjunto compartilham o mesmo tratamento do ciclo de vida, as mesmas verificações de obsolescência e os mesmos diagnósticos do planejador que o uso direto de ast-index.

Diagnósticos do planejador

--trace-plan mostra como Greph reduziu a consulta antes de executar o mecanismo completo de correspondência. Para ast-index, isso normalmente inclui:

  • a assinatura geral de fatos extraída do padrão
  • quantos índices aquecidos foram pesquisados
  • quantos arquivos foram rejeitados pelo filtro de fatos
  • quantos arquivos candidatos foram analisados novamente para uma verificação estrutural exata

O que o índice armazena

Para cada arquivo indexado, o extrator de fatos de AST registra uma linha por nó "interessante". O conjunto de tipos de fatos abrange as construções mais frequentemente visadas por padrões de AST:

  • Chamadas de funções e métodos (pelo nome chamado)
  • Instanciações de classes (pelo nome da classe)
  • Declarações de classes, interfaces, traits e enums (pelo nome)
  • Declarações de funções (pelo nome)
  • Declarações de métodos (pelo nome e pela visibilidade)
  • Instruções de importação

Quando uma consulta chega, Greph\Ast\AstFactQuery converte o padrão de pesquisa em uma assinatura geral de fatos (por exemplo, "deve conter um new de qualquer classe") e cruza os dados do armazenamento de fatos. Os arquivos que passam por esse cruzamento são analisados novamente e comparados com o padrão completo.

Isso significa que o índice de fatos é um pré-filtro, não um armazenamento de correspondências totalmente precisas. A etapa de correspondência ainda analisa o código-fonte, então a correção estrutural é idêntica à da pesquisa nativa de AST; apenas o conjunto de candidatos é menor.

Quando usar

O modo de AST indexada é a ferramenta adequada quando:

  • Você executa repetidamente as mesmas consultas estruturais na mesma base de código.
  • Os padrões visam formas identificáveis (nome de chamada, nome de classe, tipo de declaração) armazenadas pelo extrator de fatos.
  • Você quer reduzir a latência em comparação com analisar novamente todos os arquivos.

Para padrões cuja característica distintiva não está no conjunto de fatos (por exemplo, expressões aninhadas complexas sem um elemento inicial reconhecível), o modo de AST em cache costuma ser mais adequado, pois ignora completamente a etapa de análise sem depender de uma assinatura geral.

Uso programático

PHP
use Greph\Greph;
use Greph\Ast\AstSearchOptions;
use Greph\Index\IndexLifecycleProfile;

Greph::buildAstIndex('.', lifecycle: IndexLifecycleProfile::OpportunisticRefresh);

$matches = Greph::searchAstIndexed(
    'new $CLASS()',
    'src',
    new AstSearchOptions(jobs: 4, tracePlan: true),
);

searchAstIndexed aceita o mesmo AstSearchOptions da pesquisa nativa de AST e retorna o mesmo formato de list<AstMatch>. Para fluxos com vários índices ou respaldados por manifestos, use searchAstIndexedMany(...) e searchAstIndexedSet(...).