summaryrefslogtreecommitdiffstats
path: root/tests/cxx/iwyu_stricter_than_cpp.cc
blob: d6f70d864de56a67df4c5c77b2db184d956c3307 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//===--- iwyu_stricter_than_cpp.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.
//
//===----------------------------------------------------------------------===//

// IWYU_ARGS: -Xiwyu --check_also="tests/cxx/*-autocast.h" \
//            -Xiwyu --check_also="tests/cxx/*-fnreturn.h" \
//            -Xiwyu --check_also="tests/cxx/*-typedefs.h" \
//            -Xiwyu --check_also="tests/cxx/*-d2.h" \
//            -I .

// There are a few scenarios where iwyu requires a full type but c++
// doesn't.
//
// One is in a typedef: if you write 'typedef Foo MyTypedef', iwyu
// says that you are responsible for #including "foo.h", but the
// language allows a forward-declare.
//
// Another is for 'autocast': if your function has a parameter with a
// conversion (one-arg, not-explicit) constructor, iwyu require the
// function-author to provide the full type of that parameter, but the
// language doesn't.  (It's ok with all callers providing the full
// type instead.)
//
// In each case, we can disable iwyu's rule, and force it to fall back
// on the c++ requirement (forward-declare ok), by writing the code in
// the following way:
// (1) forward-declare the relevant type
// (2) do not directly #include the definition of the relevant type.
//
// This test tests that the iwyu requirement is correctly suppressed
// when these two conditions are met, and not otherwise.

#include "tests/cxx/iwyu_stricter_than_cpp-typedefs.h"
#include "tests/cxx/iwyu_stricter_than_cpp-autocast.h"
#include "tests/cxx/iwyu_stricter_than_cpp-fnreturn.h"
// We include this so the second declaration of TwiceDeclaredFunction
// is visible in the translation unit (but not by -d2.h)
#include "tests/cxx/iwyu_stricter_than_cpp-autocast2.h"
#include "tests/cxx/iwyu_stricter_than_cpp-d2.h"

typedef DoesEverythingRight DoubleTypedef;

// If the typedef in -typedefs.h requires the full type, then users of
// that typedef (here) do not.  Otherwise, they do.
void TestTypedefs() {
  DoesNotForwardDeclare dnfd(1);
  DoesNotForwardDeclareProperly dnfdp(2);
  Includes i(3);
  DoesNotForwardDeclareAndIncludes dnfdai(4);
  // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
  DoesEverythingRight dor(5);
  // Because DoubleTypedef resolves to DoesEverythingRight, we need the
  // same things DoesEverythingRight does.
  // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
  DoubleTypedef dt(6);

  // ...and with templates.
  TplDoesNotForwardDeclare tdnfd(7);
  TplDoesNotForwardDeclareProperly tdnfdp(8);
  TplIncludes ti(9);
  TplDoesNotForwardDeclareAndIncludes tdnfdai(10);
  // IWYU: TplIndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
  TplDoesEverythingRight tdor(11);
  // IWYU: TplIndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
  TplDoesEverythingRightAgain tdora(12);

  // But if we're in a forward-declare context, we don't require the
  // underlying type!
  DoesEverythingRight* dor_ptr = 0;
  TplDoesEverythingRightAgain* tdora_ptr = 0;
  // ...at least until we dereference the pointer
  // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
  (void) dor_ptr->a;

  // TODO(csilvers): test template types where we need some (but not
  // all) of the template args as well.
}

void TestAutocast() {
  // We need full type of is2 because the declarer of Fn didn't
  // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
  Fn(1, 2, 3, 4, 5);

  // We need full type of is2 because the declarer of Fn didn't
  // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
  TplFn(6, 7, 8, 9, 10);
}

