xaizek / unused-funcs (License: GPLv2+) (since 2018-12-07)
Clang-based standalone tool that detects unused external functions in a set of source files.
Commit 02d82e07e480bb75c64ab87de67bd68401056145

Print diagnostics
Author: xaizek
Author date (UTC): 2014-04-06 09:59
Committer name: xaizek
Committer date (UTC): 2014-04-06 09:59
Parent(s): 0777cb152b66e2c37fe33b7253d93757833ff4cb
Signing key:
Tree: cb1ff2817c043b9b5b3a3311c43a642b59e14775
File Lines added Lines deleted
CMakeLists.txt 2 1
Finder.cpp 75 39
FuncInfo.cpp 89 0
FuncInfo.hpp 69 0
RefInfo.cpp 12 25
RefInfo.hpp 13 19
File CMakeLists.txt changed (mode: 100644) (index b353eec..d6ba80d)
1 1 set(LLVM_LINK_COMPONENTS support) set(LLVM_LINK_COMPONENTS support)
2 2 set(LLVM_USED_LIBS clangTooling clangBasic clangAST) set(LLVM_USED_LIBS clangTooling clangBasic clangAST)
3 3
4 add_clang_executable(unused-funcs unused-funcs.cpp Finder.cpp)
4 add_clang_executable(unused-funcs
5 unused-funcs.cpp Finder.cpp FuncInfo.cpp RefInfo.cpp)
5 6 target_link_libraries(unused-funcs clangTooling clangBasic clangASTMatchers) target_link_libraries(unused-funcs clangTooling clangBasic clangASTMatchers)
File Finder.cpp changed (mode: 100644) (index 4b224b1..5a6363b)
21 21 #include "Finder.hpp" #include "Finder.hpp"
22 22
23 23 #include <iostream> #include <iostream>
24 #include <map>
25 #include <string>
24 26
25 #include <clang/Basic/SourceLocation.h>
26 #include <clang/Basic/SourceManager.h>
27 #include <clang/AST/Decl.h>
27 28
28 29 #include <clang/ASTMatchers/ASTMatchFinder.h> #include <clang/ASTMatchers/ASTMatchFinder.h>
29 30
31 #include "FuncInfo.hpp"
32
33 using namespace clang;
30 34 using namespace clang::ast_matchers; using namespace clang::ast_matchers;
31 35
36 typedef std::map<std::string, FuncInfo> Funcs;
37
32 38 static DeclarationMatcher funcDecl = functionDecl().bind("func"); static DeclarationMatcher funcDecl = functionDecl().bind("func");
33 static StatementMatcher invocation = callExpr().bind("call");
39 static StatementMatcher funcRef =
40 declRefExpr( // referencing a variable/declaration
41 to( // something that is ...
42 functionDecl( // ... a function
43
44 )
45 )
46 ).bind("ref"); // bind matched function ref to "ref" name
34 47
35 48 namespace namespace
36 49 { {
 
... ... class MatchHelper : public MatchFinder::MatchCallback
39 52 { {
40 53 typedef MatchFinder::MatchResult Result; typedef MatchFinder::MatchResult Result;
41 54
55 public:
56 MatchHelper(std::map<std::string, FuncInfo> &funcs);
57
42 58 public: public:
43 59 virtual void run(const Result &result); virtual void run(const Result &result);
44 60
45 61 private: private:
46 void printOut(const Result &result, const clang::CallExpr *call) const;
62 Funcs::iterator registerFunc(const Result &result,
63 const FunctionDecl *func) const;
64
65 void registerRef(const Result &result, const DeclRefExpr *ref) const;
47 66
48 void printOut(const Result &result, const clang::FunctionDecl *func) const;
67 private:
68 Funcs &funcs;
49 69 }; };
50 70
71 MatchHelper::MatchHelper(std::map<std::string, FuncInfo> &funcs)
72 :funcs(funcs)
73 {
74 }
75
51 76 void void
52 77 MatchHelper::run(const Result &result) MatchHelper::run(const Result &result)
53 78 { {
54 typedef clang::FunctionDecl Func;
55 typedef clang::CallExpr Call;
79 typedef FunctionDecl Func;
80 typedef DeclRefExpr Ref;
56 81
57 82 if (const Func *func = result.Nodes.getNodeAs<Func>("func")) { if (const Func *func = result.Nodes.getNodeAs<Func>("func")) {
58 if (func->isExternallyVisible()) {
59 printOut(result, func);
60 }
61 } else if (const Call *call = result.Nodes.getNodeAs<Call>("call")) {
62 printOut(result, call);
83 static_cast<void>(registerFunc(result, func));
84 } else if (const Ref *ref = result.Nodes.getNodeAs<Ref>("ref")) {
85 registerRef(result, ref);
63 86 } }
64 87 } }
65 88
66 void
67 MatchHelper::printOut(const Result &result,
68 const clang::CallExpr *call) const
89 Funcs::iterator
90 MatchHelper::registerFunc(const Result &result, const FunctionDecl *func) const
69 91 { {
70 clang::FullSourceLoc fullLoc(call->getLocStart(), *result.SourceManager);
71
72 const std::string &fileName = result.SourceManager->getFilename(fullLoc);
73 const unsigned int lineNum = fullLoc.getSpellingLineNumber();
92 if (!func->isExternallyVisible() || func->isMain()) {
93 return Funcs::iterator();
94 }
74 95
75 std::cout << fileName
76 << ":"
77 << lineNum
78 << ":call of "
79 << call->getDirectCallee()->getNameAsString()
80 << '\n';
96 const Funcs::iterator it = funcs.find(func->getNameAsString());
97 if (it == funcs.end()) {
98 const std::string &name = func->getNameAsString();
99 FuncInfo info(func, result.SourceManager);
100 return funcs.insert(std::make_pair(name, info)).first;
101 } else {
102 it->second.processDeclaration(func, result.SourceManager);
103 return it;
104 }
81 105 } }
82 106
83 107 void void
84 MatchHelper::printOut(const Result &result,
85 const clang::FunctionDecl *func) const
108 MatchHelper::registerRef(const Result &result, const DeclRefExpr *ref) const
86 109 { {
87 clang::FullSourceLoc fullLoc(func->getLocStart(), *result.SourceManager);
88
89 const std::string &fileName = result.SourceManager->getFilename(fullLoc);
90 const unsigned int lineNum = fullLoc.getSpellingLineNumber();
91
92 std::cout << fileName
93 << ":"
94 << lineNum
95 << ":declaration of "
96 << func->getNameAsString()
97 << '\n';
110 if (const FunctionDecl *func = ref->getDecl()->getAsFunction()) {
111 const Funcs::iterator it = registerFunc(result, func);
112 if (it != Funcs::iterator()) {
113 it->second.registerRef(ref, result.SourceManager);
114 }
115 }
98 116 } }
99 117
100 118 } }
 
