/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Basic/DarwinSDKInfo.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- DarwinSDKInfo.cpp - SDK Information parser for darwin - ----------===// |
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 | | |
9 | | #include "clang/Basic/DarwinSDKInfo.h" |
10 | | #include "llvm/Support/ErrorOr.h" |
11 | | #include "llvm/Support/JSON.h" |
12 | | #include "llvm/Support/MemoryBuffer.h" |
13 | | #include "llvm/Support/Path.h" |
14 | | |
15 | | using namespace clang; |
16 | | |
17 | | Optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map( |
18 | | const VersionTuple &Key, const VersionTuple &MinimumValue, |
19 | 124 | Optional<VersionTuple> MaximumValue) const { |
20 | 124 | if (Key < MinimumKeyVersion) |
21 | 37 | return MinimumValue; |
22 | 87 | if (Key > MaximumKeyVersion) |
23 | 12 | return MaximumValue; |
24 | 75 | auto KV = Mapping.find(Key.normalize()); |
25 | 75 | if (KV != Mapping.end()) |
26 | 71 | return KV->getSecond(); |
27 | | // If no exact entry found, try just the major key version. Only do so when |
28 | | // a minor version number is present, to avoid recursing indefinitely into |
29 | | // the major-only check. |
30 | 4 | if (Key.getMinor()) |
31 | 3 | return map(VersionTuple(Key.getMajor()), MinimumValue, MaximumValue); |
32 | | // If this a major only key, return None for a missing entry. |
33 | 1 | return None; |
34 | 4 | } |
35 | | |
36 | | Optional<DarwinSDKInfo::RelatedTargetVersionMapping> |
37 | | DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON( |
38 | 19.7k | const llvm::json::Object &Obj, VersionTuple MaximumDeploymentTarget) { |
39 | 19.7k | VersionTuple Min = VersionTuple(std::numeric_limits<unsigned>::max()); |
40 | 19.7k | VersionTuple Max = VersionTuple(0); |
41 | 19.7k | VersionTuple MinValue = Min; |
42 | 19.7k | llvm::DenseMap<VersionTuple, VersionTuple> Mapping; |
43 | 98.6k | for (const auto &KV : Obj) { |
44 | 98.6k | if (auto Val98.6k = KV.getSecond().getAsString()) { |
45 | 98.6k | llvm::VersionTuple KeyVersion; |
46 | 98.6k | llvm::VersionTuple ValueVersion; |
47 | 98.6k | if (KeyVersion.tryParse(KV.getFirst())98.6k || ValueVersion.tryParse(*Val)) |
48 | 1 | return None; |
49 | 98.6k | Mapping[KeyVersion.normalize()] = ValueVersion; |
50 | 98.6k | if (KeyVersion < Min) |
51 | 78.9k | Min = KeyVersion; |
52 | 98.6k | if (KeyVersion > Max) |
53 | 29.6k | Max = KeyVersion; |
54 | 98.6k | if (ValueVersion < MinValue) |
55 | 78.9k | MinValue = ValueVersion; |
56 | 98.6k | } |
57 | 98.6k | } |
58 | 19.7k | if (Mapping.empty()) |
59 | 1 | return None; |
60 | 19.7k | return RelatedTargetVersionMapping( |
61 | 19.7k | Min, Max, MinValue, MaximumDeploymentTarget, std::move(Mapping)); |
62 | 19.7k | } |
63 | | |
64 | | static Optional<VersionTuple> getVersionKey(const llvm::json::Object &Obj, |
65 | 19.8k | StringRef Key) { |
66 | 19.8k | auto Value = Obj.getString(Key); |
67 | 19.8k | if (!Value) |
68 | 3 | return None; |
69 | 19.8k | VersionTuple Version; |
70 | 19.8k | if (Version.tryParse(*Value)) |
71 | 0 | return None; |
72 | 19.8k | return Version; |
73 | 19.8k | } |
74 | | |
75 | | Optional<DarwinSDKInfo> |
76 | 9.90k | DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) { |
77 | 9.90k | auto Version = getVersionKey(*Obj, "Version"); |
78 | 9.90k | if (!Version) |
79 | 2 | return None; |
80 | 9.90k | auto MaximumDeploymentVersion = |
81 | 9.90k | getVersionKey(*Obj, "MaximumDeploymentTarget"); |
82 | 9.90k | if (!MaximumDeploymentVersion) |
83 | 1 | return None; |
84 | 9.90k | llvm::DenseMap<OSEnvPair::StorageType, Optional<RelatedTargetVersionMapping>> |
85 | 9.90k | VersionMappings; |
86 | 9.90k | if (const auto *VM = Obj->getObject("VersionMap")) { |
87 | | // FIXME: Generalize this out beyond iOS-deriving targets. |
88 | | // Look for ios_<targetos> version mapping for targets that derive from ios. |
89 | 19.7k | for (const auto &KV : *VM) { |
90 | 19.7k | auto Pair = StringRef(KV.getFirst()).split("_"); |
91 | 19.7k | if (Pair.first.compare_insensitive("ios") == 0) { |
92 | 3 | llvm::Triple TT(llvm::Twine("--") + Pair.second.lower()); |
93 | 3 | if (TT.getOS() != llvm::Triple::UnknownOS) { |
94 | 3 | auto Mapping = RelatedTargetVersionMapping::parseJSON( |
95 | 3 | *KV.getSecond().getAsObject(), *MaximumDeploymentVersion); |
96 | 3 | if (Mapping) |
97 | 3 | VersionMappings[OSEnvPair(llvm::Triple::IOS, |
98 | 3 | llvm::Triple::UnknownEnvironment, |
99 | 3 | TT.getOS(), |
100 | 3 | llvm::Triple::UnknownEnvironment) |
101 | 3 | .Value] = std::move(Mapping); |
102 | 3 | } |
103 | 3 | } |
104 | 19.7k | } |
105 | | |
106 | 9.87k | if (const auto *Mapping = VM->getObject("macOS_iOSMac")) { |
107 | 9.87k | auto VersionMap = RelatedTargetVersionMapping::parseJSON( |
108 | 9.87k | *Mapping, *MaximumDeploymentVersion); |
109 | 9.87k | if (!VersionMap) |
110 | 0 | return None; |
111 | 9.87k | VersionMappings[OSEnvPair::macOStoMacCatalystPair().Value] = |
112 | 9.87k | std::move(VersionMap); |
113 | 9.87k | } |
114 | 9.87k | if (const auto *Mapping = VM->getObject("iOSMac_macOS")) { |
115 | 9.87k | auto VersionMap = RelatedTargetVersionMapping::parseJSON( |
116 | 9.87k | *Mapping, *MaximumDeploymentVersion); |
117 | 9.87k | if (!VersionMap) |
118 | 0 | return None; |
119 | 9.87k | VersionMappings[OSEnvPair::macCatalystToMacOSPair().Value] = |
120 | 9.87k | std::move(VersionMap); |
121 | 9.87k | } |
122 | 9.87k | } |
123 | | |
124 | 9.90k | return DarwinSDKInfo(std::move(*Version), |
125 | 9.90k | std::move(*MaximumDeploymentVersion), |
126 | 9.90k | std::move(VersionMappings)); |
127 | 9.90k | } |
128 | | |
129 | | Expected<Optional<DarwinSDKInfo>> |
130 | 10.0k | clang::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) { |
131 | 10.0k | llvm::SmallString<256> Filepath = SDKRootPath; |
132 | 10.0k | llvm::sys::path::append(Filepath, "SDKSettings.json"); |
133 | 10.0k | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = |
134 | 10.0k | VFS.getBufferForFile(Filepath); |
135 | 10.0k | if (!File) { |
136 | | // If the file couldn't be read, assume it just doesn't exist. |
137 | 109 | return None; |
138 | 109 | } |
139 | 9.90k | Expected<llvm::json::Value> Result = |
140 | 9.90k | llvm::json::parse(File.get()->getBuffer()); |
141 | 9.90k | if (!Result) |
142 | 1 | return Result.takeError(); |
143 | | |
144 | 9.90k | if (const auto *9.90k Obj9.90k = Result->getAsObject()) { |
145 | 9.90k | if (auto SDKInfo = DarwinSDKInfo::parseDarwinSDKSettingsJSON(Obj)) |
146 | 9.90k | return std::move(SDKInfo); |
147 | 9.90k | } |
148 | 0 | return llvm::make_error<llvm::StringError>("invalid SDKSettings.json", |
149 | 0 | llvm::inconvertibleErrorCode()); |
150 | 9.90k | } |