diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Option/Option.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Option/Option.cpp | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Option/Option.cpp b/contrib/llvm-project/llvm/lib/Option/Option.cpp new file mode 100644 index 000000000000..9abc9fdce4c7 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Option/Option.cpp @@ -0,0 +1,290 @@ +//===- Option.cpp - Abstract Driver Options -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cstring> + +using namespace llvm; +using namespace llvm::opt; + +Option::Option(const OptTable::Info *info, const OptTable *owner) + : Info(info), Owner(owner) { + // Multi-level aliases are not supported. This just simplifies option + // tracking, it is not an inherent limitation. + assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) && + "Multi-level aliases are not supported."); + + if (Info && getAliasArgs()) { + assert(getAlias().isValid() && "Only alias options can have alias args."); + assert(getKind() == FlagClass && "Only Flag aliases can have alias args."); + assert(getAlias().getKind() != FlagClass && + "Cannot provide alias args to a flag option."); + } +} + +void Option::print(raw_ostream &O) const { + O << "<"; + switch (getKind()) { +#define P(N) case N: O << #N; break + P(GroupClass); + P(InputClass); + P(UnknownClass); + P(FlagClass); + P(JoinedClass); + P(ValuesClass); + P(SeparateClass); + P(CommaJoinedClass); + P(MultiArgClass); + P(JoinedOrSeparateClass); + P(JoinedAndSeparateClass); + P(RemainingArgsClass); + P(RemainingArgsJoinedClass); +#undef P + } + + if (Info->Prefixes) { + O << " Prefixes:["; + for (const char *const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre) { + O << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", "); + } + O << ']'; + } + + O << " Name:\"" << getName() << '"'; + + const Option Group = getGroup(); + if (Group.isValid()) { + O << " Group:"; + Group.print(O); + } + + const Option Alias = getAlias(); + if (Alias.isValid()) { + O << " Alias:"; + Alias.print(O); + } + + if (getKind() == MultiArgClass) + O << " NumArgs:" << getNumArgs(); + + O << ">\n"; +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void Option::dump() const { print(dbgs()); } +#endif + +bool Option::matches(OptSpecifier Opt) const { + // Aliases are never considered in matching, look through them. + const Option Alias = getAlias(); + if (Alias.isValid()) + return Alias.matches(Opt); + + // Check exact match. + if (getID() == Opt.getID()) + return true; + + const Option Group = getGroup(); + if (Group.isValid()) + return Group.matches(Opt); + return false; +} + +Arg *Option::acceptInternal(const ArgList &Args, unsigned &Index, + unsigned ArgSize) const { + StringRef Spelling = StringRef(Args.getArgString(Index), ArgSize); + switch (getKind()) { + case FlagClass: { + if (ArgSize != strlen(Args.getArgString(Index))) + return nullptr; + return new Arg(*this, Spelling, Index++); + } + case JoinedClass: { + const char *Value = Args.getArgString(Index) + ArgSize; + return new Arg(*this, Spelling, Index++, Value); + } + case CommaJoinedClass: { + // Always matches. + const char *Str = Args.getArgString(Index) + ArgSize; + Arg *A = new Arg(*this, Spelling, Index++); + + // Parse out the comma separated values. + const char *Prev = Str; + for (;; ++Str) { + char c = *Str; + + if (!c || c == ',') { + if (Prev != Str) { + char *Value = new char[Str - Prev + 1]; + memcpy(Value, Prev, Str - Prev); + Value[Str - Prev] = '\0'; + A->getValues().push_back(Value); + } + + if (!c) + break; + + Prev = Str + 1; + } + } + A->setOwnsValues(true); + + return A; + } + case SeparateClass: + // Matches iff this is an exact match. + // FIXME: Avoid strlen. + if (ArgSize != strlen(Args.getArgString(Index))) + return nullptr; + + Index += 2; + if (Index > Args.getNumInputArgStrings() || + Args.getArgString(Index - 1) == nullptr) + return nullptr; + + return new Arg(*this, Spelling, Index - 2, Args.getArgString(Index - 1)); + case MultiArgClass: { + // Matches iff this is an exact match. + // FIXME: Avoid strlen. + if (ArgSize != strlen(Args.getArgString(Index))) + return nullptr; + + Index += 1 + getNumArgs(); + if (Index > Args.getNumInputArgStrings()) + return nullptr; + + Arg *A = new Arg(*this, Spelling, Index - 1 - getNumArgs(), + Args.getArgString(Index - getNumArgs())); + for (unsigned i = 1; i != getNumArgs(); ++i) + A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i)); + return A; + } + case JoinedOrSeparateClass: { + // If this is not an exact match, it is a joined arg. + // FIXME: Avoid strlen. + if (ArgSize != strlen(Args.getArgString(Index))) { + const char *Value = Args.getArgString(Index) + ArgSize; + return new Arg(*this, Spelling, Index++, Value); + } + + // Otherwise it must be separate. + Index += 2; + if (Index > Args.getNumInputArgStrings() || + Args.getArgString(Index - 1) == nullptr) + return nullptr; + + return new Arg(*this, Spelling, Index - 2, Args.getArgString(Index - 1)); + } + case JoinedAndSeparateClass: + // Always matches. + Index += 2; + if (Index > Args.getNumInputArgStrings() || + Args.getArgString(Index - 1) == nullptr) + return nullptr; + + return new Arg(*this, Spelling, Index - 2, + Args.getArgString(Index - 2) + ArgSize, + Args.getArgString(Index - 1)); + case RemainingArgsClass: { + // Matches iff this is an exact match. + // FIXME: Avoid strlen. + if (ArgSize != strlen(Args.getArgString(Index))) + return nullptr; + Arg *A = new Arg(*this, Spelling, Index++); + while (Index < Args.getNumInputArgStrings() && + Args.getArgString(Index) != nullptr) + A->getValues().push_back(Args.getArgString(Index++)); + return A; + } + case RemainingArgsJoinedClass: { + Arg *A = new Arg(*this, Spelling, Index); + if (ArgSize != strlen(Args.getArgString(Index))) { + // An inexact match means there is a joined arg. + A->getValues().push_back(Args.getArgString(Index) + ArgSize); + } + Index++; + while (Index < Args.getNumInputArgStrings() && + Args.getArgString(Index) != nullptr) + A->getValues().push_back(Args.getArgString(Index++)); + return A; + } + + default: + llvm_unreachable("Invalid option kind!"); + } +} + +Arg *Option::accept(const ArgList &Args, + unsigned &Index, + unsigned ArgSize) const { + std::unique_ptr<Arg> A(acceptInternal(Args, Index, ArgSize)); + if (!A) + return nullptr; + + const Option &UnaliasedOption = getUnaliasedOption(); + if (getID() == UnaliasedOption.getID()) + return A.release(); + + // "A" is an alias for a different flag. For most clients it's more convenient + // if this function returns unaliased Args, so create an unaliased arg for + // returning. + + // This creates a completely new Arg object for the unaliased Arg because + // the alias and the unaliased arg can have different Kinds and different + // Values (due to AliasArgs<>). + + // Get the spelling from the unaliased option. + StringRef UnaliasedSpelling = Args.MakeArgString( + Twine(UnaliasedOption.getPrefix()) + Twine(UnaliasedOption.getName())); + + // It's a bit weird that aliased and unaliased arg share one index, but + // the index is mostly use as a memory optimization in render(). + // Due to this, ArgList::getArgString(A->getIndex()) will return the spelling + // of the aliased arg always, while A->getSpelling() returns either the + // unaliased or the aliased arg, depending on which Arg object it's called on. + Arg *UnaliasedA = new Arg(UnaliasedOption, UnaliasedSpelling, A->getIndex()); + Arg *RawA = A.get(); + UnaliasedA->setAlias(std::move(A)); + + if (getKind() != FlagClass) { + // Values are usually owned by the ArgList. The exception are + // CommaJoined flags, where the Arg owns the values. For aliased flags, + // make the unaliased Arg the owner of the values. + // FIXME: There aren't many uses of CommaJoined -- try removing + // CommaJoined in favor of just calling StringRef::split(',') instead. + UnaliasedA->getValues() = RawA->getValues(); + UnaliasedA->setOwnsValues(RawA->getOwnsValues()); + RawA->setOwnsValues(false); + return UnaliasedA; + } + + // FlagClass aliases can have AliasArgs<>; add those to the unaliased arg. + if (const char *Val = getAliasArgs()) { + while (*Val != '\0') { + UnaliasedA->getValues().push_back(Val); + + // Move past the '\0' to the next argument. + Val += strlen(Val) + 1; + } + } + if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs()) + // A Flag alias for a Joined option must provide an argument. + UnaliasedA->getValues().push_back(""); + return UnaliasedA; +} |