Ignore uses of declarations from inside of functions
Using type deduction, a function can define a local type and return it: auto func() { struct X {}; return X(); } Before this change, IWYU would register X as a use for callers of func. In certain situations (union inside lambda inside macro) this would lead to a forward-declare use trying to format a forward-declaration of the type local to the function in PrintForwardDeclare. This led to a crash since the lambda was unnamed, but there's really no point trying to forward-declare a type that is private to a function. Generalize this so we ignore all uses of symbols declared inside a function. In order to get in contact with that symbol, we must already have access to the function, so the containing header must already be included. Fixes issue: 795
This commit is contained in:
parent
80410de523
commit
81ee985377
|
@ -1507,4 +1507,9 @@ string GetKindName(const TypeLoc typeloc) {
|
|||
return string(typeloc.getTypePtr()->getTypeClassName()) + "TypeLoc";
|
||||
}
|
||||
|
||||
bool IsDeclaredInsideFunction(const Decl* decl) {
|
||||
const DeclContext* decl_ctx = decl->getDeclContext();
|
||||
return isa<FunctionDecl>(decl_ctx);
|
||||
}
|
||||
|
||||
} // namespace include_what_you_use
|
||||
|
|
|
@ -839,6 +839,10 @@ std::string GetKindName(const clang::Stmt* stmt);
|
|||
std::string GetKindName(const clang::Type* type);
|
||||
std::string GetKindName(const clang::TypeLoc typeloc);
|
||||
|
||||
// Returns true if decl is entirely inside a function, which implies it's only
|
||||
// visible from said function.
|
||||
bool IsDeclaredInsideFunction(const clang::Decl* decl);
|
||||
|
||||
} // namespace include_what_you_use
|
||||
|
||||
#endif // INCLUDE_WHAT_YOU_USE_IWYU_AST_UTIL_H_
|
||||
|
|
|
@ -976,8 +976,9 @@ set<string> CalculateMinimalIncludes(
|
|||
// A4) If the file containing the use has a pragma inhibiting the forward
|
||||
// declaration of the symbol, change the use to a full info use in order
|
||||
// to make sure that the compiler can see some declaration of the symbol.
|
||||
// A5) If a nested class, discard this use (the parent class declaration
|
||||
// is sufficient).
|
||||
// A5) If declaration is nested inside a class or a function, discard this use.
|
||||
// The containing class/function is required to use the nested decl, and
|
||||
// so will force use of the containing header.
|
||||
// A6) If any of the redeclarations of this declaration is in the same
|
||||
// file as the use (and before it), and is actually a definition,
|
||||
// discard the forward-declare use.
|
||||
|
@ -986,7 +987,9 @@ set<string> CalculateMinimalIncludes(
|
|||
// A8) If --no_fwd_decls has been passed, recategorize as a full use.
|
||||
|
||||
// Trimming symbol uses (1st pass):
|
||||
// B1) TBD
|
||||
// B1) If declaration is nested inside a function, discard this use.
|
||||
// The function is required to use the nested decl, and so will force use of
|
||||
// the containing header.
|
||||
// B2) If the definition of a full use comes after the use, change the
|
||||
// full use to a forward-declare use that points to a fwd-decl
|
||||
// that comes before the use. (This is for cases like typedefs
|
||||
|
@ -1108,7 +1111,8 @@ void ProcessForwardDeclare(OneUse* use,
|
|||
}
|
||||
}
|
||||
|
||||
// (A5) If using a nested class, discard this use.
|
||||
// (A5) If using a nested class or a type declared inside a function, discard
|
||||
// this use.
|
||||
if (IsNestedClass(tag_decl)) {
|
||||
// iwyu will require the full type of the parent class when it
|
||||
// recurses on the qualifier (any use of Foo::Bar requires the
|
||||
|
@ -1127,6 +1131,12 @@ void ProcessForwardDeclare(OneUse* use,
|
|||
use->set_ignore_use();
|
||||
return;
|
||||
}
|
||||
} else if (IsDeclaredInsideFunction(tag_decl)) {
|
||||
VERRS(6) << "Ignoring fwd-decl use of " << use->symbol_name() << " ("
|
||||
<< use->PrintableUseLoc() << "): declared inside a "
|
||||
<< "function\n";
|
||||
use->set_ignore_use();
|
||||
return;
|
||||
}
|
||||
|
||||
// (A6) If a definition exists earlier in this file, discard this use.
|
||||
|
@ -1197,6 +1207,16 @@ void ProcessFullUse(OneUse* use,
|
|||
if (use->ignore_use()) // we're already ignoring it
|
||||
return;
|
||||
|
||||
// (B1) If declaration is inside a function, it can only be seen via said
|
||||
// function. Discard this use and assume the use of the function provides.
|
||||
if (IsDeclaredInsideFunction(use->decl())) {
|
||||
VERRS(6) << "Ignoring full use of " << use->symbol_name() << " ("
|
||||
<< use->PrintableUseLoc() << "): declared inside a "
|
||||
<< "function\n";
|
||||
use->set_ignore_use();
|
||||
return;
|
||||
}
|
||||
|
||||
// We normally ignore uses for builtins, but when there is a mapping defined
|
||||
// for the symbol, we should respect that. So, we need to determine whether
|
||||
// the symbol has any mappings.
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
//===--- decl_inside_func-d1.h - test input file for iwyu -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "tests/cxx/decl_inside_func-i1.h"
|
|
@ -0,0 +1,34 @@
|
|||
//===--- decl_inside_func-i1.h - test input file for iwyu -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Reduced/derived/copied from Quill 1.6.3:
|
||||
// https://github.com/odygrd/quill/blob/v1.6.3/quill/include/quill/PatternFormatter.h#L35
|
||||
|
||||
// This macro defines a lambda containing a function-local declaration of a
|
||||
// union X, which is cleverly returned from the lambda.
|
||||
//
|
||||
// Declarations inside a function are only directly visible from the function
|
||||
// itself, so any uses of X should be ignored -- the only way to get in any
|
||||
// contact with X is to use MACRO, so this header will be desired already.
|
||||
|
||||
#define MACRO(str) \
|
||||
[] { \
|
||||
union X { \
|
||||
static constexpr auto value() { \
|
||||
return str; \
|
||||
} \
|
||||
}; \
|
||||
return X{}; \
|
||||
}()
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
(tests/cxx/decl_inside_func-i1.h has correct #includes/fwd-decls)
|
||||
|
||||
***** IWYU_SUMMARY */
|
|
@ -0,0 +1,41 @@
|
|||
//===--- decl_inside_func.cc - test input file for iwyu -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// A declaration inside a function can sometimes escape (see implementation of
|
||||
// MACRO), and while such a declaration may look like it's independently used
|
||||
// here, the only way to make contact with it is through its containing
|
||||
// function.
|
||||
// Since we must have a declaration of _the function_ in order to call it, the
|
||||
// contained declaration will have followed along and we can ignore any direct
|
||||
// uses of the contained decl.
|
||||
// This used to lead to the contained declaration being fwd-decl used, and IWYU
|
||||
// crashing when trying to format a printable forward-decl. Ignoring it
|
||||
// completely avoids that malfunction.
|
||||
|
||||
// IWYU_ARGS: -I . -Xiwyu --check_also="tests/cxx/decl_inside_func-i1.h"
|
||||
|
||||
#include "tests/cxx/decl_inside_func-d1.h"
|
||||
|
||||
const char* f() {
|
||||
// IWYU: MACRO is ...*decl_inside_func-i1.h
|
||||
return MACRO("bleh").value();
|
||||
}
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/decl_inside_func.cc should add these lines:
|
||||
#include "tests/cxx/decl_inside_func-i1.h"
|
||||
|
||||
tests/cxx/decl_inside_func.cc should remove these lines:
|
||||
- #include "tests/cxx/decl_inside_func-d1.h" // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/decl_inside_func.cc:
|
||||
#include "tests/cxx/decl_inside_func-i1.h" // for MACRO
|
||||
|
||||
***** IWYU_SUMMARY */
|
Loading…
Reference in New Issue