xref: /netbsd-src/external/apache2/llvm/dist/clang/tools/libclang/CIndexInclusionStack.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===- CIndexInclusionStack.cpp - Clang-C Source Indexing Library ---------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file defines a callback mechanism for clients to get the inclusion
107330f729Sjoerg // stack from a translation unit.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg 
147330f729Sjoerg #include "CIndexer.h"
157330f729Sjoerg #include "CXSourceLocation.h"
167330f729Sjoerg #include "CXTranslationUnit.h"
177330f729Sjoerg #include "clang/AST/DeclVisitor.h"
187330f729Sjoerg #include "clang/Frontend/ASTUnit.h"
197330f729Sjoerg using namespace clang;
207330f729Sjoerg 
21*e038c9c4Sjoerg namespace {
getInclusions(bool IsLocal,unsigned n,CXTranslationUnit TU,CXInclusionVisitor CB,CXClientData clientData)22*e038c9c4Sjoerg void getInclusions(bool IsLocal, unsigned n, CXTranslationUnit TU,
23*e038c9c4Sjoerg                    CXInclusionVisitor CB, CXClientData clientData) {
247330f729Sjoerg   ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
257330f729Sjoerg   SourceManager &SM = CXXUnit->getSourceManager();
267330f729Sjoerg   ASTContext &Ctx = CXXUnit->getASTContext();
277330f729Sjoerg   SmallVector<CXSourceLocation, 10> InclusionStack;
287330f729Sjoerg   const bool HasPreamble = SM.getPreambleFileID().isValid();
297330f729Sjoerg 
307330f729Sjoerg   for (unsigned i = 0 ; i < n ; ++i) {
317330f729Sjoerg     bool Invalid = false;
32*e038c9c4Sjoerg     const SrcMgr::SLocEntry &SL =
33*e038c9c4Sjoerg         IsLocal ? SM.getLocalSLocEntry(i) : SM.getLoadedSLocEntry(i, &Invalid);
347330f729Sjoerg     if (!SL.isFile() || Invalid)
357330f729Sjoerg       continue;
367330f729Sjoerg 
377330f729Sjoerg     const SrcMgr::FileInfo &FI = SL.getFile();
38*e038c9c4Sjoerg     if (!FI.getContentCache().OrigEntry)
397330f729Sjoerg       continue;
407330f729Sjoerg 
417330f729Sjoerg     // If this is the main file, and there is a preamble, skip this SLoc. The
427330f729Sjoerg     // inclusions of the preamble already showed it.
437330f729Sjoerg     SourceLocation L = FI.getIncludeLoc();
447330f729Sjoerg     if (HasPreamble && CXXUnit->isInMainFileID(L))
457330f729Sjoerg       continue;
467330f729Sjoerg 
477330f729Sjoerg     // Build the inclusion stack.
487330f729Sjoerg     InclusionStack.clear();
497330f729Sjoerg     while (L.isValid()) {
507330f729Sjoerg       PresumedLoc PLoc = SM.getPresumedLoc(L);
517330f729Sjoerg       InclusionStack.push_back(cxloc::translateSourceLocation(Ctx, L));
527330f729Sjoerg       L = PLoc.isValid()? PLoc.getIncludeLoc() : SourceLocation();
537330f729Sjoerg     }
547330f729Sjoerg 
557330f729Sjoerg     // If there is a preamble, the last entry is the "inclusion" of that
567330f729Sjoerg     // preamble into the main file, which has the bogus entry of main.c:1:1
577330f729Sjoerg     if (HasPreamble && !InclusionStack.empty())
587330f729Sjoerg       InclusionStack.pop_back();
597330f729Sjoerg 
607330f729Sjoerg     // Callback to the client.
617330f729Sjoerg     // FIXME: We should have a function to construct CXFiles.
627330f729Sjoerg     CB(static_cast<CXFile>(
63*e038c9c4Sjoerg            const_cast<FileEntry *>(FI.getContentCache().OrigEntry)),
647330f729Sjoerg        InclusionStack.data(), InclusionStack.size(), clientData);
657330f729Sjoerg   }
667330f729Sjoerg }
67*e038c9c4Sjoerg } // namespace
687330f729Sjoerg 
clang_getInclusions(CXTranslationUnit TU,CXInclusionVisitor CB,CXClientData clientData)697330f729Sjoerg void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
707330f729Sjoerg                          CXClientData clientData) {
717330f729Sjoerg   if (cxtu::isNotUsableTU(TU)) {
727330f729Sjoerg     LOG_BAD_TU(TU);
737330f729Sjoerg     return;
747330f729Sjoerg   }
757330f729Sjoerg 
767330f729Sjoerg   SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
777330f729Sjoerg   const unsigned n =  SM.local_sloc_entry_size();
787330f729Sjoerg 
797330f729Sjoerg   // In the case where all the SLocEntries are in an external source, traverse
807330f729Sjoerg   // those SLocEntries as well.  This is the case where we are looking
817330f729Sjoerg   // at the inclusion stack of an AST/PCH file. Also, if we are not looking at
827330f729Sjoerg   // a AST/PCH file, but this file has a pre-compiled preamble, we also need
837330f729Sjoerg   // to look in that file.
847330f729Sjoerg   if (n == 1 || SM.getPreambleFileID().isValid()) {
85*e038c9c4Sjoerg     getInclusions(/*IsLocal=*/false, SM.loaded_sloc_entry_size(), TU, CB,
86*e038c9c4Sjoerg                   clientData);
877330f729Sjoerg   }
887330f729Sjoerg 
897330f729Sjoerg   // Not a PCH/AST file. Note, if there is a preamble, it could still be that
907330f729Sjoerg   // there are #includes in this file (e.g. for any include after the first
917330f729Sjoerg   // declaration).
927330f729Sjoerg   if (n != 1)
93*e038c9c4Sjoerg     getInclusions(/*IsLocal=*/true, n, TU, CB, clientData);
947330f729Sjoerg }
95