코드에서 어떤 부분이 사용되지 않는지 어떻게 알 수 있습니까?


312

사용하지 않는 코드를 제거 해야하는 레거시 C ++ 코드가 있습니다. 문제는 코드 기반이 크다는 것입니다.

어떤 코드가 절대 호출 / 사용되지 않는지 어떻게 알 수 있습니까?


4
코드 쿼리 언어를 사용하면 프로젝트 전체를 더 잘 볼 수 있다고 생각합니다. 나는 C ++ 세계에 대해 확신하지 못하지만 cppdepend.com (이것은 무료가 아닙니다)이 있는 것 같습니다 . 이와 같은 것이 무료로 제공 될 수 있습니다. 다른 것은 리팩토링을하기 전에 지금 당장 가지고 있지 않으면 제정신이 유닛 테스트를받는 것입니다. 단위 테스트를 통해 코드 커버리지 도구로 코드를 프로파일 링하여 코드를 처리 할 수없는 경우 죽은 코드를 제거하는 데 도움이됩니다.
Biswanath

3
여기에서 참조를 확인하십시오 : en.wikipedia.org/wiki/Unreachable_code
Martin York

6
비슷한 주제를 찾습니다. stackoverflow.com/questions/229069/…
UmmaGumma 2012 년

3
C ++의 재미있는 점 중 하나는 "사용하지 않은"함수를 제거해도 프로그램 결과가 변경 될 수 있다는 것입니다.
MSalters

1
@MSalters : 그것은 흥미로운 것입니다 ... 그렇다면, 주어진 호출에 대해 과부하 세트의 어떤 기능이 선택되는지에 대해 이야기해야 할 것입니다. 맞습니까? 내 지식으로는, named라는 두 함수 가 있고 첫 번째 f()f()모호하게 호출하면 두 번째 함수를 추가하는 것만으로는 해당 호출을 두 번째로 해결할 f()수 없습니다. "세 번째 기능을 추가하면 호출이 모호 해져서 프로그램이 컴파일되는 것을 막을 수 있습니다. 반례를보기를 좋아할 것입니다.
j_random_hacker

답변:


197

사용되지 않는 코드에는 두 가지 종류가 있습니다.

  • 로컬 함수, 즉 일부 함수에서는 일부 경로 또는 변수가 사용되지 않습니다 (또는 쓰지만 읽지 않는 것과 같이 의미있는 방식으로 사용되지 않음)
  • 전역 함수 : 절대 호출되지 않는 함수, 절대 액세스 할 수없는 전역 오브젝트

첫 번째 종류의 경우 좋은 컴파일러가 도움이 될 수 있습니다.

  • -Wunused(GCC, Clang )는 미사용 변수에 대해 경고해야하며, Clang 미사용 분석기는 읽지 않은 변수에 대해 경고하기 위해 증분되었습니다 (사용 되더라도).
  • -Wunreachable-code(이전 GCC, 2010 에서 제거됨 )는 액세스하지 않은 로컬 블록에 대해 경고해야합니다 (항상 true로 평가되는 초기 반환 또는 조건에서 발생)
  • catch컴파일러가 일반적으로 예외가 발생하지 않는다는 것을 증명할 수 없기 때문에 사용하지 않는 블록 에 대해 경고하는 옵션은 없습니다 .

두 번째 종류의 경우 훨씬 더 어렵습니다. 정적으로 전체 프로그램 분석이 필요하며 링크 시간 최적화가 실제로 데드 코드를 제거 할 수는 있지만 실제로 프로그램은 수행 될 때 너무 많이 변환되어 의미있는 정보를 사용자에게 전달하는 것이 거의 불가능합니다.

따라서 두 가지 접근 방식이 있습니다.

  • 이론적 인 것은 정적 분석기를 사용하는 것입니다. 전체 코드를 한 번에 자세히 검사하고 모든 흐름 경로를 찾는 소프트웨어입니다. 실제로 나는 여기서 작동하는 것을 모른다.
  • 실용적인 방법은 휴리스틱을 사용하는 것입니다. 코드 커버리지 도구를 사용하십시오 (GNU 체인에서는 gcov. 컴파일 중에는 특정 플래그를 전달해야 제대로 작동합니다). 다양한 범위의 입력 (단위 테스트 또는 회귀 테스트가 아닌)으로 코드 범위 도구를 실행하면 데드 코드가 도달 할 수없는 코드 내에 있어야하므로 여기에서 시작할 수 있습니다.

