28
28
#include " swift/Frontend/Frontend.h"
29
29
#include " swift/IDE/IDERequests.h"
30
30
#include " swift/Index/Index.h"
31
+ #include " swift/ClangImporter/ClangImporter.h"
31
32
#include " swift/Parse/Lexer.h"
32
33
#include " swift/Sema/IDETypeChecking.h"
33
34
#include " swift/Subsystems.h"
@@ -3894,12 +3895,6 @@ namespace asyncrefactorings {
3894
3895
3895
3896
// TODO: Should probably split the refactorings into separate files
3896
3897
3897
- // / Whether the given parameter name identifies a completion callback
3898
- bool isCompletionHandlerName (StringRef Name) {
3899
- return Name.startswith (" completion" ) || Name.contains (" Completion" ) ||
3900
- Name.contains (" Complete" );
3901
- }
3902
-
3903
3898
// / Whether the given type is the stdlib Result type
3904
3899
bool isResultType (Type Ty) {
3905
3900
if (!Ty)
@@ -4083,7 +4078,7 @@ struct AsyncHandlerDesc {
4083
4078
HandlerType Type = HandlerType::INVALID;
4084
4079
bool HasError = false ;
4085
4080
4086
- static AsyncHandlerDesc find (const FuncDecl *FD, bool ignoreName = false ) {
4081
+ static AsyncHandlerDesc find (const FuncDecl *FD, bool ignoreName) {
4087
4082
if (!FD || FD->hasAsync () || FD->hasThrows ())
4088
4083
return AsyncHandlerDesc ();
4089
4084
@@ -4104,7 +4099,7 @@ struct AsyncHandlerDesc {
4104
4099
4105
4100
// Callback must have a completion-like name (if we're not ignoring it)
4106
4101
if (!ignoreName &&
4107
- !isCompletionHandlerName (HandlerDesc.Handler ->getNameStr ()))
4102
+ !isCompletionHandlerParamName (HandlerDesc.Handler ->getNameStr ()))
4108
4103
return AsyncHandlerDesc ();
4109
4104
4110
4105
// Callback must be a function type and return void. Doesn't need to have
@@ -4670,12 +4665,12 @@ struct CallbackClassifier {
4670
4665
}
4671
4666
};
4672
4667
4673
- // / Builds up async-converted code for any added AST nodes .
4668
+ // / Builds up async-converted code for an AST node .
4674
4669
// /
4675
- // / Function declarations will have `async` added. If a completion handler is
4676
- // / present, it will be removed and the return type of the function will
4677
- // / reflect the parameters of the handler, including an added `throws` if
4678
- // / necessary.
4670
+ // / If it is a function, its declaration will have `async` added. If a
4671
+ // / completion handler is present, it will be removed and the return type of
4672
+ // / the function will reflect the parameters of the handler, including an
4673
+ // / added `throws` if necessary.
4679
4674
// /
4680
4675
// / Calls to the completion handler are replaced with either a `return` or
4681
4676
// / `throws` depending on the arguments.
@@ -4699,32 +4694,67 @@ struct CallbackClassifier {
4699
4694
// / The fallback is generally avoided, however, since it's quite unlikely to be
4700
4695
// / the code the user intended. In most cases the refactoring will continue,
4701
4696
// / with any unhandled decls wrapped in placeholders instead.
4702
- class AsyncConversionStringBuilder : private SourceEntityWalker {
4697
+ class AsyncConverter : private SourceEntityWalker {
4703
4698
SourceManager &SM;
4704
4699
DiagnosticEngine &DiagEngine;
4700
+
4701
+ // Node to convert
4702
+ ASTNode StartNode;
4703
+
4704
+ // Completion handler of `StartNode` (if it's a function with an async
4705
+ // alternative)
4705
4706
const AsyncHandlerDesc &TopHandler;
4706
4707
SmallString<0 > Buffer;
4707
4708
llvm::raw_svector_ostream OS;
4708
4709
4710
+ // Decls where any force-unwrap of that decl should be unwrapped, eg. for a
4711
+ // previously optional closure paramter has become a non-optional local
4709
4712
llvm::DenseSet<const Decl *> Unwraps;
4713
+ // Decls whose references should be replaced with, either because they no
4714
+ // longer exist or are a different type. Any replaced code should ideally be
4715
+ // handled by the refactoring properly, but that's not possible in all cases
4710
4716
llvm::DenseSet<const Decl *> Placeholders;
4717
+ // Mapping from decl -> name, used as both the name of possibly new local
4718
+ // declarations of old parameters, as well as the replacement for any
4719
+ // references to it
4711
4720
llvm::DenseMap<const Decl *, std::string> Names;
4712
4721
4722
+ // These are per-node (ie. are saved and restored on each convertNode call)
4713
4723
SourceLoc LastAddedLoc;
4714
4724
int NestedExprCount = 0 ;
4715
4725
4716
4726
public:
4717
- AsyncConversionStringBuilder (SourceManager &SM, DiagnosticEngine &DiagEngine,
4718
- const AsyncHandlerDesc &TopHandler)
4719
- : SM(SM), DiagEngine(DiagEngine), TopHandler(TopHandler), Buffer( ),
4720
- OS (Buffer) {
4727
+ AsyncConverter (SourceManager &SM, DiagnosticEngine &DiagEngine,
4728
+ ASTNode StartNode, const AsyncHandlerDesc &TopHandler)
4729
+ : SM(SM), DiagEngine(DiagEngine), StartNode(StartNode ),
4730
+ TopHandler (TopHandler), Buffer(), OS(Buffer) {
4721
4731
Placeholders.insert (TopHandler.Handler );
4722
4732
}
4723
4733
4724
- void replace (ASTNode Node, SourceEditConsumer &EditConsumer) {
4725
- CharSourceRange Range =
4726
- Lexer::getCharSourceRangeFromSourceRange (SM, Node.getSourceRange ());
4727
- EditConsumer.accept (SM, Range, Buffer.str ());
4734
+ bool convert () {
4735
+ if (!Buffer.empty ())
4736
+ return !DiagEngine.hadAnyError ();
4737
+
4738
+ if (auto *FD = dyn_cast_or_null<FuncDecl>(StartNode.dyn_cast <Decl *>())) {
4739
+ addFuncDecl (FD);
4740
+ if (FD->getBody ()) {
4741
+ convertNode (FD->getBody ());
4742
+ }
4743
+ } else {
4744
+ convertNode (StartNode);
4745
+ }
4746
+ return !DiagEngine.hadAnyError ();
4747
+ }
4748
+
4749
+ void replace (ASTNode Node, SourceEditConsumer &EditConsumer,
4750
+ SourceLoc StartOverride = SourceLoc()) {
4751
+ SourceRange Range = Node.getSourceRange ();
4752
+ if (StartOverride.isValid ()) {
4753
+ Range = SourceRange (StartOverride, Range.End );
4754
+ }
4755
+ CharSourceRange CharRange =
4756
+ Lexer::getCharSourceRangeFromSourceRange (SM, Range);
4757
+ EditConsumer.accept (SM, CharRange, Buffer.str ());
4728
4758
Buffer.clear ();
4729
4759
}
4730
4760
@@ -4734,13 +4764,7 @@ class AsyncConversionStringBuilder : private SourceEntityWalker {
4734
4764
Buffer.clear ();
4735
4765
}
4736
4766
4737
- void convertFunction (const FuncDecl *FD) {
4738
- addFuncDecl (FD);
4739
- if (FD->getBody ()) {
4740
- convertNode (FD->getBody ());
4741
- }
4742
- }
4743
-
4767
+ private:
4744
4768
void convertNodes (ArrayRef<ASTNode> Nodes) {
4745
4769
for (auto Node : Nodes) {
4746
4770
OS << " \n " ;
@@ -4760,9 +4784,17 @@ class AsyncConversionStringBuilder : private SourceEntityWalker {
4760
4784
addRange (LastAddedLoc, Node.getEndLoc (), /* ToEndOfToken=*/ true );
4761
4785
}
4762
4786
4763
- private:
4764
4787
bool walkToDeclPre (Decl *D, CharSourceRange Range) override {
4765
- return isa<PatternBindingDecl>(D);
4788
+ if (isa<PatternBindingDecl>(D)) {
4789
+ NestedExprCount++;
4790
+ return true ;
4791
+ }
4792
+ return false ;
4793
+ }
4794
+
4795
+ bool walkToDeclPost (Decl *D) override {
4796
+ NestedExprCount--;
4797
+ return true ;
4766
4798
}
4767
4799
4768
4800
#define PLACEHOLDER_START " <#"
@@ -4800,9 +4832,8 @@ class AsyncConversionStringBuilder : private SourceEntityWalker {
4800
4832
[&]() { addHandlerCall (CE); });
4801
4833
4802
4834
if (auto *CE = dyn_cast<CallExpr>(E)) {
4803
- auto HandlerDesc =
4804
- AsyncHandlerDesc::find (getUnderlyingFunc (CE->getFn ()),
4805
- /* ignoreName=*/ true );
4835
+ auto HandlerDesc = AsyncHandlerDesc::find (
4836
+ getUnderlyingFunc (CE->getFn ()), StartNode.dyn_cast <Expr *>() == CE);
4806
4837
if (HandlerDesc.isValid ())
4807
4838
return addCustom (CE->getStartLoc (), CE->getEndLoc ().getAdvancedLoc (1 ),
4808
4839
[&]() { addAsyncAlternativeCall (CE, HandlerDesc); });
@@ -4986,7 +5017,12 @@ class AsyncConversionStringBuilder : private SourceEntityWalker {
4986
5017
DiagEngine.diagnose (CE->getStartLoc (), diag::missing_callback_arg);
4987
5018
return ;
4988
5019
}
5020
+
4989
5021
auto Callback = dyn_cast<ClosureExpr>(ArgList.ref ()[HandlerDesc.Index ]);
5022
+ auto Capture = dyn_cast<CaptureListExpr>(ArgList.ref ()[HandlerDesc.Index ]);
5023
+ if (Capture) {
5024
+ Callback = Capture->getClosureBody ();
5025
+ }
4990
5026
if (!Callback) {
4991
5027
DiagEngine.diagnose (CE->getStartLoc (), diag::missing_callback_arg);
4992
5028
return ;
@@ -5119,12 +5155,17 @@ class AsyncConversionStringBuilder : private SourceEntityWalker {
5119
5155
/* ToEndOfToken=*/ true );
5120
5156
5121
5157
OS << tok::l_paren;
5158
+ size_t realArgCount = 0 ;
5122
5159
for (size_t I = 0 , E = Args.size () - 1 ; I < E; ++I) {
5123
- if (I > 0 )
5160
+ if (isa<DefaultArgumentExpr>(Args[I]))
5161
+ continue ;
5162
+
5163
+ if (realArgCount > 0 )
5124
5164
OS << tok::comma << " " ;
5125
5165
// Can't just add the range as we need to perform replacements
5126
5166
convertNode (Args[I], /* StartOverride=*/ CE->getArgumentLabelLoc (I),
5127
5167
/* ConvertCalls=*/ false );
5168
+ realArgCount++;
5128
5169
}
5129
5170
OS << tok::r_paren;
5130
5171
}
@@ -5249,13 +5290,11 @@ bool RefactoringActionConvertCallToAsyncAlternative::performChange() {
5249
5290
" Should not run performChange when refactoring is not applicable" );
5250
5291
5251
5292
AsyncHandlerDesc TempDesc;
5252
- AsyncConversionStringBuilder Builder (SM, DiagEngine, TempDesc);
5253
- Builder.convertNode (CE);
5254
-
5255
- if (DiagEngine.hadAnyError ())
5293
+ AsyncConverter Converter (SM, DiagEngine, CE, TempDesc);
5294
+ if (!Converter.convert ())
5256
5295
return true ;
5257
5296
5258
- Builder .replace (CE, EditConsumer);
5297
+ Converter .replace (CE, EditConsumer);
5259
5298
return false ;
5260
5299
}
5261
5300
@@ -5279,13 +5318,11 @@ bool RefactoringActionConvertToAsync::performChange() {
5279
5318
" Should not run performChange when refactoring is not applicable" );
5280
5319
5281
5320
AsyncHandlerDesc TempDesc;
5282
- AsyncConversionStringBuilder Builder (SM, DiagEngine, TempDesc);
5283
- Builder.convertFunction (FD);
5284
-
5285
- if (DiagEngine.hadAnyError ())
5321
+ AsyncConverter Converter (SM, DiagEngine, FD, TempDesc);
5322
+ if (!Converter.convert ())
5286
5323
return true ;
5287
5324
5288
- Builder .replace (FD, EditConsumer);
5325
+ Converter .replace (FD, EditConsumer, FD-> getSourceRangeIncludingAttrs (). Start );
5289
5326
return false ;
5290
5327
}
5291
5328
@@ -5318,16 +5355,14 @@ bool RefactoringActionAddAsyncAlternative::performChange() {
5318
5355
assert (HandlerDesc.isValid () &&
5319
5356
" Should not run performChange when refactoring is not applicable" );
5320
5357
5321
- AsyncConversionStringBuilder Builder (SM, DiagEngine, HandlerDesc);
5322
- Builder.convertFunction (FD);
5323
-
5324
- if (DiagEngine.hadAnyError ())
5358
+ AsyncConverter Converter (SM, DiagEngine, FD, HandlerDesc);
5359
+ if (!Converter.convert ())
5325
5360
return true ;
5326
5361
5327
5362
EditConsumer.accept (SM, FD->getAttributeInsertionLoc (false ),
5328
5363
" @available(*, deprecated, message: \" Prefer async "
5329
5364
" alternative instead\" )\n " );
5330
- Builder .insertAfter (FD, EditConsumer);
5365
+ Converter .insertAfter (FD, EditConsumer);
5331
5366
5332
5367
return false ;
5333
5368
}
0 commit comments