Como posso saber quais partes do código nunca são usadas?

312

Eu tenho código C ++ legado do qual devo remover o código não utilizado. O problema é que a base de código é grande.

Como posso descobrir qual código nunca é chamado / nunca usado?

user63898
fonte
4
Eu acho que uma linguagem de consulta de código fornecerá uma visão melhor do seu projeto como um todo. Não tenho certeza sobre o mundo c ++, mas parece haver cppdepend.com (isso não é gratuito), o que parece bastante decente. Pode ser que algo assim esteja disponível gratuitamente. A outra coisa é que, antes de fazer qualquer tipo de refatoração, a coisa mais sensata a fazer seria fazer testes de unidade, se você não tiver no momento. Com os testes de unidade, o que você pode fazer é ter suas ferramentas de cobertura de código com o perfil do seu código, que por si só ajudará a remover o código morto, se você não puder cobrir esse código.
quer
3
Confira a referência aqui: en.wikipedia.org/wiki/Unreachable_code
Martin York
6
Acho tópico semelhante. stackoverflow.com/questions/229069/…
UmmaGumma
3
Sim, uma das coisas engraçadas do C ++ é que a remoção de funções "não utilizadas" ainda pode alterar o resultado de um programa.
precisa saber é o seguinte
1
@MSalters: Essa é interessante ... Para que esse seja o caso, teríamos que estar falando sobre qual função em um conjunto de sobrecarga é escolhida para uma determinada chamada, correto? Que eu saiba, se houver duas funções nomeadas f()e uma chamada para f()resolver inequivocamente a 1ª, então não é possível fazer com que a chamada seja resolvida para a 2ª adicionando uma 3ª função chamada f()- a "pior coisa que você pode fazer "adicionando que a terceira função é fazer com que a chamada se torne ambígua e, portanto, impedir que o programa seja compilado. Adoraria (= ficar horrorizado) ver um contra-exemplo.
Jrandom_hacker

Respostas:

197

Existem duas variedades de código não utilizado:

  • o local, ou seja, em algumas funções, alguns caminhos ou variáveis ​​não são utilizados (ou usados, mas de nenhuma maneira significativa, como escritos, mas nunca lidos)
  • o global: funções que nunca são chamadas, objetos globais que nunca são acessados

Para o primeiro tipo, um bom compilador pode ajudar:

  • -Wunused(GCC, Clang ) deve avisar sobre variáveis ​​não utilizadas, o analisador não utilizado da Clang foi incrementado para avisar sobre variáveis ​​que nunca são lidas (mesmo sendo usadas).
  • -Wunreachable-code(GCC mais antigo, removido em 2010 ) deve avisar sobre blocos locais que nunca são acessados ​​(isso acontece com retornos ou condições precoces que sempre avaliam como verdadeiros)
  • não há opção que eu saiba para avisar sobre catchblocos não utilizados , porque o compilador geralmente não pode provar que nenhuma exceção será lançada.

Para o segundo tipo, é muito mais difícil. Estaticamente, é necessária uma análise completa do programa e, embora a otimização do tempo do link possa realmente remover o código morto, na prática o programa foi tão transformado no momento em que é executado que é quase impossível transmitir informações significativas ao usuário.

Existem, portanto, duas abordagens:

  • O teórico é usar um analisador estático. Um software que examinará todo o código de uma só vez em grande detalhe e encontrará todos os caminhos de fluxo. Na prática, não conheço nenhum que funcione aqui.
  • O pragmático é usar uma heurística: use uma ferramenta de cobertura de código (na cadeia GNU é gcov. Observe que sinalizadores específicos devem ser passados ​​durante a compilação para que funcione corretamente). Você executa a ferramenta de cobertura de código com um bom conjunto de entradas variadas (seus testes de unidade ou testes de não regressão), o código morto está necessariamente dentro do código não alcançado ... e assim você pode começar a partir daqui.

