1 | //===--- AssertEquals.cpp - clang-tidy --------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "AssertEquals.h" |
10 | |
11 | #include <map> |
12 | #include <string> |
13 | |
14 | using namespace clang::ast_matchers; |
15 | |
16 | namespace clang::tidy::objc { |
17 | |
18 | // Mapping from `XCTAssert*Equal` to `XCTAssert*EqualObjects` name. |
19 | static const std::map<std::string, std::string> &NameMap() { |
20 | static std::map<std::string, std::string> map{ |
21 | {"XCTAssertEqual" , "XCTAssertEqualObjects" }, |
22 | {"XCTAssertNotEqual" , "XCTAssertNotEqualObjects" }, |
23 | |
24 | }; |
25 | return map; |
26 | } |
27 | |
28 | void AssertEquals::registerMatchers(MatchFinder *finder) { |
29 | for (const auto &pair : NameMap()) { |
30 | finder->addMatcher( |
31 | NodeMatch: binaryOperator(anyOf(hasOperatorName(Name: "!=" ), hasOperatorName(Name: "==" )), |
32 | isExpandedFromMacro(MacroName: pair.first), |
33 | anyOf(hasLHS(InnerMatcher: hasType(InnerMatcher: qualType( |
34 | hasCanonicalType(InnerMatcher: asString(Name: "NSString *" ))))), |
35 | hasRHS(InnerMatcher: hasType(InnerMatcher: qualType( |
36 | hasCanonicalType(InnerMatcher: asString(Name: "NSString *" )))))) |
37 | |
38 | ) |
39 | .bind(ID: pair.first), |
40 | Action: this); |
41 | } |
42 | } |
43 | |
44 | void AssertEquals::check(const ast_matchers::MatchFinder::MatchResult &result) { |
45 | for (const auto &pair : NameMap()) { |
46 | if (const auto *root = result.Nodes.getNodeAs<BinaryOperator>(ID: pair.first)) { |
47 | SourceManager *sm = result.SourceManager; |
48 | // The macros are nested two levels, so going up twice. |
49 | auto macro_callsite = sm->getImmediateMacroCallerLoc( |
50 | Loc: sm->getImmediateMacroCallerLoc(Loc: root->getBeginLoc())); |
51 | diag(Loc: macro_callsite, Description: "use " + pair.second + " for comparing objects" ) |
52 | << FixItHint::CreateReplacement( |
53 | RemoveRange: clang::CharSourceRange::getCharRange( |
54 | B: macro_callsite, |
55 | E: macro_callsite.getLocWithOffset(Offset: pair.first.length())), |
56 | Code: pair.second); |
57 | } |
58 | } |
59 | } |
60 | |
61 | } // namespace clang::tidy::objc |
62 | |