4493 lines
124 KiB
Python
Executable File
4493 lines
124 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
##===--- fix_includes_test.py - test for fix_includes.py ------------------===##
|
|
#
|
|
# The LLVM Compiler Infrastructure
|
|
#
|
|
# This file is distributed under the University of Illinois Open Source
|
|
# License. See LICENSE.TXT for details.
|
|
#
|
|
##===----------------------------------------------------------------------===##
|
|
|
|
from __future__ import print_function
|
|
|
|
"""Test for fix_includes.py
|
|
|
|
Test test test!
|
|
"""
|
|
|
|
__author__ = 'csilvers@google.com (Craig Silverstein)'
|
|
|
|
try:
|
|
from cStringIO import StringIO
|
|
except ImportError:
|
|
from io import StringIO
|
|
|
|
import re
|
|
import sys
|
|
# I use unittest instead of googletest to ease opensourcing.
|
|
import unittest
|
|
import fix_includes
|
|
|
|
|
|
class FakeFlags(object):
|
|
def __init__(self):
|
|
self.blank_lines = False
|
|
self.comments = True
|
|
self.update_comments = False
|
|
self.dry_run = False
|
|
self.ignore_re = None
|
|
self.only_re = None
|
|
self.safe_headers = False
|
|
self.separate_project_includes = None
|
|
self.keep_iwyu_namespace_format = False
|
|
self.reorder = True
|
|
self.basedir = None
|
|
|
|
|
|
class FixIncludesBase(unittest.TestCase):
|
|
"""Does setup that every test will want."""
|
|
|
|
def _ReadFile(self, filename, fileinfo):
|
|
assert filename in self.before_map, filename
|
|
return self.before_map[filename]
|
|
|
|
def _ParseFileInfo(self, filename):
|
|
return fix_includes.FileInfo('\n', 'utf-8')
|
|
|
|
def _WriteFile(self, filename, fileinfo, contents):
|
|
return self.actual_after_contents.extend(contents)
|
|
|
|
def setUp(self):
|
|
self.flags = FakeFlags()
|
|
|
|
# Map from filename to its contents (a list of lines) before fixing.
|
|
self.before_map = {}
|
|
# Map from filename to the 'correct' contents it should have after fixing.
|
|
self.expected_after_map = {}
|
|
|
|
# INPUT: fix_includes._ReadFile takes a filename
|
|
# and returns the contents of filename (as a list).
|
|
# FileInfo controls encoding details of the file,
|
|
# wire it to return something that agrees with the
|
|
# tests.
|
|
fix_includes._ReadFile = self._ReadFile
|
|
fix_includes.FileInfo.parse = self._ParseFileInfo
|
|
|
|
# OUTPUT: Instead of writing to file, save full output.
|
|
self.actual_after_contents = []
|
|
fix_includes._WriteFile = self._WriteFile
|
|
|
|
# Stub out stdout
|
|
self.stdout_stub = StringIO()
|
|
fix_includes.sys.stdout = self.stdout_stub
|
|
|
|
def RegisterFileContents(self, file_contents_map):
|
|
"""Parses and stores the given map from filename to file-contents.
|
|
|
|
The values of the map are file 'contents', written in a simple
|
|
markup language that allows us to encode both the 'before' and
|
|
expected 'after' contents of a file. Every line is taken
|
|
literally to be in both the before and after, with the following
|
|
exceptions:
|
|
1) Lines that look like '///+foo' are removed from 'before',
|
|
and replaced by 'foo' in 'after'. (This is an 'add'
|
|
instruction.)
|
|
2) Lines that end in '///-' are removed from both 'after'
|
|
and the '\s*///-' suffix is removed from 'before'.
|
|
(This is a 'remove' instruction.)
|
|
|
|
This function processes the input map to produce self.before_map
|
|
and self.expected_after_map.
|
|
|
|
Arguments:
|
|
file_contents_map: a map from filename to 'contents'. Contents
|
|
is a string, having the format mentioned above.
|
|
"""
|
|
remove_re = re.compile('\s*///-$')
|
|
for (filename, contents) in file_contents_map.items():
|
|
before_contents = []
|
|
expected_after_contents = []
|
|
for line in contents.splitlines(True):
|
|
m = remove_re.search(line)
|
|
if m:
|
|
# The trailing line separator is stripped, so append a '\n'.
|
|
before_contents.append(line[:m.start()] + '\n')
|
|
elif line.startswith('///+'):
|
|
expected_after_contents.append(line[len('///+'):])
|
|
else:
|
|
before_contents.append(line)
|
|
expected_after_contents.append(line)
|
|
self.before_map[filename] = before_contents
|
|
self.expected_after_map[filename] = expected_after_contents
|
|
|
|
def ProcessAndTest(self, iwyu_output, cmdline_files=None, unedited_files=[],
|
|
expected_num_modified_files=None, cwd=None):
|
|
"""For all files mentioned in iwyu_output, compare expected and actual.
|
|
|
|
Arguments:
|
|
iwyu_output: the output the iwyu script gave when run over the
|
|
set of input files.
|
|
cmdline_files: files to pass in to ProcessIWYUOutput (that, in
|
|
an actual fix_includes run, would come from the commandline).
|
|
These limit what files fix_includes chooses to edit.
|
|
unedited_files: the list of files that are listed in iwyu_output,
|
|
but fix_files has chosen not to edit for some reason.
|
|
expected_num_modified_files: what we expect ProcessIWYUOutput to
|
|
return. If None, suppress this check.
|
|
cwd: working directory passed to ProcessIWYUOutput, used to normalize
|
|
paths in cmdline_files. If None, no normalization occurs.
|
|
"""
|
|
filenames = re.findall('^(\S+) should add these lines:', iwyu_output, re.M)
|
|
if not filenames: # This is the other possible starting-line
|
|
filenames = re.findall('^\((\S+) has correct #includes/fwd-decls\)',
|
|
iwyu_output, re.M)
|
|
|
|
expected_after = []
|
|
for filename in fix_includes.OrderedSet(filenames): # uniquify
|
|
filename = fix_includes.NormalizeFilePath(self.flags.basedir, filename)
|
|
if filename not in unedited_files:
|
|
expected_after.extend(self.expected_after_map[filename])
|
|
|
|
iwyu_output_as_file = StringIO(iwyu_output)
|
|
num_modified_files = fix_includes.ProcessIWYUOutput(iwyu_output_as_file,
|
|
cmdline_files,
|
|
self.flags,
|
|
cwd=cwd)
|
|
|
|
if expected_after != self.actual_after_contents:
|
|
print("=== Expected:")
|
|
for line in expected_after:
|
|
print(line)
|
|
print("=== Got:")
|
|
for line in self.actual_after_contents:
|
|
print(line)
|
|
print("===")
|
|
self.assertListEqual(expected_after, self.actual_after_contents)
|
|
if expected_num_modified_files is not None:
|
|
self.assertEqual(expected_num_modified_files, num_modified_files)
|
|
|
|
|
|
class FixIncludesTest(FixIncludesBase):
|
|
"""End-to-end tests from input file to output file."""
|
|
|
|
def testSimple(self):
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
simple should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
simple should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for simple:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'simple': infile})
|
|
self.ProcessAndTest(iwyu_output, expected_num_modified_files=1)
|
|
|
|
def testUnifiedDiffOutput(self):
|
|
"""Test the unified diff output generated by dry runs."""
|
|
infile = """
|
|
#include <notused.h>
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
unified_diff.cc should add these lines:
|
|
|
|
unified_diff.cc should remove these lines:
|
|
- #include <notused.h> // lines 2-2
|
|
|
|
The full include-list for unified_diff.cc:
|
|
---
|
|
"""
|
|
diff_expect = """\
|
|
>>> Fixing #includes in 'unified_diff.cc'
|
|
@@ -1,4 +1,2 @@
|
|
-
|
|
-#include <notused.h>
|
|
|
|
int main() { return 0; }
|
|
IWYU edited 1 files on your behalf.
|
|
|
|
"""
|
|
|
|
self.flags.dry_run = True
|
|
self.RegisterFileContents({'unified_diff.cc': infile})
|
|
self.ProcessAndTest(iwyu_output, unedited_files=['unified_diff.cc'])
|
|
|
|
self.assertEqual(self.stdout_stub.getvalue(), diff_expect)
|
|
|
|
def testNodiffOutput(self):
|
|
"""Tests handling of the '(<file> has correct #includes)' iwyu output."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h> // iwyu will not reorder, even though non-alphabetical
|
|
|
|
namespace Foo;
|
|
|
|
namespace Bar;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = "(nodiffs.h has correct #includes/fwd-decls)\n"
|
|
self.RegisterFileContents({'nodiffs.h': infile})
|
|
# fix_includes gives special output when there are no changes, so
|
|
# we can't use the normal ProcessAndTest.
|
|
iwyu_output_as_file = StringIO(iwyu_output)
|
|
num_modified_files = fix_includes.ProcessIWYUOutput(iwyu_output_as_file,
|
|
None, self.flags, None)
|
|
self.assertListEqual([], self.actual_after_contents) # 'no diffs'
|
|
self.assertEqual(0, num_modified_files)
|
|
|
|
def testNodiffOutputWithNoSorting(self):
|
|
"""Tests 'correct #includes' iwyu output, but does not need reordering."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
|
|
namespace Foo;
|
|
|
|
namespace Bar;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = "(nodiffs_nosorting.h has correct #includes/fwd-decls)\n"
|
|
self.RegisterFileContents({'nodiffs_nosorting.h': infile})
|
|
# fix_includes gives special output when there are no changes, so
|
|
# we can't use the normal ProcessAndTest.
|
|
iwyu_output_as_file = StringIO(iwyu_output)
|
|
num_modified_files = fix_includes.ProcessIWYUOutput(iwyu_output_as_file,
|
|
None, self.flags, None)
|
|
self.assertListEqual([], self.actual_after_contents) # 'no diffs'
|
|
self.assertEqual(0, num_modified_files)
|
|
|
|
def testRemoveEmptyNamespace(self):
|
|
"""Tests we remove a namespace if we remove all fwd-decls inside it."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <stdio.h>
|
|
|
|
namespace ns { ///-
|
|
class Foo; ///-
|
|
namespace ns2 { ///-
|
|
namespace ns3 { ///-
|
|
class Bar; ///-
|
|
} } ///-
|
|
class Baz; ///-
|
|
} ///-
|
|
///-
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
empty_namespace should add these lines:
|
|
|
|
empty_namespace should remove these lines:
|
|
- class Foo; // lines 6-6
|
|
- namespace ns { namespace ns2 { namespace ns3 { class Bar; } } } // lines 9-9
|
|
- namespace ns { class Baz; } } // lines 11-11
|
|
|
|
The full include-list for empty_namespace:
|
|
#include <stdio.h>
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'empty_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemoveEmptyAllmanNamespace(self):
|
|
"""Tests we remove a namespace with Allman braces if we remove all fwd-decls inside it."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <stdio.h>
|
|
|
|
namespace ns ///-
|
|
{ ///-
|
|
class Foo; ///-
|
|
namespace ns2 ///-
|
|
{ ///-
|
|
namespace ns3 ///-
|
|
{ ///-
|
|
class Bar; ///-
|
|
} ///-
|
|
} ///-
|
|
class Baz; ///-
|
|
} ///-
|
|
///-
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
empty_namespace should add these lines:
|
|
|
|
empty_namespace should remove these lines:
|
|
- class Foo; // lines 7-7
|
|
- namespace ns { namespace ns2 { namespace ns3 { class Bar; } } } // lines 12-12
|
|
- namespace ns { class Baz; } } // lines 15-15
|
|
|
|
The full include-list for empty_namespace:
|
|
#include <stdio.h>
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'empty_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemoveEmptyMixedNamespace(self):
|
|
"""Tests we remove a namespace with mixed braces if we remove all fwd-decls inside it."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <stdio.h>
|
|
|
|
namespace ns ///-
|
|
{ ///-
|
|
class Foo; ///-
|
|
namespace ns2 { namespace ns3 ///-
|
|
{ ///-
|
|
class Bar; ///-
|
|
} ///-
|
|
} ///-
|
|
class Baz; ///-
|
|
} ///-
|
|
///-
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
empty_namespace should add these lines:
|
|
|
|
empty_namespace should remove these lines:
|
|
- class Foo; // lines 7-7
|
|
- namespace ns { namespace ns2 { namespace ns3 { class Bar; } } } // lines 10-10
|
|
- namespace ns { class Baz; } } // lines 13-13
|
|
|
|
The full include-list for empty_namespace:
|
|
#include <stdio.h>
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'empty_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testCXX17NS(self):
|
|
"""Tests handling of output using the --cxx17ns switch."""
|
|
infile = """\
|
|
#include "cxx17ns-i1.h"///-
|
|
///+
|
|
///+namespace a::b::c {
|
|
///+struct One;
|
|
///+} // namespace a::b::c
|
|
///+namespace a::b {
|
|
///+struct One2;
|
|
///+} // namespace a::b
|
|
///+namespace a {
|
|
///+struct One4;
|
|
///+struct One3;
|
|
///+} // namespace a
|
|
|
|
struct Two {
|
|
Two(a::b::c::One& one);
|
|
Two(a::b::One2& one);
|
|
Two(a::One3& one);
|
|
Two(a::One4& one);
|
|
};
|
|
"""
|
|
iwyu_output = """\
|
|
cxx17ns.cc should add these lines:
|
|
namespace a { namespace { struct One4; } }
|
|
namespace a { struct One3; }
|
|
namespace a::b { struct One2; }
|
|
namespace a::b::c { struct One; }
|
|
|
|
cxx17ns.cc should remove these lines:
|
|
- #include "cxx17ns-i1.h" // lines 1-1
|
|
|
|
The full include-list for cxx17ns.cc:
|
|
namespace a { namespace { struct One4; } }
|
|
namespace a { struct One3; }
|
|
namespace a::b { struct One2; }
|
|
namespace a::b::c { struct One; }
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'cxx17ns.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testNamespaceAlias(self):
|
|
"""Tests we leave namespace aliases alone."""
|
|
infile = """\
|
|
#include <stdint.h> ///-
|
|
|
|
namespace outer {
|
|
namespace middle {
|
|
namespace inner {
|
|
|
|
enum Values {
|
|
VAL
|
|
};
|
|
|
|
} // namespace inner
|
|
} // namespace middle
|
|
|
|
// This alias should not be mistaken for an Allman namespace dfn
|
|
namespace inner = middle::inner;
|
|
|
|
} // namespace outer
|
|
"""
|
|
iwyu_output = """\
|
|
namespace_alias.cc should add these lines:
|
|
|
|
namespace_alias.cc should remove these lines:
|
|
- #include <stdint.h> // lines 1-1
|
|
|
|
The full include-list for namespace_alias.cc:
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'namespace_alias.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemovePartOfEmptyNamespace(self):
|
|
"""Tests we remove a namespace if empty, but not enclosing namespaces."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
namespace maps_transit_realtime {
|
|
namespace service_alerts {
|
|
class StaticServiceAlertStore;
|
|
namespace trigger { ///-
|
|
class Trigger; ///-
|
|
} // namespace trigger ///-
|
|
namespace ui { ///-
|
|
class Alert; ///-
|
|
} // namespace ui ///-
|
|
} // namespace service_alerts
|
|
} // namespace maps_transit_realtime
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
empty_internal_namespace should add these lines:
|
|
|
|
empty_internal_namespace should remove these lines:
|
|
- namespace maps_transit_realtime { namespace service_alerts { namespace trigger { class Trigger; } } } // lines 7-7
|
|
- namespace maps_transit_realtime { namespace service_alerts { namespace ui { class Alert; } } } // lines 10-10
|
|
|
|
The full include-list for empty_internal_namespace:
|
|
namespace maps_transit_realtime { namespace service_alerts { class StaticServiceAlertStore; } } // lines 5-5
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'empty_internal_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemovePartOfEmptyAllmanNamespace(self):
|
|
"""Tests we remove a namespace with Allman braces if empty, but not enclosing namespaces."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
namespace maps_transit_realtime
|
|
{
|
|
namespace service_alerts
|
|
{
|
|
class StaticServiceAlertStore;
|
|
namespace trigger ///-
|
|
{ ///-
|
|
class Trigger; ///-
|
|
} // namespace trigger ///-
|
|
namespace ui ///-
|
|
{ ///-
|
|
class Alert; ///-
|
|
} // namespace ui ///-
|
|
} // namespace service_alerts
|
|
} // namespace maps_transit_realtime
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
empty_internal_namespace should add these lines:
|
|
|
|
empty_internal_namespace should remove these lines:
|
|
- namespace maps_transit_realtime { namespace service_alerts { namespace trigger { class Trigger; } } } // lines 10-10
|
|
- namespace maps_transit_realtime { namespace service_alerts { namespace ui { class Alert; } } } // lines 14-14
|
|
|
|
The full include-list for empty_internal_namespace:
|
|
namespace maps_transit_realtime { namespace service_alerts { class StaticServiceAlertStore; } } // lines 7-7
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'empty_internal_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemovePartOfEmptyMixedNamespace(self):
|
|
"""Tests we remove a namespace with mixed braces if empty, but not enclosing namespaces."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
namespace maps_transit_realtime
|
|
{
|
|
class StaticServiceAlertStore;
|
|
namespace service_alerts { namespace trigger ///-
|
|
{ ///-
|
|
class Trigger; ///-
|
|
} // namespace trigger ///-
|
|
namespace ui ///-
|
|
{ ///-
|
|
class Alert; ///-
|
|
} // namespace ui ///-
|
|
} // namespace service_alerts ///-
|
|
} // namespace maps_transit_realtime
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
empty_internal_namespace should add these lines:
|
|
|
|
empty_internal_namespace should remove these lines:
|
|
- namespace maps_transit_realtime { namespace service_alerts { namespace trigger { class Trigger; } } } // lines 8-8
|
|
- namespace maps_transit_realtime { namespace service_alerts { namespace ui { class Alert; } } } // lines 12-12
|
|
|
|
The full include-list for empty_internal_namespace:
|
|
namespace maps_transit_realtime { class StaticServiceAlertStore; } // lines 5-5
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'empty_internal_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemoveEmptyIfdef(self):
|
|
"""Tests we remove an #ifdef if we remove all #includes inside it."""
|
|
# Also makes sure we reorder properly around the removed ifdef.
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <stdio.h>
|
|
///+#include <stdlib.h>
|
|
// Only on windows. ///-
|
|
#ifdef OS_WINDOWS ///-
|
|
#include <notused.h> ///-
|
|
#include <notused2.h> ///-
|
|
#endif ///-
|
|
#include "used.h"
|
|
#include <stdlib.h> ///-
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
empty_ifdef should add these lines:
|
|
#include "used2.h"
|
|
|
|
empty_ifdef should remove these lines:
|
|
- #include <notused.h> // lines 6-6
|
|
- #include <notused2.h> // lines 7-7
|
|
|
|
The full include-list for empty_ifdef:
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'empty_ifdef': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemoveEmptyNestedIfdef(self):
|
|
"""Tests we remove an empty #ifdef inside a non-empty #ifdef."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <stdio.h>
|
|
#ifdef NDEBUG
|
|
// Only on windows. ///-
|
|
# ifdef OS_WINDOWS ///-
|
|
# include <notused.h> ///-
|
|
# include <notused2.h> ///-
|
|
# endif ///-
|
|
# undef VERBOSE_LOGGING
|
|
#endif
|
|
///+#include <stdlib.h>
|
|
#include "used.h"
|
|
#include <stdlib.h> ///-
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
empty_nested_ifdef should add these lines:
|
|
#include "used2.h"
|
|
|
|
empty_nested_ifdef should remove these lines:
|
|
- #include <notused.h> // lines 7-7
|
|
- #include <notused2.h> // lines 8-8
|
|
|
|
The full include-list for empty_nested_ifdef:
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'empty_nested_ifdef': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testNonEmptyIfdef(self):
|
|
"""Tests we keep an #ifdef if we don't remove all #includes inside it."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <stdio.h>
|
|
#ifdef OS_WINDOWS
|
|
#include <notused.h> ///-
|
|
#include <used_win.h>
|
|
#endif
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
nonempty_ifdef should add these lines:
|
|
#include "used2.h"
|
|
|
|
nonempty_ifdef should remove these lines:
|
|
- #include <notused.h> // lines 5-5
|
|
|
|
The full include-list for nonempty_ifdef:
|
|
#include <used_win.h>
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'nonempty_ifdef': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testKeepIfdefsWithNonIncludes(self):
|
|
"""Tests we keep an #ifdef if we have a non-#include inside it."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <stdio.h>
|
|
#ifdef OS_WINDOWS
|
|
#define IN_WINDOWS
|
|
#include <notused.h> ///-
|
|
#endif
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
nonempty_ifdef should add these lines:
|
|
#include "used2.h"
|
|
|
|
nonempty_ifdef should remove these lines:
|
|
- #include <notused.h> // lines 6-6
|
|
|
|
The full include-list for nonempty_ifdef:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'nonempty_ifdef': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemoveComments(self):
|
|
"""Tests we remove comments above #includes."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <stdio.h>
|
|
// This file is not used. ///-
|
|
#include <notused.h> ///-
|
|
///-
|
|
// This file is not used either. ///-
|
|
// It's not used. ///-
|
|
// Not used at all. ///-
|
|
#include <notused2.h> ///-
|
|
///-
|
|
#include "notused3.h" ///-
|
|
|
|
// This comment should stay, it's not before an #include.
|
|
const int kInt = 5;
|
|
// This file is used.
|
|
// It's definitedly used.
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
const int kInt2 = 6;
|
|
///-
|
|
// This forward-declare is in a reorder_span all by itself. ///-
|
|
class NotUsed; ///-
|
|
|
|
// This comment should stay, it's not before an #include.
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
remove_comments should add these lines:
|
|
#include "used2.h"
|
|
|
|
remove_comments should remove these lines:
|
|
- #include <notused.h> // lines 5-5
|
|
- #include <notused2.h> // lines 10-10
|
|
- #include "notused3.h" // lines 12-12
|
|
- class NotUsed; // lines 23-23
|
|
|
|
The full include-list for remove_comments:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'remove_comments': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testNoBlankLineAfterTopOfFileCxxComments(self):
|
|
"""Tests we don't remove top-of-file c++ comments right before #includes."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
top_of_file_comments.cc should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
top_of_file_comments.cc should remove these lines:
|
|
- #include <notused.h> // lines 2-2
|
|
|
|
The full include-list for top_of_file_comments.cc:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'top_of_file_comments.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testNoBlankLineAfterTopOfFileCComments(self):
|
|
"""Tests we don't remove top-of-file c comments right before #includes."""
|
|
infile = """\
|
|
/*
|
|
* Copyright 2010
|
|
*/
|
|
#include <notused.h> ///-
|
|
/* This is a one-line c-style comment. */ ///-
|
|
#include <notused2.h> /* this is a c-style comment after a line */ ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
top_of_file_comments.c should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
top_of_file_comments.c should remove these lines:
|
|
- #include <notused.h> // lines 4-4
|
|
- #include <notused2.h> // lines 6-6
|
|
|
|
The full include-list for top_of_file_comments.c:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'top_of_file_comments.c': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testNotFullLineCComments(self):
|
|
"""Tests that we treat lines with c comments then code as code-lines."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
///+#include <stdio.h>
|
|
///+
|
|
/* code here */ x = 4;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
not_full_line_c_comments.c should add these lines:
|
|
#include <stdio.h>
|
|
|
|
not_full_line_c_comments.c should remove these lines:
|
|
|
|
The full include-list for not_full_line_c_comments.c:
|
|
#include <stdio.h>
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'not_full_line_c_comments.c': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testUnusualHFileNames(self):
|
|
"""Tests we treat .pb.h files as header files."""
|
|
infile = """\
|
|
/*
|
|
* Copyright 2010
|
|
*/
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.pb.h"
|
|
///+#include "used2.pb.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
pb.h.cc should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.pb.h"
|
|
|
|
pb.h.cc should remove these lines:
|
|
- #include <notused.h> // lines 4-4
|
|
|
|
The full include-list for pb.h.cc:
|
|
#include <stdio.h>
|
|
#include "used.pb.h"
|
|
#include "used2.pb.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'pb.h.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testFwdDeclLines(self):
|
|
"""Tests that we keep or remove forward declares based on iwyu output."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
struct KeepStruct;
|
|
class NoKeepClass; ///-
|
|
template<typename Foo> class KeepTplClass;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
fwd_decl should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
fwd_decl should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
- class NoKeepClass; // lines 7-7
|
|
|
|
The full include-list for fwd_decl:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
struct KeepStruct; // lines 6-6
|
|
template<typename Foo> class KeepTplClass; // lines 8-8
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'fwd_decl': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testMultiLineFwdDecls(self):
|
|
"""Tests we keep forward-decls that span more than one line."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
struct KeepStruct;
|
|
class NoKeepClass; ///-
|
|
template<typename Foo, typename Bar = Baz>
|
|
class Keep2LineTplClass;
|
|
template<typename Foo, typename Bar = Baz> ///-
|
|
class NoKeep2LineTplClass; ///-
|
|
template<typename Foo,
|
|
typename Bar = Baz>
|
|
class Keep3LineTplClass;
|
|
template<typename Foo, ///-
|
|
typename Bar = Baz> ///-
|
|
class NoKeep3LineTplClass; ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
multiline_fwd_decl should add these lines:
|
|
|
|
multiline_fwd_decl should remove these lines:
|
|
- class NoKeepClass; // lines 4-4
|
|
- template<typename Foo, typename Bar = Baz> class NoKeep2LineTplClass; // lines 7-8
|
|
- template<typename Foo, typename Bar = Baz> class NoKeep3LineTplClass; // lines 12-14
|
|
|
|
The full include-list for multiline_fwd_decl:
|
|
struct KeepStruct; // lines 3-3
|
|
template<typename Foo, typename Bar=Baz> class Keep2LineTplClass; // lines 5-6
|
|
template<typename Foo, typename Bar=Baz> class Keep3LineTplClass; // lines 9-11
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'multiline_fwd_decl': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testKeepExplicitSpecializations(self):
|
|
"""Tests we don't interpret an explicit spec. as a forward-declare."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
struct KeepStruct;
|
|
class NoKeepClass; ///-
|
|
template<typename Foo> class KeepTplClass;
|
|
///+
|
|
template<> class KeepTplClass<int>;
|
|
template<typename T> void TplFn<T>();
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
explicit_specialization should add these lines:
|
|
|
|
explicit_specialization should remove these lines:
|
|
- class NoKeepClass; // lines 4-4
|
|
|
|
The full include-list for explicit_specialization:
|
|
struct KeepStruct; // lines 3-3
|
|
template<typename Foo> class KeepTplClass; // lines 5-5
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'explicit_specialization': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testKeepNestedForwardDeclares(self):
|
|
"""Tests that we don't remove forward-declares inside classes/structs."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
class Keep;
|
|
class NoKeep; ///-
|
|
///+
|
|
class Nest {
|
|
class NestedClass;
|
|
///+
|
|
class NestedClass {
|
|
};
|
|
class NestedClass2 { }; // looks just like a fwd declare, except for the {}
|
|
template<typename T>
|
|
class NestedTplClass; // test multi-line nested classes as well
|
|
///+
|
|
friend class NoKeep;
|
|
template<typename T> friend class NoKeepTpl;
|
|
};
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
nested_fwd_decl should add these lines:
|
|
|
|
nested_fwd_decl should remove these lines:
|
|
- class NoKeep; // lines 4-4
|
|
|
|
The full include-list for nested_fwd_decl:
|
|
class Keep; // lines 3-3
|
|
class Nest::NestedClass; // lines 6-6
|
|
template<typename T> class Nest::NestedTplClass; // lines 11-11
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'nested_fwd_decl': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareBeforeUsingStatement(self):
|
|
"""Tests we never add a forward-declare after a contentful line."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
///+namespace Bar {
|
|
///+class Baz;
|
|
///+} // namespace Bar
|
|
///+
|
|
using Bar::baz;
|
|
|
|
namespace Foo { class Bang; } ///-
|
|
///+namespace Foo {
|
|
///+class Bang;
|
|
///+} // namespace Foo
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_before_using should add these lines:
|
|
namespace Bar { class Baz; }
|
|
|
|
add_fwd_decl_before_using should remove these lines:
|
|
|
|
The full include-list for add_fwd_decl_before_using:
|
|
#include "foo.h"
|
|
namespace Bar { class Baz; }
|
|
namespace Foo { class Bang; } // lines 7-7
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_before_using': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInNamespace(self):
|
|
"""Make sure we normalize namespaces properly."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
///+namespace ns {
|
|
///+class Foo;
|
|
///+namespace ns2 {
|
|
///+namespace ns3 {
|
|
///+class Bar;
|
|
///+template <typename T> class Bang;
|
|
///+} // namespace ns3
|
|
///+} // namespace ns2
|
|
///+namespace ns4 {
|
|
///+class Baz;
|
|
///+} // namespace ns4
|
|
///+} // namespace ns
|
|
///+
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_inside_namespace should add these lines:
|
|
namespace ns { class Foo; }
|
|
namespace ns { namespace ns2 { namespace ns3 { class Bar; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class Bang; } } }
|
|
namespace ns { namespace ns4 { class Baz; } }
|
|
|
|
add_fwd_decl_inside_namespace should remove these lines:
|
|
|
|
The full include-list for add_fwd_decl_inside_namespace:
|
|
#include "foo.h" // lines 3-3
|
|
namespace ns { class Foo; }
|
|
namespace ns { namespace ns2 { namespace ns3 { class Bar; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class Bang; } } }
|
|
namespace ns { namespace ns4 { class Baz; } }
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_inside_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInsideNamespaceSometimes(self):
|
|
"""Tests that in special situations, we will put fwd-decls inside a ns."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
class Bar;
|
|
template <typename T> class Baz;
|
|
|
|
namespace ns {
|
|
|
|
namespace ns2 { // we sure do love nesting our namespaces!
|
|
|
|
class NsFoo;
|
|
///+namespace ns3 {
|
|
///+class NsBang;
|
|
///+template <typename T> class NsBaz;
|
|
///+} // namespace ns3
|
|
template <typename T> class NsBar;
|
|
|
|
}
|
|
}
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_inside_namespace should add these lines:
|
|
namespace ns { namespace ns2 { namespace ns3 { class NsBang; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class NsBaz; } } }
|
|
|
|
add_fwd_decl_inside_namespace should remove these lines:
|
|
|
|
The full include-list for add_fwd_decl_inside_namespace:
|
|
#include "foo.h" // lines 3-3
|
|
class Bar; // lines 5-5
|
|
namespace ns { namespace ns2 { class NsFoo; } } // lines 12-12
|
|
namespace ns { namespace ns2 { namespace ns3 { class NsBang; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class NsBaz; } } }
|
|
namespace ns { namespace ns2 { template <typename T> class NsBar; } } // lines 13-13
|
|
template <typename T> class Baz; // lines 6-6
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_inside_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInsideNamespaceWithHeaderGuard(self):
|
|
"""Tests that the header guard doesn't confuse our in-ns algorithm."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#ifndef HDR_GUARD
|
|
#define HDR_GUARD
|
|
|
|
#include "foo.h"
|
|
|
|
class Bar;
|
|
template <typename T> class Baz;
|
|
|
|
namespace ns {
|
|
|
|
namespace ns2 { // we sure do love nesting our namespaces!
|
|
|
|
class NsFoo;
|
|
///+namespace ns3 {
|
|
///+class NsBang;
|
|
///+template <typename T> class NsBaz;
|
|
///+} // namespace ns3
|
|
template <typename T> class NsBar;
|
|
|
|
}
|
|
}
|
|
|
|
#endif // HDR_GUARD
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_with_hdr_guard should add these lines:
|
|
namespace ns { namespace ns2 { namespace ns3 { class NsBang; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class NsBaz; } } }
|
|
|
|
add_fwd_decl_with_hdr_guard should remove these lines:
|
|
|
|
The full include-list for add_fwd_decl_with_hdr_guard:
|
|
#include "foo.h" // lines 6-6
|
|
class Bar; // lines 8-8
|
|
namespace ns { namespace ns2 { class NsFoo; } } // lines 15-15
|
|
namespace ns { namespace ns2 { namespace ns3 { class NsBang; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class NsBaz; } } }
|
|
namespace ns { namespace ns2 { template <typename T> class NsBar; } } // lines 16-16
|
|
template <typename T> class Baz; // lines 9-9
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_with_hdr_guard': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInsideNamespaceWithIfDef(self):
|
|
"""Tests that ifdef blocks are ignored when finding namespaces."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
class Bar;
|
|
template <typename T> class Baz;
|
|
|
|
#ifdef THIS_IS_A_CONTENTFUL_LINE
|
|
#include "bar.h"
|
|
#endif
|
|
|
|
namespace ns {
|
|
|
|
namespace ns2 {
|
|
|
|
///+class NsBang;
|
|
class NsFoo;
|
|
template <typename T> class NsBar;
|
|
///+template <typename T> class NsBaz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_forward_declares_after_ifdef_code should add these lines:
|
|
namespace ns { namespace ns2 { class NsBang; } }
|
|
namespace ns { namespace ns2 { template <typename T> class NsBaz; } }
|
|
|
|
add_forward_declares_after_ifdef_code should remove these lines:
|
|
|
|
The full include-list for add_forward_declares_after_ifdef_code:
|
|
#include "foo.h" // lines 3-3
|
|
class Bar; // lines 5-5
|
|
namespace ns { namespace ns2 { class NsBang; } }
|
|
namespace ns { namespace ns2 { class NsFoo; } } // lines 16-16
|
|
namespace ns { namespace ns2 { template <typename T> class NsBar; } } // lines 17-17
|
|
namespace ns { namespace ns2 { template <typename T> class NsBaz; } }
|
|
template <typename T> class Baz; // lines 6-6
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_forward_declares_after_ifdef_code': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInsideNamespaceWithoutForwardDeclaresAlready(self):
|
|
"""Tests we put fwd-decls inside an ns even if the ns has no fwd-decl."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
class Bar;
|
|
template <typename T> class Baz;
|
|
|
|
namespace ns {
|
|
|
|
namespace ns2 { // we sure do love nesting our namespaces!
|
|
///-
|
|
///+namespace ns3 {
|
|
///+class NsBang;
|
|
///+template <typename T> class NsBaz;
|
|
///+} // namespace ns3
|
|
///+
|
|
int MyFunction() { }
|
|
|
|
}
|
|
}
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_inside_namespace_without_fwd_decl should add these lines:
|
|
namespace ns { namespace ns2 { namespace ns3 { class NsBang; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class NsBaz; } } }
|
|
|
|
add_fwd_decl_inside_namespace_without_fwd_decl should remove these lines:
|
|
|
|
The full include-list for add_fwd_decl_inside_namespace_without_fwd_decl:
|
|
#include "foo.h" // lines 3-3
|
|
class Bar; // lines 5-5
|
|
namespace ns { namespace ns2 { namespace ns3 { class NsBang; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class NsBaz; } } }
|
|
template <typename T> class Baz; // lines 6-6
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_inside_namespace_without_fwd_decl':
|
|
infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInsideNamespaceWithCompactEndings(self):
|
|
"""Tests we put fwd-decls inside an ns when using compact namespace endings."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
namespace ns { namespace ns1 { namespace ns2 {
|
|
class Ns2Bang;
|
|
}} // namespace ns2 // namespace ns1
|
|
///+class NsBar;
|
|
class NsBaz;
|
|
///-
|
|
namespace ns3 { namespace ns4 { ///-
|
|
class Ns4Bye; ///-
|
|
}} // namespace ns4 // namespace ns3 ///-
|
|
} // namespace ns
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_inside_namespace_without_compact_endings should add these lines:
|
|
namespace ns { class NsBar; }
|
|
|
|
add_fwd_decl_inside_namespace_without_compact_endings should remove these lines:
|
|
- namespace ns { namespace ns1 { namespace ns2 { namespace ns3 { namespace ns4 { class Ns4Bye; } } } } } // lines 9-9
|
|
|
|
The full include-list for add_fwd_decl_inside_namespace_without_compact_endings:
|
|
namespace ns { namespace ns1 { namespace ns2 { class Ns2Bang; } } } // lines 4-4
|
|
namespace ns { class NsBaz; } // lines 6-6
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_inside_namespace_without_compact_endings':
|
|
infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInsideNamespaceWithUnnamedNamespace(self):
|
|
"""Tests that unnamed namespaces do not mess up our in-ns calculation."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
class Bar;
|
|
|
|
namespace ns {
|
|
///+class NsBang;
|
|
///+template <typename T> class NsBaz;
|
|
|
|
namespace {
|
|
class NsFoo;
|
|
template <typename T> class NsBar;
|
|
}
|
|
}
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_inside_namespace_unnamed_ns should add these lines:
|
|
namespace ns { class NsBang; }
|
|
namespace ns { template <typename T> class NsBaz; }
|
|
|
|
add_fwd_decl_inside_namespace_unnamed_ns should remove these lines:
|
|
|
|
The full include-list for add_fwd_decl_inside_namespace_unnamed_ns:
|
|
#include "foo.h" // lines 3-3
|
|
class Bar; // lines 5-5
|
|
namespace ns { namespace { class NsFoo; } } // lines 10-10
|
|
namespace ns { class NsBang; }
|
|
namespace ns { template <typename T> class NsBaz; }
|
|
namespace ns { namespace { template <typename T> class NsBar; } } // lines 11-11
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_inside_namespace_unnamed_ns':
|
|
infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInsideNamespacesWithUnnamedNamespaceAndContent(self):
|
|
"""Tests that nested namespaces with forward declares still get new additions."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
class Bar;
|
|
///+class Baz;
|
|
|
|
namespace ns {
|
|
///+class NsBang;
|
|
///+template <typename T> class NsBaz;
|
|
|
|
namespace {
|
|
///+class NsBaz;
|
|
class NsFoo;
|
|
template <typename T> class NsBar;
|
|
}
|
|
|
|
namespace ns1 {
|
|
///+class Ns1Bar;
|
|
///+class Ns1Baz;
|
|
class Ns1Foo;
|
|
|
|
int ns_int = 5; // here's my contentful line
|
|
}
|
|
}
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_inside_namespaces_with_existing_content should add these lines:
|
|
class Baz;
|
|
namespace ns { class NsBang; }
|
|
namespace ns { template <typename T> class NsBaz; }
|
|
namespace ns { namespace { class NsBaz; } }
|
|
namespace ns { namespace ns1 { class Ns1Bar; } }
|
|
namespace ns { namespace ns1 { class Ns1Baz; } }
|
|
|
|
add_fwd_decl_inside_namespaces_with_existing_content should remove these lines:
|
|
|
|
The full include-list for add_fwd_decl_inside_namespaces_with_existing_content:
|
|
#include "foo.h" // lines 3-3
|
|
class Bar; // lines 5-5
|
|
class Baz;
|
|
namespace ns { namespace { class NsFoo; } } // lines 10-10
|
|
namespace ns { namespace { class NsBaz; } }
|
|
namespace ns { class NsBang; }
|
|
namespace ns { template <typename T> class NsBaz; }
|
|
namespace ns { namespace { template <typename T> class NsBar; } } // lines 11-11
|
|
namespace ns { namespace ns1 { class Ns1Foo; } } // lines 15-15
|
|
namespace ns { namespace ns1 { class Ns1Bar; } }
|
|
namespace ns { namespace ns1 { class Ns1Baz; } }
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_inside_namespaces_with_existing_content':
|
|
infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInsideAllmanNamespacesWithUnnamedNamespaceAndContent(self):
|
|
"""Tests that nested Allman namespaces with forward declares still get new additions."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
class Bar;
|
|
///+class Baz;
|
|
|
|
namespace ns
|
|
{
|
|
///+class NsBang;
|
|
///+template <typename T> class NsBaz;
|
|
|
|
namespace
|
|
{
|
|
///+class NsBaz;
|
|
class NsFoo;
|
|
template <typename T> class NsBar;
|
|
}
|
|
|
|
namespace ns1
|
|
{
|
|
///+class Ns1Bar;
|
|
///+class Ns1Baz;
|
|
class Ns1Foo;
|
|
|
|
int ns_int = 5; // here's my contentful line
|
|
}
|
|
}
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_inside_allman_namespaces_with_existing_content should add these lines:
|
|
class Baz;
|
|
namespace ns { class NsBang; }
|
|
namespace ns { template <typename T> class NsBaz; }
|
|
namespace ns { namespace { class NsBaz; } }
|
|
namespace ns { namespace ns1 { class Ns1Bar; } }
|
|
namespace ns { namespace ns1 { class Ns1Baz; } }
|
|
|
|
add_fwd_decl_inside_allman_namespaces_with_existing_content should remove these lines:
|
|
|
|
The full include-list for add_fwd_decl_inside_allman_namespaces_with_existing_content:
|
|
#include "foo.h" // lines 3-3
|
|
class Bar; // lines 5-5
|
|
class Baz;
|
|
namespace ns { namespace { class NsFoo; } } // lines 12-12
|
|
namespace ns { namespace { class NsBaz; } }
|
|
namespace ns { class NsBang; }
|
|
namespace ns { template <typename T> class NsBaz; }
|
|
namespace ns { namespace { template <typename T> class NsBar; } } // lines 13-13
|
|
namespace ns { namespace ns1 { class Ns1Foo; } } // lines 18-18
|
|
namespace ns { namespace ns1 { class Ns1Bar; } }
|
|
namespace ns { namespace ns1 { class Ns1Baz; } }
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_inside_allman_namespaces_with_existing_content':
|
|
infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInsideMixedNamespacesWithUnnamedNamespaceAndContent(self):
|
|
"""Tests that nested mixed namespaces with forward declares still get new additions."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "bar.h"
|
|
///+
|
|
///+class Baz;
|
|
///+
|
|
namespace ns { namespace ns1 { namespace ns2
|
|
{
|
|
///+class Ns2Bang;
|
|
///+template <typename T> class Ns2Baz;
|
|
///+
|
|
namespace
|
|
{
|
|
///+class NsaBaz;
|
|
class NsaFoo;
|
|
template <typename T> class NsaBar;
|
|
} // namespace
|
|
namespace ns3 {
|
|
///+class Ns3Bar;
|
|
///+class Ns3Baz;
|
|
class Ns3Foo;
|
|
///+
|
|
int ns3_int = 5; // here's my contentful line
|
|
} // namespace ns3
|
|
} // namespace ns2
|
|
} // namespace ns1
|
|
} // namespace ns
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_inside_mixed_namespaces_with_existing_content should add these lines:
|
|
class Baz;
|
|
namespace ns { namespace ns1 { namespace ns2 { class Ns2Bang; } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { template <typename T> class Ns2Baz; } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace { class NsaBaz; } } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace ns3 { class Ns3Bar; } } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace ns3 { class Ns3Baz; } } } }
|
|
|
|
add_fwd_decl_inside_mixed_namespaces_with_existing_content should remove these lines:
|
|
|
|
The full include-list for add_fwd_decl_inside_mixed_namespaces_with_existing_content:
|
|
#include "bar.h" // lines 3-3
|
|
#include "foo.h"
|
|
class Baz;
|
|
namespace ns { namespace ns1 { namespace ns2 { class Ns2Bang; } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { template <typename T> class Ns2Baz; } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace { class NsaFoo; } } } } // lines 8-8
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace { template <typename T> class NsaBar; } } } } // lines 9-9
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace { class NsaBaz; } } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace ns3 { class Ns3Bar; } } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace ns3 { class Ns3Baz; } } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace ns3 { class Ns3Foo; } } } } // lines 12-12
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_inside_mixed_namespaces_with_existing_content':
|
|
infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInsideNestedNamespacesAndTopLevelForComplexNamespaces(self):
|
|
"""Tests that nested namespaces still get new additions while putting hard to resolve forward declares at the top."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
///+namespace ns {
|
|
///+class NsBang;
|
|
///+namespace ns1 {
|
|
///+Ns1Bang;
|
|
///+} // namespace ns1
|
|
///+} // namespace ns
|
|
///+
|
|
namespace ns { namespace ns1 { namespace ns2 {
|
|
class Ns2Bang;
|
|
class Ns2Bar; ///-
|
|
///+class Ns2Baz;
|
|
///+
|
|
namespace ns3 {
|
|
///+class Ns3Bang;
|
|
class Ns3Baz;
|
|
} // namespace ns3
|
|
} // namespace ns2
|
|
} // namespace ns1
|
|
} // namespace ns
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_inside_nested_namespaces_and_top_level_for_complex_namespaces should add these lines:
|
|
namespace ns { class NsBang; }
|
|
namespace ns { namespace ns1 { Ns1Bang; }
|
|
namespace ns { namespace ns1 { namespace ns2 { class Ns2Baz; } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace ns3 { class Ns3Bang; } } } }
|
|
|
|
add_fwd_decl_inside_nested_namespaces_and_top_level_for_complex_namespaces should remove these lines:
|
|
- namespace ns { namespace ns1 { namespace ns2 { class Ns2Bar; } } } // lines 5-5
|
|
|
|
The full include-list for add_fwd_decl_inside_nested_namespaces_and_top_level_for_complex_namespaces:
|
|
namespace ns { class NsBang; }
|
|
namespace ns { namespace ns1 { Ns1Bang; }
|
|
namespace ns { namespace ns1 { namespace ns2 { class Ns2Bang; } } } // lines 4-4
|
|
namespace ns { namespace ns1 { namespace ns2 { class Ns2Baz; } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace ns3 { class Ns3Bang; } } } }
|
|
namespace ns { namespace ns1 { namespace ns2 { namespace ns3 { class Ns3Baz; } } } } // lines 7-7
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_inside_nested_namespaces_and_top_level_for_complex_namespaces':
|
|
infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemoveNamespaces(self):
|
|
"""Tests that we keep or remove ns's based on fwd decl content."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
namespace ns1 {
|
|
struct KeepStruct;
|
|
class NoKeepClass; ///-
|
|
template<typename Foo> class KeepTplClass;
|
|
}
|
|
///-
|
|
namespace ns1 { ///-
|
|
namespace ns2 { ///-
|
|
// This should all go away. ///-
|
|
// Even with the multi-line comment here. ///-
|
|
template<typename Foo> class NoKeepTplClass; ///-
|
|
} ///-
|
|
} ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
ns_fwd_decl should add these lines:
|
|
|
|
ns_fwd_decl should remove these lines:
|
|
- class NoKeepClass; // lines 5-5
|
|
- namespace ns1 { namespace ns2 { template<typename Foo> class NoKeepTplClass; } } // lines 13-13
|
|
|
|
The full include-list for ns_fwd_decl:
|
|
namespace ns1 { struct KeepStruct; } // lines 4-4
|
|
namespace ns1 { template<typename Foo> class KeepTplClass; } // lines 6-6
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'ns_fwd_decl': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testKeepNamespacesWithNonForwardDecls(self):
|
|
"""Tests we never remove a ns with 'real' content in it."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
namespace ns1 {
|
|
int ns_int = 5;
|
|
class NoKeepClass; ///-
|
|
}
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
keep_ns_fwd_decl should add these lines:
|
|
|
|
keep_ns_fwd_decl should remove these lines:
|
|
- class NoKeepClass; // lines 5-5
|
|
|
|
The full include-list for keep_ns_fwd_decl:
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'keep_ns_fwd_decl': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testICUNamespaces(self):
|
|
"""Tests we treat the icu namespace macros as namespaces."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
U_NAMESPACE_BEGIN // macro from icu
|
|
struct KeepStruct;
|
|
class NoKeepClass; ///-
|
|
template<typename Foo> class KeepTplClass;
|
|
U_NAMESPACE_END
|
|
///-
|
|
U_NAMESPACE_BEGIN ///-
|
|
template<typename Foo> class NoKeepTplClass; ///-
|
|
U_NAMESPACE_END ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
icu_namespace should add these lines:
|
|
|
|
icu_namespace should remove these lines:
|
|
- class NoKeepClass; // lines 5-5
|
|
- template<typename Foo> class NoKeepTplClass; // lines 10-10
|
|
|
|
The full include-list for icu_namespace:
|
|
namespace ns1 { struct KeepStruct; } // lines 4-4
|
|
namespace ns1 { template<typename Foo> class KeepTplClass; } // lines 6-6
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'icu_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testHashNamespaces(self):
|
|
"""Tests we treat the hash namespace macros as namespaces."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
HASH_NAMESPACE_DECLARATION_START // macro from hash.h
|
|
struct KeepStruct;
|
|
class NoKeepClass; ///-
|
|
template<typename Foo> class KeepTplClass;
|
|
HASH_NAMESPACE_DECLARATION_END
|
|
///-
|
|
HASH_NAMESPACE_DECLARATION_START ///-
|
|
template<typename Foo> class NoKeepTplClass; ///-
|
|
HASH_NAMESPACE_DECLARATION_END ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
hash_namespace should add these lines:
|
|
|
|
hash_namespace should remove these lines:
|
|
- class NoKeepClass; // lines 5-5
|
|
- template<typename Foo> class NoKeepTplClass; // lines 10-10
|
|
|
|
The full include-list for hash_namespace:
|
|
namespace ns1 { struct KeepStruct; } // lines 4-4
|
|
namespace ns1 { template<typename Foo> class KeepTplClass; } // lines 6-6
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'hash_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testElaboratedClasses(self):
|
|
"""Tests we don't remove lines like 'class Foo* fooptr'."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
struct KeepStruct;
|
|
class NoKeepClass; ///-
|
|
///+
|
|
struct NoKeepStruct* s;
|
|
struct NoKeepStruct& t;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
elaborated_class should add these lines:
|
|
|
|
elaborated_class should remove these lines:
|
|
- class NoKeepClass; // lines 4-4
|
|
|
|
The full include-list for elaborated_class:
|
|
struct KeepStruct; // lines 3-3
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'elaborated_class': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testBFlag(self):
|
|
"""Tests that --b properly separates sections."""
|
|
self.flags.blank_lines = True
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include "subdir/bflag.h"
|
|
///+
|
|
///+#include <stdio.h>
|
|
///+
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
subdir/bflag.cc should add these lines:
|
|
#include "subdir/bflag.h"
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
subdir/bflag.cc should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for subdir/bflag.cc:
|
|
#include "subdir/bflag.h"
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'subdir/bflag.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testSafeHeadersFlag(self):
|
|
"""Tests that --safe_headers causes us to not delete lines."""
|
|
self.flags.safe_headers = True
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h>
|
|
#include <notused2.h> // Hello!
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
class Foo;
|
|
template<typename T>
|
|
class Bar;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
safe_flag.h should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
safe_flag.h should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
- #include <notused.h> // lines 4-4
|
|
- class Foo // lines 7-7
|
|
- class Bar // lines 8-9
|
|
|
|
The full include-list for safe_flag.h:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'safe_flag.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testSafeHeadersFlagTwice(self):
|
|
"""Tests running --safe_headers 2ce in a row doesn't duplicate comments."""
|
|
self.flags.safe_headers = True
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> // iwyu says this can be removed
|
|
#include <notused2.h> // Hello!; iwyu says this can be removed
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
class Foo; // iwyu says this can be removed
|
|
template<typename T> // iwyu says this can be removed
|
|
class Bar; // iwyu says this can be removed
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
safe_flag_twice.h should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
safe_flag_twice.h should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
- #include <notused.h> // lines 4-4
|
|
- class Foo // lines 7-7
|
|
- class Bar // lines 8-9
|
|
|
|
The full include-list for safe_flag_twice.h:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'safe_flag_twice.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testSafeHeadersFlagOnCcFiles(self):
|
|
"""Tests that we delete even in --safe_headers mode, on .cc files."""
|
|
self.flags.safe_headers = True
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
#include <notused2.h> // Hello! ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
class Foo; ///-
|
|
template<typename T> ///-
|
|
class Bar; ///-
|
|
///-
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
safe_flag.cc should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
safe_flag.cc should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
- #include <notused.h> // lines 4-4
|
|
- class Foo // lines 7-7
|
|
- class Bar // lines 8-9
|
|
|
|
The full include-list for safe_flag.cc:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'safe_flag.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testIncludeComments(self):
|
|
"""Tests that we properly include comments on #include lines."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include "subdir/include_comments.h"
|
|
///+#include <stdio.h> // for printf(), etc.
|
|
#include "used.h" ///-
|
|
///+#include "used.h" // for Used
|
|
///+#include "used2.h" // for Used2, Used2::Used2, Used2::~Used2, Used2::Used_Enum, operator==()
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
subdir/include_comments.cc should add these lines:
|
|
#include "subdir/include_comments.h"
|
|
#include <stdio.h> // for printf(), etc.
|
|
#include "used2.h" // for Used2, Used2::Used2, Used2::~Used2, Used2::Used_Enum, operator==()
|
|
|
|
subdir/include_comments.cc should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for subdir/include_comments.cc:
|
|
#include "subdir/include_comments.h"
|
|
#include <stdio.h> // for printf(), etc.
|
|
#include "used.h" // for Used
|
|
#include "used2.h" // for Used2, Used2::Used2, Used2::~Used2, Used2::Used_Enum, operator==()
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'subdir/include_comments.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testNocommentsFlag(self):
|
|
"""Tests we properly don't include/modify comments with --nocomments."""
|
|
self.flags.comments = False
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include "subdir/include_comments.h"
|
|
///+#include <stdio.h>
|
|
#include "used.h" // my favorite #include!
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
subdir/include_comments.cc should add these lines:
|
|
#include "subdir/include_comments.h"
|
|
#include <stdio.h> // for printf(), etc.
|
|
#include "used2.h" // for Used2, Used2::Used2, Used2::~Used2, Used2::Used_Enum, operator==()
|
|
|
|
subdir/include_comments.cc should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for subdir/include_comments.cc:
|
|
#include "subdir/include_comments.h"
|
|
#include <stdio.h> // for printf(), etc.
|
|
#include "used.h" // for Used
|
|
#include "used2.h" // for Used2, Used2::Used2, Used2::~Used2, Used2::Used_Enum, operator==()
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'subdir/include_comments.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testUpdateCommentsFlag(self):
|
|
"""Tests we update comments with --update_comments."""
|
|
self.flags.update_comments = True
|
|
infile = """\
|
|
#include "must_keep.h" // IWYU pragma: keep
|
|
#include "used.h" // for SomethingElse ///-
|
|
///+#include "used.h" // for Used
|
|
|
|
Used used;
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
subdir/include_comments.cc should add these lines:
|
|
|
|
subdir/include_comments.cc should remove these lines:
|
|
|
|
The full include-list for subdir/include_comments.cc:
|
|
#include "must_keep.h"
|
|
#include "used.h" // for Used
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'subdir/include_comments.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testNoUpdateCommentsFlag(self):
|
|
"""Tests we don't update comments with --noupdate_comments."""
|
|
self.flags.update_comments = False
|
|
infile = """\
|
|
#include "must_keep.h" // IWYU pragma: keep
|
|
#include "used.h" // for SomethingElse
|
|
|
|
Used used;
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
subdir/include_comments.cc should add these lines:
|
|
|
|
subdir/include_comments.cc should remove these lines:
|
|
|
|
The full include-list for subdir/include_comments.cc:
|
|
#include "must_keep.h"
|
|
#include "used.h" // for Used
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'subdir/include_comments.cc': infile})
|
|
self.ProcessAndTest(iwyu_output,
|
|
unedited_files=['subdir/include_comments.cc'])
|
|
|
|
def testFixingTwoFiles(self):
|
|
"""Make sure data for one fix doesn't overlap with a second."""
|
|
file_a = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
#include "used_only_in_file_a.h"
|
|
#include "used_only_in_file_b.h" ///-
|
|
|
|
class FileAClass; // kept for file A, not for file B
|
|
class FileBClass; // kept for file B, not for file A ///-
|
|
"""
|
|
file_b = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
#include "used_only_in_file_a.h" ///-
|
|
#include "used_only_in_file_b.h"
|
|
|
|
class FileAClass; // kept for file A, not for file B ///-
|
|
class FileBClass; // kept for file B, not for file A
|
|
"""
|
|
iwyu_output = """\
|
|
file_a.cc should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
file_a.cc should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
- #include "used_only_in_file_b.h" // lines 6-6
|
|
- class FileBClass; // lines 9-9
|
|
|
|
The full include-list for file_a.cc:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
#include "used_only_in_file_a.h"
|
|
class FileAClass; // lines 8-8
|
|
---
|
|
|
|
file_b.cc should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
file_b.cc should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
- #include "used_only_in_file_a.h" // lines 5-5
|
|
- class FileAClass; // lines 8-8
|
|
|
|
The full include-list for file_b.cc:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
#include "used_only_in_file_b.h"
|
|
class FileBClass; // lines 9-9
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'file_a.cc': file_a, 'file_b.cc': file_b})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testListingTheSameFileTwice(self):
|
|
"""Test when foo.cc is specified twice. It should fix conservatively."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
///+#include "include_this_file" // for reason 2
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
#include "used_only_in_file_a.h"
|
|
#include "used_only_in_file_b.h" ///-
|
|
|
|
class FileAClass; // kept for file A, not for file B
|
|
class FileBClass; // kept for file B, not for file A ///-
|
|
///+namespace foo {
|
|
///+template <typename Arg1> ClassTemplate;
|
|
///+} // namespace foo
|
|
///+template <typename Arg1> ClassTemplate;
|
|
"""
|
|
iwyu_output = """\
|
|
twice.cc should add these lines:
|
|
#include <stdio.h>
|
|
#include "include_this_file" // for reason 1
|
|
namespace foo { template <typename Arg1> ClassTemplate; }
|
|
template <typename Arg1> ClassTemplate;
|
|
|
|
twice.cc should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
- #include "used_only_in_file_a.h" // lines 5-5
|
|
- #include "used_only_in_file_b.h" // lines 6-6
|
|
- class FileAClass; // lines 8-8
|
|
- class FileBClass; // lines 9-9
|
|
|
|
The full include-list for twice.cc:
|
|
#include <stdio.h>
|
|
#include "include_this_file" // for reason 1
|
|
#include "used.h"
|
|
namespace foo { template <typename Arg1> ClassTemplate; }
|
|
template <typename Arg1> ClassTemplate;
|
|
---
|
|
|
|
twice.cc should add these lines:
|
|
#include "used2.h"
|
|
#include "include_this_file" // for reason 2
|
|
namespace foo { template <typename Arg2> ClassTemplate; }
|
|
template <typename Arg2> ClassTemplate;
|
|
|
|
twice.cc should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
- #include "used_only_in_file_b.h" // lines 6-6
|
|
- class FileBClass; // lines 9-9
|
|
|
|
The full include-list for twice.cc:
|
|
#include "include_this_file" // for reason 2
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
#include "used_only_in_file_a.h"
|
|
class FileAClass; // lines 8-8
|
|
namespace foo { template <typename Arg2> ClassTemplate; }
|
|
template <typename Arg2> ClassTemplate;
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'twice.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testListingTheSameFileTwiceAndOnceIsANoop(self):
|
|
"""Test when foo.cc is specified twice, once with 'all correct'."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h>
|
|
///+#include <stdio.h>
|
|
///+#include "include_this_file" // for reason 1
|
|
#include "used.h"
|
|
#include "used_only_in_file_a.h"
|
|
|
|
class FileAClass;
|
|
///+namespace foo {
|
|
///+template <typename Arg1> ClassTemplate;
|
|
///+} // namespace foo
|
|
///+template <typename Arg1> ClassTemplate;
|
|
"""
|
|
iwyu_output = """\
|
|
twice.cc should add these lines:
|
|
#include <stdio.h>
|
|
#include "include_this_file" // for reason 1
|
|
namespace foo { template <typename Arg1> ClassTemplate; }
|
|
template <typename Arg1> ClassTemplate;
|
|
|
|
twice.cc should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
- #include "used_only_in_file_a.h" // lines 5-5
|
|
- class FileAClass; // lines 7-7
|
|
|
|
The full include-list for twice.cc:
|
|
#include <stdio.h>
|
|
#include "include_this_file" // for reason 1
|
|
#include "used.h"
|
|
namespace foo { template <typename Arg1> ClassTemplate; }
|
|
template <typename Arg1> ClassTemplate;
|
|
---
|
|
|
|
(twice.cc has correct #includes/fwd-decls)
|
|
"""
|
|
self.RegisterFileContents({'twice.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclare(self):
|
|
"""Test adding a forward-declare, rather than keeping one."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
///+
|
|
///+struct NotUsed;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
new_fwd_decl should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
struct NotUsed;
|
|
|
|
new_fwd_decl should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for new_fwd_decl:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
struct NotUsed;
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'new_fwd_decl': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddAndKeepForwardDeclare(self):
|
|
"""Test adding a forward-declare in addition to keeping one."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
class ForwardDeclClass;
|
|
///+struct NotUsed;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
new_and_keep_fwd_decl should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
struct NotUsed;
|
|
|
|
new_and_keep_fwd_decl should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for new_and_keep_fwd_decl:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
class ForwardDeclareClass; // lines 6-6
|
|
struct NotUsed;
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'new_and_keep_fwd_decl': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeToFileThatHasOnlyForwardDeclarations(self):
|
|
"""Tests we add an #include in an appropriate place if none exist."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
///+#include <stdio.h>
|
|
///+#include "used.h"
|
|
///+
|
|
const int kFoo = 5; // we should insert before the contentful line.
|
|
|
|
class Foo;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
no_include_fwd_decl should add these lines:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
|
|
no_include_fwd_decl should remove these lines:
|
|
|
|
The full include-list for no_include_fwd_decl:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
class Foo; // lines 5-5
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'no_include_fwd_decl': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclarationToFileThatHasOnlyIncludes(self):
|
|
"""Tests we add a forward-declare in an appropriate place if none exist."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
const int kFoo = 5; // make sure we don't just insert at the beginning
|
|
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
///+
|
|
///+class Foo;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
no_fwd_decl_include should add these lines:
|
|
class Foo;
|
|
|
|
no_fwd_decl_include should remove these lines:
|
|
|
|
The full include-list for no_fwd_decl_include:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
class Foo;
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'no_fwd_decl_include': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeToContentlessFile(self):
|
|
"""Tests we add an #include ok to a basically empty file.."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
///+#include <stdio.h>
|
|
///+#include "used.h"
|
|
///+
|
|
///+class Foo;
|
|
"""
|
|
iwyu_output = """\
|
|
no_include should add these lines:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
class Foo;
|
|
|
|
no_include should remove these lines:
|
|
|
|
The full include-list for no_include:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
class Foo;
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'no_include': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeToEmptyFile(self):
|
|
"""Tests we add an #include ok to an empty file.."""
|
|
infile = ''
|
|
iwyu_output = """\
|
|
empty_file should add these lines:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
class Foo;
|
|
|
|
empty_file should remove these lines:
|
|
|
|
The full include-list for empty_file:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
class Foo;
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'empty_file': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeToOnlyOneContentfulLineFile(self):
|
|
"""Prevent regression when the only contentful line was the last."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
///+
|
|
///+#include <stdio.h>
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
only_one_contentful_line.c should add these lines:
|
|
#include <stdio.h>
|
|
|
|
only_one_contentful_line.c should remove these lines:
|
|
|
|
The full include-list for only_one_contentful_line.c:
|
|
#include <stdio.h>
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'only_one_contentful_line.c': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testCommentsAtEndOfFile(self):
|
|
"""Tests we don't crash if a file ends with #includs and then a comment."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
const int kFoo = 5; // make sure we don't just insert at the beginning
|
|
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
///+
|
|
///+class Foo;
|
|
// Comments, and then...nothing
|
|
"""
|
|
iwyu_output = """\
|
|
comments_at_end_of_file should add these lines:
|
|
class Foo;
|
|
|
|
comments_at_end_of_file should remove these lines:
|
|
|
|
The full include-list for comments_at_end_of_file:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
class Foo;
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'comments_at_end_of_file': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddSystemIncludeToFileWithoutAny(self):
|
|
"""Tests we add a system #include to a non-sys location when needed."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#ifdef HAVE_TYPE_TRAITS_H
|
|
#include <type_traits.h>
|
|
#endif
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
system_include should add these lines:
|
|
#include <stdio.h>
|
|
|
|
system_include should remove these lines:
|
|
|
|
The full include-list for system_include:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'system_include': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddNonSystemHeaderUnderMainCUHeader(self):
|
|
"""Tests we distinguish main-cu headers from other non-system headers."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
///+#include "main_cu.h"
|
|
#include "main_cu-inl.h"
|
|
///-
|
|
#include <stdio.h>
|
|
///+#include <stdlib.h>
|
|
#ifdef WINDOWS
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
main_cu_test.cc should add these lines:
|
|
#include <stdlib.h>
|
|
#include "main_cu.h"
|
|
#include "used2.h"
|
|
|
|
main_cu_test.cc should remove these lines:
|
|
|
|
The full include-list for main_cu_test.cc:
|
|
#include "main_cu.h"
|
|
#include "main_cu-inl.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'main_cu_test.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddWithNearestIncludes(self):
|
|
"""Tests we add "includes" with <includes> when there's a choice."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "nearest_include.h"
|
|
|
|
static int x = 6;
|
|
#include <stdio.h>
|
|
///+#include "used.h"
|
|
|
|
static int y = 7;
|
|
class Foo;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
nearest_include.cc should add these lines:
|
|
#include "used.h"
|
|
|
|
nearest_include.cc should remove these lines:
|
|
|
|
The full include-list for nearest_include.cc:
|
|
#include "nearest_include.h"
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
class Foo; // lines 9-9
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'nearest_include.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testFalseAlarmHeaderGuard(self):
|
|
"""Tests we calculate top-level-ness even in face of a fake header-guard."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "nearest_toplevel_include.h"
|
|
|
|
static int x = 6;
|
|
#include <stdio.h>
|
|
///+#include "used.h"
|
|
|
|
#ifndef MAP_ANONYMOUS // This is the fake header guard!
|
|
# define MAP_ANONYMOUS MAP_ANON
|
|
#endif
|
|
|
|
#ifdef FOO
|
|
#include <foo.h>
|
|
#endif
|
|
#if defined(BAR)
|
|
#include <bar.h>
|
|
#endif
|
|
|
|
static int y = 7;
|
|
class Foo;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
nearest_toplevel_include.cc should add these lines:
|
|
#include "used.h"
|
|
|
|
nearest_toplevel_include.cc should remove these lines:
|
|
|
|
The full include-list for nearest_toplevel_include.cc:
|
|
#include "nearest_toplevel_include.h"
|
|
#include <bar.h>
|
|
#include <foo.h>
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
class Foo; // lines 9-9
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'nearest_toplevel_include.cc': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeAfterHeaderGuard(self):
|
|
"""Test that we are willing to insert .h's inside a header guard."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#ifndef SIMPLE_H_
|
|
#define SIMPLE_H_
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
#endif
|
|
"""
|
|
iwyu_output = """\
|
|
simple.h should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
simple.h should remove these lines:
|
|
- #include <notused.h> // lines 6-6
|
|
|
|
The full include-list for simple.h:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'simple.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeAfterSoloPragmaOnce(self):
|
|
"""Test that we are willing to insert .h's after #pragma once."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#pragma once
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
"""
|
|
iwyu_output = """\
|
|
pragma_once.h should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
pragma_once.h should remove these lines:
|
|
- #include <notused.h> // lines 5-5
|
|
|
|
The full include-list for pragma_once.h:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'pragma_once.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeAfterPragmaOnceWithHeaderGuard(self):
|
|
"""Test that we are willing to insert .h's after #pragma once and header
|
|
guard."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#pragma once
|
|
#ifndef PRAGMA_ONCE_H_
|
|
#define PRAGMA_ONCE_H_
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
#endif
|
|
"""
|
|
iwyu_output = """\
|
|
pragma_once_with_guard.h should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
pragma_once_with_guard.h should remove these lines:
|
|
- #include <notused.h> // lines 7-7
|
|
|
|
The full include-list for pragma_once_with_guard.h:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'pragma_once_with_guard.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeAfterEarlyPragmaOnce(self):
|
|
"""Test that we are willing to insert .h's after early #pragma once."""
|
|
infile = """\
|
|
#pragma once
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
"""
|
|
iwyu_output = """\
|
|
early_pragma_once.h should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
early_pragma_once.h should remove these lines:
|
|
- #include <notused.h> // lines 4-4
|
|
|
|
The full include-list for early_pragma_once.h:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'early_pragma_once.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeAfterEarlyPragmaOnceWithHeaderGuard(self):
|
|
"""Test that we are willing to insert .h's after early #pragma once and
|
|
header guard."""
|
|
infile = """\
|
|
#pragma once
|
|
// Copyright 2010
|
|
|
|
#ifndef PRAGMA_ONCE_H_
|
|
#define PRAGMA_ONCE_H_
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
#endif
|
|
"""
|
|
iwyu_output = """\
|
|
early_pragma_once_with_guard.h should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
early_pragma_once_with_guard.h should remove these lines:
|
|
- #include <notused.h> // lines 7-7
|
|
|
|
The full include-list for early_pragma_once_with_guard.h:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'early_pragma_once_with_guard.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeAfterWeirdPragmaOnce(self):
|
|
"""Test that we are willing to insert .h's after creatively formatted
|
|
#pragma once."""
|
|
infile = """\
|
|
# pragma once
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
"""
|
|
iwyu_output = """\
|
|
weird_pragma_once.h should add these lines:
|
|
#include <stdio.h>
|
|
|
|
weird_pragma_once.h should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for weird_pragma_once.h:
|
|
#include <stdio.h>
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'weird_pragma_once.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeBeforePragmaMessage(self):
|
|
"""Test that non-once #pragmas are pushed after the #includes."""
|
|
infile = """\
|
|
///+#include <stdio.h>
|
|
///+
|
|
#pragma message "Hello world!"
|
|
|
|
#include <notused.h> ///-
|
|
"""
|
|
iwyu_output = """\
|
|
weird_pragma_once.h should add these lines:
|
|
#include <stdio.h>
|
|
|
|
weird_pragma_once.h should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for weird_pragma_once.h:
|
|
#include <stdio.h>
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'weird_pragma_once.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeAfterWeirdHeaderGuard(self):
|
|
"""Test that we are willing to insert .h's inside a non-standard h-guard."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#if ! defined (SIMPLE_H_)
|
|
#define SIMPLE_H_
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
#endif
|
|
"""
|
|
iwyu_output = """\
|
|
simple.h should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
simple.h should remove these lines:
|
|
- #include <notused.h> // lines 6-6
|
|
|
|
The full include-list for simple.h:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'simple.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeAfterHeaderGuardLikeIfdef(self):
|
|
"""Test that we are willing to insert .h's inside a h-guard-*like* line."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#ifdef __linux // serves the same role as a header guard
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
#endif
|
|
|
|
// Comments are allowed after the header guard.
|
|
"""
|
|
iwyu_output = """\
|
|
os_header_guard.h should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
os_header_guard.h should remove these lines:
|
|
- #include <notused.h> // lines 5-5
|
|
|
|
The full include-list for os_header_guard.h:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'os_header_guard.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddIncludeAfterHeaderGuardButBeforeComments(self):
|
|
"""Test that we introduce new #includes right after a header guard."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#ifndef SIMPLE_WITH_COMMENT_H_
|
|
#define SIMPLE_WITH_COMMENT_H_
|
|
|
|
///+#include <stdio.h>
|
|
///+#include "used.h"
|
|
///+
|
|
// This is a comment
|
|
void ForThisFunction();
|
|
|
|
#endif
|
|
"""
|
|
iwyu_output = """\
|
|
simple_with_comment.h should add these lines:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
|
|
simple_with_comment.h should remove these lines:
|
|
|
|
The full include-list for simple_with_comment.h:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'simple_with_comment.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testIdentifyingHeaderGuardLines(self):
|
|
"""Test that not all #defines look like header guards."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#ifndef IDENTIFYING_HEADER_GUARD_LINES_H_
|
|
#define IDENTIFYING_HEADER_GUARD_LINES_H_
|
|
|
|
namespace foo {
|
|
///+namespace bar {
|
|
///+class Baz;
|
|
///+} // namespace bar
|
|
///+
|
|
// The namespace decl should come before this #define, not after.
|
|
// It will, unless we wrongly say the #define is a header-guard define.
|
|
#define NOT_A_HEADER_GUARD_LINE 1
|
|
}
|
|
|
|
#endif
|
|
"""
|
|
iwyu_output = """\
|
|
identifying_header_guard_lines.h should add these lines:
|
|
namespace foo { namespace bar { class Baz; } }
|
|
|
|
identifying_header_guard_lines.h should remove these lines:
|
|
|
|
The full include-list for identifying_header_guard_lines.h:
|
|
namespace foo { namespace bar { class Baz; } }
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'identifying_header_guard_lines.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testIncludeOfCcFile(self):
|
|
"""Test that iwyu leaves .cc #includes alone."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int kFoo = 5;
|
|
|
|
#include "not_mentioned.cc"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
cc_include should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
cc_include should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for cc_include:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'cc_include': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testCommentsBeforeIncludeLines(self):
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+// This is the first include.
|
|
///+// Or it will be, after we reorder.
|
|
///+#include <stdio.h>
|
|
// This is the second include.
|
|
// Or *it* will be, after we reorder.
|
|
#include "used.h"
|
|
// This is the first include. ///-
|
|
// Or it will be, after we reorder. ///-
|
|
#include <stdio.h> ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
comments_with_includes should add these lines:
|
|
|
|
comments_with_includes should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for comments_with_includes:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'comments_with_includes': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemoveDuplicateIncludes(self):
|
|
"""Tests we uniquify if an #include is in there twice."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
#include "used.h" // same line even though it has a comment ///-
|
|
// Even though these two comment-lines are the same, they won't get de-duped.
|
|
// Even though these two comment-lines are the same, they won't get de-duped.
|
|
#ifdef _WINDOWS
|
|
// But keep this one because it's in an #ifdef.
|
|
#include "used.h"
|
|
#endif
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
remove_duplicate_includes should add these lines:
|
|
#include <stdio.h>
|
|
|
|
remove_duplicate_includes should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for remove_duplicate_includes:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'remove_duplicate_includes': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testRemoveDuplicateForwardDeclarations(self):
|
|
"""Tests we uniquify if an #include is in there twice."""
|
|
infile = """\
|
|
#include <notused.h> ///-
|
|
class A;
|
|
template<typename T> // Comment in the middle not a problem
|
|
class B;
|
|
class A; ///-
|
|
template<typename T> ///-
|
|
class B; ///-
|
|
template<typename T> class B; ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
remove_duplicate_forward_declarations should add these lines:
|
|
|
|
remove_duplicate_forward_declarations should remove these lines:
|
|
- #include <notused.h> // lines 1-1
|
|
|
|
The full include-list for remove_duplicate_forward_declarations:
|
|
class A; // lines 2-2
|
|
template <typename T> class B; // lines 3-4
|
|
class A; // lines 5-5
|
|
template <typename T> class B; // lines 6-7
|
|
template <typename T> class B; // lines 8-8
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'remove_duplicate_forward_declarations': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testDontRemoveTemplateLines(self):
|
|
"""Tests we don't accidentally think repeated template lines are dupes."""
|
|
infile = """\
|
|
#include <notused.h> ///-
|
|
template<typename T>
|
|
class A;
|
|
template<typename T>
|
|
class B;
|
|
|
|
void f(A&, B&);
|
|
"""
|
|
iwyu_output = """\
|
|
dont_remove_template_lines should add these lines:
|
|
|
|
dont_remove_template_lines should remove these lines:
|
|
- #include <notused.h> // lines 1-1
|
|
|
|
The full include-list for dont_remove_template_lines:
|
|
template <typename T> class A; // lines 2-3
|
|
template <typename T> class B; // lines 4-5
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'dont_remove_template_lines': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testDontRemoveSimilarNestedDeclarations(self):
|
|
"""Tests we don't accidentally think repeated nested forward declarations
|
|
are dupes."""
|
|
infile = """\
|
|
#include <notused.h> ///-
|
|
|
|
class A {
|
|
class Inner;
|
|
};
|
|
|
|
class B {
|
|
class Inner;
|
|
};
|
|
"""
|
|
iwyu_output = """\
|
|
dont_remove_similar_nested should add these lines:
|
|
|
|
dont_remove_similar_nested should remove these lines:
|
|
- #include <notused.h> // lines 1-1
|
|
|
|
The full include-list for dont_remove_similar_nested:
|
|
class A::Inner; // lines 4-4
|
|
class B::Inner; // lines 8-8
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'dont_remove_similar_nested': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testNestedNamespaces(self):
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
///+#include <stdio.h>
|
|
///+
|
|
namespace X {
|
|
class OneA
|
|
///+
|
|
namespace Y {
|
|
///+class TwoA;
|
|
class TwoB;
|
|
class TwoA; ///-
|
|
}}
|
|
class Toplevel;
|
|
///-
|
|
namespace A { ///-
|
|
namespace B { namespace C { ///-
|
|
class Delete1; ///-
|
|
}}} ///-
|
|
///-
|
|
namespace A { namespace B { class Delete2; } } ///-
|
|
///-
|
|
namespace A { ///-
|
|
namespace B { ///-
|
|
class Delete3; ///-
|
|
} ///-
|
|
} // namespace A ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
many_namespaces should add these lines:
|
|
#include <stdio.h>
|
|
|
|
many_namespaces should remove these lines:
|
|
- class Delete1; // lines 13-13
|
|
- class Delete2; // lines 16-16
|
|
- class Delete3; // lines 20-20
|
|
|
|
The full include-list for many_namespaces:
|
|
#include <stdio.h>
|
|
class Toplevel; // lines 9-9
|
|
class TwoA; // lines 7-7
|
|
class TwoB; // lines 6-6
|
|
class OneA; // lines 4-4
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'many_namespaces': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testDoNotInsertIncludeIntoAClass(self):
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
///+#include <stdio.h>
|
|
///+
|
|
class Foo {
|
|
};
|
|
|
|
class Bar {
|
|
class FwdDecl;
|
|
|
|
FwdDecl* f;
|
|
}
|
|
"""
|
|
iwyu_output = """\
|
|
include_not_in_class should add these lines:
|
|
#include <stdio.h>
|
|
|
|
include_not_in_class should remove these lines:
|
|
|
|
The full include-list for include_not_in_class:
|
|
#include <stdio.h>
|
|
class FwdDecl; // lines 7-7
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'include_not_in_class': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testIdenticalForwardDeclaredNamesInDifferentNamespaces(self):
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
///+namespace ns1 {
|
|
///+class ForwardDeclared;
|
|
///+} // namespace ns1
|
|
///+namespace ns2 {
|
|
///+class ForwardDeclared;
|
|
///+} // namespace ns2
|
|
"""
|
|
iwyu_output = """\
|
|
identical_names should add these lines:
|
|
namespace ns1 { class ForwardDeclared; }
|
|
namespace ns2 { class ForwardDeclared; }
|
|
|
|
identical_names should remove these lines:
|
|
|
|
The full include-list for identical_names:
|
|
namespace ns1 { class ForwardDeclared; }
|
|
namespace ns2 { class ForwardDeclared; }
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'identical_names': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testIterativeNamespaceDelete(self):
|
|
"""Tests deleting a namespace with an emptied #ifdef inside it."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
///-
|
|
namespace foo { ///-
|
|
#ifdef FWD_DECL ///-
|
|
class Bar; ///-
|
|
#endif ///-
|
|
} ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
iterative_namespace should add these lines:
|
|
|
|
iterative_namespace should remove these lines:
|
|
- class Bar; // lines 5-5
|
|
|
|
The full include-list for iterative_namespace:
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'iterative_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testIterativeAllmanNamespaceDelete(self):
|
|
"""Tests deleting an Allman namespace with an emptied #ifdef inside it."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
///-
|
|
namespace foo ///-
|
|
{ ///-
|
|
#ifdef FWD_DECL ///-
|
|
class Bar; ///-
|
|
#endif ///-
|
|
} ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
iterative_namespace should add these lines:
|
|
|
|
iterative_namespace should remove these lines:
|
|
- class Bar; // lines 6-6
|
|
|
|
The full include-list for iterative_namespace:
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'iterative_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testIterativeMixedNamespaceDelete(self):
|
|
"""Tests deleting a namespace with mixed braces with an emptied #ifdef inside it."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
///-
|
|
namespace foo { namespace baz ///-
|
|
{ ///-
|
|
#ifdef FWD_DECL ///-
|
|
class Bar; ///-
|
|
#endif ///-
|
|
} ///-
|
|
} ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
iterative_namespace should add these lines:
|
|
|
|
iterative_namespace should remove these lines:
|
|
- class Bar; // lines 6-6
|
|
|
|
The full include-list for iterative_namespace:
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'iterative_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testIterativeIfdefDelete(self):
|
|
"""Tests deleting an ifdef with an emptied namespace inside it."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
///-
|
|
#ifdef FWD_DECL ///-
|
|
namespace foo { ///-
|
|
class Bar; ///-
|
|
} ///-
|
|
#endif ///-
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
iterative_ifdef should add these lines:
|
|
|
|
iterative_ifdef should remove these lines:
|
|
- class Bar; // lines 5-5
|
|
|
|
The full include-list for iterative_ifdef:
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'iterative_ifdef': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testOutOfRangeLineNumber(self):
|
|
"""Test we skip editing completely if iwyu has a really big line number."""
|
|
# fix_includes skips the file-editing if it detects a problem, as
|
|
# in this test case. The way that skipping is evidenced in the
|
|
# test, is the output is empty.
|
|
infile = """\
|
|
// Copyright 2010 ///-
|
|
///-
|
|
#include <notused.h> ///-
|
|
#include "used.h" ///-
|
|
///-
|
|
int main() { return 0; } ///-
|
|
"""
|
|
iwyu_output = """\
|
|
out_of_range should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
out_of_range should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
- #include <bignumber.h> // lines 3000-3000
|
|
|
|
The full include-list for out_of_range:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'out_of_range': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testDeleteExtraneousBlankLines(self):
|
|
"""Test we delete blank lines around deleted spans correctly."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
class Foo { };
|
|
///-
|
|
class Bar; ///-
|
|
|
|
|
|
class Baz { };
|
|
|
|
|
|
class Bang; ///-
|
|
///-
|
|
class Qux { };
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
extraneous_blank_lines should add these lines:
|
|
|
|
extraneous_blank_lines should remove these lines:
|
|
- class Bar; // lines 5-5
|
|
- class Bang; // lines 11-11
|
|
|
|
The full include-list for extraneous_blank_lines:
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'extraneous_blank_lines': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testKeepNolintComment(self):
|
|
"""Test we keep a nolint comment."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "bar.h" // NOLINT(iwyu)
|
|
#include "baz.h" // NOLINT(iwyu): blah blah
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
keep_nolint should add these lines:
|
|
|
|
keep_nolint should remove these lines:
|
|
|
|
The full include-list for keep_nolint:
|
|
#include "bar.h" // lines 3-3
|
|
#include "baz.h" // lines 4-4
|
|
---
|
|
"""
|
|
|
|
self.RegisterFileContents({'keep_nolint': infile})
|
|
# No files are written, because there are no changes.
|
|
self.ProcessAndTest(iwyu_output, unedited_files=['keep_nolint'])
|
|
|
|
def testKeepNolintCommentInNocommentMode(self):
|
|
"""Test we keep a nolint comment even with --nocomments."""
|
|
self.flags.comments = False
|
|
self.testKeepNolintComment()
|
|
|
|
# Test the IWYUOutputParser method _MatchSectionHeading.
|
|
|
|
def testIWYUOutputParserMatchSectionHeadingSuccess(self):
|
|
parser = fix_includes.IWYUOutputParser()
|
|
self.assertEqual(None, parser.current_section)
|
|
self.assertEqual('<unknown file>', parser.filename)
|
|
|
|
self.assertTrue(parser._ProcessOneLine(''))
|
|
self.assertEqual(None, parser.current_section)
|
|
self.assertEqual('<unknown file>', parser.filename)
|
|
|
|
self.assertTrue(parser._ProcessOneLine(
|
|
'myfile.cc should add these lines:'))
|
|
self.assertEqual(parser._ADD_SECTION_RE, parser.current_section)
|
|
self.assertEqual('add', parser._RE_TO_NAME[parser.current_section])
|
|
self.assertEqual('myfile.cc', parser.filename)
|
|
|
|
self.assertTrue(parser._ProcessOneLine(
|
|
'myfile.cc should remove these lines:'))
|
|
self.assertEqual(parser._REMOVE_SECTION_RE, parser.current_section)
|
|
self.assertEqual('remove', parser._RE_TO_NAME[parser.current_section])
|
|
self.assertEqual('myfile.cc', parser.filename)
|
|
|
|
self.assertTrue(parser._ProcessOneLine(
|
|
'The full include-list for myfile.cc:'))
|
|
self.assertEqual(parser._TOTAL_SECTION_RE, parser.current_section)
|
|
self.assertEqual('total', parser._RE_TO_NAME[parser.current_section])
|
|
self.assertEqual('myfile.cc', parser.filename)
|
|
|
|
self.assertTrue(not parser._ProcessOneLine('---'))
|
|
self.assertEqual(parser._SECTION_END_RE, parser.current_section)
|
|
self.assertEqual('end', parser._RE_TO_NAME[parser.current_section])
|
|
self.assertEqual('myfile.cc', parser.filename)
|
|
|
|
def testIWYUOutputParserMatchSectionHeadingWindowsPaths(self):
|
|
# Windows path names can contain the ':' character, so make sure that parses
|
|
# correctly. IWYU uses POSIX-style forward slashes consistently, so follow
|
|
# suit here.
|
|
parser = fix_includes.IWYUOutputParser()
|
|
self.assertTrue(parser._ProcessOneLine(
|
|
'C:/src/myfile.cc should add these lines:'))
|
|
self.assertEqual(parser._ADD_SECTION_RE, parser.current_section)
|
|
self.assertEqual('add', parser._RE_TO_NAME[parser.current_section])
|
|
self.assertEqual('C:/src/myfile.cc', parser.filename)
|
|
|
|
self.assertTrue(parser._ProcessOneLine(
|
|
'C:/src/myfile.cc should remove these lines:'))
|
|
self.assertEqual(parser._REMOVE_SECTION_RE, parser.current_section)
|
|
self.assertEqual('remove', parser._RE_TO_NAME[parser.current_section])
|
|
self.assertEqual('C:/src/myfile.cc', parser.filename)
|
|
|
|
self.assertTrue(parser._ProcessOneLine(
|
|
'The full include-list for C:/src/myfile.cc:'))
|
|
self.assertEqual(parser._TOTAL_SECTION_RE, parser.current_section)
|
|
self.assertEqual('total', parser._RE_TO_NAME[parser.current_section])
|
|
self.assertEqual('C:/src/myfile.cc', parser.filename)
|
|
|
|
def testIWYUOutputParserProcessOneLineProcessNoEditsHeader(self):
|
|
parser = fix_includes.IWYUOutputParser()
|
|
line = '(myfile.cc has correct #includes/fwd-decls)'
|
|
self.assertTrue(not parser._ProcessOneLine(line))
|
|
self.assertEqual(parser._NO_EDITS_RE, parser.current_section)
|
|
self.assertEqual('no_edits', parser._RE_TO_NAME[parser.current_section])
|
|
self.assertEqual('myfile.cc', parser.filename)
|
|
|
|
def testIWYUOutputParserProcessOneLineAddNotSeenFirst(self):
|
|
parser = fix_includes.IWYUOutputParser()
|
|
self.assertRaises(fix_includes.FixIncludesError,
|
|
parser._ProcessOneLine,
|
|
'myfile.cc should remove these lines:')
|
|
|
|
def testIWYUOutputParserProcessOneLineOutOfOrder(self):
|
|
parser = fix_includes.IWYUOutputParser()
|
|
self.assertTrue(parser._ProcessOneLine(
|
|
'myfile.cc should add these lines:'))
|
|
self.assertRaises(fix_includes.FixIncludesError,
|
|
parser._ProcessOneLine,
|
|
'The full include-list for myfile.cc:')
|
|
|
|
def testIWYUOutputParserProcessOneLineIncorrectFilename(self):
|
|
parser = fix_includes.IWYUOutputParser()
|
|
self.assertTrue(parser._ProcessOneLine(
|
|
'myfile.cc should add these lines:'))
|
|
self.assertRaises(fix_includes.FixIncludesError,
|
|
parser._ProcessOneLine,
|
|
'not_myfile.cc should remove these lines:')
|
|
|
|
def testIWYUOutputParserProcessOneLineNoMatcher(self):
|
|
parser = fix_includes.IWYUOutputParser()
|
|
# We successfully process this not-in-any-section line, but update no data.
|
|
self.assertTrue(parser._ProcessOneLine('#include <foo>'))
|
|
self.assertEqual(None, parser.current_section)
|
|
self.assertEqual('<unknown file>', parser.filename)
|
|
|
|
def testIWYUOutputParserSuccess(self):
|
|
"""Tests the IWYUOutputParser method ParseOneRecord."""
|
|
iwyu_output = """\
|
|
simple should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
namespace ns {class ForwardDeclared;}
|
|
|
|
simple should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for simple:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
namespace ns {class ForwardDeclared;}
|
|
---
|
|
"""
|
|
parser = fix_includes.IWYUOutputParser()
|
|
record = parser.ParseOneRecord(iwyu_output.splitlines(), self.flags)
|
|
|
|
self.assertEqual('simple', record.filename)
|
|
self.assertSetEqual(set([3]), record.lines_to_delete)
|
|
self.assertSetEqual(set(('#include <stdio.h>',
|
|
'#include "used2.h"',
|
|
'namespace ns {class ForwardDeclared;}')),
|
|
record.includes_and_forward_declares_to_add)
|
|
|
|
def testIWYUOutputParserRemoveLineNoComment(self):
|
|
iwyu_output = """\
|
|
no_comment should add these lines:
|
|
|
|
no_comment should remove these lines:
|
|
- #include <notused.h>
|
|
|
|
The full include-list for no_key:
|
|
---
|
|
"""
|
|
parser = fix_includes.IWYUOutputParser()
|
|
self.assertRaises(fix_includes.FixIncludesError,
|
|
parser.ParseOneRecord,
|
|
iwyu_output.splitlines(),
|
|
self.flags)
|
|
|
|
def testFileSpecifiedOnCommandline(self):
|
|
"""Test we limit editing to files specified on the commandline."""
|
|
changed_infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
unchanged_infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h>
|
|
#include "used.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
changed should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
changed should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for changed:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
# Have the exact same iwyu output for 'unchanged' as for 'changed'.
|
|
iwyu_output += iwyu_output.replace('changed', 'unchanged')
|
|
|
|
self.RegisterFileContents({'changed': changed_infile,
|
|
'unchanged': unchanged_infile})
|
|
# unchanged should not be edited, since it is not listed on the 'cmdline'.
|
|
self.ProcessAndTest(iwyu_output, cmdline_files=['changed'],
|
|
unedited_files=['unchanged'])
|
|
|
|
def testIgnoreRe(self):
|
|
"""Test the behavior of the --ignore_re flag."""
|
|
changed_infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
unchanged_infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h>
|
|
#include "used.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
changed should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
changed should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for changed:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
# Have the exact same iwyu output for 'unchanged' as for 'changed'.
|
|
iwyu_output += iwyu_output.replace('changed', 'unchanged')
|
|
|
|
self.RegisterFileContents({'changed': changed_infile,
|
|
'unchanged': unchanged_infile})
|
|
# unchanged should not be edited, since it matches ignore_re.
|
|
self.flags.ignore_re = 'nch'
|
|
self.ProcessAndTest(iwyu_output, unedited_files=['unchanged'])
|
|
|
|
def testOnlyRe(self):
|
|
"""Test the behavior of the --only_re flag."""
|
|
changed_infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
unchanged_infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h>
|
|
#include "used.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
output should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
output should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for output:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
# Have the exact same iwyu output for 'alice.cpp' as for 'bob.cpp'.
|
|
iwyu_output = (iwyu_output.replace('output', 'alice.cpp') +
|
|
iwyu_output.replace('output', 'bob.cpp'))
|
|
|
|
self.RegisterFileContents({'alice.cpp': changed_infile,
|
|
'bob.cpp': unchanged_infile})
|
|
# only alice.cpp should be edited, since it matches only_re.
|
|
self.flags.only_re = 'lice'
|
|
self.ProcessAndTest(iwyu_output, unedited_files=['bob.cpp'])
|
|
|
|
def testIgnoreAndOnlyRe(self):
|
|
"""Test the behavior of both --ignore_re and --only_re flags."""
|
|
changed_infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h> ///-
|
|
///+#include <stdio.h>
|
|
#include "used.h"
|
|
///+#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
unchanged_infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h>
|
|
#include "used.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
output should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
output should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for output:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
# Have the exact same iwyu output for 'alice.cpp' as for 'bob.cpp' and 'charlie.cpp'
|
|
iwyu_output = (iwyu_output.replace('output', 'alice.cpp') +
|
|
iwyu_output.replace('output', 'bob.cpp') +
|
|
iwyu_output.replace('output', 'charlie.cpp'))
|
|
|
|
self.RegisterFileContents({'alice.cpp': changed_infile,
|
|
'bob.cpp': unchanged_infile,
|
|
'charlie.cpp': changed_infile})
|
|
# only alice.cpp should be edited, since it matches only_re and not ignore_re
|
|
self.flags.only_re = 'li'
|
|
self.flags.ignore_re = 'char'
|
|
self.ProcessAndTest(iwyu_output, unedited_files=['bob.cpp', 'charlie.cpp'])
|
|
|
|
def testSortIncludes(self):
|
|
"""Test sorting includes only -- like running fix_includes.py -s."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <stdio.h>
|
|
// This file is not used.
|
|
#include <notused.h>
|
|
|
|
// This file is not used either.
|
|
// It's not used.
|
|
// Not used at all.
|
|
#include <notused2.h>
|
|
|
|
#include "notused3.h"
|
|
|
|
// This comment should stay, it's not before an #include.
|
|
const int kInt = 5;
|
|
// This file is used.
|
|
// It's definitedly used.
|
|
#include "used.h"
|
|
#include <stdlib.h>
|
|
|
|
const int kInt2 = 6;
|
|
|
|
#include "foo.cc"
|
|
|
|
// This comment should stay, it's not before an #include.
|
|
int main() { return 0; }
|
|
"""
|
|
expected_output = """\
|
|
// Copyright 2010
|
|
|
|
// This file is not used.
|
|
#include <notused.h>
|
|
// This file is not used either.
|
|
// It's not used.
|
|
// Not used at all.
|
|
#include <notused2.h>
|
|
#include <stdio.h>
|
|
#include "notused3.h"
|
|
|
|
// This comment should stay, it's not before an #include.
|
|
const int kInt = 5;
|
|
#include <stdlib.h>
|
|
// This file is used.
|
|
// It's definitedly used.
|
|
#include "used.h"
|
|
|
|
const int kInt2 = 6;
|
|
|
|
#include "foo.cc"
|
|
|
|
// This comment should stay, it's not before an #include.
|
|
int main() { return 0; }
|
|
"""
|
|
self.RegisterFileContents({'sort': infile})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(['sort'], self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
def testSortingMultipleFiles(self):
|
|
"""Tests passing more than one argument to SortIncludesInFiles()."""
|
|
infile1 = """\
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
"""
|
|
infile2 = """\
|
|
#include "z.h"
|
|
#include "y.h"
|
|
#include "x.y"
|
|
"""
|
|
|
|
expected_output = """\
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "x.y"
|
|
#include "y.h"
|
|
#include "z.h"
|
|
"""
|
|
self.RegisterFileContents({'f1': infile1, 'f2': infile2})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(['f1', 'f2'],
|
|
self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(2, num_files_modified)
|
|
|
|
def testSortingIncludesAlreadySorted(self):
|
|
"""Tests sorting includes only, when includes are already sorted."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
|
|
namespace Foo; // fwd-decls are out of order, but sorter ignores them
|
|
|
|
namespace Bar;
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
self.RegisterFileContents({'sort_nosorting.h': infile})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(['sort_nosorting.h'],
|
|
self.flags)
|
|
self.assertListEqual([], self.actual_after_contents)
|
|
self.assertEqual(0, num_files_modified)
|
|
|
|
def testBarrierIncludes(self):
|
|
"""Tests that we correctly sort 'around' _BARRIER_INCLUDES."""
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <linux/a_stay_top.h>
|
|
#include <stdlib.h> ///-
|
|
#include <linux/can_sort_around_this_deleted_include> ///-
|
|
#include <stdio.h>
|
|
///+#include <stdlib.h>
|
|
#include "user/include.h"
|
|
///+#include "user/new_include.h"
|
|
#include <linux/c_stay_second.h>
|
|
#include <linux/b_stay_third.h>
|
|
#include <ctype.h>
|
|
#include <cpp_include>
|
|
///+#include <new_cpp_include>
|
|
#include <linux/d_stay_fourth.h>
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
barrier_includes.h should add these lines:
|
|
#include "user/new_include.h"
|
|
#include <new_cpp_include>
|
|
|
|
barrier_includes.h should remove these lines:
|
|
- #include <linux/can_sort_around_this_deleted_include> // lines 5-5
|
|
|
|
The full include-list for barrier_includes.h:
|
|
#include "user/include.h"
|
|
#include "user/new_include.h"
|
|
#include <cpp_include>
|
|
#include <ctype.h>
|
|
#include <linux/a_stay_top.h>
|
|
#include <linux/b_stay_third.h>
|
|
#include <linux/c_stay_second.h>
|
|
#include <linux/d_stay_fourth.h>
|
|
#include <new_cpp_include>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'barrier_includes.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testSortingMainCUIncludeInSameDirectory(self):
|
|
"""Check that we identify when first .h file is a main-cu #include."""
|
|
infile = """\
|
|
#include <stdio.h>
|
|
#include "me/subdir0/foo.h"
|
|
#include "other/baz.h"
|
|
"""
|
|
expected_output = """\
|
|
#include "me/subdir0/foo.h"
|
|
#include <stdio.h>
|
|
#include "other/baz.h"
|
|
"""
|
|
self.RegisterFileContents({'me/subdir0/foo.cc': infile})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(
|
|
['me/subdir0/foo.cc'], self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
def testSortingMainCUIncludeViaPragma(self):
|
|
"""Check that we treat (potentially multiple) associated headers as
|
|
main-cu #includes."""
|
|
infile = """\
|
|
#include <stdio.h>
|
|
#include "other/dir/bar.h" // IWYU pragma: associated
|
|
#include "other/baz.h" // IWYU pragma: associated
|
|
"""
|
|
expected_output = """\
|
|
#include "other/baz.h" // IWYU pragma: associated
|
|
#include "other/dir/bar.h" // IWYU pragma: associated
|
|
#include <stdio.h>
|
|
"""
|
|
self.RegisterFileContents({'me/subdir0/foo.cc': infile})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(
|
|
['me/subdir0/foo.cc'], self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
def testSortingMainCUIncludeWithUpperCaseH(self):
|
|
"""Check that we identify when first .H file is a main-cu #include."""
|
|
infile = """\
|
|
#include <stdio.h>
|
|
#include "foo.H"
|
|
"""
|
|
expected_output = """\
|
|
#include "foo.H"
|
|
#include <stdio.h>
|
|
"""
|
|
self.RegisterFileContents({'foo.cc': infile})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(
|
|
['foo.cc'], self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
def testSortingMainCUIncludeWithHpp(self):
|
|
"""Check that we identify when first .hpp file is a main-cu #include."""
|
|
infile = """\
|
|
#include <stdio.h>
|
|
#include "foo.hpp"
|
|
"""
|
|
expected_output = """\
|
|
#include "foo.hpp"
|
|
#include <stdio.h>
|
|
"""
|
|
self.RegisterFileContents({'foo.cc': infile})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(
|
|
['foo.cc'], self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
def testSortingMainCUIncludeWithMixedCaseInl(self):
|
|
"""Check that we identify when first -inl.hpp file with mixed case
|
|
is a main-cu #include."""
|
|
infile = """\
|
|
#include <stdio.h>
|
|
#include "foo-InL.h"
|
|
"""
|
|
expected_output = """\
|
|
#include "foo-InL.h"
|
|
#include <stdio.h>
|
|
"""
|
|
self.RegisterFileContents({'foo.cc': infile})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(
|
|
['foo.cc'], self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
def testSortingMainCUIncludeInSameDirectoryWithInl(self):
|
|
"""Check that we identify when first -inl.h file is a main-cu #include."""
|
|
infile = """\
|
|
#include <stdio.h>
|
|
#include "me/subdir0/foo-inl.h"
|
|
#include "other/baz.h"
|
|
"""
|
|
expected_output = """\
|
|
#include "me/subdir0/foo-inl.h"
|
|
#include <stdio.h>
|
|
#include "other/baz.h"
|
|
"""
|
|
self.RegisterFileContents({'me/subdir0/foo.cc': infile})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(
|
|
['me/subdir0/foo.cc'], self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
def testSortingMainCUIncludeInDifferentDirectory(self):
|
|
"""Check that we identify when first .h file is a main-cu #include."""
|
|
infile = """\
|
|
#include "me/subdir0/foo.h"
|
|
#include <stdio.h>
|
|
#include "other/baz.h"
|
|
"""
|
|
self.RegisterFileContents({'me/other_subdir/foo.cc': infile})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(
|
|
['me/other_subdir/foo.cc'], self.flags)
|
|
self.assertListEqual([], self.actual_after_contents)
|
|
self.assertEqual(0, num_files_modified)
|
|
|
|
def testSortingMainCUIncludeInDifferentDirectoryWhenNotFirst(self):
|
|
"""Check that we don't let second .h be a main-cu #include."""
|
|
infile = """\
|
|
#include <stdio.h>
|
|
#include "me/subdir0/foo.h"
|
|
#include "other/baz.h"
|
|
"""
|
|
self.RegisterFileContents({'me/other_subdir/foo.cc': infile})
|
|
num_files_modified = fix_includes.SortIncludesInFiles(
|
|
['me/other_subdir/foo.cc'], self.flags)
|
|
self.assertListEqual([], self.actual_after_contents)
|
|
self.assertEqual(0, num_files_modified)
|
|
|
|
def testSortingProjectIncludesAuto(self):
|
|
"""Check that project includes can be sorted separately."""
|
|
infile = """\
|
|
#include "me/subdir0/foo.h"
|
|
#include <stdio.h>
|
|
#include "me/subdir2/bar.h"
|
|
#include "me/subdir1/bar.h"
|
|
#include "me/subdir0/bar.h"
|
|
#include "other/baz.h"
|
|
"""
|
|
expected_output = """\
|
|
#include "me/subdir0/foo.h"
|
|
#include <stdio.h>
|
|
#include "other/baz.h"
|
|
#include "me/subdir0/bar.h"
|
|
#include "me/subdir1/bar.h"
|
|
#include "me/subdir2/bar.h"
|
|
"""
|
|
self.RegisterFileContents({'me/subdir0/foo.cc': infile})
|
|
self.flags.separate_project_includes = '<tld>'
|
|
num_files_modified = fix_includes.SortIncludesInFiles(['me/subdir0/foo.cc'],
|
|
self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
def testSortingProjectIncludesUserSpecified(self):
|
|
"""Test user-specified project directory name."""
|
|
infile = """\
|
|
#include "me/subdir0/foo.h"
|
|
#include <stdio.h>
|
|
#include "me/subdir2/bar.h"
|
|
#include "me/subdir1/bar.h"
|
|
#include "me/subdir0/bar.h"
|
|
#include "other/baz.h"
|
|
"""
|
|
expected_output = """\
|
|
#include "me/subdir0/foo.h"
|
|
#include <stdio.h>
|
|
#include "me/subdir1/bar.h"
|
|
#include "me/subdir2/bar.h"
|
|
#include "other/baz.h"
|
|
#include "me/subdir0/bar.h"
|
|
"""
|
|
self.RegisterFileContents({'me/subdir0/foo.cc': infile})
|
|
self.flags.separate_project_includes = 'me/subdir0'
|
|
num_files_modified = fix_includes.SortIncludesInFiles(['me/subdir0/foo.cc'],
|
|
self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
def testAddingNewIncludesAfterRemovingOldOnes(self):
|
|
infile = """\
|
|
// Copyright 2008 Google Inc. All Rights Reserved.
|
|
// Author: zhifengc@google.com (Zhifeng Chen)
|
|
|
|
#ifndef STRUCTUREDSEARCH_COMMON_INTERNAL_DFS_H_
|
|
#define STRUCTUREDSEARCH_COMMON_INTERNAL_DFS_H_
|
|
|
|
#include "util/task/status.h" ///-
|
|
#include "strings/stringpiece.h" ///-
|
|
///+#include <string> // for string
|
|
///+#include "base/macros.h" // for DISALLOW_COPY_AND_ASSIGN
|
|
///+#include "base/scoped_ptr.h" // for scoped_ptr
|
|
|
|
class Query;
|
|
///+namespace util {
|
|
///+class Status;
|
|
///+} // namespace util
|
|
|
|
namespace structuredsearch {
|
|
|
|
///+class FieldSpecification;
|
|
class FieldTokenizer;
|
|
class FieldSpecification; ///-
|
|
class TokenizationSpec;
|
|
|
|
class QueryXlator { ... };
|
|
|
|
#endif // #define STRUCTUREDSEARCH_COMMON_INTERNAL_DFS_H_
|
|
"""
|
|
iwyu_output = """\
|
|
structuredsearch/common/internal/query_field_xlate.h should add these lines:
|
|
#include <string> // for string
|
|
#include "base/macros.h" // for DISALLOW_COPY_AND_ASSIGN
|
|
#include "base/scoped_ptr.h" // for scoped_ptr
|
|
namespace util { class Status; }
|
|
|
|
structuredsearch/common/internal/query_field_xlate.h should remove these lines:
|
|
- #include "strings/stringpiece.h" // lines 8-8
|
|
- #include "util/task/status.h" // lines 7-7
|
|
|
|
The full include-list for structuredsearch/common/internal/query_field_xlate.h:
|
|
#include <string> // for string
|
|
#include "base/macros.h" // for DISALLOW_COPY_AND_ASSIGN
|
|
#include "base/scoped_ptr.h" // for scoped_ptr
|
|
class Query; // lines 10-10
|
|
namespace structuredsearch { class FieldSpecification; } // lines 15-15
|
|
namespace structuredsearch { class FieldTokenizer; } // lines 14-14
|
|
namespace structuredsearch { class TokenizationSpec; } // lines 16-16
|
|
namespace util { class Status; }
|
|
---
|
|
"""
|
|
self.RegisterFileContents(
|
|
{'structuredsearch/common/internal/query_field_xlate.h': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testDryRun(self):
|
|
"""Tests that --dry_run mode does not modify files."""
|
|
self.flags.dry_run = True
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include <notused.h>
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
dry_run should add these lines:
|
|
#include <stdio.h>
|
|
#include "used2.h"
|
|
|
|
dry_run should remove these lines:
|
|
- #include <notused.h> // lines 3-3
|
|
|
|
The full include-list for dry_run:
|
|
#include <stdio.h>
|
|
#include "used.h"
|
|
#include "used2.h"
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'dry_run': infile})
|
|
num_modified_files = fix_includes.ProcessIWYUOutput(
|
|
StringIO(iwyu_output), ['dry_run'], self.flags, None)
|
|
self.assertListEqual([], self.actual_after_contents)
|
|
self.assertEqual(1, num_modified_files)
|
|
|
|
def testAddForwardDeclareAndKeepIwyuNamespaceFormat(self):
|
|
"""Tests that --keep_iwyu_namespace_format writes namespace lines
|
|
using the IWYU one-line format.
|
|
Input code similar to case testAddForwardDeclareInNamespace."""
|
|
self.flags.keep_iwyu_namespace_format = True
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
///+namespace ns { class Foo; }
|
|
///+namespace ns { namespace ns2 { namespace ns3 { class Bar; } } }
|
|
///+namespace ns { namespace ns2 { namespace ns3 { template <typename T> class Bang; } } }
|
|
///+namespace ns { namespace ns4 { class Baz; } }
|
|
///+
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_declare_keep_iwyu_namespace should add these lines:
|
|
namespace ns { class Foo; }
|
|
namespace ns { namespace ns2 { namespace ns3 { class Bar; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class Bang; } } }
|
|
namespace ns { namespace ns4 { class Baz; } }
|
|
|
|
add_fwd_declare_keep_iwyu_namespace should remove these lines:
|
|
|
|
The full include-list for add_fwd_declare_keep_iwyu_namespace:
|
|
#include "foo.h" // lines 3-3
|
|
namespace ns { class Foo; }
|
|
namespace ns { namespace ns2 { namespace ns3 { class Bar; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class Bang; } } }
|
|
namespace ns { namespace ns4 { class Baz; } }
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_declare_keep_iwyu_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output, expected_num_modified_files=1)
|
|
|
|
def testAddNestedForwardDeclaresWithKeepIwyuNamespaceFormat(self):
|
|
"""Tests that --keep_iwyu_namespace_format writes namespace lines
|
|
using the IWYU one-line format.
|
|
Input code similar to case
|
|
testAddForwardDeclareInsideNamespaceWithoutForwardDeclaresAlready."""
|
|
self.flags.keep_iwyu_namespace_format = True
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
class Bar;
|
|
///+class Foo;
|
|
///+namespace ns1 { class NsFoo; }
|
|
///+namespace ns1 { namespace ns2 { namespace ns3 { class NsBaz; } } }
|
|
///+namespace ns1 { namespace ns2 { namespace ns3 { template <typename T> class NsBang; } } }
|
|
template <typename T> class Baz;
|
|
|
|
|
|
namespace ns {
|
|
///-
|
|
///+class NsFoo;
|
|
///+namespace ns2 { namespace ns3 { class NsBaz; } }
|
|
///+namespace ns2 { namespace ns3 { template <typename T> class NsBang; } }
|
|
///+
|
|
class NsBar;
|
|
|
|
namespace ns2 { // we sure do love nesting our namespaces!
|
|
|
|
int MyFunction() { }
|
|
|
|
}
|
|
}
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_decl_with_keep_iwyu_format should add these lines:
|
|
class Foo;
|
|
namespace ns { class NsFoo; }
|
|
namespace ns { namespace ns2 { namespace ns3 { class NsBaz; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class NsBang; } } }
|
|
namespace ns1 { class NsFoo; }
|
|
namespace ns1 { namespace ns2 { namespace ns3 { class NsBaz; } } }
|
|
namespace ns1 { namespace ns2 { namespace ns3 { template <typename T> class NsBang; } } }
|
|
|
|
add_fwd_decl_with_keep_iwyu_format should remove these lines:
|
|
|
|
The full include-list for add_fwd_decl_with_keep_iwyu_format:
|
|
#include "foo.h" // lines 3-3
|
|
class Bar; // lines 5-5
|
|
class Foo;
|
|
namespace ns { class NsFoo; }
|
|
namespace ns { namespace ns2 { class NsBar; } }
|
|
namespace ns { namespace ns2 { namespace ns3 { class NsBaz; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class NsBang; } } }
|
|
namespace ns1 { class NsFoo; }
|
|
namespace ns1 { namespace ns2 { namespace ns3 { class NsBaz; } } }
|
|
namespace ns1 { namespace ns2 { namespace ns3 { template <typename T> class NsBang; } } }
|
|
template <typename T> class Baz; // lines 6-6
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_decl_with_keep_iwyu_format': infile})
|
|
self.ProcessAndTest(iwyu_output)
|
|
|
|
def testAddForwardDeclareInNamespaceWithKeepIwyuNamespaceFormat(self):
|
|
"""Tests that --keep_iwyu_namespace_format writes namespace lines
|
|
using the IWYU one-line format.
|
|
Input code similar to case testAddForwardDeclareInNamespace."""
|
|
self.flags.keep_iwyu_namespace_format = True
|
|
infile = """\
|
|
// Copyright 2010
|
|
|
|
#include "foo.h"
|
|
|
|
///+namespace ns { class Foo; }
|
|
///+namespace ns { namespace ns2 { namespace ns3 { class Bar; } } }
|
|
///+namespace ns { namespace ns2 { namespace ns3 { template <typename T> class Bang; } } }
|
|
///+namespace ns { namespace ns4 { class Baz; } }
|
|
///+
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
iwyu_output = """\
|
|
add_fwd_declare_keep_iwyu_namespace should add these lines:
|
|
namespace ns { class Foo; }
|
|
namespace ns { namespace ns2 { namespace ns3 { class Bar; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class Bang; } } }
|
|
namespace ns { namespace ns4 { class Baz; } }
|
|
|
|
add_fwd_declare_keep_iwyu_namespace should remove these lines:
|
|
|
|
The full include-list for add_fwd_declare_keep_iwyu_namespace:
|
|
#include "foo.h" // lines 3-3
|
|
namespace ns { class Foo; }
|
|
namespace ns { namespace ns2 { namespace ns3 { class Bar; } } }
|
|
namespace ns { namespace ns2 { namespace ns3 { template <typename T> class Bang; } } }
|
|
namespace ns { namespace ns4 { class Baz; } }
|
|
---
|
|
"""
|
|
self.RegisterFileContents({'add_fwd_declare_keep_iwyu_namespace': infile})
|
|
self.ProcessAndTest(iwyu_output, expected_num_modified_files=1)
|
|
|
|
def testBasedir(self):
|
|
self.flags.basedir = "/project/build/"
|
|
iwyu_output = """\
|
|
../src/source.cc should add these lines:
|
|
|
|
../src/source.cc should remove these lines:
|
|
- #include <unused.h> // lines 1-1
|
|
|
|
The full include-list for ../src/source.cc:
|
|
#include <used.h>
|
|
---
|
|
"""
|
|
infile = """\
|
|
#include <unused.h> ///-
|
|
#include <used.h>
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
self.RegisterFileContents({'/project/src/source.cc': infile})
|
|
self.ProcessAndTest(iwyu_output, expected_num_modified_files=1)
|
|
|
|
def testBasedirWithFilesToProcess(self):
|
|
self.flags.basedir = "/project/build/"
|
|
iwyu_output = """\
|
|
../src/changed.cc should add these lines:
|
|
|
|
../src/changed.cc should remove these lines:
|
|
- #include <unused.h> // lines 1-1
|
|
|
|
The full include-list for ../src/changed.cc:
|
|
#include <used.h>
|
|
---
|
|
"""
|
|
changed_file = """\
|
|
#include <unused.h> ///-
|
|
#include <used.h>
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
unchanged_file = """\
|
|
#include <unused.h>
|
|
#include <used.h>
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
|
|
iwyu_output += iwyu_output.replace('changed.cc', 'unchanged.cc')
|
|
|
|
self.RegisterFileContents({
|
|
'/project/src/changed.cc': changed_file,
|
|
'/project/src/unchanged.cc': unchanged_file
|
|
})
|
|
self.ProcessAndTest(iwyu_output, cmdline_files=['/project/src/changed.cc'],
|
|
unedited_files=['/project/src/unchanged.cc'])
|
|
|
|
def testBasedirWithRelativeCmdlineFiles(self):
|
|
self.flags.basedir = "/project/build/"
|
|
iwyu_output = """\
|
|
../src/changed.cc should add these lines:
|
|
|
|
../src/changed.cc should remove these lines:
|
|
- #include <unused.h> // lines 1-1
|
|
|
|
The full include-list for ../src/changed.cc:
|
|
#include <used.h>
|
|
---
|
|
"""
|
|
changed_file = """\
|
|
#include <unused.h> ///-
|
|
#include <used.h>
|
|
|
|
int main() { return 0; }
|
|
"""
|
|
|
|
self.RegisterFileContents({
|
|
# File path is normalized to absolute by ProcessIWYUOutput.
|
|
'/project/src/changed.cc': changed_file,
|
|
})
|
|
self.ProcessAndTest(iwyu_output, cmdline_files=['changed.cc'],
|
|
cwd='/project/src')
|
|
|
|
def testMain(self):
|
|
"""Make sure calling main doesn't crash. Inspired by a syntax-error bug."""
|
|
# Give an empty stdin so we don't actually try to parse anything.
|
|
old_stdin = sys.stdin
|
|
try:
|
|
sys.stdin = StringIO()
|
|
fix_includes.main(['fix_includes.py']) # argv[0] doesn't really matter
|
|
finally:
|
|
sys.stdin = old_stdin
|
|
|
|
def testFilenamesForSortingInMain(self):
|
|
"""Make sure if we use s, we have a filename specified, in main()."""
|
|
# -s without any files to sort.
|
|
self.assertRaises(SystemExit, fix_includes.main,
|
|
['fix_includes.py', '-s'])
|
|
|
|
def testReorderingInclusions(self):
|
|
"""Show that the --reorder flag causes #includes to be sorted."""
|
|
infile = """\
|
|
// namespace B
|
|
namespace B { class BC; } // B
|
|
// namespace A
|
|
namespace A { class AC; } // A
|
|
// b
|
|
#include "b" // b
|
|
// c
|
|
#include <c> // c
|
|
// a
|
|
#include <a> // a
|
|
// a
|
|
#include "a" // a
|
|
// asdf
|
|
#ifdef asdf
|
|
// x
|
|
#include <x> // x
|
|
// endif
|
|
#endif
|
|
"""
|
|
expected_output = """\
|
|
// namespace B
|
|
namespace B { class BC; } // B
|
|
// namespace A
|
|
namespace A { class AC; } // A
|
|
// a
|
|
#include <a> // a
|
|
// c
|
|
#include <c> // c
|
|
// a
|
|
#include "a" // a
|
|
// b
|
|
#include "b" // b
|
|
// asdf
|
|
#ifdef asdf
|
|
// x
|
|
#include <x> // x
|
|
// endif
|
|
#endif
|
|
"""
|
|
self.RegisterFileContents({'inclusions_reordered.cc': infile})
|
|
self.flags.reorder = True
|
|
num_files_modified = fix_includes.SortIncludesInFiles(
|
|
['inclusions_reordered.cc'], self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
def testNoReorderingInclusions(self):
|
|
"""Show that the --noreorder flag causes #includes not to be sorted."""
|
|
infile = """\
|
|
// namespace B
|
|
namespace B { class BC; } // B
|
|
// namespace A
|
|
namespace A { class AC; } // A
|
|
// b
|
|
#include "b" // b
|
|
// c
|
|
#include <c> // c
|
|
// a
|
|
#include <a> // a
|
|
// a
|
|
#include "a" // a
|
|
// asdf
|
|
#ifdef asdf
|
|
// x
|
|
#include <x> // x
|
|
// endif
|
|
#endif
|
|
"""
|
|
expected_output = """\
|
|
// namespace B
|
|
namespace B { class BC; } // B
|
|
// namespace A
|
|
namespace A { class AC; } // A
|
|
// c
|
|
#include <c> // c
|
|
// a
|
|
#include <a> // a
|
|
// b
|
|
#include "b" // b
|
|
// a
|
|
#include "a" // a
|
|
// asdf
|
|
#ifdef asdf
|
|
// x
|
|
#include <x> // x
|
|
// endif
|
|
#endif
|
|
"""
|
|
self.RegisterFileContents({'inclusions_not_reordered.cc': infile})
|
|
self.flags.reorder = False
|
|
num_files_modified = fix_includes.SortIncludesInFiles(
|
|
['inclusions_not_reordered.cc'], self.flags)
|
|
self.assertListEqual(expected_output.splitlines(True),
|
|
self.actual_after_contents)
|
|
self.assertEqual(1, num_files_modified)
|
|
|
|
|
|
class FileInfoTest(unittest.TestCase):
|
|
""" Unit test for file info detection """
|
|
|
|
def testEndingsWindows(self):
|
|
buf = b'first\r\nsecond\r\nthird\r\n'
|
|
self.assertEqual('\r\n', fix_includes.FileInfo.guess_linesep(buf))
|
|
|
|
def testEndingsUnix(self):
|
|
buf = b'first\nsecond\nthird\n'
|
|
self.assertEqual('\n', fix_includes.FileInfo.guess_linesep(buf))
|
|
|
|
def testEndingsMixedUnixMajority(self):
|
|
buf = b'first\nsecond\nsecond-and-a-half\r\nthird\nfourth\r\n'
|
|
self.assertEqual('\n', fix_includes.FileInfo.guess_linesep(buf))
|
|
|
|
def testEndingsMixedWindowsMajority(self):
|
|
buf = b'first\nsecond\r\nsecond-and-a-half\r\nthird\nfourth\r\n'
|
|
self.assertEqual('\r\n', fix_includes.FileInfo.guess_linesep(buf))
|
|
|
|
def testEndingsMixedTie(self):
|
|
buf = b'first\nsecond\nthird\r\nfourth\r\n'
|
|
self.assertEqual(fix_includes.FileInfo.DEFAULT_LINESEP,
|
|
fix_includes.FileInfo.guess_linesep(buf))
|
|
|
|
def testEncodingASCII(self):
|
|
buf = b'abcdefgh'
|
|
self.assertEqual('ascii', fix_includes.FileInfo.guess_encoding(buf))
|
|
|
|
def testEncodingUTF8BOM(self):
|
|
buf = b'\xef\xbb\xbfSomeASCIIButWithTheBOM'
|
|
self.assertEqual('utf-8-sig', fix_includes.FileInfo.guess_encoding(buf))
|
|
|
|
def testEncodingUTF8NoBOM(self):
|
|
# This is a recurring test input in Swedish, translates to "shrimp sandwich"
|
|
# and contains all three Swedish exotic characters.
|
|
buf = b'r\xc3\xa4ksm\xc3\xb6rg\xc3\xa5s'
|
|
self.assertEqual('utf-8', fix_includes.FileInfo.guess_encoding(buf))
|
|
|
|
def testEncodingISO8859_1(self):
|
|
# Yours truly
|
|
buf = b'Kim Gr\xe4sman'
|
|
self.assertEqual('windows-1250', fix_includes.FileInfo.guess_encoding(buf))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|