[clang-tools-extra] r283425 - [clang-move] Move comments which are associated with the moved class.

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 6 01:59:24 PDT 2016


Author: hokein
Date: Thu Oct  6 03:59:24 2016
New Revision: 283425

URL: http://llvm.org/viewvc/llvm-project?rev=283425&view=rev
Log:
[clang-move] Move comments which are associated with the moved class.

Reviewers: ioeric

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D25227

Modified:
    clang-tools-extra/trunk/clang-move/ClangMove.cpp
    clang-tools-extra/trunk/clang-move/ClangMove.h
    clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp
    clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp

Modified: clang-tools-extra/trunk/clang-move/ClangMove.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/ClangMove.cpp?rev=283425&r1=283424&r2=283425&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/ClangMove.cpp (original)
+++ clang-tools-extra/trunk/clang-move/ClangMove.cpp Thu Oct  6 03:59:24 2016
@@ -94,6 +94,64 @@ private:
   ClangMoveTool *const MoveTool;
 };
 
+// Expand to get the end location of the line where the EndLoc of the given
+// Decl.
+SourceLocation
+getLocForEndOfDecl(const clang::Decl *D, const SourceManager *SM,
+                   const LangOptions &LangOpts = clang::LangOptions()) {
+  std::pair<FileID, unsigned> LocInfo = SM->getDecomposedLoc(D->getLocEnd());
+  // Try to load the file buffer.
+  bool InvalidTemp = false;
+  llvm::StringRef File = SM->getBufferData(LocInfo.first, &InvalidTemp);
+  if (InvalidTemp)
+    return SourceLocation();
+
+  const char *TokBegin = File.data() + LocInfo.second;
+  // Lex from the start of the given location.
+  Lexer Lex(SM->getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
+            TokBegin, File.end());
+
+  llvm::SmallVector<char, 16> Line;
+  // FIXME: this is a bit hacky to get ReadToEndOfLine work.
+  Lex.setParsingPreprocessorDirective(true);
+  Lex.ReadToEndOfLine(&Line);
+  SourceLocation EndLoc  = D->getLocEnd().getLocWithOffset(Line.size());
+  // If we already reach EOF, just return the EOF SourceLocation;
+  // otherwise, move 1 offset ahead to include the trailing newline character
+  // '\n'.
+  return SM->getLocForEndOfFile(LocInfo.first) == EndLoc
+             ? EndLoc
+             : EndLoc.getLocWithOffset(1);
+}
+
+// Get full range of a Decl including the comments associated with it.
+clang::CharSourceRange
+GetFullRange(const clang::SourceManager *SM, const clang::Decl *D,
+             const clang::LangOptions &options = clang::LangOptions()) {
+  clang::SourceRange Full = D->getSourceRange();
+  Full.setEnd(getLocForEndOfDecl(D, SM));
+  // Expand to comments that are associated with the Decl.
+  if (const auto* Comment =
+          D->getASTContext().getRawCommentForDeclNoCache(D)) {
+    if (SM->isBeforeInTranslationUnit(Full.getEnd(), Comment->getLocEnd()))
+      Full.setEnd(Comment->getLocEnd());
+    // FIXME: Don't delete a preceding comment, if there are no other entities
+    // it could refer to.
+    if (SM->isBeforeInTranslationUnit(Comment->getLocStart(),
+                                      Full.getBegin()))
+      Full.setBegin(Comment->getLocStart());
+  }
+
+  return clang::CharSourceRange::getCharRange(Full);
+}
+
+std::string getDeclarationSourceText(const clang::Decl *D,
+                                     const clang::SourceManager *SM) {
+  llvm::StringRef SourceText = clang::Lexer::getSourceText(
+      GetFullRange(SM, D), *SM, clang::LangOptions());
+  return SourceText.str();
+}
+
 clang::tooling::Replacement
 getReplacementInChangedCode(const clang::tooling::Replacements &Replacements,
                             const clang::tooling::Replacement &Replacement) {
@@ -147,26 +205,6 @@ std::vector<std::string> GetNamespaces(c
   return Namespaces;
 }
 
-SourceLocation getLocForEndOfDecl(const clang::Decl *D,
-                                  const clang::SourceManager *SM) {
-  auto End = D->getLocEnd();
-  clang::SourceLocation AfterSemi = clang::Lexer::findLocationAfterToken(
-      End, clang::tok::semi, *SM, clang::LangOptions(),
-      /*SkipTrailingWhitespaceAndNewLine=*/true);
-  if (AfterSemi.isValid())
-    End = AfterSemi.getLocWithOffset(-1);
-  return End;
-}
-
-std::string getDeclarationSourceText(const clang::Decl *D,
-                                     const clang::SourceManager *SM) {
-  auto EndLoc = getLocForEndOfDecl(D, SM);
-  llvm::StringRef SourceText = clang::Lexer::getSourceText(
-      clang::CharSourceRange::getTokenRange(D->getLocStart(), EndLoc), *SM,
-      clang::LangOptions());
-  return SourceText.str() + "\n";
-}
-
 clang::tooling::Replacements
 createInsertedReplacements(const std::vector<std::string> &Includes,
                            const std::vector<ClangMoveTool::MovedDecl> &Decls,
@@ -178,8 +216,12 @@ createInsertedReplacements(const std::ve
   // FIXME: Add header guard.
   for (const auto &Include : Includes)
     AllIncludesString += Include;
-  clang::tooling::Replacement InsertInclude(FileName, 0, 0, AllIncludesString);
-  addOrMergeReplacement(InsertInclude, &InsertedReplacements);
+
+  if (!AllIncludesString.empty()) {
+    clang::tooling::Replacement InsertInclude(FileName, 0, 0,
+                                              AllIncludesString + "\n");
+    addOrMergeReplacement(InsertInclude, &InsertedReplacements);
+  }
 
   // Add moved class definition and its related declarations. All declarations
   // in same namespace are grouped together.
@@ -213,7 +255,6 @@ createInsertedReplacements(const std::ve
       ++DeclIt;
     }
 
-    // FIXME: consider moving comments of the moved declaration.
     clang::tooling::Replacement InsertedReplacement(
         FileName, 0, 0, getDeclarationSourceText(MovedDecl.Decl, MovedDecl.SM));
     addOrMergeReplacement(InsertedReplacement, &InsertedReplacements);
@@ -366,10 +407,10 @@ void ClangMoveTool::addIncludes(llvm::St
 void ClangMoveTool::removeClassDefinitionInOldFiles() {
   for (const auto &MovedDecl : RemovedDecls) {
     const auto &SM = *MovedDecl.SM;
-    auto EndLoc = getLocForEndOfDecl(MovedDecl.Decl, &SM);
+    auto Range = GetFullRange(&SM, MovedDecl.Decl);
     clang::tooling::Replacement RemoveReplacement(
-        SM, clang::CharSourceRange::getTokenRange(MovedDecl.Decl->getLocStart(),
-                                                  EndLoc),
+        *MovedDecl.SM, clang::CharSourceRange::getCharRange(
+                           Range.getBegin(), Range.getEnd()),
         "");
     std::string FilePath = RemoveReplacement.getFilePath().str();
     addOrMergeReplacement(RemoveReplacement, &FileToReplacements[FilePath]);

Modified: clang-tools-extra/trunk/clang-move/ClangMove.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/ClangMove.h?rev=283425&r1=283424&r2=283425&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/ClangMove.h (original)
+++ clang-tools-extra/trunk/clang-move/ClangMove.h Thu Oct  6 03:59:24 2016
@@ -27,6 +27,8 @@ class ClangMoveTool : public ast_matcher
 public:
   // Information about the declaration being moved.
   struct MovedDecl {
+    // FIXME: Replace Decl with SourceRange to get rid of calculating range for
+    // the Decl duplicately.
     const clang::NamedDecl *Decl = nullptr;
     clang::SourceManager *SM = nullptr;
     MovedDecl() = default;

Modified: clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp?rev=283425&r1=283424&r2=283425&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp (original)
+++ clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp Thu Oct  6 03:59:24 2016
@@ -70,7 +70,19 @@ cl::opt<bool> Dump("dump_result",
 } // namespace
 
 int main(int argc, const char **argv) {
-  tooling::CommonOptionsParser OptionsParser(argc, argv, ClangMoveCategory);
+  // Add "-fparse-all-comments" compile option to make clang parse all comments,
+  // otherwise, ordinary comments like "//" and "/*" won't get parsed (This is
+  // a bit of hacky).
+  std::vector<std::string> ExtraArgs( argv, argv + argc );
+  ExtraArgs.insert(ExtraArgs.begin()+1, "-extra-arg=-fparse-all-comments");
+  std::unique_ptr<const char *[]> RawExtraArgs(
+      new const char *[ExtraArgs.size()]);
+  for (size_t i = 0; i < ExtraArgs.size(); ++i)
+    RawExtraArgs[i] = ExtraArgs[i].c_str();
+  int Argc = argc + 1;
+  tooling::CommonOptionsParser OptionsParser(Argc, RawExtraArgs.get(),
+                                             ClangMoveCategory);
+
   tooling::RefactoringTool Tool(OptionsParser.getCompilations(),
                                 OptionsParser.getSourcePathList());
   move::ClangMoveTool::MoveDefinitionSpec Spec;

Modified: clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp?rev=283425&r1=283424&r2=283425&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp Thu Oct  6 03:59:24 2016
@@ -29,8 +29,11 @@ const char TestHeaderName[] = "foo.h";
 const char TestCCName[] = "foo.cc";
 
 const char TestHeader[] = "namespace a {\n"
-                          "class C1;\n"
+                          "class C1; // test\n"
                           "namespace b {\n"
+                          "// This is a Foo class\n"
+                          "// which is used in\n"
+                          "// test.\n"
                           "class Foo {\n"
                           "public:\n"
                           "  void f();\n"
@@ -38,7 +41,7 @@ const char TestHeader[] = "namespace a {
                           "private:\n"
                           "  C1 *c1;\n"
                           "  static int b;\n"
-                          "};\n"
+                          "}; // abc\n"
                           "\n"
                           "class Foo2 {\n"
                           "public:\n"
@@ -51,19 +54,29 @@ const char TestCC[] = "#include \"foo.h\
                       "namespace a {\n"
                       "namespace b {\n"
                       "namespace {\n"
+                      "// comment1.\n"
                       "void f1() {}\n"
+                      "/// comment2.\n"
                       "int kConstInt1 = 0;\n"
                       "} // namespace\n"
                       "\n"
+                      "/* comment 3*/\n"
                       "static int kConstInt2 = 1;\n"
                       "\n"
+                      "/** comment4\n"
+                      "*/\n"
                       "static int help() {\n"
                       "  int a = 0;\n"
                       "  return a;\n"
                       "}\n"
                       "\n"
+                      "// comment5\n"
+                      "// comment5\n"
                       "void Foo::f() { f1(); }\n"
                       "\n"
+                      "/////////////\n"
+                      "// comment //\n"
+                      "/////////////\n"
                       "int Foo::b = 2;\n"
                       "int Foo2::f() {\n"
                       "  f1();\n"
@@ -73,7 +86,7 @@ const char TestCC[] = "#include \"foo.h\
                       "} // namespace a\n";
 
 const char ExpectedTestHeader[] = "namespace a {\n"
-                                  "class C1;\n"
+                                  "class C1; // test\n"
                                   "namespace b {\n"
                                   "\n"
                                   "class Foo2 {\n"
@@ -87,12 +100,17 @@ const char ExpectedTestCC[] = "#include
                               "namespace a {\n"
                               "namespace b {\n"
                               "namespace {\n"
+                              "// comment1.\n"
                               "void f1() {}\n"
+                              "/// comment2.\n"
                               "int kConstInt1 = 0;\n"
                               "} // namespace\n"
                               "\n"
+                              "/* comment 3*/\n"
                               "static int kConstInt2 = 1;\n"
                               "\n"
+                              "/** comment4\n"
+                              "*/\n"
                               "static int help() {\n"
                               "  int a = 0;\n"
                               "  return a;\n"
@@ -106,8 +124,11 @@ const char ExpectedTestCC[] = "#include
                               "} // namespace a\n";
 
 const char ExpectedNewHeader[] = "namespace a {\n"
-                                 "class C1;\n"
+                                 "class C1; // test\n"
                                  "namespace b {\n"
+                                 "// This is a Foo class\n"
+                                 "// which is used in\n"
+                                 "// test.\n"
                                  "class Foo {\n"
                                  "public:\n"
                                  "  void f();\n"
@@ -115,22 +136,32 @@ const char ExpectedNewHeader[] = "namesp
                                  "private:\n"
                                  "  C1 *c1;\n"
                                  "  static int b;\n"
-                                 "};\n"
+                                 "}; // abc\n"
                                  "} // namespace b\n"
                                  "} // namespace a\n";
 
 const char ExpectedNewCC[] = "namespace a {\n"
                              "namespace b {\n"
                              "namespace {\n"
+                             "// comment1.\n"
                              "void f1() {}\n"
+                             "/// comment2.\n"
                              "int kConstInt1 = 0;\n"
                              "} // namespace\n"
+                             "/* comment 3*/\n"
                              "static int kConstInt2 = 1;\n"
+                             "/** comment4\n"
+                             "*/\n"
                              "static int help() {\n"
                              "  int a = 0;\n"
                              "  return a;\n"
                              "}\n"
+                             "// comment5\n"
+                             "// comment5\n"
                              "void Foo::f() { f1(); }\n"
+                             "/////////////\n"
+                             "// comment //\n"
+                             "/////////////\n"
                              "int Foo::b = 2;\n"
                              "} // namespace b\n"
                              "} // namespace a\n";
@@ -164,8 +195,9 @@ runClangMoveOnCode(const move::ClangMove
       Spec, FileToReplacements, InitialDirectory.str(), "LLVM");
 
   tooling::runToolOnCodeWithArgs(
-      Factory->create(), TestCC, {"-std=c++11"}, TestCCName, "clang-move",
-      std::make_shared<PCHContainerOperations>(), FileToSourceText);
+      Factory->create(), TestCC, {"-std=c++11", "-fparse-all-comments"},
+      TestCCName, "clang-move", std::make_shared<PCHContainerOperations>(),
+      FileToSourceText);
   formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
   // The Key is file name, value is the new code after moving the class.
   std::map<std::string, std::string> Results;
@@ -183,7 +215,7 @@ TEST(ClangMove, MoveHeaderAndCC) {
   Spec.OldCC = "foo.cc";
   Spec.NewHeader = "new_foo.h";
   Spec.NewCC = "new_foo.cc";
-  std::string ExpectedHeader = "#include \"" + Spec.NewHeader + "\"\n";
+  std::string ExpectedHeader = "#include \"" + Spec.NewHeader + "\"\n\n";
   auto Results = runClangMoveOnCode(Spec);
   EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
   EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
@@ -207,7 +239,7 @@ TEST(ClangMove, MoveCCOnly) {
   Spec.Name = "a::b::Foo";
   Spec.OldCC = "foo.cc";
   Spec.NewCC = "new_foo.cc";
-  std::string ExpectedHeader = "#include \"foo.h\"\n";
+  std::string ExpectedHeader = "#include \"foo.h\"\n\n";
   auto Results = runClangMoveOnCode(Spec);
   EXPECT_EQ(2u, Results.size());
   EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);




More information about the cfe-commits mailing list