Skip to content

Commit 3e804d2

Browse files
committed
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
1 parent eaa8953 commit 3e804d2

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

clang/lib/Sema/SemaCodeComplete.cpp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8404,10 +8404,23 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
84048404
};
84058405

84068406
// Helper: scans IncludeDir for nice files, and adds results for each.
8407-
auto AddFilesFromIncludeDir = [&](StringRef IncludeDir, bool IsSystem) {
8407+
auto AddFilesFromIncludeDir = [&](StringRef IncludeDir,
8408+
bool IsSystem,
8409+
DirectoryLookup::LookupType_t LookupType) {
84088410
llvm::SmallString<128> Dir = IncludeDir;
8409-
if (!NativeRelDir.empty())
8410-
llvm::sys::path::append(Dir, NativeRelDir);
8411+
if (!NativeRelDir.empty()) {
8412+
if (LookupType == DirectoryLookup::LT_Framework) {
8413+
// For a framework dir, #include <Foo/Bar/> actually maps to
8414+
// a path of Foo.framework/Headers/Bar/.
8415+
auto Begin = llvm::sys::path::begin(NativeRelDir);
8416+
auto End = llvm::sys::path::end(NativeRelDir);
8417+
8418+
llvm::sys::path::append(Dir, *Begin + ".framework", "Headers");
8419+
llvm::sys::path::append(Dir, ++Begin, End);
8420+
} else {
8421+
llvm::sys::path::append(Dir, NativeRelDir);
8422+
}
8423+
}
84118424

84128425
std::error_code EC;
84138426
unsigned Count = 0;
@@ -8418,6 +8431,12 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
84188431
StringRef Filename = llvm::sys::path::filename(It->path());
84198432
switch (It->type()) {
84208433
case llvm::sys::fs::file_type::directory_file:
8434+
// All entries in a framework directory must have a ".framework" suffix,
8435+
// but the suffix does not appear in the source code's include/import.
8436+
if (LookupType == DirectoryLookup::LT_Framework &&
8437+
NativeRelDir.empty() && !Filename.consume_back(".framework"))
8438+
break;
8439+
84218440
AddCompletion(Filename, /*IsDirectory=*/true);
84228441
break;
84238442
case llvm::sys::fs::file_type::regular_file:
@@ -8446,10 +8465,12 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
84468465
// header maps are not (currently) enumerable.
84478466
break;
84488467
case DirectoryLookup::LT_NormalDir:
8449-
AddFilesFromIncludeDir(IncludeDir.getDir()->getName(), IsSystem);
8468+
AddFilesFromIncludeDir(IncludeDir.getDir()->getName(), IsSystem,
8469+
DirectoryLookup::LT_NormalDir);
84508470
break;
84518471
case DirectoryLookup::LT_Framework:
8452-
AddFilesFromIncludeDir(IncludeDir.getFrameworkDir()->getName(), IsSystem);
8472+
AddFilesFromIncludeDir(IncludeDir.getFrameworkDir()->getName(), IsSystem,
8473+
DirectoryLookup::LT_Framework);
84538474
break;
84548475
}
84558476
};
@@ -8463,7 +8484,8 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
84638484
// The current directory is on the include path for "quoted" includes.
84648485
auto *CurFile = PP.getCurrentFileLexer()->getFileEntry();
84658486
if (CurFile && CurFile->getDir())
8466-
AddFilesFromIncludeDir(CurFile->getDir()->getName(), false);
8487+
AddFilesFromIncludeDir(CurFile->getDir()->getName(), false,
8488+
DirectoryLookup::LT_NormalDir);
84678489
for (const auto &D : make_range(S.quoted_dir_begin(), S.quoted_dir_end()))
84688490
AddFilesFromDirLookup(D, false);
84698491
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: rm -rf %t && mkdir -p %t/Foo.framework/Headers/SubFolder && mkdir %t/NotAFramework/
2+
// RUN: touch %t/Foo.framework/Headers/Foo.h && touch %t/Foo.framework/Headers/FOOClass.h
3+
// RUN: touch %t/Foo.framework/Headers/SubFolder/FOOInternal.h
4+
5+
#import <Foo/Foo.h>
6+
7+
#import <Foo/SubFolder/FOOInternal.h>
8+
9+
// Note: the run lines follow their respective tests, since line/column
10+
// matter in this test.
11+
12+
// Autocomplete frameworks without the ".framework" extension.
13+
//
14+
// RUN: %clang -fsyntax-only -F %t -Xclang -code-completion-at=%s:5:10 %s -o - | FileCheck -check-prefix=CHECK-1 %s
15+
// CHECK-1-NOT: Foo.framework/
16+
// CHECK-1-NOT: NotAFramework/
17+
// CHECK-1: Foo/
18+
19+
// Autocomplete for frameworks inside its Headers folder.
20+
//
21+
// RUN: %clang -fsyntax-only -F %t -Xclang -code-completion-at=%s:5:14 %s -o - | FileCheck -check-prefix=CHECK-2 %s
22+
// CHECK-2: Foo.h>
23+
// CHECK-2: FOOClass.h>
24+
// CHECK-2: SubFolder/
25+
26+
// Autocomplete for folders inside of a frameworks.
27+
//
28+
// RUN: %clang -fsyntax-only -F %t -Xclang -code-completion-at=%s:7:24 %s -o - | FileCheck -check-prefix=CHECK-3 %s
29+
// CHECK-3: FOOInternal.h>

0 commit comments

Comments
 (0)