주제에 관심이 있고 실제로 도구를 직접 연습 할 시간과 성향이 있다면 Clang 라이브러리를 사용하여 그러한 도구를 만드는 것이 좋습니다.

  1. Clang 라이브러리를 사용하여 AST (추상 구문 트리)를 얻습니다.
  2. 진입 점부터 마크 앤 스윕 분석 수행

Clang은 코드를 구문 분석하고 과부하 해결을 수행하므로 C ++ 언어 규칙을 처리 할 필요가 없으며 당면한 문제에 집중할 수 있습니다.

그러나 이러한 종류의 기술은 사용하지 않는 가상 재정의를 식별 할 수 없습니다. 이유는 신뢰할 수없는 타사 코드로 호출 할 수 있기 때문입니다.


7
아주 좋아요, +1 어떤 상황에서도 절대로 실행되지 않는 것으로 정적으로 결정될 수있는 코드와 특정 실행에서 실행되지 않지만 잠재적으로 실행할 수있는 코드를 구별하고 싶습니다. 전자는 내가 생각하는 중요한 것이며, 전체 프로그램의 AST를 사용한 도달 가능성 분석은 그것을 얻는 방법입니다. ( foo()만 표시 될 때 "호출"으로 표시되는 것을 방지 if (0) { foo(); }하는 것은 보너스이지만 추가 스마트가 필요합니다.)
j_random_hacker

@ j_random_hacker : 아마도 CFG (Control-Flow Graph)를 사용하는 것이 더 좋을 것입니다 (예를 들어 주셔서 감사합니다). Clang은 언급 한 것과 같은 Tautological 비교에 대해 언급하고 CFG를 사용하여 데드 코드를 조기에 발견 할 수 있음을 알고 있습니다.
Matthieu M.

@Matthieu : 그래 아마도 CFG는 AST 대신 내가 의미하는 바이다.) 내 말은 : 정점이 함수이고 x가 y를 호출 할 수있을 때마다 함수 x에서 함수 y까지의 가장자리가있는 digraph이다. (그리고 오버로드 된 함수는 모두 뚜렷한 정점으로 표현된다는 점이 중요합니다. Clang처럼 들리는 소리, 휴!)
j_random_hacker

1
@j_random_hacker : 실제로 CFG는 조건문을 기반으로 한 블록에서 다른 블록으로의 링크로 블록에서 실행될 모든 코드를 나타 내기 때문에 단순한 digraph보다 더 복잡합니다. 주요 장점은 정적으로 죽은 것으로 결정될 수있는 코드를 제거 (정리할 수없는 블록을 생성 함) 할 수 있으므로 코드를 정리하는 데 자연적으로 적합하므로 AST보다 CFG를 활용하는 것이 더 좋습니다. 에 대해 이야기 ... 생각합니다 :)
Matthieu M.

1
@j_random_hacker : 실제로 Clang의 AST는 코드를 컴파일하는 것이 아니라 코드로 작업하기 때문에 모든 것을 명시 적으로 만듭니다 (또는 거의 ...). 실제로 암시 적 변환이 AST에 나타나지 않는 이니셜 라이저 목록에 문제가 있기 때문에 실제로 토론이 진행되고 있지만 수정 될 것입니다.
Matthieu M.

35

사용되지 않은 전체 함수 (및 사용되지 않은 전역 변수)의 경우 GCC와 GNU ld를 사용하는 경우 GCC는 실제로 대부분의 작업을 수행 할 수 있습니다.

소스를 컴파일 할 때는 -ffunction-sections및을 사용 하고 -fdata-sections링크 할 때는을 사용하십시오 -Wl,--gc-sections,--print-gc-sections. 링커는 이제 호출되지 않았기 때문에 제거 할 수있는 모든 함수와 참조되지 않은 모든 전역을 나열합니다.

(물론, --print-gc-sections파트를 건너 뛰고 링커에서 함수를 자동으로 제거하지만 소스에 유지하도록 할 수도 있습니다.)

