Skip to content

Commit eda08c0

Browse files
committed
WIP: Move flag prep logic to server
In hindsight, it was a shitty decision to put flag prep in the client ( Probably a whisky driven design decision ) Revert this mistake. The CompilationDatabase should be an input to Swift services and tools ( like how this works in clang ). Now the client simply prepares a CompilationDatabase, and sends us commands from that. We need to process flags for diagnostics and it is more reasonable to have all of this flag logic happen in 1 place, and have clear definitions of what the server accepts as input for these flags. resolves #6 There should be a PR to YCMD as well ( or just merge into ycm-core/ycmd#487 ) TODO: Additionally consider making the flags accept a string instead of an array. It is insane to convert the string to an array on the client.
1 parent b1b5016 commit eda08c0

File tree

10 files changed

+396
-88
lines changed

10 files changed

+396
-88
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
build
55
*.DS_Store
66
!vendor/.gitignore
7-
7+
compile_commands.json

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ add_executable(http_server
9898
HTTPServerMain.cpp
9999
)
100100

101-
add_executable(test_driver
101+
add_executable(tests
102102
Logging.hpp
103103
SwiftCompleter.hpp
104104
SwiftCompleter.cpp
105-
Driver.cpp
105+
UnitTests.cpp
106106
)
107107

108108
add_executable(integration_tests

Driver.cpp

Lines changed: 0 additions & 71 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// AppDelegate.swift
3+
// Basic
4+
//
5+
// Created by Jerry Marino on 5/13/17.
6+
// Copyright © 2017 Jerry Marino. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
@UIApplicationMain
12+
class AppDelegate: UIResponder, UIApplicationDelegate {
13+
14+
var window: UIWindow?
15+
16+
17+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18+
// Override point for customization after application launch.
19+
return true
20+
}
21+
22+
func ycmdMethod() {
23+
self.window?.sub
24+
}
25+
}
26+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// ViewController.swift
3+
// Basic
4+
//
5+
// Created by Jerry Marino on 5/13/17.
6+
// Copyright © 2017 Jerry Marino. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
class ViewController: UIViewController {
12+
13+
override func viewDidLoad() {
14+
super.viewDidLoad()
15+
}
16+
17+
override func didReceiveMemoryWarning() {
18+
super.didReceiveMemoryWarning()
19+
let delegate = UIApplication.shared.delegate as! AppDelegate
20+
// Here we are calling a custom method on the AppDelegate
21+
delegate.ycmd
22+
}
23+
}
24+

Examples/iOS/Basic/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# YCMD iOS Swift Example
2+
3+
This directory contains a basic example of an iOS project running under YCMD.
4+
5+
The example contains a project generated from Xcode, minus any unneeded files (
6+
assets, xcodeproj, etc )
7+
8+
It's a simple iOS app and ViewController.swift depends on AppDelegate.swift.
9+
10+
It should serve as a base case so that we can make sure symbols are correctly
11+
loading for people from the iOS SDK and external files.
12+
13+
These abilities are mostly dependent on a correct Compilation Database.
14+
15+
The Compilation Database is a template which is written in test setup. It must
16+
be in the root directory of the examples. This template was generated from a
17+
build of these files under xcodebuild, with the following manual changes:
18+
19+
- replace the source root with __SRCROOT__
20+
- remove 10.3 version requirement
21+
- strip out flags that pass missing build artifacts
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[
2+
{
3+
"directory": "__SRCROOT__",
4+
"command": "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -c -primary-file __SRCROOT__/Basic/ViewController.swift __SRCROOT__/Basic/AppDelegate.swift -enable-objc-interop -sdk /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -enable-testing -g -serialize-debugging-options -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/swift-overrides.hmap -Xcc -iquote -Xcc /Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/Basic-generated-files.hmap -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/Basic-own-target-headers.hmap -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/Basic-all-target-headers.hmap -Xcc -iquote -Xcc /Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/Basic-project-headers.hmap -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Products/Debug-iphonesimulator/include -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/DerivedSources/x86_64 -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/DerivedSources -Xcc -DDEBUG=1 -Xcc -working-directory__SRCROOT__ -Onone -module-name Basic -o /Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/Objects-normal/x86_64/ViewController.o",
5+
"file": "__SRCROOT__/Basic/ViewController.swift"
6+
},
7+
{
8+
"directory": "__SRCROOT__",
9+
"command": "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -c __SRCROOT__/Basic/ViewController.swift -primary-file __SRCROOT__/Basic/AppDelegate.swift -enable-objc-interop -sdk /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -enable-testing -g -serialize-debugging-options -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/swift-overrides.hmap -Xcc -iquote -Xcc /Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/Basic-generated-files.hmap -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/Basic-own-target-headers.hmap -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/Basic-all-target-headers.hmap -Xcc -iquote -Xcc /Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/Basic-project-headers.hmap -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Products/Debug-iphonesimulator/include -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/DerivedSources/x86_64 -Xcc -I/Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/DerivedSources -Xcc -DDEBUG=1 -Xcc -working-directory__SRCROOT__ -Onone -module-name Basic -o /Users/fakeuser/Library/Developer/Xcode/DerivedData/Basic-dcvyhoqxsulylretnajwiqnkngaj/Build/Intermediates/Basic.build/Debug-iphonesimulator/Basic.build/Objects-normal/x86_64/AppDelegate.o",
10+
"file": "__SRCROOT__/Basic/AppDelegate.swift"
11+
}
12+
]

SwiftCompleter.cpp

Lines changed: 91 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
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)
440441
SwiftCompleter::~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-
455444
const 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+
473477
const std::string
474478
SwiftCompleter::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+
}

SwiftCompleter.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,10 @@ class SwiftCompleter {
3939
const std::vector<UnsavedFile> &unsavedFiles,
4040
const std::vector<std::string> &flags);
4141
};
42+
43+
#pragma mark - Testing
44+
45+
extern std::vector<std::string>
46+
FlagsForCompileCommand(std::vector<std::string> flags);
47+
4248
} // namespace ssvim

0 commit comments

Comments
 (0)