yamaguchi updated this revision to Diff 102944. yamaguchi marked 3 inline comments as done. yamaguchi added a comment. Herald added a subscriber: hiraditya.
Update patch and add support for `clang -stdlib=[tab]` case. In this case we expect to see all possible values. (Eg. `libc++ libstdc++ platform` for `clang -stdlib=[tab]`). https://reviews.llvm.org/D33383 Files: clang/include/clang/Driver/Options.h clang/include/clang/Driver/Options.td clang/lib/Driver/Driver.cpp clang/lib/Driver/DriverOptions.cpp clang/test/Driver/autocomplete.c clang/utils/bash-autocomplete.sh lld/COFF/Driver.h lld/COFF/DriverUtils.cpp lld/ELF/Driver.h lld/ELF/DriverUtils.cpp lld/lib/Driver/DarwinLdDriver.cpp llvm/include/llvm/Option/OptParser.td llvm/include/llvm/Option/OptTable.h llvm/include/llvm/Option/Option.h llvm/lib/Option/OptTable.cpp llvm/lib/Option/Option.cpp llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp llvm/tools/llvm-cvtres/llvm-cvtres.cpp llvm/unittests/Option/OptionParsingTest.cpp llvm/utils/TableGen/OptParserEmitter.cpp
Index: llvm/utils/TableGen/OptParserEmitter.cpp =================================================================== --- llvm/utils/TableGen/OptParserEmitter.cpp +++ llvm/utils/TableGen/OptParserEmitter.cpp @@ -196,6 +196,9 @@ OS << ", nullptr"; // The option meta-variable name (unused). + OS << ", nullptr"; + + // The option Values (unused for groups). OS << ", nullptr)\n"; } OS << "\n"; @@ -285,6 +288,13 @@ else OS << "nullptr"; + // The option Values. Used for shell autocompletion. + OS << ", "; + if (!isa<UnsetInit>(R.getValueInit("ArgValues"))) + write_cstring(OS, R.getValueAsString("ArgValues")); + else + OS << "nullptr"; + OS << ")\n"; } OS << "#endif // OPTION\n"; Index: llvm/unittests/Option/OptionParsingTest.cpp =================================================================== --- llvm/unittests/Option/OptionParsingTest.cpp +++ llvm/unittests/Option/OptionParsingTest.cpp @@ -18,8 +18,9 @@ enum ID { OPT_INVALID = 0, // This is not an option ID. -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) OPT_##ID, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, ARGVALUE) \ + OPT_##ID, #include "Opts.inc" LastOption #undef OPTION @@ -36,10 +37,10 @@ }; static const OptTable::Info InfoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \ - FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, ARGVALUE) \ + {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, ARGVALUE}, #include "Opts.inc" #undef OPTION }; Index: llvm/tools/llvm-cvtres/llvm-cvtres.cpp =================================================================== --- llvm/tools/llvm-cvtres/llvm-cvtres.cpp +++ llvm/tools/llvm-cvtres/llvm-cvtres.cpp @@ -37,7 +37,7 @@ enum ID { OPT_INVALID = 0, // This is not an option ID. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ + HELPTEXT, METAVAR, ARGVALUE) \ OPT_##ID, #include "Opts.inc" #undef OPTION @@ -49,12 +49,12 @@ static const opt::OptTable::Info InfoTable[] = { #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ + HELPTEXT, METAVAR, ARGVALUE) \ { \ - PREFIX, NAME, HELPTEXT, \ - METAVAR, OPT_##ID, opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, \ - OPT_##ALIAS, ALIASARGS}, + PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, ARGVALUE}, #include "Opts.inc" #undef OPTION }; Index: llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp =================================================================== --- llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp +++ llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp @@ -31,7 +31,7 @@ enum { OPT_INVALID = 0, -#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID, +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, #include "Options.inc" #undef OPTION }; @@ -41,11 +41,9 @@ #undef PREFIX static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ - { \ - X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \ - OPT_##GROUP, OPT_##ALIAS, X6 \ - }, +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10, X11) \ + {X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, \ + X8, X7, OPT_##GROUP, OPT_##ALIAS, X6, X11}, #include "Options.inc" #undef OPTION }; Index: llvm/lib/Option/Option.cpp =================================================================== --- llvm/lib/Option/Option.cpp +++ llvm/lib/Option/Option.cpp @@ -45,6 +45,7 @@ P(UnknownClass); P(FlagClass); P(JoinedClass); + P(ArgValuesClass); P(SeparateClass); P(CommaJoinedClass); P(MultiArgClass); Index: llvm/lib/Option/OptTable.cpp =================================================================== --- llvm/lib/Option/OptTable.cpp +++ llvm/lib/Option/OptTable.cpp @@ -186,6 +186,49 @@ return 0; } +// returns false if one of the Prefixes + In.Names matches C +static bool optionMatches(const OptTable::Info &In, std::string C) { + if (!(In.ArgValues && In.Prefixes)) + return true; + + for (size_t I = 0; In.Prefixes[I]; I++) + if (C == std::string(In.Prefixes[I]) + In.Name) + return false; + return true; +} + +// This function is for flag value completion. +// Eg. When l,=,-stdlib was passed to this function, it will return appropiriate +// values for stdlib, which starts with l. +std::vector<std::string> OptTable::suggestValueCompletions( + const SmallVectorImpl<StringRef> &Command) const { + if (Command.size() <= 1) + return {}; + + std::vector<std::string> Result; + // values are parsed like l,=,-stdlib by bash. We have to concat = to + // -stdlib because they are separated. + std::string C = (Command[0] == "=") + ? std::string(Command[1]) + "=" + : (Command[1] == "=") ? std::string(Command[2]) + "=" + : std::string(Command[2]); + std::string S = (Command[0] == "=") ? "" : Command[0]; + + // Search all options and return possible values. + for (const Info &In : OptionInfos.slice(FirstSearchableIndex)) { + if (optionMatches(In, C)) + continue; + + SmallVector<StringRef, 8> Values; + StringRef(In.ArgValues).split(Values, ",", -1, false); + for (StringRef Val : Values) { + if (Val.startswith(S)) + Result.push_back(Val); + } + } + return Result; +} + std::vector<std::string> OptTable::findByPrefix(StringRef Cur) const { std::vector<std::string> Ret; for (const Info &In : OptionInfos.slice(FirstSearchableIndex)) { @@ -328,6 +371,9 @@ case Option::FlagClass: break; + case Option::ArgValuesClass: + break; + case Option::SeparateClass: case Option::JoinedOrSeparateClass: case Option::RemainingArgsClass: case Option::RemainingArgsJoinedClass: Name += ' '; Index: llvm/include/llvm/Option/Option.h =================================================================== --- llvm/include/llvm/Option/Option.h +++ llvm/include/llvm/Option/Option.h @@ -49,6 +49,7 @@ UnknownClass, FlagClass, JoinedClass, + ArgValuesClass, SeparateClass, RemainingArgsClass, RemainingArgsJoinedClass, @@ -147,6 +148,7 @@ case CommaJoinedClass: return RenderCommaJoinedStyle; case FlagClass: + case ArgValuesClass: case SeparateClass: case MultiArgClass: case JoinedOrSeparateClass: Index: llvm/include/llvm/Option/OptTable.h =================================================================== --- llvm/include/llvm/Option/OptTable.h +++ llvm/include/llvm/Option/OptTable.h @@ -46,6 +46,7 @@ unsigned short GroupID; unsigned short AliasID; const char *AliasArgs; + const char *ArgValues; }; private: @@ -113,6 +114,15 @@ return getInfo(id).MetaVar; } + /// Find possible value for given flags. This is used for shell + /// autocompletion. + /// + /// \param [in] Command - List of incomplete flags passed by shell. + /// + /// \return The vector of possible values. + std::vector<std::string> + suggestValueCompletions(const SmallVectorImpl<StringRef> &Command) const; + /// Find flags from OptTable which starts with Cur. /// /// \param [in] Cur - String prefix that all returned flags need Index: llvm/include/llvm/Option/OptParser.td =================================================================== --- llvm/include/llvm/Option/OptParser.td +++ llvm/include/llvm/Option/OptParser.td @@ -92,6 +92,7 @@ int NumArgs = 0; string HelpText = ?; string MetaVarName = ?; + string ArgValues = ?; list<OptionFlag> Flags = []; OptionGroup Group = ?; Option Alias = ?; @@ -126,6 +127,7 @@ class Group<OptionGroup group> { OptionGroup Group = group; } class HelpText<string text> { string HelpText = text; } class MetaVarName<string name> { string MetaVarName = name; } +class ArgValues<string value> { string ArgValues = value; } // Predefined options. Index: lld/lib/Driver/DarwinLdDriver.cpp =================================================================== --- lld/lib/Driver/DarwinLdDriver.cpp +++ lld/lib/Driver/DarwinLdDriver.cpp @@ -61,9 +61,9 @@ // Create enum with OPT_xxx values for each option in DarwinLdOptions.td enum { OPT_INVALID = 0, -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELP, META) \ - OPT_##ID, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELP, META, ARGVALUE) \ + OPT_##ID, #include "DarwinLdOptions.inc" #undef OPTION }; @@ -75,10 +75,12 @@ // Create table mapping all options defined in DarwinLdOptions.td static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, ARGVALUE) \ + {PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, ARGVALUE}, #include "DarwinLdOptions.inc" #undef OPTION }; Index: lld/ELF/DriverUtils.cpp =================================================================== --- lld/ELF/DriverUtils.cpp +++ lld/ELF/DriverUtils.cpp @@ -42,9 +42,9 @@ // Create table mapping all options defined in Options.td static const opt::OptTable::Info OptInfo[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10, X11) \ {X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, \ - X8, X7, OPT_##GROUP, OPT_##ALIAS, X6}, + X8, X7, OPT_##GROUP, OPT_##ALIAS, X6, X11}, #include "Options.inc" #undef OPTION }; Index: lld/ELF/Driver.h =================================================================== --- lld/ELF/Driver.h +++ lld/ELF/Driver.h @@ -58,7 +58,7 @@ // Create enum with OPT_xxx values for each option in Options.td enum { OPT_INVALID = 0, -#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID, +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, #include "Options.inc" #undef OPTION }; Index: lld/COFF/DriverUtils.cpp =================================================================== --- lld/COFF/DriverUtils.cpp +++ lld/COFF/DriverUtils.cpp @@ -657,11 +657,9 @@ // Create table mapping all options defined in Options.td static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ - { \ - X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \ - OPT_##GROUP, OPT_##ALIAS, X6 \ - }, +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10, X11) \ + {X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, \ + X8, X7, OPT_##GROUP, OPT_##ALIAS, X6, X11}, #include "Options.inc" #undef OPTION }; Index: lld/COFF/Driver.h =================================================================== --- lld/COFF/Driver.h +++ lld/COFF/Driver.h @@ -178,7 +178,7 @@ // Create enum with OPT_xxx values for each option in Options.td enum { OPT_INVALID = 0, -#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID, +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, #include "Options.inc" #undef OPTION }; Index: clang/utils/bash-autocomplete.sh =================================================================== --- clang/utils/bash-autocomplete.sh +++ clang/utils/bash-autocomplete.sh @@ -4,11 +4,21 @@ local cur prev words cword flags _init_completion -n : || return - flags=$( clang --autocomplete="$cur" ) - if [[ "$flags" == "" || "$cur" == "" ]]; then + arg="" + for (( i = $cword; i >= 1; i-- )) ; + do + arg="$arg""${COMP_WORDS[$i]}," + done + + flags=$( clang --autocomplete="$arg" ) + if [[ "$cur" == "=" ]]; then + cur="" + COMPREPLY=( $( compgen -W "$flags" -- "$cur") ) + else if [[ "$flags" == "" || "$cur" == "" ]]; then _filedir else COMPREPLY=( $( compgen -W "$flags" -- "$cur" ) ) fi + fi } complete -F _clang clang Index: clang/test/Driver/autocomplete.c =================================================================== --- clang/test/Driver/autocomplete.c +++ clang/test/Driver/autocomplete.c @@ -4,3 +4,7 @@ // STD: -std={{.*}}-stdlib= // RUN: %clang --autocomplete=foo | not FileCheck %s -check-prefix=NONE // NONE: foo +// RUN: %clang --autocomplete=l,=,-stdlib | FileCheck %s -check-prefix=STDLIB +// STDLIB: libc++ libstdc++ +// RUN: %clang --autocomplete==,-stdlib | FileCheck %s -check-prefix=STDLIBALL +// STDLIBALL: libc++ libstdc++ platform Index: clang/lib/Driver/DriverOptions.cpp =================================================================== --- clang/lib/Driver/DriverOptions.cpp +++ clang/lib/Driver/DriverOptions.cpp @@ -21,10 +21,10 @@ #undef PREFIX static const OptTable::Info InfoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \ - FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, ARGVALUE) \ + {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, ARGVALUE}, #include "clang/Driver/Options.inc" #undef OPTION }; Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -1225,9 +1225,21 @@ } 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. - llvm::outs() << llvm::join(Opts->findByPrefix(A->getValue()), " ") << '\n'; + StringRef PassedFlags = A->getValue(); + SmallVector<StringRef, 8> ListOfPassedFlags; + + // PassedFlags are incomplete flags which format is "c,=,-std,-fsyntax-only" + // So spilit them with "," in order to make a list of flag values. + PassedFlags.split(ListOfPassedFlags, ",", -1, false); + std::vector<std::string> SuggestedCompletions = + Opts->findByPrefix(ListOfPassedFlags[0]); + + if (SuggestedCompletions.empty()) + SuggestedCompletions = Opts->suggestValueCompletions(ListOfPassedFlags); + llvm::outs() << llvm::join(SuggestedCompletions, " ") << '\n'; return false; } Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2201,7 +2201,7 @@ def std_EQ : Joined<["-", "--"], "std=">, Flags<[CC1Option]>, Group<CompileOnly_Group>, HelpText<"Language standard to compile for">; def stdlib_EQ : Joined<["-", "--"], "stdlib=">, Flags<[CC1Option]>, - HelpText<"C++ standard library to use">; + HelpText<"C++ standard library to use">, ArgValues<"libc++,libstdc++,platform">; def sub__library : JoinedOrSeparate<["-"], "sub_library">; def sub__umbrella : JoinedOrSeparate<["-"], "sub_umbrella">; def system_header_prefix : Joined<["--"], "system-header-prefix=">, Index: clang/include/clang/Driver/Options.h =================================================================== --- clang/include/clang/Driver/Options.h +++ clang/include/clang/Driver/Options.h @@ -39,8 +39,9 @@ enum ID { OPT_INVALID = 0, // This is not an option ID. -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) OPT_##ID, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, ARGVALUE) \ + OPT_##ID, #include "clang/Driver/Options.inc" LastOption #undef OPTION
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits