Stop ignoring uses for builtins with mappings

IWYU used to ignore all uses of builtins.

This makes sense normally.  However, when a symbol has an explicit
mapping defined, we should not ignore uses of it.

In particular, for example, one might require a particular header to be
included when certain builtins are used, and this change allows that by
defining a mapping for that builtin.

Also, under some situations some standard library functions (e.g.
std::round) get treated as builtins.  With this change IWYU respects
mappings for such builtins, and by defining them suitably it will no
longer remove #include <cmath>.
This commit is contained in:
John Bytheway 2019-03-07 21:55:44 +00:00 committed by Kim Gräsman
parent 33b7ce7500
commit e00e5f1f09
6 changed files with 117 additions and 3 deletions

View File

@ -1111,6 +1111,11 @@ void ProcessForwardDeclare(OneUse* use,
}
}
// Returns true if the given symbol has a mapping defined to a file.
static bool HasMapping(const string& symbol) {
return !GlobalIncludePicker().GetCandidateHeadersForSymbol(symbol).empty();
}
void ProcessFullUse(OneUse* use,
const IwyuPreprocessorInfo* preprocessor_info) {
CHECK_(use->decl() && "Must call ProcessFullUse on a decl");
@ -1118,6 +1123,14 @@ void ProcessFullUse(OneUse* use,
if (use->ignore_use()) // we're already ignoring it
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.
bool is_builtin_function = IsBuiltinFunction(use->decl(), use->symbol_name());
bool is_builtin_function_with_mappings =
is_builtin_function && HasMapping(use->symbol_name());
// (B1) If the definition is after the use, re-point to a prior decl.
// If iwyu followed the language precisely, this wouldn't be
// necessary: code wouldn't compile if a full-use didn't have the
@ -1162,7 +1175,7 @@ void ProcessFullUse(OneUse* use,
// All this is moot when FunctionDecls are being defined, all their redecls
// are separately registered as uses so that a definition anchors all its
// declarations.
if (!use->is_function_being_defined()) {
if (!use->is_function_being_defined() && !is_builtin_function_with_mappings) {
set<const NamedDecl*> all_redecls;
if (isa<RecordDecl>(use->decl()) || isa<ClassTemplateDecl>(use->decl()))
all_redecls.insert(use->decl()); // for classes, just consider the dfn
@ -1188,7 +1201,7 @@ void ProcessFullUse(OneUse* use,
return;
}
// A compiler builtin without a predefined header file (e.g. __builtin_..)
if (IsBuiltinFunction(use->decl(), use->symbol_name()) {
if (is_builtin_function && !is_builtin_function_with_mappings) {
VERRS(6) << "Ignoring use of " << use->symbol_name()
<< " (" << use->PrintableUseLoc() << "): built-in function\n";
use->set_ignore_use();
@ -1254,7 +1267,8 @@ void ProcessFullUse(OneUse* use,
// the language requires).
// TODO(csilvers): remove this when we resolve the bugs with macros/typedefs.
if (preprocessor_info->FileTransitivelyIncludes(
GetFileEntry(use->decl()), GetFileEntry(use->use_loc()))) {
GetFileEntry(use->decl()), GetFileEntry(use->use_loc())) &&
!is_builtin_function_with_mappings) {
VERRS(6) << "Ignoring use of " << use->symbol_name()
<< " (" << use->PrintableUseLoc() << "): 'backwards' #include\n";
use->set_ignore_use();

View File

@ -63,6 +63,7 @@ class OneIwyuTest(unittest.TestCase):
flags_map = {
'backwards_includes.cc': [self.CheckAlsoExtension('-d*.h')],
'badinc.cc': [self.MappingFile('badinc.imp')],
'built_ins_with_mapping.cc': [self.MappingFile('built_ins_with_mapping.imp')],
'check_also.cc': [self.CheckAlsoExtension('-d1.h')],
'implicit_ctor.cc': [self.CheckAlsoExtension('-d1.h')],
'iwyu_stricter_than_cpp.cc': [self.CheckAlsoExtension('-autocast.h'),
@ -125,6 +126,7 @@ class OneIwyuTest(unittest.TestCase):
'backwards_includes.cc': ['.'],
'badinc.cc': ['.'],
'badinc-extradef.cc': ['.'],
'built_ins_with_mapping.cc': ['.'],
'funcptrs.cc': ['.'],
'casts.cc': ['.'],
'catch.cc': ['.'],

View File

@ -0,0 +1,15 @@
//===--- built_ins_with_mapping-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.
//
//===----------------------------------------------------------------------===//
#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_BUILT_INS_WITH_MAPPING_D1_H_
#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_BUILT_INS_WITH_MAPPING_D1_H_
int i = __builtin_expect(0, 0);
#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_BUILT_INS_WITH_MAPPING_D1_H_

View File

@ -0,0 +1,40 @@
//===--- built_ins_with_mapping.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.
//
//===----------------------------------------------------------------------===//
#include "tests/cxx/built_ins_with_mapping.h"
#include "tests/cxx/built_ins_with_mapping-d1.h"
// Normally if we use a builtin function IWYU will ignore uses of it.
// However, if there is a mapping defined for that builtin then it should be
// respected.
// Clang considers the definition of a builtin to be at its first use, so we
// have two test cases:
// First test case for a builtin which was already used in a header we included
// IWYU: __builtin_expect is defined in...*which isn't directly #included.
int j = __builtin_expect(i, 0);
// Second test case for a first use of a builtin
// IWYU: __builtin_strlen is defined in...*which isn't directly #included.
int k = __builtin_strlen("");
/**** IWYU_SUMMARY
tests/cxx/built_ins_with_mapping.cc should add these lines:
#include "tests/cxx/built_ins_with_mapping-d2.h"
#include "tests/cxx/built_ins_with_mapping-d3.h"
tests/cxx/built_ins_with_mapping.cc should remove these lines:
The full include-list for tests/cxx/built_ins_with_mapping.cc:
#include "tests/cxx/built_ins_with_mapping.h"
#include "tests/cxx/built_ins_with_mapping-d1.h" // for i
#include "tests/cxx/built_ins_with_mapping-d2.h" // for __builtin_expect
#include "tests/cxx/built_ins_with_mapping-d3.h" // for __builtin_strlen
***** IWYU_SUMMARY */

View File

@ -0,0 +1,34 @@
//===--- built_ins_with_mapping.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.
//
//===----------------------------------------------------------------------===//
#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_BUILT_INS_WITH_MAPPING_H_
#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_BUILT_INS_WITH_MAPPING_H_
// This is to simulate the situation where a builtin exists on some compilers,
// and not others, so we need a mapping. However, we need to check that the
// header mapped to (this header, in this case) is not forced to include itself
// if it uses that builtin.
void __builtin_invented_for_test();
inline void f()
{
// A regular function mapped to this file
__builtin_invented_for_test();
// A builtin mapped to this file
__builtin_strcmp("", "");
}
#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_BUILT_INS_WITH_MAPPING_H_
/**** IWYU_SUMMARY
(tests/cxx/built_ins_with_mapping.h has correct #includes/fwd-decls)
***** IWYU_SUMMARY */

View File

@ -0,0 +1,9 @@
# Header mappings for IWYU tests.
# Note that some headers listed here don't actually exist; we just want
# IWYU to suggest using them
[
{ symbol: ["__builtin_expect", "private", "\"tests/cxx/built_ins_with_mapping-d2.h\"", "public"] },
{ symbol: ["__builtin_strlen", "private", "\"tests/cxx/built_ins_with_mapping-d3.h\"", "public"] },
{ symbol: ["__builtin_strcmp", "private", "\"tests/cxx/built_ins_with_mapping.h\"", "public"] },
{ symbol: ["__builtin_invented_for_test", "private", "\"tests/cxx/built_ins_with_mapping.h\"", "public"] },
]