diff options
-rw-r--r-- | include/clang-c/Index.h | 9 | ||||
-rw-r--r-- | include/clang/Lex/PPCallbacks.h | 29 | ||||
-rw-r--r-- | include/clang/Lex/PreprocessingRecord.h | 75 | ||||
-rw-r--r-- | include/clang/Lex/Preprocessor.h | 12 | ||||
-rw-r--r-- | include/clang/Serialization/ASTBitCodes.h | 6 | ||||
-rw-r--r-- | include/clang/Serialization/ASTReader.h | 3 | ||||
-rw-r--r-- | lib/Lex/PPDirectives.cpp | 44 | ||||
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 5 | ||||
-rw-r--r-- | lib/Lex/PreprocessingRecord.cpp | 37 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 68 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 33 | ||||
-rw-r--r-- | test/Index/annotate-tokens-include.c | 1 | ||||
-rw-r--r-- | test/Index/annotate-tokens-pp.c | 2 | ||||
-rw-r--r-- | tools/c-index-test/c-index-test.c | 7 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 36 | ||||
-rw-r--r-- | tools/libclang/CXCursor.cpp | 11 | ||||
-rw-r--r-- | tools/libclang/CXCursor.h | 8 | ||||
-rw-r--r-- | tools/libclang/libclang.darwin.exports | 1 | ||||
-rw-r--r-- | tools/libclang/libclang.exports | 1 |
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/ |