Files
swift-mirror/lib/ClangImporter/ClangModuleDependencyScanner.cpp
T
Allan Shortlidge d4ffb7802c AST: Avoid including unnecessary headers in ASTContext.h.
Anything that can be forward declared in ASTContext.h should be because it is
included by nearly every implementation file in the compiler. Avoiding these
includes allows these various options types to be changed without a full
rebuild.

NFC.
2026-05-06 06:43:45 -07:00

147 lines
5.3 KiB
C++

//===--- ClangModuleDependencyScanner.cpp - Dependency Scanning -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 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
//
//===----------------------------------------------------------------------===//
//
// This file implements dependency scanning for Clang modules.
//
//===----------------------------------------------------------------------===//
#include "ImporterImpl.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/ModuleDependencies.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/CASOptions.h"
#include "swift/Basic/SourceManager.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/CAS/CASOptions.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/StringSaver.h"
using namespace swift;
using namespace clang::tooling;
using namespace clang::tooling::dependencies;
static void addScannerPrefixMapperInvocationArguments(
std::vector<std::string> &invocationArgStrs, ASTContext &ctx) {
for (const auto &arg : ctx.SearchPathOpts.ScannerPrefixMapper) {
invocationArgStrs.push_back("-fdepscan-prefix-map");
invocationArgStrs.push_back(arg.first);
invocationArgStrs.push_back(arg.second);
}
}
/// Create the command line for Clang dependency scanning.
std::vector<std::string> ClangImporter::getClangDepScanningInvocationArguments(
ASTContext &ctx) {
std::vector<std::string> commandLineArgs = getClangDriverArguments(ctx);
addScannerPrefixMapperInvocationArguments(commandLineArgs, ctx);
// HACK! Drop the -fmodule-format= argument and the one that
// precedes it.
{
auto moduleFormatPos = llvm::find_if(commandLineArgs,
[](StringRef arg) {
return arg.starts_with("-fmodule-format=");
});
assert(moduleFormatPos != commandLineArgs.end());
assert(moduleFormatPos != commandLineArgs.begin());
commandLineArgs.erase(moduleFormatPos-1, moduleFormatPos+1);
}
// Use `-fsyntax-only` to do dependency scanning and assert if not there.
assert(llvm::is_contained(commandLineArgs, "-fsyntax-only") &&
"missing -fsyntax-only option");
// The Clang modules produced by ClangImporter are always embedded in an
// ObjectFilePCHContainer and contain -gmodules debug info.
commandLineArgs.push_back("-gmodules");
// To use -gmodules we need to have a real path for the PCH; this option has
// no effect if caching is disabled.
commandLineArgs.push_back("-Xclang");
commandLineArgs.push_back("-finclude-tree-preserve-pch-path");
return commandLineArgs;
}
void ClangImporter::getBridgingHeaderOptions(
const ASTContext &ctx,
const clang::tooling::dependencies::TranslationUnitDeps &deps,
std::vector<std::string> &swiftArgs) {
auto addClangArg = [&](Twine arg) {
swiftArgs.push_back("-Xcc");
swiftArgs.push_back(arg.str());
};
// We are using Swift frontend mode.
swiftArgs.push_back("-frontend");
// Swift frontend action: -emit-pcm
swiftArgs.push_back("-emit-pch");
// Ensure that the resulting PCM build invocation uses Clang frontend
// directly
swiftArgs.push_back("-direct-clang-cc1-module-build");
// Add args reported by the scanner.
// Round-trip clang args to canonicalize and clear the options that swift
// compiler doesn't need.
clang::CompilerInvocation depsInvocation;
clang::DiagnosticOptions diagOpts;
clang::DiagnosticsEngine clangDiags(new clang::DiagnosticIDs(), diagOpts,
new clang::IgnoringDiagConsumer());
llvm::SmallVector<const char *> clangArgs;
llvm::for_each(deps.Commands[0].Arguments, [&](const std::string &Arg) {
clangArgs.push_back(Arg.c_str());
});
bool success = clang::CompilerInvocation::CreateFromArgs(
depsInvocation, clangArgs, clangDiags);
(void)success;
assert(success && "clang option from dep scanner round trip failed");
// Clear the cache key for module. The module key is computed from clang
// invocation, not swift invocation.
depsInvocation.getFrontendOpts().ProgramAction =
clang::frontend::ActionKind::GeneratePCH;
depsInvocation.getFrontendOpts().ModuleCacheKeys.clear();
depsInvocation.getFrontendOpts().PathPrefixMappings.clear();
depsInvocation.getFrontendOpts().OutputFile.clear();
llvm::BumpPtrAllocator allocator;
llvm::StringSaver saver(allocator);
clangArgs.clear();
depsInvocation.generateCC1CommandLine(
clangArgs,
[&saver](const llvm::Twine &T) { return saver.save(T).data(); });
llvm::for_each(clangArgs, addClangArg);
ctx.CASOpts.enumerateCASConfigurationFlags(
[&](StringRef Arg) { swiftArgs.push_back(Arg.str()); });
if (auto Tree = deps.IncludeTreeID) {
swiftArgs.push_back("-clang-include-tree-root");
swiftArgs.push_back(*Tree);
}
}