Index: cfe/trunk/test/Index/cindex-test-inclusions.c =================================================================== --- cfe/trunk/test/Index/cindex-test-inclusions.c +++ cfe/trunk/test/Index/cindex-test-inclusions.c @@ -11,3 +11,14 @@ // CHECK: included by: // CHECK: include_test.h:1:10 // CHECK: cindex-test-inclusions.c:3:10 + +// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-inclusion-stack-source %s 2>&1 | FileCheck -check-prefix=REPARSE %s +// REPARSE: include_test_2.h +// REPARSE: included by: +// REPARSE: include_test.h:1:10 +// REPARSE: cindex-test-inclusions.c:3:10 +// REPARSE: include_test.h +// REPARSE: included by: +// REPARSE: cindex-test-inclusions.c:3:10 +// REPARSE: cindex-test-inclusions.c +// REPARSE: included by: Index: cfe/trunk/tools/c-index-test/c-index-test.c =================================================================== --- cfe/trunk/tools/c-index-test/c-index-test.c +++ cfe/trunk/tools/c-index-test/c-index-test.c @@ -1593,6 +1593,8 @@ int num_unsaved_files = 0; enum CXErrorCode Err; int result; + unsigned Repeats = 0; + unsigned I; Idx = clang_createIndex(/* excludeDeclsFromPCH */ (!strcmp(filter, "local") || @@ -1609,6 +1611,9 @@ return -1; } + if (getenv("CINDEXTEST_EDITING")) + Repeats = 5; + Err = clang_parseTranslationUnit2(Idx, 0, argv + num_unsaved_files, argc - num_unsaved_files, @@ -1622,6 +1627,22 @@ return 1; } + for (I = 0; I != Repeats; ++I) { + if (checkForErrors(TU) != 0) + return -1; + + if (Repeats > 1) { + Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files, + clang_defaultReparseOptions(TU)); + if (Err != CXError_Success) { + describeLibclangFailure(Err); + free_remapped_files(unsaved_files, num_unsaved_files); + clang_disposeIndex(Idx); + return 1; + } + } + } + result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, CommentSchemaFile); free_remapped_files(unsaved_files, num_unsaved_files); Index: cfe/trunk/tools/libclang/CIndexInclusionStack.cpp =================================================================== --- cfe/trunk/tools/libclang/CIndexInclusionStack.cpp +++ cfe/trunk/tools/libclang/CIndexInclusionStack.cpp @@ -21,56 +21,81 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; -extern "C" { -void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB, - CXClientData clientData) { - if (cxtu::isNotUsableTU(TU)) { - LOG_BAD_TU(TU); - return; - } - +static void getInclusions(const SrcMgr::SLocEntry &(SourceManager::*Getter)(unsigned, bool*) const, unsigned n, + CXTranslationUnit TU, CXInclusionVisitor CB, + CXClientData clientData) +{ ASTUnit *CXXUnit = cxtu::getASTUnit(TU); SourceManager &SM = CXXUnit->getSourceManager(); ASTContext &Ctx = CXXUnit->getASTContext(); - SmallVector InclusionStack; - unsigned n = SM.local_sloc_entry_size(); - - // In the case where all the SLocEntries are in an external source, traverse - // those SLocEntries as well. This is the case where we are looking - // at the inclusion stack of an AST/PCH file. - const SrcMgr::SLocEntry &(SourceManager::*Getter)(unsigned, bool*) const; - if (n == 1) { - Getter = &SourceManager::getLoadedSLocEntry; - n = SM.loaded_sloc_entry_size(); - } else - Getter = &SourceManager::getLocalSLocEntry; + const bool HasPreamble = SM.getPreambleFileID().isValid(); for (unsigned i = 0 ; i < n ; ++i) { bool Invalid = false; const SrcMgr::SLocEntry &SL = (SM.*Getter)(i, &Invalid); - + if (!SL.isFile() || Invalid) continue; const SrcMgr::FileInfo &FI = SL.getFile(); if (!FI.getContentCache()->OrigEntry) continue; - - // Build the inclusion stack. + + // If this is the main file, and there is a preamble, skip this SLoc. The + // inclusions of the preamble already showed it. SourceLocation L = FI.getIncludeLoc(); + if (HasPreamble && CXXUnit->isInMainFileID(L)) + continue; + + // Build the inclusion stack. InclusionStack.clear(); while (L.isValid()) { PresumedLoc PLoc = SM.getPresumedLoc(L); InclusionStack.push_back(cxloc::translateSourceLocation(Ctx, L)); L = PLoc.isValid()? PLoc.getIncludeLoc() : SourceLocation(); } - + + // If there is a preamble, the last entry is the "inclusion" of that + // preamble into the main file, which has the bogus entry of main.c:1:1 + if (HasPreamble && !InclusionStack.empty()) + InclusionStack.pop_back(); + // Callback to the client. // FIXME: We should have a function to construct CXFiles. CB(static_cast( - const_cast(FI.getContentCache()->OrigEntry)), + const_cast(FI.getContentCache()->OrigEntry)), InclusionStack.data(), InclusionStack.size(), clientData); - } + } +} + + +extern "C" { +void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB, + CXClientData clientData) { + if (cxtu::isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return; + } + + SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager(); + const unsigned n = SM.local_sloc_entry_size(); + + // In the case where all the SLocEntries are in an external source, traverse + // those SLocEntries as well. This is the case where we are looking + // at the inclusion stack of an AST/PCH file. Also, if we are not looking at + // a AST/PCH file, but this file has a pre-compiled preamble, we also need + // to look in that file. + if (n == 1 || SM.getPreambleFileID().isValid()) { + getInclusions(&SourceManager::getLoadedSLocEntry, + SM.loaded_sloc_entry_size(), TU, CB, clientData); + } + + // Not a PCH/AST file. Note, if there is a preamble, it could still be that + // there are #includes in this file (e.g. for any include after the first + // declaration). + if (n != 1) + getInclusions(&SourceManager::getLocalSLocEntry, n, TU, CB, clientData); + } } // end extern C