@@ -109,14 +109,13 @@ findContextForNS(llvm::StringRef TargetNS, const DeclContext *CurContext) {
109
109
// afterwards it can be shared with define-inline code action.
110
110
llvm::Expected<std::string>
111
111
getFunctionSourceAfterReplacements (const FunctionDecl *FD,
112
- const tooling::Replacements &Replacements) {
112
+ const tooling::Replacements &Replacements,
113
+ bool TargetFileIsHeader) {
113
114
const auto &SM = FD->getASTContext ().getSourceManager ();
114
115
auto OrigFuncRange = toHalfOpenFileRange (
115
116
SM, FD->getASTContext ().getLangOpts (), FD->getSourceRange ());
116
117
if (!OrigFuncRange)
117
118
return error (" Couldn't get range for function." );
118
- assert (!FD->getDescribedFunctionTemplate () &&
119
- " Define out-of-line doesn't apply to function templates." );
120
119
121
120
// Get new begin and end positions for the qualified function definition.
122
121
unsigned FuncBegin = SM.getFileOffset (OrigFuncRange->getBegin ());
@@ -129,24 +128,38 @@ getFunctionSourceAfterReplacements(const FunctionDecl *FD,
129
128
if (!QualifiedFunc)
130
129
return QualifiedFunc.takeError ();
131
130
131
+ auto Source = QualifiedFunc->substr (FuncBegin, FuncEnd - FuncBegin + 1 );
132
132
std::string TemplatePrefix;
133
+ auto AddToTemplatePrefixIfApplicable = [&](const Decl *D) {
134
+ const TemplateParameterList *Params = D->getDescribedTemplateParams ();
135
+ if (!Params)
136
+ return ;
137
+ for (Decl *P : *Params) {
138
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(P))
139
+ TTP->removeDefaultArgument ();
140
+ else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
141
+ NTTP->removeDefaultArgument ();
142
+ else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(P))
143
+ TTPD->removeDefaultArgument ();
144
+ }
145
+ std::string S;
146
+ llvm::raw_string_ostream Stream (S);
147
+ Params->print (Stream, FD->getASTContext ());
148
+ if (!S.empty ())
149
+ *S.rbegin () = ' \n ' ; // Replace space with newline
150
+ TemplatePrefix.insert (0 , S);
151
+ };
152
+ AddToTemplatePrefixIfApplicable (FD);
133
153
if (auto *MD = llvm::dyn_cast<CXXMethodDecl>(FD)) {
134
154
for (const CXXRecordDecl *Parent = MD->getParent (); Parent;
135
155
Parent =
136
156
llvm::dyn_cast_or_null<const CXXRecordDecl>(Parent->getParent ())) {
137
- if (const TemplateParameterList *Params =
138
- Parent->getDescribedTemplateParams ()) {
139
- std::string S;
140
- llvm::raw_string_ostream Stream (S);
141
- Params->print (Stream, FD->getASTContext ());
142
- if (!S.empty ())
143
- *S.rbegin () = ' \n ' ; // Replace space with newline
144
- TemplatePrefix.insert (0 , S);
145
- }
157
+ AddToTemplatePrefixIfApplicable (Parent);
146
158
}
147
159
}
148
160
149
- auto Source = QualifiedFunc->substr (FuncBegin, FuncEnd - FuncBegin + 1 );
161
+ if (TargetFileIsHeader)
162
+ Source.insert (0 , " inline " );
150
163
if (!TemplatePrefix.empty ())
151
164
Source.insert (0 , TemplatePrefix);
152
165
return Source;
@@ -202,7 +215,8 @@ deleteTokensWithKind(const syntax::TokenBuffer &TokBuf, tok::TokenKind Kind,
202
215
llvm::Expected<std::string>
203
216
getFunctionSourceCode (const FunctionDecl *FD, const DeclContext *TargetContext,
204
217
const syntax::TokenBuffer &TokBuf,
205
- const HeuristicResolver *Resolver) {
218
+ const HeuristicResolver *Resolver,
219
+ bool TargetFileIsHeader) {
206
220
auto &AST = FD->getASTContext ();
207
221
auto &SM = AST.getSourceManager ();
208
222
@@ -337,7 +351,8 @@ getFunctionSourceCode(const FunctionDecl *FD, const DeclContext *TargetContext,
337
351
338
352
if (Errors)
339
353
return std::move (Errors);
340
- return getFunctionSourceAfterReplacements (FD, DeclarationCleanups);
354
+ return getFunctionSourceAfterReplacements (FD, DeclarationCleanups,
355
+ TargetFileIsHeader);
341
356
}
342
357
343
358
struct InsertionPoint {
@@ -419,15 +434,15 @@ class DefineOutline : public Tweak {
419
434
Source->isOutOfLine ())
420
435
return false ;
421
436
422
- // Bail out if this is a function template or specialization, as their
437
+ // Bail out if this is a function template specialization, as their
423
438
// definitions need to be visible in all including translation units.
424
- if (Source->getDescribedFunctionTemplate ())
425
- return false ;
426
439
if (Source->getTemplateSpecializationInfo ())
427
440
return false ;
428
441
429
442
auto *MD = llvm::dyn_cast<CXXMethodDecl>(Source);
430
443
if (!MD) {
444
+ if (Source->getDescribedFunctionTemplate ())
445
+ return false ;
431
446
// Can't outline free-standing functions in the same file.
432
447
return !SameFile;
433
448
}
@@ -450,6 +465,19 @@ class DefineOutline : public Tweak {
450
465
}
451
466
}
452
467
468
+ // For function templates, the same limitations as for class templates
469
+ // apply.
470
+ if (const TemplateParameterList *Params =
471
+ MD->getDescribedTemplateParams ()) {
472
+ // FIXME: Is this really needed? It inhibits application on
473
+ // e.g. std::enable_if.
474
+ for (NamedDecl *P : *Params) {
475
+ if (!P->getIdentifier ())
476
+ return false ;
477
+ }
478
+ SameFile = true ;
479
+ }
480
+
453
481
// The refactoring is meaningless for unnamed classes and namespaces,
454
482
// unless we're outlining in the same file
455
483
for (const DeclContext *DC = MD->getParent (); DC; DC = DC->getParent ()) {
@@ -485,7 +513,8 @@ class DefineOutline : public Tweak {
485
513
486
514
auto FuncDef = getFunctionSourceCode (
487
515
Source, InsertionPoint->EnclosingNamespace , Sel.AST ->getTokens (),
488
- Sel.AST ->getHeuristicResolver ());
516
+ Sel.AST ->getHeuristicResolver (),
517
+ SameFile && isHeaderFile (Sel.AST ->tuPath (), Sel.AST ->getLangOpts ()));
489
518
if (!FuncDef)
490
519
return FuncDef.takeError ();
491
520
0 commit comments