-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathFrontend.h
582 lines (467 loc) · 19.2 KB
/
Frontend.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
//===--- Frontend.h - frontend utility methods ------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file contains declarations of utility methods for parsing and
// performing semantic on modules.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_FRONTEND_H
#define SWIFT_FRONTEND_H
#include "swift/AST/DiagnosticConsumer.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/LinkLibrary.h"
#include "swift/AST/Module.h"
#include "swift/AST/SILOptions.h"
#include "swift/AST/SearchPathOptions.h"
#include "swift/Basic/DiagnosticOptions.h"
#include "swift/Basic/LangOptions.h"
#include "swift/Basic/SourceManager.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/ClangImporter/ClangImporterOptions.h"
#include "swift/Frontend/FrontendOptions.h"
#include "swift/Migrator/MigratorOptions.h"
#include "swift/Parse/CodeCompletionCallbacks.h"
#include "swift/Parse/Parser.h"
#include "swift/SIL/SILModule.h"
#include "swift/Sema/SourceLoader.h"
#include "swift/Serialization/Validation.h"
#include "swift/Subsystems.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include <memory>
namespace swift {
class SerializedModuleLoader;
/// The abstract configuration of the compiler, including:
/// - options for all stages of translation,
/// - information about the build environment,
/// - information about the job being performed, and
/// - lists of inputs.
///
/// A CompilerInvocation can be built from a frontend command line
/// using parseArgs. It can then be used to build a CompilerInstance,
/// which manages the actual compiler execution.
class CompilerInvocation {
LangOptions LangOpts;
FrontendOptions FrontendOpts;
ClangImporterOptions ClangImporterOpts;
SearchPathOptions SearchPathOpts;
DiagnosticOptions DiagnosticOpts;
MigratorOptions MigratorOpts;
SILOptions SILOpts;
IRGenOptions IRGenOpts;
llvm::MemoryBuffer *CodeCompletionBuffer = nullptr;
/// \brief Code completion offset in bytes from the beginning of the main
/// source file. Valid only if \c isCodeCompletion() == true.
unsigned CodeCompletionOffset = ~0U;
CodeCompletionCallbacksFactory *CodeCompletionFactory = nullptr;
public:
CompilerInvocation();
/// Initializes the compiler invocation for the list of arguments.
///
/// All parsing should be additive, i.e. options should not be reset to their
/// default values given the /absence/ of a flag. This is because \c parseArgs
/// may be used to modify an already partially configured invocation.
///
/// If non-empty, relative search paths are resolved relative to
/// \p workingDirectory.
///
/// \returns true if there was an error, false on success.
bool parseArgs(ArrayRef<const char *> Args, DiagnosticEngine &Diags,
StringRef workingDirectory = {});
/// Sets specific options based on the given serialized Swift binary data.
///
/// This is additive, i.e. options are not reset to their default values given
/// the /absence/ of a flag. However, flags that only have a single value may
/// (and should) be overwritten by this method.
///
/// Invoking this on more than one serialized AST is likely to result in
/// one or both of them failing to load. Please pick one AST to provide base
/// flags for the entire ASTContext and let the others succeed or fail the
/// normal way. (Some additive flags, like search paths, will be handled
/// properly during normal module loading.)
///
/// \returns Status::Valid on success, one of the Status issues on error.
serialization::Status loadFromSerializedAST(StringRef data);
/// Serialize the command line arguments for emitting them
/// to DWARF and inject SDKPath if necessary.
static void buildDWARFDebugFlags(std::string &Output,
const ArrayRef<const char*> &Args,
StringRef SDKPath,
StringRef ResourceDir);
void setTargetTriple(StringRef Triple);
StringRef getTargetTriple() const {
return LangOpts.Target.str();
}
void setClangModuleCachePath(StringRef Path) {
ClangImporterOpts.ModuleCachePath = Path.str();
}
StringRef getClangModuleCachePath() const {
return ClangImporterOpts.ModuleCachePath;
}
void setImportSearchPaths(const std::vector<std::string> &Paths) {
SearchPathOpts.ImportSearchPaths = Paths;
}
ArrayRef<std::string> getImportSearchPaths() const {
return SearchPathOpts.ImportSearchPaths;
}
void setFrameworkSearchPaths(
const std::vector<SearchPathOptions::FrameworkSearchPath> &Paths) {
SearchPathOpts.FrameworkSearchPaths = Paths;
}
ArrayRef<SearchPathOptions::FrameworkSearchPath> getFrameworkSearchPaths() const {
return SearchPathOpts.FrameworkSearchPaths;
}
void setExtraClangArgs(const std::vector<std::string> &Args) {
ClangImporterOpts.ExtraArgs = Args;
}
ArrayRef<std::string> getExtraClangArgs() const {
return ClangImporterOpts.ExtraArgs;
}
void addLinkLibrary(StringRef name, LibraryKind kind) {
IRGenOpts.LinkLibraries.push_back({name, kind});
}
ArrayRef<LinkLibrary> getLinkLibraries() const {
return IRGenOpts.LinkLibraries;
}
void setMainExecutablePath(StringRef Path);
void setRuntimeResourcePath(StringRef Path);
void setSDKPath(const std::string &Path) {
SearchPathOpts.SDKPath = Path;
}
StringRef getSDKPath() const {
return SearchPathOpts.SDKPath;
}
void setSerializedDiagnosticsPath(StringRef Path) {
FrontendOpts.SerializedDiagnosticsPath = Path;
}
StringRef getSerializedDiagnosticsPath() const {
return FrontendOpts.SerializedDiagnosticsPath;
}
LangOptions &getLangOptions() {
return LangOpts;
}
const LangOptions &getLangOptions() const {
return LangOpts;
}
FrontendOptions &getFrontendOptions() { return FrontendOpts; }
const FrontendOptions &getFrontendOptions() const { return FrontendOpts; }
ClangImporterOptions &getClangImporterOptions() { return ClangImporterOpts; }
const ClangImporterOptions &getClangImporterOptions() const {
return ClangImporterOpts;
}
SearchPathOptions &getSearchPathOptions() { return SearchPathOpts; }
const SearchPathOptions &getSearchPathOptions() const {
return SearchPathOpts;
}
DiagnosticOptions &getDiagnosticOptions() { return DiagnosticOpts; }
const DiagnosticOptions &getDiagnosticOptions() const {
return DiagnosticOpts;
}
const MigratorOptions &getMigratorOptions() const {
return MigratorOpts;
}
SILOptions &getSILOptions() { return SILOpts; }
const SILOptions &getSILOptions() const { return SILOpts; }
IRGenOptions &getIRGenOptions() { return IRGenOpts; }
const IRGenOptions &getIRGenOptions() const { return IRGenOpts; }
void setParseStdlib() {
FrontendOpts.ParseStdlib = true;
}
bool getParseStdlib() const {
return FrontendOpts.ParseStdlib;
}
void setInputKind(InputFileKind K) {
FrontendOpts.InputKind = K;
}
InputFileKind getInputKind() const {
return FrontendOpts.InputKind;
}
SourceFileKind getSourceFileKind() const;
void setModuleName(StringRef Name) {
FrontendOpts.ModuleName = Name.str();
IRGenOpts.ModuleName = Name.str();
}
StringRef getModuleName() const {
return FrontendOpts.ModuleName;
}
StringRef getOutputFilename() const {
return FrontendOpts.getSingleOutputFilename();
}
void setCodeCompletionPoint(llvm::MemoryBuffer *Buf, unsigned Offset) {
assert(Buf);
CodeCompletionBuffer = Buf;
CodeCompletionOffset = Offset;
// We don't need typo-correction for code-completion.
// FIXME: This isn't really true, but is a performance issue.
LangOpts.TypoCorrectionLimit = 0;
}
std::pair<llvm::MemoryBuffer *, unsigned> getCodeCompletionPoint() const {
return std::make_pair(CodeCompletionBuffer, CodeCompletionOffset);
}
/// \returns true if we are doing code completion.
bool isCodeCompletion() const {
return CodeCompletionOffset != ~0U;
}
void setCodeCompletionFactory(CodeCompletionCallbacksFactory *Factory) {
CodeCompletionFactory = Factory;
}
CodeCompletionCallbacksFactory *getCodeCompletionFactory() const {
return CodeCompletionFactory;
}
/// Retrieve a module hash string that is suitable for uniquely
/// identifying the conditions under which the module was built, for use
/// in generating a cached PCH file for the bridging header.
std::string getPCHHash() const;
SourceFile::ImplicitModuleImportKind getImplicitModuleImportKind() {
if (getInputKind() == InputFileKind::IFK_SIL) {
return SourceFile::ImplicitModuleImportKind::None;
}
if (getParseStdlib()) {
return SourceFile::ImplicitModuleImportKind::Builtin;
}
return SourceFile::ImplicitModuleImportKind::Stdlib;
}
/// Performs input setup common to these tools:
/// sil-opt, sil-func-extractor, sil-llvm-gen, and sil-nm.
/// Return value includes the buffer so caller can keep it alive.
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
setUpInputForSILTool(StringRef inputFilename, StringRef moduleNameArg,
bool alwaysSetModuleToMain, bool bePrimary,
serialization::ExtendedValidationInfo &extendedInfo);
bool hasSerializedAST() {
return FrontendOpts.InputKind == InputFileKind::IFK_Swift_Library;
}
};
/// A class which manages the state and execution of the compiler.
/// This owns the primary compiler singletons, such as the ASTContext,
/// as well as various build products such as the SILModule.
///
/// Before a CompilerInstance can be used, it must be configured by
/// calling \a setup. If successful, this will create an ASTContext
/// and set up the basic compiler invariants. Calling \a setup multiple
/// times on a single CompilerInstance is not permitted.
class CompilerInstance {
CompilerInvocation Invocation;
SourceManager SourceMgr;
DiagnosticEngine Diagnostics{SourceMgr};
std::unique_ptr<ASTContext> Context;
std::unique_ptr<SILModule> TheSILModule;
DependencyTracker *DepTracker = nullptr;
ReferencedNameTracker *NameTracker = nullptr;
ModuleDecl *MainModule = nullptr;
SerializedModuleLoader *SML = nullptr;
/// Contains buffer IDs for input source code files.
std::vector<unsigned> InputSourceCodeBufferIDs;
struct PartialModuleInputs {
std::unique_ptr<llvm::MemoryBuffer> ModuleBuffer;
std::unique_ptr<llvm::MemoryBuffer> ModuleDocBuffer;
};
/// Contains \c MemoryBuffers for partial serialized module files and
/// corresponding partial serialized module documentation files.
std::vector<PartialModuleInputs> PartialModules;
enum : unsigned { NO_SUCH_BUFFER = ~0U };
unsigned MainBufferID = NO_SUCH_BUFFER;
/// Identifies the set of input buffers in the SourceManager that are
/// considered primaries.
llvm::SetVector<unsigned> PrimaryBufferIDs;
/// Identifies the set of SourceFiles that are considered primaries. An
/// invariant is that any SourceFile in this set with an associated
/// buffer will also have its buffer ID in PrimaryBufferIDs.
std::vector<SourceFile *> PrimarySourceFiles;
/// Return whether there is an entry in PrimaryInputs for buffer \p BufID.
bool isPrimaryInput(unsigned BufID) const {
return PrimaryBufferIDs.count(BufID) != 0;
}
/// Record in PrimaryBufferIDs the fact that \p BufID is a primary.
/// If \p BufID is already in the set, do nothing.
void recordPrimaryInputBuffer(unsigned BufID);
/// Record in PrimarySourceFiles the fact that \p SF is a primary, and
/// call recordPrimaryInputBuffer on \p SF's buffer (if it exists).
void recordPrimarySourceFile(SourceFile *SF);
bool isWholeModuleCompilation() { return PrimaryBufferIDs.empty(); }
void createSILModule();
public:
SourceManager &getSourceMgr() { return SourceMgr; }
DiagnosticEngine &getDiags() { return Diagnostics; }
ASTContext &getASTContext() {
return *Context;
}
bool hasASTContext() const { return Context != nullptr; }
SILOptions &getSILOptions() { return Invocation.getSILOptions(); }
const SILOptions &getSILOptions() const { return Invocation.getSILOptions(); }
void addDiagnosticConsumer(DiagnosticConsumer *DC) {
Diagnostics.addConsumer(*DC);
}
void setDependencyTracker(DependencyTracker *DT) {
assert(!Context && "must be called before setup()");
DepTracker = DT;
}
DependencyTracker *getDependencyTracker() {
return DepTracker;
}
void setReferencedNameTracker(ReferencedNameTracker *tracker) {
assert(PrimarySourceFiles.empty() && "must be called before performSema()");
NameTracker = tracker;
}
ReferencedNameTracker *getReferencedNameTracker() {
return NameTracker;
}
/// Set the SIL module for this compilation instance.
///
/// The CompilerInstance takes ownership of the given SILModule object.
void setSILModule(std::unique_ptr<SILModule> M) {
TheSILModule = std::move(M);
}
SILModule *getSILModule() {
return TheSILModule.get();
}
std::unique_ptr<SILModule> takeSILModule() {
return std::move(TheSILModule);
}
bool hasSILModule() {
return static_cast<bool>(TheSILModule);
}
ModuleDecl *getMainModule();
SerializedModuleLoader *getSerializedModuleLoader() const { return SML; }
ArrayRef<unsigned> getInputBufferIDs() const {
return InputSourceCodeBufferIDs;
}
ArrayRef<LinkLibrary> getLinkLibraries() const {
return Invocation.getLinkLibraries();
}
bool hasSourceImport() const {
return Invocation.getFrontendOptions().EnableSourceImport;
}
/// Gets the set of SourceFiles which are the primary inputs for this
/// CompilerInstance.
ArrayRef<SourceFile *> getPrimarySourceFiles() {
return PrimarySourceFiles;
}
/// Gets the Primary Source File if one exists, otherwise the main
/// module. If multiple Primary Source Files exist, fails with an
/// assertion.
ModuleOrSourceFile getPrimarySourceFileOrMainModule() {
if (PrimarySourceFiles.empty())
return getMainModule();
else
return getPrimarySourceFile();
}
/// Gets the SourceFile which is the primary input for this CompilerInstance.
/// \returns the primary SourceFile, or nullptr if there is no primary input;
/// if there are _multiple_ primary inputs, fails with an assertion.
///
/// FIXME: This should be removed eventually, once there are no longer any
/// codepaths that rely on a single primary file.
SourceFile *getPrimarySourceFile() {
if (PrimarySourceFiles.empty()) {
return nullptr;
} else {
assert(PrimarySourceFiles.size() == 1);
return *PrimarySourceFiles.begin();
}
}
/// \brief Returns true if there was an error during setup.
bool setup(const CompilerInvocation &Invocation);
private:
void setUpLLVMArguments();
void setUpDiagnosticOptions();
bool setUpModuleLoaders();
bool isInputSwift() {
return Invocation.getInputKind() == InputFileKind::IFK_Swift;
}
bool isInSILMode() {
return Invocation.getInputKind() == InputFileKind::IFK_SIL;
}
bool setUpInputs();
Optional<unsigned> setUpCodeCompletionBuffer();
/// Set up all state in the CompilerInstance to process the given input file.
/// Return true on error.
bool setUpForInput(const InputFile &input);
/// Find a buffer for a given input file and ensure it is recorded in
/// SourceMgr, PartialModules, or InputSourceCodeBufferIDs as appropriate.
/// Return the buffer ID if it is not already compiled, or None if so.
/// Set failed on failure.
Optional<unsigned> getRecordedBufferID(const InputFile &input, bool &failed);
/// Given an input file, return a buffer to use for its contents,
/// and a buffer for the corresponding module doc file if one exists.
/// On failure, return a null pointer for the first element of the returned
/// pair.
std::pair<std::unique_ptr<llvm::MemoryBuffer>,
std::unique_ptr<llvm::MemoryBuffer>>
getInputBufferAndModuleDocBufferIfPresent(const InputFile &input);
/// Try to open the module doc file corresponding to the input parameter.
/// Return None for error, nullptr if no such file exists, or the buffer if
/// one was found.
Optional<std::unique_ptr<llvm::MemoryBuffer>>
openModuleDoc(const InputFile &input);
public:
/// Parses and type-checks all input files.
void performSema();
/// Parses the input file but does no type-checking or module imports.
/// Note that this only supports parsing an invocation with a single file.
///
///
void performParseOnly(bool EvaluateConditionals = false);
private:
SourceFile *
createSourceFileForMainModule(SourceFileKind FileKind,
SourceFile::ImplicitModuleImportKind ImportKind,
Optional<unsigned> BufferID);
public:
/// Frees up the ASTContext and SILModule objects that this instance is
/// holding on.
void freeContextAndSIL();
private:
/// Load stdlib & return true if should continue, i.e. no error
bool loadStdlib();
ModuleDecl *importUnderlyingModule();
ModuleDecl *importBridgingHeader();
void
getImplicitlyImportedModules(SmallVectorImpl<ModuleDecl *> &importModules);
public: // for static functions in Frontend.cpp
struct ImplicitImports {
SourceFile::ImplicitModuleImportKind kind;
ModuleDecl *objCModuleUnderlyingMixedFramework;
ModuleDecl *headerModule;
SmallVector<ModuleDecl *, 4> modules;
explicit ImplicitImports(CompilerInstance &compiler);
};
private:
void createREPLFile(const ImplicitImports &implicitImports);
std::unique_ptr<DelayedParsingCallbacks>
computeDelayedParsingCallback(bool isPrimary);
void addMainFileToModule(const ImplicitImports &implicitImports);
void parseAndCheckTypes(const ImplicitImports &implicitImports);
void parseLibraryFile(unsigned BufferID,
const ImplicitImports &implicitImports,
PersistentParserState &PersistentState,
DelayedParsingCallbacks *PrimaryDelayedCB,
DelayedParsingCallbacks *SecondaryDelayedCB);
/// Return true if had load error
bool
parsePartialModulesAndLibraryFiles(const ImplicitImports &implicitImports,
PersistentParserState &PersistentState,
DelayedParsingCallbacks *PrimaryDelayedCB,
DelayedParsingCallbacks *SecondaryDelayedCB);
OptionSet<TypeCheckingFlags> computeTypeCheckingOptions();
void forEachFileToTypeCheck(llvm::function_ref<void(SourceFile &)> fn);
void parseAndTypeCheckMainFile(PersistentParserState &PersistentState,
DelayedParsingCallbacks *DelayedParseCB,
OptionSet<TypeCheckingFlags> TypeCheckOptions);
void finishTypeChecking(OptionSet<TypeCheckingFlags> TypeCheckOptions);
};
} // namespace swift
#endif