On Thu, Mar 12, 2015 at 11:48 AM, Manuel Klimek <[email protected]> wrote: > Author: klimek > Date: Thu Mar 12 10:48:15 2015 > New Revision: 232051 > > URL: http://llvm.org/viewvc/llvm-project?rev=232051&view=rev > Log: > Add support for a few Objective-C matchers. > > Add some matchers for Objective-C selectors and messages to > ASTMatchers.h. Minor mods to ASTMatchersTest.h to allow test files with > ".m" extension in addition to ".cpp". New tests added to > ASTMatchersTest.c. > > Patch by Dean Sutherland.
When I commit this previously, I had to revert due to broken bots. http://bb.pgr.jp/builders/ninja-clang-x64-mingw64-RA/builds/6352/steps/build/logs/stdio ~Aaron > > Modified: > cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h > cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h > cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp > cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp > cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h > > Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=232051&r1=232050&r2=232051&view=diff > ============================================================================== > --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original) > +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Thu Mar 12 10:48:15 2015 > @@ -47,6 +47,7 @@ > > #include "clang/AST/ASTContext.h" > #include "clang/AST/DeclFriend.h" > +#include "clang/AST/DeclObjC.h" > #include "clang/AST/DeclTemplate.h" > #include "clang/ASTMatchers/ASTMatchersInternal.h" > #include "clang/ASTMatchers/ASTMatchersMacros.h" > @@ -869,6 +870,20 @@ const internal::VariadicDynCastAllOfMatc > Stmt, > CXXMemberCallExpr> memberCallExpr; > > +/// \brief Matches ObjectiveC Message invocation expressions. > +/// > +/// The innermost message send invokes the "alloc" class method on the > +/// NSString class, while the outermost message send invokes the > +/// "initWithString" instance method on the object returned from > +/// NSString's "alloc". This matcher should match both message sends. > +/// \code > +/// [[NSString alloc] initWithString:@"Hello"] > +/// \endcode > +const internal::VariadicDynCastAllOfMatcher< > + Stmt, > + ObjCMessageExpr> objcMessageExpr; > + > + > /// \brief Matches expressions that introduce cleanups to be run at the end > /// of the sub-expression's evaluation. > /// > @@ -2007,6 +2022,104 @@ AST_MATCHER_P(CXXMemberCallExpr, on, int > InnerMatcher.matches(*ExprNode, Finder, Builder)); > } > > + > +/// \brief Matches on the receiver of an ObjectiveC Message expression. > +/// > +/// Example > +/// matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *"))); > +/// matches the [webView ...] message invocation. > +/// \code > +/// NSString *webViewJavaScript = ... > +/// UIWebView *webView = ... > +/// [webView stringByEvaluatingJavaScriptFromString:webViewJavascript]; > +/// \endcode > +AST_MATCHER_P(ObjCMessageExpr, hasReceiverType, internal::Matcher<QualType>, > + InnerMatcher) { > + const QualType TypeDecl = Node.getReceiverType(); > + return InnerMatcher.matches(TypeDecl, Finder, Builder); > +} > + > +/// \brief Matches when BaseName == Selector.getAsString() > +/// > +/// matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:")); > +/// matches the outer message expr in the code below, but NOT the message > +/// invocation for self.bodyView. > +/// \code > +/// [self.bodyView loadHTMLString:html baseURL:NULL]; > +/// \endcode > + AST_MATCHER_P(ObjCMessageExpr, hasSelector, std::string, BaseName) { > + Selector Sel = Node.getSelector(); > + return BaseName.compare(Sel.getAsString()) == 0; > +} > + > + > +/// \brief Matches ObjC selectors whose name contains > +/// a substring matched by the given RegExp. > +/// matcher = objCMessageExpr(matchesSelector("loadHTMLString\:baseURL?")); > +/// matches the outer message expr in the code below, but NOT the message > +/// invocation for self.bodyView. > +/// \code > +/// [self.bodyView loadHTMLString:html baseURL:NULL]; > +/// \endcode > +AST_MATCHER_P(ObjCMessageExpr, matchesSelector, std::string, RegExp) { > + assert(!RegExp.empty()); > + std::string SelectorString = Node.getSelector().getAsString(); > + llvm::Regex RE(RegExp); > + return RE.match(SelectorString); > +} > + > +/// \brief Matches when the selector is the empty selector > +/// > +/// Matches only when the selector of the objCMessageExpr is NULL. This may > +/// represent an error condition in the tree! > +AST_MATCHER(ObjCMessageExpr, hasNullSelector) { > + return Node.getSelector().isNull(); > +} > + > +/// \brief Matches when the selector is a Unary Selector > +/// > +/// matcher = objCMessageExpr(matchesSelector(hasUnarySelector()); > +/// matches self.bodyView in the code below, but NOT the outer message > +/// invocation of "loadHTMLString:baseURL:". > +/// \code > +/// [self.bodyView loadHTMLString:html baseURL:NULL]; > +/// \endcode > +AST_MATCHER(ObjCMessageExpr, hasUnarySelector) { > + return Node.getSelector().isUnarySelector(); > +} > + > +/// \brief Matches when the selector is a keyword selector > +/// > +/// objCMessageExpr(hasKeywordSelector()) matches the generated setFrame > +/// message expression in > +/// > +/// \code > +/// UIWebView *webView = ...; > +/// CGRect bodyFrame = webView.frame; > +/// bodyFrame.size.height = self.bodyContentHeight; > +/// webView.frame = bodyFrame; > +/// // ^---- matches here > +/// \endcode > + > +AST_MATCHER(ObjCMessageExpr, hasKeywordSelector) { > + return Node.getSelector().isKeywordSelector(); > +} > + > +/// \brief Matches when the selector has the specified number of arguments > +/// > +/// matcher = objCMessageExpr(numSelectorArgs(1)); > +/// matches self.bodyView in the code below > +/// > +/// matcher = objCMessageExpr(numSelectorArgs(2)); > +/// matches the invocation of "loadHTMLString:baseURL:" but not that > +/// of self.bodyView > +/// \code > +/// [self.bodyView loadHTMLString:html baseURL:NULL]; > +/// \endcode > +AST_MATCHER_P(ObjCMessageExpr, numSelectorArgs, unsigned, N) { > + return Node.getSelector().getNumArgs() == N; > +} > + > /// \brief Matches if the call expression's callee expression matches. > /// > /// Given > @@ -2316,7 +2429,8 @@ AST_MATCHER(VarDecl, hasGlobalStorage) { > /// \endcode > AST_POLYMORPHIC_MATCHER_P(argumentCountIs, > AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr, > - CXXConstructExpr), > + CXXConstructExpr, > + ObjCMessageExpr), > unsigned, N) { > return Node.getNumArgs() == N; > } > @@ -2331,7 +2445,8 @@ AST_POLYMORPHIC_MATCHER_P(argumentCountI > /// \endcode > AST_POLYMORPHIC_MATCHER_P2(hasArgument, > AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr, > - CXXConstructExpr), > + CXXConstructExpr, > + ObjCMessageExpr), > unsigned, N, internal::Matcher<Expr>, > InnerMatcher) { > return (N < Node.getNumArgs() && > InnerMatcher.matches( > > Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=232051&r1=232050&r2=232051&view=diff > ============================================================================== > --- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original) > +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Thu Mar 12 > 10:48:15 2015 > @@ -38,9 +38,12 @@ > #include "clang/AST/ASTTypeTraits.h" > #include "clang/AST/Decl.h" > #include "clang/AST/DeclCXX.h" > +#include "clang/AST/DeclObjC.h" > #include "clang/AST/ExprCXX.h" > +#include "clang/AST/ExprObjC.h" > #include "clang/AST/Stmt.h" > #include "clang/AST/StmtCXX.h" > +#include "clang/AST/StmtObjC.h" > #include "clang/AST/Type.h" > #include "llvm/ADT/Optional.h" > #include "llvm/ADT/VariadicFunction.h" > > Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=232051&r1=232050&r2=232051&view=diff > ============================================================================== > --- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original) > +++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Thu Mar 12 10:48:15 2015 > @@ -198,6 +198,7 @@ RegistryMaps::RegistryMaps() { > REGISTER_MATCHER(hasIncrement); > REGISTER_MATCHER(hasIndex); > REGISTER_MATCHER(hasInitializer); > + REGISTER_MATCHER(hasKeywordSelector); > REGISTER_MATCHER(hasLHS); > REGISTER_MATCHER(hasLocalQualifiers); > REGISTER_MATCHER(hasLocalStorage); > @@ -205,6 +206,7 @@ RegistryMaps::RegistryMaps() { > REGISTER_MATCHER(hasLoopVariable); > REGISTER_MATCHER(hasMethod); > REGISTER_MATCHER(hasName); > + REGISTER_MATCHER(hasNullSelector); > REGISTER_MATCHER(hasObjectExpression); > REGISTER_MATCHER(hasOperatorName); > REGISTER_MATCHER(hasOverloadedOperatorName); > @@ -212,7 +214,9 @@ RegistryMaps::RegistryMaps() { > REGISTER_MATCHER(hasParent); > REGISTER_MATCHER(hasQualifier); > REGISTER_MATCHER(hasRangeInit); > + REGISTER_MATCHER(hasReceiverType); > REGISTER_MATCHER(hasRHS); > + REGISTER_MATCHER(hasSelector); > REGISTER_MATCHER(hasSingleDecl); > REGISTER_MATCHER(hasSize); > REGISTER_MATCHER(hasSizeExpr); > @@ -223,6 +227,7 @@ RegistryMaps::RegistryMaps() { > REGISTER_MATCHER(hasTrueExpression); > REGISTER_MATCHER(hasTypeLoc); > REGISTER_MATCHER(hasUnaryOperand); > + REGISTER_MATCHER(hasUnarySelector); > REGISTER_MATCHER(hasValueType); > REGISTER_MATCHER(ifStmt); > REGISTER_MATCHER(ignoringImpCasts); > @@ -262,6 +267,7 @@ RegistryMaps::RegistryMaps() { > REGISTER_MATCHER(lambdaExpr); > REGISTER_MATCHER(lValueReferenceType); > REGISTER_MATCHER(matchesName); > + REGISTER_MATCHER(matchesSelector); > REGISTER_MATCHER(materializeTemporaryExpr); > REGISTER_MATCHER(member); > REGISTER_MATCHER(memberCallExpr); > @@ -276,7 +282,9 @@ RegistryMaps::RegistryMaps() { > REGISTER_MATCHER(newExpr); > REGISTER_MATCHER(nullPtrLiteralExpr); > REGISTER_MATCHER(nullStmt); > + REGISTER_MATCHER(numSelectorArgs); > REGISTER_MATCHER(ofClass); > + REGISTER_MATCHER(objcMessageExpr); > REGISTER_MATCHER(on); > REGISTER_MATCHER(onImplicitObjectArgument); > REGISTER_MATCHER(operatorCallExpr); > > Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=232051&r1=232050&r2=232051&view=diff > ============================================================================== > --- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original) > +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Thu Mar 12 10:48:15 > 2015 > @@ -4714,5 +4714,50 @@ TEST(Matcher, IsExpansionInFileMatching) > > #endif // LLVM_ON_WIN32 > > + > +TEST(ObjCMessageExprMatcher, SimpleExprs) { > + // don't find ObjCMessageExpr where none are present > + EXPECT_TRUE(notMatchesObjC("", objcMessageExpr(anything()))); > + > + std::string Objc1String = > + "@interface Str " > + " - (Str *)uppercaseString:(Str *)str;" > + "@end " > + "@interface foo " > + "- (void)meth:(Str *)text;" > + "@end " > + " " > + "@implementation foo " > + "- (void) meth:(Str *)text { " > + " [self contents];" > + " Str *up = [text uppercaseString];" > + "} " > + "@end "; > + EXPECT_TRUE(matchesObjC( > + Objc1String, > + objcMessageExpr(anything()))); > + EXPECT_TRUE(matchesObjC( > + Objc1String, > + objcMessageExpr(hasSelector("contents")))); > + EXPECT_TRUE(matchesObjC( > + Objc1String, > + objcMessageExpr(matchesSelector("cont*")))); > + EXPECT_FALSE(matchesObjC( > + Objc1String, > + objcMessageExpr(matchesSelector("?cont*")))); > + EXPECT_TRUE(notMatchesObjC( > + Objc1String, > + objcMessageExpr(hasSelector("contents"), hasNullSelector()))); > + EXPECT_TRUE(matchesObjC( > + Objc1String, > + objcMessageExpr(hasSelector("contents"), hasUnarySelector()))); > + EXPECT_TRUE(matchesObjC( > + Objc1String, > + objcMessageExpr(matchesSelector("uppercase*"), > + argumentCountIs(0) > + ))); > + > +} > + > } // end namespace ast_matchers > } // end namespace clang > > Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h?rev=232051&r1=232050&r2=232051&view=diff > ============================================================================== > --- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h (original) > +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h Thu Mar 12 10:48:15 2015 > @@ -62,7 +62,8 @@ template <typename T> > testing::AssertionResult matchesConditionally( > const std::string &Code, const T &AMatcher, bool ExpectMatch, > llvm::StringRef CompileArg, > - const FileContentMappings &VirtualMappedFiles = FileContentMappings()) { > + const FileContentMappings &VirtualMappedFiles = FileContentMappings(), > + const std::string &Filename = "input.cc") { > bool Found = false, DynamicFound = false; > MatchFinder Finder; > VerifyMatch VerifyFound(nullptr, &Found); > @@ -78,7 +79,7 @@ testing::AssertionResult matchesConditio > // Some tests need rtti/exceptions on > Args.push_back("-frtti"); > Args.push_back("-fexceptions"); > - if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, "input.cc", > + if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, Filename, > VirtualMappedFiles)) { > return testing::AssertionFailure() << "Parsing error in \"" << Code << > "\""; > } > @@ -109,6 +110,23 @@ testing::AssertionResult notMatches(cons > return matchesConditionally(Code, AMatcher, false, "-std=c++11"); > } > > +template <typename T> > +testing::AssertionResult matchesObjC(const std::string &Code, > + const T &AMatcher) { > + return matchesConditionally( > + Code, AMatcher, true, > + "", FileContentMappings(), "input.m"); > +} > + > +template <typename T> > +testing::AssertionResult notMatchesObjC(const std::string &Code, > + const T &AMatcher) { > + return matchesConditionally( > + Code, AMatcher, false, > + "", FileContentMappings(), "input.m"); > +} > + > + > // Function based on matchesConditionally with "-x cuda" argument added and > // small CUDA header prepended to the code string. > template <typename T> > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
