Skip to content

Commit 60a91bb

Browse files
authored
[refactoring] Upstreaming the implementation for Swift local refactoring (#11568)
[refactoring] Upstreaming the implementation for Swift local refactoring
1 parent 9edef03 commit 60a91bb

File tree

251 files changed

+14158
-45
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

251 files changed

+14158
-45
lines changed

Diff for: docs/Refactoring.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This is placeholder for documentation related to Swift local refactoring.
2+
It will be expanded soon..

Diff for: include/swift/AST/ASTPrinter.h

+5
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,11 @@ uint8_t getKeywordLen(tok keyword);
319319
/// Get <#code#>;
320320
StringRef getCodePlaceholder();
321321

322+
/// Given an array of enum element decls, print them as case statements with
323+
/// placeholders as contents.
324+
void printEnumElementsAsCases(
325+
llvm::DenseSet<EnumElementDecl *> &UnhandledElements,
326+
llvm::raw_ostream &OS);
322327
} // namespace swift
323328

324329
#endif // LLVM_SWIFT_AST_ASTPRINTER_H

Diff for: include/swift/AST/DiagnosticsAll.def

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "DiagnosticsIRGen.def"
4444
#include "DiagnosticsFrontend.def"
4545
#include "DiagnosticsDriver.def"
46+
#include "DiagnosticsRefactoring.def"
4647

4748
#undef DIAG_NO_UNDEF
4849

Diff for: include/swift/AST/DiagnosticsRefactoring.def

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//===--- DiagnosticsRefactoring.def - Diagnostics Text ----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines diagnostics emitted during refactoring.
14+
// Each diagnostic is described using one of three kinds (error, warning, or
15+
// note) along with a unique identifier, category, options, and text, and is
16+
// followed by a signature describing the diagnostic argument kinds.
17+
//
18+
//===----------------------------------------------------------------------===//
19+
20+
#if !(defined(DIAG) || (defined(ERROR) && defined(WARNING) && defined(NOTE)))
21+
# error Must define either DIAG or the set {ERROR,WARNING,NOTE}
22+
#endif
23+
24+
#ifndef ERROR
25+
# define ERROR(ID,Options,Text,Signature) \
26+
DIAG(ERROR,ID,Options,Text,Signature)
27+
#endif
28+
29+
#ifndef WARNING
30+
# define WARNING(ID,Options,Text,Signature) \
31+
DIAG(WARNING,ID,Options,Text,Signature)
32+
#endif
33+
34+
#ifndef NOTE
35+
# define NOTE(ID,Options,Text,Signature) \
36+
DIAG(NOTE,ID,Options,Text,Signature)
37+
#endif
38+
39+
//==============================================================================
40+
// Refactoring diagnostics
41+
//==============================================================================
42+
43+
ERROR(invalid_name, none, "'%0' is not a valid name", (StringRef))
44+
45+
ERROR(invalid_location, none, "given location is not valid", ())
46+
47+
ERROR(arity_mismatch, none, "the given new name '%0' does not match the arity of the old name '%1'", (StringRef, StringRef))
48+
49+
ERROR(name_not_functionlike, none, "the 'call' name usage cannot be used with a non-function-like name '%0'", (StringRef))
50+
51+
ERROR(unresolved_location, none, "cannot resolve location as name", ())
52+
53+
ERROR(location_module_mismatch, none, "given location does not belong to module '%0'", (StringRef))
54+
55+
ERROR(value_decl_no_loc, none, "value decl '%0' has no declaration location", (DeclName))
56+
57+
ERROR(value_decl_referenced_out_of_range, none, "value decl '%0' is referenced out of range", (DeclName))
58+
59+
ERROR(multi_entry_range, none, "selected range has more than one entry point", ())
60+
61+
ERROR(orphan_loop_keyword, none, "selected range contains %0 but not its target loop", (StringRef))
62+
63+
ERROR(invalid_default_location, none, "given location is not on a default statement", ())
64+
65+
ERROR(no_parent_switch, none, "cannot find enclosing switch statement", ())
66+
67+
ERROR(no_subject_enum, none, "cannot find subject enum in the enclosing switch statement", ())
68+
69+
ERROR(no_remaining_cases, none, "no remaining cases to expand", ())
70+
71+
WARNING(mismatched_rename, none, "the name at the given location cannot be renamed to '%0'", (StringRef))
72+
73+
ERROR(no_insert_position, none, "cannot find inserting position", ())

Diff for: include/swift/AST/DiagnosticsRefactoring.h

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===--- DiagnosticsRefactoring.h - Diagnostic Definitions -----*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
/// \file
14+
/// \brief This file defines diagnostics for refactoring.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_DIAGNOSTICSREFACTORING_H
19+
#define SWIFT_DIAGNOSTICSREFACTORING_H
20+
21+
#include "swift/AST/DiagnosticsCommon.h"
22+
23+
namespace swift {
24+
namespace diag {
25+
// Declare common diagnostics objects with their appropriate types.
26+
#define DIAG(KIND,ID,Options,Text,Signature) \
27+
extern detail::DiagWithArguments<void Signature>::type ID;
28+
#include "DiagnosticsRefactoring.def"
29+
}
30+
}
31+
32+
#endif

