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