File: AbstractSourceFileDepGraphFactory.cpp

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (124 lines) | stat: -rw-r--r-- 5,178 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//===-------- AbstractSourceFileDepGraphFactory.cpp -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// 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
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/AST/AbstractSourceFileDepGraphFactory.h"

// may not all be needed
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/FileSystem.h"
#include "swift/AST/FineGrainedDependencies.h"
#include "swift/Basic/FileSystem.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/ReferenceDependencyKeys.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/VirtualOutputBackend.h"
#include "llvm/Support/YAMLParser.h"

using namespace swift;
using namespace fine_grained_dependencies;

//==============================================================================
// MARK: AbstractSourceFileDepGraphFactory - client interface
//==============================================================================

AbstractSourceFileDepGraphFactory::AbstractSourceFileDepGraphFactory(
    bool hadCompilationError, StringRef swiftDeps, Fingerprint fileFingerprint,
    bool emitDotFileAfterConstruction, DiagnosticEngine &diags,
    llvm::vfs::OutputBackend &backend)
    : hadCompilationError(hadCompilationError), swiftDeps(swiftDeps.str()),
      fileFingerprint(fileFingerprint),
      emitDotFileAfterConstruction(emitDotFileAfterConstruction), diags(diags),
      backend(backend) {}

SourceFileDepGraph AbstractSourceFileDepGraphFactory::construct() {
  addSourceFileNodesToGraph();
  if (!hadCompilationError) {
    addAllDefinedDecls();
    addAllUsedDecls();
  }
  assert(g.verify());
  if (emitDotFileAfterConstruction)
    g.emitDotFile(backend, swiftDeps, diags);
  return std::move(g);
}

//==============================================================================
// MARK: AbstractSourceFileDepGraphFactory - adding a defined or used Decl
//==============================================================================
void AbstractSourceFileDepGraphFactory::addSourceFileNodesToGraph() {
  g.findExistingNodePairOrCreateAndAddIfNew(
      DependencyKey::createKeyForWholeSourceFile(DeclAspect::interface,
                                                 swiftDeps),
      Fingerprint{fileFingerprint});
}

void AbstractSourceFileDepGraphFactory::addADefinedDecl(
    const DependencyKey &interfaceKey, std::optional<Fingerprint> fingerprint) {

  auto nodePair =
      g.findExistingNodePairOrCreateAndAddIfNew(interfaceKey, fingerprint);
  // Since the current type fingerprints only include tokens in the body,
  // when the interface hash changes, it is possible that the type in the
  // file has changed.
  g.addArc(g.getSourceFileNodePair().getInterface(), nodePair.getInterface());
}

void AbstractSourceFileDepGraphFactory::addAUsedDecl(
    const DependencyKey &defKey, const DependencyKey &useKey) {
  auto *defNode = g.findExistingNodeOrCreateIfNew(defKey, std::nullopt,
                                                  false /* = !isProvides */);

  // If the depended-upon node is defined in this file, then don't
  // create an arc to the user, when the user is the whole file.
  // Otherwise, if the defNode's type-body fingerprint changes,
  // the whole file will be marked as dirty, losing the benefit of the
  // fingerprint.

  //  if (defNode->getIsProvides() &&
  //      useKey.getKind() == NodeKind::sourceFileProvide)
  //    return;

  // Turns out the above three lines cause miscompiles, so comment them out
  // for now. We might want them back if we can change the inputs to this
  // function to be more precise.

  // Example of a miscompile:
  // In main.swift
  // func foo(_: Any) { print("Hello Any") }
  //    foo(123)
  // Then add the following line to another file:
  // func foo(_: Int) { print("Hello Int") }
  // Although main.swift needs to get recompiled, the commented-out code below
  // prevents that.

  auto nullableUse = g.findExistingNode(useKey);
  assert(nullableUse.isNonNull() && "Use must be an already-added provides");
  auto *useNode = nullableUse.get();
  assert(useNode->getIsProvides() && "Use (using node) must be a provides");
  g.addArc(defNode, useNode);
}

void AbstractSourceFileDepGraphFactory::addAnExternalDependency(
    const DependencyKey &defKey, const DependencyKey &useKey,
    std::optional<Fingerprint> maybeFP) {
  auto *defNode = g.findExistingNodeOrCreateIfNew(defKey, maybeFP,
                                                  false /* = !isProvides */);

  auto nullableUse = g.findExistingNode(useKey);
  assert(nullableUse.isNonNull() && "Use must be an already-added provides");
  auto *useNode = nullableUse.get();
  assert(useNode->getIsProvides() && "Use (using node) must be a provides");
  g.addArc(defNode, useNode);
}