Se você está extremamente interessado no assunto e tem tempo e inclinação para realmente elaborar uma ferramenta por si mesmo, sugiro usar as bibliotecas Clang para criar essa ferramenta.

  1. Use a biblioteca Clang para obter um AST (árvore de sintaxe abstrata)
  2. Execute uma análise de marcação e varredura a partir dos pontos de entrada em diante

Como o Clang analisará o código para você e executará a resolução de sobrecarga, você não precisará lidar com as regras das linguagens C ++ e poderá se concentrar no problema em questão.

No entanto, esse tipo de técnica não pode identificar as substituições virtuais que não são utilizadas, pois elas podem ser chamadas por código de terceiros que você não pode raciocinar.

Matthieu M.
fonte
7
Muito bom, +1. Eu gosto que você faça uma distinção entre código que pode ser estaticamente determinado a nunca ser executado em nenhuma circunstância e código que não é executado em uma execução específica, mas potencialmente poderia. O primeiro é o mais importante, eu acho, e como você diz, uma análise de acessibilidade usando o AST de todo o programa é o caminho para obtê-lo. (Prevenção foo()de ser marcado como "chamada" quando ele aparece apenas em if (0) { foo(); }seria um bônus, mas requer smarts extra.)
j_random_hacker
@j_random_hacker: talvez o uso do CFG (Control-Flow Graph) seja melhor agora que penso nisso (graças ao seu exemplo). Sei que Clang está interessado em comentar sobre comparações tautológicas como a que você mencionou e, portanto, usando o CFG, podemos identificar códigos mortos no início.
Matthieu M. 27/01
@ Matthieu: Sim, talvez CFG seja o que eu quero dizer também, em vez de AST :) O que eu quero dizer é: um dígrafo no qual os vértices são funções e há uma margem da função x para a função y sempre que x possa chamar y. (E com a propriedade importante de que funções sobrecarregadas são todas representadas por vértices distintos - parece que Clang faz isso por você, ufa!)
j_random_hacker
1
@j_random_hacker: na verdade, o CFG é mais complicado do que um simples dígrafo, pois representa todo o código a ser executado em blocos com links de um bloco para outro com base em declarações condicionais. A principal vantagem é que ele é naturalmente adequado ao código de remoção que pode ser estaticamente determinado como morto (cria blocos inacessíveis que podem ser identificados); portanto, seria melhor explorar o CFG do que o AST para construir o dígrafo falando ... Eu acho que :)
Matthieu M.
1
@j_random_hacker: na verdade, o AST de Clang faz, torna tudo explícito (ou quase ...) porque é para trabalhar com o código, não apenas para compilá-lo. Na verdade, há uma discussão no momento porque, aparentemente, há um problema nas listas de inicializadores em que essa conversão implícita não aparece no AST, mas acho que será corrigido.
Matthieu M. 27/01
35

No caso de funções inteiras não utilizadas (e variáveis ​​globais não utilizadas), o GCC pode realmente fazer a maior parte do trabalho para você, desde que você esteja usando o GCC e o GNU ld.

Ao compilar a fonte, use -ffunction-sectionse -fdata-sections, em seguida, ao vincular o uso -Wl,--gc-sections,--print-gc-sections. O vinculador agora listará todas as funções que podem ser removidas porque nunca foram chamadas e todas as globais que nunca foram referenciadas.

(Obviamente, você também pode pular a --print-gc-sectionspeça e deixar o vinculador remover as funções silenciosamente, mas mantê-las na fonte.)

Nota: isso encontrará apenas funções completas não utilizadas, não fará nada sobre código morto nas funções. As funções chamadas de código morto nas funções ativas também serão mantidas.

Alguns recursos específicos do C ++ também causarão problemas, em particular:

  • Funções virtuais. Sem saber quais subclasses existem e quais são realmente instanciadas em tempo de execução, não é possível saber quais funções virtuais você precisa existir no programa final. O vinculador não tem informações suficientes sobre isso e, portanto, terá que manter todos eles por perto.
  • Globais com construtores e seus construtores. Em geral, o vinculador não pode saber que o construtor de um global não tem efeitos colaterais, portanto deve executá-lo. Obviamente, isso significa que o próprio mundo também precisa ser mantido.

