Skip to content

Commit 68bda74

Browse files
author
David Ungar
committed
Split out ArgsToFrontendInputsConverter.
1 parent 361ff72 commit 68bda74

File tree

4 files changed

+228
-152
lines changed

4 files changed

+228
-152
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//===--- ArgsToFrontendInputsConverter.h ------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_FRONTEND_ARGSTOFRONTENDINPUTSCONVERTER_H
14+
#define SWIFT_FRONTEND_ARGSTOFRONTENDINPUTSCONVERTER_H
15+
16+
#include "swift/AST/DiagnosticConsumer.h"
17+
#include "swift/AST/DiagnosticEngine.h"
18+
#include "swift/Frontend/FrontendOptions.h"
19+
#include "llvm/Option/ArgList.h"
20+
21+
namespace swift {
22+
23+
/// Implement argument semantics in a way that will make it easier to have
24+
/// >1 primary file (or even a primary file list) in the future without
25+
/// breaking anything today.
26+
///
27+
/// Semantics today:
28+
/// If input files are on command line, primary files on command line are also
29+
/// input files; they are not repeated without -primary-file. If input files are
30+
/// in a file list, the primary files on the command line are repeated in the
31+
/// file list. Thus, if there are any primary files, it is illegal to have both
32+
/// (non-primary) input files and a file list. Finally, the order of input files
33+
/// must match the order given on the command line or the file list.
34+
///
35+
/// Side note:
36+
/// since each input file will cause a lot of work for the compiler, this code
37+
/// is biased towards clarity and not optimized.
38+
/// In the near future, it will be possible to put primary files in the
39+
/// filelist, or to have a separate filelist for primaries. The organization
40+
/// here anticipates that evolution.
41+
42+
class ArgsToFrontendInputsConverter {
43+
DiagnosticEngine &Diags;
44+
const llvm::opt::ArgList &Args;
45+
FrontendInputs &Inputs;
46+
47+
llvm::opt::Arg const *const FilelistPathArg;
48+
llvm::opt::Arg const *const PrimaryFilelistPathArg;
49+
50+
SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> BuffersToKeepAlive;
51+
52+
llvm::SetVector<StringRef> Files;
53+
54+
public:
55+
ArgsToFrontendInputsConverter(DiagnosticEngine &diags,
56+
const llvm::opt::ArgList &args,
57+
FrontendInputs &inputs);
58+
59+
bool convert();
60+
61+
private:
62+
bool enforceFilelistExclusion();
63+
bool readInputFilesFromCommandLine();
64+
bool readInputFilesFromFilelist();
65+
bool forAllFilesInFilelist(llvm::opt::Arg const *const pathArg,
66+
llvm::function_ref<void(StringRef)> fn);
67+
bool addFile(StringRef file);
68+
Optional<std::set<StringRef>> readPrimaryFiles();
69+
std::set<StringRef>
70+
createInputFilesConsumingPrimaries(std::set<StringRef> primaryFiles);
71+
bool checkForMissingPrimaryFiles(std::set<StringRef> primaryFiles);
72+
};
73+
74+
} // namespace swift
75+
76+
#endif /* SWIFT_FRONTEND_ARGSTOFRONTENDINPUTSCONVERTER_H */
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//===--- ArgsToFrontendInputsConverter.cpp ----------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/Frontend/ArgsToFrontendInputsConverter.h"
14+
15+
#include "swift/AST/DiagnosticsFrontend.h"
16+
#include "swift/Frontend/FrontendOptions.h"
17+
#include "swift/Option/Options.h"
18+
#include "swift/Parse/Lexer.h"
19+
#include "swift/Strings.h"
20+
#include "llvm/Option/Arg.h"
21+
#include "llvm/Option/ArgList.h"
22+
#include "llvm/Option/Option.h"
23+
#include "llvm/Support/ErrorHandling.h"
24+
#include "llvm/Support/FileSystem.h"
25+
#include "llvm/Support/LineIterator.h"
26+
#include "llvm/Support/Path.h"
27+
28+
using namespace swift;
29+
using namespace llvm::opt;
30+
31+
ArgsToFrontendInputsConverter::ArgsToFrontendInputsConverter(
32+
DiagnosticEngine &diags, const ArgList &args, FrontendInputs &inputs)
33+
: Diags(diags), Args(args), Inputs(inputs),
34+
FilelistPathArg(args.getLastArg(options::OPT_filelist)),
35+
PrimaryFilelistPathArg(args.getLastArg(options::OPT_primary_filelist)) {}
36+
37+
bool ArgsToFrontendInputsConverter::convert() {
38+
if (enforceFilelistExclusion())
39+
return true;
40+
if (FilelistPathArg ? readInputFilesFromFilelist()
41+
: readInputFilesFromCommandLine())
42+
return true;
43+
Optional<std::set<StringRef>> primaryFiles = readPrimaryFiles();
44+
if (!primaryFiles)
45+
return true;
46+
std::set<StringRef> unusedPrimaryFiles =
47+
createInputFilesConsumingPrimaries(*primaryFiles);
48+
return checkForMissingPrimaryFiles(unusedPrimaryFiles);
49+
}
50+
51+
bool ArgsToFrontendInputsConverter::enforceFilelistExclusion() {
52+
if (Args.hasArg(options::OPT_INPUT) && FilelistPathArg) {
53+
Diags.diagnose(SourceLoc(),
54+
diag::error_cannot_have_input_files_with_file_list);
55+
return true;
56+
}
57+
// The following is not strictly necessary, but the restriction makes
58+
// it easier to understand a given command line:
59+
if (Args.hasArg(options::OPT_primary_file) && PrimaryFilelistPathArg) {
60+
Diags.diagnose(
61+
SourceLoc(),
62+
diag::error_cannot_have_primary_files_with_primary_file_list);
63+
return true;
64+
}
65+
return false;
66+
}
67+
68+
bool ArgsToFrontendInputsConverter::readInputFilesFromCommandLine() {
69+
bool hadDuplicates = false;
70+
for (const Arg *A :
71+
Args.filtered(options::OPT_INPUT, options::OPT_primary_file)) {
72+
hadDuplicates = addFile(A->getValue()) || hadDuplicates;
73+
}
74+
return false; // FIXME: Don't bail out for duplicates, too many tests depend
75+
// on it.
76+
}
77+
78+
bool ArgsToFrontendInputsConverter::readInputFilesFromFilelist() {
79+
bool hadDuplicates = false;
80+
bool hadError =
81+
forAllFilesInFilelist(FilelistPathArg, [&](StringRef file) -> void {
82+
hadDuplicates = addFile(file) || hadDuplicates;
83+
});
84+
if (hadError)
85+
return true;
86+
return false; // FIXME: Don't bail out for duplicates, too many tests depend
87+
// on it.
88+
}
89+
90+
bool ArgsToFrontendInputsConverter::forAllFilesInFilelist(
91+
Arg const *const pathArg, llvm::function_ref<void(StringRef)> fn) {
92+
if (!pathArg)
93+
return false;
94+
StringRef path = pathArg->getValue();
95+
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> filelistBufferOrError =
96+
llvm::MemoryBuffer::getFile(path);
97+
if (!filelistBufferOrError) {
98+
Diags.diagnose(SourceLoc(), diag::cannot_open_file, path,
99+
filelistBufferOrError.getError().message());
100+
return true;
101+
}
102+
for (auto file :
103+
llvm::make_range(llvm::line_iterator(*filelistBufferOrError->get()),
104+
llvm::line_iterator()))
105+
fn(file);
106+
BuffersToKeepAlive.push_back(std::move(*filelistBufferOrError));
107+
return false;
108+
}
109+
110+
bool ArgsToFrontendInputsConverter::addFile(StringRef file) {
111+
if (Files.insert(file))
112+
return false;
113+
Diags.diagnose(SourceLoc(), diag::error_duplicate_input_file, file);
114+
return true;
115+
}
116+
117+
Optional<std::set<StringRef>>
118+
ArgsToFrontendInputsConverter::readPrimaryFiles() {
119+
std::set<StringRef> primaryFiles;
120+
for (const Arg *A : Args.filtered(options::OPT_primary_file))
121+
primaryFiles.insert(A->getValue());
122+
if (forAllFilesInFilelist(
123+
PrimaryFilelistPathArg,
124+
[&](StringRef file) -> void { primaryFiles.insert(file); }))
125+
return None;
126+
return primaryFiles;
127+
}
128+
129+
std::set<StringRef>
130+
ArgsToFrontendInputsConverter::createInputFilesConsumingPrimaries(
131+
std::set<StringRef> primaryFiles) {
132+
for (auto &file : Files) {
133+
bool isPrimary = primaryFiles.count(file) > 0;
134+
Inputs.addInput(InputFile(file, isPrimary));
135+
if (isPrimary)
136+
primaryFiles.erase(file);
137+
}
138+
return primaryFiles;
139+
}
140+
141+
bool ArgsToFrontendInputsConverter::checkForMissingPrimaryFiles(
142+
std::set<StringRef> primaryFiles) {
143+
for (auto &file : primaryFiles) {
144+
// Catch "swiftc -frontend -c -filelist foo -primary-file
145+
// some-file-not-in-foo".
146+
assert(FilelistPathArg && "Missing primary with no filelist");
147+
Diags.diagnose(SourceLoc(), diag::error_primary_file_not_found, file,
148+
FilelistPathArg->getValue());
149+
}
150+
return !primaryFiles.empty();
151+
}

