Skip to content

Commit 2c44265

Browse files
authored
Merge pull request #8359 from graydon/rdar-31044067-missing-dependencies-mark-2
2 parents aed4ed7 + ab2f429 commit 2c44265

File tree

11 files changed

+195
-55
lines changed

11 files changed

+195
-55
lines changed

include/swift/AST/ModuleLoader.h

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,38 +24,41 @@
2424
#include "llvm/ADT/SmallSet.h"
2525
#include "llvm/ADT/TinyPtrVector.h"
2626

27+
namespace clang {
28+
class DependencyCollector;
29+
}
30+
2731
namespace swift {
2832

2933
class AbstractFunctionDecl;
34+
class ClangImporterOptions;
3035
class ClassDecl;
3136
class ModuleDecl;
3237
class NominalTypeDecl;
3338

3439
enum class KnownProtocolKind : uint8_t;
3540

36-
/// Records dependencies on files outside of the current module.
41+
/// Records dependencies on files outside of the current module;
42+
/// implemented in terms of a wrapped clang::DependencyCollector.
3743
class DependencyTracker {
38-
llvm::SetVector<std::string, std::vector<std::string>,
39-
llvm::SmallSet<std::string, 16>> paths;
40-
44+
std::shared_ptr<clang::DependencyCollector> clangCollector;
4145
public:
46+
47+
DependencyTracker();
48+
4249
/// Adds a file as a dependency.
4350
///
44-
/// The contents of \p file are taken literally, and should be appropriate
51+
/// The contents of \p File are taken literally, and should be appropriate
4552
/// for appearing in a list of dependencies suitable for tooling like Make.
4653
/// No path canonicalization is done.
47-
void addDependency(StringRef file) {
48-
paths.insert(file);
49-
}
54+
void addDependency(StringRef File, bool IsSystem);
5055

5156
/// Fetches the list of dependencies.
52-
ArrayRef<std::string> getDependencies() const {
53-
if (paths.empty())
54-
return None;
55-
assert((&paths[0]) + (paths.size() - 1) == &paths.back() &&
56-
"elements not stored contiguously");
57-
return llvm::makeArrayRef(&paths[0], paths.size());
58-
}
57+
ArrayRef<std::string> getDependencies() const;
58+
59+
/// Return the underlying clang::DependencyCollector that this
60+
/// class wraps.
61+
std::shared_ptr<clang::DependencyCollector> getClangCollector();
5962
};
6063

6164
/// \brief Abstract interface that loads named modules into the AST.
@@ -66,9 +69,9 @@ class ModuleLoader {
6669
protected:
6770
ModuleLoader(DependencyTracker *tracker) : dependencyTracker(tracker) {}
6871

69-
void addDependency(StringRef file) {
72+
void addDependency(StringRef file, bool IsSystem=false) {
7073
if (dependencyTracker)
71-
dependencyTracker->addDependency(file);
74+
dependencyTracker->addDependency(file, IsSystem);
7275
}
7376

7477
public:

include/swift/ClangImporter/ClangImporter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ namespace clang {
3030
class ASTContext;
3131
class CodeGenOptions;
3232
class Decl;
33+
class DependencyCollector;
3334
class EnumConstantDecl;
3435
class EnumDecl;
3536
class MacroInfo;
@@ -94,6 +95,11 @@ class ClangImporter final : public ClangModuleLoader {
9495

9596
~ClangImporter();
9697

98+
/// \brief Create a new clang::DependencyCollector customized to
99+
/// ClangImporter's specific uses.
100+
static std::shared_ptr<clang::DependencyCollector>
101+
createDependencyCollector();
102+
97103
/// \brief Check whether the module with a given name can be imported without
98104
/// importing it.
99105
///

lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ add_swift_library(swiftAST STATIC
3434
LayoutConstraint.cpp
3535
LookupVisibleDecls.cpp
3636
Module.cpp
37+
ModuleLoader.cpp
3738
ModuleNameLookup.cpp
3839
NameLookup.cpp
3940
Parameter.cpp

lib/AST/ModuleLoader.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//===--- ModuleLoader.cpp - Swift Language Module Implementation ----------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 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+
// This file implements the ModuleLoader class and/or any helpers.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "swift/AST/ModuleLoader.h"
18+
#include "clang/Frontend/Utils.h"
19+
#include "swift/ClangImporter/ClangImporter.h"
20+
21+
namespace swift {
22+
23+
DependencyTracker::DependencyTracker()
24+
// NB: The ClangImporter believes it's responsible for the construction of
25+
// this instance, and it static_cast<>s the instance pointer to its own
26+
// subclass based on that belief. If you change this to be some other
27+
// instance, you will need to change ClangImporter's code to handle the
28+
// difference.
29+
: clangCollector(ClangImporter::createDependencyCollector())
30+
{
31+
}
32+
33+
void
34+
DependencyTracker::addDependency(StringRef File, bool IsSystem) {
35+
// DependencyTracker exposes an interface that (intentionally) does not talk
36+
// about clang at all, nor about missing deps. It does expose an IsSystem
37+
// dimension, though it is presently always false, we accept it and pass it
38+
// along to the clang DependencyCollector in case Swift callers start setting
39+
// it to true someday.
40+
clangCollector->maybeAddDependency(File, /*FromClangModule=*/false,
41+
IsSystem, /*IsClangModuleFile=*/false,
42+
/*IsMissing=*/false);
43+
}
44+
45+
ArrayRef<std::string>
46+
DependencyTracker::getDependencies() const {
47+
return clangCollector->getDependencies();
48+
}
49+
50+
std::shared_ptr<clang::DependencyCollector>
51+
DependencyTracker::getClangCollector() {
52+
return clangCollector;
53+
}
54+
55+
}

lib/ClangImporter/ClangImporter.cpp

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,10 @@ using clang::CompilerInvocation;
7474

7575
namespace {
7676
class HeaderImportCallbacks : public clang::PPCallbacks {
77-
ClangImporter &Importer;
7877
ClangImporter::Implementation &Impl;
7978
public:
80-
HeaderImportCallbacks(ClangImporter &importer,
81-
ClangImporter::Implementation &impl)
82-
: Importer(importer), Impl(impl) {}
79+
HeaderImportCallbacks(ClangImporter::Implementation &impl)
80+
: Impl(impl) {}
8381

8482
void handleImport(const clang::Module *imported) {
8583
if (!imported)
@@ -97,8 +95,6 @@ namespace {
9795
StringRef RelativePath,
9896
const clang::Module *Imported) override {
9997
handleImport(Imported);
100-
if (!Imported && File)
101-
Importer.addDependency(File->getName());
10298
}
10399

104100
void moduleImport(clang::SourceLocation ImportLoc,
@@ -108,21 +104,6 @@ namespace {
108104
}
109105
};
110106

111-
class ASTReaderCallbacks : public clang::ASTReaderListener {
112-
ClangImporter &Importer;
113-
public:
114-
explicit ASTReaderCallbacks(ClangImporter &importer) : Importer(importer) {}
115-
116-
bool needsInputFileVisitation() override { return true; }
117-
118-
bool visitInputFile(StringRef file, bool isSystem,
119-
bool isOverridden, bool isExplicitModule) override {
120-
if (!isOverridden)
121-
Importer.addDependency(file);
122-
return true;
123-
}
124-
};
125-
126107
class PCHDeserializationCallbacks : public clang::ASTDeserializationListener {
127108
ClangImporter::Implementation &Impl;
128109
public:
@@ -313,8 +294,51 @@ class BridgingPPTracker : public clang::PPCallbacks {
313294
Impl.BridgeHeaderMacros.push_back(MacroNameTok.getIdentifierInfo());
314295
}
315296
};
297+
298+
class ClangImporterDependencyCollector : public clang::DependencyCollector
299+
{
300+
llvm::StringSet<> ExcludedPaths;
301+
public:
302+
ClangImporterDependencyCollector() = default;
303+
304+
void excludePath(StringRef filename) {
305+
ExcludedPaths.insert(filename);
306+
}
307+
308+
bool isClangImporterSpecialName(StringRef Filename) {
309+
using ImporterImpl = ClangImporter::Implementation;
310+
return (Filename == ImporterImpl::moduleImportBufferName
311+
|| Filename == ImporterImpl::bridgingHeaderBufferName);
312+
}
313+
314+
// Currently preserving older ClangImporter behaviour of ignoring system
315+
// dependencies, but possibly revisit?
316+
bool needSystemDependencies() override { return false; }
317+
318+
bool sawDependency(StringRef Filename, bool FromClangModule,
319+
bool IsSystem, bool IsClangModuleFile,
320+
bool IsMissing) override {
321+
if (!clang::DependencyCollector::sawDependency(Filename, FromClangModule,
322+
IsSystem, IsClangModuleFile,
323+
IsMissing))
324+
return false;
325+
// Currently preserving older ClangImporter behaviour of ignoring .pcm
326+
// file dependencies, but possibly revisit?
327+
if (IsClangModuleFile
328+
|| isClangImporterSpecialName(Filename)
329+
|| ExcludedPaths.count(Filename))
330+
return false;
331+
return true;
332+
}
333+
};
316334
} // end anonymous namespace
317335

336+
std::shared_ptr<clang::DependencyCollector>
337+
ClangImporter::createDependencyCollector()
338+
{
339+
return std::make_shared<ClangImporterDependencyCollector>();
340+
}
341+
318342
void ClangImporter::Implementation::addBridgeHeaderTopLevelDecls(
319343
clang::Decl *D) {
320344
if (shouldIgnoreBridgeHeaderTopLevelDecl(D))
@@ -708,6 +732,14 @@ ClangImporter::create(ASTContext &ctx,
708732
if (llvm::sys::path::extension(importerOpts.BridgingHeader).endswith(
709733
PCH_EXTENSION)) {
710734
importer->Impl.IsReadingBridgingPCH = true;
735+
if (tracker) {
736+
// Currently ignoring dependency on bridging .pch files because they are
737+
// temporaries; if and when they are no longer temporaries, this condition
738+
// should be removed.
739+
auto &coll = static_cast<ClangImporterDependencyCollector &>(
740+
*tracker->getClangCollector());
741+
coll.excludePath(importerOpts.BridgingHeader);
742+
}
711743
}
712744

713745
// FIXME: These can't be controlled from the command line.
@@ -764,6 +796,9 @@ ClangImporter::create(ASTContext &ctx,
764796
llvm::make_unique<clang::ObjectFilePCHContainerReader>());
765797
importer->Impl.Instance.reset(new CompilerInstance(PCHContainerOperations));
766798
auto &instance = *importer->Impl.Instance;
799+
if (tracker)
800+
instance.addDependencyCollector(tracker->getClangCollector());
801+
767802
instance.setDiagnostics(&*clangDiags);
768803
instance.setInvocation(importer->Impl.Invocation);
769804

@@ -808,9 +843,6 @@ ClangImporter::create(ASTContext &ctx,
808843
clangPP.addPPCallbacks(std::move(ppTracker));
809844

810845
instance.createModuleManager();
811-
instance.getModuleManager()->addListener(
812-
std::unique_ptr<clang::ASTReaderListener>(
813-
new ASTReaderCallbacks(*importer)));
814846

815847
// Manually run the action, so that the TU stays open for additional parsing.
816848
instance.createSema(action->getTranslationUnitKind(), nullptr);
@@ -840,7 +872,7 @@ ClangImporter::create(ASTContext &ctx,
840872
}
841873

842874
// FIXME: This is missing implicit includes.
843-
auto *CB = new HeaderImportCallbacks(*importer, importer->Impl);
875+
auto *CB = new HeaderImportCallbacks(importer->Impl);
844876
clangPP.addPPCallbacks(std::unique_ptr<clang::PPCallbacks>(CB));
845877

846878
// Create the selectors we'll be looking for.

lib/FrontendTool/FrontendTool.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,11 @@ static bool emitMakeDependencies(DiagnosticEngine &diags,
117117
out << escape(targetName) << " :";
118118
// First include all other files in the module. Make-style dependencies
119119
// need to be conservative!
120-
for (StringRef path : opts.InputFilenames)
120+
for (auto const &path : reversePathSortedFilenames(opts.InputFilenames))
121121
out << ' ' << escape(path);
122122
// Then print dependencies we've picked up during compilation.
123-
for (StringRef path : depTracker.getDependencies())
123+
for (auto const &path :
124+
reversePathSortedFilenames(depTracker.getDependencies()))
124125
out << ' ' << escape(path);
125126
out << '\n';
126127
});

lib/FrontendTool/ReferenceDependencies.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,17 @@ static std::string mangleTypeAsContext(const NominalTypeDecl *type) {
102102
return Mangler.mangleTypeAsContextUSR(type);
103103
}
104104

105+
std::vector<std::string>
106+
swift::reversePathSortedFilenames(const ArrayRef<std::string> elts) {
107+
std::vector<std::string> tmp(elts.begin(), elts.end());
108+
std::sort(tmp.begin(), tmp.end(), [](const std::string &a,
109+
const std::string &b) -> bool {
110+
return std::lexicographical_compare(a.rbegin(), a.rend(),
111+
b.rbegin(), b.rend());
112+
});
113+
return tmp;
114+
}
115+
105116
bool swift::emitReferenceDependencies(DiagnosticEngine &diags,
106117
SourceFile *SF,
107118
DependencyTracker &depTracker,
@@ -391,7 +402,7 @@ bool swift::emitReferenceDependencies(DiagnosticEngine &diags,
391402
}
392403

393404
out << "depends-external:\n";
394-
for (auto &entry : depTracker.getDependencies()) {
405+
for (auto &entry : reversePathSortedFilenames(depTracker.getDependencies())) {
395406
out << "- \"" << llvm::yaml::escape(entry) << "\"\n";
396407
}
397408

lib/FrontendTool/ReferenceDependencies.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,23 @@
1313
#ifndef SWIFT_FRONTENDTOOL_REFERENCEDEPENDENCIES_H
1414
#define SWIFT_FRONTENDTOOL_REFERENCEDEPENDENCIES_H
1515

16+
#include "llvm/ADT/ArrayRef.h"
17+
#include <vector>
18+
#include <string>
19+
1620
namespace swift {
1721

1822
class DependencyTracker;
1923
class DiagnosticEngine;
2024
class FrontendOptions;
2125
class SourceFile;
2226

27+
/// Sort a set of paths in an order that's (comparatively) stable against
28+
/// variation in filesystem prefix: lexicographic comparison of the
29+
/// byte-reversals of each path. Used for emitting external dependencies.
30+
std::vector<std::string>
31+
reversePathSortedFilenames(const llvm::ArrayRef<std::string> paths);
32+
2333
/// Emit a Swift-style dependencies file for \p SF.
2434
bool emitReferenceDependencies(DiagnosticEngine &diags,
2535
SourceFile *SF,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// REQUIRES: objc_interop
2+
// RUN: rm -f %t.*
3+
//
4+
// Generate a bridging PCH, use it in a swift file, and check that the swift file's .swiftdeps
5+
// mention the .h the PCH was generated from, and any .h files included in it.
6+
//
7+
// RUN: %target-swift-frontend -emit-pch -o %t.pch %S/Inputs/chained-unit-test-bridging-header-to-pch.h
8+
// RUN: %target-swift-frontend -module-name test -c -emit-dependencies-path %t.d -emit-reference-dependencies-path %t.swiftdeps -primary-file %s %s -import-objc-header %t.pch
9+
// RUN: %FileCheck --check-prefix CHECK-DEPS %s < %t.d
10+
// RUN: %FileCheck --check-prefix CHECK-SWIFTDEPS %s < %t.swiftdeps
11+
// RUN: %FileCheck --check-prefix CHECK-SWIFTDEPS2 %s < %t.swiftdeps
12+
13+
print(app_function(1))
14+
15+
// CHECK-DEPS: pch-bridging-header-deps.o : {{.*}}SOURCE_DIR/test/ClangImporter/Inputs/app-bridging-header-to-pch.h {{.*}}SOURCE_DIR/test/ClangImporter/Inputs/chained-unit-test-bridging-header-to-pch.h
16+
17+
// CHECK-SWIFTDEPS: depends-external:
18+
// CHECK-SWIFTDEPS: - "SOURCE_DIR/test/ClangImporter/Inputs/app-bridging-header-to-pch.h"
19+
// CHECK-SWIFTDEPS: - "SOURCE_DIR/test/ClangImporter/Inputs/chained-unit-test-bridging-header-to-pch.h"
20+
21+
// CHECK-SWIFTDEPS2-NOT: {{.*}}.pch

test/Driver/multi-threaded.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@
5858
// EXEC: ld
5959
// EXEC: /tmp/main{{[^ ]*}}.o /tmp/multi-threaded{{[^ ]*}}.o
6060

61-
// DEPENDENCIES-DAG: {{.*}}/multi-threaded.o : {{.*}}/Inputs/main.swift {{.*}}/multi-threaded.swift
62-
// DEPENDENCIES-DAG: {{.*}}/main.o : {{.*}}/Inputs/main.swift {{.*}}/multi-threaded.swift
61+
// DEPENDENCIES-DAG: {{.*}}/multi-threaded.o : {{.*}}/multi-threaded.swift {{.*}}/Inputs/main.swift
62+
// DEPENDENCIES-DAG: {{.*}}/main.o : {{.*}}/multi-threaded.swift {{.*}}/Inputs/main.swift
6363

6464
// PARSEABLE2: "name": "compile"
6565
// PARSEABLE2: "outputs": [

0 commit comments

Comments
 (0)