blob: 58af820df340e1abe3b7c53a0574b570258ac9a7 [file] [log] [blame]
//===--- TBD.cpp -- generates and validates TBD files ---------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "TBD.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/Module.h"
#include "swift/Basic/LLVM.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Frontend/FrontendOptions.h"
#include "swift/TBDGen/TBDGen.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ValueSymbolTable.h"
#include "llvm/Support/FileSystem.h"
#include <vector>
using namespace swift;
static std::vector<StringRef> sortSymbols(llvm::StringSet<> &symbols) {
std::vector<StringRef> sorted;
for (auto &symbol : symbols)
sorted.push_back(symbol.getKey());
std::sort(sorted.begin(), sorted.end());
return sorted;
}
bool swift::writeTBD(ModuleDecl *M, bool hasMultipleIRGenThreads,
StringRef OutputFilename) {
std::error_code EC;
llvm::raw_fd_ostream OS(OutputFilename, EC, llvm::sys::fs::F_None);
if (EC) {
M->getASTContext().Diags.diagnose(SourceLoc(), diag::error_opening_output,
OutputFilename, EC.message());
return true;
}
llvm::StringSet<> symbols;
for (auto file : M->getFiles())
enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads,
/*isWholeModule=*/true);
// Ensure the order is stable.
for (auto &symbol : sortSymbols(symbols)) {
OS << symbol << "\n";
}
return false;
}
static bool validateSymbolSet(DiagnosticEngine &diags,
llvm::StringSet<> symbols,
llvm::Module &IRModule) {
auto error = false;
// Diff the two sets of symbols, flagging anything outside their intersection.
// Delay the emission of errors for things in the IR but not TBD, so we can
// sort them to get a stable order.
std::vector<StringRef> irNotTBD;
for (auto &nameValue : IRModule.getValueSymbolTable()) {
auto name = nameValue.getKey();
auto value = nameValue.getValue();
if (auto GV = dyn_cast<llvm::GlobalValue>(value)) {
// Is this a symbol that should be listed?
auto externallyVisible =
GV->hasExternalLinkage() && !GV->hasHiddenVisibility();
if (!GV->isDeclaration() && externallyVisible) {
// Is it listed?
if (!symbols.erase(name))
irNotTBD.push_back(name);
}
} else {
assert(symbols.find(name) == symbols.end() &&
"non-global value in value symbol table");
}
}
std::sort(irNotTBD.begin(), irNotTBD.end());
for (auto &name : irNotTBD) {
diags.diagnose(SourceLoc(), diag::symbol_in_ir_not_in_tbd, name,
Demangle::demangleSymbolAsString(name));
error = true;
}
for (auto &name : sortSymbols(symbols)) {
diags.diagnose(SourceLoc(), diag::symbol_in_tbd_not_in_ir, name,
Demangle::demangleSymbolAsString(name));
error = true;
}
return error;
}
bool swift::validateTBD(ModuleDecl *M, llvm::Module &IRModule,
bool hasMultipleIRGenThreads) {
llvm::StringSet<> symbols;
for (auto file : M->getFiles())
enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads,
/*isWholeModule=*/true);
return validateSymbolSet(M->getASTContext().Diags, symbols, IRModule);
}
bool swift::validateTBD(FileUnit *file, llvm::Module &IRModule,
bool hasMultipleIRGenThreads) {
llvm::StringSet<> symbols;
enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads,
/*isWholeModule=*/false);
return validateSymbolSet(file->getParentModule()->getASTContext().Diags,
symbols, IRModule);
}