1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/Tooling/DiagnosticsYaml.h" |
14 | #include "clang/Tooling/Core/Diagnostic.h" |
15 | #include "clang/Tooling/ReplacementsYaml.h" |
16 | #include "gtest/gtest.h" |
17 | |
18 | using namespace llvm; |
19 | using namespace clang::tooling; |
20 | using clang::tooling::Diagnostic; |
21 | |
22 | static DiagnosticMessage makeMessage(const std::string &Message, int FileOffset, |
23 | const std::string &FilePath) { |
24 | DiagnosticMessage DiagMessage; |
25 | DiagMessage.Message = Message; |
26 | DiagMessage.FileOffset = FileOffset; |
27 | DiagMessage.FilePath = FilePath; |
28 | return DiagMessage; |
29 | } |
30 | |
31 | static Diagnostic makeDiagnostic(StringRef DiagnosticName, |
32 | const std::string &Message, int FileOffset, |
33 | const std::string &FilePath, |
34 | const StringMap<Replacements> &Fix) { |
35 | return Diagnostic(DiagnosticName, makeMessage(Message, FileOffset, FilePath), |
36 | Fix, {}, Diagnostic::Warning, "path/to/build/directory"); |
37 | } |
38 | |
39 | TEST(DiagnosticsYamlTest, serializesDiagnostics) { |
40 | TranslationUnitDiagnostics TUD; |
41 | TUD.MainSourceFile = "path/to/source.cpp"; |
42 | |
43 | StringMap<Replacements> Fix1 = { |
44 | {"path/to/source.cpp", |
45 | Replacements({"path/to/source.cpp", 100, 12, "replacement #1"})}}; |
46 | TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#1", "message #1", 55, |
47 | "path/to/source.cpp", Fix1)); |
48 | |
49 | StringMap<Replacements> Fix2 = { |
50 | {"path/to/header.h", |
51 | Replacements({"path/to/header.h", 62, 2, "replacement #2"})}}; |
52 | TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#2", "message #2", 60, |
53 | "path/to/header.h", Fix2)); |
54 | |
55 | TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#3", "message #3", 72, |
56 | "path/to/source2.cpp", {})); |
57 | TUD.Diagnostics.back().Notes.push_back( |
58 | makeMessage("Note1", 88, "path/to/note1.cpp")); |
59 | TUD.Diagnostics.back().Notes.push_back( |
60 | makeMessage("Note2", 99, "path/to/note2.cpp")); |
61 | |
62 | std::string YamlContent; |
63 | raw_string_ostream YamlContentStream(YamlContent); |
64 | |
65 | yaml::Output YAML(YamlContentStream); |
66 | YAML << TUD; |
67 | |
68 | EXPECT_EQ("---\n" |
69 | "MainSourceFile: 'path/to/source.cpp'\n" |
70 | "Diagnostics: \n" |
71 | " - DiagnosticName: 'diagnostic#1\'\n" |
72 | " Message: 'message #1'\n" |
73 | " FileOffset: 55\n" |
74 | " FilePath: 'path/to/source.cpp'\n" |
75 | " Replacements: \n" |
76 | " - FilePath: 'path/to/source.cpp'\n" |
77 | " Offset: 100\n" |
78 | " Length: 12\n" |
79 | " ReplacementText: 'replacement #1'\n" |
80 | " - DiagnosticName: 'diagnostic#2'\n" |
81 | " Message: 'message #2'\n" |
82 | " FileOffset: 60\n" |
83 | " FilePath: 'path/to/header.h'\n" |
84 | " Replacements: \n" |
85 | " - FilePath: 'path/to/header.h'\n" |
86 | " Offset: 62\n" |
87 | " Length: 2\n" |
88 | " ReplacementText: 'replacement #2'\n" |
89 | " - DiagnosticName: 'diagnostic#3'\n" |
90 | " Message: 'message #3'\n" |
91 | " FileOffset: 72\n" |
92 | " FilePath: 'path/to/source2.cpp'\n" |
93 | " Notes: \n" |
94 | " - Message: Note1\n" |
95 | " FilePath: 'path/to/note1.cpp'\n" |
96 | " FileOffset: 88\n" |
97 | " - Message: Note2\n" |
98 | " FilePath: 'path/to/note2.cpp'\n" |
99 | " FileOffset: 99\n" |
100 | " Replacements: []\n" |
101 | "...\n", |
102 | YamlContentStream.str()); |
103 | } |
104 | |
105 | TEST(DiagnosticsYamlTest, deserializesDiagnostics) { |
106 | std::string YamlContent = "---\n" |
107 | "MainSourceFile: path/to/source.cpp\n" |
108 | "Diagnostics: \n" |
109 | " - DiagnosticName: 'diagnostic#1'\n" |
110 | " Message: 'message #1'\n" |
111 | " FileOffset: 55\n" |
112 | " FilePath: path/to/source.cpp\n" |
113 | " Replacements: \n" |
114 | " - FilePath: path/to/source.cpp\n" |
115 | " Offset: 100\n" |
116 | " Length: 12\n" |
117 | " ReplacementText: 'replacement #1'\n" |
118 | " - DiagnosticName: 'diagnostic#2'\n" |
119 | " Message: 'message #2'\n" |
120 | " FileOffset: 60\n" |
121 | " FilePath: path/to/header.h\n" |
122 | " Replacements: \n" |
123 | " - FilePath: path/to/header.h\n" |
124 | " Offset: 62\n" |
125 | " Length: 2\n" |
126 | " ReplacementText: 'replacement #2'\n" |
127 | " - DiagnosticName: 'diagnostic#3'\n" |
128 | " Message: 'message #3'\n" |
129 | " FileOffset: 98\n" |
130 | " FilePath: path/to/source.cpp\n" |
131 | " Notes:\n" |
132 | " - Message: Note1\n" |
133 | " FilePath: 'path/to/note1.cpp'\n" |
134 | " FileOffset: 66\n" |
135 | " - Message: Note2\n" |
136 | " FilePath: 'path/to/note2.cpp'\n" |
137 | " FileOffset: 77\n" |
138 | " Replacements: []\n" |
139 | "...\n"; |
140 | TranslationUnitDiagnostics TUDActual; |
141 | yaml::Input YAML(YamlContent); |
142 | YAML >> TUDActual; |
143 | |
144 | ASSERT_FALSE(YAML.error()); |
145 | ASSERT_EQ(3u, TUDActual.Diagnostics.size()); |
146 | EXPECT_EQ("path/to/source.cpp", TUDActual.MainSourceFile); |
147 | |
148 | auto getFixes = [](const StringMap<Replacements> &Fix) { |
149 | std::vector<Replacement> Fixes; |
150 | for (auto &Replacements : Fix) { |
151 | for (auto &Replacement : Replacements.second) { |
152 | Fixes.push_back(Replacement); |
153 | } |
154 | } |
155 | return Fixes; |
156 | }; |
157 | |
158 | Diagnostic D1 = TUDActual.Diagnostics[0]; |
159 | EXPECT_EQ("diagnostic#1", D1.DiagnosticName); |
160 | EXPECT_EQ("message #1", D1.Message.Message); |
161 | EXPECT_EQ(55u, D1.Message.FileOffset); |
162 | EXPECT_EQ("path/to/source.cpp", D1.Message.FilePath); |
163 | std::vector<Replacement> Fixes1 = getFixes(D1.Fix); |
164 | ASSERT_EQ(1u, Fixes1.size()); |
165 | EXPECT_EQ("path/to/source.cpp", Fixes1[0].getFilePath()); |
166 | EXPECT_EQ(100u, Fixes1[0].getOffset()); |
167 | EXPECT_EQ(12u, Fixes1[0].getLength()); |
168 | EXPECT_EQ("replacement #1", Fixes1[0].getReplacementText()); |
169 | |
170 | Diagnostic D2 = TUDActual.Diagnostics[1]; |
171 | EXPECT_EQ("diagnostic#2", D2.DiagnosticName); |
172 | EXPECT_EQ("message #2", D2.Message.Message); |
173 | EXPECT_EQ(60u, D2.Message.FileOffset); |
174 | EXPECT_EQ("path/to/header.h", D2.Message.FilePath); |
175 | std::vector<Replacement> Fixes2 = getFixes(D2.Fix); |
176 | ASSERT_EQ(1u, Fixes2.size()); |
177 | EXPECT_EQ("path/to/header.h", Fixes2[0].getFilePath()); |
178 | EXPECT_EQ(62u, Fixes2[0].getOffset()); |
179 | EXPECT_EQ(2u, Fixes2[0].getLength()); |
180 | EXPECT_EQ("replacement #2", Fixes2[0].getReplacementText()); |
181 | |
182 | Diagnostic D3 = TUDActual.Diagnostics[2]; |
183 | EXPECT_EQ("diagnostic#3", D3.DiagnosticName); |
184 | EXPECT_EQ("message #3", D3.Message.Message); |
185 | EXPECT_EQ(98u, D3.Message.FileOffset); |
186 | EXPECT_EQ("path/to/source.cpp", D3.Message.FilePath); |
187 | EXPECT_EQ(2u, D3.Notes.size()); |
188 | EXPECT_EQ("Note1", D3.Notes[0].Message); |
189 | EXPECT_EQ(66u, D3.Notes[0].FileOffset); |
190 | EXPECT_EQ("path/to/note1.cpp", D3.Notes[0].FilePath); |
191 | EXPECT_EQ("Note2", D3.Notes[1].Message); |
192 | EXPECT_EQ(77u, D3.Notes[1].FileOffset); |
193 | EXPECT_EQ("path/to/note2.cpp", D3.Notes[1].FilePath); |
194 | std::vector<Replacement> Fixes3 = getFixes(D3.Fix); |
195 | EXPECT_TRUE(Fixes3.empty()); |
196 | } |
197 | |