diff --git a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt --- a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt +++ b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt @@ -28,6 +28,7 @@ ModernizeModuleTest.cpp NamespaceAliaserTest.cpp ObjCModuleTest.cpp + ObjCStringLiteralTest.cpp OptionsProviderTest.cpp OverlappingReplacementsTest.cpp UsingInserterTest.cpp diff --git a/clang-tools-extra/unittests/clang-tidy/ObjCStringLiteralTest.cpp b/clang-tools-extra/unittests/clang-tidy/ObjCStringLiteralTest.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/unittests/clang-tidy/ObjCStringLiteralTest.cpp @@ -0,0 +1,63 @@ +//===---- ObjCStringLiteralTest.cpp - clang-tidy ---------------------------------===// +// +// 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 "ClangTidyTest.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "gtest/gtest.h" + +namespace clang { +namespace tidy { +namespace test { +namespace { + +class ObjCStringLiteralCheck : public ClangTidyCheck { +public: + ObjCStringLiteralCheck(StringRef CheckName, ClangTidyContext *Context) + : ClangTidyCheck(CheckName, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override { + using namespace ast_matchers; + Finder->addMatcher(objCStringLiteral().bind("str_lit"), this); + } + void check(const ast_matchers::MatchFinder::MatchResult &Result) override { + const auto *StrExpr = Result.Nodes.getNodeAs("str_lit"); + const StringLiteral* SL = cast(StrExpr)->getString(); + diag(StrExpr->getExprLoc(), "Matched ObjC StringLiteral: %0") << SL->getString(); + } +}; + +} // namespace + +TEST(ObjCStringLiteralTest, ObjCStringLiteralCheck) { + std::vector Errors; + runCheckOnCode( + "@interface NSObject\n" + "@end\n" + "@interface NSString\n" + "@end\n" + "@interface Test : NSObject\n" + "+ (void)someFunction:(NSString *)Desc;\n" + "@end\n" + "@implementation Test\n" + "+ (void)someFunction:(NSString *)Desc {\n" + " return;\n" + "}\n" + "- (void) foo {\n" + " [Test someFunction:@\"Ola!\"];\n" + "}\n" + "@end\n", + &Errors, + "input.m"); + EXPECT_EQ(1ul, Errors.size()); + EXPECT_EQ( + "Matched ObjC StringLiteral: Ola!", + Errors[0].Message.Message); +} + +} // namespace test +} // namespace tidy +} // namespace clang diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -1515,6 +1515,9 @@ extern const internal::VariadicDynCastAllOfMatcher objcMessageExpr; +extern const internal::VariadicDynCastAllOfMatcher + objCStringLiteral; + /// Matches Objective-C interface declarations. /// /// Example matches Foo diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -917,6 +917,7 @@ const internal::VariadicDynCastAllOfMatcher cxxBoolLiteral; const internal::VariadicDynCastAllOfMatcher stringLiteral; +const internal::VariadicDynCastAllOfMatcher objCStringLiteral; const internal::VariadicDynCastAllOfMatcher characterLiteral; const internal::VariadicDynCastAllOfMatcher diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -548,6 +548,7 @@ REGISTER_MATCHER(stmt); REGISTER_MATCHER(stmtExpr); REGISTER_MATCHER(stringLiteral); + REGISTER_MATCHER(objCStringLiteral); REGISTER_MATCHER(substNonTypeTemplateParmExpr); REGISTER_MATCHER(substTemplateTypeParmType); REGISTER_MATCHER(switchCase);