Diff for: include/swift/AST/ProtocolConformance.h

+39-9
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
9393
/// \brief The type that conforms to the protocol, in the context of the
9494
/// conformance definition.
9595
Type ConformingType;
96-
96+
9797
protected:
9898
ProtocolConformance(ProtocolConformanceKind kind, Type conformingType)
9999
: Kind(kind), ConformingType(conformingType) { }
@@ -199,6 +199,36 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
199199
bool hasWitness(ValueDecl *requirement) const;
200200

201201
public:
202+
/// Apply the given function object to each requirement, either type or value,
203+
/// that is not witnessed.
204+
///
205+
/// The function object should accept a \c ValueDecl* for the requirement.
206+
template<typename F>
207+
void forEachNonWitnessedRequirement(LazyResolver *Resolver, F f) const {
208+
const ProtocolDecl *protocol = getProtocol();
209+
for (auto req : protocol->getMembers()) {
210+
auto valueReq = dyn_cast<ValueDecl>(req);
211+
if (!valueReq || valueReq->isInvalid())
212+
continue;
213+
214+
if (auto assocTypeReq = dyn_cast<AssociatedTypeDecl>(req)) {
215+
// If we don't have witness for the associated type, apply the function.
216+
if (getTypeWitness(assocTypeReq, Resolver)->hasError()) {
217+
f(valueReq);
218+
}
219+
continue;
220+
}
221+
222+
if (!valueReq->isProtocolRequirement())
223+
continue;
224+
225+
// If we don't have witness for the value, apply the function.
226+
if (!hasWitness(valueReq)) {
227+
f(valueReq);
228+
}
229+
}
230+
}
231+
202232
/// Retrieve the protocol conformance for the inherited protocol.
203233
ProtocolConformance *getInheritedConformance(ProtocolDecl *protocol) const;
204234

@@ -213,7 +243,7 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
213243
ProtocolConformanceRef
214244
getAssociatedConformance(Type assocType, ProtocolDecl *protocol,
215245
LazyResolver *resolver = nullptr) const;
216-
246+
217247
/// Get the generic parameters open on the conforming type.
218248
GenericEnvironment *getGenericEnvironment() const;
219249

@@ -252,15 +282,15 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
252282
assert(mem);
253283
return mem;
254284
}
255-
285+
256286
/// Print a parseable and human-readable description of the identifying
257287
/// information of the protocol conformance.
258288
void printName(raw_ostream &os,
259289
const PrintOptions &PO = PrintOptions()) const;
260-
290+
261291
/// True if the conformance is for a property behavior instantiation.
262292
bool isBehaviorConformance() const;
263-
293+
264294
/// Get the property declaration for a behavior conformance, if this is one.
265295
AbstractStorageDecl *getBehaviorDecl() const;
266296

@@ -269,7 +299,7 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
269299
ProtocolConformance *subst(Type substType,
270300
TypeSubstitutionFn subs,
271301
LookupConformanceFn conformances) const;
272-
302+
273303
void dump() const;
274304
void dump(llvm::raw_ostream &out, unsigned indent = 0) const;
275305
};
@@ -348,7 +378,7 @@ class NormalProtocolConformance : public ProtocolConformance,
348378
/// Get the protocol being conformed to.
349379
ProtocolDecl *getProtocol() const { return ProtocolAndState.getPointer(); }
350380

351-
/// Retrieve the location of this
381+
/// Retrieve the location of this
352382
SourceLoc getLoc() const { return Loc; }
353383

