diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -362,8 +362,10 @@ if (auto ToInclude = Inserted(Inc)) { CodeCompletion::IncludeCandidate Include; Include.Header = ToInclude->first; + // TODO: Suggest #import here instead of #include for Objective-C code. if (ToInclude->second && ShouldInsert) - Include.Insertion = Includes.insert(ToInclude->first); + Include.Insertion = + Includes.insert(ToInclude->first, /*ViaImport=*/false); Completion.Includes.push_back(std::move(Include)); } else log("Failed to generate include insertion edits for adding header " diff --git a/clang-tools-extra/clangd/Headers.h b/clang-tools-extra/clangd/Headers.h --- a/clang-tools-extra/clangd/Headers.h +++ b/clang-tools-extra/clangd/Headers.h @@ -228,7 +228,8 @@ /// Calculates an edit that inserts \p VerbatimHeader into code. If the header /// is already included, this returns None. - llvm::Optional insert(llvm::StringRef VerbatimHeader) const; + llvm::Optional insert(llvm::StringRef VerbatimHeader, + bool ViaImport) const; private: StringRef FileName; diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp --- a/clang-tools-extra/clangd/Headers.cpp +++ b/clang-tools-extra/clangd/Headers.cpp @@ -276,11 +276,12 @@ return Suggested; } -llvm::Optional -IncludeInserter::insert(llvm::StringRef VerbatimHeader) const { +llvm::Optional IncludeInserter::insert(llvm::StringRef VerbatimHeader, + bool ViaImport) const { llvm::Optional Edit = None; - if (auto Insertion = Inserter.insert(VerbatimHeader.trim("\"<>"), - VerbatimHeader.startswith("<"))) + if (auto Insertion = + Inserter.insert(VerbatimHeader.trim("\"<>"), + VerbatimHeader.startswith("<"), ViaImport)) Edit = replacementToEdit(Code, *Insertion); return Edit; } diff --git a/clang-tools-extra/clangd/IncludeFixer.cpp b/clang-tools-extra/clangd/IncludeFixer.cpp --- a/clang-tools-extra/clangd/IncludeFixer.cpp +++ b/clang-tools-extra/clangd/IncludeFixer.cpp @@ -163,7 +163,10 @@ auto I = InsertedHeaders.try_emplace(ToInclude->first); if (!I.second) continue; - if (auto Edit = Inserter->insert(ToInclude->first)) + // TODO: Suggest #import here instead of #include for Objective-C + // code. + if (auto Edit = + Inserter->insert(ToInclude->first, /*ViaImport=*/false)) Fixes.push_back(Fix{std::string(llvm::formatv( "Add include {0} for symbol {1}{2}", ToInclude->first, Sym.Scope, Sym.Name)), diff --git a/clang-tools-extra/clangd/unittests/HeadersTests.cpp b/clang-tools-extra/clangd/unittests/HeadersTests.cpp --- a/clang-tools-extra/clangd/unittests/HeadersTests.cpp +++ b/clang-tools-extra/clangd/unittests/HeadersTests.cpp @@ -115,7 +115,8 @@ return Path.getValueOr(""); } - llvm::Optional insert(llvm::StringRef VerbatimHeader) { + llvm::Optional insert(llvm::StringRef VerbatimHeader, + bool ViaImport) { Clang = setupClang(); PreprocessOnlyAction Action; EXPECT_TRUE( @@ -124,7 +125,7 @@ IncludeInserter Inserter(MainFile, /*Code=*/"", format::getLLVMStyle(), CDB.getCompileCommand(MainFile)->Directory, &Clang->getPreprocessor().getHeaderSearchInfo()); - auto Edit = Inserter.insert(VerbatimHeader); + auto Edit = Inserter.insert(VerbatimHeader, ViaImport); Action.EndSourceFile(); return Edit; } @@ -315,11 +316,17 @@ } TEST_F(HeadersTest, PreferInserted) { - auto Edit = insert(""); + auto Edit = insert("", /*ViaImport=*/false); EXPECT_TRUE(Edit.hasValue()); EXPECT_TRUE(StringRef(Edit->newText).contains("")); } +TEST_F(HeadersTest, Import) { + auto Edit = insert("\"y\"", /*ViaImport=*/true); + EXPECT_TRUE(Edit.hasValue()); + EXPECT_TRUE(StringRef(Edit->newText).contains("#import \"y\"")); +} + TEST(Headers, NoHeaderSearchInfo) { std::string MainFile = testPath("main.cpp"); IncludeInserter Inserter(MainFile, /*Code=*/"", format::getLLVMStyle(), diff --git a/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h b/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h --- a/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h +++ b/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h @@ -50,9 +50,9 @@ HeaderIncludes(llvm::StringRef FileName, llvm::StringRef Code, const IncludeStyle &Style); - /// Inserts an #include directive of \p Header into the code. If \p IsAngled - /// is true, \p Header will be quoted with <> in the directive; otherwise, it - /// will be quoted with "". + /// Inserts an #include or #import directive of \p IncludeName into the code. + /// If \p IsAngled is true, \p IncludeName will be quoted with <> in the + /// directive; otherwise, it will be quoted with "". /// /// When searching for points to insert new header, this ignores #include's /// after the #include block(s) in the beginning of a file to avoid inserting @@ -69,13 +69,14 @@ /// same category in the code that should be sorted after \p IncludeName. If /// \p IncludeName already exists (with exactly the same spelling), this /// returns None. - llvm::Optional insert(llvm::StringRef Header, - bool IsAngled) const; + llvm::Optional insert(llvm::StringRef IncludeName, + bool IsAngled, + bool IsImport = false) const; /// Removes all existing #includes of \p Header quoted with <> if \p IsAngled /// is true or "" if \p IsAngled is false. - /// This doesn't resolve the header file path; it only deletes #includes with - /// exactly the same spelling. + /// This doesn't resolve the header file path; it only deletes #includes and + /// #imports with exactly the same spelling. tooling::Replacements remove(llvm::StringRef Header, bool IsAngled) const; private: diff --git a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp --- a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp +++ b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp @@ -340,7 +340,8 @@ } llvm::Optional -HeaderIncludes::insert(llvm::StringRef IncludeName, bool IsAngled) const { +HeaderIncludes::insert(llvm::StringRef IncludeName, bool IsAngled, + bool IsImport) const { assert(IncludeName == trimInclude(IncludeName)); // If a
("header") already exists in code, "header" (
) with // different quotation will still be inserted. @@ -370,7 +371,8 @@ } assert(InsertOffset <= Code.size()); std::string NewInclude = - std::string(llvm::formatv("#include {0}\n", QuotedName)); + IsImport ? std::string(llvm::formatv("#import {0}\n", QuotedName)) + : std::string(llvm::formatv("#include {0}\n", QuotedName)); // When inserting headers at end of the code, also append '\n' to the code // if it does not end with '\n'. // FIXME: when inserting multiple #includes at the end of code, only one