summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolodymyr Sapsai <vsapsai@gmail.com>2017-01-15 19:37:07 -0800
committerVolodymyr Sapsai <vsapsai@gmail.com>2017-01-28 16:52:02 -0800
commit4e957bf33a337f5fe5e275a354cfc46650e11ac2 (patch)
treea43b080ff0d51e6b3a5fea80464a44b8861d1fe2
parent17642d407aa15df9639bf0f7c2ae7c5da069ec60 (diff)
Fix GetFirstClassArgument.
Check function parameters types instead of types of arguments at call site. This way we are able to detect template substitutions for the function itself, not for the caller. PR https://github.com/include-what-you-use/include-what-you-use/pull/399
-rw-r--r--iwyu_ast_util.cc43
1 files changed, 29 insertions, 14 deletions
diff --git a/iwyu_ast_util.cc b/iwyu_ast_util.cc
index 405909f..8ff8420 100644
--- a/iwyu_ast_util.cc
+++ b/iwyu_ast_util.cc
@@ -1266,20 +1266,35 @@ const Type* TypeOfParentIfMethod(const CallExpr* expr) {
}
const Expr* GetFirstClassArgument(CallExpr* expr) {
- for (CallExpr::arg_iterator it = expr->arg_begin();
- it != expr->arg_end(); ++it) {
- const Type* argtype = GetTypeOf(*it);
- // Make sure we do the right thing given a function like
- // template <typename T> void operator>>(const T& x, ostream& os);
- // In this case ('myclass >> os'), we want to be returning the
- // type of os, not of myclass, and we do, because myclass will be
- // a SubstTemplateTypeParmType, not a RecordType.
- if (isa<SubstTemplateTypeParmType>(argtype))
- continue;
- argtype = argtype->getUnqualifiedDesugaredType(); // see through typedefs
- if (isa<RecordType>(argtype) ||
- isa<TemplateSpecializationType>(argtype)) {
- return *it;
+ if (const FunctionDecl* callee_decl = expr->getDirectCallee()) {
+ if (isa<CXXMethodDecl>(callee_decl)) {
+ // If a method is called, return 'this'.
+ return expr->getArg(0);
+ }
+ // Handle free functions.
+ CHECK_(callee_decl->getNumParams() == expr->getNumArgs() &&
+ "Require one-to-one match between call arguments and decl parameters");
+ int params_count = callee_decl->getNumParams();
+ for (int i = 0; i < params_count; i++) {
+ // View argument types from the perspective of function declaration,
+ // not from the caller's perspective. For example, function parameter
+ // can have template type but function argument is not necessarily
+ // a template when the function is called.
+ const Type* param_type = GetTypeOf(callee_decl->getParamDecl(i));
+ param_type = RemovePointersAndReferencesAsWritten(param_type);
+ // Make sure we do the right thing given a function like
+ // template <typename T> void operator>>(const T& x, ostream& os);
+ // In this case ('myclass >> os'), we want to be returning the
+ // type of os, not of myclass, and we do, because myclass will be
+ // a SubstTemplateTypeParmType, not a RecordType.
+ if (isa<SubstTemplateTypeParmType>(param_type))
+ continue;
+ // See through typedefs.
+ param_type = param_type->getUnqualifiedDesugaredType();
+ if (isa<RecordType>(param_type) ||
+ isa<TemplateSpecializationType>(param_type)) {
+ return expr->getArg(i);
+ }
}
}
return nullptr;