354384
/// Get the declaration context that contains the conforming extension or
@@ -376,7 +406,7 @@ class NormalProtocolConformance : public ProtocolConformance,
376406
bool isInvalid() const {
377407
return ContextAndInvalid.getInt();
378408
}
379-
409+
380410
/// Mark this conformance as invalid.
381411
void setInvalid() {
382412
ContextAndInvalid.setInt(true);
@@ -391,7 +421,7 @@ class NormalProtocolConformance : public ProtocolConformance,
391421
bool isBehaviorConformance() const {
392422
return ContextAndInvalid.getPointer().is<AbstractStorageDecl *>();
393423
}
394-
424+
395425
/// Return the declaration using the behavior for this conformance, or null
396426
/// if this isn't a behavior conformance.
397427
AbstractStorageDecl *getBehaviorDecl() const {

Diff for: include/swift/IDE/Refactoring.h

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//===--- Refactoring.h - APIs for refactoring --------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_IDE_REFACTORING_H
14+
#define SWIFT_IDE_REFACTORING_H
15+
16+
#include "llvm/ADT/StringRef.h"
17+
#include "swift/Basic/LLVM.h"
18+
#include "swift/AST/DiagnosticConsumer.h"
19+
#include "swift/IDE/Utils.h"
20+
21+
namespace swift {
22+
class ModuleDecl;
23+
class SourceLoc;
24+
class SourceManager;
25+
26+
namespace ide {
27+
struct SemaToken;
28+
29+
enum class RefactoringKind : int8_t {
30+
None,
31+
#define REFACTORING(KIND, NAME, ID) KIND,
32+
#include "RefactoringKinds.def"
33+
};
34+
35+
struct RangeConfig {
36+
unsigned BufferId;
37+
unsigned Line;
38+
unsigned Column;
39+
unsigned Length;
40+
SourceLoc getStart(SourceManager &SM);
41+
SourceLoc getEnd(SourceManager &SM);
42+
};
43+
44+
enum class NameUsage {
45+
Unknown,
46+
Reference,
47+
Definition,
48+
Call
49+
};
50+
51+
struct RenameLoc {
52+
unsigned Line;
53+
unsigned Column;
54+
NameUsage Usage;
55+
StringRef OldName;
56+
StringRef NewName; // May be empty.
57+
const bool IsFunctionLike;
58+
const bool IsNonProtocolType;
59+
};
60+
61+
struct RefactoringOptions {
62+
RefactoringKind Kind;
63+
RangeConfig Range;
64+
std::string PreferredName;
65+
RefactoringOptions(RefactoringKind Kind) : Kind(Kind) {}
66+
};
67+
68+
// TODO: Merge with NoteRegion – range needs to change to start/end line/column
69+
struct RenameRangeDetail {
70+
CharSourceRange Range;
71+
RefactoringRangeKind RangeKind;
72+
Optional<unsigned> Index;
73+
};
74+
75+
enum class RenameAvailableKind {
76+
Available,
77+
Unavailable_system_symbol,
78+
Unavailable_has_no_location,
79+
Unavailable_has_no_name,
80+
Unavailable_has_no_accessibility,
81+
Unavailable_decl_from_clang,
82+
};
83+
84+
struct RenameAvailabiliyInfo {
85+
RefactoringKind Kind;
86+
RenameAvailableKind AvailableKind;
87+
RenameAvailabiliyInfo(RefactoringKind Kind, RenameAvailableKind AvailableKind) :
88+
Kind(Kind), AvailableKind(AvailableKind) {}
89+
RenameAvailabiliyInfo(RefactoringKind Kind) :
90+
RenameAvailabiliyInfo(Kind, RenameAvailableKind::Available) {}
91+
};
92+
93+
class FindRenameRangesConsumer {
94+
public:
95+
virtual void accept(SourceManager &SM, RegionType RegionType,
96+
ArrayRef<RenameRangeDetail> Ranges) = 0;
97+
virtual ~FindRenameRangesConsumer() = default;
98+
};
99+
100+
class FindRenameRangesAnnotatingConsumer : public FindRenameRangesConsumer {
101+
struct Implementation;
102+
Implementation &Impl;
103+
104+
public:
105+
FindRenameRangesAnnotatingConsumer(SourceManager &SM, unsigned BufferId,
106+
llvm::raw_ostream &OS);
107+
~FindRenameRangesAnnotatingConsumer();
108+
void accept(SourceManager &SM, RegionType RegionType,
109+
ArrayRef<RenameRangeDetail> Ranges) override;
110+
};
111+
112+
StringRef getDescriptiveRefactoringKindName(RefactoringKind Kind);
113+
114+
StringRef getDescriptiveRenameUnavailableReason(RenameAvailableKind Kind);
115+
116+
bool refactorSwiftModule(ModuleDecl *M, RefactoringOptions Opts,
117+
SourceEditConsumer &EditConsumer,
118+
DiagnosticConsumer &DiagConsumer);
119+
120+
int syntacticRename(SourceFile *SF, llvm::ArrayRef<RenameLoc> RenameLocs,
121+
SourceEditConsumer &EditConsumer,
122+
DiagnosticConsumer &DiagConsumer);
123+
124+
int findSyntacticRenameRanges(SourceFile *SF,
125+
llvm::ArrayRef<RenameLoc> RenameLocs,
126+
FindRenameRangesConsumer &RenameConsumer,
127+
DiagnosticConsumer &DiagConsumer);
128+
129+
int findLocalRenameRanges(SourceFile *SF, RangeConfig Range,
130+
FindRenameRangesConsumer &RenameConsumer,
131+
DiagnosticConsumer &DiagConsumer);
132+
133+
ArrayRef<RefactoringKind>
134+
collectAvailableRefactorings(SourceFile *SF, RangeConfig Range,
135+
bool &RangeStartMayNeedRename,
136+
std::vector<RefactoringKind> &Scratch,
137+
llvm::ArrayRef<DiagnosticConsumer*> DiagConsumers);
138+
139+
ArrayRef<RefactoringKind>
140+
collectAvailableRefactorings(SourceFile *SF, SemaToken Tok,
141+
std::vector<RefactoringKind> &Scratch,
142+
bool ExcludeRename);
143+
144+
ArrayRef<RenameAvailabiliyInfo>
145+
collectRenameAvailabilityInfo(const ValueDecl *VD,
146+
std::vector<RenameAvailabiliyInfo> &Scratch);
147+
148+
} // namespace ide
149+
} // namespace swift
150+
151+
#endif // SWIFT_IDE_REFACTORING_H

0 commit comments

Comments
 (0)