lib/Frontend/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_swift_library(swiftFrontend STATIC
2+
ArgsToFrontendInputsConverter.cpp
23
CompilerInvocation.cpp
34
DiagnosticVerifier.cpp
45
Frontend.cpp

lib/Frontend/CompilerInvocation.cpp

Lines changed: 0 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -94,158 +94,6 @@ static void debugFailWithCrash() { LLVM_BUILTIN_TRAP; }
9494

9595
namespace swift {
9696

97-
/// Implement argument semantics in a way that will make it easier to have
98-
/// >1 primary file (or even a primary file list) in the future without
99-
/// breaking anything today.
100-
///
101-
/// Semantics today:
102-
/// If input files are on command line, primary files on command line are also
103-
/// input files; they are not repeated without -primary-file. If input files are
104-
/// in a file list, the primary files on the command line are repeated in the
105-
/// file list. Thus, if there are any primary files, it is illegal to have both
106-
/// (non-primary) input files and a file list. Finally, the order of input files
107-
/// must match the order given on the command line or the file list.
108-
///
109-
/// Side note:
110-
/// since each input file will cause a lot of work for the compiler, this code
111-
/// is biased towards clarity and not optimized.
112-
/// In the near future, it will be possible to put primary files in the
113-
/// filelist, or to have a separate filelist for primaries. The organization
114-
/// here anticipates that evolution.
115-
116-
class ArgsToFrontendInputsConverter {
117-
DiagnosticEngine &Diags;
118-
const ArgList &Args;
119-
FrontendInputs &Inputs;
120-
121-
Arg const *const FilelistPathArg;
122-
Arg const *const PrimaryFilelistPathArg;
123-
124-
SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> BuffersToKeepAlive;
125-
126-
llvm::SetVector<StringRef> Files;
127-
128-
public:
129-
ArgsToFrontendInputsConverter(DiagnosticEngine &Diags, const ArgList &Args,
130-
FrontendInputs &Inputs)
131-
: Diags(Diags), Args(Args), Inputs(Inputs),
132-
FilelistPathArg(Args.getLastArg(options::OPT_filelist)),
133-
PrimaryFilelistPathArg(Args.getLastArg(options::OPT_primary_filelist)) {
134-
}
135-
136-
bool convert() {
137-
if (enforceFilelistExclusion())
138-
return true;
139-
if (FilelistPathArg ? readInputFilesFromFilelist()
140-
: readInputFilesFromCommandLine())
141-
return true;
142-
Optional<std::set<StringRef>> primaryFiles = readPrimaryFiles();
143-
if (!primaryFiles)
144-
return true;
145-
std::set<StringRef> unusedPrimaryFiles =
146-
createInputFilesConsumingPrimaries(*primaryFiles);
147-
return checkForMissingPrimaryFiles(unusedPrimaryFiles);
148-
}
149-
150-
private:
151-
bool enforceFilelistExclusion() {
152-
if (Args.hasArg(options::OPT_INPUT) && FilelistPathArg) {
153-
Diags.diagnose(SourceLoc(),
154-
diag::error_cannot_have_input_files_with_file_list);
155-
return true;
156-
}
157-
// The following is not strictly necessary, but the restriction makes
158-
// it easier to understand a given command line:
159-
if (Args.hasArg(options::OPT_primary_file) && PrimaryFilelistPathArg) {
160-
Diags.diagnose(
161-
SourceLoc(),
162-
diag::error_cannot_have_primary_files_with_primary_file_list);
163-
return true;
164-
}
165-
return false;
166-
}
167-
168-
bool readInputFilesFromCommandLine() {
169-
bool hadDuplicates = false;
170-
for (const Arg *A :
171-
Args.filtered(options::OPT_INPUT, options::OPT_primary_file)) {
172-
hadDuplicates = addFile(A->getValue()) || hadDuplicates;
173-
}
174-
return false; // FIXME: Don't bail out for duplicates, too many tests depend
175-
// on it.
176-
}
177-
178-
bool readInputFilesFromFilelist() {
179-
bool hadDuplicates = false;
180-
bool hadError =
181-
forAllFilesInFilelist(FilelistPathArg, [&](StringRef file) -> void {
182-
hadDuplicates = addFile(file) || hadDuplicates;
183-
});
184-
if (hadError)
185-
return true;
186-
return false; // FIXME: Don't bail out for duplicates, too many tests depend on it.
187-
}
188-
189-
bool forAllFilesInFilelist(Arg const *const pathArg,
190-
llvm::function_ref<void(StringRef)> fn) {
191-
if (!pathArg)
192-
return false;
193-
StringRef path = pathArg->getValue();
194-
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> filelistBufferOrError =
195-
llvm::MemoryBuffer::getFile(path);
196-
if (!filelistBufferOrError) {
197-
Diags.diagnose(SourceLoc(), diag::cannot_open_file, path,
198-
filelistBufferOrError.getError().message());
199-
return true;
200-
}
201-
for (auto file :
202-
llvm::make_range(llvm::line_iterator(*filelistBufferOrError->get()),
203-
llvm::line_iterator()))
204-
fn(file);
205-
BuffersToKeepAlive.push_back(std::move(*filelistBufferOrError));
206-
return false;
207-
}
208-
209-
bool addFile(StringRef file) {
210-
if (Files.insert(file))
211-
return false;
212-
Diags.diagnose(SourceLoc(), diag::error_duplicate_input_file, file);
213-
return true;
214-
}
215-
216-
Optional<std::set<StringRef>> readPrimaryFiles() {
217-
std::set<StringRef> primaryFiles;
218-
for (const Arg *A : Args.filtered(options::OPT_primary_file))
219-
primaryFiles.insert(A->getValue());
220-
if (forAllFilesInFilelist(
221-
PrimaryFilelistPathArg,
222-
[&](StringRef file) -> void { primaryFiles.insert(file); }))
223-
return None;
224-
return primaryFiles;
225-
}
226-
227-
std::set<StringRef>
228-
createInputFilesConsumingPrimaries(std::set<StringRef> primaryFiles) {
229-
for (auto &file : Files) {
230-
bool isPrimary = primaryFiles.count(file) > 0;
231-
Inputs.addInput(InputFile(file, isPrimary));
232-
if (isPrimary)
233-
primaryFiles.erase(file);
234-
}
235-
return primaryFiles;
236-
}
237-
238-
bool checkForMissingPrimaryFiles(std::set<StringRef> primaryFiles) {
239-
for (auto &file : primaryFiles) {
240-
// Catch "swiftc -frontend -c -filelist foo -primary-file
241-
// some-file-not-in-foo".
242-
assert(FilelistPathArg && "Missing primary with no filelist");
243-
Diags.diagnose(SourceLoc(), diag::error_primary_file_not_found, file,
244-
FilelistPathArg->getValue());
245-
}
246-
return !primaryFiles.empty();
247-
}
248-
};
24997
class FrontendArgsToOptionsConverter {
25098
private:
25199
DiagnosticEngine &Diags;

0 commit comments

Comments
 (0)