r326684 - [Bash-autocompletion] Pass all flags in shell command-line to Clang

Yuka Takahashi via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 5 00:54:21 PST 2018


Author: yamaguchi
Date: Mon Mar  5 00:54:20 2018
New Revision: 326684

URL: http://llvm.org/viewvc/llvm-project?rev=326684&view=rev
Log:
[Bash-autocompletion] Pass all flags in shell command-line to Clang

Previously, we passed "#" to --autocomplete to indicate to enable cc1
flags. For example, when -cc1 or -Xclang was passed to bash, bash
executed `clang --autocomplete=#-<flag they want to complete>`.

However, this was not a good implementation because it depends -Xclang
and -cc1 parsing to shell. So I changed this to pass all flags shell
has, so that Clang can handle them internally.

I had to change many testcases because API spec changed quite a lot.

Reviewers: teemperor, v.g.vassilev

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D39342

Modified:
    cfe/trunk/include/clang/Driver/Driver.h
    cfe/trunk/lib/Driver/Driver.cpp
    cfe/trunk/test/Driver/autocomplete.c
    cfe/trunk/utils/bash-autocomplete.sh

Modified: cfe/trunk/include/clang/Driver/Driver.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Driver.h?rev=326684&r1=326683&r2=326684&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Driver.h (original)
+++ cfe/trunk/include/clang/Driver/Driver.h Mon Mar  5 00:54:20 2018
@@ -442,9 +442,9 @@ public:
   // 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.

Modified: cfe/trunk/lib/Driver/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Driver.cpp?rev=326684&r1=326683&r2=326684&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Driver.cpp (original)
+++ cfe/trunk/lib/Driver/Driver.cpp Mon Mar  5 00:54:20 2018
@@ -1419,44 +1419,56 @@ static void PrintDiagnosticCategories(ra
     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<std::string> SuggestedCompletions;
+  std::vector<std::string> 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 @@ bool Driver::HandleImmediateArgs(const C
 
   if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) {
     StringRef PassedFlags = A->getValue();
-    handleAutocompletions(PassedFlags);
+    HandleAutocompletions(PassedFlags);
     return false;
   }
 

Modified: cfe/trunk/test/Driver/autocomplete.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/autocomplete.c?rev=326684&r1=326683&r2=326684&view=diff
==============================================================================
--- cfe/trunk/test/Driver/autocomplete.c (original)
+++ cfe/trunk/test/Driver/autocomplete.c Mon Mar  5 00:54:20 2018
@@ -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

Modified: cfe/trunk/utils/bash-autocomplete.sh
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/bash-autocomplete.sh?rev=326684&r1=326683&r2=326684&view=diff
==============================================================================
--- cfe/trunk/utils/bash-autocomplete.sh (original)
+++ cfe/trunk/utils/bash-autocomplete.sh Mon Mar  5 00:54:20 2018
@@ -25,35 +25,16 @@ _clang()
     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<tab>
-    arg="$arg$cur"
-  elif [[ "$w1" == -*  && "$cur" == '=' ]]; then
-    # -foo=<tab>
-    arg="$arg$w1=,"
-  elif [[ "$cur" == -*= ]]; then
-    # -foo=<tab>
-    arg="$arg$cur,"
-  elif [[ "$w1" == -* ]]; then
-    # -foo <tab> or -foo bar<tab>
-    arg="$arg$w1,$cur"
-  elif [[ "$w2" == -* && "$w1" == '=' ]]; then
-    # -foo=bar<tab>
-    arg="$arg$w2=,$cur"
-  elif [[ ${cur: -1} != '=' && ${cur/=} != $cur ]]; then
-    # -foo=bar<tab>
-    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 @@ _clang()
 
   # 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=<tab> and there was no possible values, autocomplete files.
     [[ "$cur" == '=' || "$cur" == -*= ]] && cur=""
     _clang_filedir




More information about the cfe-commits mailing list