Support framework import/include auto-completion

Frameworks filesystem representations:
  UIKit.framework/Headers/%header%

Framework import format:
  #import <UIKit/%header%>

Thus the completion code must map the input format of <UIKit/> to
the path of UIKit.framework/Headers as well as strip the
".framework" suffix when auto-completing the framework name.

llvm-svn: 355008
This commit is contained in:
David Goldman 2019-02-27 17:40:33 +00:00
parent eaa895368b
commit 3e804d2581
2 changed files with 57 additions and 6 deletions

View File

@ -8404,10 +8404,23 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
};
// Helper: scans IncludeDir for nice files, and adds results for each.
auto AddFilesFromIncludeDir = [&](StringRef IncludeDir, bool IsSystem) {
auto AddFilesFromIncludeDir = [&](StringRef IncludeDir,
bool IsSystem,
DirectoryLookup::LookupType_t LookupType) {
llvm::SmallString<128> Dir = IncludeDir;
if (!NativeRelDir.empty())
llvm::sys::path::append(Dir, NativeRelDir);
if (!NativeRelDir.empty()) {
if (LookupType == DirectoryLookup::LT_Framework) {
// For a framework dir, #include <Foo/Bar/> actually maps to
// a path of Foo.framework/Headers/Bar/.
auto Begin = llvm::sys::path::begin(NativeRelDir);
auto End = llvm::sys::path::end(NativeRelDir);
llvm::sys::path::append(Dir, *Begin + ".framework", "Headers");
llvm::sys::path::append(Dir, ++Begin, End);
} else {
llvm::sys::path::append(Dir, NativeRelDir);
}
}
std::error_code EC;
unsigned Count = 0;
@ -8418,6 +8431,12 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
StringRef Filename = llvm::sys::path::filename(It->path());
switch (It->type()) {
case llvm::sys::fs::file_type::directory_file:
// All entries in a framework directory must have a ".framework" suffix,
// but the suffix does not appear in the source code's include/import.
if (LookupType == DirectoryLookup::LT_Framework &&
NativeRelDir.empty() && !Filename.consume_back(".framework"))
break;
AddCompletion(Filename, /*IsDirectory=*/true);
break;
case llvm::sys::fs::file_type::regular_file:
@ -8446,10 +8465,12 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
// header maps are not (currently) enumerable.
break;
case DirectoryLookup::LT_NormalDir:
AddFilesFromIncludeDir(IncludeDir.getDir()->getName(), IsSystem);
AddFilesFromIncludeDir(IncludeDir.getDir()->getName(), IsSystem,
DirectoryLookup::LT_NormalDir);
break;
case DirectoryLookup::LT_Framework:
AddFilesFromIncludeDir(IncludeDir.getFrameworkDir()->getName(), IsSystem);
AddFilesFromIncludeDir(IncludeDir.getFrameworkDir()->getName(), IsSystem,
DirectoryLookup::LT_Framework);
break;
}
};
@ -8463,7 +8484,8 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
// The current directory is on the include path for "quoted" includes.
auto *CurFile = PP.getCurrentFileLexer()->getFileEntry();
if (CurFile && CurFile->getDir())
AddFilesFromIncludeDir(CurFile->getDir()->getName(), false);
AddFilesFromIncludeDir(CurFile->getDir()->getName(), false,
DirectoryLookup::LT_NormalDir);
for (const auto &D : make_range(S.quoted_dir_begin(), S.quoted_dir_end()))
AddFilesFromDirLookup(D, false);
}

View File

@ -0,0 +1,29 @@
// RUN: rm -rf %t && mkdir -p %t/Foo.framework/Headers/SubFolder && mkdir %t/NotAFramework/
// RUN: touch %t/Foo.framework/Headers/Foo.h && touch %t/Foo.framework/Headers/FOOClass.h
// RUN: touch %t/Foo.framework/Headers/SubFolder/FOOInternal.h
#import <Foo/Foo.h>
#import <Foo/SubFolder/FOOInternal.h>
// Note: the run lines follow their respective tests, since line/column
// matter in this test.
// Autocomplete frameworks without the ".framework" extension.
//
// RUN: %clang -fsyntax-only -F %t -Xclang -code-completion-at=%s:5:10 %s -o - | FileCheck -check-prefix=CHECK-1 %s
// CHECK-1-NOT: Foo.framework/
// CHECK-1-NOT: NotAFramework/
// CHECK-1: Foo/
// Autocomplete for frameworks inside its Headers folder.
//
// RUN: %clang -fsyntax-only -F %t -Xclang -code-completion-at=%s:5:14 %s -o - | FileCheck -check-prefix=CHECK-2 %s
// CHECK-2: Foo.h>
// CHECK-2: FOOClass.h>
// CHECK-2: SubFolder/
// Autocomplete for folders inside of a frameworks.
//
// RUN: %clang -fsyntax-only -F %t -Xclang -code-completion-at=%s:7:24 %s -o - | FileCheck -check-prefix=CHECK-3 %s
// CHECK-3: FOOInternal.h>