Index: clang/include/clang/Driver/Driver.h =================================================================== --- clang/include/clang/Driver/Driver.h +++ clang/include/clang/Driver/Driver.h @@ -420,6 +420,10 @@ // FIXME: This should be in CompilationInfo. std::string GetProgramPath(StringRef Name, const ToolChain &TC) const; + /// handleAutocompletions - Handle --autocomplete by searching and printing + /// possible flags, descriptions, and its arguments. + void handleAutocompletions(StringRef PassedFlags) const; + /// HandleImmediateArgs - Handle any arguments which should be /// treated before building actions or binding tools. /// Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -1157,6 +1157,56 @@ OS << i << ',' << DiagnosticIDs::getCategoryNameFromID(i) << '\n'; } +void Driver::handleAutocompletions(StringRef PassedFlags) const { + // Print out all options that start with a given argument. This is used for + // shell autocompletion. + std::vector SuggestedCompletions; + + unsigned short DisableFlags = + options::NoDriverOption | options::Unsupported | options::Ignored; + // We want to show cc1-only options only when clang is invoked as "clang + // -cc1". + // When clang is invoked as "clang -cc1", we add "#" to the beginning of an + // --autocomplete + // option so that the clang driver can distinguish whether it is requested to + // show cc1-only options or not. + if (PassedFlags[0] == '#') { + DisableFlags &= ~options::NoDriverOption; + PassedFlags = PassedFlags.substr(1); + } + + if (PassedFlags.find(',') == StringRef::npos) { + // If the flag is in the form of "--autocomplete=-foo", + // we were requested to print out all option names that start with "-foo". + // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". + SuggestedCompletions = Opts->findByPrefix(PassedFlags, DisableFlags); + + // We have to query the -W flags manually as they're not in the OptTable. + // TODO: Find a good way to add them to OptTable instead and them remove + // this code. + for (StringRef S : DiagnosticIDs::getDiagnosticFlags()) + if (S.startswith(PassedFlags)) + SuggestedCompletions.push_back(S); + } else { + // If the flag is in the form of "--autocomplete=foo,bar", we were + // requested to print out all option values for "-foo" that start with + // "bar". For example, + // "--autocomplete=-stdlib=,l" is expanded to "libc++" and "libstdc++". + StringRef Option, Arg; + std::tie(Option, Arg) = PassedFlags.split(','); + SuggestedCompletions = Opts->suggestValueCompletions(Option, Arg); + } + + // Sort the autocomplete candidates so that shells print them out in a + // deterministic order. We could sort in any way, but we chose + // case-insensitive sorting for consistency with the -help option + // which prints out options in the case-insensitive alphabetical order. + std::sort(SuggestedCompletions.begin(), SuggestedCompletions.end(), + [](StringRef A, StringRef B) { return A.compare_lower(B) < 0; }); + + llvm::outs() << llvm::join(SuggestedCompletions, "\n") << '\n'; +} + bool Driver::HandleImmediateArgs(const Compilation &C) { // The order these options are handled in gcc is all over the place, but we // don't expect inconsistencies w.r.t. that to matter in practice. @@ -1250,50 +1300,8 @@ } if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) { - // Print out all options that start with a given argument. This is used for - // shell autocompletion. StringRef PassedFlags = A->getValue(); - std::vector SuggestedCompletions; - - unsigned short DisableFlags = options::NoDriverOption | options::Unsupported | options::Ignored; - // We want to show cc1-only options only when clang is invoked as "clang -cc1". - // When clang is invoked as "clang -cc1", we add "#" to the beginning of an --autocomplete - // option so that the clang driver can distinguish whether it is requested to show cc1-only options or not. - if (PassedFlags[0] == '#') { - DisableFlags &= ~options::NoDriverOption; - PassedFlags = PassedFlags.substr(1); - } - - if (PassedFlags.find(',') == StringRef::npos) { - // If the flag is in the form of "--autocomplete=-foo", - // we were requested to print out all option names that start with "-foo". - // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". - SuggestedCompletions = Opts->findByPrefix(PassedFlags, DisableFlags); - - // We have to query the -W flags manually as they're not in the OptTable. - // TODO: Find a good way to add them to OptTable instead and them remove - // this code. - for (StringRef S : DiagnosticIDs::getDiagnosticFlags()) - if (S.startswith(PassedFlags)) - SuggestedCompletions.push_back(S); - } else { - // If the flag is in the form of "--autocomplete=foo,bar", we were - // requested to print out all option values for "-foo" that start with - // "bar". For example, - // "--autocomplete=-stdlib=,l" is expanded to "libc++" and "libstdc++". - StringRef Option, Arg; - std::tie(Option, Arg) = PassedFlags.split(','); - SuggestedCompletions = Opts->suggestValueCompletions(Option, Arg); - } - - // Sort the autocomplete candidates so that shells print them out in a - // deterministic order. We could sort in any way, but we chose - // case-insensitive sorting for consistency with the -help option - // which prints out options in the case-insensitive alphabetical order. - std::sort(SuggestedCompletions.begin(), SuggestedCompletions.end(), - [](StringRef A, StringRef B) { return A.compare_lower(B) < 0; }); - - llvm::outs() << llvm::join(SuggestedCompletions, "\n") << '\n'; + handleAutocompletions(PassedFlags); return false; }