292 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			292 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- 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, StringRef Spelling,
 | |
|                             unsigned &Index) const {
 | |
|   size_t ArgSize = Spelling.size();
 | |
|   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, StringRef CurArg,
 | |
|                     bool GroupedShortOption, unsigned &Index) const {
 | |
|   std::unique_ptr<Arg> A(GroupedShortOption && getKind() == FlagClass
 | |
|                              ? new Arg(*this, CurArg, Index)
 | |
|                              : acceptInternal(Args, CurArg, Index));
 | |
|   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;
 | |
| }
 |