|
12 | 12 | #include "clang/Driver/Driver.h"
|
13 | 13 | #include "llvm/ADT/DenseSet.h"
|
14 | 14 | #include "llvm/ADT/SmallSet.h"
|
| 15 | +#include "llvm/ADT/SmallString.h" |
15 | 16 | #include "llvm/ADT/StringRef.h"
|
16 | 17 | #include "llvm/Support/Compiler.h"
|
17 | 18 | #include "llvm/Support/Error.h"
|
@@ -95,9 +96,113 @@ MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
|
95 | 96 |
|
96 | 97 | void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
|
97 | 98 |
|
| 99 | +static void WarnUnclaimedMultilibCustomFlags( |
| 100 | + const Driver &D, const SmallVector<StringRef> &UnclaimedCustomFlagValues, |
| 101 | + const SmallVector<custom_flag::CustomFlagDeclarationPtr> &CustomFlagDecls) { |
| 102 | + struct EditDistanceInfo { |
| 103 | + StringRef FlagValue; |
| 104 | + unsigned EditDistance; |
| 105 | + }; |
| 106 | + const unsigned MaxEditDistance = 5; |
| 107 | + |
| 108 | + for (StringRef Unclaimed : UnclaimedCustomFlagValues) { |
| 109 | + std::optional<EditDistanceInfo> BestCandidate; |
| 110 | + for (const auto &Decl : CustomFlagDecls) { |
| 111 | + for (const auto &Value : Decl->ValueList) { |
| 112 | + const std::string &FlagValueName = Value.Name; |
| 113 | + unsigned EditDistance = |
| 114 | + Unclaimed.edit_distance(FlagValueName, /*AllowReplacements=*/true, |
| 115 | + /*MaxEditDistance=*/MaxEditDistance); |
| 116 | + if (!BestCandidate || (EditDistance <= MaxEditDistance && |
| 117 | + EditDistance < BestCandidate->EditDistance)) { |
| 118 | + BestCandidate = {FlagValueName, EditDistance}; |
| 119 | + } |
| 120 | + } |
| 121 | + } |
| 122 | + if (!BestCandidate) |
| 123 | + D.Diag(clang::diag::warn_drv_unsupported_opt) |
| 124 | + << (custom_flag::Prefix + Unclaimed).str(); |
| 125 | + else |
| 126 | + D.Diag(clang::diag::warn_drv_unsupported_opt_with_suggestion) |
| 127 | + << (custom_flag::Prefix + Unclaimed).str() |
| 128 | + << (custom_flag::Prefix + BestCandidate->FlagValue).str(); |
| 129 | + } |
| 130 | +} |
| 131 | + |
| 132 | +namespace clang::driver::custom_flag { |
| 133 | +class ValueNameToDetailMap { |
| 134 | + SmallVector<std::pair<StringRef, const CustomFlagValueDetail *>> Mapping; |
| 135 | + |
| 136 | +public: |
| 137 | + template <typename It> |
| 138 | + ValueNameToDetailMap(It FlagDeclsBegin, It FlagDeclsEnd) { |
| 139 | + for (auto DeclIt = FlagDeclsBegin; DeclIt != FlagDeclsEnd; ++DeclIt) { |
| 140 | + const CustomFlagDeclarationPtr &Decl = *DeclIt; |
| 141 | + for (const auto &Value : Decl->ValueList) |
| 142 | + Mapping.emplace_back(Value.Name, &Value); |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + const CustomFlagValueDetail *get(StringRef Key) const { |
| 147 | + auto Iter = llvm::find_if( |
| 148 | + Mapping, [&](const auto &Pair) { return Pair.first == Key; }); |
| 149 | + return Iter != Mapping.end() ? Iter->second : nullptr; |
| 150 | + } |
| 151 | +}; |
| 152 | +} // namespace clang::driver::custom_flag |
| 153 | + |
| 154 | +Multilib::flags_list |
| 155 | +MultilibSet::processCustomFlags(const Driver &D, |
| 156 | + const Multilib::flags_list &Flags) const { |
| 157 | + Multilib::flags_list Result; |
| 158 | + SmallVector<const custom_flag::CustomFlagValueDetail *> |
| 159 | + ClaimedCustomFlagValues; |
| 160 | + SmallVector<StringRef> UnclaimedCustomFlagValueStrs; |
| 161 | + |
| 162 | + const auto ValueNameToValueDetail = custom_flag::ValueNameToDetailMap( |
| 163 | + CustomFlagDecls.begin(), CustomFlagDecls.end()); |
| 164 | + |
| 165 | + for (StringRef Flag : Flags) { |
| 166 | + if (!Flag.starts_with(custom_flag::Prefix)) { |
| 167 | + Result.push_back(Flag.str()); |
| 168 | + continue; |
| 169 | + } |
| 170 | + |
| 171 | + StringRef CustomFlagValueStr = Flag.substr(custom_flag::Prefix.size()); |
| 172 | + const custom_flag::CustomFlagValueDetail *Detail = |
| 173 | + ValueNameToValueDetail.get(CustomFlagValueStr); |
| 174 | + if (Detail) |
| 175 | + ClaimedCustomFlagValues.push_back(Detail); |
| 176 | + else |
| 177 | + UnclaimedCustomFlagValueStrs.push_back(CustomFlagValueStr); |
| 178 | + } |
| 179 | + |
| 180 | + llvm::SmallSet<custom_flag::CustomFlagDeclarationPtr, 32> |
| 181 | + TriggeredCustomFlagDecls; |
| 182 | + |
| 183 | + for (auto *CustomFlagValue : llvm::reverse(ClaimedCustomFlagValues)) { |
| 184 | + if (!TriggeredCustomFlagDecls.insert(CustomFlagValue->Decl).second) |
| 185 | + continue; |
| 186 | + Result.push_back(std::string(custom_flag::Prefix) + CustomFlagValue->Name); |
| 187 | + } |
| 188 | + |
| 189 | + for (const auto &Decl : CustomFlagDecls) { |
| 190 | + if (TriggeredCustomFlagDecls.contains(Decl)) |
| 191 | + continue; |
| 192 | + Result.push_back(std::string(custom_flag::Prefix) + |
| 193 | + Decl->ValueList[Decl->DefaultValueIdx].Name); |
| 194 | + } |
| 195 | + |
| 196 | + WarnUnclaimedMultilibCustomFlags(D, UnclaimedCustomFlagValueStrs, |
| 197 | + CustomFlagDecls); |
| 198 | + |
| 199 | + return Result; |
| 200 | +} |
| 201 | + |
98 | 202 | bool MultilibSet::select(const Driver &D, const Multilib::flags_list &Flags,
|
99 | 203 | llvm::SmallVectorImpl<Multilib> &Selected) const {
|
100 |
| - llvm::StringSet<> FlagSet(expandFlags(Flags)); |
| 204 | + Multilib::flags_list FlagsWithCustom = processCustomFlags(D, Flags); |
| 205 | + llvm::StringSet<> FlagSet(expandFlags(FlagsWithCustom)); |
101 | 206 | Selected.clear();
|
102 | 207 | bool AnyErrors = false;
|
103 | 208 |
|
@@ -387,8 +492,34 @@ LLVM_DUMP_METHOD void MultilibSet::dump() const {
|
387 | 492 | }
|
388 | 493 |
|
389 | 494 | void MultilibSet::print(raw_ostream &OS) const {
|
390 |
| - for (const auto &M : *this) |
391 |
| - OS << M << "\n"; |
| 495 | + const auto ValueNameToValueDetail = custom_flag::ValueNameToDetailMap( |
| 496 | + CustomFlagDecls.begin(), CustomFlagDecls.end()); |
| 497 | + |
| 498 | + for (const auto &M : *this) { |
| 499 | + if (M.isError()) |
| 500 | + continue; |
| 501 | + llvm::SmallString<128> Buf; |
| 502 | + llvm::raw_svector_ostream StrOS(Buf); |
| 503 | + |
| 504 | + M.print(StrOS); |
| 505 | + |
| 506 | + for (StringRef Flag : M.flags()) { |
| 507 | + if (!Flag.starts_with(custom_flag::Prefix)) |
| 508 | + continue; |
| 509 | + |
| 510 | + StringRef CustomFlagValueStr = Flag.substr(custom_flag::Prefix.size()); |
| 511 | + const custom_flag::CustomFlagValueDetail *Detail = |
| 512 | + ValueNameToValueDetail.get(CustomFlagValueStr); |
| 513 | + |
| 514 | + if (!Detail || !Detail->ExtraBuildArgs) |
| 515 | + continue; |
| 516 | + |
| 517 | + for (StringRef Arg : *Detail->ExtraBuildArgs) |
| 518 | + StrOS << '@' << (Arg[0] == '-' ? Arg.substr(1) : Arg); |
| 519 | + } |
| 520 | + |
| 521 | + OS << StrOS.str() << '\n'; |
| 522 | + } |
392 | 523 | }
|
393 | 524 |
|
394 | 525 | raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) {
|
|
0 commit comments