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