diff options
author | Volodymyr Sapsai <vsapsai@gmail.com> | 2017-01-15 19:37:07 -0800 |
---|---|---|
committer | Volodymyr Sapsai <vsapsai@gmail.com> | 2017-01-28 16:52:02 -0800 |
commit | 4e957bf33a337f5fe5e275a354cfc46650e11ac2 (patch) | |
tree | a43b080ff0d51e6b3a5fea80464a44b8861d1fe2 | |
parent | 17642d407aa15df9639bf0f7c2ae7c5da069ec60 (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.cc | 43 |
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; |