//===--- Option.h - Abstract Driver Options ---------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef CLANG_DRIVER_OPTION_H_ #define CLANG_DRIVER_OPTION_H_ #include "clang/Driver/OptSpecifier.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" using llvm::isa; using llvm::cast; using llvm::cast_or_null; using llvm::dyn_cast; using llvm::dyn_cast_or_null; namespace clang { namespace driver { class Arg; class ArgList; class OptionGroup; /// Option - Abstract representation for a single form of driver /// argument. /// /// An Option class represents a form of option that the driver /// takes, for example how many arguments the option has and how /// they can be provided. Individual option instances store /// additional information about what group the option is a member /// of (if any), if the option is an alias, and a number of /// flags. At runtime the driver parses the command line into /// concrete Arg instances, each of which corresponds to a /// particular Option instance. class Option { public: enum OptionClass { GroupClass = 0, InputClass, UnknownClass, FlagClass, JoinedClass, SeparateClass, CommaJoinedClass, MultiArgClass, JoinedOrSeparateClass, JoinedAndSeparateClass }; enum RenderStyleKind { RenderCommaJoinedStyle, RenderJoinedStyle, RenderSeparateStyle, RenderValuesStyle }; private: OptionClass Kind; /// The option ID. OptSpecifier ID; /// The option name. llvm::StringRef Name; /// Group this option is a member of, if any. const OptionGroup *Group; /// Option that this is an alias for, if any. const Option *Alias; /// Unsupported options will be rejected. bool Unsupported : 1; /// Treat this option like a linker input? bool LinkerInput : 1; /// When rendering as an input, don't render the option. // FIXME: We should ditch the render/renderAsInput distinction. bool NoOptAsInput : 1; /// The style to using when rendering arguments parsed by this option. unsigned RenderStyle : 2; /// This option is only consumed by the driver. bool DriverOption : 1; /// This option should not report argument unused errors. bool NoArgumentUnused : 1; /// This option should not be implicitly forwarded. bool NoForward : 1; protected: Option(OptionClass Kind, OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias); public: virtual ~Option(); unsigned getID() const { return ID.getID(); } OptionClass getKind() const { return Kind; } llvm::StringRef getName() const { return Name; } const OptionGroup *getGroup() const { return Group; } const Option *getAlias() const { return Alias; } bool isUnsupported() const { return Unsupported; } void setUnsupported(bool Value) { Unsupported = Value; } bool isLinkerInput() const { return LinkerInput; } void setLinkerInput(bool Value) { LinkerInput = Value; } bool hasNoOptAsInput() const { return NoOptAsInput; } void setNoOptAsInput(bool Value) { NoOptAsInput = Value; } RenderStyleKind getRenderStyle() const { return RenderStyleKind(RenderStyle); } void setRenderStyle(RenderStyleKind Value) { RenderStyle = Value; } bool isDriverOption() const { return DriverOption; } void setDriverOption(bool Value) { DriverOption = Value; } bool hasNoArgumentUnused() const { return NoArgumentUnused; } void setNoArgumentUnused(bool Value) { NoArgumentUnused = Value; } bool hasNoForward() const { return NoForward; } void setNoForward(bool Value) { NoForward = Value; } bool hasForwardToGCC() const { return !NoForward && !DriverOption && !LinkerInput; } /// getUnaliasedOption - Return the final option this option /// aliases (itself, if the option has no alias). const Option *getUnaliasedOption() const { if (Alias) return Alias->getUnaliasedOption(); return this; } /// getRenderName - Return the name to use when rendering this /// option. llvm::StringRef getRenderName() const { return getUnaliasedOption()->getName(); } /// matches - Predicate for whether this option is part of the /// given option (which may be a group). /// /// Note that matches against options which are an alias should never be /// done -- aliases do not participate in matching and so such a query will /// always be false. bool matches(OptSpecifier ID) const; /// accept - Potentially accept the current argument, returning a /// new Arg instance, or 0 if the option does not accept this /// argument (or the argument is missing values). /// /// If the option accepts the current argument, accept() sets /// Index to the position where argument parsing should resume /// (even if the argument is missing values). virtual Arg *accept(const ArgList &Args, unsigned &Index) const = 0; void dump() const; static bool classof(const Option *) { return true; } }; /// OptionGroup - A set of options which are can be handled uniformly /// by the driver. class OptionGroup : public Option { public: OptionGroup(OptSpecifier ID, const char *Name, const OptionGroup *Group); virtual Arg *accept(const ArgList &Args, unsigned &Index) const; static bool classof(const Option *O) { return O->getKind() == Option::GroupClass; } static bool classof(const OptionGroup *) { return true; } }; // Dummy option classes. /// InputOption - Dummy option class for representing driver inputs. class InputOption : public Option { public: InputOption(OptSpecifier ID); virtual Arg *accept(const ArgList &Args, unsigned &Index) const; static bool classof(const Option *O) { return O->getKind() == Option::InputClass; } static bool classof(const InputOption *) { return true; } }; /// UnknownOption - Dummy option class for represent unknown arguments. class UnknownOption : public Option { public: UnknownOption(OptSpecifier ID); virtual Arg *accept(const ArgList &Args, unsigned &Index) const; static bool classof(const Option *O) { return O->getKind() == Option::UnknownClass; } static bool classof(const UnknownOption *) { return true; } }; // Normal options. class FlagOption : public Option { public: FlagOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const ArgList &Args, unsigned &Index) const; static bool classof(const Option *O) { return O->getKind() == Option::FlagClass; } static bool classof(const FlagOption *) { return true; } }; class JoinedOption : public Option { public: JoinedOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const ArgList &Args, unsigned &Index) const; static bool classof(const Option *O) { return O->getKind() == Option::JoinedClass; } static bool classof(const JoinedOption *) { return true; } }; class SeparateOption : public Option { public: SeparateOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const ArgList &Args, unsigned &Index) const; static bool classof(const Option *O) { return O->getKind() == Option::SeparateClass; } static bool classof(const SeparateOption *) { return true; } }; class CommaJoinedOption : public Option { public: CommaJoinedOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const ArgList &Args, unsigned &Index) const; static bool classof(const Option *O) { return O->getKind() == Option::CommaJoinedClass; } static bool classof(const CommaJoinedOption *) { return true; } }; // FIXME: Fold MultiArgOption into SeparateOption? /// MultiArgOption - An option which takes multiple arguments (these /// are always separate arguments). class MultiArgOption : public Option { unsigned NumArgs; public: MultiArgOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias, unsigned NumArgs); unsigned getNumArgs() const { return NumArgs; } virtual Arg *accept(const ArgList &Args, unsigned &Index) const; static bool classof(const Option *O) { return O->getKind() == Option::MultiArgClass; } static bool classof(const MultiArgOption *) { return true; } }; /// JoinedOrSeparateOption - An option which either literally /// prefixes its (non-empty) value, or is follwed by a value. class JoinedOrSeparateOption : public Option { public: JoinedOrSeparateOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const ArgList &Args, unsigned &Index) const; static bool classof(const Option *O) { return O->getKind() == Option::JoinedOrSeparateClass; } static bool classof(const JoinedOrSeparateOption *) { return true; } }; /// JoinedAndSeparateOption - An option which literally prefixes its /// value and is followed by another value. class JoinedAndSeparateOption : public Option { public: JoinedAndSeparateOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias); virtual Arg *accept(const ArgList &Args, unsigned &Index) const; static bool classof(const Option *O) { return O->getKind() == Option::JoinedAndSeparateClass; } static bool classof(const JoinedAndSeparateOption *) { return true; } }; } // end namespace driver } // end namespace clang #endif