Skip to content

Commit

Permalink
WIP: Move flag prep logic to server
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jerrymarino committed Jun 1, 2017
1 parent b1b5016 commit eda08c0
Show file tree
Hide file tree
Showing 10 changed files with 396 additions and 88 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
build
*.DS_Store
!vendor/.gitignore

compile_commands.json
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ add_executable(http_server
HTTPServerMain.cpp
)

add_executable(test_driver
add_executable(tests
Logging.hpp
SwiftCompleter.hpp
SwiftCompleter.cpp
Driver.cpp
UnitTests.cpp
)

add_executable(integration_tests
Expand Down
71 changes: 0 additions & 71 deletions Driver.cpp

This file was deleted.

26 changes: 26 additions & 0 deletions Examples/iOS/Basic/Basic/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// AppDelegate.swift
// Basic
//
// Created by Jerry Marino on 5/13/17.
// Copyright © 2017 Jerry Marino. All rights reserved.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}

func ycmdMethod() {
self.window?.sub
}
}

24 changes: 24 additions & 0 deletions Examples/iOS/Basic/Basic/ViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// ViewController.swift
// Basic
//
// Created by Jerry Marino on 5/13/17.
// Copyright © 2017 Jerry Marino. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
let delegate = UIApplication.shared.delegate as! AppDelegate
// Here we are calling a custom method on the AppDelegate
delegate.ycmd
}
}

21 changes: 21 additions & 0 deletions Examples/iOS/Basic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# YCMD iOS Swift Example

This directory contains a basic example of an iOS project running under YCMD.

The example contains a project generated from Xcode, minus any unneeded files (
assets, xcodeproj, etc )

It's a simple iOS app and ViewController.swift depends on AppDelegate.swift.

It should serve as a base case so that we can make sure symbols are correctly
loading for people from the iOS SDK and external files.

These abilities are mostly dependent on a correct Compilation Database.

The Compilation Database is a template which is written in test setup. It must
be in the root directory of the examples. This template was generated from a
build of these files under xcodebuild, with the following manual changes:

- replace the source root with __SRCROOT__
- remove 10.3 version requirement
- strip out flags that pass missing build artifacts
12 changes: 12 additions & 0 deletions Examples/iOS/Basic/compile_commands.json.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"directory": "__SRCROOT__",
"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",
"file": "__SRCROOT__/Basic/ViewController.swift"
},
{
"directory": "__SRCROOT__",
"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",
"file": "__SRCROOT__/Basic/AppDelegate.swift"
}
]
105 changes: 91 additions & 14 deletions SwiftCompleter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#import <future>
#import <iostream>
#import <map>
#import <set>
#import <sourcekitd/sourcekitd.h>
#import <sstream>
#import <string>
Expand Down Expand Up @@ -440,18 +441,6 @@ SwiftCompleter::SwiftCompleter(LogLevel logLevel)
SwiftCompleter::~SwiftCompleter() {
}

// Transform completion flags into diagnostic flags
auto DiagnosticFlagsFromFlags(std::string filename, std::vector<std::string> flags) {
std::vector<std::string> outputFlags;
for (auto &f : flags) {
if (f == filename) {
continue;
}
outputFlags.push_back(f);
}
return outputFlags;
}

const std::string SwiftCompleter::CandidatesForLocationInFile(
const std::string &filename, int line, int column,
const std::vector<UnsavedFile> &unsavedFiles,
Expand All @@ -461,7 +450,7 @@ const std::string SwiftCompleter::CandidatesForLocationInFile(
ctx.line = line;
ctx.column = column;
ctx.unsavedFiles = unsavedFiles;
ctx.flags = flags;
ctx.flags = FlagsForCompileCommand(flags);

SourceKitService sktService(_logger.level());
char *response = NULL;
Expand All @@ -470,14 +459,30 @@ const std::string SwiftCompleter::CandidatesForLocationInFile(
return response;
}

// Transform completion flags into diagnostic flags
auto DiagnosticFlagsFromFlags(std::string filename,
std::vector<std::string> flags) {
std::vector<std::string> outputFlags;
// Skip the file - I'm not 100% sure why we need this but it will output
// weird warnings if not.
for (auto &f : flags) {
if (f == filename) {
continue;
}
outputFlags.push_back(f);
}
return outputFlags;
}

const std::string
SwiftCompleter::DiagnosticsForFile(const std::string &filename,
const std::vector<UnsavedFile> &unsavedFiles,
const std::vector<std::string> &flags) {
CompletionContext ctx;
ctx.sourceFilename = filename;
ctx.unsavedFiles = unsavedFiles;
ctx.flags = DiagnosticFlagsFromFlags(filename, flags);
auto completionFlags = FlagsForCompileCommand(flags);
ctx.flags = DiagnosticFlagsFromFlags(filename, completionFlags);
ctx.line = 0;
ctx.column = 0;

Expand All @@ -495,3 +500,75 @@ SwiftCompleter::DiagnosticsForFile(const std::string &filename,
return semaresult;
}
} // namespace ssvim
// namespace ssvim

#pragma mark - Command Preparation Logic

// Basic flag blacklist is a list of flags that cannot be included in a
// CompilerInvocation for completion.
//
// These flags are a pair in the form
// __FLAG__ Optional(__VALUE__)
//
// For example -c sometimes has a value after it.
//
// Only skip __VALUE__ when it doesn't start with -.

auto FlagStartToken = '-';
std::set<std::string> BasicFlagBlacklist{"-c",
"-MP",
"-MD",
"-MMD",
"--fcolor-diagnostics",
"-emit-reference-dependencies-path",
"-emit-dependencies-path",
"-emit-module-path",
"-serialize-diagnostics-path",
"-emit-module-doc-path",
"-frontend",
"-o"};

// These flags may specified as pair of the form
// __FLAG__ __VALUE__
//
// Unconditionally exclude flags in this blacklist and the next value

std::set<std::string> PairedFlagBlacklist{"-Xcc"};

// Take a raw split command and output completion flags
std::vector<std::string>
ssvim::FlagsForCompileCommand(std::vector<std::string> flags) {
if (flags.size() == 0) {
return flags;
}

std::vector<std::string> outFlags;

// Skip the first flag if needed
// Assume that someone will be using a swift compiler with an absolute path
// and strip it off if so. All compile commands should be formed this way,
// but some old test code uses it, so leave it for now.
auto isCompilerBinary = flags.at(0)[0] == '/';
unsigned long i = isCompilerBinary ? 1 : 0;
auto length = flags.size();
while (i < length) {
auto flag = flags.at(i);
if (PairedFlagBlacklist.find(flag) != PairedFlagBlacklist.end()) {
i = i + 1;
} else if (BasicFlagBlacklist.find(flag) != BasicFlagBlacklist.end()) {
auto nextIdx = i + 1;

// Skip the pair (FLAG, VALUE) when the next value isn't
// another flag.
if (nextIdx < length) {
if (flags[nextIdx][0] != FlagStartToken) {
i = i + 1;
}
}
} else {
outFlags.push_back(flag);
}
i = i + 1;
}
return outFlags;
}
6 changes: 6 additions & 0 deletions SwiftCompleter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,10 @@ class SwiftCompleter {
const std::vector<UnsavedFile> &unsavedFiles,
const std::vector<std::string> &flags);
};

#pragma mark - Testing

extern std::vector<std::string>
FlagsForCompileCommand(std::vector<std::string> flags);

} // namespace ssvim
Loading

0 comments on commit eda08c0

Please sign in to comment.