Files
swift-mirror/lib/Migrator/EditorAdapter.cpp
David Farler e55191f7d5 [Migrator] Don't take redundant replacements during AST Passes
We already had this functionality in the FixitApplyDiagnosticConsumer,
but we also need it in the AST passes because different entries in the
API diff data may drive identical fix-its, namely a general type rename,
which can occur anywhere a DeclRef appears, but also for function overrides'
parameter type changes, which are context specific.

rdar://problem/32431533
2017-06-14 14:21:51 -07:00

204 lines
7.2 KiB
C++

//===--- EditorAdapter.cpp ------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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/Basic/SourceLoc.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Migrator/EditorAdapter.h"
#include "swift/Migrator/Replacement.h"
#include "swift/Parse/Lexer.h"
#include "clang/Basic/SourceManager.h"
using namespace swift;
using namespace swift::migrator;
std::pair<unsigned, unsigned>
EditorAdapter::getLocInfo(swift::SourceLoc Loc) const {
auto SwiftBufferID = SwiftSrcMgr.findBufferContainingLoc(Loc);
auto Offset = SwiftSrcMgr.getLocOffsetInBuffer(Loc, SwiftBufferID);
return { SwiftBufferID, Offset };
}
bool
EditorAdapter::cacheReplacement(CharSourceRange Range, StringRef Text) const {
unsigned SwiftBufferID, Offset;
std::tie(SwiftBufferID, Offset) = getLocInfo(Range.getStart());
Replacement R { Offset, Range.getByteLength(), Text };
if (Replacements.count(R)) {
return true;
} else {
Replacements.insert(R);
}
return false;
}
clang::FileID
EditorAdapter::getClangFileIDForSwiftBufferID(unsigned BufferID) const {
/// Check if we already have a mapping for this BufferID.
auto Found = SwiftToClangBufferMap.find(BufferID);
if (Found != SwiftToClangBufferMap.end()) {
return Found->getSecond();
}
// If we don't copy the corresponding buffer's text into a new buffer
// that the ClangSrcMgr can understand.
auto Text = SwiftSrcMgr.getEntireTextForBuffer(BufferID);
auto NewBuffer = llvm::MemoryBuffer::getMemBufferCopy(Text);
auto NewFileID = ClangSrcMgr.createFileID(std::move(NewBuffer));
SwiftToClangBufferMap.insert({BufferID, NewFileID});
return NewFileID;
}
clang::SourceLocation
EditorAdapter::translateSourceLoc(SourceLoc SwiftLoc) const {
unsigned SwiftBufferID, Offset;
std::tie(SwiftBufferID, Offset) = getLocInfo(SwiftLoc);
auto ClangFileID = getClangFileIDForSwiftBufferID(SwiftBufferID);
return ClangSrcMgr.getLocForStartOfFile(ClangFileID).getLocWithOffset(Offset);
}
clang::SourceRange
EditorAdapter::translateSourceRange(SourceRange SwiftSourceRange) const {
auto Start = translateSourceLoc(SwiftSourceRange.Start);
auto End = translateSourceLoc(SwiftSourceRange.End);
return clang::SourceRange { Start, End };
}
clang::CharSourceRange EditorAdapter::
translateCharSourceRange(CharSourceRange SwiftSourceSourceRange) const {
auto ClangStartLoc = translateSourceLoc(SwiftSourceSourceRange.getStart());
auto ClangEndLoc = translateSourceLoc(SwiftSourceSourceRange.getEnd());
return clang::CharSourceRange::getCharRange(ClangStartLoc, ClangEndLoc);
}
bool EditorAdapter::insert(SourceLoc Loc, StringRef Text, bool AfterToken,
bool BeforePreviousInsertions) {
// We don't have tokens on the clang side, so handle AfterToken in Swift
if (AfterToken)
Loc = Lexer::getLocForEndOfToken(SwiftSrcMgr, Loc);
if (cacheReplacement(CharSourceRange { Loc, 0 }, Text)) {
return true;
}
auto ClangLoc = translateSourceLoc(Loc);
return Edits.insert(ClangLoc, Text, /*AfterToken=*/false, BeforePreviousInsertions);
}
bool EditorAdapter::insertFromRange(SourceLoc Loc, CharSourceRange Range,
bool AfterToken,
bool BeforePreviousInsertions) {
// We don't have tokens on the clang side, so handle AfterToken in Swift
if (AfterToken)
Loc = Lexer::getLocForEndOfToken(SwiftSrcMgr, Loc);
if (cacheReplacement(CharSourceRange { Loc, 0 },
SwiftSrcMgr.extractText(Range))) {
return true;
}
auto ClangLoc = translateSourceLoc(Loc);
auto ClangCharRange = translateCharSourceRange(Range);
return Edits.insertFromRange(ClangLoc, ClangCharRange, /*AfterToken=*/false,
BeforePreviousInsertions);
}
bool EditorAdapter::insertWrap(StringRef Before, CharSourceRange Range,
StringRef After) {
auto ClangRange = translateCharSourceRange(Range);
return Edits.insertWrap(Before, ClangRange, After);
}
bool EditorAdapter::remove(CharSourceRange Range) {
if (cacheReplacement(Range, "")) {
return true;
}
auto ClangRange = translateCharSourceRange(Range);
return Edits.remove(ClangRange);
}
bool EditorAdapter::replace(CharSourceRange Range, StringRef Text) {
if (cacheReplacement(Range, Text)) {
return true;
}
auto ClangRange = translateCharSourceRange(Range);
return Edits.replace(ClangRange, Text);
}
bool EditorAdapter::replaceWithInner(CharSourceRange Range,
CharSourceRange InnerRange) {
if (cacheReplacement(Range, SwiftSrcMgr.extractText(InnerRange))) {
return true;
}
auto ClangRange = translateCharSourceRange(Range);
auto ClangInnerRange = translateCharSourceRange(InnerRange);
return Edits.replaceWithInner(ClangRange, ClangInnerRange);
}
bool EditorAdapter::replaceText(SourceLoc Loc, StringRef Text,
StringRef ReplacementText) {
auto Range = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr,
{ Loc, Loc.getAdvancedLoc(Text.size())});
if (cacheReplacement(Range, Text)) {
return true;
}
auto ClangLoc = translateSourceLoc(Loc);
return Edits.replaceText(ClangLoc, Text, ReplacementText);
}
bool EditorAdapter::insertFromRange(SourceLoc Loc, SourceRange TokenRange,
bool AfterToken,
bool BeforePreviousInsertions) {
auto CharRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr, TokenRange);
return insertFromRange(Loc, CharRange,
AfterToken, BeforePreviousInsertions);
}
bool EditorAdapter::insertWrap(StringRef Before, SourceRange TokenRange,
StringRef After) {
auto CharRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr, TokenRange);
return insertWrap(Before, CharRange, After);
}
bool EditorAdapter::remove(SourceLoc TokenLoc) {
return remove(Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr,
TokenLoc));
}
bool EditorAdapter::remove(SourceRange TokenRange) {
auto CharRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr, TokenRange);
return remove(CharRange);
}
bool EditorAdapter::replace(SourceRange TokenRange, StringRef Text) {
auto CharRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr,TokenRange);
return replace(CharRange, Text);
}
bool EditorAdapter::replaceWithInner(SourceRange TokenRange,
SourceRange TokenInnerRange) {
auto CharRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr, TokenRange);
auto CharInnerRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr, TokenInnerRange);
return replaceWithInner(CharRange, CharInnerRange);
}
bool EditorAdapter::replaceToken(SourceLoc TokenLoc, StringRef Text) {
return replace(Lexer::getTokenAtLocation(SwiftSrcMgr, TokenLoc).getRange(),
Text);
}