Skip to content

[Source Tooling] Refactoring action to convert to computed property #25141

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 1 commit into from
Jan 7, 2020
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
2 changes: 2 additions & 0 deletions include/swift/IDE/RefactoringKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ RANGE_REFACTORING(ConvertIfLetExprToGuardExpr, "Convert To Guard Expression", co

RANGE_REFACTORING(ConvertGuardExprToIfLetExpr, "Convert To IfLet Expression", convert.to.iflet.expr)

RANGE_REFACTORING(ConvertToComputedProperty, "Convert To Computed Property", convert.to.computed.property)

// These internal refactorings are designed to be helpful for working on
// the compiler/standard library, etc., but are likely to be just confusing and
// noise for general development.
Expand Down
91 changes: 91 additions & 0 deletions lib/IDE/Refactoring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3166,6 +3166,97 @@ static bool rangeStartMayNeedRename(ResolvedRangeInfo Info) {
}
llvm_unreachable("unhandled kind");
}

bool RefactoringActionConvertToComputedProperty::
isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
if (Info.Kind != RangeKind::SingleDecl) {
return false;
}

if (Info.ContainedNodes.size() != 1) {
return false;
}

auto D = Info.ContainedNodes[0].dyn_cast<Decl*>();
if (!D) {
return false;
}

auto Binding = dyn_cast<PatternBindingDecl>(D);
if (!Binding) {
return false;
}

auto SV = Binding->getSingleVar();
if (!SV) {
return false;
}

// willSet, didSet cannot be provided together with a getter
for (auto AD : SV->getAllAccessors()) {
if (AD->isObservingAccessor()) {
return false;
}
}

// 'lazy' must not be used on a computed property
// NSCopying and IBOutlet attribute requires property to be mutable
auto Attributies = SV->getAttrs();
if (Attributies.hasAttribute<LazyAttr>() ||
Attributies.hasAttribute<NSCopyingAttr>() ||
Attributies.hasAttribute<IBOutletAttr>()) {
return false;
}

// Property wrapper cannot be applied to a computed property
if (SV->hasAttachedPropertyWrapper()) {
return false;
}

// has an initializer
return Binding->hasInitStringRepresentation(0);
}

bool RefactoringActionConvertToComputedProperty::performChange() {
// Get an initialization
auto D = RangeInfo.ContainedNodes[0].dyn_cast<Decl*>();
auto Binding = dyn_cast<PatternBindingDecl>(D);
SmallString<128> scratch;
auto Init = Binding->getInitStringRepresentation(0, scratch);

// Get type
auto SV = Binding->getSingleVar();
auto SVType = SV->getType();
auto TR = SV->getTypeReprOrParentPatternTypeRepr();

llvm::SmallString<64> DeclBuffer;
llvm::raw_svector_ostream OS(DeclBuffer);
llvm::StringRef Space = " ";
llvm::StringRef NewLine = "\n";

OS << tok::kw_var << Space;
// Add var name
OS << SV->getNameStr().str() << ":" << Space;
// For computed property must write a type of var
if (TR) {
OS << Lexer::getCharSourceRangeFromSourceRange(SM, TR->getSourceRange()).str();
} else {
SVType.print(OS);
}

OS << Space << tok::l_brace << NewLine;
// Add an initialization
OS << tok::kw_return << Space << Init.str() << NewLine;
OS << tok::r_brace;

// Replace initializer to computed property
auto ReplaceStartLoc = Binding->getLoc();
auto ReplaceEndLoc = Binding->getSourceRange().End;
auto ReplaceRange = SourceRange(ReplaceStartLoc, ReplaceEndLoc);
auto ReplaceCharSourceRange = Lexer::getCharSourceRangeFromSourceRange(SM, ReplaceRange);
EditConsumer.accept(SM, ReplaceCharSourceRange, DeclBuffer.str());
return false; // success
}
}// end of anonymous namespace

StringRef swift::ide::
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct S {
var field1 = 2
var field2 = "2"
var field3 = String()
static var field4 = 4
var y: Int! = 45
}

class C {
static var field1: S {
return S()
}
public var field2 = 2
private dynamic var field3 = 5
@available(macOS 10.12, *) private static dynamic var field4 = 4
let field5 = 5
}











Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct S {
var field1 = 2
var field2 = "2"
var field3 = String()
static var field4 = 4
var y: Int! = 45
}

class C {
static var field1 = S()
public var field2: Int {
return 2
}
private dynamic var field3 = 5
@available(macOS 10.12, *) private static dynamic var field4 = 4
let field5 = 5
}











Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct S {
var field1 = 2
var field2 = "2"
var field3 = String()
static var field4 = 4
var y: Int! = 45
}

class C {
static var field1 = S()
public var field2 = 2
private dynamic var field3: Int {
return 5
}
@available(macOS 10.12, *) private static dynamic var field4 = 4
let field5 = 5
}











Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct S {
var field1 = 2
var field2 = "2"
var field3 = String()
static var field4 = 4
var y: Int! = 45
}

class C {
static var field1 = S()
public var field2 = 2
private dynamic var field3 = 5
@available(macOS 10.12, *) private static dynamic var field4: Int {
return 4
}
let field5 = 5
}











Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct S {
var field1 = 2
var field2 = "2"
var field3 = String()
static var field4 = 4
var y: Int! = 45
}

class C {
static var field1 = S()
public var field2 = 2
private dynamic var field3 = 5
@available(macOS 10.12, *) private static dynamic var field4 = 4
var field5: Int {
return 5
}
}











Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct S {
var field1: Int {
return 2
}
var field2 = "2"
var field3 = String()
static var field4 = 4
var y: Int! = 45
}

class C {
static var field1 = S()
public var field2 = 2
private dynamic var field3 = 5
@available(macOS 10.12, *) private static dynamic var field4 = 4
let field5 = 5
}











Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct S {
var field1 = 2
var field2: String {
return "2"
}
var field3 = String()
static var field4 = 4
var y: Int! = 45
}

class C {
static var field1 = S()
public var field2 = 2
private dynamic var field3 = 5
@available(macOS 10.12, *) private static dynamic var field4 = 4
let field5 = 5
}











Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct S {
var field1 = 2
var field2 = "2"
var field3: String {
return String()
}
static var field4 = 4
var y: Int! = 45
}

class C {
static var field1 = S()
public var field2 = 2
private dynamic var field3 = 5
@available(macOS 10.12, *) private static dynamic var field4 = 4
let field5 = 5
}











Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct S {
var field1 = 2
var field2 = "2"
var field3 = String()
static var field4: Int {
return 4
}
var y: Int! = 45
}

class C {
static var field1 = S()
public var field2 = 2
private dynamic var field3 = 5
@available(macOS 10.12, *) private static dynamic var field4 = 4
let field5 = 5
}











Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
struct S {
var field1 = 2
var field2 = "2"
var field3 = String()
static var field4 = 4
var y: Int! {
return 45
}
}

class C {
static var field1 = S()
public var field2 = 2
private dynamic var field3 = 5
@available(macOS 10.12, *) private static dynamic var field4 = 4
let field5 = 5
}











Loading