summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/ASTMatchers/ASTMatchersInternal.cpp4
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp6
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Parser.cpp72
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Registry.cpp17
4 files changed, 91 insertions, 8 deletions
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index f1a9ff2e09c..3144261612c 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -82,6 +82,10 @@ BoundNodesTree BoundNodesTreeBuilder::build() const {
return BoundNodesTree(Bindings, RecursiveBindings);
}
+DynTypedMatcher::~DynTypedMatcher() {}
+
+DynTypedMatcher *DynTypedMatcher::tryBind(StringRef ID) const { return NULL; }
+
} // end namespace internal
} // end namespace ast_matchers
} // end namespace clang
diff --git a/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp
index fb3cac370f5..4b01b997a17 100644
--- a/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp
@@ -37,6 +37,8 @@ StringRef ErrorTypeToString(Diagnostics::ErrorType Type) {
return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
case Diagnostics::ET_RegistryWrongArgType:
return "Incorrect type on function $0 for arg $1.";
+ case Diagnostics::ET_RegistryNotBindable:
+ return "Matcher does not support binding.";
case Diagnostics::ET_ParserStringError:
return "Error parsing string token: <$0>";
@@ -56,6 +58,10 @@ StringRef ErrorTypeToString(Diagnostics::ErrorType Type) {
return "Input value is not a matcher expression.";
case Diagnostics::ET_ParserInvalidToken:
return "Invalid token <$0> found when looking for a value.";
+ case Diagnostics::ET_ParserMalformedBindExpr:
+ return "Malformed bind() expression.";
+ case Diagnostics::ET_ParserTrailingCode:
+ return "Expected end of code.";
case Diagnostics::ET_None:
return "<N/A>";
diff --git a/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/clang/lib/ASTMatchers/Dynamic/Parser.cpp
index 1678820da01..1ed40f3050f 100644
--- a/clang/lib/ASTMatchers/Dynamic/Parser.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -32,12 +32,16 @@ struct Parser::TokenInfo {
TK_OpenParen = 1,
TK_CloseParen = 2,
TK_Comma = 3,
- TK_Literal = 4,
- TK_Ident = 5,
- TK_InvalidChar = 6,
- TK_Error = 7
+ TK_Period = 4,
+ TK_Literal = 5,
+ TK_Ident = 6,
+ TK_InvalidChar = 7,
+ TK_Error = 8
};
+ /// \brief Some known identifiers.
+ static const char* const ID_Bind;
+
TokenInfo() : Text(), Kind(TK_Eof), Range(), Value() {}
StringRef Text;
@@ -46,6 +50,8 @@ struct Parser::TokenInfo {
VariantValue Value;
};
+const char* const Parser::TokenInfo::ID_Bind = "bind";
+
/// \brief Simple tokenizer for the parser.
class Parser::CodeTokenizer {
public:
@@ -84,6 +90,11 @@ private:
Result.Text = Code.substr(0, 1);
Code = Code.drop_front();
break;
+ case '.':
+ Result.Kind = TokenInfo::TK_Period;
+ Result.Text = Code.substr(0, 1);
+ Code = Code.drop_front();
+ break;
case '(':
Result.Kind = TokenInfo::TK_OpenParen;
Result.Text = Code.substr(0, 1);
@@ -234,11 +245,43 @@ bool Parser::parseMatcherExpressionImpl(VariantValue *Value) {
return false;
}
+ std::string BindID;
+ if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period) {
+ // Parse .bind("foo")
+ Tokenizer->consumeNextToken(); // consume the period.
+ const TokenInfo BindToken = Tokenizer->consumeNextToken();
+ const TokenInfo OpenToken = Tokenizer->consumeNextToken();
+ const TokenInfo IDToken = Tokenizer->consumeNextToken();
+ const TokenInfo CloseToken = Tokenizer->consumeNextToken();
+
+ // TODO: We could use different error codes for each/some to be more
+ // explicit about the syntax error.
+ if (BindToken.Kind != TokenInfo::TK_Ident ||
+ BindToken.Text != TokenInfo::ID_Bind) {
+ Error->pushErrorFrame(BindToken.Range, Error->ET_ParserMalformedBindExpr);
+ return false;
+ }
+ if (OpenToken.Kind != TokenInfo::TK_OpenParen) {
+ Error->pushErrorFrame(OpenToken.Range, Error->ET_ParserMalformedBindExpr);
+ return false;
+ }
+ if (IDToken.Kind != TokenInfo::TK_Literal || !IDToken.Value.isString()) {
+ Error->pushErrorFrame(IDToken.Range, Error->ET_ParserMalformedBindExpr);
+ return false;
+ }
+ if (CloseToken.Kind != TokenInfo::TK_CloseParen) {
+ Error->pushErrorFrame(CloseToken.Range,
+ Error->ET_ParserMalformedBindExpr);
+ return false;
+ }
+ BindID = IDToken.Value.getString();
+ }
+
// Merge the start and end infos.
SourceRange MatcherRange = NameToken.Range;
MatcherRange.End = EndToken.Range.End;
- DynTypedMatcher *Result =
- S->actOnMatcherExpression(NameToken.Text, MatcherRange, Args, Error);
+ DynTypedMatcher *Result = S->actOnMatcherExpression(
+ NameToken.Text, MatcherRange, BindID, Args, Error);
if (Result == NULL) {
Error->pushErrorFrame(NameToken.Range, Error->ET_ParserMatcherFailure)
<< NameToken.Text;
@@ -271,6 +314,7 @@ bool Parser::parseExpressionImpl(VariantValue *Value) {
case TokenInfo::TK_OpenParen:
case TokenInfo::TK_CloseParen:
case TokenInfo::TK_Comma:
+ case TokenInfo::TK_Period:
case TokenInfo::TK_InvalidChar:
const TokenInfo Token = Tokenizer->consumeNextToken();
Error->pushErrorFrame(Token.Range, Error->ET_ParserInvalidToken)
@@ -290,9 +334,15 @@ public:
virtual ~RegistrySema() {}
DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName,
const SourceRange &NameRange,
+ StringRef BindID,
ArrayRef<ParserValue> Args,
Diagnostics *Error) {
- return Registry::constructMatcher(MatcherName, NameRange, Args, Error);
+ if (BindID.empty()) {
+ return Registry::constructMatcher(MatcherName, NameRange, Args, Error);
+ } else {
+ return Registry::constructBoundMatcher(MatcherName, NameRange, BindID,
+ Args, Error);
+ }
}
};
@@ -305,7 +355,13 @@ bool Parser::parseExpression(StringRef Code, VariantValue *Value,
bool Parser::parseExpression(StringRef Code, Sema *S,
VariantValue *Value, Diagnostics *Error) {
CodeTokenizer Tokenizer(Code, Error);
- return Parser(&Tokenizer, S, Error).parseExpressionImpl(Value);
+ if (!Parser(&Tokenizer, S, Error).parseExpressionImpl(Value)) return false;
+ if (Tokenizer.peekNextToken().Kind != TokenInfo::TK_Eof) {
+ Error->pushErrorFrame(Tokenizer.peekNextToken().Range,
+ Error->ET_ParserTrailingCode);
+ return false;
+ }
+ return true;
}
DynTypedMatcher *Parser::parseMatcherExpression(StringRef Code,
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 34a230b8728..6e543fc8504 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -148,6 +148,23 @@ DynTypedMatcher *Registry::constructMatcher(StringRef MatcherName,
return it->second->run(NameRange, Args, Error);
}
+// static
+DynTypedMatcher *Registry::constructBoundMatcher(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ OwningPtr<DynTypedMatcher> Out(
+ constructMatcher(MatcherName, NameRange, Args, Error));
+ if (!Out) return NULL;
+ DynTypedMatcher *Bound = Out->tryBind(BindID);
+ if (!Bound) {
+ Error->pushErrorFrame(NameRange, Error->ET_RegistryNotBindable);
+ return NULL;
+ }
+ return Bound;
+}
+
} // namespace dynamic
} // namespace ast_matchers
} // namespace clang
OpenPOWER on IntegriCloud