Nos dois casos, qualquer coisa usada por uma função virtual ou por um construtor de variável global também deve ser mantida.

Uma ressalva adicional é que, se você estiver criando uma biblioteca compartilhada, as configurações padrão no GCC exportarão todas as funções da biblioteca compartilhada, fazendo com que ela seja "usada" no que diz respeito ao vinculador. Para corrigir isso, você precisa definir o padrão para ocultar símbolos em vez de exportar (usando, por exemplo -fvisibility=hidden) e, em seguida, selecionar explicitamente as funções exportadas que você precisa exportar.

olsner
fonte
Ótimos conselhos práticos. Apenas a obtenção de uma lista das funções conhecidas por não serem usadas em nenhum lugar (mesmo que, como você diz, esta lista não esteja completa) obterá muitas das frutas mais baixas que eu acho.
Jrandom_hacker
Acho que nada disso funciona para modelos não instanciados .
Jakub Klinkovský
25

Bem, se você estiver usando g ++, poderá usar esta flag -Wunused

De acordo com a documentação:

Avise sempre que uma variável não for usada, além de sua declaração, sempre que uma função for declarada estática, mas nunca definida, sempre que um rótulo for declarado mas não usado, e sempre que uma instrução computar um resultado que não é explicitamente usado.

http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html

Editar : Aqui está outro sinalizador útil -Wunreachable-code De acordo com a documentação:

Esta opção tem como objetivo avisar quando o compilador detectar que pelo menos uma linha inteira de código fonte nunca será executada, porque alguma condição nunca é satisfeita ou porque é após um procedimento que nunca retorna.

Atualização : Encontrei tópico semelhante Detecção de código morto no projeto C / C ++ herdado

UmmaGumma
fonte
4
Isso não irá capturar os cabeçalhos das funções de protótipo que nunca são chamadas. Ou métodos de classe pública que não são chamados. Ele só pode verificar se as variáveis ​​com escopo local são usadas nesse escopo.
Falmarri 27/01
@Falmarri Eu nunca usei essa bandeira. Estou tentando descobrir que tipo de códigos mortos posso encontrar com ele.
UmmaGumma
-Wunusedavisa sobre variáveis ​​que são declaradas (ou declaradas e definidas de uma só vez), mas que na verdade nunca são usadas. A propósito, é bastante irritante para os guardas com escopo definido: p Existe uma implementação experimental em Clang que também alerta para variáveis ​​não voláteis que são escritas para, mas nunca lidas (por Ted Kremenek). -Wunreachable-codeadverte sobre o código dentro de uma função que não pode ser alcançado, pode ser código localizado após uma throwou returndeclaração ou código em um ramo que nunca é levado (o que acontece em caso de comparações tautológicos), por exemplo.
Matthieu M. 27/01
18

Eu acho que você está procurando uma cobertura de código ferramenta de . Uma ferramenta de cobertura de código analisará seu código durante a execução e informará quais linhas de código foram executadas e quantas vezes, além de quais não foram.

Você pode tentar dar a essa ferramenta de cobertura de código-fonte aberto uma chance: TestCocoon - ferramenta de cobertura de código para C / C ++ e C #.

Carlos V
fonte
7
A chave aqui é "como está sendo executada" - se os dados de entrada não exercitarem algum caminho de código, esse caminho não será reconhecido como usado, certo?
Sharptooth
1
Está correto. Sem executar o código, não há como saber quais linhas não estão sendo alcançadas. Gostaria de saber como será difícil configurar alguns testes de unidade para emular algumas execuções normais.
Carlos V
1
@ Drhishch Eu acho que a maioria desses códigos não utilizados deve encontrar vinculador e não compilador.
UmmaGumma
1
@drhirsch É verdade que o compilador pode cuidar de parte do código inacessível, como funções declaradas mas não chamadas e algumas avaliações de curto-circuito, mas e o código que depende da ação do usuário ou variáveis ​​de tempo de execução?
Carlos V
1
@golcarcol Ok, vamos ter função void func()em a.cpp, que é usado em b.cpp. Como o compilador pode verificar, se o func () é usado no programa? É trabalho de vinculadores.
UmmaGumma
15

