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,28 +4694,58 @@ 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
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
+
4724
4749
void replace (ASTNode Node, SourceEditConsumer &EditConsumer,
4725
4750
SourceLoc StartOverride = SourceLoc()) {
4726
4751
SourceRange Range = Node.getSourceRange ();
@@ -4739,13 +4764,7 @@ class AsyncConversionStringBuilder : private SourceEntityWalker {
4739
4764
Buffer.clear ();
4740
4765
}
4741
4766
4742
- void convertFunction (const FuncDecl *FD) {
4743
- addFuncDecl (FD);
4744
- if (FD->getBody ()) {
4745
- convertNode (FD->getBody ());
4746
- }
4747
- }
4748
-
4767
+ private:
4749
4768
void convertNodes (ArrayRef<ASTNode> Nodes) {
4750
4769
for (auto Node : Nodes) {
4751
4770
OS << " \n " ;
@@ -4765,9 +4784,17 @@ class AsyncConversionStringBuilder : private SourceEntityWalker {
4765
4784
addRange (LastAddedLoc, Node.getEndLoc (), /* ToEndOfToken=*/ true );
4766
4785
}
4767
4786
4768
- private:
4769
4787
bool walkToDeclPre (Decl *D, CharSourceRange Range) override {
4770
- 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 ;
4771
4798
}
4772
4799
4773
4800
#define PLACEHOLDER_START " <#"
@@ -4805,9 +4832,8 @@ class AsyncConversionStringBuilder : private SourceEntityWalker {
4805
4832
[&]() { addHandlerCall (CE); });
4806
4833
4807
4834
if (auto *CE = dyn_cast<CallExpr>(E)) {
4808
- auto HandlerDesc =
4809
- AsyncHandlerDesc::find (getUnderlyingFunc (CE->getFn ()),
4810
- /* ignoreName=*/ true );
4835
+ auto HandlerDesc = AsyncHandlerDesc::find (
4836
+ getUnderlyingFunc (CE->getFn ()), StartNode.dyn_cast <Expr *>() == CE);
4811
4837
if (HandlerDesc.isValid ())
4812
4838
return addCustom (CE->getStartLoc (), CE->getEndLoc ().getAdvancedLoc (1 ),
4813
4839
[&]() { addAsyncAlternativeCall (CE, HandlerDesc); });
@@ -5259,13 +5285,11 @@ bool RefactoringActionConvertCallToAsyncAlternative::performChange() {
5259
5285
" Should not run performChange when refactoring is not applicable" );
5260
5286
5261
5287
AsyncHandlerDesc TempDesc;
5262
- AsyncConversionStringBuilder Builder (SM, DiagEngine, TempDesc);
5263
- Builder.convertNode (CE);
5264
-
5265
- if (DiagEngine.hadAnyError ())
5288
+ AsyncConverter Converter (SM, DiagEngine, CE, TempDesc);
5289
+ if (!Converter.convert ())
5266
5290
return true ;
5267
5291
5268
- Builder .replace (CE, EditConsumer);
5292
+ Converter .replace (CE, EditConsumer);
5269
5293
return false ;
5270
5294
}
5271
5295
@@ -5289,13 +5313,11 @@ bool RefactoringActionConvertToAsync::performChange() {
5289
5313
" Should not run performChange when refactoring is not applicable" );
5290
5314
5291
5315
AsyncHandlerDesc TempDesc;
5292
- AsyncConversionStringBuilder Builder (SM, DiagEngine, TempDesc);
5293
- Builder.convertFunction (FD);
5294
-
5295
- if (DiagEngine.hadAnyError ())
5316
+ AsyncConverter Converter (SM, DiagEngine, FD, TempDesc);
5317
+ if (!Converter.convert ())
5296
5318
return true ;
5297
5319
5298
- Builder .replace (FD, EditConsumer, FD->getSourceRangeIncludingAttrs ().Start );
5320
+ Converter .replace (FD, EditConsumer, FD->getSourceRangeIncludingAttrs ().Start );
5299
5321
return false ;
5300
5322
}
5301
5323
@@ -5328,16 +5350,14 @@ bool RefactoringActionAddAsyncAlternative::performChange() {
5328
5350
assert (HandlerDesc.isValid () &&
5329
5351
" Should not run performChange when refactoring is not applicable" );
5330
5352
5331
- AsyncConversionStringBuilder Builder (SM, DiagEngine, HandlerDesc);
5332
- Builder.convertFunction (FD);
5333
-
5334
- if (DiagEngine.hadAnyError ())
5353
+ AsyncConverter Converter (SM, DiagEngine, FD, HandlerDesc);
5354
+ if (!Converter.convert ())
5335
5355
return true ;
5336
5356
5337
5357
EditConsumer.accept (SM, FD->getAttributeInsertionLoc (false ),
5338
5358
" @available(*, deprecated, message: \" Prefer async "
5339
5359
" alternative instead\" )\n " );
5340
- Builder .insertAfter (FD, EditConsumer);
5360
+ Converter .insertAfter (FD, EditConsumer);
5341
5361
5342
5362
return false ;
5343
5363
}
0 commit comments