hokein updated this revision to Diff 243768.
hokein marked 3 inline comments as done.
hokein added a comment.

- rebase to master
- fix the breakage of the rename tool
- add more symbol to the tests
- some tweaks on the python script


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D71110/new/

https://reviews.llvm.org/D71110

Files:
  clang-tools-extra/clangd/CMakeLists.txt
  clang-tools-extra/clangd/eval-rename/CMakeLists.txt
  clang-tools-extra/clangd/eval-rename/RenameMain.cpp
  clang-tools-extra/clangd/eval-rename/eval-rename.py
  clang-tools-extra/clangd/eval-rename/symbol_to_rename.txt

Index: clang-tools-extra/clangd/eval-rename/symbol_to_rename.txt
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/eval-rename/symbol_to_rename.txt
@@ -0,0 +1,16 @@
+# normal functions
+clang-tools-extra/clangd/XRefs.h clang::clangd::findReferences clangd
+# normal class methods
+clang-tools-extra/clangd/index/Index.h clang::clangd::SwapIndex::reset clangd
+# normal classes
+clang-tools-extra/clangd/index/Index.h clang::clangd::SymbolIndex clangd
+clang-tools-extra/clangd/ClangdServer.h clang::clangd::ClangdServer clangd
+clang-tools-extra/clangd/GlobalCompilationDatabase.h clang::clangd::GlobalCompilationDatabase clangd
+clang-tools-extra/clangd/GlobalCompilationDatabase.h clang::clangd::OverlayCDB clangd
+clang-tools-extra/clangd/Protocol.h clang::clangd::CodeAction clangd
+# rename enum
+clang-tools-extra/clangd/index/Ref.h clang::clangd::RefKind clangd
+# rename enum constants
+clang-tools-extra/clangd/FindTarget.h clang::clangd::DeclRelation::Alias clangd
+# class with template constructors
+clang-tools-extra/clangd/index/MemIndex.h clang::clangd::MemIndex clangd
\ No newline at end of file
Index: clang-tools-extra/clangd/eval-rename/eval-rename.py
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/eval-rename/eval-rename.py
@@ -0,0 +1,88 @@
+#!/usr/bin/python
+"""
+A script to perform cross-file rename and evalute the results.
+
+Usage:
+
+$ cd <path>/llvm-project
+$ ninja -C build clangd-indexer
+$ ./build/bin/clangd-indexer -format=binary -executor=all-TUs . > llvm-index.idx
+$ ninja -C build clangd-rename
+$ clang-tools-extra/clangd/eval-rename/eval-rename.py --index=llvm-index.idx --file=clang-tools-extra/clangd/eval-rename/symbol_to_rename.txt
+"""
+
+from __future__ import print_function
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+import tempfile
+
+RENAME_EXECUTOR='build/bin/clangd-rename'
+
+def Run(cmd):
+  s = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+  print('>', ' '.join(cmd))
+  [stdout, stderr] = s.communicate()
+  return (s.returncode, stdout, stderr)
+
+if __name__ == '__main__':
+  if not os.getcwd().endswith('llvm-project'):
+    sys.exit('The tool must be run from llvm-project/ root.')
+
+  ap = argparse.ArgumentParser()
+  ap.add_argument(
+      '-f',
+      '--file',
+      required=True,
+      help='A file containing rename symbols to be evaluted.'
+  )
+  ap.add_argument(
+      '-idx',
+      '--index',
+      required=True,
+      help='A path to the index file'
+  )
+  args = ap.parse_args()
+
+  with open(args.file) as f:
+    out = f.read()
+  test_cases = [line.strip().split() for line in out.split('\n') \
+     if line and not line.startswith('#') and line.strip()]
+
+  log_output_dir = tempfile.mkdtemp(prefix='eval-rename_')
+  success_cnt = 0
+  for file_name, rename_symbol, verify_target in test_cases:
+    Run(['git', 'reset', '--hard'])
+    execute_rename_cmd = [
+      RENAME_EXECUTOR,
+       '--index-path=%s' % args.index,
+       '--rename-symbol=%s' % rename_symbol,
+       '-fix',
+       file_name,
+    ]
+    rename_results = Run(execute_rename_cmd)
+    if rename_results[0] != 0:
+      log_file = open(os.path.join(
+        log_output_dir, rename_symbol.replace("::", "_") + '_RenameFailed'), 'w')
+      log_file.write(rename_results[1]) # stdout
+      log_file.write(rename_results[2]) # stderr
+      log_file.close()
+      continue
+
+    build_results = Run(['ninja', '-C', 'build', verify_target])
+    if build_results[0] != 0:
+      print('failed on renaming %s' % rename_symbol)
+      log_file = open(os.path.join(
+        log_output_dir, rename_symbol.replace("::", "_") + '_BuildFailed'), 'w')
+      log_file.write(build_results[1]) # stdout
+      log_file.write(build_results[2]) # stderr
+      log_file.close()
+      continue
+    print('succeed on renaming %s' % rename_symbol)
+    success_cnt += 1
+  Run(['git', 'reset', '--hard'])
+  print('Evaluated rename on %d symbols, %d symbol succeeded, go %s for failure logs' %
+      (len(test_cases), success_cnt, log_output_dir))
Index: clang-tools-extra/clangd/eval-rename/RenameMain.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/eval-rename/RenameMain.cpp
@@ -0,0 +1,204 @@
+//===--- RenameMain.cpp ------------------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CompileCommands.h"
+#include "Compiler.h"
+#include "FS.h"
+#include "FSProvider.h"
+#include "FindTarget.h"
+#include "GlobalCompilationDatabase.h"
+#include "Logger.h"
+#include "ParsedAST.h"
+#include "SourceCode.h"
+#include "index/MemIndex.h"
+#include "index/Serialization.h"
+#include "refactor/Rename.h"
+#include "clang/AST/Decl.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/ReplacementsYaml.h"
+#include "llvm/ADT/STLExtras.h"
+
+static llvm::cl::opt<std::string>
+    IndexPath("index-path", llvm::cl::desc("Path to the index file"),
+              llvm::cl::init(""));
+static llvm::cl::opt<std::string>
+    RenameSymbol("rename-symbol",
+                 llvm::cl::desc("Qualified symbol name to rename"),
+                 llvm::cl::Required);
+static llvm::cl::opt<bool>
+    Fix("fix", llvm::cl::desc("Apply the rename edits to disk files"),
+        llvm::cl::init(false));
+
+namespace clang {
+namespace clangd {
+namespace {
+
+llvm::Expected<std::string> getAbsolutePath(StringRef File,
+                                            const FileSystemProvider &FS) {
+  SmallString<1024> AbsolutePath = File;
+  if (auto EC = FS.getFileSystem()->makeAbsolute(AbsolutePath))
+    return llvm::errorCodeToError(EC);
+  return clangd::removeDots(AbsolutePath.str());
+}
+
+class RenameExecutor {
+public:
+  explicit RenameExecutor(llvm::StringRef SymbolOnRename,
+                          llvm::StringRef FileOnRename,
+                          const FileSystemProvider &FSProvider,
+                          const GlobalCompilationDatabase &CDB,
+                          std::unique_ptr<SymbolIndex> Index)
+      : QualifiedName(SymbolOnRename), FileName(FileOnRename),
+        FSProvider(FSProvider), CDB(CDB), Index(std::move(Index)) {}
+
+  ParsedAST buildAST() {
+    ParseInputs PInputs;
+    PInputs.CompileCommand = *CDB.getCompileCommand(FileName);
+    auto Buffer = FSProvider.getFileSystem()->getBufferForFile(FileName);
+    llvm::StringRef Content = Buffer->get()->getBuffer();
+    PInputs.Contents = Content.str();
+    PInputs.FS = FSProvider.getFileSystem();
+    IgnoreDiagnostics Diags;
+
+    auto CI = buildCompilerInvocation(PInputs, Diags);
+    assert(CI && "Failed to build compilation invocation.");
+    auto Preamble =
+        buildPreamble(FileName, *CI,
+                      /*OldPreamble=*/nullptr,
+                      /*OldCompileCommand=*/PInputs.CompileCommand, PInputs,
+                      /*StoreInMemory=*/true, /*PreambleCallback=*/nullptr);
+    auto AST = ::clang::clangd::buildAST(FileName, std::move(CI), {}, PInputs,
+                                         Preamble);
+    assert(AST && "Failed to build AST.");
+    return std::move(*AST);
+  }
+
+  llvm::Expected<FileEdits> execute(ParsedAST &AST) {
+    const auto *RenameDecl = findRenameDecl(AST, QualifiedName);
+    auto &SM = AST.getSourceManager();
+    assert(RenameDecl);
+
+    auto Pos =
+        clang::clangd::sourceLocToPosition(SM, RenameDecl->getLocation());
+    clang::clangd::RenameInputs Inputs{Pos,      "_test_rename_", AST,
+                                       FileName, Index.get(),     true};
+    return clang::clangd::rename(Inputs);
+  }
+
+  const clang::NamedDecl *findRenameDecl(const clang::clangd::ParsedAST &AST,
+                                         llvm::StringRef QName) {
+    const NamedDecl *TargetDecl = nullptr;
+    findExplicitReferences(AST.getASTContext(), [&](ReferenceLoc Loc) {
+      if (!Loc.IsDecl)
+        return;
+      if (TargetDecl)
+        return;
+      for (const auto *D : Loc.Targets) {
+        if (const auto *ND = llvm::dyn_cast<NamedDecl>(D)) {
+          if (ND->getQualifiedNameAsString() == QName) {
+            TargetDecl = ND;
+            break;
+          }
+        }
+      }
+    });
+    return TargetDecl;
+  }
+
+private:
+  llvm::StringRef QualifiedName;
+  llvm::StringRef FileName;
+  const FileSystemProvider &FSProvider;
+  const GlobalCompilationDatabase &CDB;
+  std::unique_ptr<SymbolIndex> Index;
+};
+
+std::unique_ptr<SymbolIndex> openIndex(llvm::StringRef IndexPath) {
+  if (IndexPath.empty()) // create an empty one.
+    return clang::clangd::MemIndex::build({}, {}, {});
+  auto S = loadIndex(IndexPath, /*UseDex=*/true);
+  return S;
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
+
+int main(int Argc, const char **Argv) {
+  clang::tooling::CommonOptionsParser OP(Argc, Argv, llvm::cl::GeneralCategory);
+  assert(OP.getSourcePathList().size() == 1 && "Expect exactly one file path.");
+  clang::clangd::StreamLogger Logger(llvm::errs(),
+                                     clang::clangd::Logger::Error);
+  clang::clangd::LoggingSession LoggingSession(Logger);
+
+  clang::clangd::RealFileSystemProvider FSProvider;
+  clang::clangd::DirectoryBasedGlobalCompilationDatabase DCDB(llvm::None);
+  // inject the standard resource directory.
+  auto Mangler = clang::clangd::CommandMangler::detect();
+  clang::clangd::OverlayCDB OCDB(&DCDB, {},
+                                 clang::tooling::ArgumentsAdjuster(Mangler));
+
+  auto AbsFile =
+      clang::clangd::getAbsolutePath(OP.getSourcePathList()[0], FSProvider);
+  if (!AbsFile) {
+    clang::clangd::elog("Error on getting an absolute path {0}: {1}",
+                        OP.getSourcePathList()[0], AbsFile.takeError());
+    return 1;
+  }
+  clang::clangd::RenameExecutor RExecutor(RenameSymbol, *AbsFile, FSProvider,
+                                          OCDB,
+                                          clang::clangd::openIndex(IndexPath));
+  clang::clangd::ParsedAST AST = RExecutor.buildAST();
+  auto FatalDiag =
+      llvm::find_if(AST.getDiagnostics(), [](const clang::clangd::Diag &D) {
+        return D.Severity != clang::DiagnosticsEngine::Fatal;
+      });
+  if (FatalDiag != AST.getDiagnostics().end()) {
+    clang::clangd::elog("source file {0} is illformed: {1}",
+                        *AbsFile,
+                        FatalDiag->Message);
+    return 1;
+  }
+
+  auto RenameResults = RExecutor.execute(AST);
+  if (!RenameResults) {
+    clang::clangd::elog("Failed to rename: {0}", RenameResults.takeError());
+    return 1;
+  }
+
+  if (Fix) {
+    auto &SM = AST.getSourceManager();
+    clang::Rewriter Rewriter(SM, AST.getLangOpts());
+    bool Succeed = true;
+    for (const auto &R : *RenameResults) {
+      bool Success = clang::tooling::applyAllReplacements(
+          R.getValue().Replacements, Rewriter);
+      // Succeed &= Success;
+      if (!Success) {
+        clang::clangd::elog("Failed to apply replacements for file: {0}",
+                            R.first());
+        Succeed = false;
+        continue;
+      }
+    }
+    Rewriter.overwriteChangedFiles();
+    return Succeed ? 0 : 1;
+  }
+  // Emit the serialized rename edit (YAML format) to the stdout.
+  llvm::yaml::Output YAML(llvm::outs());
+  for (auto &RenameEditForFile : *RenameResults) {
+    clang::tooling::TranslationUnitReplacements Output;
+    Output.MainSourceFile = RenameEditForFile.first().str();
+    Output.Replacements = {RenameEditForFile.second.Replacements.begin(),
+                           RenameEditForFile.second.Replacements.end()};
+    YAML << Output;
+  }
+  return 0;
+}
Index: clang-tools-extra/clangd/eval-rename/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/eval-rename/CMakeLists.txt
@@ -0,0 +1,23 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../)
+
+set(LLVM_LINK_COMPONENTS
+    Support
+    )
+
+add_clang_tool(clangd-rename
+  RenameMain.cpp
+  )
+
+clang_target_link_libraries(clangd-rename
+  PRIVATE
+  clangAST
+  clangBasic
+  clangFrontend
+  clangIndex
+  clangLex
+  clangTooling
+)
+target_link_libraries(clangd-rename
+  PRIVATE
+  clangDaemon
+)
Index: clang-tools-extra/clangd/CMakeLists.txt
===================================================================
--- clang-tools-extra/clangd/CMakeLists.txt
+++ clang-tools-extra/clangd/CMakeLists.txt
@@ -139,6 +139,7 @@
 add_subdirectory(tool)
 add_subdirectory(indexer)
 add_subdirectory(index/dex/dexp)
+add_subdirectory(eval-rename)
 
 if (LLVM_INCLUDE_BENCHMARKS)
   add_subdirectory(benchmarks)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to