Skip to content

Commit 73f49fd

Browse files
author
Eric Liu
committedOct 12, 2016
[change-namespace] don't miss comments in the beginning of a namespace block.
Reviewers: hokein Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D25397 llvm-svn: 284011
1 parent cc1ba8c commit 73f49fd

File tree

2 files changed

+73
-13
lines changed

2 files changed

+73
-13
lines changed
 

‎clang-tools-extra/change-namespace/ChangeNamespace.cpp

+41-13
Original file line numberDiff line numberDiff line change
@@ -82,33 +82,42 @@ const NamespaceDecl *getOuterNamespace(const NamespaceDecl *InnerNs,
8282
return CurrentNs;
8383
}
8484

85-
// FIXME: get rid of this helper function if this is supported in clang-refactor
86-
// library.
87-
SourceLocation getStartOfNextLine(SourceLocation Loc, const SourceManager &SM,
88-
const LangOptions &LangOpts) {
85+
static std::unique_ptr<Lexer>
86+
getLexerStartingFromLoc(SourceLocation Loc, const SourceManager &SM,
87+
const LangOptions &LangOpts) {
8988
if (Loc.isMacroID() &&
9089
!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
91-
return SourceLocation();
90+
return nullptr;
9291
// Break down the source location.
9392
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
9493
// Try to load the file buffer.
9594
bool InvalidTemp = false;
9695
llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
9796
if (InvalidTemp)
98-
return SourceLocation();
97+
return nullptr;
9998

10099
const char *TokBegin = File.data() + LocInfo.second;
101100
// Lex from the start of the given location.
102-
Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
103-
TokBegin, File.end());
101+
return llvm::make_unique<Lexer>(SM.getLocForStartOfFile(LocInfo.first),
102+
LangOpts, File.begin(), TokBegin, File.end());
103+
}
104104

105+
// FIXME: get rid of this helper function if this is supported in clang-refactor
106+
// library.
107+
static SourceLocation getStartOfNextLine(SourceLocation Loc,
108+
const SourceManager &SM,
109+
const LangOptions &LangOpts) {
110+
std::unique_ptr<Lexer> Lex = getLexerStartingFromLoc(Loc, SM, LangOpts);
111+
if (!Lex.get())
112+
return SourceLocation();
105113
llvm::SmallVector<char, 16> Line;
106114
// FIXME: this is a bit hacky to get ReadToEndOfLine work.
107-
Lex.setParsingPreprocessorDirective(true);
108-
Lex.ReadToEndOfLine(&Line);
115+
Lex->setParsingPreprocessorDirective(true);
116+
Lex->ReadToEndOfLine(&Line);
109117
auto End = Loc.getLocWithOffset(Line.size());
110-
return SM.getLocForEndOfFile(LocInfo.first) == End ? End
111-
: End.getLocWithOffset(1);
118+
return SM.getLocForEndOfFile(SM.getDecomposedLoc(Loc).first) == End
119+
? End
120+
: End.getLocWithOffset(1);
112121
}
113122

114123
// Returns `R` with new range that refers to code after `Replaces` being
@@ -365,6 +374,23 @@ void ChangeNamespaceTool::run(
365374
}
366375
}
367376

377+
static SourceLocation getLocAfterNamespaceLBrace(const NamespaceDecl *NsDecl,
378+
const SourceManager &SM,
379+
const LangOptions &LangOpts) {
380+
std::unique_ptr<Lexer> Lex =
381+
getLexerStartingFromLoc(NsDecl->getLocStart(), SM, LangOpts);
382+
assert(Lex.get() &&
383+
"Failed to create lexer from the beginning of namespace.");
384+
if (!Lex.get())
385+
return SourceLocation();
386+
Token Tok;
387+
while (!Lex->LexFromRawLexer(Tok) && Tok.isNot(tok::TokenKind::l_brace)) {
388+
}
389+
return Tok.isNot(tok::TokenKind::l_brace)
390+
? SourceLocation()
391+
: Tok.getEndLoc().getLocWithOffset(1);
392+
}
393+
368394
// Stores information about a moved namespace in `MoveNamespaces` and leaves
369395
// the actual movement to `onEndOfTranslationUnit()`.
370396
void ChangeNamespaceTool::moveOldNamespace(
@@ -375,7 +401,9 @@ void ChangeNamespaceTool::moveOldNamespace(
375401
return;
376402

377403
// Get the range of the code in the old namespace.
378-
SourceLocation Start = NsDecl->decls_begin()->getLocStart();
404+
SourceLocation Start = getLocAfterNamespaceLBrace(
405+
NsDecl, *Result.SourceManager, Result.Context->getLangOpts());
406+
assert(Start.isValid() && "Can't find l_brace for namespace.");
379407
SourceLocation End = NsDecl->getRBraceLoc().getLocWithOffset(-1);
380408
// Create a replacement that deletes the code in the old namespace merely for
381409
// retrieving offset and length from it.

‎clang-tools-extra/unittests/change-namespace/ChangeNamespaceTests.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,38 @@ TEST_F(ChangeNamespaceTest, NoMisplaceAtEOF) {
552552
EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
553553
}
554554

555+
TEST_F(ChangeNamespaceTest, CommentsBeforeMovedClass) {
556+
std::string Code = "namespace na {\n"
557+
"namespace nb {\n"
558+
"\n\n"
559+
"// Wild comments.\n"
560+
"\n"
561+
"// Comments.\n"
562+
"// More comments.\n"
563+
"class B {\n"
564+
" // Private comments.\n"
565+
" int a;\n"
566+
"};\n"
567+
"}\n"
568+
"}";
569+
std::string Expected = "\n"
570+
"\n"
571+
"namespace x {\n"
572+
"namespace y {\n"
573+
"\n\n"
574+
"// Wild comments.\n"
575+
"\n"
576+
"// Comments.\n"
577+
"// More comments.\n"
578+
"class B {\n"
579+
" // Private comments.\n"
580+
" int a;\n"
581+
"};\n"
582+
"} // namespace y\n"
583+
"} // namespace x\n";
584+
EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
585+
}
586+
555587
} // anonymous namespace
556588
} // namespace change_namespace
557589
} // namespace clang

0 commit comments

Comments
 (0)