void TestFunctionReturn() {
  // In each of these cases, we bind the return value to a reference,
  // so we only need a forward-declare unless the function-author has
  // not taken responsibility for the return type.

  // IWYU: IndirectStruct1 needs a declaration
  const IndirectStruct1& is1 = DoesNotForwardDeclareFn();

  // IWYU: IndirectStructForwardDeclaredInD1 needs a declaration
  const IndirectStructForwardDeclaredInD1& isfdid1 =
      DoesNotForwardDeclareProperlyFn();

  // IWYU: DirectStruct1 needs a declaration
  const DirectStruct1& ds1 = IncludesFn();

  // IWYU: DirectStruct2 needs a declaration
  const DirectStruct2& ds2 = DoesNotForwardDeclareAndIncludesFn();

  // IWYU: IndirectStruct2 needs a declaration
  // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
  const IndirectStruct2& is2 = DoesEverythingRightFn();

  // -- And with templates.

  // IWYU: TplIndirectStruct1 needs a declaration
  const TplIndirectStruct1<int>& tis1 = TplDoesNotForwardDeclareFn();

  // IWYU: TplIndirectStructForwardDeclaredInD1 needs a declaration
  const TplIndirectStructForwardDeclaredInD1<int>& tisfdid1 =
      TplDoesNotForwardDeclareProperlyFn();

  // IWYU: TplDirectStruct1 needs a declaration
  const TplDirectStruct1<int>& tds1 = TplIncludesFn();

  // IWYU: TplDirectStruct2 needs a declaration
  const TplDirectStruct2<int>& tds2 = TplDoesNotForwardDeclareAndIncludesFn();

  // IWYU: TplIndirectStruct2 needs a declaration
  // IWYU: TplIndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
  const TplIndirectStruct2<int>& tis2 = TplDoesEverythingRightFn();

  // IWYU: TplIndirectStruct2 needs a declaration
  // IWYU: TplIndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
  const TplIndirectStruct2<float>& tis2b = TplDoesEverythingRightAgainFn();
}


/**** IWYU_SUMMARY

tests/cxx/iwyu_stricter_than_cpp.cc should add these lines:
#include "tests/cxx/iwyu_stricter_than_cpp-i2.h"
struct DirectStruct1;
struct DirectStruct2;
struct IndirectStruct1;
struct IndirectStructForwardDeclaredInD1;
template <typename T> struct TplDirectStruct1;
template <typename T> struct TplDirectStruct2;
template <typename T> struct TplIndirectStruct1;
template <typename T> struct TplIndirectStructForwardDeclaredInD1;

tests/cxx/iwyu_stricter_than_cpp.cc should remove these lines:
- #include "tests/cxx/iwyu_stricter_than_cpp-autocast2.h"  // lines XX-XX
- #include "tests/cxx/iwyu_stricter_than_cpp-d2.h"  // lines XX-XX

The full include-list for tests/cxx/iwyu_stricter_than_cpp.cc:
#include "tests/cxx/iwyu_stricter_than_cpp-autocast.h"  // for Fn, TplFn
#include "tests/cxx/iwyu_stricter_than_cpp-fnreturn.h"  // for DoesEverythingRightFn, DoesNotForwardDeclareAndIncludesFn, DoesNotForwardDeclareFn, DoesNotForwardDeclareProperlyFn, IncludesFn, TplDoesEverythingRightAgainFn, TplDoesEverythingRightFn, TplDoesNotForwardDeclareAndIncludesFn, TplDoesNotForwardDeclareFn, TplDoesNotForwardDeclareProperlyFn, TplIncludesFn
#include "tests/cxx/iwyu_stricter_than_cpp-i2.h"  // for IndirectStruct2, TplIndirectStruct2
#include "tests/cxx/iwyu_stricter_than_cpp-typedefs.h"  // for DoesEverythingRight, DoesNotForwardDeclare, DoesNotForwardDeclareAndIncludes, DoesNotForwardDeclareProperly, Includes, TplDoesEverythingRight, TplDoesEverythingRightAgain, TplDoesNotForwardDeclare, TplDoesNotForwardDeclareAndIncludes, TplDoesNotForwardDeclareProperly, TplIncludes
struct DirectStruct1;
struct DirectStruct2;
struct IndirectStruct1;
struct IndirectStructForwardDeclaredInD1;
template <typename T> struct TplDirectStruct1;
template <typename T> struct TplDirectStruct2;
template <typename T> struct TplIndirectStruct1;
template <typename T> struct TplIndirectStructForwardDeclaredInD1;

***** IWYU_SUMMARY */