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