11
11
#include " clang/AST/ASTConsumer.h"
12
12
#include " clang/AST/ASTContext.h"
13
13
#include " clang/AST/DeclGroup.h"
14
+ #include " clang/Basic/FileEntry.h"
15
+ #include " clang/Basic/LLVM.h"
16
+ #include " clang/Basic/SourceLocation.h"
14
17
#include " clang/Basic/SourceManager.h"
15
18
#include " clang/Basic/Specifiers.h"
16
19
#include " clang/Frontend/CompilerInstance.h"
20
23
#include " clang/Lex/Preprocessor.h"
21
24
#include " clang/Tooling/Inclusions/HeaderAnalysis.h"
22
25
#include " clang/Tooling/Inclusions/StandardLibrary.h"
26
+ #include " llvm/ADT/ArrayRef.h"
27
+ #include " llvm/ADT/STLExtras.h"
28
+ #include " llvm/ADT/SmallVector.h"
23
29
#include " llvm/ADT/StringRef.h"
30
+ #include " llvm/Support/Allocator.h"
31
+ #include " llvm/Support/Error.h"
32
+ #include " llvm/Support/StringSaver.h"
33
+ #include < algorithm>
34
+ #include < assert.h>
24
35
#include < memory>
36
+ #include < optional>
25
37
#include < utility>
26
38
#include < vector>
27
39
@@ -262,32 +274,14 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
262
274
if (!Pragma)
263
275
return false ;
264
276
265
- if (Pragma->consume_front (" private" )) {
266
- auto *FE = SM.getFileEntryForID (SM.getFileID (Range.getBegin ()));
267
- if (!FE)
268
- return false ;
269
- StringRef PublicHeader;
270
- if (Pragma->consume_front (" , include " )) {
271
- // We always insert using the spelling from the pragma.
272
- PublicHeader = save (Pragma->startswith (" <" ) || Pragma->startswith (" \" " )
273
- ? (*Pragma)
274
- : (" \" " + *Pragma + " \" " ).str ());
275
- }
276
- Out->IWYUPublic .insert ({FE->getLastRef ().getUniqueID (), PublicHeader});
277
- return false ;
278
- }
279
- FileID CommentFID = SM.getFileID (Range.getBegin ());
280
- int CommentLine = SM.getLineNumber (SM.getFileID (Range.getBegin ()),
281
- SM.getFileOffset (Range.getBegin ()));
277
+ auto [CommentFID, CommentOffset] = SM.getDecomposedLoc (Range.getBegin ());
278
+ int CommentLine = SM.getLineNumber (CommentFID, CommentOffset);
279
+ auto Filename = SM.getBufferName (Range.getBegin ());
282
280
// Record export pragma.
283
281
if (Pragma->startswith (" export" )) {
284
- ExportStack.push_back ({CommentLine, CommentFID,
285
- save (SM.getFileEntryForID (CommentFID)->getName ()),
286
- false });
282
+ ExportStack.push_back ({CommentLine, CommentFID, save (Filename), false });
287
283
} else if (Pragma->startswith (" begin_exports" )) {
288
- ExportStack.push_back ({CommentLine, CommentFID,
289
- save (SM.getFileEntryForID (CommentFID)->getName ()),
290
- true });
284
+ ExportStack.push_back ({CommentLine, CommentFID, save (Filename), true });
291
285
} else if (Pragma->startswith (" end_exports" )) {
292
286
// FIXME: be robust on unmatching cases. We should only pop the stack if
293
287
// the begin_exports and end_exports is in the same file.
@@ -307,6 +301,29 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler {
307
301
KeepStack.pop_back ();
308
302
}
309
303
}
304
+
305
+ auto FE = SM.getFileEntryRefForID (CommentFID);
306
+ if (!FE) {
307
+ // FIXME: Support IWYU pragmas in virtual files. Our mappings rely on
308
+ // "persistent" UniqueIDs and that is not the case for virtual files.
309
+ return false ;
310
+ }
311
+ auto CommentUID = FE->getUniqueID ();
312
+ if (Pragma->consume_front (" private" )) {
313
+ StringRef PublicHeader;
314
+ if (Pragma->consume_front (" , include " )) {
315
+ // We always insert using the spelling from the pragma.
316
+ PublicHeader = save (Pragma->startswith (" <" ) || Pragma->startswith (" \" " )
317
+ ? (*Pragma)
318
+ : (" \" " + *Pragma + " \" " ).str ());
319
+ }
320
+ Out->IWYUPublic .insert ({CommentUID, PublicHeader});
321
+ return false ;
322
+ }
323
+ if (Pragma->consume_front (" always_keep" )) {
324
+ Out->AlwaysKeep .insert (CommentUID);
325
+ return false ;
326
+ }
310
327
return false ;
311
328
}
312
329
@@ -401,6 +418,14 @@ bool PragmaIncludes::isPrivate(const FileEntry *FE) const {
401
418
return IWYUPublic.contains (FE->getUniqueID ());
402
419
}
403
420
421
+ bool PragmaIncludes::shouldKeep (unsigned HashLineNumber) const {
422
+ return ShouldKeep.contains (HashLineNumber);
423
+ }
424
+
425
+ bool PragmaIncludes::shouldKeep (const FileEntry *FE) const {
426
+ return AlwaysKeep.contains (FE->getUniqueID ());
427
+ }
428
+
404
429
namespace {
405
430
template <typename T> bool isImplicitTemplateSpecialization (const Decl *D) {
406
431
if (const auto *TD = dyn_cast<T>(D))
0 commit comments