blob: 0ffd9ee4d2751037e448454c7c88cc35726bf63c [file] [log] [blame]
Eric Liuc5105f92018-02-16 14:15:55 +00001//===--- Headers.cpp - Include headers ---------------------------*- C++-*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Eric Liuc5105f92018-02-16 14:15:55 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "Headers.h"
Kadir Cetinkaya538c2752020-05-14 12:26:47 +020010#include "Preamble.h"
Eric Liu155f5a42018-05-14 12:19:16 +000011#include "SourceCode.h"
kleines Filmröllchen1f907972024-12-27 20:14:29 +010012#include "support/Logger.h"
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +020013#include "clang/Basic/SourceLocation.h"
14#include "clang/Basic/SourceManager.h"
Eric Liuc5105f92018-02-16 14:15:55 +000015#include "clang/Frontend/CompilerInstance.h"
Sam McCalld97a3412023-07-20 21:46:52 +020016#include "clang/Lex/DirectoryLookup.h"
Eric Liuc5105f92018-02-16 14:15:55 +000017#include "clang/Lex/HeaderSearch.h"
Kirill Bobyreveecfc732021-12-08 15:55:39 +010018#include "clang/Lex/PPCallbacks.h"
19#include "clang/Lex/Preprocessor.h"
Haojian Wudd46a082022-11-07 13:30:47 +010020#include "clang/Tooling/Inclusions/HeaderAnalysis.h"
Viktoriia Bakalovae028c972023-02-07 16:52:51 +000021#include "llvm/ADT/SmallVector.h"
Kadir Cetinkaya1f6d9842019-07-03 07:47:19 +000022#include "llvm/ADT/StringRef.h"
Eric Liu709bde82018-02-19 18:48:44 +000023#include "llvm/Support/Path.h"
Kirill Bobyrev9f05b112022-04-21 16:59:59 +020024#include <cstring>
Kazu Hirata71f55732023-01-07 20:02:20 -080025#include <optional>
Viktoriia Bakalova7322f2d2023-07-11 13:33:53 +000026#include <string>
Eric Liuc5105f92018-02-16 14:15:55 +000027
28namespace clang {
29namespace clangd {
Eric Liuc5105f92018-02-16 14:15:55 +000030
Haojian Wube39dae2023-03-10 12:06:32 +010031class IncludeStructure::RecordHeaders : public PPCallbacks {
Eric Liuc5105f92018-02-16 14:15:55 +000032public:
Kirill Bobyreveecfc732021-12-08 15:55:39 +010033 RecordHeaders(const CompilerInstance &CI, IncludeStructure *Out)
kleines Filmröllchen1f907972024-12-27 20:14:29 +010034 : SM(CI.getSourceManager()), Out(Out) {}
Eric Liuc5105f92018-02-16 14:15:55 +000035
Eric Liu155f5a42018-05-14 12:19:16 +000036 // Record existing #includes - both written and resolved paths. Only #includes
37 // in the main file are collected.
Kadir Cetinkaya6e017182020-04-15 22:00:19 +020038 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000039 llvm::StringRef FileName, bool IsAngled,
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +020040 CharSourceRange /*FilenameRange*/,
Benjamin Kramer854c10f2022-12-20 00:15:11 +010041 OptionalFileEntryRef File,
Jan Svobodad79ad2f2022-04-11 12:10:05 +020042 llvm::StringRef /*SearchPath*/,
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000043 llvm::StringRef /*RelativePath*/,
Jan Svobodada95d922024-02-08 19:19:18 +010044 const clang::Module * /*SuggestedModule*/,
45 bool /*ModuleImported*/,
Sam McCall991e3162018-11-20 10:58:48 +000046 SrcMgr::CharacteristicKind FileKind) override {
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +020047 auto MainFID = SM.getMainFileID();
48 // If an include is part of the preamble patch, translate #line directives.
Kadir Cetinkaya538c2752020-05-14 12:26:47 +020049 if (InBuiltinFile)
50 HashLoc = translatePreamblePatchLocation(HashLoc, SM);
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +020051
52 // Record main-file inclusions (including those mapped from the preamble
53 // patch).
Haojian Wu6ae86ea2019-07-19 08:33:39 +000054 if (isInsideMainFile(HashLoc, SM)) {
Sam McCall991e3162018-11-20 10:58:48 +000055 Out->MainFileIncludes.emplace_back();
56 auto &Inc = Out->MainFileIncludes.back();
Sam McCall991e3162018-11-20 10:58:48 +000057 Inc.Written =
58 (IsAngled ? "<" + FileName + ">" : "\"" + FileName + "\"").str();
Viktoriia Bakalova7322f2d2023-07-11 13:33:53 +000059 Inc.Resolved = std::string(
60 File ? getCanonicalPath(*File, SM.getFileManager()).value_or("")
61 : "");
Sam McCall991e3162018-11-20 10:58:48 +000062 Inc.HashOffset = SM.getFileOffset(HashLoc);
Kadir Cetinkayad8700162020-05-04 10:48:19 +020063 Inc.HashLine =
64 SM.getLineNumber(SM.getFileID(HashLoc), Inc.HashOffset) - 1;
Sam McCall991e3162018-11-20 10:58:48 +000065 Inc.FileKind = FileKind;
Kadir Cetinkaya6e017182020-04-15 22:00:19 +020066 Inc.Directive = IncludeTok.getIdentifierInfo()->getPPKeywordID();
Sam McCall478863e2021-11-17 13:27:58 +010067 if (File) {
Jan Svobodad79ad2f2022-04-11 12:10:05 +020068 IncludeStructure::HeaderID HID = Out->getOrCreateID(*File);
Sam McCall478863e2021-11-17 13:27:58 +010069 Inc.HeaderID = static_cast<unsigned>(HID);
70 if (IsAngled)
Kirill Bobyrev46a6f5a2022-02-09 11:04:58 +010071 if (auto StdlibHeader = tooling::stdlib::Header::named(Inc.Written)) {
Sam McCall478863e2021-11-17 13:27:58 +010072 auto &IDs = Out->StdlibHeaders[*StdlibHeader];
73 // Few physical files for one stdlib header name, linear scan is ok.
74 if (!llvm::is_contained(IDs, HID))
75 IDs.push_back(HID);
76 }
77 }
Kazu Hirata3f156ef2024-10-11 09:00:39 -070078 Out->MainFileIncludesBySpelling[Inc.Written].push_back(
79 Out->MainFileIncludes.size() - 1);
Sam McCall991e3162018-11-20 10:58:48 +000080 }
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +020081
82 // Record include graph (not just for main-file includes)
Sam McCall3f0243f2018-07-03 08:09:29 +000083 if (File) {
Jan Svobodad79ad2f2022-04-11 12:10:05 +020084 auto IncludingFileEntry = SM.getFileEntryRefForID(SM.getFileID(HashLoc));
Sam McCall3f0243f2018-07-03 08:09:29 +000085 if (!IncludingFileEntry) {
Kazu Hiratad5953e32023-12-13 23:26:09 -080086 assert(SM.getBufferName(HashLoc).starts_with("<") &&
Sam McCall3f0243f2018-07-03 08:09:29 +000087 "Expected #include location to be a file or <built-in>");
88 // Treat as if included from the main file.
Jan Svobodad79ad2f2022-04-11 12:10:05 +020089 IncludingFileEntry = SM.getFileEntryRefForID(MainFID);
Sam McCall3f0243f2018-07-03 08:09:29 +000090 }
Jan Svobodad79ad2f2022-04-11 12:10:05 +020091 auto IncludingID = Out->getOrCreateID(*IncludingFileEntry),
92 IncludedID = Out->getOrCreateID(*File);
Kirill Bobyrevdea48072021-09-30 14:41:27 +020093 Out->IncludeChildren[IncludingID].push_back(IncludedID);
Sam McCall3f0243f2018-07-03 08:09:29 +000094 }
Eric Liuc5105f92018-02-16 14:15:55 +000095 }
96
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +020097 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
98 SrcMgr::CharacteristicKind FileType,
99 FileID PrevFID) override {
100 switch (Reason) {
101 case PPCallbacks::EnterFile:
Kirill Bobyreveecfc732021-12-08 15:55:39 +0100102 ++Level;
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +0200103 if (BuiltinFile.isInvalid() && SM.isWrittenInBuiltinFile(Loc)) {
104 BuiltinFile = SM.getFileID(Loc);
105 InBuiltinFile = true;
106 }
107 break;
Kirill Bobyrevcd0ca5a2021-11-26 14:12:35 +0100108 case PPCallbacks::ExitFile: {
Kirill Bobyreveecfc732021-12-08 15:55:39 +0100109 --Level;
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +0200110 if (PrevFID == BuiltinFile)
111 InBuiltinFile = false;
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +0200112 break;
Kirill Bobyrevcd0ca5a2021-11-26 14:12:35 +0100113 }
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +0200114 case PPCallbacks::RenameFile:
115 case PPCallbacks::SystemHeaderPragma:
116 break;
117 }
118 }
119
Eric Liuc5105f92018-02-16 14:15:55 +0000120private:
Kirill Bobyreveecfc732021-12-08 15:55:39 +0100121 // Keeps track of include depth for the current file. It's 1 for main file.
122 int Level = 0;
123 bool inMainFile() const { return Level == 1; }
124
Eric Liu155f5a42018-05-14 12:19:16 +0000125 const SourceManager &SM;
Kadir Cetinkaya6d6d48a2020-05-06 16:20:31 +0200126 // Set after entering the <built-in> file.
127 FileID BuiltinFile;
128 // Indicates whether <built-in> file is part of include stack.
129 bool InBuiltinFile = false;
130
Sam McCall3f0243f2018-07-03 08:09:29 +0000131 IncludeStructure *Out;
Eric Liuc5105f92018-02-16 14:15:55 +0000132};
133
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000134bool isLiteralInclude(llvm::StringRef Include) {
Kazu Hiratad5953e32023-12-13 23:26:09 -0800135 return Include.starts_with("<") || Include.starts_with("\"");
Eric Liu6c8e8582018-02-26 08:32:13 +0000136}
137
138bool HeaderFile::valid() const {
139 return (Verbatim && isLiteralInclude(File)) ||
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000140 (!Verbatim && llvm::sys::path::is_absolute(File));
Eric Liu6c8e8582018-02-26 08:32:13 +0000141}
142
Eric Liudd662772019-01-28 14:01:55 +0000143llvm::Expected<HeaderFile> toHeaderFile(llvm::StringRef Header,
144 llvm::StringRef HintPath) {
145 if (isLiteralInclude(Header))
146 return HeaderFile{Header.str(), /*Verbatim=*/true};
147 auto U = URI::parse(Header);
148 if (!U)
149 return U.takeError();
150
151 auto IncludePath = URI::includeSpelling(*U);
152 if (!IncludePath)
153 return IncludePath.takeError();
154 if (!IncludePath->empty())
155 return HeaderFile{std::move(*IncludePath), /*Verbatim=*/true};
156
157 auto Resolved = URI::resolve(*U, HintPath);
158 if (!Resolved)
159 return Resolved.takeError();
160 return HeaderFile{std::move(*Resolved), /*Verbatim=*/false};
161}
162
David Goldman51f1ae52022-12-02 10:04:31 -0500163llvm::SmallVector<SymbolInclude, 1> getRankedIncludes(const Symbol &Sym) {
Eric Liudd662772019-01-28 14:01:55 +0000164 auto Includes = Sym.IncludeHeaders;
165 // Sort in descending order by reference count and header length.
166 llvm::sort(Includes, [](const Symbol::IncludeHeaderWithReferences &LHS,
167 const Symbol::IncludeHeaderWithReferences &RHS) {
168 if (LHS.References == RHS.References)
169 return LHS.IncludeHeader.size() < RHS.IncludeHeader.size();
170 return LHS.References > RHS.References;
171 });
David Goldman51f1ae52022-12-02 10:04:31 -0500172 llvm::SmallVector<SymbolInclude, 1> Headers;
Eric Liudd662772019-01-28 14:01:55 +0000173 for (const auto &Include : Includes)
David Goldman51f1ae52022-12-02 10:04:31 -0500174 Headers.push_back({Include.IncludeHeader, Include.supportedDirectives()});
Eric Liudd662772019-01-28 14:01:55 +0000175 return Headers;
176}
177
Kirill Bobyreveecfc732021-12-08 15:55:39 +0100178void IncludeStructure::collect(const CompilerInstance &CI) {
Kirill Bobyrevcd0ca5a2021-11-26 14:12:35 +0100179 auto &SM = CI.getSourceManager();
Kirill Bobyrevb06df222021-10-04 08:39:06 +0200180 MainFileEntry = SM.getFileEntryForID(SM.getMainFileID());
Kirill Bobyreveecfc732021-12-08 15:55:39 +0100181 auto Collector = std::make_unique<RecordHeaders>(CI, this);
Kirill Bobyreveecfc732021-12-08 15:55:39 +0100182 CI.getPreprocessor().addPPCallbacks(std::move(Collector));
Sam McCalld97a3412023-07-20 21:46:52 +0200183
184 // If we're reusing a preamble, don't repopulate SearchPathsCanonical.
185 // The entries will be the same, but canonicalizing to find out is expensive!
186 if (SearchPathsCanonical.empty()) {
187 for (const auto &Dir :
188 CI.getPreprocessor().getHeaderSearchInfo().search_dir_range()) {
189 if (Dir.getLookupType() == DirectoryLookup::LT_NormalDir)
190 SearchPathsCanonical.emplace_back(
191 SM.getFileManager().getCanonicalName(*Dir.getDirRef()));
192 }
193 }
Sam McCall3f0243f2018-07-03 08:09:29 +0000194}
195
Kazu Hirataf71ffd32023-01-07 20:19:42 -0800196std::optional<IncludeStructure::HeaderID>
Kirill Bobyrevb06df222021-10-04 08:39:06 +0200197IncludeStructure::getID(const FileEntry *Entry) const {
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200198 // HeaderID of the main file is always 0;
Kirill Bobyrevb06df222021-10-04 08:39:06 +0200199 if (Entry == MainFileEntry) {
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200200 return static_cast<IncludeStructure::HeaderID>(0u);
201 }
202 auto It = UIDToIndex.find(Entry->getUniqueID());
203 if (It == UIDToIndex.end())
Kazu Hirata059a23c2022-12-03 11:54:50 -0800204 return std::nullopt;
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200205 return It->second;
Sam McCall3f0243f2018-07-03 08:09:29 +0000206}
207
Kirill Bobyrev40f361a2022-05-16 10:13:38 +0200208IncludeStructure::HeaderID IncludeStructure::getOrCreateID(FileEntryRef Entry) {
Kirill Bobyrevb06df222021-10-04 08:39:06 +0200209 // Main file's FileEntry was not known at IncludeStructure creation time.
Jan Svobodad79ad2f2022-04-11 12:10:05 +0200210 if (&Entry.getFileEntry() == MainFileEntry) {
Kirill Bobyrevb06df222021-10-04 08:39:06 +0200211 if (RealPathNames.front().empty())
212 RealPathNames.front() = MainFileEntry->tryGetRealPathName().str();
213 return MainFileID;
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200214 }
215 auto R = UIDToIndex.try_emplace(
Jan Svobodad79ad2f2022-04-11 12:10:05 +0200216 Entry.getUniqueID(),
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200217 static_cast<IncludeStructure::HeaderID>(RealPathNames.size()));
Kirill Bobyrev230a6ed2021-09-30 11:36:34 +0200218 if (R.second)
Sam McCall3f0243f2018-07-03 08:09:29 +0000219 RealPathNames.emplace_back();
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200220 IncludeStructure::HeaderID Result = R.first->getSecond();
221 std::string &RealPathName = RealPathNames[static_cast<unsigned>(Result)];
222 if (RealPathName.empty())
Jan Svobodad79ad2f2022-04-11 12:10:05 +0200223 RealPathName = Entry.getFileEntry().tryGetRealPathName().str();
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200224 return Result;
Sam McCall3f0243f2018-07-03 08:09:29 +0000225}
226
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200227llvm::DenseMap<IncludeStructure::HeaderID, unsigned>
228IncludeStructure::includeDepth(HeaderID Root) const {
Sam McCall3f0243f2018-07-03 08:09:29 +0000229 // Include depth 0 is the main file only.
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200230 llvm::DenseMap<HeaderID, unsigned> Result;
231 assert(static_cast<unsigned>(Root) < RealPathNames.size());
Sam McCall3f0243f2018-07-03 08:09:29 +0000232 Result[Root] = 0;
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200233 std::vector<IncludeStructure::HeaderID> CurrentLevel;
234 CurrentLevel.push_back(Root);
235 llvm::DenseSet<IncludeStructure::HeaderID> Seen;
236 Seen.insert(Root);
Sam McCall3f0243f2018-07-03 08:09:29 +0000237
238 // Each round of BFS traversal finds the next depth level.
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200239 std::vector<IncludeStructure::HeaderID> PreviousLevel;
Sam McCall3f0243f2018-07-03 08:09:29 +0000240 for (unsigned Level = 1; !CurrentLevel.empty(); ++Level) {
241 PreviousLevel.clear();
242 PreviousLevel.swap(CurrentLevel);
243 for (const auto &Parent : PreviousLevel) {
244 for (const auto &Child : IncludeChildren.lookup(Parent)) {
245 if (Seen.insert(Child).second) {
246 CurrentLevel.push_back(Child);
Kirill Bobyrevdea48072021-09-30 14:41:27 +0200247 Result[Child] = Level;
Sam McCall3f0243f2018-07-03 08:09:29 +0000248 }
249 }
250 }
251 }
252 return Result;
Eric Liu155f5a42018-05-14 12:19:16 +0000253}
254
Viktoriia Bakalovae028c972023-02-07 16:52:51 +0000255llvm::SmallVector<const Inclusion *>
256IncludeStructure::mainFileIncludesWithSpelling(llvm::StringRef Spelling) const {
257 llvm::SmallVector<const Inclusion *> Includes;
258 for (auto Idx : MainFileIncludesBySpelling.lookup(Spelling))
259 Includes.push_back(&MainFileIncludes[Idx]);
260 return Includes;
261}
262
Eric Liufd9f4262018-09-27 14:27:02 +0000263void IncludeInserter::addExisting(const Inclusion &Inc) {
264 IncludedHeaders.insert(Inc.Written);
265 if (!Inc.Resolved.empty())
266 IncludedHeaders.insert(Inc.Resolved);
267}
268
Eric Liuc5105f92018-02-16 14:15:55 +0000269/// FIXME(ioeric): we might not want to insert an absolute include path if the
270/// path is not shortened.
Eric Liu8f3678d2018-06-15 13:34:18 +0000271bool IncludeInserter::shouldInsertInclude(
Eric Liu417c8892019-04-16 14:35:49 +0000272 PathRef DeclaringHeader, const HeaderFile &InsertedHeader) const {
273 assert(InsertedHeader.valid());
Eric Liu00d99bd2019-04-11 09:36:36 +0000274 if (!HeaderSearchInfo && !InsertedHeader.Verbatim)
275 return false;
Eric Liu417c8892019-04-16 14:35:49 +0000276 if (FileName == DeclaringHeader || FileName == InsertedHeader.File)
Eric Liu8f3678d2018-06-15 13:34:18 +0000277 return false;
Ilya Biryukovf2001aa2019-01-07 15:45:19 +0000278 auto Included = [&](llvm::StringRef Header) {
Kazu Hirata15aa9652023-03-14 21:30:29 -0700279 return IncludedHeaders.contains(Header);
Eric Liu6c8e8582018-02-26 08:32:13 +0000280 };
Eric Liu417c8892019-04-16 14:35:49 +0000281 return !Included(DeclaringHeader) && !Included(InsertedHeader.File);
Eric Liu8f3678d2018-06-15 13:34:18 +0000282}
Eric Liuc5105f92018-02-16 14:15:55 +0000283
Kazu Hirataf71ffd32023-01-07 20:19:42 -0800284std::optional<std::string>
Kadir Cetinkaya1f6d9842019-07-03 07:47:19 +0000285IncludeInserter::calculateIncludePath(const HeaderFile &InsertedHeader,
286 llvm::StringRef IncludingFile) const {
Eric Liu417c8892019-04-16 14:35:49 +0000287 assert(InsertedHeader.valid());
Eric Liu6c8e8582018-02-26 08:32:13 +0000288 if (InsertedHeader.Verbatim)
289 return InsertedHeader.File;
kleines Filmröllchen1f907972024-12-27 20:14:29 +0100290 bool IsAngledByDefault = false;
Sam McCallb324c642019-07-08 18:07:46 +0000291 std::string Suggested;
292 if (HeaderSearchInfo) {
293 Suggested = HeaderSearchInfo->suggestPathToFileForDiagnostics(
kleines Filmröllchen1f907972024-12-27 20:14:29 +0100294 InsertedHeader.File, BuildDir, IncludingFile, &IsAngledByDefault);
Sam McCallb324c642019-07-08 18:07:46 +0000295 } else {
296 // Calculate include relative to including file only.
297 StringRef IncludingDir = llvm::sys::path::parent_path(IncludingFile);
298 SmallString<256> RelFile(InsertedHeader.File);
299 // Replacing with "" leaves "/RelFile" if IncludingDir doesn't end in "/".
300 llvm::sys::path::replace_path_prefix(RelFile, IncludingDir, "./");
301 Suggested = llvm::sys::path::convert_to_slash(
302 llvm::sys::path::remove_leading_dotslash(RelFile));
303 }
304 // FIXME: should we allow (some limited number of) "../header.h"?
305 if (llvm::sys::path::is_absolute(Suggested))
Kazu Hirata059a23c2022-12-03 11:54:50 -0800306 return std::nullopt;
kleines Filmröllchen1f907972024-12-27 20:14:29 +0100307 bool IsAngled = false;
308 for (auto Filter : AngledHeaders) {
309 if (Filter(Suggested)) {
310 IsAngled = true;
311 break;
312 }
313 }
314 bool IsQuoted = false;
315 for (auto Filter : QuotedHeaders) {
316 if (Filter(Suggested)) {
317 IsQuoted = true;
318 break;
319 }
320 }
321 // No filters apply, or both filters apply (a bug), use system default.
322 if (IsAngled == IsQuoted) {
323 // Probably a bug in the config regex.
324 if (IsAngled && IsQuoted) {
325 elog("Header '{0}' matches both quoted and angled regexes, default will "
326 "be used.",
327 Suggested);
328 }
329 IsAngled = IsAngledByDefault;
330 }
David Goldman9fe632b2023-07-31 11:36:22 -0400331 if (IsAngled)
Eric Liuc5105f92018-02-16 14:15:55 +0000332 Suggested = "<" + Suggested + ">";
kleines Filmröllchen1f907972024-12-27 20:14:29 +0100333 else // if (IsQuoted)
Eric Liuc5105f92018-02-16 14:15:55 +0000334 Suggested = "\"" + Suggested + "\"";
Eric Liuc5105f92018-02-16 14:15:55 +0000335 return Suggested;
336}
337
Kazu Hirataf71ffd32023-01-07 20:19:42 -0800338std::optional<TextEdit>
David Goldmanfc46d6e2022-12-02 10:04:51 -0500339IncludeInserter::insert(llvm::StringRef VerbatimHeader,
340 tooling::IncludeDirective Directive) const {
Kazu Hirataf71ffd32023-01-07 20:19:42 -0800341 std::optional<TextEdit> Edit;
David Goldmanfc46d6e2022-12-02 10:04:51 -0500342 if (auto Insertion =
343 Inserter.insert(VerbatimHeader.trim("\"<>"),
Kazu Hiratad5953e32023-12-13 23:26:09 -0800344 VerbatimHeader.starts_with("<"), Directive))
Eric Liu8f3678d2018-06-15 13:34:18 +0000345 Edit = replacementToEdit(Code, *Insertion);
346 return Edit;
Eric Liu63f419a2018-05-15 15:29:32 +0000347}
348
Sam McCall991e3162018-11-20 10:58:48 +0000349llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Inclusion &Inc) {
350 return OS << Inc.Written << " = "
Kadir Cetinkayad8700162020-05-04 10:48:19 +0200351 << (!Inc.Resolved.empty() ? Inc.Resolved : "[unresolved]")
352 << " at line" << Inc.HashLine;
Sam McCall991e3162018-11-20 10:58:48 +0000353}
354
Kadir Cetinkaya717bef62020-04-23 17:44:51 +0200355bool operator==(const Inclusion &LHS, const Inclusion &RHS) {
356 return std::tie(LHS.Directive, LHS.FileKind, LHS.HashOffset, LHS.HashLine,
357 LHS.Resolved, LHS.Written) ==
358 std::tie(RHS.Directive, RHS.FileKind, RHS.HashOffset, RHS.HashLine,
359 RHS.Resolved, RHS.Written);
360}
Sam McCall478863e2021-11-17 13:27:58 +0100361
Eric Liuc5105f92018-02-16 14:15:55 +0000362} // namespace clangd
363} // namespace clang