A resposta real aqui é: você nunca pode realmente ter certeza.

Pelo menos, para casos não triviais, você não pode ter certeza de ter conseguido tudo isso. Considere o seguinte no artigo da Wikipedia sobre código inacessível :

double x = sqrt(2);
if (x > 5)
{
  doStuff();
}

Como a Wikipedia observa corretamente, um compilador inteligente pode ser capaz de capturar algo assim. Mas considere uma modificação:

int y;
cin >> y;
double x = sqrt((double)y);

if (x != 0 && x < 1)
{
  doStuff();
}

O compilador vai entender isso? Talvez. Mas, para fazer isso, será necessário fazer mais do que executarsqrt contra um valor escalar constante. Ele terá que descobrir que (double)ysempre será um número inteiro (fácil) e, em seguida, entender o intervalo matemático de sqrtpara o conjunto de números inteiros (difícil). Um compilador muito sofisticado pode fazer isso para a sqrtfunção, ou para todas as funções em math.h , ou para qualquer função de entrada fixa cujo domínio ele possa descobrir. Isso fica muito, muito complexo, e a complexidade é basicamente ilimitada. Você pode continuar adicionando camadas de sofisticação ao seu compilador, mas sempre haverá uma maneira de ocultar algum código que será inacessível para qualquer conjunto de entradas.

E existem os conjuntos de entrada que simplesmente nunca são inseridos. Entrada que não faria sentido na vida real ou seria bloqueada pela lógica de validação em outro lugar. Não há como o compilador saber sobre isso.

O resultado final disso é que, embora as ferramentas de software mencionadas por outros sejam extremamente úteis, você nunca saberá com certeza que capturou tudo, a menos que repasse o código manualmente posteriormente. Mesmo assim, você nunca terá certeza de que não perdeu nada.

A única solução real, IMHO, é ser o mais vigilante possível, usar a automação à sua disposição, refatorar onde puder e procurar constantemente maneiras de melhorar seu código. Claro, é uma boa ideia fazer isso de qualquer maneira.

Justin Morgan
fonte
1
Verdadeiro e não deixe o código morto! Se você remover um recurso, mate o código morto. Deixá-lo lá "por precaução" apenas causa inchaço que (como você discutiu) é difícil de encontrar mais tarde. Deixe o controle de versão fazer a acumulação para você.
Lightness Races em órbita
12

Eu não o usei, mas o cppcheck afirma encontrar funções não utilizadas. Provavelmente não resolverá o problema completo, mas pode ser um começo.

Mr Shark
fonte
Sim, é capaz de encontrar variáveis ​​e funções locais não referenciadas.
Chugaister
Sim, use cppcheck --enable=unusedFunction --language=c++ .para encontrar essas funções não utilizadas.
Jason Harris
9

Você pode tentar usar o PC-lint / FlexeLint da Gimple Software . Alega

encontre macros, typedef, classes, membros, declarações, etc. não utilizados em todo o projeto

Usei-o para análise estática e achei muito bom, mas tenho que admitir que não o usei para encontrar especificamente código morto.

Tony
fonte
5

Minha abordagem normal para encontrar coisas não utilizadas é

  1. verifique se o sistema de compilação manipula o rastreamento de dependência corretamente
  2. configure um segundo monitor, com uma janela de terminal em tela cheia, executando construções repetidas e mostrando a primeira tela cheia de saída. watch "make 2>&1"tende a fazer o truque no Unix.
  3. execute uma operação de localização e substituição em toda a árvore de origem, adicionando "//?" no início de cada linha
  4. corrija o primeiro erro sinalizado pelo compilador, removendo o "//?" nas linhas correspondentes.
  5. Repita até que não haja mais erros.

Este é um processo um tanto demorado, mas oferece bons resultados.

