8
8
9
9
#include " IncludeCleaner.h"
10
10
#include " Config.h"
11
+ #include " Headers.h"
11
12
#include " ParsedAST.h"
12
13
#include " Protocol.h"
13
14
#include " SourceCode.h"
16
17
#include " clang/AST/ExprCXX.h"
17
18
#include " clang/AST/RecursiveASTVisitor.h"
18
19
#include " clang/Basic/SourceLocation.h"
20
+ #include " clang/Basic/SourceManager.h"
19
21
#include " clang/Lex/HeaderSearch.h"
20
22
#include " clang/Lex/Preprocessor.h"
21
23
#include " clang/Tooling/Syntax/Tokens.h"
@@ -221,6 +223,31 @@ bool mayConsiderUnused(const Inclusion &Inc, ParsedAST &AST) {
221
223
return true ;
222
224
}
223
225
226
+ // In case symbols are coming from non self-contained header, we need to find
227
+ // its first includer that is self-contained. This is the header users can
228
+ // include, so it will be responsible for bringing the symbols from given
229
+ // header into the scope.
230
+ FileID headerResponsible (FileID ID, const SourceManager &SM,
231
+ const IncludeStructure &Includes) {
232
+ // Unroll the chain of non self-contained headers until we find the one that
233
+ // can be included.
234
+ for (const FileEntry *FE = SM.getFileEntryForID (ID); ID != SM.getMainFileID ();
235
+ FE = SM.getFileEntryForID (ID)) {
236
+ // If FE is nullptr, we consider it to be the responsible header.
237
+ if (!FE)
238
+ break ;
239
+ auto HID = Includes.getID (FE);
240
+ assert (HID && " We're iterating over headers already existing in "
241
+ " IncludeStructure" );
242
+ if (Includes.isSelfContained (*HID))
243
+ break ;
244
+ // The header is not self-contained: put the responsibility for its symbols
245
+ // on its includer.
246
+ ID = SM.getFileID (SM.getIncludeLoc (ID));
247
+ }
248
+ return ID;
249
+ }
250
+
224
251
} // namespace
225
252
226
253
ReferencedLocations findReferencedLocations (ParsedAST &AST) {
@@ -234,20 +261,27 @@ ReferencedLocations findReferencedLocations(ParsedAST &AST) {
234
261
235
262
llvm::DenseSet<FileID>
236
263
findReferencedFiles (const llvm::DenseSet<SourceLocation> &Locs,
237
- const SourceManager &SM) {
264
+ const IncludeStructure &Includes, const SourceManager &SM) {
238
265
std::vector<SourceLocation> Sorted{Locs.begin (), Locs.end ()};
239
266
llvm::sort (Sorted); // Group by FileID.
240
- ReferencedFiles Result (SM);
267
+ ReferencedFiles Files (SM);
241
268
for (auto It = Sorted.begin (); It < Sorted.end ();) {
242
269
FileID FID = SM.getFileID (*It);
243
- Result .add (FID, *It);
270
+ Files .add (FID, *It);
244
271
// Cheaply skip over all the other locations from the same FileID.
245
272
// This avoids lots of redundant Loc->File lookups for the same file.
246
273
do
247
274
++It;
248
275
while (It != Sorted.end () && SM.isInFileID (*It, FID));
249
276
}
250
- return std::move (Result.Files );
277
+ // If a header is not self-contained, we consider its symbols a logical part
278
+ // of the including file. Therefore, mark the parents of all used
279
+ // non-self-contained FileIDs as used. Perform this on FileIDs rather than
280
+ // HeaderIDs, as each inclusion of a non-self-contained file is distinct.
281
+ llvm::DenseSet<FileID> Result;
282
+ for (FileID ID : Files.Files )
283
+ Result.insert (headerResponsible (ID, SM, Includes));
284
+ return Result;
251
285
}
252
286
253
287
std::vector<const Inclusion *>
@@ -304,12 +338,8 @@ std::vector<const Inclusion *> computeUnusedIncludes(ParsedAST &AST) {
304
338
const auto &SM = AST.getSourceManager ();
305
339
306
340
auto Refs = findReferencedLocations (AST);
307
- // FIXME(kirillbobyrev): Attribute the symbols from non self-contained
308
- // headers to their parents while the information about respective
309
- // SourceLocations and FileIDs is not lost. It is not possible to do that
310
- // later when non-guarded headers included multiple times will get same
311
- // HeaderID.
312
- auto ReferencedFileIDs = findReferencedFiles (Refs, SM);
341
+ auto ReferencedFileIDs = findReferencedFiles (Refs, AST.getIncludeStructure (),
342
+ AST.getSourceManager ());
313
343
auto ReferencedHeaders =
314
344
translateToHeaderIDs (ReferencedFileIDs, AST.getIncludeStructure (), SM);
315
345
return getUnused (AST, ReferencedHeaders);
0 commit comments