ilya-biryukov updated this revision to Diff 162701.
ilya-biryukov marked 2 inline comments as done.
ilya-biryukov added a comment.

- Remove computeTraits, put the body inside a lambda


Repository:
  rC Clang

https://reviews.llvm.org/D51314

Files:
  lib/Tooling/InterpolatingCompilationDatabase.cpp

Index: lib/Tooling/InterpolatingCompilationDatabase.cpp
===================================================================
--- lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -56,7 +56,9 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/StringSaver.h"
 #include "llvm/Support/raw_ostream.h"
+#include <atomic>
 #include <memory>
+#include <mutex>
 
 namespace clang {
 namespace tooling {
@@ -119,87 +121,63 @@
   }
 }
 
-// A CompileCommand that can be applied to another file.
+// A CompileCommand that can be applied to another file. Any instance of this
+// object is invalid after std::move() from it.
 struct TransferableCommand {
-  // Flags that should not apply to all files are stripped from CommandLine.
-  CompileCommand Cmd;
-  // Language detected from -x or the filename.
-  types::ID Type = types::TY_INVALID;
-  // Standard specified by -std.
-  LangStandard::Kind Std = LangStandard::lang_unspecified;
-
   TransferableCommand(CompileCommand C)
-      : Cmd(std::move(C)), Type(guessType(Cmd.Filename)) {
-    std::vector<std::string> NewArgs = {Cmd.CommandLine.front()};
-    // Parse the old args in order to strip out and record unwanted flags.
-    auto OptTable = clang::driver::createDriverOptTable();
-    std::vector<const char *> Argv;
-    for (unsigned I = 1; I < Cmd.CommandLine.size(); ++I)
-      Argv.push_back(Cmd.CommandLine[I].c_str());
-    unsigned MissingI, MissingC;
-    auto ArgList = OptTable->ParseArgs(Argv, MissingI, MissingC);
-    for (const auto *Arg : ArgList) {
-      const auto &option = Arg->getOption();
-      // Strip input and output files.
-      if (option.matches(clang::driver::options::OPT_INPUT) ||
-          option.matches(clang::driver::options::OPT_o)) {
-        continue;
-      }
-      // Strip -x, but record the overridden language.
-      if (option.matches(clang::driver::options::OPT_x)) {
-        for (const char *Value : Arg->getValues())
-          Type = types::lookupTypeForTypeSpecifier(Value);
-        continue;
-      }
-      // Strip --std, but record the value.
-      if (option.matches(clang::driver::options::OPT_std_EQ)) {
-        for (const char *Value : Arg->getValues()) {
-          Std = llvm::StringSwitch<LangStandard::Kind>(Value)
-#define LANGSTANDARD(id, name, lang, desc, features)                           \
-  .Case(name, LangStandard::lang_##id)
-#define LANGSTANDARD_ALIAS(id, alias) .Case(alias, LangStandard::lang_##id)
-#include "clang/Frontend/LangStandards.def"
-                    .Default(Std);
-        }
-        continue;
-      }
-      llvm::opt::ArgStringList ArgStrs;
-      Arg->render(ArgList, ArgStrs);
-      NewArgs.insert(NewArgs.end(), ArgStrs.begin(), ArgStrs.end());
-    }
-    Cmd.CommandLine = std::move(NewArgs);
-
-    if (Std != LangStandard::lang_unspecified) // -std take precedence over -x
-      Type = toType(LangStandard::getLangStandardForKind(Std).getLanguage());
-    Type = foldType(Type);
-  }
+      : OriginalCmd(std::move(C)),
+        TraitsComputed(llvm::make_unique<std::once_flag>()) {}
 
   // Produce a CompileCommand for \p filename, based on this one.
   CompileCommand transferTo(StringRef Filename) const {
-    CompileCommand Result = Cmd;
+    assert(TraitsComputed && "calling transferTo on moved-from object");
+    const CommandTraits &T = getTraits();
+    CompileCommand Result = T.Cmd;
     Result.Filename = Filename;
     bool TypeCertain;
     auto TargetType = guessType(Filename, &TypeCertain);
     // If the filename doesn't determine the language (.h), transfer with -x.
     if (!TypeCertain) {
       TargetType = types::onlyPrecompileType(TargetType) // header?
-                       ? types::lookupHeaderTypeForSourceType(Type)
-                       : Type;
+                       ? types::lookupHeaderTypeForSourceType(T.Type)
+                       : T.Type;
       Result.CommandLine.push_back("-x");
       Result.CommandLine.push_back(types::getTypeName(TargetType));
     }
     // --std flag may only be transferred if the language is the same.
     // We may consider "translating" these, e.g. c++11 -> c11.
-    if (Std != LangStandard::lang_unspecified && foldType(TargetType) == Type) {
+    if (T.Std != LangStandard::lang_unspecified &&
+        foldType(TargetType) == T.Type) {
       Result.CommandLine.push_back(
           "-std=" +
-          std::string(LangStandard::getLangStandardForKind(Std).getName()));
+          std::string(LangStandard::getLangStandardForKind(T.Std).getName()));
     }
     Result.CommandLine.push_back(Filename);
     return Result;
   }
 
+  llvm::StringRef filename() const {
+    assert(TraitsComputed && "calling filename on moved-from object");
+    return OriginalCmd.Filename;
+  }
+
+  types::ID type() const {
+    assert(TraitsComputed && "calling type on moved-from object");
+    return getTraits().Type;
+  }
+
 private:
+  // Extra information that cannot be inferred solely by the filename. Slow to
+  // compute, so we only compute on first access.
+  struct CommandTraits {
+    // Flags that should not apply to all files are stripped from CommandLine.
+    CompileCommand Cmd;
+    // Language detected from -x or the filename.
+    types::ID Type = types::TY_INVALID;
+    // Standard specified by -std.
+    LangStandard::Kind Std = LangStandard::lang_unspecified;
+  };
+
   // Map the language from the --std flag to that of the -x flag.
   static types::ID toType(InputKind::Language Lang) {
     switch (Lang) {
@@ -215,6 +193,73 @@
       return types::TY_INVALID;
     }
   }
+
+  const CommandTraits &getTraits() const {
+    assert(TraitsComputed && "calling getTraits on moved-from object");
+    // Compute the Traits field.
+    std::call_once(*TraitsComputed, [this]() {
+      Traits.Type = guessType(OriginalCmd.Filename);
+
+      std::vector<std::string> NewArgs = {OriginalCmd.CommandLine.front()};
+      // Parse the old args in order to strip out and record unwanted flags.
+      // Note that we reuse the OptTable because it's slow to create.
+      static const auto *OptTable =
+          clang::driver::createDriverOptTable().release();
+
+      std::vector<const char *> Argv;
+      for (unsigned I = 1; I < OriginalCmd.CommandLine.size(); ++I)
+        Argv.push_back(OriginalCmd.CommandLine[I].c_str());
+      unsigned MissingI, MissingC;
+      auto ArgList = OptTable->ParseArgs(Argv, MissingI, MissingC);
+      for (const auto *Arg : ArgList) {
+        const auto &option = Arg->getOption();
+        // Strip input and output files.
+        if (option.matches(clang::driver::options::OPT_INPUT) ||
+            option.matches(clang::driver::options::OPT_o)) {
+          continue;
+        }
+        // Strip -x, but record the overridden language.
+        if (option.matches(clang::driver::options::OPT_x)) {
+          for (const char *Value : Arg->getValues())
+            Traits.Type = types::lookupTypeForTypeSpecifier(Value);
+          continue;
+        }
+        // Strip --std, but record the value.
+        if (option.matches(clang::driver::options::OPT_std_EQ)) {
+          for (const char *Value : Arg->getValues()) {
+            Traits.Std = llvm::StringSwitch<LangStandard::Kind>(Value)
+#define LANGSTANDARD(id, name, lang, desc, features)                           \
+  .Case(name, LangStandard::lang_##id)
+#define LANGSTANDARD_ALIAS(id, alias) .Case(alias, LangStandard::lang_##id)
+#include "clang/Frontend/LangStandards.def"
+                             .Default(Traits.Std);
+          }
+          continue;
+        }
+        llvm::opt::ArgStringList ArgStrs;
+        Arg->render(ArgList, ArgStrs);
+        NewArgs.insert(NewArgs.end(), ArgStrs.begin(), ArgStrs.end());
+      }
+      Traits.Cmd.CommandLine = std::move(NewArgs);
+
+      if (Traits.Std !=
+          LangStandard::lang_unspecified) // -std take precedence over -x
+        Traits.Type = toType(
+            LangStandard::getLangStandardForKind(Traits.Std).getLanguage());
+      Traits.Type = foldType(Traits.Type);
+    });
+    return Traits;
+  }
+
+  /// The original command we were created with, used as input to compute the
+  /// Traits field.
+  CompileCommand OriginalCmd;
+  /// A flag indicating if Traits were computed. unique_ptr to allow moving from
+  /// TransferableCommand.
+  mutable std::unique_ptr<std::once_flag> TraitsComputed;
+  /// Lazilly computed information about compile command. Should only be
+  /// accessed via getTraits.
+  mutable CommandTraits Traits;
 };
 
 // CommandIndex does the real work: given a filename, it produces the best
@@ -233,11 +278,10 @@
     llvm::sort(
         Commands.begin(), Commands.end(),
         [](const TransferableCommand &Left, const TransferableCommand &Right) {
-          return Left.Cmd.Filename < Right.Cmd.Filename;
+          return Left.filename() < Right.filename();
         });
     for (size_t I = 0; I < Commands.size(); ++I) {
-      StringRef Path =
-          Strings.save(StringRef(Commands[I].Cmd.Filename).lower());
+      StringRef Path = Strings.save(StringRef(Commands[I].filename()).lower());
       Paths.push_back({Path, I});
       Stems.emplace_back(sys::path::stem(Path), I);
       auto Dir = ++sys::path::rbegin(Path), DirEnd = sys::path::rend(Path);
@@ -263,15 +307,14 @@
     std::pair<size_t, int> Best =
         pickWinner(Candidates, Filename, PreferLanguage);
 
-    DEBUG_WITH_TYPE("interpolate",
-                    llvm::dbgs()
-                        << "interpolate: chose "
-                        << Commands[Best.first].Cmd.Filename << " as proxy for "
-                        << OriginalFilename << " preferring "
-                        << (PreferLanguage == types::TY_INVALID
-                                ? "none"
-                                : types::getTypeName(PreferLanguage))
-                        << " score=" << Best.second << "\n");
+    DEBUG_WITH_TYPE(
+        "interpolate",
+        llvm::dbgs() << "interpolate: chose " << Commands[Best.first].filename()
+                     << " as proxy for " << OriginalFilename << " preferring "
+                     << (PreferLanguage == types::TY_INVALID
+                             ? "none"
+                             : types::getTypeName(PreferLanguage))
+                     << " score=" << Best.second << "\n");
     return Commands[Best.first];
   }
 
@@ -338,7 +381,7 @@
       ScoredCandidate S;
       S.Index = Candidate.first;
       S.Preferred = PreferredLanguage == types::TY_INVALID ||
-                    PreferredLanguage == Commands[S.Index].Type;
+                    PreferredLanguage == Commands[S.Index].type();
       S.Points = Candidate.second;
       if (!S.Preferred && Best.Preferred)
         continue;
@@ -435,11 +478,8 @@
 private:
   std::vector<TransferableCommand> allCommands() {
     std::vector<TransferableCommand> Result;
-    for (auto Command : Inner->getAllCompileCommands()) {
+    for (auto Command : Inner->getAllCompileCommands())
       Result.emplace_back(std::move(Command));
-      if (Result.back().Type == types::TY_INVALID)
-        Result.pop_back();
-    }
     return Result;
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to