1de3ef502SDouglas Gregor //===--- Module.h - Describe a module ---------------------------*- C++ -*-===//
2de3ef502SDouglas Gregor //
3de3ef502SDouglas Gregor //                     The LLVM Compiler Infrastructure
4de3ef502SDouglas Gregor //
5de3ef502SDouglas Gregor // This file is distributed under the University of Illinois Open Source
6de3ef502SDouglas Gregor // License. See LICENSE.TXT for details.
7de3ef502SDouglas Gregor //
8de3ef502SDouglas Gregor //===----------------------------------------------------------------------===//
9de3ef502SDouglas Gregor //
10de3ef502SDouglas Gregor // This file defines the Module class, which describes a module in the source
11de3ef502SDouglas Gregor // code.
12de3ef502SDouglas Gregor //
13de3ef502SDouglas Gregor //===----------------------------------------------------------------------===//
14de3ef502SDouglas Gregor #include "clang/Basic/Module.h"
15de3ef502SDouglas Gregor #include "clang/Basic/FileManager.h"
16*1fb5c3a6SDouglas Gregor #include "clang/Basic/LangOptions.h"
17*1fb5c3a6SDouglas Gregor #include "llvm/Support/ErrorHandling.h"
18de3ef502SDouglas Gregor #include "llvm/Support/raw_ostream.h"
19*1fb5c3a6SDouglas Gregor #include "llvm/ADT/SmallVector.h"
20*1fb5c3a6SDouglas Gregor #include "llvm/ADT/StringSwitch.h"
21de3ef502SDouglas Gregor using namespace clang;
22de3ef502SDouglas Gregor 
23de3ef502SDouglas Gregor Module::~Module() {
24de3ef502SDouglas Gregor   for (llvm::StringMap<Module *>::iterator I = SubModules.begin(),
25de3ef502SDouglas Gregor                                         IEnd = SubModules.end();
26de3ef502SDouglas Gregor        I != IEnd; ++I) {
27de3ef502SDouglas Gregor     delete I->getValue();
28de3ef502SDouglas Gregor   }
29de3ef502SDouglas Gregor 
30de3ef502SDouglas Gregor }
31de3ef502SDouglas Gregor 
32*1fb5c3a6SDouglas Gregor /// \brief Determine whether a translation unit built using the current
33*1fb5c3a6SDouglas Gregor /// language options has the given feature.
34*1fb5c3a6SDouglas Gregor static bool hasFeature(StringRef Feature, const LangOptions &LangOpts) {
35*1fb5c3a6SDouglas Gregor   return llvm::StringSwitch<bool>(Feature)
36*1fb5c3a6SDouglas Gregor            .Case("blocks", LangOpts.Blocks)
37*1fb5c3a6SDouglas Gregor            .Case("cplusplus", LangOpts.CPlusPlus)
38*1fb5c3a6SDouglas Gregor            .Case("cplusplus11", LangOpts.CPlusPlus0x)
39*1fb5c3a6SDouglas Gregor            .Case("objc", LangOpts.ObjC1)
40*1fb5c3a6SDouglas Gregor            .Case("objc_arc", LangOpts.ObjCAutoRefCount)
41*1fb5c3a6SDouglas Gregor            .Default(false);
42*1fb5c3a6SDouglas Gregor }
43*1fb5c3a6SDouglas Gregor 
44*1fb5c3a6SDouglas Gregor bool
45*1fb5c3a6SDouglas Gregor Module::isAvailable(const LangOptions &LangOpts, StringRef &Feature) const {
46*1fb5c3a6SDouglas Gregor   if (IsAvailable)
47*1fb5c3a6SDouglas Gregor     return true;
48*1fb5c3a6SDouglas Gregor 
49*1fb5c3a6SDouglas Gregor   for (const Module *Current = this; Current; Current = Current->Parent) {
50*1fb5c3a6SDouglas Gregor     for (unsigned I = 0, N = Current->Requires.size(); I != N; ++I) {
51*1fb5c3a6SDouglas Gregor       if (!hasFeature(Current->Requires[I], LangOpts)) {
52*1fb5c3a6SDouglas Gregor         Feature = Current->Requires[I];
53*1fb5c3a6SDouglas Gregor         return false;
54*1fb5c3a6SDouglas Gregor       }
55*1fb5c3a6SDouglas Gregor     }
56*1fb5c3a6SDouglas Gregor   }
57*1fb5c3a6SDouglas Gregor 
58*1fb5c3a6SDouglas Gregor   llvm_unreachable("could not find a reason why module is unavailable");
59*1fb5c3a6SDouglas Gregor   return false;
60*1fb5c3a6SDouglas Gregor }
61*1fb5c3a6SDouglas Gregor 
62f5eedd05SDouglas Gregor bool Module::isSubModuleOf(Module *Other) const {
63f5eedd05SDouglas Gregor   const Module *This = this;
64f5eedd05SDouglas Gregor   do {
65f5eedd05SDouglas Gregor     if (This == Other)
66f5eedd05SDouglas Gregor       return true;
67f5eedd05SDouglas Gregor 
68f5eedd05SDouglas Gregor     This = This->Parent;
69f5eedd05SDouglas Gregor   } while (This);
70f5eedd05SDouglas Gregor 
71f5eedd05SDouglas Gregor   return false;
72f5eedd05SDouglas Gregor }
73f5eedd05SDouglas Gregor 
7473441091SDouglas Gregor const Module *Module::getTopLevelModule() const {
7573441091SDouglas Gregor   const Module *Result = this;
7673441091SDouglas Gregor   while (Result->Parent)
7773441091SDouglas Gregor     Result = Result->Parent;
7873441091SDouglas Gregor 
7973441091SDouglas Gregor   return Result;
8073441091SDouglas Gregor }
8173441091SDouglas Gregor 
82de3ef502SDouglas Gregor std::string Module::getFullModuleName() const {
83de3ef502SDouglas Gregor   llvm::SmallVector<StringRef, 2> Names;
84de3ef502SDouglas Gregor 
85de3ef502SDouglas Gregor   // Build up the set of module names (from innermost to outermost).
86de3ef502SDouglas Gregor   for (const Module *M = this; M; M = M->Parent)
87de3ef502SDouglas Gregor     Names.push_back(M->Name);
88de3ef502SDouglas Gregor 
89de3ef502SDouglas Gregor   std::string Result;
90de3ef502SDouglas Gregor   for (llvm::SmallVector<StringRef, 2>::reverse_iterator I = Names.rbegin(),
91de3ef502SDouglas Gregor                                                       IEnd = Names.rend();
92de3ef502SDouglas Gregor        I != IEnd; ++I) {
93de3ef502SDouglas Gregor     if (!Result.empty())
94de3ef502SDouglas Gregor       Result += '.';
95de3ef502SDouglas Gregor 
96de3ef502SDouglas Gregor     Result += *I;
97de3ef502SDouglas Gregor   }
98de3ef502SDouglas Gregor 
99de3ef502SDouglas Gregor   return Result;
100de3ef502SDouglas Gregor }
101de3ef502SDouglas Gregor 
10273141fa9SDouglas Gregor const DirectoryEntry *Module::getUmbrellaDir() const {
10373141fa9SDouglas Gregor   if (const FileEntry *Header = getUmbrellaHeader())
10473141fa9SDouglas Gregor     return Header->getDir();
10573141fa9SDouglas Gregor 
10673141fa9SDouglas Gregor   return Umbrella.dyn_cast<const DirectoryEntry *>();
10773141fa9SDouglas Gregor }
10873141fa9SDouglas Gregor 
109*1fb5c3a6SDouglas Gregor void Module::addRequirement(StringRef Feature, const LangOptions &LangOpts) {
110*1fb5c3a6SDouglas Gregor   Requires.push_back(Feature);
111*1fb5c3a6SDouglas Gregor 
112*1fb5c3a6SDouglas Gregor   // If this feature is currently available, we're done.
113*1fb5c3a6SDouglas Gregor   if (hasFeature(Feature, LangOpts))
114*1fb5c3a6SDouglas Gregor     return;
115*1fb5c3a6SDouglas Gregor 
116*1fb5c3a6SDouglas Gregor   if (!IsAvailable)
117*1fb5c3a6SDouglas Gregor     return;
118*1fb5c3a6SDouglas Gregor 
119*1fb5c3a6SDouglas Gregor   llvm::SmallVector<Module *, 2> Stack;
120*1fb5c3a6SDouglas Gregor   Stack.push_back(this);
121*1fb5c3a6SDouglas Gregor   while (!Stack.empty()) {
122*1fb5c3a6SDouglas Gregor     Module *Current = Stack.back();
123*1fb5c3a6SDouglas Gregor     Stack.pop_back();
124*1fb5c3a6SDouglas Gregor 
125*1fb5c3a6SDouglas Gregor     if (!Current->IsAvailable)
126*1fb5c3a6SDouglas Gregor       continue;
127*1fb5c3a6SDouglas Gregor 
128*1fb5c3a6SDouglas Gregor     Current->IsAvailable = false;
129*1fb5c3a6SDouglas Gregor     for (llvm::StringMap<Module *>::iterator Sub = Current->SubModules.begin(),
130*1fb5c3a6SDouglas Gregor                                           SubEnd = Current->SubModules.end();
131*1fb5c3a6SDouglas Gregor          Sub != SubEnd; ++Sub) {
132*1fb5c3a6SDouglas Gregor       if (Sub->second->IsAvailable)
133*1fb5c3a6SDouglas Gregor         Stack.push_back(Sub->second);
134*1fb5c3a6SDouglas Gregor     }
135*1fb5c3a6SDouglas Gregor   }
136*1fb5c3a6SDouglas Gregor }
137*1fb5c3a6SDouglas Gregor 
13824bb923aSDouglas Gregor static void printModuleId(llvm::raw_ostream &OS, const ModuleId &Id) {
13924bb923aSDouglas Gregor   for (unsigned I = 0, N = Id.size(); I != N; ++I) {
14024bb923aSDouglas Gregor     if (I)
14124bb923aSDouglas Gregor       OS << ".";
14224bb923aSDouglas Gregor     OS << Id[I].first;
14324bb923aSDouglas Gregor   }
14424bb923aSDouglas Gregor }
14524bb923aSDouglas Gregor 
146de3ef502SDouglas Gregor void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
147de3ef502SDouglas Gregor   OS.indent(Indent);
148de3ef502SDouglas Gregor   if (IsFramework)
149de3ef502SDouglas Gregor     OS << "framework ";
150de3ef502SDouglas Gregor   if (IsExplicit)
151de3ef502SDouglas Gregor     OS << "explicit ";
152de3ef502SDouglas Gregor   OS << "module " << Name << " {\n";
153de3ef502SDouglas Gregor 
154*1fb5c3a6SDouglas Gregor   if (!Requires.empty()) {
155*1fb5c3a6SDouglas Gregor     OS.indent(Indent + 2);
156*1fb5c3a6SDouglas Gregor     OS << "requires ";
157*1fb5c3a6SDouglas Gregor     for (unsigned I = 0, N = Requires.size(); I != N; ++I) {
158*1fb5c3a6SDouglas Gregor       if (I)
159*1fb5c3a6SDouglas Gregor         OS << ", ";
160*1fb5c3a6SDouglas Gregor       OS << Requires[I];
161*1fb5c3a6SDouglas Gregor     }
162*1fb5c3a6SDouglas Gregor     OS << "\n";
163*1fb5c3a6SDouglas Gregor   }
164*1fb5c3a6SDouglas Gregor 
16573141fa9SDouglas Gregor   if (const FileEntry *UmbrellaHeader = getUmbrellaHeader()) {
166de3ef502SDouglas Gregor     OS.indent(Indent + 2);
167322f633cSDouglas Gregor     OS << "umbrella header \"";
168de3ef502SDouglas Gregor     OS.write_escaped(UmbrellaHeader->getName());
169de3ef502SDouglas Gregor     OS << "\"\n";
170322f633cSDouglas Gregor   } else if (const DirectoryEntry *UmbrellaDir = getUmbrellaDir()) {
171322f633cSDouglas Gregor     OS.indent(Indent + 2);
172322f633cSDouglas Gregor     OS << "umbrella \"";
173322f633cSDouglas Gregor     OS.write_escaped(UmbrellaDir->getName());
174322f633cSDouglas Gregor     OS << "\"\n";
175de3ef502SDouglas Gregor   }
176de3ef502SDouglas Gregor 
177de3ef502SDouglas Gregor   for (unsigned I = 0, N = Headers.size(); I != N; ++I) {
178de3ef502SDouglas Gregor     OS.indent(Indent + 2);
179de3ef502SDouglas Gregor     OS << "header \"";
180de3ef502SDouglas Gregor     OS.write_escaped(Headers[I]->getName());
181de3ef502SDouglas Gregor     OS << "\"\n";
182de3ef502SDouglas Gregor   }
183de3ef502SDouglas Gregor 
184de3ef502SDouglas Gregor   for (llvm::StringMap<Module *>::const_iterator MI = SubModules.begin(),
185de3ef502SDouglas Gregor                                               MIEnd = SubModules.end();
186de3ef502SDouglas Gregor        MI != MIEnd; ++MI)
187de3ef502SDouglas Gregor     MI->getValue()->print(OS, Indent + 2);
188de3ef502SDouglas Gregor 
18924bb923aSDouglas Gregor   for (unsigned I = 0, N = Exports.size(); I != N; ++I) {
19024bb923aSDouglas Gregor     OS.indent(Indent + 2);
1918c7c8352SDouglas Gregor     OS << "export ";
1928c7c8352SDouglas Gregor     if (Module *Restriction = Exports[I].getPointer()) {
1938c7c8352SDouglas Gregor       OS << Restriction->getFullModuleName();
19424bb923aSDouglas Gregor       if (Exports[I].getInt())
19524bb923aSDouglas Gregor         OS << ".*";
1968c7c8352SDouglas Gregor     } else {
1978c7c8352SDouglas Gregor       OS << "*";
1988c7c8352SDouglas Gregor     }
19924bb923aSDouglas Gregor     OS << "\n";
20024bb923aSDouglas Gregor   }
20124bb923aSDouglas Gregor 
20224bb923aSDouglas Gregor   for (unsigned I = 0, N = UnresolvedExports.size(); I != N; ++I) {
20324bb923aSDouglas Gregor     OS.indent(Indent + 2);
20424bb923aSDouglas Gregor     OS << "export ";
20524bb923aSDouglas Gregor     printModuleId(OS, UnresolvedExports[I].Id);
2068c7c8352SDouglas Gregor     if (UnresolvedExports[I].Wildcard) {
2078c7c8352SDouglas Gregor       if (UnresolvedExports[I].Id.empty())
2088c7c8352SDouglas Gregor         OS << "*";
2098c7c8352SDouglas Gregor       else
21024bb923aSDouglas Gregor         OS << ".*";
2118c7c8352SDouglas Gregor     }
21224bb923aSDouglas Gregor     OS << "\n";
21324bb923aSDouglas Gregor   }
21424bb923aSDouglas Gregor 
21573441091SDouglas Gregor   if (InferSubmodules) {
21673441091SDouglas Gregor     OS.indent(Indent + 2);
21773441091SDouglas Gregor     if (InferExplicitSubmodules)
21873441091SDouglas Gregor       OS << "explicit ";
21973441091SDouglas Gregor     OS << "module * {\n";
22073441091SDouglas Gregor     if (InferExportWildcard) {
22173441091SDouglas Gregor       OS.indent(Indent + 4);
22273441091SDouglas Gregor       OS << "export *\n";
22373441091SDouglas Gregor     }
22473441091SDouglas Gregor     OS.indent(Indent + 2);
22573441091SDouglas Gregor     OS << "}\n";
22673441091SDouglas Gregor   }
22773441091SDouglas Gregor 
228de3ef502SDouglas Gregor   OS.indent(Indent);
229de3ef502SDouglas Gregor   OS << "}\n";
230de3ef502SDouglas Gregor }
231de3ef502SDouglas Gregor 
232de3ef502SDouglas Gregor void Module::dump() const {
233de3ef502SDouglas Gregor   print(llvm::errs());
234de3ef502SDouglas Gregor }
235de3ef502SDouglas Gregor 
236de3ef502SDouglas Gregor 
237