File src/IncludeFinderAction.cpp changed (mode: 100644) (index a67d4a3..e7554bd) |
25 |
25 |
#include <clang/Lex/Preprocessor.h> |
#include <clang/Lex/Preprocessor.h> |
26 |
26 |
#include <clang/Lex/PPCallbacks.h> |
#include <clang/Lex/PPCallbacks.h> |
27 |
27 |
|
|
|
28 |
|
#include <algorithm> |
28 |
29 |
#include <iostream> |
#include <iostream> |
|
30 |
|
#include <string> |
|
31 |
|
#include <vector> |
|
32 |
|
#include <utility> |
|
33 |
|
|
|
34 |
|
#include "path_utils.hpp" |
29 |
35 |
|
|
30 |
36 |
namespace |
namespace |
31 |
37 |
{ |
{ |
|
... |
... |
public: |
86 |
92 |
public: |
public: |
87 |
93 |
inline clang::PPCallbacks * createPreprocessorCallbacks(); |
inline clang::PPCallbacks * createPreprocessorCallbacks(); |
88 |
94 |
|
|
|
95 |
|
inline void diagnoseAndReport(); |
|
96 |
|
|
89 |
97 |
virtual inline void InclusionDirective(clang::SourceLocation hashLoc, |
virtual inline void InclusionDirective(clang::SourceLocation hashLoc, |
90 |
98 |
const clang::Token &includeTok, |
const clang::Token &includeTok, |
91 |
99 |
clang::StringRef fileName, |
clang::StringRef fileName, |
|
... |
... |
public: |
98 |
106 |
|
|
99 |
107 |
private: |
private: |
100 |
108 |
const clang::CompilerInstance &compiler; |
const clang::CompilerInstance &compiler; |
|
109 |
|
std::string name; |
|
110 |
|
|
|
111 |
|
typedef std::pair<int, std::string> IncludeInfo; |
|
112 |
|
typedef std::vector<IncludeInfo> Includes; |
|
113 |
|
Includes includes; |
101 |
114 |
}; |
}; |
102 |
115 |
|
|
103 |
116 |
inline |
inline |
104 |
117 |
IncludeFinder::IncludeFinder(const clang::CompilerInstance &compiler) |
IncludeFinder::IncludeFinder(const clang::CompilerInstance &compiler) |
105 |
118 |
: compiler(compiler) |
: compiler(compiler) |
106 |
119 |
{ |
{ |
|
120 |
|
const clang::FileID mainFile = compiler.getSourceManager().getMainFileID(); |
|
121 |
|
name = compiler.getSourceManager().getFileEntryForID(mainFile)->getName(); |
107 |
122 |
} |
} |
108 |
123 |
|
|
109 |
124 |
inline clang::PPCallbacks * |
inline clang::PPCallbacks * |
|
... |
... |
IncludeFinder::createPreprocessorCallbacks() |
112 |
127 |
return new CallbacksProxy(*this); |
return new CallbacksProxy(*this); |
113 |
128 |
} |
} |
114 |
129 |
|
|
|
130 |
|
typedef std::vector<std::string> KnownHdrExts; |
|
131 |
|
static KnownHdrExts |
|
132 |
|
getKnownHdrExts() |
|
133 |
|
{ |
|
134 |
|
KnownHdrExts knownHdrExts; |
|
135 |
|
knownHdrExts.push_back("h"); |
|
136 |
|
knownHdrExts.push_back("H"); |
|
137 |
|
knownHdrExts.push_back("hpp"); |
|
138 |
|
knownHdrExts.push_back("HPP"); |
|
139 |
|
knownHdrExts.push_back("hxx"); |
|
140 |
|
knownHdrExts.push_back("HXX"); |
|
141 |
|
return knownHdrExts; |
|
142 |
|
} |
|
143 |
|
static const KnownHdrExts KNOWN_HDR_EXTS = getKnownHdrExts(); |
|
144 |
|
|
|
145 |
|
template <typename C, typename T> |
|
146 |
|
inline bool |
|
147 |
|
contains(const C &c, const T &val) |
|
148 |
|
{ |
|
149 |
|
return std::find(c.begin(), c.end(), val) != c.end(); |
|
150 |
|
} |
|
151 |
|
|
|
152 |
|
inline void |
|
153 |
|
IncludeFinder::diagnoseAndReport() |
|
154 |
|
{ |
|
155 |
|
IncludeInfo selfInclude; |
|
156 |
|
|
|
157 |
|
const std::string &tail = path_utils::extractTail(name); |
|
158 |
|
const std::string &root = path_utils::extractRoot(tail); |
|
159 |
|
|
|
160 |
|
typedef Includes::iterator It; |
|
161 |
|
for (It it = includes.begin(); it != includes.end(); ++it) { |
|
162 |
|
const std::string &hdrName = it->second; |
|
163 |
|
|
|
164 |
|
const std::pair<std::string, std::string> nameParts = |
|
165 |
|
path_utils::crackName(hdrName); |
|
166 |
|
|
|
167 |
|
// if root parts are the same and extension is one of known |
|
168 |
|
// TODO: maybe compare roots case insensitive |
|
169 |
|
if (nameParts.first == root) { |
|
170 |
|
if (contains(KNOWN_HDR_EXTS, nameParts.second)) { |
|
171 |
|
if (selfInclude.second.empty()) { |
|
172 |
|
selfInclude = *it; |
|
173 |
|
} else { |
|
174 |
|
// TODO: issue a warning about failed self include detection |
|
175 |
|
std::cout << name |
|
176 |
|
<< ':' |
|
177 |
|
<< "ambiguous header name detection: " |
|
178 |
|
<< hdrName |
|
179 |
|
<< std::endl; |
|
180 |
|
} |
|
181 |
|
} |
|
182 |
|
} |
|
183 |
|
} |
|
184 |
|
|
|
185 |
|
|
|
186 |
|
if (!selfInclude.second.empty() && !includes.empty()) { |
|
187 |
|
if (includes[0] != selfInclude) { |
|
188 |
|
std::cout << name |
|
189 |
|
<< ':' |
|
190 |
|
<< selfInclude.first |
|
191 |
|
<< ':' |
|
192 |
|
<< "should be the first include in the file" |
|
193 |
|
<< std::endl; |
|
194 |
|
} |
|
195 |
|
} |
|
196 |
|
|
|
197 |
|
} |
|
198 |
|
|
115 |
199 |
inline void |
inline void |
116 |
200 |
IncludeFinder::InclusionDirective(clang::SourceLocation hashLoc, |
IncludeFinder::InclusionDirective(clang::SourceLocation hashLoc, |
117 |
201 |
const clang::Token &includeTok, |
const clang::Token &includeTok, |
|
... |
... |
IncludeFinder::InclusionDirective(clang::SourceLocation hashLoc, |
123 |
207 |
clang::StringRef relativePath, |
clang::StringRef relativePath, |
124 |
208 |
const clang::Module *imported) |
const clang::Module *imported) |
125 |
209 |
{ |
{ |
126 |
|
if (compiler.getSourceManager().isInMainFile(hashLoc)) { |
|
127 |
|
std::cout << fileName.str() << std::endl; |
|
|
210 |
|
clang::SourceManager &sm = compiler.getSourceManager(); |
|
211 |
|
|
|
212 |
|
if (sm.isInMainFile(hashLoc)) { |
|
213 |
|
const unsigned int lineNum = sm.getSpellingLineNumber(hashLoc); |
|
214 |
|
includes.push_back(std::make_pair(lineNum, fileName)); |
128 |
215 |
} |
} |
129 |
216 |
} |
} |
130 |
217 |
|
|
|
... |
... |
IncludeFinderAction::ExecuteAction() |
139 |
226 |
); |
); |
140 |
227 |
|
|
141 |
228 |
clang::PreprocessOnlyAction::ExecuteAction(); |
clang::PreprocessOnlyAction::ExecuteAction(); |
|
229 |
|
|
|
230 |
|
includeFinder.diagnoseAndReport(); |
142 |
231 |
} |
} |
File src/path_utils.cpp added (mode: 100644) (index 0000000..e944ee3) |
|
1 |
|
/* |
|
2 |
|
* self-inc-first |
|
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 "path_utils.hpp" |
|
22 |
|
|
|
23 |
|
#include <algorithm> |
|
24 |
|
#include <string> |
|
25 |
|
|
|
26 |
|
std::string |
|
27 |
|
path_utils::extractTail(std::string path) |
|
28 |
|
{ |
|
29 |
|
// normalize slashes |
|
30 |
|
std::replace(path.begin(), path.end(), '\\', '/'); |
|
31 |
|
|
|
32 |
|
// leave only trailing path component |
|
33 |
|
std::string::size_type tailPos = path.rfind('/'); |
|
34 |
|
tailPos = (tailPos == std::string::npos) ? 0UL : (tailPos + 1); |
|
35 |
|
return std::string(path, tailPos); |
|
36 |
|
} |
|
37 |
|
|
|
38 |
|
std::pair<std::string, std::string> |
|
39 |
|
path_utils::crackName(const std::string &name) |
|
40 |
|
{ |
|
41 |
|
const std::string::size_type dotPos = name.rfind('.'); |
|
42 |
|
const std::string::size_type extPos = (dotPos == std::string::npos) |
|
43 |
|
? 0UL |
|
44 |
|
: (dotPos + 1); |
|
45 |
|
|
|
46 |
|
return std::make_pair(std::string(name, 0UL, dotPos), |
|
47 |
|
std::string(name, extPos)); |
|
48 |
|
} |
|
49 |
|
|
|
50 |
|
std::string |
|
51 |
|
path_utils::extractRoot(const std::string &name) |
|
52 |
|
{ |
|
53 |
|
return std::string(name, 0UL, name.rfind('.')); |
|
54 |
|
} |
File src/path_utils.hpp copied from file src/IncludeFinderAction.hpp (similarity 68%) (mode: 100644) (index 2a066f4..254f01d) |
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 SELF_INC_FIRST__INCLUDEFINDERACTION_HPP__ |
|
22 |
|
#define SELF_INC_FIRST__INCLUDEFINDERACTION_HPP__ |
|
|
21 |
|
#ifndef SELF_INC_FIRST__PATH_UTILS_HPP__ |
|
22 |
|
#define SELF_INC_FIRST__PATH_UTILS_HPP__ |
23 |
23 |
|
|
24 |
|
#include <clang/Frontend/FrontendActions.h> |
|
|
24 |
|
#include <string> |
|
25 |
|
#include <utility> |
25 |
26 |
|
|
26 |
|
class IncludeFinderAction : public clang::PreprocessOnlyAction |
|
|
27 |
|
namespace path_utils |
27 |
28 |
{ |
{ |
28 |
|
protected: |
|
29 |
|
virtual void ExecuteAction(); |
|
30 |
|
}; |
|
31 |
29 |
|
|
32 |
|
#endif // SELF_INC_FIRST__INCLUDEFINDERACTION_HPP__ |
|
|
30 |
|
std::string extractTail(std::string path); |
|
31 |
|
|
|
32 |
|
std::pair<std::string, std::string> crackName(const std::string &name); |
|
33 |
|
|
|
34 |
|
std::string extractRoot(const std::string &name); |
|
35 |
|
|
|
36 |
|
} |
|
37 |
|
|
|
38 |
|
#endif // SELF_INC_FIRST__PATH_UTILS_HPP__ |