1 | //===- Module.cpp - Describe a module -------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines the Module class, which describes a module in the source |
10 | // code. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/Basic/Module.h" |
15 | #include "clang/Basic/CharInfo.h" |
16 | #include "clang/Basic/FileManager.h" |
17 | #include "clang/Basic/LangOptions.h" |
18 | #include "clang/Basic/SourceLocation.h" |
19 | #include "clang/Basic/TargetInfo.h" |
20 | #include "llvm/ADT/ArrayRef.h" |
21 | #include "llvm/ADT/SmallVector.h" |
22 | #include "llvm/ADT/StringMap.h" |
23 | #include "llvm/ADT/StringRef.h" |
24 | #include "llvm/ADT/StringSwitch.h" |
25 | #include "llvm/Support/Compiler.h" |
26 | #include "llvm/Support/ErrorHandling.h" |
27 | #include "llvm/Support/raw_ostream.h" |
28 | #include <algorithm> |
29 | #include <cassert> |
30 | #include <functional> |
31 | #include <string> |
32 | #include <utility> |
33 | #include <vector> |
34 | |
35 | using namespace clang; |
36 | |
37 | Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, |
38 | bool IsFramework, bool IsExplicit, unsigned VisibilityID) |
39 | : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), |
40 | VisibilityID(VisibilityID), IsUnimportable(false), |
41 | HasIncompatibleModuleFile(false), IsAvailable(true), |
42 | IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(IsExplicit), |
43 | IsSystem(false), IsExternC(false), IsInferred(false), |
44 | InferSubmodules(false), InferExplicitSubmodules(false), |
45 | InferExportWildcard(false), ConfigMacrosExhaustive(false), |
46 | NoUndeclaredIncludes(false), ModuleMapIsPrivate(false), |
47 | NamedModuleHasInit(true), NameVisibility(Hidden) { |
48 | if (Parent) { |
49 | IsAvailable = Parent->isAvailable(); |
50 | IsUnimportable = Parent->isUnimportable(); |
51 | IsSystem = Parent->IsSystem; |
52 | IsExternC = Parent->IsExternC; |
53 | NoUndeclaredIncludes = Parent->NoUndeclaredIncludes; |
54 | ModuleMapIsPrivate = Parent->ModuleMapIsPrivate; |
55 | |
56 | Parent->SubModuleIndex[Name] = Parent->SubModules.size(); |
57 | Parent->SubModules.push_back(x: this); |
58 | } |
59 | } |
60 | |
61 | Module::~Module() { |
62 | for (auto *Submodule : SubModules) { |
63 | delete Submodule; |
64 | } |
65 | } |
66 | |
67 | static bool isPlatformEnvironment(const TargetInfo &Target, StringRef Feature) { |
68 | StringRef Platform = Target.getPlatformName(); |
69 | StringRef Env = Target.getTriple().getEnvironmentName(); |
70 | |
71 | // Attempt to match platform and environment. |
72 | if (Platform == Feature || Target.getTriple().getOSName() == Feature || |
73 | Env == Feature) |
74 | return true; |
75 | |
76 | auto CmpPlatformEnv = [](StringRef LHS, StringRef RHS) { |
77 | auto Pos = LHS.find(C: '-'); |
78 | if (Pos == StringRef::npos) |
79 | return false; |
80 | SmallString<128> NewLHS = LHS.slice(Start: 0, End: Pos); |
81 | NewLHS += LHS.slice(Start: Pos+1, End: LHS.size()); |
82 | return NewLHS == RHS; |
83 | }; |
84 | |
85 | SmallString<128> PlatformEnv = Target.getTriple().getOSAndEnvironmentName(); |
86 | // Darwin has different but equivalent variants for simulators, example: |
87 | // 1. x86_64-apple-ios-simulator |
88 | // 2. x86_64-apple-iossimulator |
89 | // where both are valid examples of the same platform+environment but in the |
90 | // variant (2) the simulator is hardcoded as part of the platform name. Both |
91 | // forms above should match for "iossimulator" requirement. |
92 | if (Target.getTriple().isOSDarwin() && PlatformEnv.ends_with(Suffix: "simulator" )) |
93 | return PlatformEnv == Feature || CmpPlatformEnv(PlatformEnv, Feature); |
94 | |
95 | return PlatformEnv == Feature; |
96 | } |
97 | |
98 | /// Determine whether a translation unit built using the current |
99 | /// language options has the given feature. |
100 | static bool hasFeature(StringRef Feature, const LangOptions &LangOpts, |
101 | const TargetInfo &Target) { |
102 | bool HasFeature = llvm::StringSwitch<bool>(Feature) |
103 | .Case(S: "altivec" , Value: LangOpts.AltiVec) |
104 | .Case(S: "blocks" , Value: LangOpts.Blocks) |
105 | .Case(S: "coroutines" , Value: LangOpts.Coroutines) |
106 | .Case(S: "cplusplus" , Value: LangOpts.CPlusPlus) |
107 | .Case(S: "cplusplus11" , Value: LangOpts.CPlusPlus11) |
108 | .Case(S: "cplusplus14" , Value: LangOpts.CPlusPlus14) |
109 | .Case(S: "cplusplus17" , Value: LangOpts.CPlusPlus17) |
110 | .Case(S: "cplusplus20" , Value: LangOpts.CPlusPlus20) |
111 | .Case(S: "cplusplus23" , Value: LangOpts.CPlusPlus23) |
112 | .Case(S: "cplusplus26" , Value: LangOpts.CPlusPlus26) |
113 | .Case(S: "c99" , Value: LangOpts.C99) |
114 | .Case(S: "c11" , Value: LangOpts.C11) |
115 | .Case(S: "c17" , Value: LangOpts.C17) |
116 | .Case(S: "c23" , Value: LangOpts.C23) |
117 | .Case(S: "freestanding" , Value: LangOpts.Freestanding) |
118 | .Case(S: "gnuinlineasm" , Value: LangOpts.GNUAsm) |
119 | .Case(S: "objc" , Value: LangOpts.ObjC) |
120 | .Case(S: "objc_arc" , Value: LangOpts.ObjCAutoRefCount) |
121 | .Case(S: "opencl" , Value: LangOpts.OpenCL) |
122 | .Case(S: "tls" , Value: Target.isTLSSupported()) |
123 | .Case(S: "zvector" , Value: LangOpts.ZVector) |
124 | .Default(Value: Target.hasFeature(Feature) || |
125 | isPlatformEnvironment(Target, Feature)); |
126 | if (!HasFeature) |
127 | HasFeature = llvm::is_contained(Range: LangOpts.ModuleFeatures, Element: Feature); |
128 | return HasFeature; |
129 | } |
130 | |
131 | bool Module::isUnimportable(const LangOptions &LangOpts, |
132 | const TargetInfo &Target, Requirement &Req, |
133 | Module *&ShadowingModule) const { |
134 | if (!IsUnimportable) |
135 | return false; |
136 | |
137 | for (const Module *Current = this; Current; Current = Current->Parent) { |
138 | if (Current->ShadowingModule) { |
139 | ShadowingModule = Current->ShadowingModule; |
140 | return true; |
141 | } |
142 | for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) { |
143 | if (hasFeature(Feature: Current->Requirements[I].first, LangOpts, Target) != |
144 | Current->Requirements[I].second) { |
145 | Req = Current->Requirements[I]; |
146 | return true; |
147 | } |
148 | } |
149 | } |
150 | |
151 | llvm_unreachable("could not find a reason why module is unimportable" ); |
152 | } |
153 | |
154 | // The -fmodule-name option tells the compiler to textually include headers in |
155 | // the specified module, meaning Clang won't build the specified module. This |
156 | // is useful in a number of situations, for instance, when building a library |
157 | // that vends a module map, one might want to avoid hitting intermediate build |
158 | // products containing the module map or avoid finding the system installed |
159 | // modulemap for that library. |
160 | bool Module::isForBuilding(const LangOptions &LangOpts) const { |
161 | StringRef TopLevelName = getTopLevelModuleName(); |
162 | StringRef CurrentModule = LangOpts.CurrentModule; |
163 | |
164 | // When building the implementation of framework Foo, we want to make sure |
165 | // that Foo *and* Foo_Private are textually included and no modules are built |
166 | // for either. |
167 | if (!LangOpts.isCompilingModule() && getTopLevelModule()->IsFramework && |
168 | CurrentModule == LangOpts.ModuleName && |
169 | !CurrentModule.ends_with(Suffix: "_Private" ) && |
170 | TopLevelName.ends_with(Suffix: "_Private" )) |
171 | TopLevelName = TopLevelName.drop_back(N: 8); |
172 | |
173 | return TopLevelName == CurrentModule; |
174 | } |
175 | |
176 | bool Module::(const LangOptions &LangOpts, const TargetInfo &Target, |
177 | Requirement &Req, |
178 | UnresolvedHeaderDirective &, |
179 | Module *&ShadowingModule) const { |
180 | if (IsAvailable) |
181 | return true; |
182 | |
183 | if (isUnimportable(LangOpts, Target, Req, ShadowingModule)) |
184 | return false; |
185 | |
186 | // FIXME: All missing headers are listed on the top-level module. Should we |
187 | // just look there? |
188 | for (const Module *Current = this; Current; Current = Current->Parent) { |
189 | if (!Current->MissingHeaders.empty()) { |
190 | MissingHeader = Current->MissingHeaders.front(); |
191 | return false; |
192 | } |
193 | } |
194 | |
195 | llvm_unreachable("could not find a reason why module is unavailable" ); |
196 | } |
197 | |
198 | bool Module::isSubModuleOf(const Module *Other) const { |
199 | for (auto *Parent = this; Parent; Parent = Parent->Parent) { |
200 | if (Parent == Other) |
201 | return true; |
202 | } |
203 | return false; |
204 | } |
205 | |
206 | const Module *Module::getTopLevelModule() const { |
207 | const Module *Result = this; |
208 | while (Result->Parent) |
209 | Result = Result->Parent; |
210 | |
211 | return Result; |
212 | } |
213 | |
214 | static StringRef getModuleNameFromComponent( |
215 | const std::pair<std::string, SourceLocation> &IdComponent) { |
216 | return IdComponent.first; |
217 | } |
218 | |
219 | static StringRef getModuleNameFromComponent(StringRef R) { return R; } |
220 | |
221 | template<typename InputIter> |
222 | static void printModuleId(raw_ostream &OS, InputIter Begin, InputIter End, |
223 | bool AllowStringLiterals = true) { |
224 | for (InputIter It = Begin; It != End; ++It) { |
225 | if (It != Begin) |
226 | OS << "." ; |
227 | |
228 | StringRef Name = getModuleNameFromComponent(*It); |
229 | if (!AllowStringLiterals || isValidAsciiIdentifier(S: Name)) |
230 | OS << Name; |
231 | else { |
232 | OS << '"'; |
233 | OS.write_escaped(Str: Name); |
234 | OS << '"'; |
235 | } |
236 | } |
237 | } |
238 | |
239 | template<typename Container> |
240 | static void printModuleId(raw_ostream &OS, const Container &C) { |
241 | return printModuleId(OS, C.begin(), C.end()); |
242 | } |
243 | |
244 | std::string Module::getFullModuleName(bool AllowStringLiterals) const { |
245 | SmallVector<StringRef, 2> Names; |
246 | |
247 | // Build up the set of module names (from innermost to outermost). |
248 | for (const Module *M = this; M; M = M->Parent) |
249 | Names.push_back(Elt: M->Name); |
250 | |
251 | std::string Result; |
252 | |
253 | llvm::raw_string_ostream Out(Result); |
254 | printModuleId(OS&: Out, Begin: Names.rbegin(), End: Names.rend(), AllowStringLiterals); |
255 | Out.flush(); |
256 | |
257 | return Result; |
258 | } |
259 | |
260 | bool Module::fullModuleNameIs(ArrayRef<StringRef> nameParts) const { |
261 | for (const Module *M = this; M; M = M->Parent) { |
262 | if (nameParts.empty() || M->Name != nameParts.back()) |
263 | return false; |
264 | nameParts = nameParts.drop_back(); |
265 | } |
266 | return nameParts.empty(); |
267 | } |
268 | |
269 | OptionalDirectoryEntryRef Module::getEffectiveUmbrellaDir() const { |
270 | if (const auto *Hdr = std::get_if<FileEntryRef>(ptr: &Umbrella)) |
271 | return Hdr->getDir(); |
272 | if (const auto *Dir = std::get_if<DirectoryEntryRef>(ptr: &Umbrella)) |
273 | return *Dir; |
274 | return std::nullopt; |
275 | } |
276 | |
277 | void Module::(FileEntryRef File) { |
278 | assert(File); |
279 | TopHeaders.insert(X: File); |
280 | } |
281 | |
282 | ArrayRef<FileEntryRef> Module::(FileManager &FileMgr) { |
283 | if (!TopHeaderNames.empty()) { |
284 | for (StringRef : TopHeaderNames) |
285 | if (auto FE = FileMgr.getOptionalFileRef(Filename: TopHeaderName)) |
286 | TopHeaders.insert(X: *FE); |
287 | TopHeaderNames.clear(); |
288 | } |
289 | |
290 | return llvm::ArrayRef(TopHeaders.begin(), TopHeaders.end()); |
291 | } |
292 | |
293 | bool Module::directlyUses(const Module *Requested) { |
294 | auto *Top = getTopLevelModule(); |
295 | |
296 | // A top-level module implicitly uses itself. |
297 | if (Requested->isSubModuleOf(Other: Top)) |
298 | return true; |
299 | |
300 | for (auto *Use : Top->DirectUses) |
301 | if (Requested->isSubModuleOf(Other: Use)) |
302 | return true; |
303 | |
304 | // Anyone is allowed to use our builtin stdarg.h and stddef.h and their |
305 | // accompanying modules. |
306 | if (Requested->getTopLevelModuleName() == "_Builtin_stdarg" || |
307 | Requested->getTopLevelModuleName() == "_Builtin_stddef" ) |
308 | return true; |
309 | |
310 | if (NoUndeclaredIncludes) |
311 | UndeclaredUses.insert(X: Requested); |
312 | |
313 | return false; |
314 | } |
315 | |
316 | void Module::addRequirement(StringRef Feature, bool RequiredState, |
317 | const LangOptions &LangOpts, |
318 | const TargetInfo &Target) { |
319 | Requirements.push_back(Elt: Requirement(std::string(Feature), RequiredState)); |
320 | |
321 | // If this feature is currently available, we're done. |
322 | if (hasFeature(Feature, LangOpts, Target) == RequiredState) |
323 | return; |
324 | |
325 | markUnavailable(/*Unimportable*/true); |
326 | } |
327 | |
328 | void Module::markUnavailable(bool Unimportable) { |
329 | auto needUpdate = [Unimportable](Module *M) { |
330 | return M->IsAvailable || (!M->IsUnimportable && Unimportable); |
331 | }; |
332 | |
333 | if (!needUpdate(this)) |
334 | return; |
335 | |
336 | SmallVector<Module *, 2> Stack; |
337 | Stack.push_back(Elt: this); |
338 | while (!Stack.empty()) { |
339 | Module *Current = Stack.back(); |
340 | Stack.pop_back(); |
341 | |
342 | if (!needUpdate(Current)) |
343 | continue; |
344 | |
345 | Current->IsAvailable = false; |
346 | Current->IsUnimportable |= Unimportable; |
347 | for (auto *Submodule : Current->submodules()) { |
348 | if (needUpdate(Submodule)) |
349 | Stack.push_back(Elt: Submodule); |
350 | } |
351 | } |
352 | } |
353 | |
354 | Module *Module::findSubmodule(StringRef Name) const { |
355 | llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Key: Name); |
356 | if (Pos == SubModuleIndex.end()) |
357 | return nullptr; |
358 | |
359 | return SubModules[Pos->getValue()]; |
360 | } |
361 | |
362 | Module *Module::findOrInferSubmodule(StringRef Name) { |
363 | llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Key: Name); |
364 | if (Pos != SubModuleIndex.end()) |
365 | return SubModules[Pos->getValue()]; |
366 | if (!InferSubmodules) |
367 | return nullptr; |
368 | Module *Result = new Module(Name, SourceLocation(), this, false, InferExplicitSubmodules, 0); |
369 | Result->InferExplicitSubmodules = InferExplicitSubmodules; |
370 | Result->InferSubmodules = InferSubmodules; |
371 | Result->InferExportWildcard = InferExportWildcard; |
372 | if (Result->InferExportWildcard) |
373 | Result->Exports.push_back(Elt: Module::ExportDecl(nullptr, true)); |
374 | return Result; |
375 | } |
376 | |
377 | Module *Module::getGlobalModuleFragment() const { |
378 | assert(isNamedModuleUnit() && "We should only query the global module " |
379 | "fragment from the C++20 Named modules" ); |
380 | |
381 | for (auto *SubModule : SubModules) |
382 | if (SubModule->isExplicitGlobalModule()) |
383 | return SubModule; |
384 | |
385 | return nullptr; |
386 | } |
387 | |
388 | Module *Module::getPrivateModuleFragment() const { |
389 | assert(isNamedModuleUnit() && "We should only query the private module " |
390 | "fragment from the C++20 Named modules" ); |
391 | |
392 | for (auto *SubModule : SubModules) |
393 | if (SubModule->isPrivateModule()) |
394 | return SubModule; |
395 | |
396 | return nullptr; |
397 | } |
398 | |
399 | void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const { |
400 | // All non-explicit submodules are exported. |
401 | for (std::vector<Module *>::const_iterator I = SubModules.begin(), |
402 | E = SubModules.end(); |
403 | I != E; ++I) { |
404 | Module *Mod = *I; |
405 | if (!Mod->IsExplicit) |
406 | Exported.push_back(Elt: Mod); |
407 | } |
408 | |
409 | // Find re-exported modules by filtering the list of imported modules. |
410 | bool AnyWildcard = false; |
411 | bool UnrestrictedWildcard = false; |
412 | SmallVector<Module *, 4> WildcardRestrictions; |
413 | for (unsigned I = 0, N = Exports.size(); I != N; ++I) { |
414 | Module *Mod = Exports[I].getPointer(); |
415 | if (!Exports[I].getInt()) { |
416 | // Export a named module directly; no wildcards involved. |
417 | Exported.push_back(Elt: Mod); |
418 | |
419 | continue; |
420 | } |
421 | |
422 | // Wildcard export: export all of the imported modules that match |
423 | // the given pattern. |
424 | AnyWildcard = true; |
425 | if (UnrestrictedWildcard) |
426 | continue; |
427 | |
428 | if (Module *Restriction = Exports[I].getPointer()) |
429 | WildcardRestrictions.push_back(Elt: Restriction); |
430 | else { |
431 | WildcardRestrictions.clear(); |
432 | UnrestrictedWildcard = true; |
433 | } |
434 | } |
435 | |
436 | // If there were any wildcards, push any imported modules that were |
437 | // re-exported by the wildcard restriction. |
438 | if (!AnyWildcard) |
439 | return; |
440 | |
441 | for (unsigned I = 0, N = Imports.size(); I != N; ++I) { |
442 | Module *Mod = Imports[I]; |
443 | bool Acceptable = UnrestrictedWildcard; |
444 | if (!Acceptable) { |
445 | // Check whether this module meets one of the restrictions. |
446 | for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) { |
447 | Module *Restriction = WildcardRestrictions[R]; |
448 | if (Mod == Restriction || Mod->isSubModuleOf(Other: Restriction)) { |
449 | Acceptable = true; |
450 | break; |
451 | } |
452 | } |
453 | } |
454 | |
455 | if (!Acceptable) |
456 | continue; |
457 | |
458 | Exported.push_back(Elt: Mod); |
459 | } |
460 | } |
461 | |
462 | void Module::buildVisibleModulesCache() const { |
463 | assert(VisibleModulesCache.empty() && "cache does not need building" ); |
464 | |
465 | // This module is visible to itself. |
466 | VisibleModulesCache.insert(V: this); |
467 | |
468 | // Every imported module is visible. |
469 | SmallVector<Module *, 16> Stack(Imports.begin(), Imports.end()); |
470 | while (!Stack.empty()) { |
471 | Module *CurrModule = Stack.pop_back_val(); |
472 | |
473 | // Every module transitively exported by an imported module is visible. |
474 | if (VisibleModulesCache.insert(V: CurrModule).second) |
475 | CurrModule->getExportedModules(Exported&: Stack); |
476 | } |
477 | } |
478 | |
479 | void Module::print(raw_ostream &OS, unsigned Indent, bool Dump) const { |
480 | OS.indent(NumSpaces: Indent); |
481 | if (IsFramework) |
482 | OS << "framework " ; |
483 | if (IsExplicit) |
484 | OS << "explicit " ; |
485 | OS << "module " ; |
486 | printModuleId(OS, Begin: &Name, End: &Name + 1); |
487 | |
488 | if (IsSystem || IsExternC) { |
489 | OS.indent(NumSpaces: Indent + 2); |
490 | if (IsSystem) |
491 | OS << " [system]" ; |
492 | if (IsExternC) |
493 | OS << " [extern_c]" ; |
494 | } |
495 | |
496 | OS << " {\n" ; |
497 | |
498 | if (!Requirements.empty()) { |
499 | OS.indent(NumSpaces: Indent + 2); |
500 | OS << "requires " ; |
501 | for (unsigned I = 0, N = Requirements.size(); I != N; ++I) { |
502 | if (I) |
503 | OS << ", " ; |
504 | if (!Requirements[I].second) |
505 | OS << "!" ; |
506 | OS << Requirements[I].first; |
507 | } |
508 | OS << "\n" ; |
509 | } |
510 | |
511 | if (std::optional<Header> H = getUmbrellaHeaderAsWritten()) { |
512 | OS.indent(NumSpaces: Indent + 2); |
513 | OS << "umbrella header \"" ; |
514 | OS.write_escaped(Str: H->NameAsWritten); |
515 | OS << "\"\n" ; |
516 | } else if (std::optional<DirectoryName> D = getUmbrellaDirAsWritten()) { |
517 | OS.indent(NumSpaces: Indent + 2); |
518 | OS << "umbrella \"" ; |
519 | OS.write_escaped(Str: D->NameAsWritten); |
520 | OS << "\"\n" ; |
521 | } |
522 | |
523 | if (!ConfigMacros.empty() || ConfigMacrosExhaustive) { |
524 | OS.indent(NumSpaces: Indent + 2); |
525 | OS << "config_macros " ; |
526 | if (ConfigMacrosExhaustive) |
527 | OS << "[exhaustive]" ; |
528 | for (unsigned I = 0, N = ConfigMacros.size(); I != N; ++I) { |
529 | if (I) |
530 | OS << ", " ; |
531 | OS << ConfigMacros[I]; |
532 | } |
533 | OS << "\n" ; |
534 | } |
535 | |
536 | struct { |
537 | StringRef Prefix; |
538 | HeaderKind Kind; |
539 | } Kinds[] = {{.Prefix: "" , .Kind: HK_Normal}, |
540 | {.Prefix: "textual " , .Kind: HK_Textual}, |
541 | {.Prefix: "private " , .Kind: HK_Private}, |
542 | {.Prefix: "private textual " , .Kind: HK_PrivateTextual}, |
543 | {.Prefix: "exclude " , .Kind: HK_Excluded}}; |
544 | |
545 | for (auto &K : Kinds) { |
546 | assert(&K == &Kinds[K.Kind] && "kinds in wrong order" ); |
547 | for (auto &H : Headers[K.Kind]) { |
548 | OS.indent(NumSpaces: Indent + 2); |
549 | OS << K.Prefix << "header \"" ; |
550 | OS.write_escaped(Str: H.NameAsWritten); |
551 | OS << "\" { size " << H.Entry.getSize() |
552 | << " mtime " << H.Entry.getModificationTime() << " }\n" ; |
553 | } |
554 | } |
555 | for (auto *Unresolved : {&UnresolvedHeaders, &MissingHeaders}) { |
556 | for (auto &U : *Unresolved) { |
557 | OS.indent(NumSpaces: Indent + 2); |
558 | OS << Kinds[U.Kind].Prefix << "header \"" ; |
559 | OS.write_escaped(Str: U.FileName); |
560 | OS << "\"" ; |
561 | if (U.Size || U.ModTime) { |
562 | OS << " {" ; |
563 | if (U.Size) |
564 | OS << " size " << *U.Size; |
565 | if (U.ModTime) |
566 | OS << " mtime " << *U.ModTime; |
567 | OS << " }" ; |
568 | } |
569 | OS << "\n" ; |
570 | } |
571 | } |
572 | |
573 | if (!ExportAsModule.empty()) { |
574 | OS.indent(NumSpaces: Indent + 2); |
575 | OS << "export_as" << ExportAsModule << "\n" ; |
576 | } |
577 | |
578 | for (auto *Submodule : submodules()) |
579 | // Print inferred subframework modules so that we don't need to re-infer |
580 | // them (requires expensive directory iteration + stat calls) when we build |
581 | // the module. Regular inferred submodules are OK, as we need to look at all |
582 | // those header files anyway. |
583 | if (!Submodule->IsInferred || Submodule->IsFramework) |
584 | Submodule->print(OS, Indent: Indent + 2, Dump); |
585 | |
586 | for (unsigned I = 0, N = Exports.size(); I != N; ++I) { |
587 | OS.indent(NumSpaces: Indent + 2); |
588 | OS << "export " ; |
589 | if (Module *Restriction = Exports[I].getPointer()) { |
590 | OS << Restriction->getFullModuleName(AllowStringLiterals: true); |
591 | if (Exports[I].getInt()) |
592 | OS << ".*" ; |
593 | } else { |
594 | OS << "*" ; |
595 | } |
596 | OS << "\n" ; |
597 | } |
598 | |
599 | for (unsigned I = 0, N = UnresolvedExports.size(); I != N; ++I) { |
600 | OS.indent(NumSpaces: Indent + 2); |
601 | OS << "export " ; |
602 | printModuleId(OS, C: UnresolvedExports[I].Id); |
603 | if (UnresolvedExports[I].Wildcard) |
604 | OS << (UnresolvedExports[I].Id.empty() ? "*" : ".*" ); |
605 | OS << "\n" ; |
606 | } |
607 | |
608 | if (Dump) { |
609 | for (Module *M : Imports) { |
610 | OS.indent(NumSpaces: Indent + 2); |
611 | llvm::errs() << "import " << M->getFullModuleName() << "\n" ; |
612 | } |
613 | } |
614 | |
615 | for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) { |
616 | OS.indent(NumSpaces: Indent + 2); |
617 | OS << "use " ; |
618 | OS << DirectUses[I]->getFullModuleName(AllowStringLiterals: true); |
619 | OS << "\n" ; |
620 | } |
621 | |
622 | for (unsigned I = 0, N = UnresolvedDirectUses.size(); I != N; ++I) { |
623 | OS.indent(NumSpaces: Indent + 2); |
624 | OS << "use " ; |
625 | printModuleId(OS, C: UnresolvedDirectUses[I]); |
626 | OS << "\n" ; |
627 | } |
628 | |
629 | for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) { |
630 | OS.indent(NumSpaces: Indent + 2); |
631 | OS << "link " ; |
632 | if (LinkLibraries[I].IsFramework) |
633 | OS << "framework " ; |
634 | OS << "\"" ; |
635 | OS.write_escaped(Str: LinkLibraries[I].Library); |
636 | OS << "\"" ; |
637 | } |
638 | |
639 | for (unsigned I = 0, N = UnresolvedConflicts.size(); I != N; ++I) { |
640 | OS.indent(NumSpaces: Indent + 2); |
641 | OS << "conflict " ; |
642 | printModuleId(OS, C: UnresolvedConflicts[I].Id); |
643 | OS << ", \"" ; |
644 | OS.write_escaped(Str: UnresolvedConflicts[I].Message); |
645 | OS << "\"\n" ; |
646 | } |
647 | |
648 | for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) { |
649 | OS.indent(NumSpaces: Indent + 2); |
650 | OS << "conflict " ; |
651 | OS << Conflicts[I].Other->getFullModuleName(AllowStringLiterals: true); |
652 | OS << ", \"" ; |
653 | OS.write_escaped(Str: Conflicts[I].Message); |
654 | OS << "\"\n" ; |
655 | } |
656 | |
657 | if (InferSubmodules) { |
658 | OS.indent(NumSpaces: Indent + 2); |
659 | if (InferExplicitSubmodules) |
660 | OS << "explicit " ; |
661 | OS << "module * {\n" ; |
662 | if (InferExportWildcard) { |
663 | OS.indent(NumSpaces: Indent + 4); |
664 | OS << "export *\n" ; |
665 | } |
666 | OS.indent(NumSpaces: Indent + 2); |
667 | OS << "}\n" ; |
668 | } |
669 | |
670 | OS.indent(NumSpaces: Indent); |
671 | OS << "}\n" ; |
672 | } |
673 | |
674 | LLVM_DUMP_METHOD void Module::dump() const { |
675 | print(OS&: llvm::errs(), Indent: 0, Dump: true); |
676 | } |
677 | |
678 | void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc, |
679 | VisibleCallback Vis, ConflictCallback Cb) { |
680 | // We can't import a global module fragment so the location can be invalid. |
681 | assert((M->isGlobalModule() || Loc.isValid()) && |
682 | "setVisible expects a valid import location" ); |
683 | if (isVisible(M)) |
684 | return; |
685 | |
686 | ++Generation; |
687 | |
688 | struct Visiting { |
689 | Module *M; |
690 | Visiting *ExportedBy; |
691 | }; |
692 | |
693 | std::function<void(Visiting)> VisitModule = [&](Visiting V) { |
694 | // Nothing to do for a module that's already visible. |
695 | unsigned ID = V.M->getVisibilityID(); |
696 | if (ImportLocs.size() <= ID) |
697 | ImportLocs.resize(new_size: ID + 1); |
698 | else if (ImportLocs[ID].isValid()) |
699 | return; |
700 | |
701 | ImportLocs[ID] = Loc; |
702 | Vis(V.M); |
703 | |
704 | // Make any exported modules visible. |
705 | SmallVector<Module *, 16> Exports; |
706 | V.M->getExportedModules(Exported&: Exports); |
707 | for (Module *E : Exports) { |
708 | // Don't import non-importable modules. |
709 | if (!E->isUnimportable()) |
710 | VisitModule({.M: E, .ExportedBy: &V}); |
711 | } |
712 | |
713 | for (auto &C : V.M->Conflicts) { |
714 | if (isVisible(M: C.Other)) { |
715 | llvm::SmallVector<Module*, 8> Path; |
716 | for (Visiting *I = &V; I; I = I->ExportedBy) |
717 | Path.push_back(Elt: I->M); |
718 | Cb(Path, C.Other, C.Message); |
719 | } |
720 | } |
721 | }; |
722 | VisitModule({.M: M, .ExportedBy: nullptr}); |
723 | } |
724 | |
725 | void VisibleModuleSet::makeTransitiveImportsVisible(Module *M, |
726 | SourceLocation Loc, |
727 | VisibleCallback Vis, |
728 | ConflictCallback Cb) { |
729 | for (auto *I : M->Imports) |
730 | setVisible(M: I, Loc, Vis, Cb); |
731 | } |
732 | |
733 | ASTSourceDescriptor::ASTSourceDescriptor(Module &M) |
734 | : Signature(M.Signature), ClangModule(&M) { |
735 | if (M.Directory) |
736 | Path = M.Directory->getName(); |
737 | if (auto File = M.getASTFile()) |
738 | ASTFile = File->getName(); |
739 | } |
740 | |
741 | std::string ASTSourceDescriptor::getModuleName() const { |
742 | if (ClangModule) |
743 | return ClangModule->Name; |
744 | else |
745 | return std::string(PCHModuleName); |
746 | } |
747 | |