Skip to content

[migrator] Add pass for API type changes #9084

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
Apr 28, 2017
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
14 changes: 14 additions & 0 deletions include/swift/IDE/APIDigesterData.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,20 @@ struct CommonDiffItem: public APIDiffItem {
return DiffKind == NodeAnnotation::Rename ||
DiffKind == NodeAnnotation::ModernizeEnum;
}

bool isTypeChange() const {
switch (DiffKind) {
case NodeAnnotation::WrapOptional:
case NodeAnnotation::UnwrapOptional:
case NodeAnnotation::ImplicitOptionalToOptional:
case NodeAnnotation::OptionalToImplicitOptional:
case NodeAnnotation::WrapImplicitOptional:
case NodeAnnotation::TypeRewritten:
return true;
default:
return false;
}
}
StringRef getNewName() const { assert(isRename()); return RightComment; }
APIDiffItemKind getKind() const override {
return APIDiffItemKind::ADK_CommonDiffItem;
Expand Down
41 changes: 41 additions & 0 deletions include/swift/Index/Utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===--- Utils.h - Index utilities that are generally useful ----*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_INDEX_UTILS_H
#define SWIFT_INDEX_UTILS_H

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

namespace swift {
class ValueDecl;

/// \brief Collect all the protocol requirements that a given declaration can
/// provide default implementations for. VD is a declaration in extension
/// declaration. Scratch is the buffer to collect those protocol
/// requirements.
///
/// \returns the slice of Scratch
ArrayRef<ValueDecl*>
canDeclProvideDefaultImplementationFor(ValueDecl* VD,
llvm::SmallVectorImpl<ValueDecl*> &Scratch);

/// \brief Get decls that the given decl overrides, protocol requirements that
/// it serves as a default implementation of, and optionally protocol
/// requirements it satisfies in a conforming class
std::vector<ValueDecl*>
getOverriddenDecls(ValueDecl *VD, bool IncludeProtocolRequirements = true,
bool Transitive = false);

} // end namespace swift
#endif // SWIFT_INDEX_UTILS_H
1 change: 1 addition & 0 deletions include/swift/Migrator/EditorAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class EditorAdapter {
bool AfterToken = false,
bool BeforePreviousInsertions = false);
bool insertWrap(StringRef before, SourceRange TokenRange, StringRef after);
bool remove(SourceLoc TokenLoc);
bool remove(SourceRange TokenRange);
bool replace(SourceRange TokenRange, StringRef Text);
bool replaceWithInner(SourceRange TokenRange, SourceRange TokenInnerRange);
Expand Down
9 changes: 0 additions & 9 deletions include/swift/Sema/IDETypeChecking.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,6 @@ namespace swift {
void collectDefaultImplementationForProtocolMembers(ProtocolDecl *PD,
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap);

/// \brief Collect all the protocol requirements that a given declaration can
/// provide default implementations for. VD is a declaration in extension
/// declaration. Scratch is the buffer to collect those protocol
/// requirements.
///
/// \returns the slice of Scratch
ArrayRef<ValueDecl*> canDeclProvideDefaultImplementationFor(ValueDecl* VD,
llvm::SmallVectorImpl<ValueDecl*> &Scratch);

/// \brief Given an unresolved member E and its parent P, this function tries
/// to infer the type of E.
/// \returns true on success, false on error.
Expand Down
40 changes: 0 additions & 40 deletions lib/IDE/IDETypeChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,6 @@

using namespace swift;

static Type getContextFreeInterfaceType(ValueDecl *VD) {
if (auto AFD = dyn_cast<AbstractFunctionDecl>(VD)) {
return AFD->getMethodInterfaceType();
}
return VD->getInterfaceType();
}

ArrayRef<ValueDecl*> swift::
canDeclProvideDefaultImplementationFor(ValueDecl* VD,
llvm::SmallVectorImpl<ValueDecl*> &Scratch) {

// Skip decls that don't have valid names.
if (!VD->getFullName())
return {};

// Check if VD is from a protocol extension.
auto P = VD->getDeclContext()->getAsProtocolExtensionContext();
if (!P)
return {};

// Look up all decls in the protocol's inheritance chain for the ones with
// the same name with VD.
ResolvedMemberResult LookupResult =
resolveValueMember(*P->getInnermostDeclContext(),
P->getDeclaredInterfaceType(), VD->getFullName());

auto VDType = getContextFreeInterfaceType(VD);
for (auto Mem : LookupResult.getMemberDecls(InterestedMemberKind::All)) {
if (isa<ProtocolDecl>(Mem->getDeclContext())) {
if (Mem->isProtocolRequirement() &&
getContextFreeInterfaceType(Mem)->isEqual(VDType)) {
// We find a protocol requirement VD can provide default
// implementation for.
Scratch.push_back(Mem);
}
}
}
return Scratch;
}

void swift::
collectDefaultImplementationForProtocolMembers(ProtocolDecl *PD,
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap) {
Expand Down
91 changes: 70 additions & 21 deletions lib/Index/Index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "swift/Index/Index.h"
#include "swift/Index/Utils.h"

#include "swift/AST/ASTContext.h"
#include "swift/AST/Comment.h"
Expand Down Expand Up @@ -663,30 +664,11 @@ bool IndexSwiftASTWalker::startEntityDecl(ValueDecl *D) {
return false;
}

if (auto Overridden = D->getOverriddenDecl()) {
if (addRelation(Info, (SymbolRoleSet) SymbolRole::RelationOverrideOf, Overridden))
for (auto Overriden: getOverriddenDecls(D, /*IncludeProtocolReqs=*/!isSystemModule)) {
if (addRelation(Info, (SymbolRoleSet) SymbolRole::RelationOverrideOf, Overriden))
return false;
}

{
// Collect the protocol requirements this decl can provide default
// implementations to, and record them as overriding.
llvm::SmallVector<ValueDecl*, 2> Buffer;
for (auto Req : canDeclProvideDefaultImplementationFor(D, Buffer)) {
if (addRelation(Info, (SymbolRoleSet) SymbolRole::RelationOverrideOf, Req))
return false;
}
}

// FIXME: This is quite expensive and not worth the cost for indexing purposes
// of system modules. Revisit if this becomes more efficient.
if (!isSystemModule) {
for (auto Conf : D->getSatisfiedProtocolRequirements()) {
if (addRelation(Info, (SymbolRoleSet) SymbolRole::RelationOverrideOf, Conf))
return false;
}
}

if (auto Parent = getParentDecl()) {
if (auto ParentVD = dyn_cast<ValueDecl>(Parent)) {
SymbolRoleSet RelationsToParent = (SymbolRoleSet)SymbolRole::RelationChildOf;
Expand Down Expand Up @@ -1398,6 +1380,73 @@ void IndexSwiftASTWalker::getModuleHash(SourceFileOrModule Mod,
OS << llvm::APInt(64, code).toString(36, /*Signed=*/false);
}

static Type getContextFreeInterfaceType(ValueDecl *VD) {
if (auto AFD = dyn_cast<AbstractFunctionDecl>(VD)) {
return AFD->getMethodInterfaceType();
}
return VD->getInterfaceType();
}

ArrayRef<ValueDecl*> swift::
canDeclProvideDefaultImplementationFor(ValueDecl* VD,
llvm::SmallVectorImpl<ValueDecl*> &Scratch) {

// Skip decls that don't have valid names.
if (!VD->getFullName())
return {};

// Check if VD is from a protocol extension.
auto P = VD->getDeclContext()->getAsProtocolExtensionContext();
if (!P)
return {};

// Look up all decls in the protocol's inheritance chain for the ones with
// the same name with VD.
ResolvedMemberResult LookupResult =
resolveValueMember(*P->getInnermostDeclContext(),
P->getDeclaredInterfaceType(), VD->getFullName());

auto VDType = getContextFreeInterfaceType(VD);
for (auto Mem : LookupResult.getMemberDecls(InterestedMemberKind::All)) {
if (isa<ProtocolDecl>(Mem->getDeclContext())) {
if (Mem->isProtocolRequirement() &&
getContextFreeInterfaceType(Mem)->isEqual(VDType)) {
// We find a protocol requirement VD can provide default
// implementation for.
Scratch.push_back(Mem);
}
}
}
return Scratch;
}

std::vector<ValueDecl*> swift::
getOverriddenDecls(ValueDecl *VD, bool IncludeProtocolRequirements,
bool Transitive) {
std::vector<ValueDecl*> results;

if (auto Overridden = VD->getOverriddenDecl()) {
results.push_back(Overridden);
while (Transitive && (Overridden = Overridden->getOverriddenDecl()))
results.push_back(Overridden);
}

// Collect the protocol requirements this decl is a default impl for
llvm::SmallVector<ValueDecl*, 2> Buffer;
for (auto Req : canDeclProvideDefaultImplementationFor(VD, Buffer)) {
results.push_back(Req);
}

if (IncludeProtocolRequirements) {
for (auto Satisfied : VD->getSatisfiedProtocolRequirements()) {
results.push_back(Satisfied);
}
}

return results;
}


//===----------------------------------------------------------------------===//
// Indexing entry points
//===----------------------------------------------------------------------===//
Expand Down
37 changes: 28 additions & 9 deletions lib/Migrator/EditorAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "swift/Basic/SourceLoc.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Migrator/EditorAdapter.h"
#include "swift/Parse/Lexer.h"
#include "clang/Basic/SourceManager.h"

using namespace swift;
Expand Down Expand Up @@ -60,12 +61,27 @@ translateCharSourceRange(CharSourceRange SwiftSourceSourceRange) const {
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);

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);

auto ClangLoc = translateSourceLoc(Loc);
auto ClangCharRange = translateCharSourceRange(Range);
return Edits.insertFromRange(ClangLoc, ClangCharRange, AfterToken,

return Edits.insertFromRange(ClangLoc, ClangCharRange, /*AfterToken=*/false,
BeforePreviousInsertions);
}

Expand Down Expand Up @@ -100,32 +116,35 @@ bool EditorAdapter::replaceText(SourceLoc Loc, StringRef Text,
bool EditorAdapter::insertFromRange(SourceLoc Loc, SourceRange TokenRange,
bool AfterToken,
bool BeforePreviousInsertions) {
CharSourceRange CharRange { SwiftSrcMgr, TokenRange.Start, TokenRange.End };
auto CharRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr, TokenRange);
return insertFromRange(Loc, CharRange,
AfterToken, BeforePreviousInsertions);
}

bool EditorAdapter::insertWrap(StringRef Before, SourceRange TokenRange,
StringRef After) {
CharSourceRange CharRange { SwiftSrcMgr, TokenRange.Start, TokenRange.End };
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) {
CharSourceRange CharRange { SwiftSrcMgr, TokenRange.Start, TokenRange.End };
auto CharRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr, TokenRange);
return remove(CharRange);
}

bool EditorAdapter::replace(SourceRange TokenRange, StringRef Text) {
CharSourceRange CharRange { SwiftSrcMgr, TokenRange.Start, TokenRange.End };
auto CharRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr,TokenRange);
return replace(CharRange, Text);
}

bool EditorAdapter::replaceWithInner(SourceRange TokenRange,
SourceRange TokenInnerRange) {
CharSourceRange CharRange { SwiftSrcMgr, TokenRange.Start, TokenRange.End };
CharSourceRange CharInnerRange {
SwiftSrcMgr, TokenInnerRange.Start, TokenInnerRange.End
};
auto CharRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr, TokenRange);
auto CharInnerRange = Lexer::getCharSourceRangeFromSourceRange(SwiftSrcMgr, TokenInnerRange);
return replaceWithInner(CharRange, CharInnerRange);
}
8 changes: 4 additions & 4 deletions lib/Migrator/Migrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,15 @@ Migrator::performAFixItMigration() {
}

FixitApplyDiagnosticConsumer FixitApplyConsumer {
InputState->getInputText(),
InputState->getOutputText(),
getInputFilename(),
};
Instance.addDiagnosticConsumer(&FixitApplyConsumer);

Instance.performSema();

StringRef ResultText = InputState->getInputText();
unsigned ResultBufferID = InputState->getInputBufferID();
StringRef ResultText = InputState->getOutputText();
unsigned ResultBufferID = InputState->getOutputBufferID();

if (FixitApplyConsumer.getNumFixitsApplied() > 0) {
SmallString<4096> Scratch;
Expand All @@ -145,7 +145,7 @@ Migrator::performAFixItMigration() {
}

return MigrationState::make(MigrationKind::CompilerFixits,
SrcMgr, InputState->getInputBufferID(),
SrcMgr, InputState->getOutputBufferID(),
ResultBufferID);
}

Expand Down
Loading