summaryrefslogtreecommitdiff
path: root/include/clang/ASTMatchers/Dynamic
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/ASTMatchers/Dynamic')
-rw-r--r--include/clang/ASTMatchers/Dynamic/Diagnostics.h4
-rw-r--r--include/clang/ASTMatchers/Dynamic/Parser.h130
-rw-r--r--include/clang/ASTMatchers/Dynamic/Registry.h51
-rw-r--r--include/clang/ASTMatchers/Dynamic/VariantValue.h184
4 files changed, 247 insertions, 122 deletions
diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
index 82a14f1929bec..ef93ac54508d7 100644
--- a/include/clang/ASTMatchers/Dynamic/Diagnostics.h
+++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
@@ -12,8 +12,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
-#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
+#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H
+#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
#include "clang/Basic/LLVM.h"
diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h
index 4045f57d1b364..bd006b6e1290e 100644
--- a/include/clang/ASTMatchers/Dynamic/Parser.h
+++ b/include/clang/ASTMatchers/Dynamic/Parser.h
@@ -31,8 +31,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
-#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
+#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H
+#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
#include "clang/ASTMatchers/Dynamic/Registry.h"
@@ -63,17 +63,6 @@ public:
public:
virtual ~Sema();
- /// \brief Lookup a value by name.
- ///
- /// This can be used in the Sema layer to declare known constants or to
- /// allow to split an expression in pieces.
- ///
- /// \param Name The name of the value to lookup.
- ///
- /// \return The named value. It could be any type that VariantValue
- /// supports. An empty value means that the name is not recognized.
- virtual VariantValue getNamedValue(StringRef Name);
-
/// \brief Process a matcher expression.
///
/// All the arguments passed here have already been processed.
@@ -105,6 +94,29 @@ public:
/// found.
virtual llvm::Optional<MatcherCtor>
lookupMatcherCtor(StringRef MatcherName) = 0;
+
+ /// \brief Compute the list of completion types for \p Context.
+ ///
+ /// Each element of \p Context represents a matcher invocation, going from
+ /// outermost to innermost. Elements are pairs consisting of a reference to
+ /// the matcher constructor and the index of the next element in the
+ /// argument list of that matcher (or for the last element, the index of
+ /// the completion point in the argument list). An empty list requests
+ /// completion for the root matcher.
+ virtual std::vector<ArgKind> getAcceptedCompletionTypes(
+ llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context);
+
+ /// \brief Compute the list of completions that match any of
+ /// \p AcceptedTypes.
+ ///
+ /// \param AcceptedTypes All types accepted for this completion.
+ ///
+ /// \return All completions for the specified types.
+ /// Completions should be valid when used in \c lookupMatcherCtor().
+ /// The matcher constructed from the return of \c lookupMatcherCtor()
+ /// should be convertible to some type in \p AcceptedTypes.
+ virtual std::vector<MatcherCompletion>
+ getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes);
};
/// \brief Sema implementation that uses the matcher registry to process the
@@ -121,58 +133,91 @@ public:
StringRef BindID,
ArrayRef<ParserValue> Args,
Diagnostics *Error) override;
+
+ std::vector<ArgKind> getAcceptedCompletionTypes(
+ llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) override;
+
+ std::vector<MatcherCompletion>
+ getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) override;
};
- /// \brief Parse a matcher expression, creating matchers from the registry.
- ///
- /// This overload creates matchers calling directly into the registry. If the
- /// caller needs more control over how the matchers are created, then it can
- /// use the overload below that takes a Sema.
- ///
- /// \param MatcherCode The matcher expression to parse.
- ///
- /// \return The matcher object constructed, or an empty Optional if an error
- /// occurred.
- /// In that case, \c Error will contain a description of the error.
- /// The caller takes ownership of the DynTypedMatcher object returned.
- static llvm::Optional<DynTypedMatcher>
- parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error);
+ typedef llvm::StringMap<VariantValue> NamedValueMap;
/// \brief Parse a matcher expression.
///
/// \param MatcherCode The matcher expression to parse.
///
/// \param S The Sema instance that will help the parser
- /// construct the matchers.
+ /// construct the matchers. If null, it uses the default registry.
+ ///
+ /// \param NamedValues A map of precomputed named values. This provides
+ /// the dictionary for the <NamedValue> rule of the grammar.
+ /// If null, it is ignored.
+ ///
/// \return The matcher object constructed by the processor, or an empty
/// Optional if an error occurred. In that case, \c Error will contain a
/// description of the error.
/// The caller takes ownership of the DynTypedMatcher object returned.
static llvm::Optional<DynTypedMatcher>
- parseMatcherExpression(StringRef MatcherCode, Sema *S, Diagnostics *Error);
-
- /// \brief Parse an expression, creating matchers from the registry.
- ///
- /// Parses any expression supported by this parser. In general, the
- /// \c parseMatcherExpression function is a better approach to get a matcher
- /// object.
- static bool parseExpression(StringRef Code, VariantValue *Value,
- Diagnostics *Error);
+ parseMatcherExpression(StringRef MatcherCode, Sema *S,
+ const NamedValueMap *NamedValues,
+ Diagnostics *Error);
+ static llvm::Optional<DynTypedMatcher>
+ parseMatcherExpression(StringRef MatcherCode, Sema *S,
+ Diagnostics *Error) {
+ return parseMatcherExpression(MatcherCode, S, nullptr, Error);
+ }
+ static llvm::Optional<DynTypedMatcher>
+ parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error) {
+ return parseMatcherExpression(MatcherCode, nullptr, Error);
+ }
/// \brief Parse an expression.
///
/// Parses any expression supported by this parser. In general, the
/// \c parseMatcherExpression function is a better approach to get a matcher
/// object.
+ ///
+ /// \param S The Sema instance that will help the parser
+ /// construct the matchers. If null, it uses the default registry.
+ ///
+ /// \param NamedValues A map of precomputed named values. This provides
+ /// the dictionary for the <NamedValue> rule of the grammar.
+ /// If null, it is ignored.
static bool parseExpression(StringRef Code, Sema *S,
+ const NamedValueMap *NamedValues,
VariantValue *Value, Diagnostics *Error);
+ static bool parseExpression(StringRef Code, Sema *S,
+ VariantValue *Value, Diagnostics *Error) {
+ return parseExpression(Code, S, nullptr, Value, Error);
+ }
+ static bool parseExpression(StringRef Code, VariantValue *Value,
+ Diagnostics *Error) {
+ return parseExpression(Code, nullptr, Value, Error);
+ }
/// \brief Complete an expression at the given offset.
///
+ /// \param S The Sema instance that will help the parser
+ /// construct the matchers. If null, it uses the default registry.
+ ///
+ /// \param NamedValues A map of precomputed named values. This provides
+ /// the dictionary for the <NamedValue> rule of the grammar.
+ /// If null, it is ignored.
+ ///
/// \return The list of completions, which may be empty if there are no
/// available completions or if an error occurred.
static std::vector<MatcherCompletion>
- completeExpression(StringRef Code, unsigned CompletionOffset);
+ completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S,
+ const NamedValueMap *NamedValues);
+ static std::vector<MatcherCompletion>
+ completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S) {
+ return completeExpression(Code, CompletionOffset, S, nullptr);
+ }
+ static std::vector<MatcherCompletion>
+ completeExpression(StringRef Code, unsigned CompletionOffset) {
+ return completeExpression(Code, CompletionOffset, nullptr);
+ }
private:
class CodeTokenizer;
@@ -180,6 +225,7 @@ private:
struct TokenInfo;
Parser(CodeTokenizer *Tokenizer, Sema *S,
+ const NamedValueMap *NamedValues,
Diagnostics *Error);
bool parseExpressionImpl(VariantValue *Value);
@@ -187,12 +233,16 @@ private:
VariantValue *Value);
bool parseIdentifierPrefixImpl(VariantValue *Value);
- void addCompletion(const TokenInfo &CompToken, StringRef TypedText,
- StringRef Decl);
+ void addCompletion(const TokenInfo &CompToken,
+ const MatcherCompletion &Completion);
void addExpressionCompletions();
+ std::vector<MatcherCompletion>
+ getNamedValueCompletions(ArrayRef<ArgKind> AcceptedTypes);
+
CodeTokenizer *const Tokenizer;
Sema *const S;
+ const NamedValueMap *const NamedValues;
Diagnostics *const Error;
typedef std::vector<std::pair<MatcherCtor, unsigned> > ContextStackTy;
diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h
index faa9254bc2e7a..ad24a8d1b7947 100644
--- a/include/clang/ASTMatchers/Dynamic/Registry.h
+++ b/include/clang/ASTMatchers/Dynamic/Registry.h
@@ -14,8 +14,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H
-#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H
+#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H
+#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
@@ -36,8 +36,10 @@ typedef const internal::MatcherDescriptor *MatcherCtor;
struct MatcherCompletion {
MatcherCompletion() {}
- MatcherCompletion(StringRef TypedText, StringRef MatcherDecl)
- : TypedText(TypedText), MatcherDecl(MatcherDecl) {}
+ MatcherCompletion(StringRef TypedText, StringRef MatcherDecl,
+ unsigned Specificity)
+ : TypedText(TypedText), MatcherDecl(MatcherDecl),
+ Specificity(Specificity) {}
/// \brief The text to type to select this matcher.
std::string TypedText;
@@ -45,6 +47,13 @@ struct MatcherCompletion {
/// \brief The "declaration" of the matcher, with type information.
std::string MatcherDecl;
+ /// \brief Value corresponding to the "specificity" of the converted matcher.
+ ///
+ /// Zero specificity indicates that this conversion would produce a trivial
+ /// matcher that will either always or never match.
+ /// Such matchers are excluded from code completion results.
+ unsigned Specificity;
+
bool operator==(const MatcherCompletion &Other) const {
return TypedText == Other.TypedText && MatcherDecl == Other.MatcherDecl;
}
@@ -58,28 +67,28 @@ public:
/// constructor, or Optional<MatcherCtor>() if not found.
static llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName);
- /// \brief Compute the list of completions for \p Context.
+ /// \brief Compute the list of completion types for \p Context.
///
/// Each element of \p Context represents a matcher invocation, going from
- /// outermost to innermost. Elements are pairs consisting of a reference to the
- /// matcher constructor and the index of the next element in the argument list
- /// of that matcher (or for the last element, the index of the completion
- /// point in the argument list). An empty list requests completion for the
- /// root matcher.
+ /// outermost to innermost. Elements are pairs consisting of a reference to
+ /// the matcher constructor and the index of the next element in the
+ /// argument list of that matcher (or for the last element, the index of
+ /// the completion point in the argument list). An empty list requests
+ /// completion for the root matcher.
+ static std::vector<ArgKind> getAcceptedCompletionTypes(
+ llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context);
+
+ /// \brief Compute the list of completions that match any of
+ /// \p AcceptedTypes.
///
- /// The completions are ordered first by decreasing relevance, then
- /// alphabetically. Relevance is determined by how closely the matcher's
- /// type matches that of the context. For example, if the innermost matcher
- /// takes a FunctionDecl matcher, the FunctionDecl matchers are returned
- /// first, followed by the ValueDecl matchers, then NamedDecl, then Decl, then
- /// polymorphic matchers.
+ /// \param AcceptedTypes All types accepted for this completion.
///
- /// Matchers which are technically convertible to the innermost context but
- /// which would match either all or no nodes are excluded. For example,
- /// namedDecl and varDecl are excluded in a FunctionDecl context, because
- /// those matchers would match respectively all or no nodes in such a context.
+ /// \return All completions for the specified types.
+ /// Completions should be valid when used in \c lookupMatcherCtor().
+ /// The matcher constructed from the return of \c lookupMatcherCtor()
+ /// should be convertible to some type in \p AcceptedTypes.
static std::vector<MatcherCompletion>
- getCompletions(ArrayRef<std::pair<MatcherCtor, unsigned> > Context);
+ getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes);
/// \brief Construct a matcher from the registry.
///
diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h
index b25267b1c54b0..a9bd3d50115ad 100644
--- a/include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -14,8 +14,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
-#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
+#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
+#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
@@ -29,6 +29,51 @@ namespace clang {
namespace ast_matchers {
namespace dynamic {
+/// \brief Kind identifier.
+///
+/// It supports all types that VariantValue can contain.
+class ArgKind {
+ public:
+ enum Kind {
+ AK_Matcher,
+ AK_Unsigned,
+ AK_String
+ };
+ /// \brief Constructor for non-matcher types.
+ ArgKind(Kind K) : K(K) { assert(K != AK_Matcher); }
+
+ /// \brief Constructor for matcher types.
+ ArgKind(ast_type_traits::ASTNodeKind MatcherKind)
+ : K(AK_Matcher), MatcherKind(MatcherKind) {}
+
+ Kind getArgKind() const { return K; }
+ ast_type_traits::ASTNodeKind getMatcherKind() const {
+ assert(K == AK_Matcher);
+ return MatcherKind;
+ }
+
+ /// \brief Determines if this type can be converted to \p To.
+ ///
+ /// \param To the requested destination type.
+ ///
+ /// \param Specificity value corresponding to the "specificity" of the
+ /// convertion.
+ bool isConvertibleTo(ArgKind To, unsigned *Specificity) const;
+
+ bool operator<(const ArgKind &Other) const {
+ if (K == AK_Matcher && Other.K == AK_Matcher)
+ return MatcherKind < Other.MatcherKind;
+ return K < Other.K;
+ }
+
+ /// \brief String representation of the type.
+ std::string asString() const;
+
+private:
+ Kind K;
+ ast_type_traits::ASTNodeKind MatcherKind;
+};
+
using ast_matchers::internal::DynTypedMatcher;
/// \brief A variant matcher object.
@@ -48,13 +93,28 @@ class VariantMatcher {
/// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher.
class MatcherOps {
public:
- virtual ~MatcherOps();
- virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
- bool &IsExactMatch) const = 0;
- virtual void constructFrom(const DynTypedMatcher &Matcher) = 0;
- virtual void constructVariadicOperator(
- ast_matchers::internal::VariadicOperatorFunction Func,
- ArrayRef<VariantMatcher> InnerMatchers) = 0;
+ MatcherOps(ast_type_traits::ASTNodeKind NodeKind) : NodeKind(NodeKind) {}
+
+ bool canConstructFrom(const DynTypedMatcher &Matcher,
+ bool &IsExactMatch) const;
+
+ /// \brief Convert \p Matcher the destination type and return it as a new
+ /// DynTypedMatcher.
+ virtual DynTypedMatcher
+ convertMatcher(const DynTypedMatcher &Matcher) const = 0;
+
+ /// \brief Constructs a variadic typed matcher from \p InnerMatchers.
+ /// Will try to convert each inner matcher to the destination type and
+ /// return llvm::None if it fails to do so.
+ llvm::Optional<DynTypedMatcher>
+ constructVariadicOperator(DynTypedMatcher::VariadicOperator Op,
+ ArrayRef<VariantMatcher> InnerMatchers) const;
+
+ protected:
+ ~MatcherOps() {}
+
+ private:
+ ast_type_traits::ASTNodeKind NodeKind;
};
/// \brief Payload interface to be specialized by each matcher type.
@@ -65,7 +125,10 @@ class VariantMatcher {
virtual ~Payload();
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
virtual std::string getTypeAsString() const = 0;
- virtual void makeTypedMatcher(MatcherOps &Ops) const = 0;
+ virtual llvm::Optional<DynTypedMatcher>
+ getTypedMatcher(const MatcherOps &Ops) const = 0;
+ virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
+ unsigned *Specificity) const = 0;
};
public:
@@ -84,9 +147,9 @@ public:
/// \brief Creates a 'variadic' operator matcher.
///
/// It will bind to the appropriate type on getTypedMatcher<T>().
- static VariantMatcher VariadicOperatorMatcher(
- ast_matchers::internal::VariadicOperatorFunction Func,
- std::vector<VariantMatcher> Args);
+ static VariantMatcher
+ VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op,
+ std::vector<VariantMatcher> Args);
/// \brief Makes the matcher the "null" matcher.
void reset();
@@ -111,9 +174,21 @@ public:
/// that can, the result would be ambiguous and false is returned.
template <class T>
bool hasTypedMatcher() const {
- TypedMatcherOps<T> Ops;
- if (Value) Value->makeTypedMatcher(Ops);
- return Ops.hasMatcher();
+ if (!Value) return false;
+ return Value->getTypedMatcher(TypedMatcherOps<T>()).hasValue();
+ }
+
+ /// \brief Determines if the contained matcher can be converted to \p Kind.
+ ///
+ /// \param Kind the requested destination type.
+ ///
+ /// \param Specificity value corresponding to the "specificity" of the
+ /// convertion.
+ bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
+ unsigned *Specificity) const {
+ if (Value)
+ return Value->isConvertibleTo(Kind, Specificity);
+ return false;
}
/// \brief Return this matcher as a \c Matcher<T>.
@@ -122,10 +197,9 @@ public:
/// Asserts that \c hasTypedMatcher<T>() is true.
template <class T>
ast_matchers::internal::Matcher<T> getTypedMatcher() const {
- TypedMatcherOps<T> Ops;
- Value->makeTypedMatcher(Ops);
- assert(Ops.hasMatcher() && "hasTypedMatcher<T>() == false");
- return Ops.matcher();
+ assert(hasTypedMatcher<T>() && "hasTypedMatcher<T>() == false");
+ return Value->getTypedMatcher(TypedMatcherOps<T>())
+ ->template convertTo<T>();
}
/// \brief String representation of the type of the value.
@@ -137,51 +211,25 @@ public:
private:
explicit VariantMatcher(Payload *Value) : Value(Value) {}
+ template <typename T> struct TypedMatcherOps;
+
class SinglePayload;
class PolymorphicPayload;
class VariadicOpPayload;
- template <typename T>
- class TypedMatcherOps : public MatcherOps {
- public:
- typedef ast_matchers::internal::Matcher<T> MatcherT;
-
- virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
- bool &IsExactMatch) const {
- IsExactMatch = Matcher.getSupportedKind().isSame(
- ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
- return Matcher.canConvertTo<T>();
- }
-
- virtual void constructFrom(const DynTypedMatcher& Matcher) {
- Out.reset(new MatcherT(Matcher.convertTo<T>()));
- }
-
- virtual void constructVariadicOperator(
- ast_matchers::internal::VariadicOperatorFunction Func,
- ArrayRef<VariantMatcher> InnerMatchers) {
- std::vector<DynTypedMatcher> DynMatchers;
- for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
- // Abort if any of the inner matchers can't be converted to
- // Matcher<T>.
- if (!InnerMatchers[i].hasTypedMatcher<T>()) {
- return;
- }
- DynMatchers.push_back(InnerMatchers[i].getTypedMatcher<T>());
- }
- Out.reset(new MatcherT(
- new ast_matchers::internal::VariadicOperatorMatcherInterface<T>(
- Func, DynMatchers)));
- }
-
- bool hasMatcher() const { return Out.get() != nullptr; }
- const MatcherT &matcher() const { return *Out; }
+ IntrusiveRefCntPtr<const Payload> Value;
+};
- private:
- std::unique_ptr<MatcherT> Out;
- };
+template <typename T>
+struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps {
+ TypedMatcherOps()
+ : MatcherOps(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) {}
+ typedef ast_matchers::internal::Matcher<T> MatcherT;
- IntrusiveRefCntPtr<const Payload> Value;
+ DynTypedMatcher
+ convertMatcher(const DynTypedMatcher &Matcher) const override {
+ return DynTypedMatcher(Matcher.convertTo<T>());
+ }
};
/// \brief Variant value class.
@@ -228,6 +276,24 @@ public:
const VariantMatcher &getMatcher() const;
void setMatcher(const VariantMatcher &Matcher);
+ /// \brief Determines if the contained value can be converted to \p Kind.
+ ///
+ /// \param Kind the requested destination type.
+ ///
+ /// \param Specificity value corresponding to the "specificity" of the
+ /// convertion.
+ bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const;
+
+ /// \brief Determines if the contained value can be converted to any kind
+ /// in \p Kinds.
+ ///
+ /// \param Kinds the requested destination types.
+ ///
+ /// \param Specificity value corresponding to the "specificity" of the
+ /// convertion. It is the maximum specificity of all the possible
+ /// conversions.
+ bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const;
+
/// \brief String representation of the type of the value.
std::string getTypeAsString() const;