-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Hook up -emit-interface-path to a simple AST printer #18224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,6 +64,21 @@ void PrintOptions::clearSynthesizedExtension() { | |
TransformContext.reset(); | ||
} | ||
|
||
PrintOptions PrintOptions::printTextualInterfaceFile() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name of this function sounds like it does the printing, but it only computes options. I see that it follows the practice of the other two, but still... |
||
PrintOptions result; | ||
result.PrintLongAttrsOnSeparateLines = true; | ||
result.TypeDefinitions = true; | ||
result.PrintIfConfig = false; | ||
result.FullyQualifiedTypes = true; | ||
result.SkipImports = true; | ||
result.AccessFilter = AccessLevel::Public; | ||
|
||
// FIXME: We'll need the actual default parameter expression. | ||
result.PrintDefaultParameterPlaceholder = false; | ||
|
||
return result; | ||
} | ||
|
||
TypeTransformContext::TypeTransformContext(Type T) | ||
: BaseType(T.getPointer()) { | ||
assert(T->mayHaveMembers()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors | ||
// Copyright (c) 2014 - 2018 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 | ||
|
@@ -11,9 +11,15 @@ | |
//===----------------------------------------------------------------------===// | ||
|
||
#include "swift/Basic/FileSystem.h" | ||
|
||
#include "swift/Basic/LLVM.h" | ||
#include "clang/Basic/FileManager.h" | ||
#include "llvm/ADT/Twine.h" | ||
#include "llvm/Support/Errc.h" | ||
#include "llvm/Support/FileSystem.h" | ||
#include "llvm/Support/Path.h" | ||
#include "llvm/Support/Process.h" | ||
#include "clang/Basic/FileManager.h" | ||
#include "llvm/Support/Signals.h" | ||
|
||
using namespace swift; | ||
|
||
|
@@ -30,6 +36,137 @@ namespace { | |
}; | ||
} // end anonymous namespace | ||
|
||
/// Does some simple checking to see if a temporary file can be written next to | ||
/// \p outputPath and then renamed into place. | ||
/// | ||
/// Helper for swift::atomicallyWritingToFile. | ||
/// | ||
/// If the result is an error, the write won't succeed at all, and the calling | ||
/// operation should bail out early. | ||
static llvm::ErrorOr<bool> | ||
canUseTemporaryForWrite(const StringRef outputPath) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like that |
||
namespace fs = llvm::sys::fs; | ||
|
||
if (outputPath == "-") { | ||
// Special case: "-" represents stdout, and LLVM's output stream APIs are | ||
// aware of this. It doesn't make sense to use a temporary in this case. | ||
return false; | ||
} | ||
|
||
fs::file_status status; | ||
(void)fs::status(outputPath, status); | ||
if (!fs::exists(status)) { | ||
// Assume we'll be able to write to both a temporary file and to the final | ||
// destination if the final destination doesn't exist yet. | ||
return true; | ||
} | ||
|
||
// Fail early if we can't write to the final destination. | ||
if (!fs::can_write(outputPath)) | ||
return llvm::make_error_code(llvm::errc::operation_not_permitted); | ||
|
||
// Only use a temporary if the output is a regular file. This handles | ||
// things like '-o /dev/null' | ||
return fs::is_regular_file(status); | ||
} | ||
|
||
/// Attempts to open a temporary file next to \p outputPath, with the intent | ||
/// that once the file has been written it will be renamed into place. | ||
/// | ||
/// Helper for swift::atomicallyWritingToFile. | ||
/// | ||
/// \param[out] openedStream On success, a stream opened for writing to the | ||
/// temporary file that was just created. | ||
/// \param outputPath The path to the final output file, which is used to decide | ||
/// where to put the temporary. | ||
/// \param openFlags Controls how the output stream will be opened. | ||
/// | ||
/// \returns The path to the temporary file that was opened, or \c None if the | ||
/// file couldn't be created. | ||
static Optional<std::string> | ||
tryToOpenTemporaryFile(Optional<llvm::raw_fd_ostream> &openedStream, | ||
const StringRef outputPath, | ||
const llvm::sys::fs::OpenFlags openFlags) { | ||
namespace fs = llvm::sys::fs; | ||
|
||
// Create a temporary file path. | ||
// Insert a placeholder for a random suffix before the extension (if any). | ||
// Then because some tools glob for build artifacts (such as clang's own | ||
// GlobalModuleIndex.cpp), also append .tmp. | ||
SmallString<128> tempPath; | ||
const StringRef outputExtension = llvm::sys::path::extension(outputPath); | ||
tempPath = outputPath.drop_back(outputExtension.size()); | ||
tempPath += "-%%%%%%%%"; | ||
tempPath += outputExtension; | ||
tempPath += ".tmp"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wish we had Swift's string interpolation, sigh. |
||
|
||
int fd; | ||
const unsigned perms = fs::all_read | fs::all_write; | ||
std::error_code EC = fs::createUniqueFile(tempPath, fd, tempPath, perms, | ||
openFlags); | ||
|
||
if (EC) { | ||
// Ignore the specific error; the caller has to fall back to not using a | ||
// temporary anyway. | ||
return None; | ||
} | ||
|
||
openedStream.emplace(fd, /*shouldClose=*/true); | ||
// Make sure the temporary file gets removed if we crash. | ||
llvm::sys::RemoveFileOnSignal(tempPath); | ||
return tempPath.str().str(); | ||
} | ||
|
||
std::error_code swift::atomicallyWritingToFile( | ||
const StringRef outputPath, const bool binaryMode, | ||
const llvm::function_ref<void(llvm::raw_pwrite_stream &)> action) { | ||
namespace fs = llvm::sys::fs; | ||
|
||
// FIXME: This is mostly a simplified version of | ||
// clang::CompilerInstance::createOutputFile. It would be great to share the | ||
// implementation. | ||
assert(!outputPath.empty()); | ||
|
||
llvm::ErrorOr<bool> canUseTemporary = canUseTemporaryForWrite(outputPath); | ||
if (std::error_code error = canUseTemporary.getError()) | ||
return error; | ||
|
||
Optional<std::string> temporaryPath; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like how the refactoring is going! When I see a declaration, followed by a block that computes it, I wonder if it works better as a separate function. But I'm not sure I see that factoring here would be comprehensible, even though the code wants it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah. It's almost |
||
{ | ||
const fs::OpenFlags openFlags = (binaryMode ? fs::F_None : fs::F_Text); | ||
|
||
Optional<llvm::raw_fd_ostream> OS; | ||
if (canUseTemporary.get()) { | ||
temporaryPath = tryToOpenTemporaryFile(OS, outputPath, openFlags); | ||
|
||
if (!temporaryPath) { | ||
assert(!OS.hasValue()); | ||
// If we failed to create the temporary, fall back to writing to the | ||
// file directly. This handles the corner case where we cannot write to | ||
// the directory, but can write to the file. | ||
} | ||
} | ||
|
||
if (!OS.hasValue()) { | ||
std::error_code error; | ||
OS.emplace(outputPath, error, openFlags); | ||
if (error) | ||
return error; | ||
} | ||
|
||
action(OS.getValue()); | ||
// In addition to scoping the use of 'OS', ending the scope here also | ||
// ensures that it's been flushed (by destroying it). | ||
} | ||
|
||
if (!temporaryPath.hasValue()) { | ||
// If we didn't use a temporary, we're done! | ||
return std::error_code(); | ||
} | ||
|
||
return swift::moveFileIfDifferent(temporaryPath.getValue(), outputPath); | ||
} | ||
|
||
std::error_code swift::moveFileIfDifferent(const llvm::Twine &source, | ||
const llvm::Twine &destination) { | ||
namespace fs = llvm::sys::fs; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!