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 MacroCallsite = Sm->getImmediateMacroCallerLoc( |
50 | Loc: Sm->getImmediateMacroCallerLoc(Loc: Root->getBeginLoc())); |
51 | diag(Loc: MacroCallsite, Description: "use " + Pair.second + " for comparing objects" ) |
52 | << FixItHint::CreateReplacement( |
53 | RemoveRange: clang::CharSourceRange::getCharRange( |
54 | B: MacroCallsite, |
55 | E: MacroCallsite.getLocWithOffset(Offset: Pair.first.length())), |
56 | Code: Pair.second); |
57 | } |
58 | } |
59 | } |
60 | |
61 | } // namespace clang::tidy::objc |
62 | |