blob: f8829a0aea767cf39d2ef0c70dc3ed009f4da45a [file] [log] [blame]
//===--- swift_indent_main.cpp - Swift code formatting tool ---------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Extracts a Symbol Graph from a .swiftmodule file.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/LLVMInitialize.h"
#include "swift/Basic/Version.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/SymbolGraphGen/SymbolGraphGen.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
using namespace swift;
using namespace llvm::opt;
namespace options {
static llvm::cl::OptionCategory Category("swift-symbolgraph-extract Options");
static llvm::cl::opt<std::string>
ModuleName("module-name", llvm::cl::desc("Name of the module to extract (Required)"), llvm::cl::cat(Category));
static llvm::cl::list<std::string>
FrameworkSearchPaths("F", llvm::cl::desc("Add a directory to the framework search paths"), llvm::cl::ZeroOrMore,
llvm::cl::cat(Category));
static llvm::cl::list<std::string>
SystemFrameworkSearchPaths("Fsystem", llvm::cl::desc("Add directory to system framework search path"), llvm::cl::ZeroOrMore,
llvm::cl::cat(Category));
static llvm::cl::list<std::string>
LibrarySearchPaths("L", llvm::cl::desc("Add a directory to the library search paths"), llvm::cl::ZeroOrMore,
llvm::cl::cat(Category));
static llvm::cl::list<std::string>
ImportSearchPaths("I", llvm::cl::desc("Add directory to the import search paths"), llvm::cl::ZeroOrMore,
llvm::cl::cat(Category));
static llvm::cl::opt<std::string>
ModuleCachePath("module-cache-path", llvm::cl::desc("Specifies a path to cache modules"), llvm::cl::cat(Category));
static llvm::cl::opt<std::string>
SDK("sdk", llvm::cl::desc("Path to the SDK"),
llvm::cl::cat(Category));
static llvm::cl::opt<std::string>
Target("target", llvm::cl::desc("Target triple (Required)"),
llvm::cl::cat(Category));
static llvm::cl::opt<std::string>
SwiftVersion("swift-version", llvm::cl::desc("Interpret input according to a specific Swift language version number"), llvm::cl::cat(Category));
static llvm::cl::opt<bool>
PrettyPrint("pretty-print", llvm::cl::desc("Pretty-print the resulting Symbol Graph JSON"), llvm::cl::cat(Category));
static llvm::cl::opt<bool>
SkipSynthesizedMembers("skip-synthesized-members",
llvm::cl::desc("Skip members inherited through classes or default implementations"),
llvm::cl::cat(Category));
static llvm::cl::opt<std::string>
MinimumAccessLevel("minimum-access-level", llvm::cl::desc("Include symbols with this access level or more"), llvm::cl::cat(Category));
static llvm::cl::list<std::string>
Xcc("Xcc", llvm::cl::desc("Pass the following command-line flag to Clang"),
llvm::cl::cat(Category));
static llvm::cl::opt<std::string>
ResourceDir("resource-dir",
llvm::cl::desc("Override the directory that holds the compiler resource files"),
llvm::cl::cat(Category));
static llvm::cl::opt<std::string>
OutputDir("output-dir", llvm::cl::desc("Symbol Graph JSON Output Directory (Required)"), llvm::cl::cat(Category));
} // end namespace options
static bool argumentsAreValid() {
bool Valid = true;
if (options::Target.empty()) {
llvm::errs() << "Required -target option is missing\n";
Valid = false;
}
if (options::ModuleName.empty()) {
llvm::errs() << "Required -module-name argument is missing\n";
Valid = false;
}
if (options::OutputDir.empty()) {
llvm::errs() << "Required -output-dir argument is missing\n";
Valid = false;
}
return Valid;
}
int swift_symbolgraph_extract_main(ArrayRef<const char *> Args, const char *Argv0, void *MainAddr) {
INITIALIZE_LLVM();
llvm::cl::HideUnrelatedOptions(options::Category);
// LLVM Command Line expects to trim off argv[0].
SmallVector<const char *, 8> ArgsWithArgv0 { Argv0 };
ArgsWithArgv0.append(Args.begin(), Args.end());
if (Args.empty()) {
ArgsWithArgv0.push_back("-help");
}
llvm::cl::ParseCommandLineOptions(ArgsWithArgv0.size(),
llvm::makeArrayRef(ArgsWithArgv0).data(),
"Swift Symbol Graph Extractor\n");
if (!argumentsAreValid()) {
llvm::cl::PrintHelpMessage();
return EXIT_FAILURE;
}
if (!llvm::sys::fs::is_directory(options::OutputDir)) {
llvm::errs() << "-output-dir argument '" << options::OutputDir
<< " does not exist or is not a directory\n";
return EXIT_FAILURE;
}
CompilerInvocation Invocation;
Invocation.setMainExecutablePath(
llvm::sys::fs::getMainExecutable(Argv0, MainAddr));
Invocation.setModuleName("swift_symbolgraph_extract");
if (!options::ResourceDir.empty()) {
Invocation.setRuntimeResourcePath(options::ResourceDir);
}
Invocation.setSDKPath(options::SDK);
Invocation.setTargetTriple(options::Target);
for (auto &Arg : options::Xcc) {
Invocation.getClangImporterOptions().ExtraArgs.push_back(Arg);
}
std::vector<SearchPathOptions::FrameworkSearchPath> FrameworkSearchPaths;
for (const auto &Path : options::FrameworkSearchPaths) {
FrameworkSearchPaths.push_back({ Path, /*isSystem*/ false});
}
for (const auto &Path : options::SystemFrameworkSearchPaths) {
FrameworkSearchPaths.push_back({ Path, /*isSystem*/ true });
}
Invocation.setFrameworkSearchPaths(FrameworkSearchPaths);
Invocation.getSearchPathOptions().LibrarySearchPaths = options::LibrarySearchPaths;
Invocation.setImportSearchPaths(options::ImportSearchPaths);
Invocation.getLangOptions().EnableObjCInterop = llvm::Triple(options::Target).isOSDarwin();
Invocation.getLangOptions().DebuggerSupport = true;
Invocation.getFrontendOptions().EnableLibraryEvolution = true;
Invocation.setClangModuleCachePath(options::ModuleCachePath);
Invocation.getClangImporterOptions().ModuleCachePath = options::ModuleCachePath;
Invocation.setDefaultPrebuiltCacheIfNecessary();
if (!options::SwiftVersion.empty()) {
using version::Version;
bool isValid = false;
if (auto Version = Version::parseVersionString(options::SwiftVersion,
SourceLoc(), nullptr)) {
if (auto Effective = Version.getValue().getEffectiveLanguageVersion()) {
Invocation.getLangOptions().EffectiveLanguageVersion = *Effective;
isValid = true;
}
}
if (!isValid) {
llvm::errs() << "Unsupported Swift Version.\n";
return EXIT_FAILURE;
}
}
symbolgraphgen::SymbolGraphOptions Options {
options::OutputDir,
llvm::Triple(options::Target),
options::PrettyPrint,
AccessLevel::Public,
!options::SkipSynthesizedMembers,
};
if (!options::MinimumAccessLevel.empty()) {
Options.MinimumAccessLevel =
llvm::StringSwitch<AccessLevel>(options::MinimumAccessLevel)
.Case("open", AccessLevel::Open)
.Case("public", AccessLevel::Public)
.Case("internal", AccessLevel::Internal)
.Case("fileprivate", AccessLevel::FilePrivate)
.Case("private", AccessLevel::Private)
.Default(AccessLevel::Public);
}
PrintingDiagnosticConsumer DiagPrinter;
CompilerInstance CI;
CI.getDiags().addConsumer(DiagPrinter);
if (CI.setup(Invocation)) {
llvm::outs() << "Failed to setup compiler instance\n";
return EXIT_FAILURE;
}
auto M = CI.getASTContext().getModuleByName(options::ModuleName);
SmallVector<Identifier, 32> VisibleModuleNames;
CI.getASTContext().getVisibleTopLevelModuleNames(VisibleModuleNames);
if (!M) {
llvm::errs()
<< "Couldn't load module '" << options::ModuleName << '\''
<< " in the current SDK and search paths.\n";
if (VisibleModuleNames.empty()) {
llvm::errs() << "Could not find any modules.\n";
} else {
std::sort(VisibleModuleNames.begin(), VisibleModuleNames.end(),
[](const Identifier &A, const Identifier &B) -> bool {
return A.str() < B.str();
});
llvm::errs() << "Current visible modules:\n";
for (const auto &ModuleName : VisibleModuleNames) {
llvm::errs() << ModuleName.str() << "\n";
}
}
return EXIT_FAILURE;
}
const auto &MainFile = M->getMainFile(FileUnitKind::SerializedAST);
llvm::errs() << "Emitting symbol graph for module file: " << MainFile.getModuleDefiningPath() << '\n';
int Success = symbolgraphgen::emitSymbolGraphForModule(M, Options);
// Look for cross-import overlays that the given module imports.
// Clear out the diagnostic printer before looking for cross-import overlay modules,
// since some SDK modules can cause errors in the getModuleByName() call. The call
// itself will properly return nullptr after this failure, so for our purposes we
// don't need to print these errors.
CI.removeDiagnosticConsumer(&DiagPrinter);
for (const auto &ModuleName : VisibleModuleNames) {
if (ModuleName.str().startswith("_")) {
auto CIM = CI.getASTContext().getModuleByName(ModuleName.str());
if (CIM && CIM->isCrossImportOverlayOf(M)) {
const auto &CIMainFile = CIM->getMainFile(FileUnitKind::SerializedAST);
llvm::errs() << "Emitting symbol graph for cross-import overlay module file: "
<< CIMainFile.getModuleDefiningPath() << '\n';
Success |= symbolgraphgen::emitSymbolGraphForModule(CIM, Options);
}
}
}
return Success;
}