Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: tools/clang/traffic_annotation_extractor/traffic_annotation_extractor.cpp

Issue 2911633002: Expanding traffic_annotation_extractor clang tool to extract network calls. (Closed)
Patch Set: Clang tool updated. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // This clang tool finds all instances of the following functions: 5 // This clang tool finds all instances of the following functions:
6 // - net::DefineNetworkTrafficAnnotation 6 // - net::DefineNetworkTrafficAnnotation
7 // - net::DefinePartialNetworkTrafficAnnotation 7 // - net::DefinePartialNetworkTrafficAnnotation
8 // - net::CompleteNetworkTrafficAnnotation 8 // - net::CompleteNetworkTrafficAnnotation
9 // - net::BranchedCompleteNetworkTrafficAnnotation 9 // - net::BranchedCompleteNetworkTrafficAnnotation
10 // It extracts the location info and content of annotation tags, and outputs 10 // It extracts the location info and content of annotation tags, and outputs
11 // them to llvm::outs. Please refer to README.md for build and usage 11 // them to llvm::outs. It also extracts all calls the following network request
msramek 2017/05/29 21:03:36 typo: calls of
Ramin Halavati 2017/05/30 04:40:36 Done.
12 // instructions. 12 // creation functions and returns their source location and availability of a
13 // net::[Partial]NetworkTrafficAnnotation parameter in them:
14 // - SSLClientSocket::SSLClientSocket
15 // - TCPClientSocket::TCPClientSocket
16 // - UDPClientSocket::UDPClientSocket
17 // - URLFetcher::Create
18 // - ClientSocketFactory::CreateDatagramClientSocket
19 // - ClientSocketFactory::CreateSSLClientSocket
20 // - ClientSocketFactory::CreateTransportClientSocket
21 // - URLRequestContext::CreateRequest
22 // Please refer to README.md for build and usage instructions.
13 23
14 #include <memory> 24 #include <memory>
15 #include <vector> 25 #include <vector>
16 26
17 #include "clang/ASTMatchers/ASTMatchFinder.h" 27 #include "clang/ASTMatchers/ASTMatchFinder.h"
18 #include "clang/ASTMatchers/ASTMatchers.h" 28 #include "clang/ASTMatchers/ASTMatchers.h"
19 #include "clang/Basic/SourceManager.h" 29 #include "clang/Basic/SourceManager.h"
20 #include "clang/Frontend/FrontendActions.h" 30 #include "clang/Frontend/FrontendActions.h"
21 #include "clang/Lex/Lexer.h" 31 #include "clang/Lex/Lexer.h"
22 #include "clang/Tooling/CommonOptionsParser.h" 32 #include "clang/Tooling/CommonOptionsParser.h"
23 #include "clang/Tooling/Refactoring.h" 33 #include "clang/Tooling/Refactoring.h"
24 #include "clang/Tooling/Tooling.h" 34 #include "clang/Tooling/Tooling.h"
25 #include "llvm/Support/CommandLine.h" 35 #include "llvm/Support/CommandLine.h"
26 36
27 using namespace clang::ast_matchers; 37 using namespace clang::ast_matchers;
28 38
29 namespace { 39 namespace {
30 40
41 // Information about location of a line of code.
42 struct Location {
43 std::string file_path;
44 int line_number = -1;
45
46 // Name of the function including this line. E.g., in the following code,
47 // |function_name| will be 'foo' for all |line_number| values 101-103.
48 //
49 // 100 void foo() {
50 // 101 NetworkTrafficAnnotationTag baz =
51 // 102 net::DefineNetworkTrafficAnnotation(...); }
52 // 103 bar(baz);
53 // 104 }
54 // If no function is found, 'Global Namespace' will be returned.
55 std::string function_name;
56 };
57
31 // An instance of a call to either of the 4 network traffic annotation 58 // An instance of a call to either of the 4 network traffic annotation
32 // definition functions. 59 // definition functions.
33 struct NetworkAnnotationInstance { 60 struct NetworkAnnotationInstance {
34 // Information about where the call has happened.
35 struct Location {
36 std::string file_path;
37 int line_number = -1;
38
39 // Name of the function including this line. E.g., in the following code,
40 // |function_name| will be 'foo' for all |line_number| values 101-103.
41 //
42 // 100 void foo() {
43 // 101 NetworkTrafficAnnotationTag baz =
44 // 102 net::DefineNetworkTrafficAnnotation(...); }
45 // 103 bar(baz);
46 // 104 }
47 // If no function is found, 'Global Namespace' will be returned.
48 std::string function_name;
49 };
50
51 // Annotation content. These are the arguments of the call to either of the 4 61 // Annotation content. These are the arguments of the call to either of the 4
52 // network traffic annotation definition functions. 62 // network traffic annotation definition functions.
53 struct Annotation { 63 struct Annotation {
54 std::string unique_id; 64 std::string unique_id;
55 std::string text; 65 std::string text;
56 66
57 // |extra_id| will have |completing_id| for 67 // |extra_id| will have |completing_id| for
58 // net::DefinePartialNetworkTrafficAnnotation and |group_id| for 68 // net::DefinePartialNetworkTrafficAnnotation and |group_id| for
59 // net::BranchedCompleteNetworkTrafficAnnotation. It will be empty in other 69 // net::BranchedCompleteNetworkTrafficAnnotation. It will be empty in other
60 // cases. 70 // cases.
(...skipping 22 matching lines...) Expand all
83 case kCompleting: 93 case kCompleting:
84 return "Completing"; 94 return "Completing";
85 case kBranchedCompleting: 95 case kBranchedCompleting:
86 return "BranchedCompleting"; 96 return "BranchedCompleting";
87 } 97 }
88 assert(false); 98 assert(false);
89 return ""; 99 return "";
90 } 100 }
91 }; 101 };
92 102
93 using Collector = std::vector<NetworkAnnotationInstance>; 103 // An instance of a call to one of the monitored function.
104 struct CallInstance {
105 // Location of the call.
106 Location location;
107
108 // Whether the function is annotated.
109 bool has_annotation = false;
110
111 // Name of the called function.
112 std::string called_function_name;
113 };
114
115 // A structure to keep detected annotation and call instances.
116 struct Collector {
117 std::vector<NetworkAnnotationInstance> annotations;
118 std::vector<CallInstance> calls;
119 };
94 120
95 // This class implements the call back functions for AST Matchers. The matchers 121 // This class implements the call back functions for AST Matchers. The matchers
96 // are defined in RunMatchers function. When a pattern is found there, 122 // are defined in RunMatchers function. When a pattern is found there,
97 // the run function in this class is called back with information on the matched 123 // the run function in this class is called back with information on the matched
98 // location and description of the matched pattern. 124 // location and description of the matched pattern.
99 class NetworkAnnotationTagCallback : public MatchFinder::MatchCallback { 125 class NetworkAnnotationTagCallback : public MatchFinder::MatchCallback {
100 public: 126 public:
101 explicit NetworkAnnotationTagCallback(Collector* collector) 127 explicit NetworkAnnotationTagCallback(Collector* collector)
102 : collector_(collector) {} 128 : collector_(collector) {}
103 ~NetworkAnnotationTagCallback() override = default; 129 ~NetworkAnnotationTagCallback() override = default;
104 130
105 // Is called on any pattern found by ASTMathers that are defined in RunMathers 131 // Is called on any pattern found by ASTMathers that are defined in RunMathers
106 // function. 132 // function.
107 virtual void run(const MatchFinder::MatchResult& result) override { 133 virtual void run(const MatchFinder::MatchResult& result) override {
134 if (const clang::CallExpr* call_expr =
135 result.Nodes.getNodeAs<clang::CallExpr>("monitored_function")) {
136 AddFunction(call_expr, result);
137 } else {
138 AddAnnotation(result);
139 }
140 }
141
142 void GetInstanceLocation(const MatchFinder::MatchResult& result,
143 const clang::CallExpr* call_expr,
144 const clang::FunctionDecl* ancestor,
145 Location* instance_location) {
146 clang::SourceLocation source_location = call_expr->getLocStart();
147 if (source_location.isMacroID()) {
148 source_location =
149 result.SourceManager->getImmediateMacroCallerLoc(source_location);
150 }
151 instance_location->file_path =
152 result.SourceManager->getFilename(source_location);
153 instance_location->line_number =
154 result.SourceManager->getSpellingLineNumber(source_location);
155 if (ancestor)
156 instance_location->function_name = ancestor->getQualifiedNameAsString();
157 else
158 instance_location->function_name = "Global Namespace";
159
160 std::replace(instance_location->file_path.begin(),
161 instance_location->file_path.end(), '\\', '/');
162
163 // Trim leading "../"s from file path.
164 while (instance_location->file_path.length() > 3 &&
165 instance_location->file_path.substr(0, 3) == "../") {
166 instance_location->file_path = instance_location->file_path.substr(
167 3, instance_location->file_path.length() - 3);
168 }
169 }
170
171 // Stores a function call that should be monitored.
172 void AddFunction(const clang::CallExpr* call_expr,
173 const MatchFinder::MatchResult& result) {
174 CallInstance instance;
175
176 const clang::FunctionDecl* ancestor =
177 result.Nodes.getNodeAs<clang::FunctionDecl>("function_context");
178 GetInstanceLocation(result, call_expr, ancestor, &instance.location);
179 instance.called_function_name =
180 call_expr->getDirectCallee()->getQualifiedNameAsString();
181 instance.has_annotation =
182 (result.Nodes.getNodeAs<clang::RecordDecl>("annotation") != nullptr);
183 collector_->calls.push_back(instance);
184 }
185
186 // Stores an annotation.
187 void AddAnnotation(const MatchFinder::MatchResult& result) {
108 NetworkAnnotationInstance instance; 188 NetworkAnnotationInstance instance;
109 189
110 const clang::StringLiteral* unique_id = 190 const clang::StringLiteral* unique_id =
111 result.Nodes.getNodeAs<clang::StringLiteral>("unique_id"); 191 result.Nodes.getNodeAs<clang::StringLiteral>("unique_id");
112 const clang::StringLiteral* annotation_text = 192 const clang::StringLiteral* annotation_text =
113 result.Nodes.getNodeAs<clang::StringLiteral>("annotation_text"); 193 result.Nodes.getNodeAs<clang::StringLiteral>("annotation_text");
114 const clang::FunctionDecl* ancestor = 194 const clang::FunctionDecl* ancestor =
115 result.Nodes.getNodeAs<clang::FunctionDecl>("function_context"); 195 result.Nodes.getNodeAs<clang::FunctionDecl>("function_context");
116 const clang::StringLiteral* group_id = 196 const clang::StringLiteral* group_id =
117 result.Nodes.getNodeAs<clang::StringLiteral>("group_id"); 197 result.Nodes.getNodeAs<clang::StringLiteral>("group_id");
(...skipping 18 matching lines...) Expand all
136 assert(group_id); 216 assert(group_id);
137 instance.annotation.extra_id = group_id->getString(); 217 instance.annotation.extra_id = group_id->getString();
138 } else { 218 } else {
139 assert(false); 219 assert(false);
140 } 220 }
141 221
142 assert(unique_id && annotation_text); 222 assert(unique_id && annotation_text);
143 instance.annotation.unique_id = unique_id->getString(); 223 instance.annotation.unique_id = unique_id->getString();
144 instance.annotation.text = annotation_text->getString(); 224 instance.annotation.text = annotation_text->getString();
145 225
146 // Get annotation location. 226 GetInstanceLocation(result, call_expr, ancestor, &instance.location);
147 clang::SourceLocation source_location = call_expr->getLocStart();
148 if (source_location.isMacroID()) {
149 source_location =
150 result.SourceManager->getImmediateMacroCallerLoc(source_location);
151 }
152 instance.location.file_path =
153 result.SourceManager->getFilename(source_location);
154 instance.location.line_number =
155 result.SourceManager->getSpellingLineNumber(source_location);
156 if (ancestor)
157 instance.location.function_name = ancestor->getQualifiedNameAsString();
158 else
159 instance.location.function_name = "Global Namespace";
160 227
161 // Trim leading "../"s from file path. 228 collector_->annotations.push_back(instance);
162 std::replace(instance.location.file_path.begin(),
163 instance.location.file_path.end(), '\\', '/');
164 while (instance.location.file_path.length() > 3 &&
165 instance.location.file_path.substr(0, 3) == "../") {
166 instance.location.file_path = instance.location.file_path.substr(
167 3, instance.location.file_path.length() - 3);
168 }
169
170 collector_->push_back(instance);
171 } 229 }
172 230
173 private: 231 private:
174 Collector* collector_; 232 Collector* collector_;
175 }; 233 };
176 234
177 // Sets up an ASTMatcher and runs clang tool to populate collector. Returns the 235 // Sets up an ASTMatcher and runs clang tool to populate collector. Returns the
178 // result of running the clang tool. 236 // result of running the clang tool.
179 int RunMatchers(clang::tooling::ClangTool* clang_tool, Collector* collector) { 237 int RunMatchers(clang::tooling::ClangTool* clang_tool, Collector* collector) {
180 NetworkAnnotationTagCallback callback(collector); 238 NetworkAnnotationTagCallback callback(collector);
181 MatchFinder match_finder; 239 MatchFinder match_finder;
182 240
183 // Set up patterns to find network traffic annotation definition functions, 241 // Set up patterns to find network traffic annotation definition functions,
184 // their arguments, and their ancestor function (when possible). 242 // their arguments, and their ancestor function (when possible).
243 auto bind_function_context_if_present =
244 anyOf(hasAncestor(functionDecl().bind("function_context")),
245 unless(hasAncestor(functionDecl())));
246 auto has_annotation_parameter = anyOf(
247 hasAnyParameter(hasType(
248 recordDecl(anyOf(hasName("net::NetworkTrafficAnnotationTag"),
249 hasName("net::PartialNetworkTrafficAnnotationTag")))
250 .bind("annotation"))),
251 unless(hasAnyParameter(hasType(recordDecl(
252 anyOf(hasName("net::NetworkTrafficAnnotationTag"),
253 hasName("net::PartialNetworkTrafficAnnotationTag")))))));
185 match_finder.addMatcher( 254 match_finder.addMatcher(
186 callExpr(hasDeclaration(functionDecl( 255 callExpr(hasDeclaration(functionDecl(
187 anyOf(hasName("DefineNetworkTrafficAnnotation"), 256 anyOf(hasName("DefineNetworkTrafficAnnotation"),
188 hasName("net::DefineNetworkTrafficAnnotation")))), 257 hasName("net::DefineNetworkTrafficAnnotation")))),
189 hasArgument(0, stringLiteral().bind("unique_id")), 258 hasArgument(0, stringLiteral().bind("unique_id")),
190 hasArgument(1, stringLiteral().bind("annotation_text")), 259 hasArgument(1, stringLiteral().bind("annotation_text")),
191 anyOf(hasAncestor(functionDecl().bind("function_context")), 260 bind_function_context_if_present)
192 unless(hasAncestor(functionDecl()))))
193 .bind("definition_function"), 261 .bind("definition_function"),
194 &callback); 262 &callback);
195 match_finder.addMatcher( 263 match_finder.addMatcher(
196 callExpr(hasDeclaration(functionDecl(anyOf( 264 callExpr(hasDeclaration(functionDecl(anyOf(
197 hasName("DefinePartialNetworkTrafficAnnotation"), 265 hasName("DefinePartialNetworkTrafficAnnotation"),
198 hasName("net::DefinePartialNetworkTrafficAnnotation")))), 266 hasName("net::DefinePartialNetworkTrafficAnnotation")))),
199 hasArgument(0, stringLiteral().bind("unique_id")), 267 hasArgument(0, stringLiteral().bind("unique_id")),
200 hasArgument(1, stringLiteral().bind("completing_id")), 268 hasArgument(1, stringLiteral().bind("completing_id")),
201 hasArgument(2, stringLiteral().bind("annotation_text")), 269 hasArgument(2, stringLiteral().bind("annotation_text")),
202 anyOf(hasAncestor(functionDecl().bind("function_context")), 270 bind_function_context_if_present)
203 unless(hasAncestor(functionDecl()))))
204 .bind("partial_function"), 271 .bind("partial_function"),
205 &callback); 272 &callback);
206 match_finder.addMatcher( 273 match_finder.addMatcher(
207 callExpr(hasDeclaration(functionDecl( 274 callExpr(hasDeclaration(functionDecl(
208 anyOf(hasName("CompleteNetworkTrafficAnnotation"), 275 anyOf(hasName("CompleteNetworkTrafficAnnotation"),
209 hasName("net::CompleteNetworkTrafficAnnotation")))), 276 hasName("net::CompleteNetworkTrafficAnnotation")))),
210 hasArgument(0, stringLiteral().bind("unique_id")), 277 hasArgument(0, stringLiteral().bind("unique_id")),
211 hasArgument(2, stringLiteral().bind("annotation_text")), 278 hasArgument(2, stringLiteral().bind("annotation_text")),
212 anyOf(hasAncestor(functionDecl().bind("function_context")), 279 bind_function_context_if_present)
213 unless(hasAncestor(functionDecl()))))
214 .bind("completing_function"), 280 .bind("completing_function"),
215 &callback); 281 &callback);
216 match_finder.addMatcher( 282 match_finder.addMatcher(
217 callExpr(hasDeclaration(functionDecl(anyOf( 283 callExpr(hasDeclaration(functionDecl(anyOf(
218 hasName("BranchedCompleteNetworkTrafficAnnotation"), 284 hasName("BranchedCompleteNetworkTrafficAnnotation"),
219 hasName("net::BranchedCompleteNetworkTrafficAnnotation")))), 285 hasName("net::BranchedCompleteNetworkTrafficAnnotation")))),
220 hasArgument(0, stringLiteral().bind("unique_id")), 286 hasArgument(0, stringLiteral().bind("unique_id")),
221 hasArgument(1, stringLiteral().bind("group_id")), 287 hasArgument(1, stringLiteral().bind("group_id")),
222 hasArgument(3, stringLiteral().bind("annotation_text")), 288 hasArgument(3, stringLiteral().bind("annotation_text")),
223 anyOf(hasAncestor(functionDecl().bind("function_context")), 289 bind_function_context_if_present)
224 unless(hasAncestor(functionDecl()))))
225 .bind("branched_completing_function"), 290 .bind("branched_completing_function"),
226 &callback); 291 &callback);
292
293 // Setup patterns to find functions that should be monitored.
294 match_finder.addMatcher(
295 callExpr(
296 hasDeclaration(functionDecl(
297 anyOf(hasName("SSLClientSocket::SSLClientSocket"),
298 hasName("TCPClientSocket::TCPClientSocket"),
299 hasName("UDPClientSocket::UDPClientSocket"),
300 hasName("URLFetcher::Create"),
301 hasName("ClientSocketFactory::CreateDatagramClientSocket"),
302 hasName("ClientSocketFactory::CreateSSLClientSocket"),
303 hasName("ClientSocketFactory::CreateTransportClientSocket"),
304 hasName("URLRequestContext::CreateRequest")),
305 has_annotation_parameter)),
306 bind_function_context_if_present)
307 .bind("monitored_function"),
308 &callback);
309
227 std::unique_ptr<clang::tooling::FrontendActionFactory> frontend_factory = 310 std::unique_ptr<clang::tooling::FrontendActionFactory> frontend_factory =
228 clang::tooling::newFrontendActionFactory(&match_finder); 311 clang::tooling::newFrontendActionFactory(&match_finder);
229 return clang_tool->run(frontend_factory.get()); 312 return clang_tool->run(frontend_factory.get());
230 } 313 }
231 314
232 } // namespace 315 } // namespace
233 316
234 static llvm::cl::OptionCategory ToolCategory( 317 static llvm::cl::OptionCategory ToolCategory(
235 "traffic_annotation_extractor: Extract traffic annotation texts"); 318 "traffic_annotation_extractor: Extract traffic annotation texts");
236 static llvm::cl::extrahelp CommonHelp( 319 static llvm::cl::extrahelp CommonHelp(
237 clang::tooling::CommonOptionsParser::HelpMessage); 320 clang::tooling::CommonOptionsParser::HelpMessage);
238 321
239 int main(int argc, const char* argv[]) { 322 int main(int argc, const char* argv[]) {
240 clang::tooling::CommonOptionsParser options(argc, argv, ToolCategory); 323 clang::tooling::CommonOptionsParser options(argc, argv, ToolCategory);
241 clang::tooling::ClangTool tool(options.getCompilations(), 324 clang::tooling::ClangTool tool(options.getCompilations(),
242 options.getSourcePathList()); 325 options.getSourcePathList());
243 Collector collector; 326 Collector collector;
244 327
245 int result = RunMatchers(&tool, &collector); 328 int result = RunMatchers(&tool, &collector);
246 329
247 if (result != 0) 330 if (result != 0)
248 return result; 331 return result;
249 332
250 // For each call to any of the functions that define a network traffic 333 // For each call to any of the functions that define a network traffic
251 // annotation, write annotation text and relevant meta data into llvm::outs(). 334 // annotation, write annotation text and relevant meta data into llvm::outs().
252 for (const NetworkAnnotationInstance& call : collector) { 335 for (const NetworkAnnotationInstance& instance : collector.annotations) {
253 llvm::outs() << "==== NEW ANNOTATION ====\n"; 336 llvm::outs() << "==== NEW ANNOTATION ====\n";
254 llvm::outs() << call.location.file_path << "\n"; 337 llvm::outs() << instance.location.file_path << "\n";
255 llvm::outs() << call.location.function_name << "\n"; 338 llvm::outs() << instance.location.function_name << "\n";
256 llvm::outs() << call.location.line_number << "\n"; 339 llvm::outs() << instance.location.line_number << "\n";
257 llvm::outs() << call.GetTypeName() << "\n"; 340 llvm::outs() << instance.GetTypeName() << "\n";
258 llvm::outs() << call.annotation.unique_id << "\n"; 341 llvm::outs() << instance.annotation.unique_id << "\n";
259 llvm::outs() << call.annotation.extra_id << "\n"; 342 llvm::outs() << instance.annotation.extra_id << "\n";
260 llvm::outs() << call.annotation.text << "\n"; 343 llvm::outs() << instance.annotation.text << "\n";
261 llvm::outs() << "==== ANNOTATION ENDS ====\n"; 344 llvm::outs() << "==== ANNOTATION ENDS ====\n";
262 } 345 }
263 346
347 // For each call, write annotation text and relevant meta data.
348 for (const CallInstance& instance : collector.calls) {
349 llvm::outs() << "==== NEW CALL ====\n";
350 llvm::outs() << instance.location.file_path << "\n";
351 llvm::outs() << instance.location.function_name << "\n";
352 llvm::outs() << instance.location.line_number << "\n";
353 llvm::outs() << instance.called_function_name << "\n";
354 llvm::outs() << instance.has_annotation << "\n";
355 llvm::outs() << "==== CALL ENDS ====\n";
356 }
357
264 return 0; 358 return 0;
265 } 359 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698