Skip to content

Commit 81eac3b

Browse files
author
David Ungar
committed
Separate out ArgsToFrontendInputsConverter
1 parent 04b92c0 commit 81eac3b

File tree

5 files changed

+233
-154
lines changed

5 files changed

+233
-154
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//===--- ArgsToFrontendInputsConverter.h ----------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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 ArgsToFrontendInputsConverter_h
14+
#define 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+
using namespace swift;
22+
using namespace llvm::opt;
23+
24+
namespace swift {
25+
26+
/// Implement argument semantics in a way that will make it easier to have
27+
/// >1 primary file (or even a primary file list) in the future without
28+
/// breaking anything today.
29+
///
30+
/// Semantics today:
31+
/// If input files are on command line, primary files on command line are also
32+
/// input files; they are not repeated without -primary-file. If input files are
33+
/// in a file list, the primary files on the command line are repeated in the
34+
/// file list. Thus, if there are any primary files, it is illegal to have both
35+
/// (non-primary) input files and a file list. Finally, the order of input files
36+
/// must match the order given on the command line or the file list.
37+
///
38+
/// Side note:
39+
/// since each input file will cause a lot of work for the compiler, this code
40+
/// is biased towards clarity and not optimized.
41+
/// In the near future, it will be possible to put primary files in the
42+
/// filelist, or to have a separate filelist for primaries. The organization
43+
/// here anticipates that evolution.
44+
45+
class ArgsToFrontendInputsConverter {
46+
DiagnosticEngine &Diags;
47+
const ArgList &Args;
48+
FrontendInputs &Inputs;
49+
50+
Arg const *const FilelistPathArg;
51+
Arg const *const PrimaryFilelistPathArg;
52+
53+
SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> BuffersToKeepAlive;
54+
55+
llvm::SetVector<StringRef> Files;
56+
57+
public:
58+
ArgsToFrontendInputsConverter(DiagnosticEngine &diags, const ArgList &args,
59+
FrontendInputs &inputs);
60+
61+
bool convert();
62+
63+
private:
64+
bool enforceFilelistExclusion();
65+
bool readInputFilesFromCommandLine();
66+
bool readInputFilesFromFilelist();
67+
bool forAllFilesInFilelist(Arg const *const pathArg,
68+
llvm::function_ref<void(StringRef)> fn);
69+
bool addFile(StringRef file);
70+
Optional<std::set<StringRef>> readPrimaryFiles();
71+
std::set<StringRef>
72+
createInputFilesConsumingPrimaries(std::set<StringRef> primaryFiles);
73+
bool checkForMissingPrimaryFiles(std::set<StringRef> primaryFiles);
74+
};
75+
76+
} // namespace swift
77+
78+
#endif /* ArgsToFrontendInputsConverter_h */

include/swift/Frontend/FrontendInputs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class FrontendInputs {
100100

101101
bool shouldTreatAsSIL() const;
102102

103-
/// Return true for error
103+
/// \return true for error
104104
bool verifyInputs(DiagnosticEngine &diags, bool treatAsSIL,
105105
bool isREPLRequested, bool isNoneRequested) const;
106106

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//===--- ArgsToFrontendInputsConverter.cpp --------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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/FrontendOptions.h"
14+
15+
#include "swift/AST/DiagnosticsFrontend.h"
16+
#include "swift/Frontend/ArgsToFrontendInputsConverter.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

0 commit comments

Comments
 (0)