Skip to content

Commit 7c92a8e

Browse files
committed
[SourceKit] Add a request to generate object files in SourceKit
Add 'request.compile'
1 parent 21e13c4 commit 7c92a8e

36 files changed

+1000
-84
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
SWIFT_TYPEID(ActorIsolation)
1919
SWIFT_TYPEID(AncestryFlags)
20+
SWIFT_TYPEID(BodyAndFingerprint)
2021
SWIFT_TYPEID(BodyInitKind)
2122
SWIFT_TYPEID(BodyInitKindAndExpr)
2223
SWIFT_TYPEID(CtorInitializerKind)

include/swift/AST/ASTTypeIDs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ enum class AncestryFlags : uint8_t;
8181
enum class ImplicitMemberAction : uint8_t;
8282
struct FingerprintAndMembers;
8383
class Identifier;
84+
class BodyAndFingerprint;
8485

8586
// Define the AST type zone (zone 1)
8687
#define SWIFT_TYPEID_ZONE AST

include/swift/AST/Decl.h

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5904,6 +5904,38 @@ class ImportAsMemberStatus {
59045904
}
59055905
};
59065906

5907+
class BodyAndFingerprint {
5908+
llvm::PointerIntPair<BraceStmt *, 1, bool> BodyAndHasFp;
5909+
Fingerprint Fp;
5910+
5911+
public:
5912+
BodyAndFingerprint(BraceStmt *body, Optional<Fingerprint> fp)
5913+
: BodyAndHasFp(body, fp.hasValue()),
5914+
Fp(fp.hasValue() ? *fp : Fingerprint::ZERO()) {}
5915+
BodyAndFingerprint() : BodyAndFingerprint(nullptr, None) {}
5916+
5917+
BraceStmt *getBody() const { return BodyAndHasFp.getPointer(); }
5918+
5919+
Optional<Fingerprint> getFingerprint() const {
5920+
if (BodyAndHasFp.getInt())
5921+
return Fp;
5922+
else
5923+
return None;
5924+
}
5925+
5926+
void setFingerprint(Optional<Fingerprint> fp) {
5927+
if (fp.hasValue()) {
5928+
Fp = *fp;
5929+
BodyAndHasFp.setInt(true);
5930+
} else {
5931+
Fp = Fingerprint::ZERO();
5932+
BodyAndHasFp.setInt(false);
5933+
}
5934+
}
5935+
};
5936+
5937+
void simple_display(llvm::raw_ostream &out, BodyAndFingerprint value);
5938+
59075939
/// Base class for function-like declarations.
59085940
class AbstractFunctionDecl : public GenericContext, public ValueDecl {
59095941
friend class NeedsNewVTableEntryRequest;
@@ -5986,7 +6018,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
59866018
union {
59876019
/// This enum member is active if getBodyKind() is BodyKind::Parsed or
59886020
/// BodyKind::TypeChecked.
5989-
BraceStmt *Body;
6021+
BodyAndFingerprint BodyAndFP;
59906022

59916023
/// This enum member is active if getBodyKind() is BodyKind::Deserialized.
59926024
StringRef BodyStringRepresentation;
@@ -6022,9 +6054,10 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
60226054
bool Throws, SourceLoc ThrowsLoc,
60236055
bool HasImplicitSelfDecl,
60246056
GenericParamList *GenericParams)
6025-
: GenericContext(DeclContextKind::AbstractFunctionDecl, Parent, GenericParams),
6026-
ValueDecl(Kind, Parent, Name, NameLoc),
6027-
Body(nullptr), AsyncLoc(AsyncLoc), ThrowsLoc(ThrowsLoc) {
6057+
: GenericContext(DeclContextKind::AbstractFunctionDecl, Parent,
6058+
GenericParams),
6059+
ValueDecl(Kind, Parent, Name, NameLoc), BodyAndFP(), AsyncLoc(AsyncLoc),
6060+
ThrowsLoc(ThrowsLoc) {
60286061
setBodyKind(BodyKind::None);
60296062
Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl;
60306063
Bits.AbstractFunctionDecl.Overridden = false;
@@ -6195,8 +6228,9 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
61956228
void setBodyToBeReparsed(SourceRange bodyRange);
61966229

61976230
/// Provide the parsed body for the function.
6198-
void setBodyParsed(BraceStmt *S) {
6231+
void setBodyParsed(BraceStmt *S, Optional<Fingerprint> fp = None) {
61996232
setBody(S, BodyKind::Parsed);
6233+
BodyAndFP.setFingerprint(fp);
62006234
}
62016235

62026236
/// Was there a nested type declaration detected when parsing this
@@ -6286,6 +6320,15 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
62866320
/// itself.
62876321
void keepOriginalBodySourceRange();
62886322

6323+
/// Retrieve the fingerprint of the body. Note that this is not affected by
6324+
/// the body of the local functions or the members of the local types in this
6325+
/// function.
6326+
Optional<Fingerprint> getBodyFingerprint() const;
6327+
6328+
/// Retrieve the fingerprint of the body including the local type members and
6329+
/// the local funcition bodies.
6330+
Optional<Fingerprint> getBodyFingerprintIncludingLocalTypeMembers() const;
6331+
62896332
/// Retrieve the source range of the *original* function body.
62906333
///
62916334
/// This may be different from \c getBodySourceRange() that returns the source

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ ERROR(error_immediate_mode_primary_file,none,
102102
"immediate mode is incompatible with -primary-file", ())
103103
ERROR(error_missing_frontend_action,none,
104104
"no frontend action was selected", ())
105+
ERROR(error_unsupported_frontend_action, none,
106+
"unsupported action: %0", (StringRef))
105107
ERROR(error_invalid_source_location_str,none,
106108
"invalid source location string '%0'", (StringRef))
107109
ERROR(error_no_source_location_scope_map,none,

include/swift/AST/ParseRequests.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,25 +63,25 @@ class ParseMembersRequest
6363
};
6464

6565
/// Parse the body of a function, initializer, or deinitializer.
66-
class ParseAbstractFunctionBodyRequest :
67-
public SimpleRequest<ParseAbstractFunctionBodyRequest,
68-
BraceStmt *(AbstractFunctionDecl *),
69-
RequestFlags::SeparatelyCached>
70-
{
66+
class ParseAbstractFunctionBodyRequest
67+
: public SimpleRequest<ParseAbstractFunctionBodyRequest,
68+
BodyAndFingerprint(AbstractFunctionDecl *),
69+
RequestFlags::SeparatelyCached> {
7170
public:
7271
using SimpleRequest::SimpleRequest;
7372

7473
private:
7574
friend SimpleRequest;
7675

7776
// Evaluation.
78-
BraceStmt *evaluate(Evaluator &evaluator, AbstractFunctionDecl *afd) const;
77+
BodyAndFingerprint evaluate(Evaluator &evaluator,
78+
AbstractFunctionDecl *afd) const;
7979

8080
public:
8181
// Caching
8282
bool isCached() const { return true; }
83-
Optional<BraceStmt *> getCachedResult() const;
84-
void cacheResult(BraceStmt *value) const;
83+
Optional<BodyAndFingerprint> getCachedResult() const;
84+
void cacheResult(BodyAndFingerprint value) const;
8585
};
8686

8787
struct SourceFileParsingResult {

include/swift/AST/ParseTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ SWIFT_REQUEST(Parse, CodeCompletionSecondPassRequest,
2020
SWIFT_REQUEST(Parse, ParseMembersRequest,
2121
FingerprintAndMembers(IterableDeclContext *), Cached, NoLocationInfo)
2222
SWIFT_REQUEST(Parse, ParseAbstractFunctionBodyRequest,
23-
BraceStmt *(AbstractFunctionDecl *), SeparatelyCached,
23+
BodyAndFingerprint(AbstractFunctionDecl *), SeparatelyCached,
2424
NoLocationInfo)
2525
SWIFT_REQUEST(Parse, ParseSourceFileRequest,
2626
SourceFileParsingResult(SourceFile *), SeparatelyCached,

include/swift/Basic/SourceManager.h

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,10 @@ class SourceManager {
5050
/// to speed up stats.
5151
mutable llvm::DenseMap<StringRef, llvm::vfs::Status> StatusCache;
5252

53-
struct ReplacedRangeType {
54-
SourceRange Original;
55-
SourceRange New;
56-
ReplacedRangeType() {}
57-
ReplacedRangeType(NoneType) {}
58-
ReplacedRangeType(SourceRange Original, SourceRange New)
59-
: Original(Original), New(New) {
60-
assert(Original.isValid() && New.isValid());
61-
}
62-
63-
explicit operator bool() const { return Original.isValid(); }
64-
};
65-
ReplacedRangeType ReplacedRange;
53+
/// Holds replaced ranges. Keys are orignal ranges, and values are new ranges
54+
/// in different buffers. This is used for code completion and ASTContext
55+
/// reusing compilation.
56+
llvm::DenseMap<SourceRange, SourceRange> ReplacedRanges;
6657

6758
std::map<const char *, VirtualFile> VirtualFiles;
6859
mutable std::pair<const char *, const VirtualFile*> CachedVFile = {nullptr, nullptr};
@@ -109,8 +100,12 @@ class SourceManager {
109100

110101
SourceLoc getCodeCompletionLoc() const;
111102

112-
const ReplacedRangeType &getReplacedRange() const { return ReplacedRange; }
113-
void setReplacedRange(const ReplacedRangeType &val) { ReplacedRange = val; }
103+
const llvm::DenseMap<SourceRange, SourceRange> &getReplacedRanges() const {
104+
return ReplacedRanges;
105+
}
106+
void setReplacedRange(SourceRange Orig, SourceRange New) {
107+
ReplacedRanges[Orig] = New;
108+
}
114109

115110
/// Returns true if \c LHS is before \c RHS in the source buffer.
116111
bool isBeforeInBuffer(SourceLoc LHS, SourceLoc RHS) const {

include/swift/Frontend/Frontend.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353

5454
namespace swift {
5555

56+
class FrontendObserver;
5657
class SerializedModuleLoaderBase;
5758
class MemoryBufferSerializedModuleLoader;
5859
class SILModule;
@@ -663,6 +664,9 @@ class CompilerInstance {
663664
/// library, returning \c false if we should continue, i.e. no error.
664665
bool loadStdlibIfNeeded();
665666

667+
/// If \p fn returns true, exits early and returns true.
668+
bool forEachFileToTypeCheck(llvm::function_ref<bool(SourceFile &)> fn);
669+
666670
private:
667671
/// Compute the parsing options for a source file in the main module.
668672
SourceFile::ParsingOptions getSourceFileParsingOptions(bool forPrimary) const;
@@ -676,8 +680,6 @@ class CompilerInstance {
676680
bool loadPartialModulesAndImplicitImports(
677681
ModuleDecl *mod, SmallVectorImpl<FileUnit *> &partialModules) const;
678682

679-
void forEachFileToTypeCheck(llvm::function_ref<void(SourceFile &)> fn);
680-
681683
void finishTypeChecking();
682684

683685
public:

include/swift/Frontend/FrontendOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,10 @@ class FrontendOptions {
438438
/// Whether to include symbols with SPI information in the symbol graph.
439439
bool IncludeSPISymbolsInSymbolGraph = false;
440440

441+
/// Whether to reuse a frontend (i.e. compiler instance) for multiple
442+
/// compiletions. This prevents ASTContext being freed.
443+
bool ReuseFrontendForMutipleCompilations = false;
444+
441445
/// This is used to obfuscate the serialized search paths so we don't have
442446
/// to encode the actual paths into the .swiftmodule file.
443447
PathObfuscator serializedPathObfuscator;

include/swift/FrontendTool/FrontendTool.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ int performFrontend(ArrayRef<const char *> args,
7878
void *mainAddr,
7979
FrontendObserver *observer = nullptr);
8080

81+
bool performCompileStepsPostSema(CompilerInstance &Instance, int &ReturnValue,
82+
FrontendObserver *observer);
8183

8284
} // namespace swift
8385

include/swift/IDE/CompileInstance.h

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//===--- CompileInstance.h ------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021 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+
#ifndef SWIFT_IDE_COMPILEINSTANCE_H
14+
#define SWIFT_IDE_COMPILEINSTANCE_H
15+
16+
#include "swift/Frontend/Frontend.h"
17+
#include "llvm/ADT/Hashing.h"
18+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
19+
#include "llvm/ADT/StringRef.h"
20+
#include "llvm/Support/Chrono.h"
21+
#include "llvm/Support/MemoryBuffer.h"
22+
#include "llvm/Support/VirtualFileSystem.h"
23+
24+
namespace swift {
25+
26+
class CompilerInstance;
27+
class CompilerInvocation;
28+
class DiagnosticConsumer;
29+
30+
namespace ide {
31+
32+
/// Manages \c CompilerInstance for completion like operations.
33+
class CompileInstance {
34+
const std::string &RuntimeResourcePath;
35+
const std::string &DiagnosticDocumentationPath;
36+
37+
struct Options {
38+
unsigned MaxASTReuseCount = 100;
39+
} Opts;
40+
41+
std::mutex mtx;
42+
43+
std::unique_ptr<CompilerInstance> CI;
44+
llvm::hash_code CachedArgHash;
45+
std::atomic<bool> CachedCIInvalidated;
46+
unsigned CachedReuseCount;
47+
48+
/// Perform cached sema. Returns \c true if the CI is not reusable.
49+
bool performCachedSemaIfPossible(DiagnosticConsumer *DiagC);
50+
51+
/// Setup the CI with \p Args . Returns \c true if failed.
52+
bool setupCI(llvm::ArrayRef<const char *> Args,
53+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
54+
DiagnosticConsumer *DiagC);
55+
56+
/// Perform Parse and Sema, potentially CI from previous compilation is
57+
/// reused.
58+
void performSema(llvm::ArrayRef<const char *> Args,
59+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
60+
DiagnosticConsumer *DiagC,
61+
std::shared_ptr<std::atomic<bool>> CancellationFlag);
62+
63+
public:
64+
CompileInstance(const std::string &RuntimeResourcePath,
65+
const std::string &DiagnosticDocumentationPath)
66+
: RuntimeResourcePath(RuntimeResourcePath),
67+
DiagnosticDocumentationPath(DiagnosticDocumentationPath),
68+
CachedCIInvalidated(false), CachedReuseCount(0) {}
69+
70+
/// NOTE: \p Args is only used for checking the equaity of the invocation.
71+
/// Since this function assumes that it is already normalized, exact the same
72+
/// arguments including their order is considered as the same invocation.
73+
bool
74+
performCompile(llvm::ArrayRef<const char *> Args,
75+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
76+
DiagnosticConsumer *DiagC,
77+
std::shared_ptr<std::atomic<bool>> CancellationFlag);
78+
};
79+
80+
} // namespace ide
81+
} // namespace swift
82+
83+
#endif // SWIFT_IDE_COMPILEINSTANCE_H

include/swift/Parse/Parser.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,9 +1195,11 @@ class Parser {
11951195
ParseDeclOptions Flags,
11961196
DeclAttributes &Attributes,
11971197
bool HasFuncKeyword = true);
1198-
BraceStmt *parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD);
1198+
BodyAndFingerprint
1199+
parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD);
11991200
void parseAbstractFunctionBody(AbstractFunctionDecl *AFD);
1200-
BraceStmt *parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD);
1201+
BodyAndFingerprint
1202+
parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD);
12011203
ParserResult<ProtocolDecl> parseDeclProtocol(ParseDeclOptions Flags,
12021204
DeclAttributes &Attributes);
12031205

lib/AST/ASTScopeLookup.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ ASTScopeImpl *ASTScopeImpl::findInnermostEnclosingScopeImpl(
7878
static SourceLoc translateLocForReplacedRange(SourceManager &sourceMgr,
7979
CharSourceRange range,
8080
SourceLoc loc) {
81-
if (const auto &replacedRange = sourceMgr.getReplacedRange()) {
82-
if (sourceMgr.rangeContainsTokenLoc(replacedRange.New, loc) &&
83-
!sourceMgr.rangeContainsTokenLoc(replacedRange.New, range.getStart())) {
84-
return replacedRange.Original.Start;
81+
for (const auto &pair : sourceMgr.getReplacedRanges()) {
82+
if (sourceMgr.rangeContainsTokenLoc(pair.second, loc) &&
83+
!sourceMgr.rangeContainsTokenLoc(pair.second, range.getStart())) {
84+
return pair.first.Start;
8585
}
8686
}
8787
return loc;

lib/AST/ASTScopeSourceRange.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,11 @@ void ASTScopeImpl::checkSourceRangeBeforeAddingChild(ASTScopeImpl *child,
5555

5656
bool childContainedInParent = [&]() {
5757
// HACK: For code completion. Handle replaced range.
58-
if (const auto &replacedRange = sourceMgr.getReplacedRange()) {
59-
auto originalRange = Lexer::getCharSourceRangeFromSourceRange(
60-
sourceMgr, replacedRange.Original);
61-
auto newRange = Lexer::getCharSourceRangeFromSourceRange(
62-
sourceMgr, replacedRange.New);
63-
58+
for (const auto &pair : sourceMgr.getReplacedRanges()) {
59+
auto originalRange =
60+
Lexer::getCharSourceRangeFromSourceRange(sourceMgr, pair.first);
61+
auto newRange =
62+
Lexer::getCharSourceRangeFromSourceRange(sourceMgr, pair.second);
6463
if (range.contains(originalRange) &&
6564
newRange.contains(childCharRange))
6665
return true;

0 commit comments

Comments
 (0)