Simon Richter
fonte
2
Tem mérito, mas exige muito trabalho. Além disso, você deve certificar-se de remover o comentário de todas as sobrecargas de uma função ao mesmo tempo - se houver mais de uma, a remoção de uma menos preferida pode permitir que a compilação seja bem-sucedida, mas resultar em comportamento incorreto do programa (e uma idéia incorreta da qual funções são usadas).
Jrandom_hacker
Apenas descomente as declarações na primeira etapa (todas as sobrecargas) e, na próxima iteração, vejo quais definições estão ausentes; Dessa forma, posso ver quais sobrecargas são realmente usadas.
Simon Richter
@ Simon: Curiosamente, em um comentário sobre a questão principal, o MSalters salienta que mesmo a presença / ausência de uma declaração para uma função que nunca é chamada pode afetar qual das outras 2 funções é encontrada por resolução de sobrecarga. É certo que isso requer uma configuração extremamente bizarra e artificial, por isso é improvável que seja um problema na prática.
Jrandom_hacker
4

Marque tantas funções públicas e variáveis ​​como privadas ou protegidas sem causar erro de compilação; ao fazer isso, tente refatorar o código. Ao tornar as funções privadas e, até certo ponto, protegidas, você reduziu sua área de pesquisa, pois as funções privadas só podem ser chamadas da mesma classe (a menos que haja macro estúpida ou outros truques para contornar a restrição de acesso, e se for esse o caso, recomendo encontrar um novo emprego). É muito mais fácil determinar que você não precisa de uma função privada, pois somente a classe em que você está trabalhando no momento pode chamar essa função. Esse método é mais fácil se a sua base de código tiver classes pequenas e for fracamente acoplada. Se sua base de código não possui classes pequenas ou possui um acoplamento muito rígido, sugiro limpá-las primeiro.

A seguir, marque todas as demais funções públicas e faça um gráfico de chamada para descobrir o relacionamento entre as classes. Nesta árvore, tente descobrir qual parte do ramo parece que pode ser aparada.

A vantagem desse método é que você pode fazê-lo por módulo, por isso é fácil continuar passando o seu melhor, sem ter um grande período de tempo quando você tem uma base de código quebrada.

Lie Ryan
fonte
3

Se você estiver no Linux, convém procurar callgrinduma ferramenta de análise de programa C / C ++ que faça parte dovalgrind conjunto, que também contém ferramentas que verificam vazamentos de memória e outros erros de memória (que você também deve usar). Ele analisa uma instância em execução do seu programa e produz dados sobre o gráfico de chamadas e os custos de desempenho dos nós no gráfico de chamadas. Geralmente é usado para análise de desempenho, mas também produz um gráfico de chamadas para seus aplicativos, para que você possa ver quais funções são chamadas, bem como seus chamadores.

Obviamente, isso é complementar aos métodos estáticos mencionados em outras partes da página e só será útil para eliminar classes, métodos e funções totalmente não utilizados - não ajuda a encontrar o código morto dentro dos métodos que são realmente chamados.

Adam Higuera
fonte
3

Eu realmente não usei nenhuma ferramenta que faça isso ... Mas, até onde eu vi em todas as respostas, ninguém nunca disse que esse problema é incontestável.

O que quero dizer com isso? Que esse problema não pode ser resolvido por nenhum algoritmo de um computador. Esse teorema (de que tal algoritmo não existe) é um corolário do Problema de Parada de Turing.

Todas as ferramentas que você usará não são algoritmos, mas heurísticas (ou seja, algoritmos não exatos). Eles não fornecerão exatamente todo o código que não é usado.

geekazoid
fonte
1
Eu acho que o OP quer principalmente encontrar funções que não são chamadas de qualquer lugar, o que certamente não é incontestável - a maioria dos linkers modernos pode fazer isso! É apenas uma questão de extrair essas informações com a menor quantidade de dor e esforço.
Jrandom_hacker
Você está certo, eu não vi o último comentário à questão principal. A propósito, pode haver funções referidas no código que não são realmente usadas. Esse tipo de coisa pode não ser detectado.
precisa saber é o seguinte
2

