1 | #include "ClangTidy.h" |
2 | #include "ClangTidyTest.h" |
3 | #include "gtest/gtest.h" |
4 | |
5 | namespace clang { |
6 | namespace tidy { |
7 | namespace test { |
8 | |
9 | namespace { |
10 | class TestCheck : public ClangTidyCheck { |
11 | public: |
12 | TestCheck(StringRef Name, ClangTidyContext *Context) |
13 | : ClangTidyCheck(Name, Context) { |
14 | diag(Description: "DiagWithNoLoc" ); |
15 | } |
16 | void registerMatchers(ast_matchers::MatchFinder *Finder) override { |
17 | Finder->addMatcher(NodeMatch: ast_matchers::varDecl().bind(ID: "var" ), Action: this); |
18 | } |
19 | void check(const ast_matchers::MatchFinder::MatchResult &Result) override { |
20 | const auto *Var = Result.Nodes.getNodeAs<VarDecl>(ID: "var" ); |
21 | // Add diagnostics in the wrong order. |
22 | diag(Var->getLocation(), "variable" ); |
23 | diag(Var->getTypeSpecStartLoc(), "type specifier" ); |
24 | } |
25 | }; |
26 | |
27 | class HighlightTestCheck : public ClangTidyCheck { |
28 | public: |
29 | HighlightTestCheck(StringRef Name, ClangTidyContext *Context) |
30 | : ClangTidyCheck(Name, Context) {} |
31 | void registerMatchers(ast_matchers::MatchFinder *Finder) override { |
32 | Finder->addMatcher(NodeMatch: ast_matchers::varDecl().bind(ID: "var" ), Action: this); |
33 | } |
34 | void check(const ast_matchers::MatchFinder::MatchResult &Result) override { |
35 | const auto *Var = Result.Nodes.getNodeAs<VarDecl>(ID: "var" ); |
36 | diag(Var->getLocation(), "highlight range" ) << Var->getSourceRange(); |
37 | } |
38 | }; |
39 | |
40 | class InvalidRangeTestCheck : public ClangTidyCheck { |
41 | public: |
42 | InvalidRangeTestCheck(StringRef Name, ClangTidyContext *Context) |
43 | : ClangTidyCheck(Name, Context) {} |
44 | void registerMatchers(ast_matchers::MatchFinder *Finder) override { |
45 | Finder->addMatcher(NodeMatch: ast_matchers::varDecl().bind(ID: "var" ), Action: this); |
46 | } |
47 | void check(const ast_matchers::MatchFinder::MatchResult &Result) override { |
48 | const auto *Var = Result.Nodes.getNodeAs<VarDecl>(ID: "var" ); |
49 | SourceLocation ValidBeginLoc = Var->getBeginLoc(); |
50 | SourceLocation ValidEndLoc = Var->getEndLoc(); |
51 | SourceLocation InvalidLoc; |
52 | ASSERT_TRUE(ValidBeginLoc.isValid()); |
53 | ASSERT_TRUE(ValidEndLoc.isValid()); |
54 | ASSERT_TRUE(InvalidLoc.isInvalid()); |
55 | |
56 | diag(Loc: ValidBeginLoc, Description: "valid->valid" ) |
57 | << SourceRange(ValidBeginLoc, ValidEndLoc); |
58 | diag(Loc: ValidBeginLoc, Description: "valid->invalid" ) |
59 | << SourceRange(ValidBeginLoc, InvalidLoc); |
60 | diag(Loc: ValidBeginLoc, Description: "invalid->valid" ) |
61 | << SourceRange(InvalidLoc, ValidEndLoc); |
62 | diag(Loc: ValidBeginLoc, Description: "invalid->invalid" ) |
63 | << SourceRange(InvalidLoc, InvalidLoc); |
64 | } |
65 | }; |
66 | |
67 | } // namespace |
68 | |
69 | TEST(ClangTidyDiagnosticConsumer, SortsErrors) { |
70 | std::vector<ClangTidyError> Errors; |
71 | runCheckOnCode<TestCheck>(Code: "int a;" , Errors: &Errors); |
72 | EXPECT_EQ(3ul, Errors.size()); |
73 | EXPECT_EQ("DiagWithNoLoc" , Errors[0].Message.Message); |
74 | EXPECT_EQ("type specifier" , Errors[1].Message.Message); |
75 | EXPECT_EQ("variable" , Errors[2].Message.Message); |
76 | } |
77 | |
78 | TEST(ClangTidyDiagnosticConsumer, HandlesSourceRangeHighlight) { |
79 | std::vector<ClangTidyError> Errors; |
80 | runCheckOnCode<HighlightTestCheck>(Code: "int abc;" , Errors: &Errors); |
81 | EXPECT_EQ(1ul, Errors.size()); |
82 | EXPECT_EQ("highlight range" , Errors[0].Message.Message); |
83 | |
84 | // int abc; |
85 | // ____^ |
86 | // 01234 |
87 | EXPECT_EQ(4ul, Errors[0].Message.FileOffset); |
88 | |
89 | // int abc |
90 | // ~~~~~~~ -> Length 7. (0-length highlights are nonsensical.) |
91 | EXPECT_EQ(1ul, Errors[0].Message.Ranges.size()); |
92 | EXPECT_EQ(0ul, Errors[0].Message.Ranges[0].FileOffset); |
93 | EXPECT_EQ(7ul, Errors[0].Message.Ranges[0].Length); |
94 | } |
95 | |
96 | TEST(ClangTidyDiagnosticConsumer, InvalidSourceLocationRangesIgnored) { |
97 | std::vector<ClangTidyError> Errors; |
98 | runCheckOnCode<InvalidRangeTestCheck>(Code: "int x;" , Errors: &Errors); |
99 | EXPECT_EQ(4ul, Errors.size()); |
100 | |
101 | EXPECT_EQ("invalid->invalid" , Errors[0].Message.Message); |
102 | EXPECT_TRUE(Errors[0].Message.Ranges.empty()); |
103 | |
104 | EXPECT_EQ("invalid->valid" , Errors[1].Message.Message); |
105 | EXPECT_TRUE(Errors[1].Message.Ranges.empty()); |
106 | |
107 | EXPECT_EQ("valid->invalid" , Errors[2].Message.Message); |
108 | EXPECT_TRUE(Errors[2].Message.Ranges.empty()); |
109 | |
110 | EXPECT_EQ("valid->valid" , Errors[3].Message.Message); |
111 | EXPECT_EQ(1ul, Errors[3].Message.Ranges.size()); |
112 | } |
113 | |
114 | } // namespace test |
115 | } // namespace tidy |
116 | } // namespace clang |
117 | |