aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang-c/Index.h9
-rw-r--r--include/clang/Lex/PPCallbacks.h29
-rw-r--r--include/clang/Lex/PreprocessingRecord.h75
-rw-r--r--include/clang/Lex/Preprocessor.h12
-rw-r--r--include/clang/Serialization/ASTBitCodes.h6
-rw-r--r--include/clang/Serialization/ASTReader.h3
-rw-r--r--lib/Lex/PPDirectives.cpp44
-rw-r--r--lib/Lex/PPMacroExpansion.cpp5
-rw-r--r--lib/Lex/PreprocessingRecord.cpp37
-rw-r--r--lib/Serialization/ASTReader.cpp68
-rw-r--r--lib/Serialization/ASTWriter.cpp33
-rw-r--r--test/Index/annotate-tokens-include.c1
-rw-r--r--test/Index/annotate-tokens-pp.c2
-rw-r--r--tools/c-index-test/c-index-test.c7
-rw-r--r--tools/libclang/CIndex.cpp36
-rw-r--r--tools/libclang/CXCursor.cpp11
-rw-r--r--tools/libclang/CXCursor.h8
-rw-r--r--tools/libclang/libclang.darwin.exports1
-rw-r--r--tools/libclang/libclang.exports1
19 files changed, 342 insertions, 46 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 40d3bafaff..7f569d2883 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -1190,8 +1190,9 @@ enum CXCursorKind {
CXCursor_PreprocessingDirective = 500,
CXCursor_MacroDefinition = 501,
CXCursor_MacroInstantiation = 502,
+ CXCursor_InclusionDirective = 503,
CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective,
- CXCursor_LastPreprocessing = CXCursor_MacroInstantiation
+ CXCursor_LastPreprocessing = CXCursor_InclusionDirective
};
/**
@@ -1466,6 +1467,12 @@ CINDEX_LINKAGE void clang_getOverriddenCursors(CXCursor cursor,
CINDEX_LINKAGE void clang_disposeOverriddenCursors(CXCursor *overridden);
/**
+ * \brief Retrieve the file that is included by the given inclusion directive
+ * cursor.
+ */
+CINDEX_LINKAGE CXFile clang_getIncludedFile(CXCursor cursor);
+
+/**
* @}
*/
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index 782f2d57a5..1bcc364e67 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -54,6 +54,35 @@ public:
SrcMgr::CharacteristicKind FileType) {
}
+ /// \brief This callback is invoked whenever an inclusion directive of
+ /// any kind (\c #include, \c #import, etc.) has been processed, regardless
+ /// of whether the inclusion will actually result in an inclusion.
+ ///
+ /// \param HashLoc The location of the '#' that starts the inclusion
+ /// directive.
+ ///
+ /// \param IncludeTok The token that indicates the kind of inclusion
+ /// directive, e.g., 'include' or 'import'.
+ ///
+ /// \param FileName The name of the file being included, as written in the
+ /// source code.
+ ///
+ /// \param IsAngled Whether the file name was enclosed in angle brackets;
+ /// otherwise, it was enclosed in quotes.
+ ///
+ /// \param File The actual file that may be included by this inclusion
+ /// directive.
+ ///
+ /// \param EndLoc The location of the last token within the inclusion
+ /// directive.
+ virtual void InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ llvm::StringRef FileName,
+ bool IsAngled,
+ const FileEntry *File,
+ SourceLocation EndLoc) {
+ }
+
/// EndOfMainFile - This callback is invoked when the end of the main file is
/// reach, no subsequent callbacks will be made.
virtual void EndOfMainFile() {
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index 576b571a4e..0c5b7bc37f 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -35,6 +35,7 @@ void operator delete(void* ptr, clang::PreprocessingRecord& PR,
namespace clang {
class MacroDefinition;
+ class FileEntry;
/// \brief Base class that describes a preprocessed entity, which may be a
/// preprocessor directive or macro instantiation.
@@ -54,8 +55,12 @@ namespace clang {
/// \brief A macro definition.
MacroDefinitionKind,
+ /// \brief An inclusion directive, such as \c #include, \c
+ /// #import, or \c #include_next.
+ InclusionDirectiveKind,
+
FirstPreprocessingDirective = PreprocessingDirectiveKind,
- LastPreprocessingDirective = MacroDefinitionKind
+ LastPreprocessingDirective = InclusionDirectiveKind
};
private:
@@ -173,6 +178,68 @@ namespace clang {
}
static bool classof(const MacroDefinition *) { return true; }
};
+
+ /// \brief Record the location of an inclusion directive, such as an
+ /// \c #include or \c #import statement.
+ class InclusionDirective : public PreprocessingDirective {
+ public:
+ /// \brief The kind of inclusion directives known to the
+ /// preprocessor.
+ enum InclusionKind {
+ /// \brief An \c #include directive.
+ Include,
+ /// \brief An Objective-C \c #import directive.
+ Import,
+ /// \brief A GNU \c #include_next directive.
+ IncludeNext,
+ /// \brief A Clang \c #__include_macros directive.
+ IncludeMacros
+ };
+
+ private:
+ /// \brief The name of the file that was included, as written in
+ /// the source.
+ std::string FileName;
+
+ /// \brief Whether the file name was in quotation marks; otherwise, it was
+ /// in angle brackets.
+ unsigned InQuotes : 1;
+
+ /// \brief The kind of inclusion directive we have.
+ ///
+ /// This is a value of type InclusionKind.
+ unsigned Kind : 2;
+
+ /// \brief The file that was included.
+ const FileEntry *File;
+
+ public:
+ explicit InclusionDirective(InclusionKind Kind,
+ const std::string &FileName, bool InQuotes,
+ const FileEntry *File, SourceRange Range)
+ : PreprocessingDirective(InclusionDirectiveKind, Range),
+ FileName(FileName), InQuotes(InQuotes), Kind(Kind), File(File) { }
+
+ /// \brief Determine what kind of inclusion directive this is.
+ InclusionKind getKind() const { return static_cast<InclusionKind>(Kind); }
+
+ /// \brief Retrieve the included file name as it was written in the source.
+ llvm::StringRef getFileName() const { return FileName; }
+
+ /// \brief Determine whether the included file name was written in quotes;
+ /// otherwise, it was written in angle brackets.
+ bool wasInQuotes() const { return InQuotes; }
+
+ /// \brief Retrieve the file entry for the actual file that was included
+ /// by this directive.
+ const FileEntry *getFile() const { return File; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const PreprocessedEntity *PE) {
+ return PE->getKind() == InclusionDirectiveKind;
+ }
+ static bool classof(const InclusionDirective *) { return true; }
+ };
/// \brief An abstract class that should be subclassed by any external source
/// of preprocessing record entries.
@@ -263,6 +330,12 @@ namespace clang {
virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
virtual void MacroUndefined(SourceLocation Loc, const IdentifierInfo *II,
const MacroInfo *MI);
+ virtual void InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ llvm::StringRef FileName,
+ bool IsAngled,
+ const FileEntry *File,
+ SourceLocation EndLoc);
};
} // end namespace clang
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 1ee0fec1c5..87b62d0a9a 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -823,7 +823,8 @@ public:
/// This code concatenates and consumes tokens up to the '>' token. It
/// returns false if the > was found, otherwise it returns true if it finds
/// and consumes the EOM marker.
- bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer);
+ bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer,
+ SourceLocation &End);
private:
@@ -972,12 +973,13 @@ private:
void HandleIdentSCCSDirective(Token &Tok);
// File inclusion.
- void HandleIncludeDirective(Token &Tok,
+ void HandleIncludeDirective(SourceLocation HashLoc,
+ Token &Tok,
const DirectoryLookup *LookupFrom = 0,
bool isImport = false);
- void HandleIncludeNextDirective(Token &Tok);
- void HandleIncludeMacrosDirective(Token &Tok);
- void HandleImportDirective(Token &Tok);
+ void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok);
+ void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok);
+ void HandleImportDirective(SourceLocation HashLoc, Token &Tok);
// Macro handling.
void HandleDefineDirective(Token &Tok);
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index edb61917d4..da27cde29f 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -372,7 +372,11 @@ namespace clang {
PP_MACRO_INSTANTIATION = 4,
/// \brief Describes a macro definition within the preprocessing record.
- PP_MACRO_DEFINITION = 5
+ PP_MACRO_DEFINITION = 5,
+
+ /// \brief Describes am inclusion directive within the preprocessing
+ /// record.
+ PP_INCLUSION_DIRECTIVE = 6
};
/// \defgroup ASTAST AST file AST constants
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 979b953d1f..b049e6eb4e 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -277,6 +277,9 @@ private:
/// all of the macro definitions.
llvm::BitstreamCursor MacroCursor;
+ /// \brief The offset of the start of the set of defined macros.
+ uint64_t MacroStartOffset;
+
/// \brief The number of macro definitions in this file.
unsigned LocalNumMacroDefinitions;
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 8f66d99b18..d5abc20a3d 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -591,9 +591,11 @@ TryAgain:
// C99 6.10.2 - Source File Inclusion.
case tok::pp_include:
- return HandleIncludeDirective(Result); // Handle #include.
+ // Handle #include.
+ return HandleIncludeDirective(SavedHash.getLocation(), Result);
case tok::pp___include_macros:
- return HandleIncludeMacrosDirective(Result); // Handle -imacros.
+ // Handle -imacros.
+ return HandleIncludeMacrosDirective(SavedHash.getLocation(), Result);
// C99 6.10.3 - Macro Replacement.
case tok::pp_define:
@@ -615,9 +617,9 @@ TryAgain:
// GNU Extensions.
case tok::pp_import:
- return HandleImportDirective(Result);
+ return HandleImportDirective(SavedHash.getLocation(), Result);
case tok::pp_include_next:
- return HandleIncludeNextDirective(Result);
+ return HandleIncludeNextDirective(SavedHash.getLocation(), Result);
case tok::pp_warning:
Diag(Result, diag::ext_pp_warning_directive);
@@ -1034,11 +1036,14 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
/// false if the > was found, otherwise it returns true if it finds and consumes
/// the EOM marker.
bool Preprocessor::ConcatenateIncludeName(
- llvm::SmallString<128> &FilenameBuffer) {
+ llvm::SmallString<128> &FilenameBuffer,
+ SourceLocation &End) {
Token CurTok;
Lex(CurTok);
while (CurTok.isNot(tok::eom)) {
+ End = CurTok.getLocation();
+
// Append the spelling of this token to the buffer. If there was a space
// before it, add it now.
if (CurTok.hasLeadingSpace())
@@ -1077,7 +1082,8 @@ bool Preprocessor::ConcatenateIncludeName(
/// routine with functionality shared between #include, #include_next and
/// #import. LookupFrom is set when this is a #include_next directive, it
/// specifies the file to start searching from.
-void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
+void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
+ Token &IncludeTok,
const DirectoryLookup *LookupFrom,
bool isImport) {
@@ -1087,7 +1093,8 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
// Reserve a buffer to get the spelling.
llvm::SmallString<128> FilenameBuffer;
llvm::StringRef Filename;
-
+ SourceLocation End;
+
switch (FilenameTok.getKind()) {
case tok::eom:
// If the token kind is EOM, the error has already been diagnosed.
@@ -1096,13 +1103,14 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
case tok::angle_string_literal:
case tok::string_literal:
Filename = getSpelling(FilenameTok, FilenameBuffer);
+ End = FilenameTok.getLocation();
break;
case tok::less:
// This could be a <foo/bar.h> file coming from a macro expansion. In this
// case, glue the tokens together into FilenameBuffer and interpret those.
FilenameBuffer.push_back('<');
- if (ConcatenateIncludeName(FilenameBuffer))
+ if (ConcatenateIncludeName(FilenameBuffer, End))
return; // Found <eom> but no ">"? Diagnostic already emitted.
Filename = FilenameBuffer.str();
break;
@@ -1141,6 +1149,11 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
return;
}
+ // Notify the callback object that we've seen an inclusion directive.
+ if (Callbacks)
+ Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File,
+ End);
+
// The #included file will be considered to be a system header if either it is
// in a system include directory, or if the #includer is a system include
// header.
@@ -1170,7 +1183,8 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
/// HandleIncludeNextDirective - Implements #include_next.
///
-void Preprocessor::HandleIncludeNextDirective(Token &IncludeNextTok) {
+void Preprocessor::HandleIncludeNextDirective(SourceLocation HashLoc,
+ Token &IncludeNextTok) {
Diag(IncludeNextTok, diag::ext_pp_include_next_directive);
// #include_next is like #include, except that we start searching after
@@ -1187,23 +1201,25 @@ void Preprocessor::HandleIncludeNextDirective(Token &IncludeNextTok) {
++Lookup;
}
- return HandleIncludeDirective(IncludeNextTok, Lookup);
+ return HandleIncludeDirective(HashLoc, IncludeNextTok, Lookup);
}
/// HandleImportDirective - Implements #import.
///
-void Preprocessor::HandleImportDirective(Token &ImportTok) {
+void Preprocessor::HandleImportDirective(SourceLocation HashLoc,
+ Token &ImportTok) {
if (!Features.ObjC1) // #import is standard for ObjC.
Diag(ImportTok, diag::ext_pp_import_directive);
- return HandleIncludeDirective(ImportTok, 0, true);
+ return HandleIncludeDirective(HashLoc, ImportTok, 0, true);
}
/// HandleIncludeMacrosDirective - The -imacros command line option turns into a
/// pseudo directive in the predefines buffer. This handles it by sucking all
/// tokens through the preprocessor and discarding them (only keeping the side
/// effects on the preprocessor).
-void Preprocessor::HandleIncludeMacrosDirective(Token &IncludeMacrosTok) {
+void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc,
+ Token &IncludeMacrosTok) {
// This directive should only occur in the predefines buffer. If not, emit an
// error and reject it.
SourceLocation Loc = IncludeMacrosTok.getLocation();
@@ -1216,7 +1232,7 @@ void Preprocessor::HandleIncludeMacrosDirective(Token &IncludeMacrosTok) {
// Treat this as a normal #include for checking purposes. If this is
// successful, it will push a new lexer onto the include stack.
- HandleIncludeDirective(IncludeMacrosTok, 0, false);
+ HandleIncludeDirective(HashLoc, IncludeMacrosTok, 0, false);
Token TmpTok;
do {
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 19a6ca8521..68fc56f7b7 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -570,7 +570,8 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
// Reserve a buffer to get the spelling.
llvm::SmallString<128> FilenameBuffer;
llvm::StringRef Filename;
-
+ SourceLocation EndLoc;
+
switch (Tok.getKind()) {
case tok::eom:
// If the token kind is EOM, the error has already been diagnosed.
@@ -589,7 +590,7 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
// This could be a <foo/bar.h> file coming from a macro expansion. In this
// case, glue the tokens together into FilenameBuffer and interpret those.
FilenameBuffer.push_back('<');
- if (PP.ConcatenateIncludeName(FilenameBuffer))
+ if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc))
return false; // Found <eom> but no ">"? Diagnostic already emitted.
Filename = FilenameBuffer.str();
break;
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index c446d96b45..34421779c9 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -14,6 +14,8 @@
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Token.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -127,3 +129,38 @@ void PreprocessingRecord::MacroUndefined(SourceLocation Loc,
MacroDefinitions.erase(Pos);
}
+void PreprocessingRecord::InclusionDirective(SourceLocation HashLoc,
+ const clang::Token &IncludeTok,
+ llvm::StringRef FileName,
+ bool IsAngled,
+ const FileEntry *File,
+ clang::SourceLocation EndLoc) {
+ InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
+
+ switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
+ case tok::pp_include:
+ Kind = InclusionDirective::Include;
+ break;
+
+ case tok::pp_import:
+ Kind = InclusionDirective::Import;
+ break;
+
+ case tok::pp_include_next:
+ Kind = InclusionDirective::IncludeNext;
+ break;
+
+ case tok::pp___include_macros:
+ Kind = InclusionDirective::IncludeMacros;
+ break;
+
+ default:
+ llvm_unreachable("Unknown include directive kind");
+ return;
+ }
+
+ clang::InclusionDirective *ID
+ = new (*this) clang::InclusionDirective(Kind, FileName, !IsAngled, File,
+ SourceRange(HashLoc, EndLoc));
+ PreprocessedEntities.push_back(ID);
+}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index d9e97fe8b3..5389b51944 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1337,18 +1337,21 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
}
while (true) {
+ uint64_t Offset = Cursor.GetCurrentBitNo();
unsigned Code = Cursor.ReadCode();
-
+
// We expect all abbrevs to be at the start of the block.
- if (Code != llvm::bitc::DEFINE_ABBREV)
+ if (Code != llvm::bitc::DEFINE_ABBREV) {
+ Cursor.JumpToBit(Offset);
return false;
+ }
Cursor.ReadAbbrevRecord();
}
}
void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) {
assert(PP && "Forgot to set Preprocessor ?");
- llvm::BitstreamCursor &Stream = F.Stream;
+ llvm::BitstreamCursor &Stream = F.MacroCursor;
// Keep track of where we are in the stream, then jump back there
// after reading this macro.
@@ -1381,9 +1384,12 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) {
}
// Read a record.
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
Record.clear();
PreprocessorRecordTypes RecType =
- (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record);
+ (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record, BlobStart,
+ BlobLen);
switch (RecType) {
case PP_MACRO_OBJECT_LIKE:
case PP_MACRO_FUNCTION_LIKE: {
@@ -1524,6 +1530,41 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) {
return;
}
+
+ case PP_INCLUSION_DIRECTIVE: {
+ // If we already have a macro, that means that we've hit the end
+ // of the definition of the macro we were looking for. We're
+ // done.
+ if (Macro)
+ return;
+
+ if (!PP->getPreprocessingRecord()) {
+ Error("missing preprocessing record in AST file");
+ return;
+ }
+
+ PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
+ if (PPRec.getPreprocessedEntity(Record[0]))
+ return;
+
+ const char *FullFileNameStart = BlobStart + Record[3];
+ const FileEntry *File
+ = PP->getFileManager().getFile(FullFileNameStart,
+ FullFileNameStart + (BlobLen - Record[3]));
+
+ // FIXME: Stable encoding
+ InclusionDirective::InclusionKind Kind
+ = static_cast<InclusionDirective::InclusionKind>(Record[5]);
+ InclusionDirective *ID
+ = new (PPRec) InclusionDirective(Kind,
+ llvm::StringRef(BlobStart, Record[3]),
+ Record[4],
+ File,
+ SourceRange(ReadSourceLocation(F, Record[1]),
+ ReadSourceLocation(F, Record[2])));
+ PPRec.SetPreallocatedEntity(Record[0], ID);
+ return;
+ }
}
}
}
@@ -1538,22 +1579,14 @@ void ASTReader::ReadDefinedMacros() {
continue;
llvm::BitstreamCursor Cursor = MacroCursor;
- if (Cursor.EnterSubBlock(PREPROCESSOR_BLOCK_ID)) {
- Error("malformed preprocessor block record in AST file");
- return;
- }
-
+ Cursor.JumpToBit(F.MacroStartOffset);
+
RecordData Record;
while (true) {
uint64_t Offset = Cursor.GetCurrentBitNo();
unsigned Code = Cursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (Cursor.ReadBlockEnd()) {
- Error("error at end of preprocessor block in AST file");
- return;
- }
+ if (Code == llvm::bitc::END_BLOCK)
break;
- }
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
// No known subblocks, always skip them.
@@ -1589,6 +1622,7 @@ void ASTReader::ReadDefinedMacros() {
case PP_MACRO_INSTANTIATION:
case PP_MACRO_DEFINITION:
+ case PP_INCLUSION_DIRECTIVE:
// Read the macro record.
// FIXME: That's a stupid way to do this. We should reuse this cursor.
ReadMacroRecord(F, Offset);
@@ -1686,10 +1720,12 @@ ASTReader::ReadASTBlock(PerFileData &F) {
if (PP)
PP->setExternalSource(this);
- if (Stream.SkipBlock()) {
+ if (Stream.SkipBlock() ||
+ ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
Error("malformed block record in AST file");
return Failure;
}
+ F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
break;
case SOURCE_MANAGER_BLOCK_ID:
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 2cbe08190b..8cf7e85dc6 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -1256,16 +1256,32 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
}
// Enter the preprocessor block.
- Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 2);
+ Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);
// If the AST file contains __DATE__ or __TIME__ emit a warning about this.
// FIXME: use diagnostics subsystem for localization etc.
if (PP.SawDateOrTime())
fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
+
// Loop over all the macro definitions that are live at the end of the file,
// emitting each to the PP section.
PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
+ unsigned InclusionAbbrev = 0;
+ if (PPRec) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(PP_INCLUSION_DIRECTIVE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // start location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // end location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ InclusionAbbrev = Stream.EmitAbbrev(Abbrev);
+ }
+
for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
I != E; ++I) {
// FIXME: This emits macros in hash table order, we should do it in a stable
@@ -1381,6 +1397,21 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
Stream.EmitRecord(PP_MACRO_DEFINITION, Record);
continue;
}
+
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
+ Record.push_back(PP_INCLUSION_DIRECTIVE);
+ Record.push_back(IndexBase + NumPreprocessingRecords++);
+ AddSourceLocation(ID->getSourceRange().getBegin(), Record);
+ AddSourceLocation(ID->getSourceRange().getEnd(), Record);
+ Record.push_back(ID->getFileName().size());
+ Record.push_back(ID->wasInQuotes());
+ Record.push_back(static_cast<unsigned>(ID->getKind()));
+ llvm::SmallString<64> Buffer;
+ Buffer += ID->getFileName();
+ Buffer += ID->getFile()->getName();
+ Stream.EmitRecordWithBlob(InclusionAbbrev, Record, Buffer);
+ continue;
+ }
}
}
diff --git a/test/Index/annotate-tokens-include.c b/test/Index/annotate-tokens-include.c
index 3c3c43b746..b60c1af181 100644
--- a/test/Index/annotate-tokens-include.c
+++ b/test/Index/annotate-tokens-include.c
@@ -1,6 +1,7 @@
#include "annotate-tokens-include.h"
// RUN: c-index-test -test-annotate-tokens=%s:1:1:2:1 %s | FileCheck %s
+// CHECK: Punctuation: "#" [1:1 - 1:2] inclusion directive=annotate-tokens-include.h
// CHECK: Identifier: "include" [1:2 - 1:9] preprocessing directive=
// CHECK: Literal: ""annotate-tokens-include.h"" [1:10 - 1:37] preprocessing directive=
diff --git a/test/Index/annotate-tokens-pp.c b/test/Index/annotate-tokens-pp.c
index 55ee7630eb..631caab839 100644
--- a/test/Index/annotate-tokens-pp.c
+++ b/test/Index/annotate-tokens-pp.c
@@ -68,7 +68,7 @@ void test() {
// CHECK: Identifier: "BAR" [6:5 - 6:8] macro instantiation=BAR:3:9
// CHECK: Identifier: "STILL_NOTHING" [6:9 - 6:22] macro instantiation=STILL_NOTHING:2:9
// CHECK: Punctuation: ";" [6:22 - 6:23]
-// CHECK: Punctuation: "#" [7:1 - 7:2] preprocessing directive=
+// CHECK: Punctuation: "#" [7:1 - 7:2] inclusion directive=foo.h
// CHECK: Identifier: "include" [7:2 - 7:9] preprocessing directive=
// CHECK: Literal: ""foo.h"" [7:10 - 7:17] preprocessing directive=
// CHECK: Punctuation: "#" [8:1 - 8:2] preprocessing directive=
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 32cada08ae..c95fb307a6 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -271,6 +271,13 @@ static void PrintCursor(CXCursor Cursor) {
printf("]");
clang_disposeOverriddenCursors(overridden);
}
+
+ if (Cursor.kind == CXCursor_InclusionDirective) {
+ CXFile File = clang_getIncludedFile(Cursor);
+ CXString Included = clang_getFileName(File);
+ printf(" (%s)", clang_getCString(Included));
+ clang_disposeString(Included);
+ }
}
}
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 722e2cb738..c944883fa4 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -555,6 +555,13 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
continue;
}
+
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
+ if (Visit(MakeInclusionDirectiveCursor(ID, CXXUnit)))
+ return true;
+
+ continue;
+ }
}
}
return false;
@@ -2565,6 +2572,9 @@ CXString clang_getCursorSpelling(CXCursor C) {
return createCXString(getCursorMacroDefinition(C)->getName()
->getNameStart());
+ if (C.kind == CXCursor_InclusionDirective)
+ return createCXString(getCursorInclusionDirective(C)->getFileName());
+
if (clang_isDeclaration(C.kind))
return getDeclSpelling(getCursorDecl(C));
@@ -2757,6 +2767,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("macro definition");
case CXCursor_MacroInstantiation:
return createCXString("macro instantiation");
+ case CXCursor_InclusionDirective:
+ return createCXString("inclusion directive");
case CXCursor_Namespace:
return createCXString("Namespace");
case CXCursor_LinkageSpec:
@@ -2977,7 +2989,13 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
SourceLocation L = cxcursor::getCursorMacroDefinition(C)->getLocation();
return cxloc::translateSourceLocation(getCursorContext(C), L);
}
-
+
+ if (C.kind == CXCursor_InclusionDirective) {
+ SourceLocation L
+ = cxcursor::getCursorInclusionDirective(C)->getSourceRange().getBegin();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl)
return clang_getNullLocation();
@@ -3043,12 +3061,14 @@ static SourceRange getRawCursorExtent(CXCursor C) {
if (C.kind == CXCursor_MacroDefinition)
return cxcursor::getCursorMacroDefinition(C)->getSourceRange();
-
+
+ if (C.kind == CXCursor_InclusionDirective)
+ return cxcursor::getCursorInclusionDirective(C)->getSourceRange();
+
if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl)
return getCursorDecl(C)->getSourceRange();
- return SourceRange();
-}
+ return SourceRange();}
extern "C" {
@@ -4149,6 +4169,14 @@ void clang_disposeOverriddenCursors(CXCursor *overridden) {
delete [] overridden;
}
+CXFile clang_getIncludedFile(CXCursor cursor) {
+ if (cursor.kind != CXCursor_InclusionDirective)
+ return 0;
+
+ InclusionDirective *ID = getCursorInclusionDirective(cursor);
+ return (void *)ID->getFile();
+}
+
} // end: extern "C"
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 52594dcf6b..d506400407 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -363,6 +363,17 @@ MacroInstantiation *cxcursor::getCursorMacroInstantiation(CXCursor C) {
return static_cast<MacroInstantiation *>(C.data[0]);
}
+CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID,
+ ASTUnit *TU) {
+ CXCursor C = { CXCursor_InclusionDirective, { ID, 0, TU } };
+ return C;
+}
+
+InclusionDirective *cxcursor::getCursorInclusionDirective(CXCursor C) {
+ assert(C.kind == CXCursor_InclusionDirective);
+ return static_cast<InclusionDirective *>(C.data[0]);
+}
+
CXCursor cxcursor::MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc,
ASTUnit *TU) {
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index 4a29dd0f1c..a31a322076 100644
--- a/tools/libclang/CXCursor.h
+++ b/