참고 : 이것은 사용되지 않는 완전한 함수 만 찾을 수 있으며 함수 내의 데드 코드에 대해서는 아무 것도하지 않습니다. 라이브 함수의 데드 코드에서 호출 된 함수도 유지됩니다.

일부 C ++ 관련 기능은 특히 다음과 같은 문제를 일으킬 수 있습니다.

  • 가상 기능. 어떤 서브 클래스가 존재하고 어떤 서브 클래스가 런타임에 실제로 인스턴스화되는지 알지 못하면 최종 프로그램에 어떤 가상 함수가 있어야하는지 알 수 없습니다. 링커에는 그것에 대한 충분한 정보가 없으므로 모든 정보를 보관해야합니다.
  • 생성자와 생성자가있는 전역 일반적으로 링커는 전역의 생성자가 부작용이 없음을 알 수 없으므로 실행해야합니다. 분명히 이것은 지구 자체도 유지되어야 함을 의미합니다.

두 경우 모두, 아무것도 사용하는 가상 함수 나 전역 변수 생성자는 주위에 유지되어야한다.

공유 라이브러리를 구축하는 경우 GCC의 기본 설정 은 공유 라이브러리의 모든 기능 을 내보내 링커에 관한 한 "사용"될 수 있다는 추가 경고가 있습니다. 이 문제를 해결하려면 내보내기 대신 기호를 숨기도록 기본값을 설정 -fvisibility=hidden한 다음 (예 :) 내 보내야하는 내 보낸 함수를 명시 적으로 선택해야합니다.


실용적인 조언. 아무데도 사용되지 않는 기능 목록을 얻는 것만으로도 (이 목록이 완전하지 않은 경우에도) 내 생각에 많은 약한 과일을 얻을 수 있습니다.
j_random_hacker

나는 이것이 인스턴스화 되지 않은 템플릿 에 대해서는 효과가 없다고 생각합니다 .
Jakub Klinkovský

25

g ++을 사용하면이 플래그를 사용할 수 있습니다 -Wunused

문서에 따르면 :

변수가 선언과 별도로 사용되지 않고, 함수가 정적으로 선언되었지만 정의되지 않은 경우, 레이블이 선언되었지만 사용되지 않은 경우 및 명령문이 명시 적으로 사용되지 않은 결과를 계산할 때마다 경고합니다.

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

편집 : 다른 유용한 플래그는 다음과 같습니다 -Wunreachable-code .

이 옵션은 일부 조건이 충족되지 않거나 절대 반환되지 않는 프로 시저 이후이므로 컴파일러가 소스 코드의 전체 라인이 실행되지 않을 것임을 감지 할 때 경고하기위한 것입니다.

업데이트 : 레거시 C / C ++ 프로젝트 에서 비슷한 주제 데드 코드 감지를 발견 했습니다.


4
이것은 결코 호출되지 않은 함수를 프로토 타입 화하는 헤더를 포착하지 않습니다. 또는 호출되지 않는 공개 클래스 메소드. 로컬 범위 변수가 해당 범위 내에서 사용되는지 만 확인할 수 있습니다.
Falmarri

@ 팔 마리 나는이 플래그를 사용하지 않았습니다. 어떤 종류의 데드 코드로 찾을 수 있는지 알아 내려고 노력 중입니다.
UmmaGumma

-Wunused선언되었지만 실제로 사용되지 않은 변수에 대해 경고합니다. Clang에는 실험적 구현이 있습니다. Clang에는 (Ted Kremenek에 의해) 쓰여지지만 읽지 않는 비 휘발성 변수에 대해서도 경고합니다. -Wunreachable-code도달 할 수없는 함수 내의 코드에 대해 경고합니다 . 예를 들어 절대 론적 인 경우에 발생하지 않는 분기에서 throwor return문 또는 코드 뒤에있는 코드 일 수 있습니다 .
Matthieu M.

18

코드 커버리지 도구를 찾고 있다고 생각합니다 . 코드 커버리지 도구는 코드가 실행되는 동안 코드를 분석하고, 실행 된 코드 줄과 몇 번, 그리고 어떤 코드 줄이 아닌지 알려줍니다.

