55#import < future>
66#import < iostream>
77#import < map>
8+ #import < set>
89#import < sourcekitd/sourcekitd.h>
910#import < sstream>
1011#import < string>
@@ -440,18 +441,6 @@ SwiftCompleter::SwiftCompleter(LogLevel logLevel)
440441SwiftCompleter::~SwiftCompleter () {
441442}
442443
443- // Transform completion flags into diagnostic flags
444- auto DiagnosticFlagsFromFlags (std::string filename, std::vector<std::string> flags) {
445- std::vector<std::string> outputFlags;
446- for (auto &f : flags) {
447- if (f == filename) {
448- continue ;
449- }
450- outputFlags.push_back (f);
451- }
452- return outputFlags;
453- }
454-
455444const std::string SwiftCompleter::CandidatesForLocationInFile (
456445 const std::string &filename, int line, int column,
457446 const std::vector<UnsavedFile> &unsavedFiles,
@@ -461,7 +450,7 @@ const std::string SwiftCompleter::CandidatesForLocationInFile(
461450 ctx.line = line;
462451 ctx.column = column;
463452 ctx.unsavedFiles = unsavedFiles;
464- ctx.flags = flags;
453+ ctx.flags = FlagsForCompileCommand ( flags) ;
465454
466455 SourceKitService sktService (_logger.level ());
467456 char *response = NULL ;
@@ -470,14 +459,30 @@ const std::string SwiftCompleter::CandidatesForLocationInFile(
470459 return response;
471460}
472461
462+ // Transform completion flags into diagnostic flags
463+ auto DiagnosticFlagsFromFlags (std::string filename,
464+ std::vector<std::string> flags) {
465+ std::vector<std::string> outputFlags;
466+ // Skip the file - I'm not 100% sure why we need this but it will output
467+ // weird warnings if not.
468+ for (auto &f : flags) {
469+ if (f == filename) {
470+ continue ;
471+ }
472+ outputFlags.push_back (f);
473+ }
474+ return outputFlags;
475+ }
476+
473477const std::string
474478SwiftCompleter::DiagnosticsForFile (const std::string &filename,
475479 const std::vector<UnsavedFile> &unsavedFiles,
476480 const std::vector<std::string> &flags) {
477481 CompletionContext ctx;
478482 ctx.sourceFilename = filename;
479483 ctx.unsavedFiles = unsavedFiles;
480- ctx.flags = DiagnosticFlagsFromFlags (filename, flags);
484+ auto completionFlags = FlagsForCompileCommand (flags);
485+ ctx.flags = DiagnosticFlagsFromFlags (filename, completionFlags);
481486 ctx.line = 0 ;
482487 ctx.column = 0 ;
483488
@@ -495,3 +500,75 @@ SwiftCompleter::DiagnosticsForFile(const std::string &filename,
495500 return semaresult;
496501}
497502} // namespace ssvim
503+ // namespace ssvim
504+
505+ #pragma mark - Command Preparation Logic
506+
507+ // Basic flag blacklist is a list of flags that cannot be included in a
508+ // CompilerInvocation for completion.
509+ //
510+ // These flags are a pair in the form
511+ // __FLAG__ Optional(__VALUE__)
512+ //
513+ // For example -c sometimes has a value after it.
514+ //
515+ // Only skip __VALUE__ when it doesn't start with -.
516+
517+ auto FlagStartToken = ' -' ;
518+ std::set<std::string> BasicFlagBlacklist{" -c" ,
519+ " -MP" ,
520+ " -MD" ,
521+ " -MMD" ,
522+ " --fcolor-diagnostics" ,
523+ " -emit-reference-dependencies-path" ,
524+ " -emit-dependencies-path" ,
525+ " -emit-module-path" ,
526+ " -serialize-diagnostics-path" ,
527+ " -emit-module-doc-path" ,
528+ " -frontend" ,
529+ " -o" };
530+
531+ // These flags may specified as pair of the form
532+ // __FLAG__ __VALUE__
533+ //
534+ // Unconditionally exclude flags in this blacklist and the next value
535+
536+ std::set<std::string> PairedFlagBlacklist{" -Xcc" };
537+
538+ // Take a raw split command and output completion flags
539+ std::vector<std::string>
540+ ssvim::FlagsForCompileCommand (std::vector<std::string> flags) {
541+ if (flags.size () == 0 ) {
542+ return flags;
543+ }
544+
545+ std::vector<std::string> outFlags;
546+
547+ // Skip the first flag if needed
548+ // Assume that someone will be using a swift compiler with an absolute path
549+ // and strip it off if so. All compile commands should be formed this way,
550+ // but some old test code uses it, so leave it for now.
551+ auto isCompilerBinary = flags.at (0 )[0 ] == ' /' ;
552+ unsigned long i = isCompilerBinary ? 1 : 0 ;
553+ auto length = flags.size ();
554+ while (i < length) {
555+ auto flag = flags.at (i);
556+ if (PairedFlagBlacklist.find (flag) != PairedFlagBlacklist.end ()) {
557+ i = i + 1 ;
558+ } else if (BasicFlagBlacklist.find (flag) != BasicFlagBlacklist.end ()) {
559+ auto nextIdx = i + 1 ;
560+
561+ // Skip the pair (FLAG, VALUE) when the next value isn't
562+ // another flag.
563+ if (nextIdx < length) {
564+ if (flags[nextIdx][0 ] != FlagStartToken) {
565+ i = i + 1 ;
566+ }
567+ }
568+ } else {
569+ outFlags.push_back (flag);
570+ }
571+ i = i + 1 ;
572+ }
573+ return outFlags;
574+ }
0 commit comments