|
10 | 10 | #include "FindTarget.h"
|
11 | 11 | #include "HeaderSourceSwitch.h"
|
12 | 12 | #include "Logger.h"
|
| 13 | +#include "ParsedAST.h" |
13 | 14 | #include "Path.h"
|
14 | 15 | #include "Selection.h"
|
15 | 16 | #include "SourceCode.h"
|
|
21 | 22 | #include "clang/AST/Stmt.h"
|
22 | 23 | #include "clang/Basic/SourceLocation.h"
|
23 | 24 | #include "clang/Basic/SourceManager.h"
|
| 25 | +#include "clang/Basic/TokenKinds.h" |
24 | 26 | #include "clang/Driver/Types.h"
|
25 | 27 | #include "clang/Format/Format.h"
|
| 28 | +#include "clang/Lex/Lexer.h" |
26 | 29 | #include "clang/Tooling/Core/Replacement.h"
|
| 30 | +#include "clang/Tooling/Syntax/Tokens.h" |
27 | 31 | #include "llvm/ADT/None.h"
|
28 | 32 | #include "llvm/ADT/Optional.h"
|
| 33 | +#include "llvm/ADT/STLExtras.h" |
29 | 34 | #include "llvm/ADT/StringRef.h"
|
30 | 35 | #include "llvm/Support/Casting.h"
|
31 | 36 | #include "llvm/Support/Error.h"
|
@@ -133,12 +138,14 @@ getFunctionSourceAfterReplacements(const FunctionDecl *FD,
|
133 | 138 |
|
134 | 139 | // Creates a modified version of function definition that can be inserted at a
|
135 | 140 | // different location, qualifies return value and function name to achieve that.
|
136 |
| -// Contains function signature, body and template parameters if applicable. |
137 |
| -// No need to qualify parameters, as they are looked up in the context |
138 |
| -// containing the function/method. |
| 141 | +// Contains function signature, except defaulted parameter arguments, body and |
| 142 | +// template parameters if applicable. No need to qualify parameters, as they are |
| 143 | +// looked up in the context containing the function/method. |
139 | 144 | llvm::Expected<std::string>
|
140 |
| -getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace) { |
141 |
| - auto &SM = FD->getASTContext().getSourceManager(); |
| 145 | +getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace, |
| 146 | + const syntax::TokenBuffer &TokBuf) { |
| 147 | + auto &AST = FD->getASTContext(); |
| 148 | + auto &SM = AST.getSourceManager(); |
142 | 149 | auto TargetContext = findContextForNS(TargetNamespace, FD->getDeclContext());
|
143 | 150 | if (!TargetContext)
|
144 | 151 | return llvm::createStringError(
|
@@ -169,14 +176,38 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace) {
|
169 | 176 | }
|
170 | 177 | }
|
171 | 178 | const NamedDecl *ND = Ref.Targets.front();
|
172 |
| - const std::string Qualifier = |
173 |
| - getQualification(FD->getASTContext(), *TargetContext, |
174 |
| - SM.getLocForStartOfFile(SM.getMainFileID()), ND); |
| 179 | + const std::string Qualifier = getQualification( |
| 180 | + AST, *TargetContext, SM.getLocForStartOfFile(SM.getMainFileID()), ND); |
175 | 181 | if (auto Err = QualifierInsertions.add(
|
176 | 182 | tooling::Replacement(SM, Ref.NameLoc, 0, Qualifier)))
|
177 | 183 | Errors = llvm::joinErrors(std::move(Errors), std::move(Err));
|
178 | 184 | });
|
179 | 185 |
|
| 186 | + // Get rid of default arguments, since they should not be specified in |
| 187 | + // out-of-line definition. |
| 188 | + for (const auto *PVD : FD->parameters()) { |
| 189 | + if (PVD->hasDefaultArg()) { |
| 190 | + // Deletion range initially spans the initializer, excluding the `=`. |
| 191 | + auto DelRange = CharSourceRange::getTokenRange(PVD->getDefaultArgRange()); |
| 192 | + // Get all tokens before the default argument. |
| 193 | + auto Tokens = TokBuf.expandedTokens(PVD->getSourceRange()) |
| 194 | + .take_while([&SM, &DelRange](const syntax::Token &Tok) { |
| 195 | + return SM.isBeforeInTranslationUnit( |
| 196 | + Tok.location(), DelRange.getBegin()); |
| 197 | + }); |
| 198 | + // Find the last `=` before the default arg. |
| 199 | + auto Tok = |
| 200 | + llvm::find_if(llvm::reverse(Tokens), [](const syntax::Token &Tok) { |
| 201 | + return Tok.kind() == tok::equal; |
| 202 | + }); |
| 203 | + assert(Tok != Tokens.rend()); |
| 204 | + DelRange.setBegin(Tok->location()); |
| 205 | + if (auto Err = |
| 206 | + QualifierInsertions.add(tooling::Replacement(SM, DelRange, ""))) |
| 207 | + Errors = llvm::joinErrors(std::move(Errors), std::move(Err)); |
| 208 | + } |
| 209 | + } |
| 210 | + |
180 | 211 | if (Errors)
|
181 | 212 | return std::move(Errors);
|
182 | 213 | return getFunctionSourceAfterReplacements(FD, QualifierInsertions);
|
@@ -290,8 +321,8 @@ class DefineOutline : public Tweak {
|
290 | 321 | if (!InsertionPoint)
|
291 | 322 | return InsertionPoint.takeError();
|
292 | 323 |
|
293 |
| - auto FuncDef = |
294 |
| - getFunctionSourceCode(Source, InsertionPoint->EnclosingNamespace); |
| 324 | + auto FuncDef = getFunctionSourceCode( |
| 325 | + Source, InsertionPoint->EnclosingNamespace, Sel.AST.getTokens()); |
295 | 326 | if (!FuncDef)
|
296 | 327 | return FuncDef.takeError();
|
297 | 328 |
|
|
0 commit comments