이 오픈 소스 코드 커버리지 도구에 기회를 줄 수 있습니다 : TestCocoon -C / C ++ 및 C # 용 코드 커버리지 도구.


7
여기서 핵심은 "실행 중"입니다. 입력 데이터에 경로가 사용 된 것으로 인식되지 않는 코드 경로가없는 경우 해당 경로가 인식됩니까?
sharptooth

1
맞아요. 코드를 실행하지 않으면 도달하지 못한 행을 알 수있는 방법이 없습니다. 몇 가지 정상적인 실행을 모방하기 위해 일부 단위 테스트를 설정하는 것이 얼마나 어려운지 궁금합니다.
Carlos V

1
@drhishch 나는 그렇게 사용되지 않는 대부분의 코드가 컴파일러가 아닌 링커를 찾아야한다고 생각합니다.
UmmaGumma

1
@drhirsch 사실, 컴파일러는 선언되었지만 호출되지 않은 함수 및 일부 단락 평가와 같이 도달 할 수없는 일부 코드를 처리 할 수 ​​있지만 사용자 작업 또는 런타임 변수에 의존하는 코드는 어떻습니까?
Carlos V

1
@golcarcol Ok, void func()b.cpp에서 사용되는 a.cpp의 함수 를 보자. 컴파일러가 프로그램에서 func ()가 사용되는지 어떻게 확인할 수 있습니까? 링커 일입니다.
UmmaGumma

15

실제 답변은 다음과 같습니다. 절대 확실하게 알 수 없습니다.

적어도 사소한 경우에는 모든 것을 얻었을 수도 있습니다. 도달 할 수없는 코드에 대한 Wikipedia의 기사에서 다음을 고려하십시오 .

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

Wikipedia가 올바르게 지적했듯이 영리한 컴파일러는 이와 같은 것을 잡을 수 있습니다. 그러나 수정을 고려하십시오.

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

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

컴파일러가 이것을 잡을까요? 아마도. 그러나이를 위해서는 sqrt상수 스칼라 값에 대해 실행 하는 것 이상을 수행해야 합니다. 그것은 그 파악해야한다 (double)y항상 정수 (쉬운) 될 것이며, 다음의 수학 범위 이해 sqrt정수 (하드)의 세트를. 매우 복잡한 컴파일러는 sqrt함수 또는 math.h의 모든 함수 또는 도메인을 파악할 수있는 고정 입력 함수에 대해이 작업을 수행 할 수 있습니다. 이것은 매우 복잡해지며 복잡성은 기본적으로 무한합니다. 컴파일러에 정교함을 계속 추가 할 수 있지만 주어진 입력 세트에 도달 할 수없는 일부 코드를 몰래 숨길 수있는 방법이 항상 있습니다.

그리고 입력 되지 않은 입력 세트 가 있습니다. 실생활에서 의미가 없거나 다른 곳의 검증 로직에 의해 차단되는 입력. 컴파일러가 이에 대해 알 수있는 방법이 없습니다.

이것의 최종 결과는 다른 사람들이 언급 한 소프트웨어 도구가 매우 유용하지만 나중에 수동으로 코드를 거치지 않으면 모든 것을 포착했는지 확실하게 알 수 없다는 것입니다. 그럼에도 불구하고, 당신은 당신이 아무것도 놓치지 않았다고 확신하지 못할 것입니다.

유일한 실제 솔루션 인 IMHO는 가능한 한주의를 기울이고, 원하는대로 자동화를 사용하고, 가능한 경우 리팩터링하며, 코드를 개선 할 수있는 방법을 지속적으로 찾는 것입니다. 물론 어쨌든 그렇게하는 것이 좋습니다.


1
사실이며 데드 코드를 넣지 마십시오! 기능을 제거하면 죽은 코드를 종료하십시오. "경우에 따라"그대로두면 나중에 논의하기 어려운 문제가 발생합니다. 버전 관리가 나중에 방해가되게하십시오.
궤도에서 가벼움 경주

12

나는 그것을 직접 사용하지는 않았지만 cppcheck 는 사용되지 않는 기능을 찾는 다고 주장합니다. 완전한 문제를 해결하지 못할 수도 있지만 시작일 수도 있습니다.


예, 지역 비 참조 변수 및 기능을 찾을 수 있습니다.
Chugaister

