Index: cfe/trunk/include/clang/Driver/Driver.h =================================================================== --- cfe/trunk/include/clang/Driver/Driver.h +++ cfe/trunk/include/clang/Driver/Driver.h @@ -442,9 +442,9 @@ // FIXME: This should be in CompilationInfo. std::string GetProgramPath(StringRef Name, const ToolChain &TC) const; - /// handleAutocompletions - Handle --autocomplete by searching and printing + /// HandleAutocompletions - Handle --autocomplete by searching and printing /// possible flags, descriptions, and its arguments. - void handleAutocompletions(StringRef PassedFlags) const; + void HandleAutocompletions(StringRef PassedFlags) const; /// HandleImmediateArgs - Handle any arguments which should be /// treated before building actions or binding tools. Index: cfe/trunk/lib/Driver/Driver.cpp =================================================================== --- cfe/trunk/lib/Driver/Driver.cpp +++ cfe/trunk/lib/Driver/Driver.cpp @@ -1419,44 +1419,56 @@ OS << i << ',' << DiagnosticIDs::getCategoryNameFromID(i) << '\n'; } -void Driver::handleAutocompletions(StringRef PassedFlags) const { +void Driver::HandleAutocompletions(StringRef PassedFlags) const { + if (PassedFlags == "") return; // Print out all options that start with a given argument. This is used for // shell autocompletion. std::vector SuggestedCompletions; + std::vector Flags; 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.size() > 0 && PassedFlags[0] == '#') { + + // Parse PassedFlags by "," as all the command-line flags are passed to this + // function separated by "," + StringRef TargetFlags = PassedFlags; + while (TargetFlags != "") { + StringRef CurFlag; + std::tie(CurFlag, TargetFlags) = TargetFlags.split(","); + Flags.push_back(std::string(CurFlag)); + } + + // We want to show cc1-only options only when clang is invoked with -cc1 or + // -Xclang. + if (std::find(Flags.begin(), Flags.end(), "-Xclang") != Flags.end() || std::find(Flags.begin(), Flags.end(), "-cc1") != Flags.end()) DisableFlags &= ~options::NoDriverOption; - PassedFlags = PassedFlags.substr(1); + + StringRef Cur; + Cur = Flags.at(Flags.size() - 1); + StringRef Prev; + if (Flags.size() >= 2) { + Prev = Flags.at(Flags.size() - 2); + SuggestedCompletions = Opts->suggestValueCompletions(Prev, Cur); } - if (PassedFlags.find(',') == StringRef::npos) { + if (SuggestedCompletions.empty()) + SuggestedCompletions = Opts->suggestValueCompletions(Cur, ""); + + if (SuggestedCompletions.empty()) { // 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); + SuggestedCompletions = Opts->findByPrefix(Cur, 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)) + if (S.startswith(Cur)) 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 @@ -1574,7 +1586,7 @@ if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) { StringRef PassedFlags = A->getValue(); - handleAutocompletions(PassedFlags); + HandleAutocompletions(PassedFlags); return false; } Index: cfe/trunk/test/Driver/autocomplete.c =================================================================== --- cfe/trunk/test/Driver/autocomplete.c +++ cfe/trunk/test/Driver/autocomplete.c @@ -3,13 +3,8 @@ // add/modify flags, change HelpTexts or the values of some flags. // Some corner cases. -// RUN: %clang --autocomplete= | FileCheck %s -check-prefix=ALL_FLAGS -// RUN: %clang --autocomplete=# | FileCheck %s -check-prefix=ALL_FLAGS -// Let's pick some example flags that are hopefully unlikely to change. -// ALL_FLAGS: -fast -// ALL_FLAGS: -fastcp -// ALL_FLAGS: -fastf // Just test that this doesn't crash: +// RUN: %clang --autocomplete= // RUN: %clang --autocomplete=, // RUN: %clang --autocomplete== // RUN: %clang --autocomplete=,, @@ -17,27 +12,27 @@ // RUN: %clang --autocomplete=-fsyn | FileCheck %s -check-prefix=FSYN // FSYN: -fsyntax-only -// RUN: %clang --autocomplete=-std= | FileCheck %s -check-prefix=STD +// RUN: %clang --autocomplete=-std | FileCheck %s -check-prefix=STD // STD: -std= Language standard to compile for // RUN: %clang --autocomplete=foo | FileCheck %s -check-prefix=FOO // FOO-NOT: foo // RUN: %clang --autocomplete=-stdlib=,l | FileCheck %s -check-prefix=STDLIB // STDLIB: libc++ // STDLIB-NEXT: libstdc++ -// RUN: %clang --autocomplete=-stdlib=, | FileCheck %s -check-prefix=STDLIBALL +// RUN: %clang --autocomplete=-stdlib= | FileCheck %s -check-prefix=STDLIBALL // STDLIBALL: libc++ // STDLIBALL-NEXT: libstdc++ // STDLIBALL-NEXT: platform // RUN: %clang --autocomplete=-meabi,d | FileCheck %s -check-prefix=MEABI // MEABI: default -// RUN: %clang --autocomplete=-meabi, | FileCheck %s -check-prefix=MEABIALL +// RUN: %clang --autocomplete=-meabi | FileCheck %s -check-prefix=MEABIALL // MEABIALL: 4 // MEABIALL-NEXT: 5 // MEABIALL-NEXT: default // MEABIALL-NEXT: gnu // RUN: %clang --autocomplete=-cl-std=,CL2 | FileCheck %s -check-prefix=CLSTD // CLSTD: CL2.0 -// RUN: %clang --autocomplete=-cl-std=, | FileCheck %s -check-prefix=CLSTDALL +// RUN: %clang --autocomplete=-cl-std= | FileCheck %s -check-prefix=CLSTDALL // CLSTDALL: cl // CLSTDALL-NEXT: CL // CLSTDALL-NEXT: cl1.1 @@ -48,7 +43,7 @@ // CLSTDALL-NEXT: CL2.0 // RUN: %clang --autocomplete=-fno-sanitize-coverage=,f | FileCheck %s -check-prefix=FNOSANICOVER // FNOSANICOVER: func -// RUN: %clang --autocomplete=-fno-sanitize-coverage=, | FileCheck %s -check-prefix=FNOSANICOVERALL +// RUN: %clang --autocomplete=-fno-sanitize-coverage= | FileCheck %s -check-prefix=FNOSANICOVERALL // FNOSANICOVERALL: 8bit-counters // FNOSANICOVERALL-NEXT: bb // FNOSANICOVERALL-NEXT: edge @@ -62,41 +57,37 @@ // FNOSANICOVERALL-NEXT: trace-gep // FNOSANICOVERALL-NEXT: trace-pc // FNOSANICOVERALL-NEXT: trace-pc-guard -// RUN: %clang --autocomplete=-ffp-contract=, | FileCheck %s -check-prefix=FFPALL +// RUN: %clang --autocomplete=-ffp-contract= | FileCheck %s -check-prefix=FFPALL // FFPALL: fast // FFPALL-NEXT: off // FFPALL-NEXT: on -// RUN: %clang --autocomplete=-flto=, | FileCheck %s -check-prefix=FLTOALL +// RUN: %clang --autocomplete=-flto= | FileCheck %s -check-prefix=FLTOALL // FLTOALL: full // FLTOALL-NEXT: thin -// RUN: %clang --autocomplete=-fveclib=, | FileCheck %s -check-prefix=FVECLIBALL +// RUN: %clang --autocomplete=-fveclib= | FileCheck %s -check-prefix=FVECLIBALL // FVECLIBALL: Accelerate // FVECLIBALL-NEXT: none // FVECLIBALL-NEXT: SVML -// RUN: %clang --autocomplete=-fshow-overloads=, | FileCheck %s -check-prefix=FSOVERALL +// RUN: %clang --autocomplete=-fshow-overloads= | FileCheck %s -check-prefix=FSOVERALL // FSOVERALL: all // FSOVERALL-NEXT: best -// RUN: %clang --autocomplete=-fvisibility=, | FileCheck %s -check-prefix=FVISIBILITYALL +// RUN: %clang --autocomplete=-fvisibility= | FileCheck %s -check-prefix=FVISIBILITYALL // FVISIBILITYALL: default // FVISIBILITYALL-NEXT: hidden -// RUN: %clang --autocomplete=-mfloat-abi=, | FileCheck %s -check-prefix=MFLOATABIALL +// RUN: %clang --autocomplete=-mfloat-abi= | FileCheck %s -check-prefix=MFLOATABIALL // MFLOATABIALL: hard // MFLOATABIALL-NEXT: soft // MFLOATABIALL-NEXT: softfp -// RUN: %clang --autocomplete=-mthread-model, | FileCheck %s -check-prefix=MTHREADMODELALL +// RUN: %clang --autocomplete=-mthread-model | FileCheck %s -check-prefix=MTHREADMODELALL // MTHREADMODELALL: posix // MTHREADMODELALL-NEXT: single -// RUN: %clang --autocomplete=-mrelocation-model, | FileCheck %s -check-prefix=MRELOCMODELALL +// RUN: %clang --autocomplete=-mrelocation-model | FileCheck %s -check-prefix=MRELOCMODELALL // MRELOCMODELALL: dynamic-no-pic // MRELOCMODELALL-NEXT: pic // MRELOCMODELALL-NEXT: ropi // MRELOCMODELALL-NEXT: ropi-rwpi // MRELOCMODELALL-NEXT: rwpi // MRELOCMODELALL-NEXT: static -// RUN: %clang --autocomplete=-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CLANG -// MRELOCMODEL_CLANG-NOT: -mrelocation-model -// RUN: %clang --autocomplete=#-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CC1 -// MRELOCMODEL_CC1: -mrelocation-model // RUN: %clang --autocomplete=-Wma | FileCheck %s -check-prefix=WARNING // WARNING: -Wmacro-redefined // WARNING-NEXT: -Wmain @@ -106,7 +97,20 @@ // WARNING-NEXT: -Wmax-unsigned-zero // RUN: %clang --autocomplete=-Wno-invalid-pp- | FileCheck %s -check-prefix=NOWARNING // NOWARNING: -Wno-invalid-pp-token -// RUN: %clang --autocomplete=-analyzer-checker, | FileCheck %s -check-prefix=ANALYZER +// RUN: %clang --autocomplete=-analyzer-checker | FileCheck %s -check-prefix=ANALYZER // ANALYZER: unix.Malloc -// RUN: %clang --autocomplete=-std=, | FileCheck %s -check-prefix=STDVAL +// RUN: %clang --autocomplete=-std= | FileCheck %s -check-prefix=STDVAL // STDVAL: c99 +// +// Clang shouldn't autocomplete CC1 options unless -cc1 or -Xclang were provided +// RUN: %clang --autocomplete=-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CLANG +// MRELOCMODEL_CLANG-NOT: -mrelocation-model +// RUN: %clang --autocomplete=-Xclang,-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CC1 +// RUN: %clang --autocomplete=-cc1,-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CC1 +// MRELOCMODEL_CC1: -mrelocation-model +// Make sure it ignores passed flags unlesss they are -Xclang or -cc1 +// RUN: %clang --autocomplete=foo,bar,,-fsyn | FileCheck %s -check-prefix=FSYN-CORON +// FSYN-CORON: -fsyntax-only +// Check if they can autocomplete values with coron +// RUN: %clang --autocomplete=foo,bar,,,-fno-sanitize-coverage=,f | FileCheck %s -check-prefix=FNOSANICOVER-CORON +// FNOSANICOVER-CORON: func Index: cfe/trunk/utils/bash-autocomplete.sh =================================================================== --- cfe/trunk/utils/bash-autocomplete.sh +++ cfe/trunk/utils/bash-autocomplete.sh @@ -25,35 +25,16 @@ w2="${COMP_WORDS[$cword - 2]}" fi - # Clang want to know if -cc1 or -Xclang option is specified or not, because we don't want to show - # cc1 options otherwise. - if [[ "${COMP_WORDS[1]}" == "-cc1" || "$w1" == "-Xclang" ]]; then - arg="#" - fi - - # bash always separates '=' as a token even if there's no space before/after '='. - # On the other hand, '=' is just a regular character for clang options that - # contain '='. For example, "-stdlib=" is defined as is, instead of "-stdlib" and "=". - # So, we need to partially undo bash tokenization here for integrity. - if [[ "$cur" == -* ]]; then - # -foo - arg="$arg$cur" - elif [[ "$w1" == -* && "$cur" == '=' ]]; then - # -foo= - arg="$arg$w1=," - elif [[ "$cur" == -*= ]]; then - # -foo= - arg="$arg$cur," - elif [[ "$w1" == -* ]]; then - # -foo or -foo bar - arg="$arg$w1,$cur" - elif [[ "$w2" == -* && "$w1" == '=' ]]; then - # -foo=bar - arg="$arg$w2=,$cur" - elif [[ ${cur: -1} != '=' && ${cur/=} != $cur ]]; then - # -foo=bar - arg="$arg${cur%=*}=,${cur#*=}" - fi + # Pass all the current command-line flags to clang, so that clang can handle + # these internally. + # '=' is separated differently by bash, so we have to concat them without ',' + for i in `seq 1 $cword`; do + if [[ $i == $cword || "${COMP_WORDS[$(($i+1))]}" == '=' ]]; then + arg="$arg${COMP_WORDS[$i]}" + else + arg="$arg${COMP_WORDS[$i]}," + fi + done # expand ~ to $HOME eval local path=${COMP_WORDS[0]} @@ -67,7 +48,7 @@ # When clang does not emit any possible autocompletion, or user pushed tab after " ", # just autocomplete files. - if [[ "$flags" == "$(echo -e '\n')" || "$arg" == "" ]]; then + if [[ "$flags" == "$(echo -e '\n')" ]]; then # If -foo= and there was no possible values, autocomplete files. [[ "$cur" == '=' || "$cur" == -*= ]] && cur="" _clang_filedir Index: llvm/trunk/lib/Option/OptTable.cpp =================================================================== --- llvm/trunk/lib/Option/OptTable.cpp +++ llvm/trunk/lib/Option/OptTable.cpp @@ -219,7 +219,7 @@ std::vector Result; for (StringRef Val : Candidates) - if (Val.startswith(Arg)) + if (Val.startswith(Arg) && Arg.compare(Val)) Result.push_back(Val); return Result; } @@ -240,7 +240,7 @@ std::string S = std::string(In.Prefixes[I]) + std::string(In.Name) + "\t"; if (In.HelpText) S += In.HelpText; - if (StringRef(S).startswith(Cur)) + if (StringRef(S).startswith(Cur) && S.compare(std::string(Cur) + "\t")) Ret.push_back(S); } }