brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.6 KiB · 738f75b Raw
297 lines · cpp
1//===- Option.cpp - Abstract Driver Options -------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Option/Option.h"10#include "llvm/ADT/StringRef.h"11#include "llvm/ADT/Twine.h"12#include "llvm/Config/llvm-config.h"13#include "llvm/Option/Arg.h"14#include "llvm/Option/ArgList.h"15#include "llvm/Option/OptTable.h"16#include "llvm/Support/Compiler.h"17#include "llvm/Support/Debug.h"18#include "llvm/Support/ErrorHandling.h"19#include "llvm/Support/raw_ostream.h"20#include <cassert>21 22using namespace llvm;23using namespace llvm::opt;24 25Option::Option(const OptTable::Info *info, const OptTable *owner)26  : Info(info), Owner(owner) {27  // Multi-level aliases are not supported. This just simplifies option28  // tracking, it is not an inherent limitation.29  assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) &&30         "Multi-level aliases are not supported.");31 32  if (Info && getAliasArgs()) {33    assert(getAlias().isValid() && "Only alias options can have alias args.");34    assert(getKind() == FlagClass && "Only Flag aliases can have alias args.");35    assert(getAlias().getKind() != FlagClass &&36           "Cannot provide alias args to a flag option.");37  }38}39 40void Option::print(raw_ostream &O, bool AddNewLine) const {41  O << "<";42  switch (getKind()) {43#define P(N) case N: O << #N; break44    P(GroupClass);45    P(InputClass);46    P(UnknownClass);47    P(FlagClass);48    P(JoinedClass);49    P(ValuesClass);50    P(SeparateClass);51    P(CommaJoinedClass);52    P(MultiArgClass);53    P(JoinedOrSeparateClass);54    P(JoinedAndSeparateClass);55    P(RemainingArgsClass);56    P(RemainingArgsJoinedClass);57#undef P58  }59 60  if (!Info->hasNoPrefix()) {61    O << " Prefixes:[";62    for (size_t I = 0, N = Info->getNumPrefixes(Owner->getPrefixesTable());63         I != N; ++I)64      O << '"'65        << Info->getPrefix(Owner->getStrTable(), Owner->getPrefixesTable(), I)66        << (I == N - 1 ? "\"" : "\", ");67    O << ']';68  }69 70  O << " Name:\"" << getName() << '"';71 72  const Option Group = getGroup();73  if (Group.isValid()) {74    O << " Group:";75    Group.print(O, /*AddNewLine=*/false);76  }77 78  const Option Alias = getAlias();79  if (Alias.isValid()) {80    O << " Alias:";81    Alias.print(O, /*AddNewLine=*/false);82  }83 84  if (getKind() == MultiArgClass)85    O << " NumArgs:" << getNumArgs();86 87  O << ">";88  if (AddNewLine)89    O << "\n";90}91 92#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)93LLVM_DUMP_METHOD void Option::dump() const { print(dbgs()); }94#endif95 96bool Option::matches(OptSpecifier Opt) const {97  // Aliases are never considered in matching, look through them.98  const Option Alias = getAlias();99  if (Alias.isValid())100    return Alias.matches(Opt);101 102  // Check exact match.103  if (getID() == Opt.getID())104    return true;105 106  const Option Group = getGroup();107  if (Group.isValid())108    return Group.matches(Opt);109  return false;110}111 112std::unique_ptr<Arg> Option::acceptInternal(const ArgList &Args,113                                            StringRef Spelling,114                                            unsigned &Index) const {115  const size_t SpellingSize = Spelling.size();116  const size_t ArgStringSize = StringRef(Args.getArgString(Index)).size();117  switch (getKind()) {118  case FlagClass: {119    if (SpellingSize != ArgStringSize)120      return nullptr;121    return std::make_unique<Arg>(*this, Spelling, Index++);122  }123  case JoinedClass: {124    const char *Value = Args.getArgString(Index) + SpellingSize;125    return std::make_unique<Arg>(*this, Spelling, Index++, Value);126  }127  case CommaJoinedClass: {128    // Always matches.129    const char *Str = Args.getArgString(Index) + SpellingSize;130    auto A = std::make_unique<Arg>(*this, Spelling, Index++);131 132    // Parse out the comma separated values.133    const char *Prev = Str;134    for (;; ++Str) {135      char c = *Str;136 137      if (!c || c == ',') {138        if (Prev != Str) {139          char *Value = new char[Str - Prev + 1];140          memcpy(Value, Prev, Str - Prev);141          Value[Str - Prev] = '\0';142          A->getValues().push_back(Value);143        }144 145        if (!c)146          break;147 148        Prev = Str + 1;149      }150    }151    A->setOwnsValues(true);152 153    return A;154  }155  case SeparateClass:156    // Matches iff this is an exact match.157    if (SpellingSize != ArgStringSize)158      return nullptr;159 160    Index += 2;161    if (Index > Args.getNumInputArgStrings() ||162        Args.getArgString(Index - 1) == nullptr)163      return nullptr;164 165    return std::make_unique<Arg>(*this, Spelling, Index - 2,166                                 Args.getArgString(Index - 1));167  case MultiArgClass: {168    // Matches iff this is an exact match.169    if (SpellingSize != ArgStringSize)170      return nullptr;171 172    Index += 1 + getNumArgs();173    if (Index > Args.getNumInputArgStrings())174      return nullptr;175 176    auto A = std::make_unique<Arg>(*this, Spelling, Index - 1 - getNumArgs(),177                                   Args.getArgString(Index - getNumArgs()));178    for (unsigned i = 1; i != getNumArgs(); ++i)179      A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));180    return A;181  }182  case JoinedOrSeparateClass: {183    // If this is not an exact match, it is a joined arg.184    if (SpellingSize != ArgStringSize) {185      const char *Value = Args.getArgString(Index) + SpellingSize;186      return std::make_unique<Arg>(*this, Spelling, Index++, Value);187    }188 189    // Otherwise it must be separate.190    Index += 2;191    if (Index > Args.getNumInputArgStrings() ||192        Args.getArgString(Index - 1) == nullptr)193      return nullptr;194 195    return std::make_unique<Arg>(*this, Spelling, Index - 2,196                                 Args.getArgString(Index - 1));197  }198  case JoinedAndSeparateClass:199    // Always matches.200    Index += 2;201    if (Index > Args.getNumInputArgStrings() ||202        Args.getArgString(Index - 1) == nullptr)203      return nullptr;204 205    return std::make_unique<Arg>(*this, Spelling, Index - 2,206                                 Args.getArgString(Index - 2) + SpellingSize,207                                 Args.getArgString(Index - 1));208  case RemainingArgsClass: {209    // Matches iff this is an exact match.210    if (SpellingSize != ArgStringSize)211      return nullptr;212    auto A = std::make_unique<Arg>(*this, Spelling, Index++);213    while (Index < Args.getNumInputArgStrings() &&214           Args.getArgString(Index) != nullptr)215      A->getValues().push_back(Args.getArgString(Index++));216    return A;217  }218  case RemainingArgsJoinedClass: {219    auto A = std::make_unique<Arg>(*this, Spelling, Index);220    if (SpellingSize != ArgStringSize) {221      // An inexact match means there is a joined arg.222      A->getValues().push_back(Args.getArgString(Index) + SpellingSize);223    }224    Index++;225    while (Index < Args.getNumInputArgStrings() &&226           Args.getArgString(Index) != nullptr)227      A->getValues().push_back(Args.getArgString(Index++));228    return A;229  }230 231  default:232    llvm_unreachable("Invalid option kind!");233  }234}235 236std::unique_ptr<Arg> Option::accept(const ArgList &Args, StringRef CurArg,237                                    bool GroupedShortOption,238                                    unsigned &Index) const {239  auto A(GroupedShortOption && getKind() == FlagClass240                             ? std::make_unique<Arg>(*this, CurArg, Index)241                             : acceptInternal(Args, CurArg, Index));242  if (!A)243    return nullptr;244 245  const Option &UnaliasedOption = getUnaliasedOption();246  if (getID() == UnaliasedOption.getID())247    return A;248 249  // "A" is an alias for a different flag. For most clients it's more convenient250  // if this function returns unaliased Args, so create an unaliased arg for251  // returning.252 253  // This creates a completely new Arg object for the unaliased Arg because254  // the alias and the unaliased arg can have different Kinds and different255  // Values (due to AliasArgs<>).256 257  // Get the spelling from the unaliased option.258  StringRef UnaliasedSpelling = Args.MakeArgString(259      Twine(UnaliasedOption.getPrefix()) + Twine(UnaliasedOption.getName()));260 261  // It's a bit weird that aliased and unaliased arg share one index, but262  // the index is mostly use as a memory optimization in render().263  // Due to this, ArgList::getArgString(A->getIndex()) will return the spelling264  // of the aliased arg always, while A->getSpelling() returns either the265  // unaliased or the aliased arg, depending on which Arg object it's called on.266  auto UnaliasedA =267      std::make_unique<Arg>(UnaliasedOption, UnaliasedSpelling, A->getIndex());268  Arg *RawA = A.get();269  UnaliasedA->setAlias(std::move(A));270 271  if (getKind() != FlagClass) {272    // Values are usually owned by the ArgList. The exception are273    // CommaJoined flags, where the Arg owns the values. For aliased flags,274    // make the unaliased Arg the owner of the values.275    // FIXME: There aren't many uses of CommaJoined -- try removing276    // CommaJoined in favor of just calling StringRef::split(',') instead.277    UnaliasedA->getValues() = RawA->getValues();278    UnaliasedA->setOwnsValues(RawA->getOwnsValues());279    RawA->setOwnsValues(false);280    return UnaliasedA;281  }282 283  // FlagClass aliases can have AliasArgs<>; add those to the unaliased arg.284  if (const char *Val = getAliasArgs()) {285    while (*Val != '\0') {286      UnaliasedA->getValues().push_back(Val);287 288      // Move past the '\0' to the next argument.289      Val += strlen(Val) + 1;290    }291  }292  if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs())293    // A Flag alias for a Joined option must provide an argument.294    UnaliasedA->getValues().push_back("");295  return UnaliasedA;296}297