사용 cppcheck --enable=unusedFunction --language=c++ .하지 않는 기능을 찾는 데 사용하십시오.
Jason Harris

9

Gimple Software에서 PC-lint / FlexeLint를 사용해 볼 수 있습니다. 그것은 주장

전체 프로젝트에서 사용되지 않는 매크로, typedef, 클래스, 멤버, 선언 등을 찾습니다.

나는 정적 분석을 위해 그것을 사용했고 그것을 매우 좋아한다는 것을 알았지 만 죽은 코드를 찾기 위해 그것을 사용하지 않았다는 것을 인정해야합니다.


5

사용하지 않는 물건을 찾는 일반적인 방법은

  1. 빌드 시스템이 종속성 추적을 올바르게 처리하는지 확인하십시오.
  2. 전체 화면 터미널 창이있는 두 번째 모니터를 설정하고 반복 빌드를 실행하고 첫 번째 화면 출력을 표시합니다. watch "make 2>&1"유닉스에서 트릭을 수행하는 경향이 있습니다.
  3. 모든 줄의 시작 부분에 "//?"를 추가하여 전체 소스 트리에서 찾기 및 바꾸기 작업을 실행합니다.
  4. "//?"를 제거하여 컴파일러가 표시 한 첫 번째 오류를 수정하십시오. 해당 줄에.
  5. 남은 오류가 없을 때까지 반복하십시오.

이것은 다소 긴 프로세스이지만 좋은 결과를 제공합니다.


2
장점이 있지만 노동 집약적입니다. 또한 함수의 모든 오버로드를 동시에 주석 처리를 제거해야합니다. 둘 이상의 해당되는 경우, 선호하지 않는 것을 주석 해제하면 컴파일이 성공할 수 있지만 잘못된 프로그램 동작이 발생할 수 있습니다. 기능이 사용됩니다).
j_random_hacker

첫 번째 단계 (모든 오버로드)에서만 선언을 주석 해제하고 다음 반복에서는 누락 된 정의를 확인합니다. 그렇게하면 실제로 어떤 과부하가 사용되는지 알 수 있습니다.
Simon Richter

@Simon : 흥미롭게도 주요 질문에 대한 의견에서 MSalters는 호출되지 않은 함수에 대한 선언의 존재 여부조차도 과부하 해결에 의해 발견되는 다른 두 함수 중 어떤 것에 영향을 줄 수 있다고 지적합니다. 분명히 이것은 매우 기괴하고 고안된 설정을 필요로하므로 실제로 문제가되지는 않습니다.
j_random_hacker

4

컴파일 오류를 발생시키지 않으면 서 많은 공용 함수 및 변수를 개인용 또는 보호 된 것으로 표시하십시오. 이렇게하는 동안 코드도 리팩토링하십시오. 기능을 비공개로 만들고 어느 정도 보호하면 검색 기능이 줄어 듭니다. 비공개 기능은 같은 클래스에서만 호출 할 수 있기 때문입니다 (액세스 제한을 우회하는 어리석은 매크로 나 다른 트릭이없는 경우에는 권장됩니다) 새로운 직업을 찾으십시오). 현재 작업중 인 클래스만이 함수를 호출 할 수 있으므로 개인 함수가 필요하지 않다는 것을 결정하는 것이 훨씬 쉽습니다. 코드 기반에 작은 클래스가 있고 느슨하게 연결된 경우이 방법이 더 쉽습니다. 코드베이스에 작은 클래스가 없거나 결합이 매우 타이트한 경우 먼저 정리하는 것이 좋습니다.

다음으로 나머지 모든 공용 함수를 표시하고 클래스 간의 관계를 파악하기 위해 호출 그래프를 작성합니다. 이 나무에서 가지의 어떤 부분이 잘릴 수 있는지 알아 봅니다.

이 방법의 장점은 모듈 단위로 수행 할 수 있으므로 코드 기반이 깨졌을 때 오랜 시간이 걸리지 않고 단위 테스트를 계속 통과하기 쉽다는 것입니다.


3