Uma maneira é usar um depurador e o recurso de compilador para eliminar o código de máquina não utilizado durante a compilação.

Depois que algum código de máquina é eliminado, o depurador não permite que você coloque um breakpojnt na linha correspondente do código-fonte. Então você coloca pontos de interrupção em todos os lugares, inicia o programa e inspeciona os pontos de interrupção - aqueles que estão no estado "nenhum código carregado para esta fonte" correspondem ao código eliminado - ou esse código nunca é chamado ou foi incorporado e é necessário executar um mínimo análise para descobrir qual desses dois aconteceu.

Pelo menos é assim que funciona no Visual Studio e acho que outros conjuntos de ferramentas também podem fazer isso.

Isso dá muito trabalho, mas acho que mais rápido do que analisar manualmente todo o código.

dente afiado
fonte
4
Eu acho que a pergunta do OP é sobre como encontrar um subconjunto menor e mais gerenciável de código-fonte, não muito para garantir que o binário compilado seja eficiente.
Jrandom_hacker
@j_random_hacker Eu pensei um pouco - e acontece que a eliminação de código pode até ser usada para rastrear o código-fonte original.
sharptooth 27/01
você precisa de alguns sinalizadores de compilador específicos no visual studio para alcançá-lo? e funciona apenas no modo de lançamento ou também funciona na depuração?
Naveen
E as linhas usadas, mas otimizadas pelo compilador?
Itamar Katz
@ Naveen: No Visual C ++ 9, você precisa ativar a otimização e usar / OPT: ICF #
sharptooth
2

O CppDepend é uma ferramenta comercial que pode detectar tipos, métodos e campos não utilizados e fazer muito mais. Está disponível para Windows e Linux (mas atualmente não possui suporte a 64 bits) e vem com uma avaliação de 2 semanas.

Isenção de responsabilidade: não trabalho lá, mas possuo uma licença para esta ferramenta (assim como o NDepend , que é uma alternativa mais poderosa ao código .NET).

Para quem está curioso, aqui está um exemplo de regra interna (personalizável) para detectar métodos mortos, escrita em CQLinq :

// <Name>Potentially dead Methods</Name>
warnif count > 0
// Filter procedure for methods that should'nt be considered as dead
let canMethodBeConsideredAsDeadProc = new Func<IMethod, bool>(
    m => !m.IsPublic &&       // Public methods might be used by client applications of your Projects.
         !m.IsEntryPoint &&            // Main() method is not used by-design.
         !m.IsClassConstructor &&      
         !m.IsVirtual &&               // Only check for non virtual method that are not seen as used in IL.
         !(m.IsConstructor &&          // Don't take account of protected ctor that might be call by a derived ctors.
           m.IsProtected) &&
         !m.IsGeneratedByCompiler
)

// Get methods unused
let methodsUnused = 
   from m in JustMyCode.Methods where 
   m.NbMethodsCallingMe == 0 && 
   canMethodBeConsideredAsDeadProc(m)
   select m

// Dead methods = methods used only by unused methods (recursive)
let deadMethodsMetric = methodsUnused.FillIterative(
   methods => // Unique loop, just to let a chance to build the hashset.
              from o in new[] { new object() }
              // Use a hashet to make Intersect calls much faster!
              let hashset = methods.ToHashSet()
              from m in codeBase.Application.Methods.UsedByAny(methods).Except(methods)
              where canMethodBeConsideredAsDeadProc(m) &&
                    // Select methods called only by methods already considered as dead
                    hashset.Intersect(m.MethodsCallingMe).Count() == m.NbMethodsCallingMe
              select m)

from m in JustMyCode.Methods.Intersect(deadMethodsMetric.DefinitionDomain)
select new { m, m.MethodsCallingMe, depth = deadMethodsMetric[m] }
Roman Boiko
fonte
Atualização: o suporte de 64 bits para Linux foi adicionado na versão 3.1.
Roman Boiko
1

