@@ -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 ());
@@ -130,23 +129,40 @@ getFunctionSourceAfterReplacements(const FunctionDecl *FD,
130
129
return QualifiedFunc.takeError ();
131
130
132
131
std::string TemplatePrefix;
132
+ auto AddToTemplatePrefixIfApplicable = [&](const Decl *D, bool append) {
133
+ const TemplateParameterList *Params = D->getDescribedTemplateParams ();
134
+ if (!Params)
135
+ return ;
136
+ for (Decl *P : *Params) {
137
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(P))
138
+ TTP->removeDefaultArgument ();
139
+ else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
140
+ NTTP->removeDefaultArgument ();
141
+ else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(P))
142
+ TTPD->removeDefaultArgument ();
143
+ }
144
+ std::string S;
145
+ llvm::raw_string_ostream Stream (S);
146
+ Params->print (Stream, FD->getASTContext ());
147
+ if (!S.empty ())
148
+ *S.rbegin () = ' \n ' ; // Replace space with newline
149
+ if (append)
150
+ TemplatePrefix.append (S);
151
+ else
152
+ TemplatePrefix.insert (0 , S);
153
+ };
133
154
if (auto *MD = llvm::dyn_cast<CXXMethodDecl>(FD)) {
134
155
for (const CXXRecordDecl *Parent = MD->getParent (); Parent;
135
156
Parent =
136
157
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
- }
158
+ AddToTemplatePrefixIfApplicable (Parent, false );
146
159
}
147
160
}
148
161
162
+ AddToTemplatePrefixIfApplicable (FD, true );
149
163
auto Source = QualifiedFunc->substr (FuncBegin, FuncEnd - FuncBegin + 1 );
164
+ if (TargetFileIsHeader)
165
+ Source.insert (0 , " inline " );
150
166
if (!TemplatePrefix.empty ())
151
167
Source.insert (0 , TemplatePrefix);
152
168
return Source;
@@ -202,7 +218,8 @@ deleteTokensWithKind(const syntax::TokenBuffer &TokBuf, tok::TokenKind Kind,
202
218
llvm::Expected<std::string>
203
219
getFunctionSourceCode (const FunctionDecl *FD, const DeclContext *TargetContext,
204
220
const syntax::TokenBuffer &TokBuf,
205
- const HeuristicResolver *Resolver) {
221
+ const HeuristicResolver *Resolver,
222
+ bool targetFileIsHeader) {
206
223
auto &AST = FD->getASTContext ();
207
224
auto &SM = AST.getSourceManager ();
208
225
@@ -337,7 +354,8 @@ getFunctionSourceCode(const FunctionDecl *FD, const DeclContext *TargetContext,
337
354
338
355
if (Errors)
339
356
return std::move (Errors);
340
- return getFunctionSourceAfterReplacements (FD, DeclarationCleanups);
357
+ return getFunctionSourceAfterReplacements (FD, DeclarationCleanups,
358
+ targetFileIsHeader);
341
359
}
342
360
343
361
struct InsertionPoint {
@@ -419,15 +437,15 @@ class DefineOutline : public Tweak {
419
437
Source->isOutOfLine ())
420
438
return false ;
421
439
422
- // Bail out if this is a function template or specialization, as their
440
+ // Bail out if this is a function template specialization, as their
423
441
// definitions need to be visible in all including translation units.
424
- if (Source->getDescribedFunctionTemplate ())
425
- return false ;
426
442
if (Source->getTemplateSpecializationInfo ())
427
443
return false ;
428
444
429
445
auto *MD = llvm::dyn_cast<CXXMethodDecl>(Source);
430
446
if (!MD) {
447
+ if (Source->getDescribedFunctionTemplate ())
448
+ return false ;
431
449
// Can't outline free-standing functions in the same file.
432
450
return !SameFile;
433
451
}
@@ -443,13 +461,26 @@ class DefineOutline : public Tweak {
443
461
SameFile = true ;
444
462
445
463
// Bail out if the template parameter is unnamed.
464
+ // FIXME: Is this really needed? It inhibits application on
465
+ // e.g. std::enable_if.
446
466
for (NamedDecl *P : *Params) {
447
467
if (!P->getIdentifier ())
448
468
return false ;
449
469
}
450
470
}
451
471
}
452
472
473
+ // For function templates, the same limitations as for class templates
474
+ // apply.
475
+ if (const TemplateParameterList *Params =
476
+ MD->getDescribedTemplateParams ()) {
477
+ for (NamedDecl *P : *Params) {
478
+ if (!P->getIdentifier ())
479
+ return false ;
480
+ }
481
+ SameFile = true ;
482
+ }
483
+
453
484
// The refactoring is meaningless for unnamed classes and namespaces,
454
485
// unless we're outlining in the same file
455
486
for (const DeclContext *DC = MD->getParent (); DC; DC = DC->getParent ()) {
@@ -485,7 +516,8 @@ class DefineOutline : public Tweak {
485
516
486
517
auto FuncDef = getFunctionSourceCode (
487
518
Source, InsertionPoint->EnclosingNamespace , Sel.AST ->getTokens (),
488
- Sel.AST ->getHeuristicResolver ());
519
+ Sel.AST ->getHeuristicResolver (),
520
+ SameFile && isHeaderFile (Sel.AST ->tuPath (), Sel.AST ->getLangOpts ()));
489
521
if (!FuncDef)
490
522
return FuncDef.takeError ();
491
523
0 commit comments