forked from OSchip/llvm-project
Extend the preprocessing record and libclang with support for
inclusion directives, keeping track of every #include, #import, etc. in the translation unit. We keep track of the source location and kind of the inclusion, how the file name was spelled, and the underlying file to which the inclusion resolved. llvm-svn: 116952
This commit is contained in:
parent
2edaa2fb24
commit
796d76a663
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1465,6 +1466,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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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=
|
||||
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ class CXXBaseSpecifier;
|
|||
class Decl;
|
||||
class Expr;
|
||||
class FieldDecl;
|
||||
class InclusionDirective;
|
||||
class LabelStmt;
|
||||
class MacroDefinition;
|
||||
class MacroInstantiation;
|
||||
|
@ -133,6 +134,13 @@ CXCursor MakeMacroInstantiationCursor(MacroInstantiation *, ASTUnit *TU);
|
|||
/// source range.
|
||||
MacroInstantiation *getCursorMacroInstantiation(CXCursor C);
|
||||
|
||||
/// \brief Create an inclusion directive cursor.
|
||||
CXCursor MakeInclusionDirectiveCursor(InclusionDirective *, ASTUnit *TU);
|
||||
|
||||
/// \brief Unpack a given inclusion directive cursor to retrieve its
|
||||
/// source range.
|
||||
InclusionDirective *getCursorInclusionDirective(CXCursor C);
|
||||
|
||||
/// \brief Create a label reference at the given location.
|
||||
CXCursor MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc, ASTUnit *TU);
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ _clang_getFile
|
|||
_clang_getFileName
|
||||
_clang_getFileTime
|
||||
_clang_getIBOutletCollectionType
|
||||
_clang_getIncludedFile
|
||||
_clang_getInclusions
|
||||
_clang_getInstantiationLocation
|
||||
_clang_getLocation
|
||||
|
|
|
@ -68,6 +68,7 @@ clang_getFile
|
|||
clang_getFileName
|
||||
clang_getFileTime
|
||||
clang_getIBOutletCollectionType
|
||||
clang_getIncludedFile
|
||||
clang_getInclusions
|
||||
clang_getInstantiationLocation
|
||||
clang_getLocation
|
||||
|
|
Loading…
Reference in New Issue