Depende da plataforma que você usa para criar seu aplicativo.

Por exemplo, se você usa o Visual Studio, pode usar uma ferramenta como o .NET ANTS Profiler, capaz de analisar e criar um perfil do seu código. Dessa forma, você deve saber rapidamente qual parte do seu código é realmente usada. O Eclipse também possui plugins equivalentes.

Caso contrário, se você precisar saber qual função do seu aplicativo é realmente usada pelo usuário final e se puder liberá-lo facilmente, poderá usar um arquivo de log para uma auditoria.

Para cada função principal, você pode rastrear seu uso e, após alguns dias / semana, obtenha esse arquivo de log e dê uma olhada nele.

AUS
fonte
1
O .net ANTS Profiler parece ser para C # - você tem certeza de que também funciona com C ++?
Jrandom_hacker
@j_random_hacker: desde que eu saiba, ele funciona com código gerenciado. Portanto, o .net ANTS certamente não será capaz de analisar o código C ++ 'padrão' (ou seja, compilado com o gcc, ...).
AUS
0

Eu não acho que isso possa ser feito automaticamente.

Mesmo com as ferramentas de cobertura de código, você precisa fornecer dados de entrada suficientes para executar.

Pode ser uma ferramenta de análise estática muito complexa e de alto preço, como os compiladores Coverity ou LLVM, que podem ajudar.

Mas não tenho certeza e prefiro a revisão manual do código.

ATUALIZADA

Bem .. apenas removendo variáveis ​​não utilizadas, funções não utilizadas não é difícil.

ATUALIZADA

Depois de ler outras respostas e comentários, estou mais convencido de que isso não pode ser feito.

Você precisa conhecer o código para obter uma medida significativa da cobertura do código e, se souber que muita edição manual será mais rápida do que preparar / executar / revisar os resultados da cobertura.

9dan
fonte
2
a redação da sua resposta é enganosa, não há nada caro no LLVM ... é grátis!
Matthieu M. 27/01
a edição manual não o ajudará com variáveis ​​de tempo de execução que passam pelas ramificações lógicas do seu programa. E se o seu código nunca atender a um determinado critério e, portanto, sempre seguir o mesmo caminho?
Carlos V
0

Hoje, um amigo me fez essa pergunta e observei alguns desenvolvimentos promissores do Clang, como o ASTMatcher e o Static Analyzer que podem ter visibilidade suficiente durante a compilação para determinar as seções do código morto, mas então eu encontrou o seguinte:

https://blog.flameeyes.eu/2008/01/today-how-to-identify-unused-exported-functions-and-variables

É praticamente uma descrição completa de como usar alguns sinalizadores do GCC que aparentemente foram projetados com a finalidade de identificar símbolos não referenciados!

Steven Lu
fonte
0

O problema geral de se alguma função será chamada é NP-Complete. Você não pode saber antecipadamente de uma maneira geral se alguma função será chamada, pois você não saberá se uma máquina de Turing irá parar. Você pode descobrir se existe algum caminho (estaticamente) que vai de main () para a função que você escreveu, mas isso não garante que será chamado.

Luis Colorado
fonte
-3

Bem, se você estiver usando g ++, poderá usar esta flag -Wunused

De acordo com a documentação:

Warn whenever a variable is unused aside from its declaration, whenever a function is declared static but never defined, whenever a label is declared but not used, and whenever a statement computes a result that is explicitly not used.

http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html

Edit: Aqui está outro sinalizador útil -Wunreachable-code De acordo com a documentação:

This option is intended to warn when the compiler detects that at least a whole line of source code will never be executed, because some condition is never satisfied or because it is after a procedure that never returns.
ram singh
fonte
6
Esta informação exata já foi mencionada na resposta atualmente com a melhor classificação. Leia as respostas existentes para evitar duplicação desnecessária.
Jrandom_hacker
1
Agora você pode ganhar seu distintivo de Pressão dos Pares!
Andrew Grimm