1 //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
11 
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/Lex/Preprocessor.h"
14 #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
15 
16 using namespace clang;
17 using namespace tooling;
18 using namespace dependencies;
19 
20 void ModuleDepCollectorPP::FileChanged(SourceLocation Loc,
21                                        FileChangeReason Reason,
22                                        SrcMgr::CharacteristicKind FileType,
23                                        FileID PrevFID) {
24   if (Reason != PPCallbacks::EnterFile)
25     return;
26 
27   SourceManager &SM = Instance.getSourceManager();
28 
29   // Dependency generation really does want to go all the way to the
30   // file entry for a source location to find out what is depended on.
31   // We do not want #line markers to affect dependency generation!
32   Optional<FileEntryRef> File =
33       SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(Loc)));
34   if (!File)
35     return;
36 
37   StringRef FileName =
38       llvm::sys::path::remove_leading_dotslash(File->getName());
39 
40   MDC.MainDeps.push_back(FileName);
41 }
42 
43 void ModuleDepCollectorPP::InclusionDirective(
44     SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
45     bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
46     StringRef SearchPath, StringRef RelativePath, const Module *Imported,
47     SrcMgr::CharacteristicKind FileType) {
48   if (!File && !Imported) {
49     // This is a non-modular include that HeaderSearch failed to find. Add it
50     // here as `FileChanged` will never see it.
51     MDC.MainDeps.push_back(FileName);
52   }
53 
54   if (!Imported)
55     return;
56 
57   MDC.Deps[MDC.ContextHash + Imported->getTopLevelModule()->getFullModuleName()]
58       .ImportedByMainFile = true;
59   DirectDeps.insert(Imported->getTopLevelModule());
60 }
61 
62 void ModuleDepCollectorPP::EndOfMainFile() {
63   FileID MainFileID = Instance.getSourceManager().getMainFileID();
64   MDC.MainFile =
65       Instance.getSourceManager().getFileEntryForID(MainFileID)->getName();
66 
67   for (const Module *M : DirectDeps) {
68     handleTopLevelModule(M);
69   }
70 
71   for (auto &&I : MDC.Deps)
72     MDC.Consumer.handleModuleDependency(I.second);
73 
74   DependencyOutputOptions Opts;
75   for (auto &&I : MDC.MainDeps)
76     MDC.Consumer.handleFileDependency(Opts, I);
77 }
78 
79 void ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
80   assert(M == M->getTopLevelModule() && "Expected top level module!");
81 
82   auto ModI = MDC.Deps.insert(
83       std::make_pair(MDC.ContextHash + M->getFullModuleName(), ModuleDeps{}));
84 
85   if (!ModI.first->second.ModuleName.empty())
86     return;
87 
88   ModuleDeps &MD = ModI.first->second;
89 
90   const FileEntry *ModuleMap = Instance.getPreprocessor()
91                                    .getHeaderSearchInfo()
92                                    .getModuleMap()
93                                    .getContainingModuleMapFile(M);
94 
95   MD.ClangModuleMapFile = ModuleMap ? ModuleMap->getName() : "";
96   MD.ModuleName = M->getFullModuleName();
97   MD.ModulePCMPath = M->getASTFile()->getName();
98   MD.ContextHash = MDC.ContextHash;
99   serialization::ModuleFile *MF =
100       MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile());
101   MDC.Instance.getASTReader()->visitInputFiles(
102       *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) {
103         MD.FileDeps.insert(IF.getFile()->getName());
104       });
105 
106   addAllSubmoduleDeps(M, MD);
107 }
108 
109 void ModuleDepCollectorPP::addAllSubmoduleDeps(const Module *M,
110                                                ModuleDeps &MD) {
111   addModuleDep(M, MD);
112 
113   for (const Module *SubM : M->submodules())
114     addAllSubmoduleDeps(SubM, MD);
115 }
116 
117 void ModuleDepCollectorPP::addModuleDep(const Module *M, ModuleDeps &MD) {
118   for (const Module *Import : M->Imports) {
119     if (Import->getTopLevelModule() != M->getTopLevelModule()) {
120       MD.ClangModuleDeps.insert(Import->getTopLevelModuleName());
121       handleTopLevelModule(Import->getTopLevelModule());
122     }
123   }
124 }
125 
126 ModuleDepCollector::ModuleDepCollector(CompilerInstance &I,
127                                        DependencyConsumer &C)
128     : Instance(I), Consumer(C), ContextHash(I.getInvocation().getModuleHash()) {
129 }
130 
131 void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
132   PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(Instance, *this));
133 }
134 
135 void ModuleDepCollector::attachToASTReader(ASTReader &R) {}
136