clang 22.0.0git
FileList.cpp
Go to the documentation of this file.
1//===- FileList.cpp ---------------------------------------------*- C++ -*-===//
2//
3// 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
6//
7//===----------------------------------------------------------------------===//
8
10#include "llvm/ADT/StringSwitch.h"
11#include "llvm/Support/Error.h"
12#include "llvm/Support/JSON.h"
13#include "llvm/TextAPI/TextAPIError.h"
14#include <optional>
15
16// clang-format off
17/*
18InstallAPI JSON Input Format specification.
19
20{
21 "headers" : [ # Required: Key must exist.
22 { # Optional: May contain 0 or more header inputs.
23 "path" : "/usr/include/mach-o/dlfn.h", # Required: Path should point to destination
24 # location where applicable.
25 "type" : "public", # Required: Maps to HeaderType for header.
26 "language": "c++" # Optional: Language mode for header.
27 }
28 ],
29 "version" : "3" # Required: Version 3 supports language mode
30 & project header input.
31}
32*/
33// clang-format on
34
35using namespace llvm;
36using namespace llvm::json;
37using namespace llvm::MachO;
38using namespace clang::installapi;
39
40namespace {
41class Implementation {
42private:
43 Expected<StringRef> parseString(const Object *Obj, StringRef Key,
44 StringRef Error);
45 Expected<StringRef> parsePath(const Object *Obj);
46 Expected<HeaderType> parseType(const Object *Obj);
47 std::optional<clang::Language> parseLanguage(const Object *Obj);
48 Error parseHeaders(Array &Headers);
49
50public:
51 std::unique_ptr<MemoryBuffer> InputBuffer;
52 clang::FileManager *FM;
53 unsigned Version;
54 HeaderSeq HeaderList;
55
56 Error parse(StringRef Input);
57};
58
60Implementation::parseString(const Object *Obj, StringRef Key, StringRef Error) {
61 auto Str = Obj->getString(Key);
62 if (!Str)
63 return make_error<StringError>(Error, inconvertibleErrorCode());
64 return *Str;
65}
66
67Expected<HeaderType> Implementation::parseType(const Object *Obj) {
68 auto TypeStr =
69 parseString(Obj, "type", "required field 'type' not specified");
70 if (!TypeStr)
71 return TypeStr.takeError();
72
73 if (*TypeStr == "public")
74 return HeaderType::Public;
75 else if (*TypeStr == "private")
76 return HeaderType::Private;
77 else if (*TypeStr == "project" && Version >= 2)
78 return HeaderType::Project;
79
80 return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat,
81 "unsupported header type");
82}
83
84Expected<StringRef> Implementation::parsePath(const Object *Obj) {
85 auto Path = parseString(Obj, "path", "required field 'path' not specified");
86 if (!Path)
87 return Path.takeError();
88
89 return *Path;
90}
91
92std::optional<clang::Language>
93Implementation::parseLanguage(const Object *Obj) {
94 auto Language = Obj->getString("language");
95 if (!Language)
96 return std::nullopt;
97
98 return StringSwitch<clang::Language>(*Language)
99 .Case("c", clang::Language::C)
100 .Case("c++", clang::Language::CXX)
101 .Case("objective-c", clang::Language::ObjC)
102 .Case("objective-c++", clang::Language::ObjCXX)
103 .Default(clang::Language::Unknown);
104}
105
106Error Implementation::parseHeaders(Array &Headers) {
107 for (const auto &H : Headers) {
108 auto *Obj = H.getAsObject();
109 if (!Obj)
110 return make_error<StringError>("expect a JSON object",
111 inconvertibleErrorCode());
112 auto Type = parseType(Obj);
113 if (!Type)
114 return Type.takeError();
115 auto Path = parsePath(Obj);
116 if (!Path)
117 return Path.takeError();
118 auto Language = parseLanguage(Obj);
119
120 StringRef PathStr = *Path;
121 if (*Type == HeaderType::Project) {
122 HeaderList.emplace_back(
123 HeaderFile{PathStr, *Type, /*IncludeName=*/"", Language});
124 continue;
125 }
126
127 if (FM)
128 if (!FM->getOptionalFileRef(PathStr))
129 return createFileError(
130 PathStr, make_error_code(std::errc::no_such_file_or_directory));
131
132 auto IncludeName = createIncludeHeaderName(PathStr);
133 HeaderList.emplace_back(PathStr, *Type,
134 IncludeName.has_value() ? IncludeName.value() : "",
135 Language);
136 }
137
138 return Error::success();
139}
140
141Error Implementation::parse(StringRef Input) {
142 auto Val = json::parse(Input);
143 if (!Val)
144 return Val.takeError();
145
146 auto *Root = Val->getAsObject();
147 if (!Root)
148 return make_error<StringError>("not a JSON object",
149 inconvertibleErrorCode());
150
151 auto VersionStr = Root->getString("version");
152 if (!VersionStr)
153 return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat,
154 "required field 'version' not specified");
155 if (VersionStr->getAsInteger(10, Version))
156 return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat,
157 "invalid version number");
158
159 if (Version < 1 || Version > 3)
160 return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat,
161 "unsupported version");
162
163 // Not specifying any header files should be atypical, but valid.
164 auto Headers = Root->getArray("headers");
165 if (!Headers)
166 return Error::success();
167
168 Error Err = parseHeaders(*Headers);
169 if (Err)
170 return Err;
171
172 return Error::success();
173}
174} // namespace
175
176llvm::Error
177FileListReader::loadHeaders(std::unique_ptr<MemoryBuffer> InputBuffer,
178 HeaderSeq &Destination, clang::FileManager *FM) {
179 Implementation Impl;
180 Impl.InputBuffer = std::move(InputBuffer);
181 Impl.FM = FM;
182
183 if (llvm::Error Err = Impl.parse(Impl.InputBuffer->getBuffer()))
184 return Err;
185
186 Destination.reserve(Destination.size() + Impl.HeaderList.size());
187 llvm::move(Impl.HeaderList, std::back_inserter(Destination));
188
189 return Error::success();
190}
Implements support for file system lookup, file system caching, and directory search management.
Definition FileManager.h:53
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Get a FileEntryRef if it exists, without doing anything on error.
static llvm::Error loadHeaders(std::unique_ptr< llvm::MemoryBuffer > InputBuffer, HeaderSeq &Destination, clang::FileManager *FM=nullptr)
Decode JSON input and append header input into destination container.
Definition FileList.cpp:177
std::error_code make_error_code(ParseError e)
Definition Format.cpp:1382
The DirectoryScanner for collecting library files on the file system.
Definition Context.h:20
std::optional< std::string > createIncludeHeaderName(const StringRef FullPath)
Assemble expected way header will be included by clients.
std::vector< HeaderFile > HeaderSeq
Definition HeaderFile.h:150
Language
The language for the input, used to select and validate the language standard and possible actions.
@ C
Languages that the frontend can parse and compile.
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30