mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #18016 from ahoppen/003-incremental-syntax-coloring
[libSyntax] Incremental syntax colouring
This commit is contained in:
@@ -27,6 +27,7 @@
|
|||||||
#include "llvm/Support/Regex.h"
|
#include "llvm/Support/Regex.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace swift {
|
namespace swift {
|
||||||
@@ -341,6 +342,10 @@ struct unvalidatedObjectTraits : public std::integral_constant<bool,
|
|||||||
&& !has_ObjectValidateTraits<T>::value> {};
|
&& !has_ObjectValidateTraits<T>::value> {};
|
||||||
|
|
||||||
class Output {
|
class Output {
|
||||||
|
public:
|
||||||
|
using UserInfoMap = std::map<void *, void *>;
|
||||||
|
|
||||||
|
private:
|
||||||
enum State {
|
enum State {
|
||||||
ArrayFirstValue,
|
ArrayFirstValue,
|
||||||
ArrayOtherValue,
|
ArrayOtherValue,
|
||||||
@@ -353,13 +358,19 @@ class Output {
|
|||||||
bool PrettyPrint;
|
bool PrettyPrint;
|
||||||
bool NeedBitValueComma;
|
bool NeedBitValueComma;
|
||||||
bool EnumerationMatchFound;
|
bool EnumerationMatchFound;
|
||||||
|
UserInfoMap UserInfo;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Output(llvm::raw_ostream &os, bool PrettyPrint = true) : Stream(os),
|
Output(llvm::raw_ostream &os, UserInfoMap UserInfo = {},
|
||||||
PrettyPrint(PrettyPrint), NeedBitValueComma(false),
|
bool PrettyPrint = true)
|
||||||
EnumerationMatchFound(false) {}
|
: Stream(os), PrettyPrint(PrettyPrint), NeedBitValueComma(false),
|
||||||
|
EnumerationMatchFound(false), UserInfo(UserInfo) {}
|
||||||
virtual ~Output() = default;
|
virtual ~Output() = default;
|
||||||
|
|
||||||
|
UserInfoMap &getUserInfo() {
|
||||||
|
return UserInfo;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned beginArray();
|
unsigned beginArray();
|
||||||
bool preflightElement(unsigned, void *&);
|
bool preflightElement(unsigned, void *&);
|
||||||
void postflightElement(void*);
|
void postflightElement(void*);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public:
|
|||||||
OwnedString(): OwnedString(nullptr, 0, StringOwnership::Unowned) {}
|
OwnedString(): OwnedString(nullptr, 0, StringOwnership::Unowned) {}
|
||||||
|
|
||||||
OwnedString(const char *Data, size_t Length):
|
OwnedString(const char *Data, size_t Length):
|
||||||
OwnedString(Data, Length, StringOwnership::Unowned) {}
|
OwnedString(Data, Length, StringOwnership::Copied) {}
|
||||||
|
|
||||||
OwnedString(StringRef Str) : OwnedString(Str.data(), Str.size()) {}
|
OwnedString(StringRef Str) : OwnedString(Str.data(), Str.size()) {}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnedString copy() {
|
OwnedString copy() const {
|
||||||
return OwnedString(Data, Length, StringOwnership::Copied);
|
return OwnedString(Data, Length, StringOwnership::Copied);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,13 @@ namespace swift {
|
|||||||
|
|
||||||
using namespace swift::syntax;
|
using namespace swift::syntax;
|
||||||
|
|
||||||
|
struct SyntaxReuseRegion {
|
||||||
|
/// The byte offset at which the range begins
|
||||||
|
uintptr_t Start;
|
||||||
|
/// The byte offset at which the end ends
|
||||||
|
uintptr_t End;
|
||||||
|
};
|
||||||
|
|
||||||
class SyntaxParsingCache {
|
class SyntaxParsingCache {
|
||||||
/// The syntax tree prior to the edit
|
/// The syntax tree prior to the edit
|
||||||
SourceFileSyntax OldSyntaxTree;
|
SourceFileSyntax OldSyntaxTree;
|
||||||
@@ -61,7 +68,7 @@ class SyntaxParsingCache {
|
|||||||
|
|
||||||
/// If \c RecordReuseInformation buffer offsets of ranges that have been
|
/// If \c RecordReuseInformation buffer offsets of ranges that have been
|
||||||
/// successfully looked up in this cache are stored.
|
/// successfully looked up in this cache are stored.
|
||||||
std::vector<std::pair<unsigned, unsigned>> ReusedRanges;
|
std::vector<SyntaxReuseRegion> ReusedRanges;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SyntaxParsingCache(SourceFileSyntax OldSyntaxTree)
|
SyntaxParsingCache(SourceFileSyntax OldSyntaxTree)
|
||||||
@@ -85,7 +92,7 @@ public:
|
|||||||
/// Return the ranges of the new source file that have been successfully
|
/// Return the ranges of the new source file that have been successfully
|
||||||
/// looked up in this cache as a (start, end) pair of byte offsets in the
|
/// looked up in this cache as a (start, end) pair of byte offsets in the
|
||||||
/// post-edit file.
|
/// post-edit file.
|
||||||
std::vector<std::pair<unsigned, unsigned>> getReusedRanges() const {
|
std::vector<SyntaxReuseRegion> getReusedRanges() const {
|
||||||
return ReusedRanges;
|
return ReusedRanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ namespace swift {
|
|||||||
class SILParserTUState;
|
class SILParserTUState;
|
||||||
class SourceFile;
|
class SourceFile;
|
||||||
class SourceManager;
|
class SourceManager;
|
||||||
|
class SyntaxParsingCache;
|
||||||
class Token;
|
class Token;
|
||||||
class TopLevelContext;
|
class TopLevelContext;
|
||||||
struct TypeLoc;
|
struct TypeLoc;
|
||||||
@@ -327,7 +328,8 @@ namespace swift {
|
|||||||
class ParserUnit {
|
class ParserUnit {
|
||||||
public:
|
public:
|
||||||
ParserUnit(SourceManager &SM, unsigned BufferID,
|
ParserUnit(SourceManager &SM, unsigned BufferID,
|
||||||
const LangOptions &LangOpts, StringRef ModuleName);
|
const LangOptions &LangOpts, StringRef ModuleName,
|
||||||
|
SyntaxParsingCache *SyntaxCache = nullptr);
|
||||||
ParserUnit(SourceManager &SM, unsigned BufferID);
|
ParserUnit(SourceManager &SM, unsigned BufferID);
|
||||||
ParserUnit(SourceManager &SM, unsigned BufferID,
|
ParserUnit(SourceManager &SM, unsigned BufferID,
|
||||||
unsigned Offset, unsigned EndOffset);
|
unsigned Offset, unsigned EndOffset);
|
||||||
|
|||||||
@@ -27,6 +27,10 @@
|
|||||||
namespace swift {
|
namespace swift {
|
||||||
namespace json {
|
namespace json {
|
||||||
|
|
||||||
|
/// The associated value will be interpreted as \c bool. If \c true the node IDs
|
||||||
|
/// will not be included in the serialized JSON.
|
||||||
|
static void *DontSerializeNodeIdsUserInfoKey = &DontSerializeNodeIdsUserInfoKey;
|
||||||
|
|
||||||
/// Serialization traits for SourcePresence.
|
/// Serialization traits for SourcePresence.
|
||||||
template <>
|
template <>
|
||||||
struct ScalarEnumerationTraits<syntax::SourcePresence> {
|
struct ScalarEnumerationTraits<syntax::SourcePresence> {
|
||||||
@@ -141,8 +145,12 @@ struct ObjectTraits<syntax::RawSyntax> {
|
|||||||
}
|
}
|
||||||
auto presence = value.getPresence();
|
auto presence = value.getPresence();
|
||||||
out.mapRequired("presence", presence);
|
out.mapRequired("presence", presence);
|
||||||
auto nodeId = value.getId();
|
|
||||||
out.mapRequired("id", nodeId);
|
bool omitNodeId = (bool)out.getUserInfo()[DontSerializeNodeIdsUserInfoKey];
|
||||||
|
if (!omitNodeId) {
|
||||||
|
auto nodeId = value.getId();
|
||||||
|
out.mapRequired("id", nodeId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -242,7 +242,8 @@ static bool emitLoadedModuleTraceIfNeeded(ASTContext &ctxt,
|
|||||||
std::string stringBuffer;
|
std::string stringBuffer;
|
||||||
{
|
{
|
||||||
llvm::raw_string_ostream memoryBuffer(stringBuffer);
|
llvm::raw_string_ostream memoryBuffer(stringBuffer);
|
||||||
json::Output jsonOutput(memoryBuffer, /*PrettyPrint=*/false);
|
json::Output jsonOutput(memoryBuffer, /*UserInfo=*/{},
|
||||||
|
/*PrettyPrint=*/false);
|
||||||
json::jsonize(jsonOutput, trace, /*Required=*/true);
|
json::jsonize(jsonOutput, trace, /*Required=*/true);
|
||||||
}
|
}
|
||||||
stringBuffer += "\n";
|
stringBuffer += "\n";
|
||||||
@@ -289,7 +290,7 @@ static bool emitSyntax(SourceFile *SF, LangOptions &LangOpts,
|
|||||||
auto os = getFileOutputStream(OutputFilename, SF->getASTContext());
|
auto os = getFileOutputStream(OutputFilename, SF->getASTContext());
|
||||||
if (!os) return true;
|
if (!os) return true;
|
||||||
|
|
||||||
json::Output jsonOut(*os, /*PrettyPrint=*/false);
|
json::Output jsonOut(*os, /*UserInfo=*/{}, /*PrettyPrint=*/false);
|
||||||
auto Root = SF->getSyntaxRoot().getRaw();
|
auto Root = SF->getSyntaxRoot().getRaw();
|
||||||
jsonOut << *Root;
|
jsonOut << *Root;
|
||||||
*os << "\n";
|
*os << "\n";
|
||||||
|
|||||||
@@ -1018,9 +1018,11 @@ ParserUnit::ParserUnit(SourceManager &SM, unsigned BufferID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ParserUnit::ParserUnit(SourceManager &SM, unsigned BufferID,
|
ParserUnit::ParserUnit(SourceManager &SM, unsigned BufferID,
|
||||||
const LangOptions &LangOpts, StringRef ModuleName)
|
const LangOptions &LangOpts, StringRef ModuleName,
|
||||||
: Impl(*new Implementation(SM, BufferID, LangOpts, ModuleName)) {
|
SyntaxParsingCache *SyntaxCache)
|
||||||
|
: Impl(*new Implementation(SM, BufferID, LangOpts, ModuleName)) {
|
||||||
|
|
||||||
|
Impl.SF->SyntaxParsingCache = SyntaxCache;
|
||||||
Impl.TheParser.reset(new Parser(BufferID, *Impl.SF, nullptr));
|
Impl.TheParser.reset(new Parser(BufferID, *Impl.SF, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
// RUN: %empty-directory(%t)
|
// RUN: %empty-directory(%t)
|
||||||
// RUN: %incparse-test %s --test-case NO_CHANGES
|
// RUN: %incparse-test %s --test-case NO_CHANGES
|
||||||
|
// RUN: %incparse-test %s --test-case NESTED_INITIALIZERS
|
||||||
|
|
||||||
func start() {}
|
func start() {}
|
||||||
|
|
||||||
class Bar
|
class Bar
|
||||||
|
|
||||||
let y = 1
|
let y = 1
|
||||||
|
|
||||||
|
class NestedInitializers {
|
||||||
|
<<NESTED_INITIALIZERS<|||init() {>>>
|
||||||
|
init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
<<NESTED_INITIALIZERS<|||}>>>
|
||||||
|
}
|
||||||
|
|||||||
@@ -188,6 +188,13 @@ struct DiagnosticEntryInfo : DiagnosticEntryInfoBase {
|
|||||||
SmallVector<DiagnosticEntryInfoBase, 1> Notes;
|
SmallVector<DiagnosticEntryInfoBase, 1> Notes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SourceFileRange {
|
||||||
|
/// The byte offset at which the range begins
|
||||||
|
uintptr_t Start;
|
||||||
|
/// The byte offset at which the end ends
|
||||||
|
uintptr_t End;
|
||||||
|
};
|
||||||
|
|
||||||
class EditorConsumer {
|
class EditorConsumer {
|
||||||
virtual void anchor();
|
virtual void anchor();
|
||||||
public:
|
public:
|
||||||
@@ -240,6 +247,10 @@ public:
|
|||||||
virtual bool handleSerializedSyntaxTree(StringRef Text) = 0;
|
virtual bool handleSerializedSyntaxTree(StringRef Text) = 0;
|
||||||
virtual bool syntaxTreeEnabled() = 0;
|
virtual bool syntaxTreeEnabled() = 0;
|
||||||
|
|
||||||
|
virtual bool syntaxReuseInfoEnabled() = 0;
|
||||||
|
virtual bool handleSyntaxReuseRegions(
|
||||||
|
std::vector<SourceFileRange> ReuseRegions) = 0;
|
||||||
|
|
||||||
virtual void finished() {}
|
virtual void finished() {}
|
||||||
|
|
||||||
// FIXME: This is just for bootstrapping incremental syntax tree parsing.
|
// FIXME: This is just for bootstrapping incremental syntax tree parsing.
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#include "swift/Syntax/SyntaxNodes.h"
|
#include "swift/Syntax/SyntaxNodes.h"
|
||||||
|
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
|
#include "llvm/Support/FileSystem.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include "llvm/Support/Mutex.h"
|
#include "llvm/Support/Mutex.h"
|
||||||
|
|
||||||
@@ -773,6 +774,9 @@ class SwiftDocumentSyntaxInfo {
|
|||||||
unsigned BufferID;
|
unsigned BufferID;
|
||||||
std::vector<std::string> Args;
|
std::vector<std::string> Args;
|
||||||
std::string PrimaryFile;
|
std::string PrimaryFile;
|
||||||
|
/// Whether or not the AST stored in the source file is up-to-date or just an
|
||||||
|
/// artifact of incremental syntax parsing
|
||||||
|
bool HasUpToDateAST;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SwiftDocumentSyntaxInfo(const CompilerInvocation &CompInv,
|
SwiftDocumentSyntaxInfo(const CompilerInvocation &CompInv,
|
||||||
@@ -792,10 +796,15 @@ public:
|
|||||||
Parser.reset(
|
Parser.reset(
|
||||||
new ParserUnit(SM, BufferID,
|
new ParserUnit(SM, BufferID,
|
||||||
CompInv.getLangOptions(),
|
CompInv.getLangOptions(),
|
||||||
CompInv.getModuleName())
|
CompInv.getModuleName(),
|
||||||
|
CompInv.getMainFileSyntaxParsingCache())
|
||||||
);
|
);
|
||||||
|
|
||||||
Parser->getDiagnosticEngine().addConsumer(DiagConsumer);
|
Parser->getDiagnosticEngine().addConsumer(DiagConsumer);
|
||||||
|
|
||||||
|
// If there is a syntax parsing cache, incremental syntax parsing is
|
||||||
|
// performed and thus the generated AST may not be up-to-date.
|
||||||
|
HasUpToDateAST = CompInv.getMainFileSyntaxParsingCache() == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse() {
|
void parse() {
|
||||||
@@ -824,6 +833,8 @@ public:
|
|||||||
return SM;
|
return SM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasUpToDateAST() { return HasUpToDateAST; }
|
||||||
|
|
||||||
ArrayRef<DiagnosticEntryInfo> getDiagnostics() {
|
ArrayRef<DiagnosticEntryInfo> getDiagnostics() {
|
||||||
return DiagConsumer.getDiagnosticsForBuffer(BufferID);
|
return DiagConsumer.getDiagnosticsForBuffer(BufferID);
|
||||||
}
|
}
|
||||||
@@ -1138,6 +1149,8 @@ struct SwiftEditorDocument::Implementation {
|
|||||||
llvm::Optional<SwiftEditorCharRange> AffectedRange;
|
llvm::Optional<SwiftEditorCharRange> AffectedRange;
|
||||||
/// Whether the last operation was an edit rather than a document open
|
/// Whether the last operation was an edit rather than a document open
|
||||||
bool Edited;
|
bool Edited;
|
||||||
|
/// The syntax tree of the document
|
||||||
|
llvm::Optional<SourceFileSyntax> SyntaxTree;
|
||||||
|
|
||||||
std::vector<DiagnosticEntryInfo> ParserDiagnostics;
|
std::vector<DiagnosticEntryInfo> ParserDiagnostics;
|
||||||
RefPtr<SwiftDocumentSemanticInfo> SemanticInfo;
|
RefPtr<SwiftDocumentSemanticInfo> SemanticInfo;
|
||||||
@@ -1853,7 +1866,8 @@ void SwiftEditorDocument::updateSemaInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SwiftEditorDocument::parse(ImmutableTextSnapshotRef Snapshot,
|
void SwiftEditorDocument::parse(ImmutableTextSnapshotRef Snapshot,
|
||||||
SwiftLangSupport &Lang, bool BuildSyntexTree) {
|
SwiftLangSupport &Lang, bool BuildSyntaxTree,
|
||||||
|
SyntaxParsingCache *SyntaxCache) {
|
||||||
llvm::sys::ScopedLock L(Impl.AccessMtx);
|
llvm::sys::ScopedLock L(Impl.AccessMtx);
|
||||||
|
|
||||||
assert(Impl.SemanticInfo && "Impl.SemanticInfo must be set");
|
assert(Impl.SemanticInfo && "Impl.SemanticInfo must be set");
|
||||||
@@ -1876,7 +1890,11 @@ void SwiftEditorDocument::parse(ImmutableTextSnapshotRef Snapshot,
|
|||||||
Lang.getASTManager().
|
Lang.getASTManager().
|
||||||
initCompilerInvocation(CompInv, Args, StringRef(), Error);
|
initCompilerInvocation(CompInv, Args, StringRef(), Error);
|
||||||
}
|
}
|
||||||
CompInv.getLangOptions().BuildSyntaxTree = BuildSyntexTree;
|
CompInv.getLangOptions().BuildSyntaxTree = BuildSyntaxTree;
|
||||||
|
CompInv.setMainFileSyntaxParsingCache(SyntaxCache);
|
||||||
|
// When reuse parts of the syntax tree from a SyntaxParsingCache, not
|
||||||
|
// all tokens are visited and thus token collection is invalid
|
||||||
|
CompInv.getLangOptions().CollectParsedToken = (SyntaxCache == nullptr);
|
||||||
// Access to Impl.SyntaxInfo is guarded by Impl.AccessMtx
|
// Access to Impl.SyntaxInfo is guarded by Impl.AccessMtx
|
||||||
Impl.SyntaxInfo.reset(
|
Impl.SyntaxInfo.reset(
|
||||||
new SwiftDocumentSyntaxInfo(CompInv, Snapshot, Args, Impl.FilePath));
|
new SwiftDocumentSyntaxInfo(CompInv, Snapshot, Args, Impl.FilePath));
|
||||||
@@ -1892,7 +1910,7 @@ void SwiftEditorDocument::readSyntaxInfo(EditorConsumer &Consumer) {
|
|||||||
if (Consumer.syntaxTreeEnabled()) {
|
if (Consumer.syntaxTreeEnabled()) {
|
||||||
std::string SyntaxContent;
|
std::string SyntaxContent;
|
||||||
llvm::raw_string_ostream OS(SyntaxContent);
|
llvm::raw_string_ostream OS(SyntaxContent);
|
||||||
json::Output JsonOut(OS, /*PrettyPrint=*/false);
|
json::Output JsonOut(OS, /*UserInfo=*/{}, /*PrettyPrint=*/false);
|
||||||
auto Root = Impl.SyntaxInfo->getSourceFile().getSyntaxRoot().getRaw();
|
auto Root = Impl.SyntaxInfo->getSourceFile().getSyntaxRoot().getRaw();
|
||||||
JsonOut << *Root;
|
JsonOut << *Root;
|
||||||
Consumer.handleSerializedSyntaxTree(OS.str());
|
Consumer.handleSerializedSyntaxTree(OS.str());
|
||||||
@@ -1907,6 +1925,7 @@ void SwiftEditorDocument::readSyntaxInfo(EditorConsumer &Consumer) {
|
|||||||
auto Classification = Classifier.classify(SyntaxTree);
|
auto Classification = Classifier.classify(SyntaxTree);
|
||||||
SyntaxToSyntaxMapConverter Printer(NewMap, Classification);
|
SyntaxToSyntaxMapConverter Printer(NewMap, Classification);
|
||||||
Printer.writeToSyntaxMap(SyntaxTree);
|
Printer.writeToSyntaxMap(SyntaxTree);
|
||||||
|
Impl.SyntaxTree.emplace(SyntaxTree);
|
||||||
} else {
|
} else {
|
||||||
ide::SyntaxModelContext ModelContext(Impl.SyntaxInfo->getSourceFile());
|
ide::SyntaxModelContext ModelContext(Impl.SyntaxInfo->getSourceFile());
|
||||||
|
|
||||||
@@ -1989,6 +2008,29 @@ const CodeFormatOptions &SwiftEditorDocument::getFormatOptions() {
|
|||||||
return Impl.FormatOptions;
|
return Impl.FormatOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const llvm::Optional<swift::SourceFileSyntax> &
|
||||||
|
SwiftEditorDocument::getSyntaxTree() const {
|
||||||
|
return Impl.SyntaxTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SourceManager &SwiftEditorDocument::getSourceManager() const {
|
||||||
|
return Impl.SyntaxInfo->getSourceManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceManager &SwiftEditorDocument::getSourceManager() {
|
||||||
|
return Impl.SyntaxInfo->getSourceManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned SwiftEditorDocument::getBufferID() const {
|
||||||
|
return Impl.SyntaxInfo->getBufferID();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SwiftEditorDocument::getFilePath() const { return Impl.FilePath; }
|
||||||
|
|
||||||
|
bool SwiftEditorDocument::hasUpToDateAST() const {
|
||||||
|
return Impl.SyntaxInfo->hasUpToDateAST();
|
||||||
|
}
|
||||||
|
|
||||||
void SwiftEditorDocument::formatText(unsigned Line, unsigned Length,
|
void SwiftEditorDocument::formatText(unsigned Line, unsigned Length,
|
||||||
EditorConsumer &Consumer) {
|
EditorConsumer &Consumer) {
|
||||||
auto SyntaxInfo = Impl.getSyntaxInfo();
|
auto SyntaxInfo = Impl.getSyntaxInfo();
|
||||||
@@ -2212,10 +2254,98 @@ void SwiftLangSupport::editorClose(StringRef Name, bool RemoveCache) {
|
|||||||
// EditorReplaceText
|
// EditorReplaceText
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
void verifyIncrementalParse(SwiftEditorDocumentRef EditorDoc,
|
||||||
|
unsigned EditOffset, unsigned EditLength,
|
||||||
|
StringRef PreEditText, StringRef ReplaceText) {
|
||||||
|
swift::json::Output::UserInfoMap JsonUserInfo;
|
||||||
|
JsonUserInfo[swift::json::DontSerializeNodeIdsUserInfoKey] =
|
||||||
|
reinterpret_cast<void *>(true);
|
||||||
|
|
||||||
|
// Dump the incremental syntax tree
|
||||||
|
std::string IncrTreeString;
|
||||||
|
llvm::raw_string_ostream IncrTreeStream(IncrTreeString);
|
||||||
|
swift::json::Output IncrTreeOutput(IncrTreeStream, JsonUserInfo);
|
||||||
|
IncrTreeOutput << *EditorDoc->getSyntaxTree()->getRaw();
|
||||||
|
|
||||||
|
// Reparse the file from scratch
|
||||||
|
CompilerInvocation Invocation;
|
||||||
|
Invocation.getLangOptions().BuildSyntaxTree = true;
|
||||||
|
std::vector<std::string> Args;
|
||||||
|
SwiftDocumentSyntaxInfo ScratchSyntaxInfo(Invocation,
|
||||||
|
EditorDoc->getLatestSnapshot(),
|
||||||
|
Args, EditorDoc->getFilePath());
|
||||||
|
ScratchSyntaxInfo.parse();
|
||||||
|
|
||||||
|
// Dump the from-scratch syntax tree
|
||||||
|
std::string FromScratchTreeString;
|
||||||
|
llvm::raw_string_ostream ScratchTreeStream(FromScratchTreeString);
|
||||||
|
swift::json::Output ScratchTreeOutput(ScratchTreeStream, JsonUserInfo);
|
||||||
|
auto SyntaxRoot = ScratchSyntaxInfo.getSourceFile().getSyntaxRoot();
|
||||||
|
ScratchTreeOutput << *SyntaxRoot.getRaw();
|
||||||
|
|
||||||
|
// If the serialized format of the two trees doesn't match incremental parsing
|
||||||
|
// we have found an error.
|
||||||
|
if (IncrTreeStream.str().compare(ScratchTreeStream.str())) {
|
||||||
|
LOG_SECTION("Incremental Parsing", Warning) {
|
||||||
|
Log->getOS() << "Incremental parsing different to from scratch parsing\n";
|
||||||
|
Log->getOS() << "Edit was " << EditOffset << "-"
|
||||||
|
<< (EditOffset + EditLength) << "='" << ReplaceText << "'"
|
||||||
|
<< " pre-edit-text: '" << PreEditText << "'\n";
|
||||||
|
|
||||||
|
SmallString<32> DirectoryName;
|
||||||
|
if (llvm::sys::fs::createUniqueDirectory(
|
||||||
|
"SourceKit-IncrementalParsing-Inconsistency", DirectoryName)) {
|
||||||
|
Log->getOS() << "Failed to create log directory\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ErrorCode;
|
||||||
|
|
||||||
|
// Write the incremental syntax tree
|
||||||
|
auto IncrTreeFilename = DirectoryName + "/incrementalTree.json";
|
||||||
|
llvm::raw_fd_ostream IncrementalFilestream(
|
||||||
|
IncrTreeFilename.str(), ErrorCode, llvm::sys::fs::F_RW);
|
||||||
|
IncrementalFilestream << IncrTreeStream.str();
|
||||||
|
if (ErrorCode) {
|
||||||
|
Log->getOS() << "Failed to write incremental syntax tree to "
|
||||||
|
<< IncrTreeFilename << "(error code " << ErrorCode.value()
|
||||||
|
<< ": " << ErrorCode.message() << ")\n";
|
||||||
|
} else {
|
||||||
|
Log->getOS() << "Incremental syntax tree written to "
|
||||||
|
<< IncrTreeFilename << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write from-scratch syntax tree
|
||||||
|
auto ScratchTreeFilename = DirectoryName + "/fromScratchTree.json";
|
||||||
|
llvm::raw_fd_ostream ScratchTreeFilestream(
|
||||||
|
ScratchTreeFilename.str(), ErrorCode, llvm::sys::fs::F_RW);
|
||||||
|
ScratchTreeFilestream << ScratchTreeStream.str();
|
||||||
|
if (ErrorCode) {
|
||||||
|
Log->getOS() << "Failed to write from-scratch syntax tree to "
|
||||||
|
<< ScratchTreeFilename << "(error code "
|
||||||
|
<< ErrorCode.value() << ": " << ErrorCode.message()
|
||||||
|
<< ")\n";
|
||||||
|
} else {
|
||||||
|
Log->getOS() << "From-scratch syntax tree written to "
|
||||||
|
<< ScratchTreeFilename << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write source file
|
||||||
|
auto SourceFilename = DirectoryName + "/postEditSource.swift";
|
||||||
|
llvm::raw_fd_ostream SourceFilestream(SourceFilename.str(), ErrorCode,
|
||||||
|
llvm::sys::fs::F_RW);
|
||||||
|
auto FileBuffer = EditorDoc->getLatestSnapshot()->getBuffer();
|
||||||
|
SourceFilestream << FileBuffer->getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SwiftLangSupport::editorReplaceText(StringRef Name,
|
void SwiftLangSupport::editorReplaceText(StringRef Name,
|
||||||
llvm::MemoryBuffer *Buf,
|
llvm::MemoryBuffer *Buf,
|
||||||
unsigned Offset, unsigned Length,
|
unsigned Offset, unsigned Length,
|
||||||
EditorConsumer &Consumer) {
|
EditorConsumer &Consumer) {
|
||||||
|
bool LogReuseRegions = ::getenv("SOURCEKIT_LOG_INCREMENTAL_REUSE_REGIONS");
|
||||||
|
bool ValidateSyntaxTree = ::getenv("SOURCEKIT_INCREMENTAL_PARSE_VALIDATION");
|
||||||
|
|
||||||
auto EditorDoc = EditorDocuments.getByUnresolvedName(Name);
|
auto EditorDoc = EditorDocuments.getByUnresolvedName(Name);
|
||||||
if (!EditorDoc) {
|
if (!EditorDoc) {
|
||||||
Consumer.handleRequestError("No associated Editor Document");
|
Consumer.handleRequestError("No associated Editor Document");
|
||||||
@@ -2224,13 +2354,80 @@ void SwiftLangSupport::editorReplaceText(StringRef Name,
|
|||||||
|
|
||||||
ImmutableTextSnapshotRef Snapshot;
|
ImmutableTextSnapshotRef Snapshot;
|
||||||
if (Length != 0 || Buf->getBufferSize() != 0) {
|
if (Length != 0 || Buf->getBufferSize() != 0) {
|
||||||
|
std::string PreEditText;
|
||||||
|
if (ValidateSyntaxTree) {
|
||||||
|
auto CurBuffer = EditorDoc->getLatestSnapshot()->getBuffer();
|
||||||
|
auto BufferStart = CurBuffer->getInternalBuffer()->getBufferStart();
|
||||||
|
StringRef PreEditTextRef(BufferStart + Offset, Length);
|
||||||
|
PreEditText = PreEditTextRef.str();
|
||||||
|
}
|
||||||
Snapshot = EditorDoc->replaceText(Offset, Length, Buf,
|
Snapshot = EditorDoc->replaceText(Offset, Length, Buf,
|
||||||
Consumer.needsSemanticInfo());
|
Consumer.needsSemanticInfo());
|
||||||
assert(Snapshot);
|
assert(Snapshot);
|
||||||
bool BuildSyntaxTree = Consumer.syntaxTreeEnabled() ||
|
bool BuildSyntaxTree = Consumer.syntaxTreeEnabled() ||
|
||||||
Consumer.forceLibSyntaxBasedProcessing();
|
Consumer.forceLibSyntaxBasedProcessing();
|
||||||
EditorDoc->parse(Snapshot, *this, BuildSyntaxTree);
|
|
||||||
|
llvm::Optional<SyntaxParsingCache> SyntaxCache;
|
||||||
|
if (EditorDoc->getSyntaxTree().hasValue()) {
|
||||||
|
SyntaxCache.emplace(EditorDoc->getSyntaxTree().getValue());
|
||||||
|
SyntaxCache->addEdit(Offset, Offset + Length, Buf->getBufferSize());
|
||||||
|
SyntaxCache->setRecordReuseInformation();
|
||||||
|
}
|
||||||
|
|
||||||
|
SyntaxParsingCache *SyntaxCachePtr = nullptr;
|
||||||
|
if (SyntaxCache.hasValue()) {
|
||||||
|
SyntaxCachePtr = SyntaxCache.getPointer();
|
||||||
|
}
|
||||||
|
EditorDoc->parse(Snapshot, *this, BuildSyntaxTree, SyntaxCachePtr);
|
||||||
EditorDoc->readSyntaxInfo(Consumer);
|
EditorDoc->readSyntaxInfo(Consumer);
|
||||||
|
|
||||||
|
// Log reuse information
|
||||||
|
if (SyntaxCache.hasValue()) {
|
||||||
|
// Avoid computing the reused ranges if the consumer doesn't care about
|
||||||
|
// them
|
||||||
|
if (Consumer.syntaxReuseInfoEnabled()) {
|
||||||
|
auto ReuseRegions = SyntaxCache->getReusedRanges();
|
||||||
|
std::vector<SourceFileRange> ReuseRegionOffsets;
|
||||||
|
ReuseRegionOffsets.reserve(ReuseRegions.size());
|
||||||
|
for (auto ReuseRegion : ReuseRegions) {
|
||||||
|
auto Start = ReuseRegion.Start;
|
||||||
|
auto End = ReuseRegion.End;
|
||||||
|
ReuseRegionOffsets.push_back({Start, End});
|
||||||
|
}
|
||||||
|
Consumer.handleSyntaxReuseRegions(ReuseRegionOffsets);
|
||||||
|
}
|
||||||
|
if (LogReuseRegions) {
|
||||||
|
LOG_SECTION("SyntaxCache", InfoHighPrio) {
|
||||||
|
Log->getOS() << "Reused ";
|
||||||
|
|
||||||
|
bool FirstIteration = true;
|
||||||
|
unsigned LastPrintedBufferID;
|
||||||
|
for (auto ReuseRegion : SyntaxCache->getReusedRanges()) {
|
||||||
|
if (!FirstIteration) {
|
||||||
|
Log->getOS() << ", ";
|
||||||
|
} else {
|
||||||
|
FirstIteration = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SourceManager &SM = EditorDoc->getSourceManager();
|
||||||
|
unsigned BufferID = EditorDoc->getBufferID();
|
||||||
|
auto Start = SM.getLocForOffset(BufferID, ReuseRegion.Start);
|
||||||
|
auto End = SM.getLocForOffset(BufferID, ReuseRegion.End);
|
||||||
|
|
||||||
|
Start.print(Log->getOS(), SM, LastPrintedBufferID);
|
||||||
|
Log->getOS() << " - ";
|
||||||
|
End.print(Log->getOS(), SM, LastPrintedBufferID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Consumer.handleSyntaxReuseRegions({});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ValidateSyntaxTree) {
|
||||||
|
verifyIncrementalParse(EditorDoc, Offset, Length, PreEditText,
|
||||||
|
Buf->getBuffer());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Snapshot = EditorDoc->getLatestSnapshot();
|
Snapshot = EditorDoc->getLatestSnapshot();
|
||||||
}
|
}
|
||||||
@@ -2258,6 +2455,13 @@ void SwiftLangSupport::editorFormatText(StringRef Name, unsigned Line,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!EditorDoc->hasUpToDateAST()) {
|
||||||
|
// An up-to-date AST is needed for formatting. If it does not exist, fall
|
||||||
|
// back to a full reparse of the file
|
||||||
|
EditorDoc->parse(EditorDoc->getLatestSnapshot(), *this,
|
||||||
|
/*BuildSyntaxTree=*/true);
|
||||||
|
}
|
||||||
|
|
||||||
EditorDoc->formatText(Line, Length, Consumer);
|
EditorDoc->formatText(Line, Length, Consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ public:
|
|||||||
ImmutableTextSnapshotRef getLatestSnapshot() const;
|
ImmutableTextSnapshotRef getLatestSnapshot() const;
|
||||||
|
|
||||||
void parse(ImmutableTextSnapshotRef Snapshot, SwiftLangSupport &Lang,
|
void parse(ImmutableTextSnapshotRef Snapshot, SwiftLangSupport &Lang,
|
||||||
bool BuildSyntaxTree);
|
bool BuildSyntaxTree,
|
||||||
|
swift::SyntaxParsingCache *SyntaxCache = nullptr);
|
||||||
void readSyntaxInfo(EditorConsumer &consumer);
|
void readSyntaxInfo(EditorConsumer &consumer);
|
||||||
void readSemanticInfo(ImmutableTextSnapshotRef Snapshot,
|
void readSemanticInfo(ImmutableTextSnapshotRef Snapshot,
|
||||||
EditorConsumer& Consumer);
|
EditorConsumer& Consumer);
|
||||||
@@ -106,6 +107,20 @@ public:
|
|||||||
|
|
||||||
static void reportDocumentStructure(swift::SourceFile &SrcFile,
|
static void reportDocumentStructure(swift::SourceFile &SrcFile,
|
||||||
EditorConsumer &Consumer);
|
EditorConsumer &Consumer);
|
||||||
|
|
||||||
|
const llvm::Optional<swift::SourceFileSyntax> &getSyntaxTree() const;
|
||||||
|
|
||||||
|
const swift::SourceManager &getSourceManager() const;
|
||||||
|
swift::SourceManager &getSourceManager();
|
||||||
|
|
||||||
|
/// Get the buffer ID of this file in its source manager
|
||||||
|
unsigned getBufferID() const;
|
||||||
|
|
||||||
|
std::string getFilePath() const;
|
||||||
|
|
||||||
|
/// Whether or not the AST stored for this document is up-to-date or just an
|
||||||
|
/// artifact of incremental syntax parsing
|
||||||
|
bool hasUpToDateAST() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef IntrusiveRefCntPtr<SwiftEditorDocument> SwiftEditorDocumentRef;
|
typedef IntrusiveRefCntPtr<SwiftEditorDocument> SwiftEditorDocumentRef;
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ struct SKEditorConsumerOptions {
|
|||||||
bool EnableDiagnostics = false;
|
bool EnableDiagnostics = false;
|
||||||
bool EnableSyntaxTree = false;
|
bool EnableSyntaxTree = false;
|
||||||
bool SyntacticOnly = false;
|
bool SyntacticOnly = false;
|
||||||
|
bool EnableSyntaxReuseInfo = false;
|
||||||
// FIXME: This is just for bootstrapping incremental syntax tree parsing.
|
// FIXME: This is just for bootstrapping incremental syntax tree parsing.
|
||||||
// Remove it once when we are able to incrementally transfer the syntax tree
|
// Remove it once when we are able to incrementally transfer the syntax tree
|
||||||
bool ForceLibSyntaxBasedProcessing = false;
|
bool ForceLibSyntaxBasedProcessing = false;
|
||||||
@@ -441,6 +442,9 @@ void handleRequestImpl(sourcekitd_object_t ReqObj, ResponseReceiver Rec) {
|
|||||||
int64_t ForceLibSyntaxBasedProcessing = false;
|
int64_t ForceLibSyntaxBasedProcessing = false;
|
||||||
Req.getInt64(KeyForceLibSyntaxBasedProcessing,
|
Req.getInt64(KeyForceLibSyntaxBasedProcessing,
|
||||||
ForceLibSyntaxBasedProcessing, /*isOptional=*/true);
|
ForceLibSyntaxBasedProcessing, /*isOptional=*/true);
|
||||||
|
int64_t EnableSyntaxReuseInfo = false;
|
||||||
|
Req.getInt64(KeyEnableSyntaxReuseRegions, EnableSyntaxReuseInfo,
|
||||||
|
/*isOptional=*/true);
|
||||||
|
|
||||||
SKEditorConsumerOptions Opts;
|
SKEditorConsumerOptions Opts;
|
||||||
Opts.EnableSyntaxMap = EnableSyntaxMap;
|
Opts.EnableSyntaxMap = EnableSyntaxMap;
|
||||||
@@ -448,6 +452,7 @@ void handleRequestImpl(sourcekitd_object_t ReqObj, ResponseReceiver Rec) {
|
|||||||
Opts.EnableDiagnostics = EnableDiagnostics;
|
Opts.EnableDiagnostics = EnableDiagnostics;
|
||||||
Opts.EnableSyntaxTree = EnableSyntaxTree;
|
Opts.EnableSyntaxTree = EnableSyntaxTree;
|
||||||
Opts.SyntacticOnly = SyntacticOnly;
|
Opts.SyntacticOnly = SyntacticOnly;
|
||||||
|
Opts.EnableSyntaxReuseInfo = EnableSyntaxReuseInfo;
|
||||||
Opts.ForceLibSyntaxBasedProcessing = ForceLibSyntaxBasedProcessing;
|
Opts.ForceLibSyntaxBasedProcessing = ForceLibSyntaxBasedProcessing;
|
||||||
return Rec(editorOpen(*Name, InputBuf.get(), Opts, Args));
|
return Rec(editorOpen(*Name, InputBuf.get(), Opts, Args));
|
||||||
}
|
}
|
||||||
@@ -487,6 +492,9 @@ void handleRequestImpl(sourcekitd_object_t ReqObj, ResponseReceiver Rec) {
|
|||||||
Req.getInt64(KeyForceLibSyntaxBasedProcessing,
|
Req.getInt64(KeyForceLibSyntaxBasedProcessing,
|
||||||
ForceLibSyntaxBasedProcessing,
|
ForceLibSyntaxBasedProcessing,
|
||||||
/*isOptional=*/true);
|
/*isOptional=*/true);
|
||||||
|
int64_t EnableSyntaxReuseInfo = false;
|
||||||
|
Req.getInt64(KeyEnableSyntaxReuseRegions, EnableSyntaxReuseInfo,
|
||||||
|
/*isOptional=*/true);
|
||||||
|
|
||||||
SKEditorConsumerOptions Opts;
|
SKEditorConsumerOptions Opts;
|
||||||
Opts.EnableSyntaxMap = EnableSyntaxMap;
|
Opts.EnableSyntaxMap = EnableSyntaxMap;
|
||||||
@@ -494,6 +502,7 @@ void handleRequestImpl(sourcekitd_object_t ReqObj, ResponseReceiver Rec) {
|
|||||||
Opts.EnableDiagnostics = EnableDiagnostics;
|
Opts.EnableDiagnostics = EnableDiagnostics;
|
||||||
Opts.EnableSyntaxTree = EnableSyntaxTree;
|
Opts.EnableSyntaxTree = EnableSyntaxTree;
|
||||||
Opts.SyntacticOnly = SyntacticOnly;
|
Opts.SyntacticOnly = SyntacticOnly;
|
||||||
|
Opts.EnableSyntaxReuseInfo = EnableSyntaxReuseInfo;
|
||||||
Opts.ForceLibSyntaxBasedProcessing = ForceLibSyntaxBasedProcessing;
|
Opts.ForceLibSyntaxBasedProcessing = ForceLibSyntaxBasedProcessing;
|
||||||
|
|
||||||
return Rec(editorReplaceText(*Name, InputBuf.get(), Offset, Length, Opts));
|
return Rec(editorReplaceText(*Name, InputBuf.get(), Offset, Length, Opts));
|
||||||
@@ -2072,6 +2081,11 @@ public:
|
|||||||
bool handleSourceText(StringRef Text) override;
|
bool handleSourceText(StringRef Text) override;
|
||||||
bool handleSerializedSyntaxTree(StringRef Text) override;
|
bool handleSerializedSyntaxTree(StringRef Text) override;
|
||||||
bool syntaxTreeEnabled() override { return Opts.EnableSyntaxTree; }
|
bool syntaxTreeEnabled() override { return Opts.EnableSyntaxTree; }
|
||||||
|
|
||||||
|
bool syntaxReuseInfoEnabled() override { return Opts.EnableSyntaxReuseInfo; }
|
||||||
|
bool handleSyntaxReuseRegions(
|
||||||
|
std::vector<SourceFileRange> ReuseRegions) override;
|
||||||
|
|
||||||
void finished() override {
|
void finished() override {
|
||||||
if (RespReceiver)
|
if (RespReceiver)
|
||||||
RespReceiver(createResponse());
|
RespReceiver(createResponse());
|
||||||
@@ -2085,8 +2099,8 @@ public:
|
|||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
static sourcekitd_response_t
|
static sourcekitd_response_t
|
||||||
editorOpen(StringRef Name, llvm::MemoryBuffer *Buf, SKEditorConsumerOptions Opts,
|
editorOpen(StringRef Name, llvm::MemoryBuffer *Buf,
|
||||||
ArrayRef<const char *> Args) {
|
SKEditorConsumerOptions Opts, ArrayRef<const char *> Args) {
|
||||||
SKEditorConsumer EditC(Opts);
|
SKEditorConsumer EditC(Opts);
|
||||||
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
|
LangSupport &Lang = getGlobalContext().getSwiftLangSupport();
|
||||||
Lang.editorOpen(Name, Buf, EditC, Args);
|
Lang.editorOpen(Name, Buf, EditC, Args);
|
||||||
@@ -2417,6 +2431,20 @@ bool SKEditorConsumer::handleSerializedSyntaxTree(StringRef Text) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SKEditorConsumer::handleSyntaxReuseRegions(
|
||||||
|
std::vector<SourceFileRange> ReuseRegions) {
|
||||||
|
if (Opts.EnableSyntaxReuseInfo) {
|
||||||
|
auto Array = Dict.setArray(KeySyntaxReuseRegions);
|
||||||
|
|
||||||
|
for (auto Region : ReuseRegions) {
|
||||||
|
auto SubDict = Array.appendDictionary();
|
||||||
|
SubDict.set(KeyOffset, Region.Start);
|
||||||
|
SubDict.set(KeyLength, Region.End - Region.Start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static sourcekitd_response_t
|
static sourcekitd_response_t
|
||||||
editorFindUSR(StringRef DocumentName, StringRef USR) {
|
editorFindUSR(StringRef DocumentName, StringRef USR) {
|
||||||
ResponseBuilder RespBuilder;
|
ResponseBuilder RespBuilder;
|
||||||
|
|||||||
@@ -198,8 +198,8 @@ struct ByteBasedSourceRange {
|
|||||||
ByteBasedSourceRange(unsigned Start, unsigned End) : Start(Start), End(End) {
|
ByteBasedSourceRange(unsigned Start, unsigned End) : Start(Start), End(End) {
|
||||||
assert(Start <= End);
|
assert(Start <= End);
|
||||||
}
|
}
|
||||||
ByteBasedSourceRange(std::pair<unsigned, unsigned> Pair)
|
ByteBasedSourceRange(SyntaxReuseRegion Pair)
|
||||||
: ByteBasedSourceRange(Pair.first, Pair.second) {}
|
: ByteBasedSourceRange(Pair.Start, Pair.End) {}
|
||||||
ByteBasedSourceRange() : ByteBasedSourceRange(0, 0) {}
|
ByteBasedSourceRange() : ByteBasedSourceRange(0, 0) {}
|
||||||
|
|
||||||
ByteBasedSourceRange intersect(const ByteBasedSourceRange &Other) {
|
ByteBasedSourceRange intersect(const ByteBasedSourceRange &Other) {
|
||||||
@@ -228,8 +228,7 @@ struct ByteBasedSourceRangeSet {
|
|||||||
|
|
||||||
ByteBasedSourceRangeSet() {}
|
ByteBasedSourceRangeSet() {}
|
||||||
|
|
||||||
ByteBasedSourceRangeSet(
|
ByteBasedSourceRangeSet(std::vector<SyntaxReuseRegion> PairVector) {
|
||||||
std::vector<std::pair<unsigned, unsigned>> PairVector) {
|
|
||||||
for (auto Pair : PairVector) {
|
for (auto Pair : PairVector) {
|
||||||
addRange(Pair);
|
addRange(Pair);
|
||||||
}
|
}
|
||||||
@@ -439,11 +438,11 @@ void printVisualNodeReuseInformation(SourceManager &SourceMgr,
|
|||||||
|
|
||||||
for (auto ReuseRange : Cache->getReusedRanges()) {
|
for (auto ReuseRange : Cache->getReusedRanges()) {
|
||||||
// Print region that was not reused
|
// Print region that was not reused
|
||||||
PrintReparsedRegion(SourceText, CurrentOffset, ReuseRange.first);
|
PrintReparsedRegion(SourceText, CurrentOffset, ReuseRange.Start);
|
||||||
|
|
||||||
llvm::outs() << SourceText.substr(ReuseRange.first,
|
llvm::outs() << SourceText.substr(ReuseRange.Start,
|
||||||
ReuseRange.second - ReuseRange.first);
|
ReuseRange.End - ReuseRange.Start);
|
||||||
CurrentOffset = ReuseRange.second;
|
CurrentOffset = ReuseRange.End;
|
||||||
}
|
}
|
||||||
PrintReparsedRegion(SourceText, CurrentOffset, SourceText.size());
|
PrintReparsedRegion(SourceText, CurrentOffset, SourceText.size());
|
||||||
if (useColoredOutput())
|
if (useColoredOutput())
|
||||||
@@ -460,8 +459,8 @@ void saveReuseLog(SourceManager &SourceMgr, unsigned BufferID,
|
|||||||
assert(!ErrorCode && "Unable to open incremental usage log");
|
assert(!ErrorCode && "Unable to open incremental usage log");
|
||||||
|
|
||||||
for (auto ReuseRange : Cache->getReusedRanges()) {
|
for (auto ReuseRange : Cache->getReusedRanges()) {
|
||||||
SourceLoc Start = SourceMgr.getLocForOffset(BufferID, ReuseRange.first);
|
SourceLoc Start = SourceMgr.getLocForOffset(BufferID, ReuseRange.Start);
|
||||||
SourceLoc End = SourceMgr.getLocForOffset(BufferID, ReuseRange.second);
|
SourceLoc End = SourceMgr.getLocForOffset(BufferID, ReuseRange.End);
|
||||||
|
|
||||||
ReuseLog << "Reused ";
|
ReuseLog << "Reused ";
|
||||||
Start.printLineAndColumn(ReuseLog, SourceMgr, BufferID);
|
Start.printLineAndColumn(ReuseLog, SourceMgr, BufferID);
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ struct Root {
|
|||||||
namespace swift {
|
namespace swift {
|
||||||
namespace json {
|
namespace json {
|
||||||
|
|
||||||
|
void *IncludeSpecialValueUserInfoKey = &IncludeSpecialValueUserInfoKey;
|
||||||
|
|
||||||
template <> struct ObjectTraits<Leaf> {
|
template <> struct ObjectTraits<Leaf> {
|
||||||
static void mapping(Output &out, Leaf &value) {
|
static void mapping(Output &out, Leaf &value) {
|
||||||
switch (value.Val) {
|
switch (value.Val) {
|
||||||
@@ -71,6 +73,10 @@ template <> struct ObjectTraits<Root> {
|
|||||||
out.mapRequired("Children", value.Children);
|
out.mapRequired("Children", value.Children);
|
||||||
out.mapRequired("Empty", value.Empty);
|
out.mapRequired("Empty", value.Empty);
|
||||||
out.mapRequired("Side", value.Side);
|
out.mapRequired("Side", value.Side);
|
||||||
|
if ((bool)out.getUserInfo()[IncludeSpecialValueUserInfoKey]) {
|
||||||
|
std::string Value = "42";
|
||||||
|
out.mapRequired("SpecialValue", Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -84,7 +90,7 @@ TEST(JSONSerialization, basicCompact) {
|
|||||||
Root RootObj{"foo", {&LeafObj0, &LeafObj1, nullptr, &LeafObj2}, {}, nullptr};
|
Root RootObj{"foo", {&LeafObj0, &LeafObj1, nullptr, &LeafObj2}, {}, nullptr};
|
||||||
std::string Buffer;
|
std::string Buffer;
|
||||||
llvm::raw_string_ostream Stream(Buffer);
|
llvm::raw_string_ostream Stream(Buffer);
|
||||||
swift::json::Output Out(Stream, /*PrettyPrint=*/false);
|
swift::json::Output Out(Stream, /*UserInfo=*/{}, /*PrettyPrint=*/false);
|
||||||
|
|
||||||
Out << RootObj;
|
Out << RootObj;
|
||||||
Stream.flush();
|
Stream.flush();
|
||||||
@@ -121,3 +127,24 @@ TEST(JSONSerialization, basicPretty) {
|
|||||||
"Side": null
|
"Side": null
|
||||||
})""");
|
})""");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(JSONSerialization, basicUserInfo) {
|
||||||
|
Root RootObj{"foo", {}, {}, nullptr};
|
||||||
|
std::string Buffer;
|
||||||
|
llvm::raw_string_ostream Stream(Buffer);
|
||||||
|
|
||||||
|
swift::json::Output::UserInfoMap UserInfo;
|
||||||
|
UserInfo[swift::json::IncludeSpecialValueUserInfoKey] = (void *)true;
|
||||||
|
swift::json::Output Out(Stream, UserInfo);
|
||||||
|
|
||||||
|
Out << RootObj;
|
||||||
|
Stream.flush();
|
||||||
|
|
||||||
|
EXPECT_EQ(Buffer, R"""({
|
||||||
|
"Name": "foo",
|
||||||
|
"Children": [],
|
||||||
|
"Empty": [],
|
||||||
|
"Side": null,
|
||||||
|
"SpecialValue": "42"
|
||||||
|
})""");
|
||||||
|
}
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ TEST(OwnedStringTest, copy_constructor_original_not_copy) {
|
|||||||
// Make sure updating the original pointer doesn't affect the copy.
|
// Make sure updating the original pointer doesn't affect the copy.
|
||||||
data[0] = 'a';
|
data[0] = 'a';
|
||||||
|
|
||||||
EXPECT_EQ("atring", str);
|
EXPECT_EQ("string", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OwnedStringTest, copy_constructor_original_copy) {
|
TEST(OwnedStringTest, copy_constructor_original_copy) {
|
||||||
|
|||||||
@@ -92,6 +92,12 @@ class NullEditorConsumer : public EditorConsumer {
|
|||||||
bool syntaxTreeEnabled() override { return false; }
|
bool syntaxTreeEnabled() override { return false; }
|
||||||
bool forceLibSyntaxBasedProcessing() override { return false; }
|
bool forceLibSyntaxBasedProcessing() override { return false; }
|
||||||
|
|
||||||
|
bool syntaxReuseInfoEnabled() override { return false; }
|
||||||
|
|
||||||
|
bool handleSyntaxReuseRegions(
|
||||||
|
std::vector<SourceFileRange> ReuseRegions) override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
bool needsSema = false;
|
bool needsSema = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -100,6 +100,13 @@ private:
|
|||||||
bool handleSerializedSyntaxTree(StringRef Text) override { return false; }
|
bool handleSerializedSyntaxTree(StringRef Text) override { return false; }
|
||||||
bool syntaxTreeEnabled() override { return false; }
|
bool syntaxTreeEnabled() override { return false; }
|
||||||
bool forceLibSyntaxBasedProcessing() override { return false; }
|
bool forceLibSyntaxBasedProcessing() override { return false; }
|
||||||
|
|
||||||
|
bool syntaxReuseInfoEnabled() override { return false; }
|
||||||
|
|
||||||
|
bool handleSyntaxReuseRegions(
|
||||||
|
std::vector<SourceFileRange> ReuseRegions) override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DocUpdateMutexState {
|
struct DocUpdateMutexState {
|
||||||
|
|||||||
@@ -47,8 +47,10 @@ UID_KEYS = [
|
|||||||
KEY('Length', 'key.length'),
|
KEY('Length', 'key.length'),
|
||||||
KEY('SourceFile', 'key.sourcefile'),
|
KEY('SourceFile', 'key.sourcefile'),
|
||||||
KEY('SerializedSyntaxTree', 'key.serialized_syntax_tree'),
|
KEY('SerializedSyntaxTree', 'key.serialized_syntax_tree'),
|
||||||
|
KEY('SyntaxReuseRegions', 'key.syntaxreuseregions'),
|
||||||
KEY('SourceText', 'key.sourcetext'),
|
KEY('SourceText', 'key.sourcetext'),
|
||||||
KEY('ForceLibSyntaxBasedProcessing', 'key.forcelibsyntaxbasedprocessing'),
|
KEY('ForceLibSyntaxBasedProcessing', 'key.forcelibsyntaxbasedprocessing'),
|
||||||
|
KEY('EnableSyntaxReuseRegions', 'key.enablesyntaxreuseregions'),
|
||||||
KEY('EnableSyntaxMap', 'key.enablesyntaxmap'),
|
KEY('EnableSyntaxMap', 'key.enablesyntaxmap'),
|
||||||
KEY('EnableSyntaxTree', 'key.enablesyntaxtree'),
|
KEY('EnableSyntaxTree', 'key.enablesyntaxtree'),
|
||||||
KEY('EnableStructure', 'key.enablesubstructure'),
|
KEY('EnableStructure', 'key.enablesubstructure'),
|
||||||
|
|||||||
Reference in New Issue
Block a user