forked from OSchip/llvm-project
Add a callback for `__has_include` and use it for dependency scanning.
This adds a preprocessor callback for the `__has_include` and `__has_include_next` directives. Successful checking for the presence of a header should add it to the list of header dependencies so this overrides the callback in the dependency scanner. Patch by Pete Cooper with some additions by me. rdar://problem/39545636 Differential Revision: https://reviews.llvm.org/D30882 llvm-svn: 342517
This commit is contained in:
parent
78381c63ae
commit
a4c53284c1
|
@ -276,6 +276,12 @@ public:
|
|||
SourceRange Range) {
|
||||
}
|
||||
|
||||
/// Hook called when a '__has_include' or '__has_include_next' directive is
|
||||
/// read.
|
||||
virtual void HasInclude(SourceLocation Loc, StringRef FileName, bool IsAngled,
|
||||
const FileEntry *File,
|
||||
SrcMgr::CharacteristicKind FileType) {}
|
||||
|
||||
/// Hook called when a source range is skipped.
|
||||
/// \param Range The SourceRange that was skipped. The range begins at the
|
||||
/// \#if/\#else directive and ends after the \#endif/\#else directive.
|
||||
|
@ -443,6 +449,13 @@ public:
|
|||
Second->PragmaDiagnostic(Loc, Namespace, mapping, Str);
|
||||
}
|
||||
|
||||
void HasInclude(SourceLocation Loc, StringRef FileName, bool IsAngled,
|
||||
const FileEntry *File,
|
||||
SrcMgr::CharacteristicKind FileType) override {
|
||||
First->HasInclude(Loc, FileName, IsAngled, File, FileType);
|
||||
Second->HasInclude(Loc, FileName, IsAngled, File, FileType);
|
||||
}
|
||||
|
||||
void PragmaOpenCLExtension(SourceLocation NameLoc, const IdentifierInfo *Name,
|
||||
SourceLocation StateLoc, unsigned State) override {
|
||||
First->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State);
|
||||
|
|
|
@ -200,6 +200,10 @@ public:
|
|||
const Module *Imported,
|
||||
SrcMgr::CharacteristicKind FileType) override;
|
||||
|
||||
void HasInclude(SourceLocation Loc, StringRef SpelledFilename, bool IsAngled,
|
||||
const FileEntry *File,
|
||||
SrcMgr::CharacteristicKind FileType) override;
|
||||
|
||||
void EndOfMainFile() override {
|
||||
OutputDependencyFile();
|
||||
}
|
||||
|
@ -328,6 +332,17 @@ void DFGImpl::InclusionDirective(SourceLocation HashLoc,
|
|||
}
|
||||
}
|
||||
|
||||
void DFGImpl::HasInclude(SourceLocation Loc, StringRef SpelledFilename,
|
||||
bool IsAngled, const FileEntry *File,
|
||||
SrcMgr::CharacteristicKind FileType) {
|
||||
if (!File)
|
||||
return;
|
||||
StringRef Filename = File->getName();
|
||||
if (!FileMatchesDepCriteria(Filename.data(), FileType))
|
||||
return;
|
||||
AddFilename(llvm::sys::path::remove_leading_dotslash(Filename));
|
||||
}
|
||||
|
||||
bool DFGImpl::AddFilename(StringRef Filename) {
|
||||
if (FilesSet.insert(Filename).second) {
|
||||
Files.push_back(Filename);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "clang/Lex/CodeCompletionHandler.h"
|
||||
#include "clang/Lex/DirectoryLookup.h"
|
||||
#include "clang/Lex/ExternalPreprocessorSource.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
#include "clang/Lex/MacroArgs.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
|
@ -1242,6 +1243,13 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
|
|||
PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile,
|
||||
CurDir, nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
if (PPCallbacks *Callbacks = PP.getPPCallbacks()) {
|
||||
SrcMgr::CharacteristicKind FileType = SrcMgr::C_User;
|
||||
if (File)
|
||||
FileType = PP.getHeaderSearchInfo().getFileDirFlavor(File);
|
||||
Callbacks->HasInclude(FilenameLoc, Filename, isAngled, File, FileType);
|
||||
}
|
||||
|
||||
// Get the result value. A result of true means the file exists.
|
||||
return File != nullptr;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// REQUIRES: shell
|
||||
|
||||
// Basic test
|
||||
// RUN: rm -rf %t.dir
|
||||
// RUN: mkdir %t.dir
|
||||
// RUN: mkdir %t.dir/a
|
||||
// RUN: echo "#ifndef HEADER_A" > %t.dir/a/header.h
|
||||
// RUN: echo "#define HEADER_A" >> %t.dir/a/header.h
|
||||
// RUN: echo "#endif" >> %t.dir/a/header.h
|
||||
// RUN: mkdir %t.dir/system
|
||||
// RUN: echo "#define SYSTEM_HEADER" > %t.dir/system/system-header.h
|
||||
// RUN: mkdir %t.dir/next-a
|
||||
// RUN: echo "#if __has_include_next(<next-header.h>)" > %t.dir/next-a/next-header.h
|
||||
// RUN: echo "#endif" >> %t.dir/next-a/next-header.h
|
||||
// RUN: mkdir %t.dir/next-b
|
||||
// RUN: echo "#define NEXT_HEADER" > %t.dir/next-b/next-header.h
|
||||
|
||||
// RUN: %clang -MD -MF %t.dir/file.deps %s -fsyntax-only -I %t.dir -isystem %t.dir/system -I %t.dir/next-a -I %t.dir/next-b
|
||||
// RUN: FileCheck -input-file=%t.dir/file.deps %s
|
||||
// CHECK: dependency-gen-has-include.o
|
||||
// CHECK: dependency-gen-has-include.c
|
||||
// CHECK: a/header.h
|
||||
// CHECK-NOT: missing/file.h
|
||||
// CHECK: system/system-header.h
|
||||
// CHECK: next-a/next-header.h
|
||||
// CHECK: next-b/next-header.h
|
||||
|
||||
// Verify that we ignore system headers in user-only headers mode.
|
||||
// RUN: %clang -MMD -MF %t.dir/user-headers.deps %s -fsyntax-only -I %t.dir -isystem %t.dir/system -I %t.dir/next-a -I %t.dir/next-b
|
||||
// RUN: FileCheck -input-file=%t.dir/user-headers.deps --check-prefix CHECK-USER-HEADER %s
|
||||
// CHECK-USER-HEADER-NOT: system/system-header.h
|
||||
|
||||
#if __has_include("a/header.h")
|
||||
#endif
|
||||
#if __has_include("missing/file.h")
|
||||
#endif
|
||||
#if __has_include(<system-header.h>)
|
||||
#endif
|
||||
|
||||
#include <next-header.h>
|
Loading…
Reference in New Issue