... ... class Finder::Impl
103 121 { {
104 122 public: public:
105 123 Impl(); Impl();
124 ~Impl();
106 125
107 126 public: public:
108 127 MatchFinder & getMatchFinder(); MatchFinder & getMatchFinder();
109 128
110 129 private: private:
130 Funcs funcs;
111 131 MatchHelper helper; MatchHelper helper;
112 132 MatchFinder matchFinder; MatchFinder matchFinder;
113 133 }; };
114 134
115 135 Finder::Impl::Impl() Finder::Impl::Impl()
136 :helper(funcs)
116 137 { {
117 138 matchFinder.addMatcher(funcDecl, &helper); matchFinder.addMatcher(funcDecl, &helper);
118 matchFinder.addMatcher(invocation, &helper);
139 matchFinder.addMatcher(funcRef, &helper);
140 }
141
142 Finder::Impl::~Impl()
143 {
144 for (Funcs::const_iterator cit = funcs.begin(); cit != funcs.end(); ++cit) {
145 const FuncInfo &funcInfo = cit->second;
146
147 if (funcInfo.isFullyDeclared()) {
148 if (funcInfo.isUnused()) {
149 std::cout << funcInfo << ":unused\n";
150 } else if (funcInfo.canBeMadeStatic()) {
151 std::cout << funcInfo << ":can be made static\n";
152 }
153 }
154 }
119 155 } }
120 156
121 157 Finder::MatchFinder & Finder::MatchFinder &
File FuncInfo.cpp added (mode: 100644) (index 0000000..c3057f0)
1 /*
2 * unused-funcs
3 *
4 * Copyright (C) 2014 xaizek.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "FuncInfo.hpp"
22
23 #include <clang/Basic/SourceLocation.h>
24 #include <clang/Basic/SourceManager.h>
25
26 #include <clang/AST/Decl.h>
27 #include <clang/AST/Expr.h>
28
29 FuncInfo::FuncInfo(const clang::FunctionDecl *func,
30 const clang::SourceManager *sm)
31 :name(func->getNameAsString())
32 ,lineNum(0U)
33 {
34 processDeclaration(func, sm);
35 }
36
37 void
38 FuncInfo::processDeclaration(const clang::FunctionDecl *func,
39 const clang::SourceManager *sm)
40 {
41 if (isFullyDeclared() || !func->isThisDeclarationADefinition()) {
42 return;
43 }
44
45 clang::FullSourceLoc fullLoc(func->getNameInfo().getBeginLoc(), *sm);
46 fileName = sm->getFilename(fullLoc);
47 lineNum = fullLoc.getSpellingLineNumber();
48 }
49
50 bool
51 FuncInfo::isFullyDeclared() const
52 {
53 return lineNum != 0U;
54 }
55
56 void
57 FuncInfo::registerRef(const clang::DeclRefExpr *ref,
58 const clang::SourceManager *sm)
59 {
60 calls.push_back(RefInfo(ref, sm));
61 }
62
63 bool
64 FuncInfo::isUnused() const
65 {
66 return calls.empty();
67 }
68
69 bool
70 FuncInfo::canBeMadeStatic() const
71 {
72 typedef Refs::const_iterator Cit;
73 for (Cit cit = calls.begin(); cit != calls.end(); ++cit) {
74 if (!cit->isInThisUnit(fileName)) {
75 return false;
76 }
77 }
78 return true;
79 }
80
81 std::ostream &
82 operator<<(std::ostream &os, const FuncInfo &fi)
83 {
84 return os << fi.fileName
85 << ':'
86 << fi.lineNum
87 << ':'
88 << fi.name;
89 }
File FuncInfo.hpp added (mode: 100644) (index 0000000..ec6aeed)
1 /*
2 * unused-funcs
3 *
4 * Copyright (C) 2014 xaizek.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #ifndef UNUSED_FUNCS__FUNCINFO_HPP__
22 #define UNUSED_FUNCS__FUNCINFO_HPP__
23
24 #include <iosfwd>
25 #include <string>
26 #include <vector>
27
28 #include "RefInfo.hpp"
29
30 namespace clang
31 {
32 class FunctionDecl;
33 class DeclRefExpr;
34 class SourceManager;
35 }
36
37 class FuncInfo
38 {
39 friend std::ostream & operator<<(std::ostream &os, const FuncInfo &fi);
40
41 public:
42 FuncInfo(const clang::FunctionDecl *func, const clang::SourceManager *sm);
43
44 public:
45 void processDeclaration(const clang::FunctionDecl *func,
46 const clang::SourceManager *sm);
47
48 bool isFullyDeclared() const;
49
50 void registerRef(const clang::DeclRefExpr *ref,
51 const clang::SourceManager *sm);
52
53 bool isUnused() const;
54
55 bool canBeMadeStatic() const;
56
57 private:
58 const std::string name;
59
60 std::string fileName;
61 unsigned int lineNum;
62
63 typedef std::vector<RefInfo> Refs;
64 Refs calls;
65 };
66
67 std::ostream & operator<<(std::ostream &os, const FuncInfo &fi);
68
69 #endif // UNUSED_FUNCS__FUNCINFO_HPP__
File RefInfo.cpp copied from file Finder.hpp (similarity 60%) (mode: 100644) (index 6a3e3ee..94b50d8)
18 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 19 */ */
20 20
21 #ifndef UNUSED_FUNCS__FINDER_HPP__
22 #define UNUSED_FUNCS__FINDER_HPP__
21 #include "RefInfo.hpp"
23 22
24 #include <memory>
23 #include <clang/Basic/SourceLocation.h>
24 #include <clang/Basic/SourceManager.h>
25 25
26 #include <clang/ASTMatchers/ASTMatchFinder.h>
26 #include <clang/AST/Expr.h>
27 27
28 class Finder
28 RefInfo::RefInfo(const clang::DeclRefExpr *ref, const clang::SourceManager *sm)
29 29 { {
30 typedef clang::ast_matchers::MatchFinder MatchFinder;
30 clang::FullSourceLoc fullLoc(ref->getExprLoc(), *sm);
31 fileName = sm->getFilename(fullLoc);
32 }
31 33
32 public:
33 Finder();
34 ~Finder();
35
36 public:
37 MatchFinder & getMatchFinder();
38
39 private:
40 // these operations are forbidden
41 Finder(const Finder &rhs);
42 Finder & operator=(const Finder &rhs);
43
44 private:
45 class Impl;
46
47 const std::auto_ptr<Impl> impl;
48 };
49
50 #endif // UNUSED_FUNCS__FINDER_HPP__
34 bool RefInfo::isInThisUnit(const std::string& other) const
35 {
36 return other == fileName;
37 }
File RefInfo.hpp copied from file Finder.hpp (similarity 62%) (mode: 100644) (index 6a3e3ee..57a600c)
18 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 19 */ */
20 20
21 #ifndef UNUSED_FUNCS__FINDER_HPP__
22 #define UNUSED_FUNCS__FINDER_HPP__
21 #ifndef UNUSED_FUNCS__REFINFO_HPP__
22 #define UNUSED_FUNCS__REFINFO_HPP__
23 23
24 #include <memory>
24 #include <string>
25 25
26 #include <clang/ASTMatchers/ASTMatchFinder.h>
27
28 class Finder
26 namespace clang
29 27 { {
30 typedef clang::ast_matchers::MatchFinder MatchFinder;
28 class DeclRefExpr;
29 class SourceManager;
30 }
31 31
32 class RefInfo
33 {
32 34 public: public:
33 Finder();
34 ~Finder();
35 RefInfo(const clang::DeclRefExpr *ref, const clang::SourceManager *sm);
35 36
36 37 public: public:
37 MatchFinder & getMatchFinder();
38 bool isInThisUnit(const std::string& other) const;
38 39
39 40 private: private:
40 // these operations are forbidden
41 Finder(const Finder &rhs);
42 Finder & operator=(const Finder &rhs);
43
44 private:
45 class Impl;
46
47 const std::auto_ptr<Impl> impl;
41 std::string fileName;
48 42 }; };
49 43
50 #endif // UNUSED_FUNCS__FINDER_HPP__
44 #endif // UNUSED_FUNCS__REFINFO_HPP__
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/unused-funcs

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/unused-funcs

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master