Skip to content

Use StringMap in EditorDiagConsumer #68550

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion include/swift/AST/DiagnosticConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ class DiagnosticConsumer {
/// Invoked whenever the frontend emits a diagnostic.
///
/// \param SM The source manager associated with the source locations in
/// this diagnostic.
/// this diagnostic. NOTE: Do not persist either the SourceManager, or the
/// buffer names from the SourceManager, since it may not outlive the
/// DiagnosticConsumer (this is the case when building module interfaces).
///
/// \param Info Information describing the diagnostic.
virtual void handleDiagnostic(SourceManager &SM,
Expand Down
24 changes: 19 additions & 5 deletions include/swift/Basic/Edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,34 @@
#ifndef SWIFT_BASIC_EDIT_H
#define SWIFT_BASIC_EDIT_H

#include "llvm/ADT/ArrayRef.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/SourceLoc.h"

namespace swift {
class SourceManager;
class CharSourceRange;

struct SingleEdit {
SourceManager &SM;
CharSourceRange Range;
std::string Text;
/// A set of edits made to a source file.
class SourceEdits final {
public:
struct Edit {
std::string Path;
std::string Text;
unsigned Offset;
unsigned Length;
};

private:
std::vector<Edit> Edits;

public:
ArrayRef<Edit> getEdits() const { return Edits; }

void addEdit(SourceManager &SM, CharSourceRange Range, StringRef Text);
};

void writeEditsInJson(ArrayRef<SingleEdit> Edits, llvm::raw_ostream &OS);
void writeEditsInJson(const SourceEdits &Edits, llvm::raw_ostream &OS);
}

#endif // SWIFT_BASIC_EDIT_H
43 changes: 26 additions & 17 deletions lib/Basic/Edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,37 @@
#include "swift/Basic/Edit.h"
#include "swift/Basic/SourceManager.h"

using namespace swift;

void SourceEdits::addEdit(SourceManager &SM, CharSourceRange Range,
StringRef Text) {
SourceLoc Loc = Range.getStart();
unsigned BufID = SM.findBufferContainingLoc(Loc);
unsigned Offset = SM.getLocOffsetInBuffer(Loc, BufID);
unsigned Length = Range.getByteLength();
StringRef Path = SM.getIdentifierForBuffer(BufID);

// NOTE: We cannot store SourceManager here since this logic is used by a
// DiagnosticConsumer where the SourceManager may not remain valid. This is
// the case when e.g build swift interfaces, we create a fresh
// CompilerInstance for a limited scope, but diagnostics are passed outside of
// it.
Edits.push_back({Path.str(), Text.str(), Offset, Length});
}

void swift::
writeEditsInJson(ArrayRef<SingleEdit> AllEdits, llvm::raw_ostream &OS) {
writeEditsInJson(const SourceEdits &AllEdits, llvm::raw_ostream &OS) {
OS << "[\n";
for (auto &Edit : AllEdits) {
SourceManager &SM = Edit.SM;
CharSourceRange Range = Edit.Range;
StringRef Text = Edit.Text;
SourceLoc Loc = Range.getStart();
unsigned BufID = SM.findBufferContainingLoc(Loc);
unsigned Offset = SM.getLocOffsetInBuffer(Loc, BufID);
unsigned Length = Range.getByteLength();
StringRef Path(SM.getIdentifierForBuffer(BufID));

for (auto &Edit : AllEdits.getEdits()) {
OS << " {\n";
OS << " \"file\": \"";
OS.write_escaped(Path) << "\",\n";
OS << " \"offset\": " << Offset << ",\n";
if (Length != 0)
OS << " \"remove\": " << Length << ",\n";
if (!Text.empty()) {
OS.write_escaped(Edit.Path) << "\",\n";
OS << " \"offset\": " << Edit.Offset << ",\n";
if (Edit.Length != 0)
OS << " \"remove\": " << Edit.Length << ",\n";
if (!Edit.Text.empty()) {
OS << " \"text\": \"";
OS.write_escaped(Text) << "\",\n";
OS.write_escaped(Edit.Text) << "\",\n";
}
OS << " },\n";
}
Expand Down
11 changes: 6 additions & 5 deletions lib/Frontend/SerializedDiagnosticConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,12 @@ namespace serialized_diagnostics {
unsigned SerializedDiagnosticConsumer::getEmitFile(
SourceManager &SM, StringRef Filename, unsigned bufferID
) {
// NOTE: Using Filename.data() here relies on SourceMgr using
// const char* as buffer identifiers. This is fast, but may
// be brittle. We can always switch over to using a StringMap.
// Note that the logic in EditorDiagConsumer::getBufferInfo
// will also need changing.
// FIXME: Using Filename.data() here is wrong, since the provided
// SourceManager may not live as long as this consumer (which is
// the case if it's a diagnostic produced from building a module
// interface). We ought to switch over to using a StringMap once
// buffer names are unique (currently not the case for
// pretty-printed decl buffers).
unsigned &existingEntry = State->Files[Filename.data()];
if (existingEntry)
return existingEntry;
Expand Down
9 changes: 4 additions & 5 deletions lib/FrontendTool/FrontendTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ class JSONFixitWriter
std::string FixitsOutputPath;
std::unique_ptr<llvm::raw_ostream> OSPtr;
bool FixitAll;
std::vector<SingleEdit> AllEdits;
SourceEdits AllEdits;

public:
JSONFixitWriter(std::string fixitsOutputPath,
Expand All @@ -229,9 +229,8 @@ class JSONFixitWriter
const DiagnosticInfo &Info) override {
if (!(FixitAll || shouldTakeFixit(Info)))
return;
for (const auto &Fix : Info.FixIts) {
AllEdits.push_back({SM, Fix.getRange(), Fix.getText().str()});
}
for (const auto &Fix : Info.FixIts)
AllEdits.addEdit(SM, Fix.getRange(), Fix.getText());
}

bool finishProcessing() override {
Expand All @@ -251,7 +250,7 @@ class JSONFixitWriter
return true;
}

swift::writeEditsInJson(llvm::makeArrayRef(AllEdits), *OS);
swift::writeEditsInJson(AllEdits, *OS);
return false;
}
};
Expand Down
4 changes: 2 additions & 2 deletions lib/IDE/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -722,14 +722,14 @@ void swift::ide::SourceEditConsumer::acceptMacroExpansionBuffer(

struct swift::ide::SourceEditJsonConsumer::Implementation {
llvm::raw_ostream &OS;
std::vector<SingleEdit> AllEdits;
SourceEdits AllEdits;
Implementation(llvm::raw_ostream &OS) : OS(OS) {}
~Implementation() {
writeEditsInJson(AllEdits, OS);
}
void accept(SourceManager &SM, CharSourceRange Range,
llvm::StringRef Text) {
AllEdits.push_back({SM, Range, Text.str()});
AllEdits.addEdit(SM, Range, Text);
}
};

Expand Down
4 changes: 0 additions & 4 deletions tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,6 @@ BufferInfoSharedPtr
EditorDiagConsumer::getBufferInfo(StringRef FileName,
llvm::Optional<unsigned> BufferID,
swift::SourceManager &SM) {
// NOTE: Using StringRef as a key here relies on SourceMgr using const char*
// as buffer identifiers. This is fast, but may be brittle. We can always
// switch over to using a StringMap. Note that the logic in
// SerializedDiagnosticConsumer::getEmitFile will also need changing.
auto Result = BufferInfos.find(FileName);
if (Result != BufferInfos.end())
return Result->second;
Expand Down
4 changes: 2 additions & 2 deletions tools/SourceKit/lib/SwiftLang/SwiftEditorDiagConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include "SourceKit/Core/LangSupport.h"
#include "swift/AST/DiagnosticConsumer.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringMap.h"

namespace SourceKit {

Expand All @@ -27,7 +27,7 @@ class EditorDiagConsumer : public swift::DiagnosticConsumer {
llvm::DenseMap<unsigned, DiagnosticsTy> BufferDiagnostics;
DiagnosticsTy InvalidLocDiagnostics;

llvm::MapVector<StringRef, BufferInfoSharedPtr> BufferInfos;
llvm::StringMap<BufferInfoSharedPtr> BufferInfos;

int LastDiagBufferID = -1;
unsigned LastDiagIndex = 0;
Expand Down