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].FeatureName, LangOpts, Target) != |
144 | Current->Requirements[I].RequiredState) { |
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 stddef.h and its accompanying modules. |
305 | if (Requested->fullModuleNameIs(nameParts: {"_Builtin_stddef" , "max_align_t" }) || |
306 | Requested->fullModuleNameIs(nameParts: {"_Builtin_stddef_wint_t" })) |
307 | return true; |
308 | // Darwin is allowed is to use our builtin 'ptrauth.h' and its accompanying |
309 | // module. |
310 | if (!Requested->Parent && Requested->Name == "ptrauth" ) |
311 | return true; |
312 | |
313 | if (NoUndeclaredIncludes) |
314 | UndeclaredUses.insert(X: Requested); |
315 | |
316 | return false; |
317 | } |
318 | |
319 | void Module::addRequirement(StringRef Feature, bool RequiredState, |
320 | const LangOptions &LangOpts, |
321 | const TargetInfo &Target) { |
322 | Requirements.push_back(Elt: Requirement{.FeatureName: std::string(Feature), .RequiredState: RequiredState}); |
323 | |
324 | // If this feature is currently available, we're done. |
325 | if (hasFeature(Feature, LangOpts, Target) == RequiredState) |
326 | return; |
327 | |
328 | markUnavailable(/*Unimportable*/true); |
329 | } |
330 | |
331 | void Module::markUnavailable(bool Unimportable) { |
332 | auto needUpdate = [Unimportable](Module *M) { |
333 | return M->IsAvailable || (!M->IsUnimportable && Unimportable); |
334 | }; |
335 | |
336 | if (!needUpdate(this)) |
337 | return; |
338 | |
339 | SmallVector<Module *, 2> Stack; |
340 | Stack.push_back(Elt: this); |
341 | while (!Stack.empty()) { |
342 | Module *Current = Stack.back(); |
343 | Stack.pop_back(); |
344 | |
345 | if (!needUpdate(Current)) |
346 | continue; |
347 | |
348 | Current->IsAvailable = false; |
349 | Current->IsUnimportable |= Unimportable; |
350 | for (auto *Submodule : Current->submodules()) { |
351 | if (needUpdate(Submodule)) |
352 | Stack.push_back(Elt: Submodule); |
353 | } |
354 | } |
355 | } |
356 | |
357 | Module *Module::findSubmodule(StringRef Name) const { |
358 | llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Key: Name); |
359 | if (Pos == SubModuleIndex.end()) |
360 | return nullptr; |
361 | |
362 | return SubModules[Pos->getValue()]; |
363 | } |
364 | |
365 | Module *Module::findOrInferSubmodule(StringRef Name) { |
366 | llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Key: Name); |
367 | if (Pos != SubModuleIndex.end()) |
368 | return SubModules[Pos->getValue()]; |
369 | if (!InferSubmodules) |
370 | return nullptr; |
371 | Module *Result = new Module(Name, SourceLocation(), this, false, InferExplicitSubmodules, 0); |
372 | Result->InferExplicitSubmodules = InferExplicitSubmodules; |
373 | Result->InferSubmodules = InferSubmodules; |
374 | Result->InferExportWildcard = InferExportWildcard; |
375 | if (Result->InferExportWildcard) |
376 | Result->Exports.push_back(Elt: Module::ExportDecl(nullptr, true)); |
377 | return Result; |
378 | } |
379 | |
380 | Module *Module::getGlobalModuleFragment() const { |
381 | assert(isNamedModuleUnit() && "We should only query the global module " |
382 | "fragment from the C++20 Named modules" ); |
383 | |
384 | for (auto *SubModule : SubModules) |
385 | if (SubModule->isExplicitGlobalModule()) |
386 | return SubModule; |
387 | |
388 | return nullptr; |
389 | } |
390 | |
391 | Module *Module::getPrivateModuleFragment() const { |
392 | assert(isNamedModuleUnit() && "We should only query the private module " |
393 | "fragment from the C++20 Named modules" ); |
394 | |
395 | for (auto *SubModule : SubModules) |
396 | if (SubModule->isPrivateModule()) |
397 | return SubModule; |
398 | |
399 | return nullptr; |
400 | } |
401 | |
402 | void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const { |
403 | // All non-explicit submodules are exported. |
404 | for (std::vector<Module *>::const_iterator I = SubModules.begin(), |
405 | E = SubModules.end(); |
406 | I != E; ++I) { |
407 | Module *Mod = *I; |
408 | if (!Mod->IsExplicit) |
409 | Exported.push_back(Elt: Mod); |
410 | } |
411 | |
412 | // Find re-exported modules by filtering the list of imported modules. |
413 | bool AnyWildcard = false; |
414 | bool UnrestrictedWildcard = false; |
415 | SmallVector<Module *, 4> WildcardRestrictions; |
416 | for (unsigned I = 0, N = Exports.size(); I != N; ++I) { |
417 | Module *Mod = Exports[I].getPointer(); |
418 | if (!Exports[I].getInt()) { |
419 | // Export a named module directly; no wildcards involved. |
420 | Exported.push_back(Elt: Mod); |
421 | |
422 | continue; |
423 | } |
424 | |
425 | // Wildcard export: export all of the imported modules that match |
426 | // the given pattern. |
427 | AnyWildcard = true; |
428 | if (UnrestrictedWildcard) |
429 | continue; |
430 | |
431 | if (Module *Restriction = Exports[I].getPointer()) |
432 | WildcardRestrictions.push_back(Elt: Restriction); |
433 | else { |
434 | WildcardRestrictions.clear(); |
435 | UnrestrictedWildcard = true; |
436 | } |
437 | } |
438 | |
439 | // If there were any wildcards, push any imported modules that were |
440 | // re-exported by the wildcard restriction. |
441 | if (!AnyWildcard) |
442 | return; |
443 | |
444 | for (unsigned I = 0, N = Imports.size(); I != N; ++I) { |
445 | Module *Mod = Imports[I]; |
446 | bool Acceptable = UnrestrictedWildcard; |
447 | if (!Acceptable) { |
448 | // Check whether this module meets one of the restrictions. |
449 | for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) { |
450 | Module *Restriction = WildcardRestrictions[R]; |
451 | if (Mod == Restriction || Mod->isSubModuleOf(Other: Restriction)) { |
452 | Acceptable = true; |
453 | break; |
454 | } |
455 | } |
456 | } |
457 | |
458 | if (!Acceptable) |
459 | continue; |
460 | |
461 | Exported.push_back(Elt: Mod); |
462 | } |
463 | } |
464 | |
465 | void Module::buildVisibleModulesCache() const { |
466 | assert(VisibleModulesCache.empty() && "cache does not need building" ); |
467 | |
468 | // This module is visible to itself. |
469 | VisibleModulesCache.insert(V: this); |
470 | |
471 | // Every imported module is visible. |
472 | SmallVector<Module *, 16> Stack(Imports.begin(), Imports.end()); |
473 | while (!Stack.empty()) { |
474 | Module *CurrModule = Stack.pop_back_val(); |
475 | |
476 | // Every module transitively exported by an imported module is visible. |
477 | if (VisibleModulesCache.insert(V: CurrModule).second) |
478 | CurrModule->getExportedModules(Exported&: Stack); |
479 | } |
480 | } |
481 | |
482 | void Module::print(raw_ostream &OS, unsigned Indent, bool Dump) const { |
483 | OS.indent(NumSpaces: Indent); |
484 | if (IsFramework) |
485 | OS << "framework " ; |
486 | if (IsExplicit) |
487 | OS << "explicit " ; |
488 | OS << "module " ; |
489 | printModuleId(OS, Begin: &Name, End: &Name + 1); |
490 | |
491 | if (IsSystem || IsExternC) { |
492 | OS.indent(NumSpaces: Indent + 2); |
493 | if (IsSystem) |
494 | OS << " [system]" ; |
495 | if (IsExternC) |
496 | OS << " [extern_c]" ; |
497 | } |
498 | |
499 | OS << " {\n" ; |
500 | |
501 | if (!Requirements.empty()) { |
502 | OS.indent(NumSpaces: Indent + 2); |
503 | OS << "requires " ; |
504 | for (unsigned I = 0, N = Requirements.size(); I != N; ++I) { |
505 | if (I) |
506 | OS << ", " ; |
507 | if (!Requirements[I].RequiredState) |
508 | OS << "!" ; |
509 | OS << Requirements[I].FeatureName; |
510 | } |
511 | OS << "\n" ; |
512 | } |
513 | |
514 | if (std::optional<Header> H = getUmbrellaHeaderAsWritten()) { |
515 | OS.indent(NumSpaces: Indent + 2); |
516 | OS << "umbrella header \"" ; |
517 | OS.write_escaped(Str: H->NameAsWritten); |
518 | OS << "\"\n" ; |
519 | } else if (std::optional<DirectoryName> D = getUmbrellaDirAsWritten()) { |
520 | OS.indent(NumSpaces: Indent + 2); |
521 | OS << "umbrella \"" ; |
522 | OS.write_escaped(Str: D->NameAsWritten); |
523 | OS << "\"\n" ; |
524 | } |
525 | |
526 | if (!ConfigMacros.empty() || ConfigMacrosExhaustive) { |
527 | OS.indent(NumSpaces: Indent + 2); |
528 | OS << "config_macros " ; |
529 | if (ConfigMacrosExhaustive) |
530 | OS << "[exhaustive]" ; |
531 | for (unsigned I = 0, N = ConfigMacros.size(); I != N; ++I) { |
532 | if (I) |
533 | OS << ", " ; |
534 | OS << ConfigMacros[I]; |
535 | } |
536 | OS << "\n" ; |
537 | } |
538 | |
539 | struct { |
540 | StringRef Prefix; |
541 | HeaderKind Kind; |
542 | } Kinds[] = {{.Prefix: "" , .Kind: HK_Normal}, |
543 | {.Prefix: "textual " , .Kind: HK_Textual}, |
544 | {.Prefix: "private " , .Kind: HK_Private}, |
545 | {.Prefix: "private textual " , .Kind: HK_PrivateTextual}, |
546 | {.Prefix: "exclude " , .Kind: HK_Excluded}}; |
547 | |
548 | for (auto &K : Kinds) { |
549 | assert(&K == &Kinds[K.Kind] && "kinds in wrong order" ); |
550 | for (auto &H : Headers[K.Kind]) { |
551 | OS.indent(NumSpaces: Indent + 2); |
552 | OS << K.Prefix << "header \"" ; |
553 | OS.write_escaped(Str: H.NameAsWritten); |
554 | OS << "\" { size " << H.Entry.getSize() |
555 | << " mtime " << H.Entry.getModificationTime() << " }\n" ; |
556 | } |
557 | } |
558 | for (auto *Unresolved : {&UnresolvedHeaders, &MissingHeaders}) { |
559 | for (auto &U : *Unresolved) { |
560 | OS.indent(NumSpaces: Indent + 2); |
561 | OS << Kinds[U.Kind].Prefix << "header \"" ; |
562 | OS.write_escaped(Str: U.FileName); |
563 | OS << "\"" ; |
564 | if (U.Size || U.ModTime) { |
565 | OS << " {" ; |
566 | if (U.Size) |
567 | OS << " size " << *U.Size; |
568 | if (U.ModTime) |
569 | OS << " mtime " << *U.ModTime; |
570 | OS << " }" ; |
571 | } |
572 | OS << "\n" ; |
573 | } |
574 | } |
575 | |
576 | if (!ExportAsModule.empty()) { |
577 | OS.indent(NumSpaces: Indent + 2); |
578 | OS << "export_as" << ExportAsModule << "\n" ; |
579 | } |
580 | |
581 | for (auto *Submodule : submodules()) |
582 | // Print inferred subframework modules so that we don't need to re-infer |
583 | // them (requires expensive directory iteration + stat calls) when we build |
584 | // the module. Regular inferred submodules are OK, as we need to look at all |
585 | // those header files anyway. |
586 | if (!Submodule->IsInferred || Submodule->IsFramework) |
587 | Submodule->print(OS, Indent: Indent + 2, Dump); |
588 | |
589 | for (unsigned I = 0, N = Exports.size(); I != N; ++I) { |
590 | OS.indent(NumSpaces: Indent + 2); |
591 | OS << "export " ; |
592 | if (Module *Restriction = Exports[I].getPointer()) { |
593 | OS << Restriction->getFullModuleName(AllowStringLiterals: true); |
594 | if (Exports[I].getInt()) |
595 | OS << ".*" ; |
596 | } else { |
597 | OS << "*" ; |
598 | } |
599 | OS << "\n" ; |
600 | } |
601 | |
602 | for (unsigned I = 0, N = UnresolvedExports.size(); I != N; ++I) { |
603 | OS.indent(NumSpaces: Indent + 2); |
604 | OS << "export " ; |
605 | printModuleId(OS, C: UnresolvedExports[I].Id); |
606 | if (UnresolvedExports[I].Wildcard) |
607 | OS << (UnresolvedExports[I].Id.empty() ? "*" : ".*" ); |
608 | OS << "\n" ; |
609 | } |
610 | |
611 | if (Dump) { |
612 | for (Module *M : Imports) { |
613 | OS.indent(NumSpaces: Indent + 2); |
614 | llvm::errs() << "import " << M->getFullModuleName() << "\n" ; |
615 | } |
616 | } |
617 | |
618 | for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) { |
619 | OS.indent(NumSpaces: Indent + 2); |
620 | OS << "use " ; |
621 | OS << DirectUses[I]->getFullModuleName(AllowStringLiterals: true); |
622 | OS << "\n" ; |
623 | } |
624 | |
625 | for (unsigned I = 0, N = UnresolvedDirectUses.size(); I != N; ++I) { |
626 | OS.indent(NumSpaces: Indent + 2); |
627 | OS << "use " ; |
628 | printModuleId(OS, C: UnresolvedDirectUses[I]); |
629 | OS << "\n" ; |
630 | } |
631 | |
632 | for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) { |
633 | OS.indent(NumSpaces: Indent + 2); |
634 | OS << "link " ; |
635 | if (LinkLibraries[I].IsFramework) |
636 | OS << "framework " ; |
637 | OS << "\"" ; |
638 | OS.write_escaped(Str: LinkLibraries[I].Library); |
639 | OS << "\"" ; |
640 | } |
641 | |
642 | for (unsigned I = 0, N = UnresolvedConflicts.size(); I != N; ++I) { |
643 | OS.indent(NumSpaces: Indent + 2); |
644 | OS << "conflict " ; |
645 | printModuleId(OS, C: UnresolvedConflicts[I].Id); |
646 | OS << ", \"" ; |
647 | OS.write_escaped(Str: UnresolvedConflicts[I].Message); |
648 | OS << "\"\n" ; |
649 | } |
650 | |
651 | for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) { |
652 | OS.indent(NumSpaces: Indent + 2); |
653 | OS << "conflict " ; |
654 | OS << Conflicts[I].Other->getFullModuleName(AllowStringLiterals: true); |
655 | OS << ", \"" ; |
656 | OS.write_escaped(Str: Conflicts[I].Message); |
657 | OS << "\"\n" ; |
658 | } |
659 | |
660 | if (InferSubmodules) { |
661 | OS.indent(NumSpaces: Indent + 2); |
662 | if (InferExplicitSubmodules) |
663 | OS << "explicit " ; |
664 | OS << "module * {\n" ; |
665 | if (InferExportWildcard) { |
666 | OS.indent(NumSpaces: Indent + 4); |
667 | OS << "export *\n" ; |
668 | } |
669 | OS.indent(NumSpaces: Indent + 2); |
670 | OS << "}\n" ; |
671 | } |
672 | |
673 | OS.indent(NumSpaces: Indent); |
674 | OS << "}\n" ; |
675 | } |
676 | |
677 | LLVM_DUMP_METHOD void Module::dump() const { |
678 | print(OS&: llvm::errs(), Indent: 0, Dump: true); |
679 | } |
680 | |
681 | void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc, |
682 | VisibleCallback Vis, ConflictCallback Cb) { |
683 | // We can't import a global module fragment so the location can be invalid. |
684 | assert((M->isGlobalModule() || Loc.isValid()) && |
685 | "setVisible expects a valid import location" ); |
686 | if (isVisible(M)) |
687 | return; |
688 | |
689 | ++Generation; |
690 | |
691 | struct Visiting { |
692 | Module *M; |
693 | Visiting *ExportedBy; |
694 | }; |
695 | |
696 | std::function<void(Visiting)> VisitModule = [&](Visiting V) { |
697 | // Nothing to do for a module that's already visible. |
698 | unsigned ID = V.M->getVisibilityID(); |
699 | if (ImportLocs.size() <= ID) |
700 | ImportLocs.resize(new_size: ID + 1); |
701 | else if (ImportLocs[ID].isValid()) |
702 | return; |
703 | |
704 | ImportLocs[ID] = Loc; |
705 | Vis(V.M); |
706 | |
707 | // Make any exported modules visible. |
708 | SmallVector<Module *, 16> Exports; |
709 | V.M->getExportedModules(Exported&: Exports); |
710 | for (Module *E : Exports) { |
711 | // Don't import non-importable modules. |
712 | if (!E->isUnimportable()) |
713 | VisitModule({.M: E, .ExportedBy: &V}); |
714 | } |
715 | |
716 | for (auto &C : V.M->Conflicts) { |
717 | if (isVisible(M: C.Other)) { |
718 | llvm::SmallVector<Module*, 8> Path; |
719 | for (Visiting *I = &V; I; I = I->ExportedBy) |
720 | Path.push_back(Elt: I->M); |
721 | Cb(Path, C.Other, C.Message); |
722 | } |
723 | } |
724 | }; |
725 | VisitModule({.M: M, .ExportedBy: nullptr}); |
726 | } |
727 | |