Linux를 callgrind사용하는 경우 valgrind제품군의 일부인 C / C ++ 프로그램 분석 도구 인 메모리 누수 및 기타 메모리 오류 (사용해야하는)를 검사하는 도구가 포함되어 있습니다. 실행중인 프로그램 인스턴스를 분석하고 호출 그래프 및 호출 그래프에서 노드의 성능 비용에 대한 데이터를 생성합니다. 일반적으로 성능 분석에 사용되지만 응용 프로그램에 대한 호출 그래프도 생성하므로 호출자와 함께 어떤 함수가 호출되는지 확인할 수 있습니다.

이것은 페이지의 다른 곳에서 언급 된 정적 메소드를 보완하는 것으로, 완전히 사용되지 않는 클래스, 메소드 및 함수를 제거하는 데 도움이됩니다. 실제로 호출되는 메소드 내에서 죽은 코드를 찾는 데 도움이되지 않습니다.


3

나는 실제로 그런 일을하는 도구를 사용하지 않았습니다 ...하지만 모든 대답에서 본 한, 아무도이 문제를 계산할 수 없다고 말한 적이 없습니다.

이것이 무엇을 의미합니까? 이 문제는 컴퓨터의 어떤 알고리즘으로도 해결할 수 없습니다. 이 정리 (이러한 알고리즘이 존재하지 않음)는 Turing의 Halting Problem의 결과입니다.

사용할 모든 도구는 알고리즘이 아니라 휴리스틱입니다 (예 : 정확한 알고리즘이 아님). 사용되지 않은 모든 코드를 정확하게 제공하지는 않습니다.


1
OP는 주로 어디서나 호출되지 않는 함수를 찾으려고 생각합니다. 그것은 최소한의 고통과 마약으로 정보를 추출하는 것입니다.
j_random_hacker

네 말이 맞아, 나는 주요 질문에 대한 마지막 의견을 보지 못했다. 그런데 실제로 사용되지 않는 코드에서 참조되는 함수가있을 수 있습니다. 그런 종류의 것들이 감지되지 않을 수 있습니다.
geekazoid

2

한 가지 방법은 컴파일 중에 사용되지 않는 기계 코드를 제거하는 디버거 및 컴파일러 기능을 사용하는 것입니다.

일부 기계 코드가 제거되면 디버거는 해당 소스 코드 줄에 breakpojnt를 넣을 수 없습니다. 따라서 중단 점을 어디에나 배치하고 프로그램을 시작하고 중단 점을 검사합니다. "이 소스에로드 된 코드가없는"상태 인 코드는 제거 된 코드에 해당합니다. 해당 코드가 호출되지 않았거나 인라인되지 않았으며 최소한의 작업을 수행해야합니다. 이 두 가지 중 어느 것이 일어 났는지 찾아 내야합니다.

적어도 그것이 Visual Studio에서 작동하는 방식이며 다른 도구 세트도 그렇게 할 수 있다고 생각합니다.

많은 작업이지만 수동으로 모든 코드를 분석하는 것보다 빠릅니다.


4
OP의 질문은 더 작고 관리하기 쉬운 소스 코드의 하위 세트를 찾는 방법에 관한 것이며, 컴파일 된 바이너리가 효율적인지는 확실하지 않습니다.
j_random_hacker

@j_random_hacker 나는 그것을 주었다-그리고 코드 제거는 원래 소스 코드로 다시 추적하는 데 사용될 수 있음이 밝혀졌다.
sharptooth

그것을 달성하기 위해 Visual Studio의 특정 컴파일러 플래그가 있어야합니까? 릴리스 모드에서만 작동합니까, 아니면 디버그에서도 작동합니까?
Naveen

컴파일러에서 사용하지만 최적화 된 행은 어떻습니까?
Itamar Katz

@Naveen : Visual C ++ 9에서는 최적화를 켜고 / OPT : ICF를 사용해야합니다.
sharptooth

2

CppDepend 는 사용되지 않는 유형, 방법 및 필드를 감지하고 훨씬 더 많은 작업을 수행 할 수있는 상용 도구입니다. Windows 및 Linux에서 사용할 수 있지만 (현재 64 비트 지원은 없음) 2 주 평가판이 제공됩니다.

면책 조항 : 나는 거기에서 일하지 않지만이 도구에 대한 라이센스 ( .NET 코드에 대한 더 강력한 대안 인 NDepend )를 소유 하고 있습니다.

