aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/clang-tidy/objc/AssertEqualsCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy/objc/AssertEqualsCheck.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/objc/AssertEqualsCheck.cpp57
1 files changed, 57 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/objc/AssertEqualsCheck.cpp b/clang-tools-extra/clang-tidy/objc/AssertEqualsCheck.cpp
new file mode 100644
index 0000000..a9e6a4b
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/objc/AssertEqualsCheck.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "AssertEqualsCheck.h"
+#include "llvm/ADT/StringMap.h"
+
+#include <string>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::objc {
+
+// Mapping from `XCTAssert*Equal` to `XCTAssert*EqualObjects` name.
+static const llvm::StringMap<StringRef> NameMap{
+ {"XCTAssertEqual", "XCTAssertEqualObjects"},
+ {"XCTAssertNotEqual", "XCTAssertNotEqualObjects"},
+};
+
+void AssertEqualsCheck::registerMatchers(MatchFinder *Finder) {
+ for (const auto &[CurrName, _] : NameMap) {
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("!="), hasOperatorName("==")),
+ isExpandedFromMacro(std::string(CurrName)),
+ anyOf(hasLHS(hasType(qualType(
+ hasCanonicalType(asString("NSString *"))))),
+ hasRHS(hasType(qualType(
+ hasCanonicalType(asString("NSString *")))))))
+ .bind(CurrName),
+ this);
+ }
+}
+
+void AssertEqualsCheck::check(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ for (const auto &[CurrName, TargetName] : NameMap) {
+ if (const auto *Root = Result.Nodes.getNodeAs<BinaryOperator>(CurrName)) {
+ const SourceManager *Sm = Result.SourceManager;
+ // The macros are nested two levels, so going up twice.
+ auto MacroCallsite = Sm->getImmediateMacroCallerLoc(
+ Sm->getImmediateMacroCallerLoc(Root->getBeginLoc()));
+ diag(MacroCallsite,
+ (Twine("use ") + TargetName + " for comparing objects").str())
+ << FixItHint::CreateReplacement(
+ clang::CharSourceRange::getCharRange(
+ MacroCallsite,
+ MacroCallsite.getLocWithOffset(CurrName.size())),
+ TargetName);
+ }
+ }
+}
+
+} // namespace clang::tidy::objc