궁금한 사람들을 위해 다음은 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] }

업데이트 : Linux에 대한 64 비트 지원이 버전 3.1에 추가되었습니다.
Roman Boiko

1

응용 프로그램을 만드는 데 사용하는 플랫폼에 따라 다릅니다.

예를 들어 Visual Studio를 사용하는 경우 코드를 구문 분석하고 프로파일 링 할 수있는 .NET ANTS 프로파일 러 와 같은 도구를 사용할 수 있습니다 . 이런 식으로 코드의 어느 부분이 실제로 사용되는지 빠르게 알아야합니다. Eclipse에는 동등한 플러그인이 있습니다.

그렇지 않으면 최종 사용자가 실제로 사용하는 응용 프로그램의 기능을 알아야하고 응용 프로그램을 쉽게 해제 할 수있는 경우 감사를 위해 로그 파일을 사용할 수 있습니다.

각 주요 기능에 대해 사용량을 추적 할 수 있으며 며칠 / 주 후에 해당 로그 파일을 가져 와서 살펴보십시오.


1
.net ANTS Profiler는 C # 용으로 보입니다. C ++에서도 작동합니까?
j_random_hacker

@ j_random_hacker : 내가 아는 한 관리 코드와 함께 작동합니다. 따라서 .net ANTS는 '표준'C ++ 코드 (예 : gcc, ...로 컴파일)를 분석 할 수 없습니다.
AUS

0

나는 그것이 자동으로 이루어질 수 있다고 생각하지 않습니다.

코드 적용 도구를 사용하더라도 실행할 충분한 입력 데이터를 제공해야합니다.

Coverity 또는 LLVM 컴파일러 와 같은 매우 복잡하고 가격이 높은 정적 분석 도구 가 도움이 될 수 있습니다.

그러나 확실하지 않으며 수동 코드 검토를 선호합니다.

업데이트

글쎄 .. 사용하지 않는 변수 만 제거하면 사용되지 않는 함수는 어렵지 않습니다.

업데이트

다른 답변과 의견을 읽은 후에는 할 수 없다는 것을 더 확신합니다.

의미있는 코드 적용 범위 측정을 위해서는 코드를 알아야하며, 수동 편집을 많이 수행하면 적용 범위 결과를 준비 / 실행 / 검토하는 것보다 빠릅니다.


2
귀하의 답변에 대한 문구가 오도의 소지가 있습니다. LLVM에 대한 비판은 없습니다 ... 무료입니다!
Matthieu M.

수동 편집은 프로그램의 로직 로직 분기를 통과하는 런타임 변수에 도움이되지 않습니다. 코드가 특정 기준을 충족하지 않아서 항상 같은 경로를 따르는 경우 어떻게해야합니까?
Carlos V

0

나는 친구에게 오늘이 질문을 나에게 요청했으며 , 데드 코드 섹션을 결정하기 위해 컴파일하는 동안 진행 중에 충분한 가시성을 가질 수있는 유망한 Clang 개발 (예 : ASTMatcher정적 분석기) 을 살펴 보았습니다. 이것을 찾았습니다 :

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

참조되지 않은 심볼을 식별하기 위해 설계된 것처럼 보이는 몇 가지 GCC 플래그를 사용하는 방법에 대한 완전한 설명입니다!


0

어떤 함수가 호출 될지에 대한 일반적인 문제는 NP-Complete입니다. 튜링 기계가 멈추는 지 알 수 없으므로 어떤 기능이 호출되면 일반적인 방법으로 미리 알 수 없습니다. main ()에서 작성한 함수로 이동하는 경로가 (정적으로) 있으면 얻을 수 있지만 호출되지는 않습니다.


-3

g ++을 사용하면이 플래그를 사용할 수 있습니다-사용하지 않음

문서에 따르면 :

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

편집 : 여기에 다른 유용한 플래그가 있습니다-접근 할 수없는 코드 문서에 따르면 :

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.

6
이 정확한 정보는 현재 최고 답변에서 이미 언급되었습니다. 불필요한 중복을 피하기 위해 기존 답변을 읽으십시오.
j_random_hacker

1
이제 Peer Pressure 배지를 얻을 수 있습니다!
Andrew Grimm
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.