blob: 6087d8f20ae61d2e4974ddd3337c97838893859b [file] [log] [blame]
#!/usr/bin/python
# -*- coding: utf-8; -*-
#
# Copyright (c) 2009 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Unit test for cpplint.py."""
# TODO(unknown): Add a good test that tests UpdateIncludeState.
import codecs
import os
import random
import re
import subprocess
import sys
import unittest
import cpplint
try:
xrange # Python 2
except NameError:
xrange = range # Python 3
# This class works as an error collector and replaces cpplint.Error
# function for the unit tests. We also verify each category we see
# is in cpplint._ERROR_CATEGORIES, to help keep that list up to date.
class ErrorCollector(object):
# These are a global list, covering all categories seen ever.
_ERROR_CATEGORIES = cpplint._ERROR_CATEGORIES
_SEEN_ERROR_CATEGORIES = {}
def __init__(self, assert_fn):
"""assert_fn: a function to call when we notice a problem."""
self._assert_fn = assert_fn
self._errors = []
cpplint.ResetNolintSuppressions()
def __call__(self, unused_filename, linenum,
category, confidence, message):
self._assert_fn(category in self._ERROR_CATEGORIES,
'Message "%s" has category "%s",'
' which is not in _ERROR_CATEGORIES' % (message, category))
self._SEEN_ERROR_CATEGORIES[category] = 1
if cpplint._ShouldPrintError(category, confidence, linenum):
self._errors.append('%s [%s] [%d]' % (message, category, confidence))
def Results(self):
if len(self._errors) < 2:
return ''.join(self._errors) # Most tests expect to have a string.
else:
return self._errors # Let's give a list if there is more than one.
def ResultList(self):
return self._errors
def VerifyAllCategoriesAreSeen(self):
"""Fails if there's a category in _ERROR_CATEGORIES~_SEEN_ERROR_CATEGORIES.
This should only be called after all tests are run, so
_SEEN_ERROR_CATEGORIES has had a chance to fully populate. Since
this isn't called from within the normal unittest framework, we
can't use the normal unittest assert macros. Instead we just exit
when we see an error. Good thing this test is always run last!
"""
for category in self._ERROR_CATEGORIES:
if category not in self._SEEN_ERROR_CATEGORIES:
sys.exit('FATAL ERROR: There are no tests for category "%s"' % category)
def RemoveIfPresent(self, substr):
for (index, error) in enumerate(self._errors):
if error.find(substr) != -1:
self._errors = self._errors[0:index] + self._errors[(index + 1):]
break
# This class is a lame mock of codecs. We do not verify filename, mode, or
# encoding, but for the current use case it is not needed.
class MockIo(object):
def __init__(self, mock_file):
self.mock_file = mock_file
def open(self, # pylint: disable-msg=C6409
unused_filename, unused_mode, unused_encoding, _):
return self.mock_file
class CpplintTestBase(unittest.TestCase):
"""Provides some useful helper functions for cpplint tests."""
def setUp(self):
# Allow subclasses to cheat os.path.abspath called in FileInfo class.
self.os_path_abspath_orig = os.path.abspath
def tearDown(self):
os.path.abspath = self.os_path_abspath_orig
# Perform lint on single line of input and return the error message.
def PerformSingleLineLint(self, code):
error_collector = ErrorCollector(self.assert_)
lines = code.split('\n')
cpplint.RemoveMultiLineComments('foo.h', lines, error_collector)
clean_lines = cpplint.CleansedLines(lines)
include_state = cpplint._IncludeState()
function_state = cpplint._FunctionState()
nesting_state = cpplint.NestingState()
cpplint.ProcessLine('foo.cc', 'cc', clean_lines, 0,
include_state, function_state,
nesting_state, error_collector)
# Single-line lint tests are allowed to fail the 'unlintable function'
# check.
error_collector.RemoveIfPresent(
'Lint failed to find start of function body.')
return error_collector.Results()
# Perform lint over multiple lines and return the error message.
def PerformMultiLineLint(self, code):
error_collector = ErrorCollector(self.assert_)
lines = code.split('\n')
cpplint.RemoveMultiLineComments('foo.h', lines, error_collector)
lines = cpplint.CleansedLines(lines)
nesting_state = cpplint.NestingState()
for i in xrange(lines.NumLines()):
nesting_state.Update('foo.h', lines, i, error_collector)
cpplint.CheckStyle('foo.h', lines, i, 'h', nesting_state,
error_collector)
cpplint.CheckForNonStandardConstructs('foo.h', lines, i,
nesting_state, error_collector)
nesting_state.CheckCompletedBlocks('foo.h', error_collector)
return error_collector.Results()
# Similar to PerformMultiLineLint, but calls CheckLanguage instead of
# CheckForNonStandardConstructs
def PerformLanguageRulesCheck(self, file_name, code):
error_collector = ErrorCollector(self.assert_)
include_state = cpplint._IncludeState()
nesting_state = cpplint.NestingState()
lines = code.split('\n')
cpplint.RemoveMultiLineComments(file_name, lines, error_collector)
lines = cpplint.CleansedLines(lines)
ext = file_name[file_name.rfind('.') + 1:]
for i in xrange(lines.NumLines()):
cpplint.CheckLanguage(file_name, lines, i, ext, include_state,
nesting_state, error_collector)
return error_collector.Results()
def PerformFunctionLengthsCheck(self, code):
"""Perform Lint function length check on block of code and return warnings.
Builds up an array of lines corresponding to the code and strips comments
using cpplint functions.
Establishes an error collector and invokes the function length checking
function following cpplint's pattern.
Args:
code: C++ source code expected to generate a warning message.
Returns:
The accumulated errors.
"""
file_name = 'foo.cc'
error_collector = ErrorCollector(self.assert_)
function_state = cpplint._FunctionState()
lines = code.split('\n')
cpplint.RemoveMultiLineComments(file_name, lines, error_collector)
lines = cpplint.CleansedLines(lines)
for i in xrange(lines.NumLines()):
cpplint.CheckForFunctionLengths(file_name, lines, i,
function_state, error_collector)
return error_collector.Results()
def PerformIncludeWhatYouUse(self, code, filename='foo.h', io=codecs):
# First, build up the include state.
error_collector = ErrorCollector(self.assert_)
include_state = cpplint._IncludeState()
nesting_state = cpplint.NestingState()
lines = code.split('\n')
cpplint.RemoveMultiLineComments(filename, lines, error_collector)
lines = cpplint.CleansedLines(lines)
for i in xrange(lines.NumLines()):
cpplint.CheckLanguage(filename, lines, i, '.h', include_state,
nesting_state, error_collector)
# We could clear the error_collector here, but this should
# also be fine, since our IncludeWhatYouUse unittests do not
# have language problems.
# Second, look for missing includes.
cpplint.CheckForIncludeWhatYouUse(filename, lines, include_state,
error_collector, io)
return error_collector.Results()
# Perform lint and compare the error message with "expected_message".
def TestLint(self, code, expected_message):
self.assertEquals(expected_message, self.PerformSingleLineLint(code))
def TestMultiLineLint(self, code, expected_message):
self.assertEquals(expected_message, self.PerformMultiLineLint(code))
def TestMultiLineLintRE(self, code, expected_message_re):
message = self.PerformMultiLineLint(code)
if not re.search(expected_message_re, message):
self.fail('Message was:\n' + message + 'Expected match to "' +
expected_message_re + '"')
def TestLanguageRulesCheck(self, file_name, code, expected_message):
self.assertEquals(expected_message,
self.PerformLanguageRulesCheck(file_name, code))
def TestIncludeWhatYouUse(self, code, expected_message):
self.assertEquals(expected_message,
self.PerformIncludeWhatYouUse(code))
def TestBlankLinesCheck(self, lines, start_errors, end_errors):
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData('foo.cc', 'cc', lines, error_collector)
self.assertEquals(
start_errors,
error_collector.Results().count(
'Redundant blank line at the start of a code block '
'should be deleted. [whitespace/blank_line] [2]'))
self.assertEquals(
end_errors,
error_collector.Results().count(
'Redundant blank line at the end of a code block '
'should be deleted. [whitespace/blank_line] [3]'))
class CpplintTest(CpplintTestBase):
def GetNamespaceResults(self, lines):
error_collector = ErrorCollector(self.assert_)
cpplint.RemoveMultiLineComments('foo.h', lines, error_collector)
lines = cpplint.CleansedLines(lines)
nesting_state = cpplint.NestingState()
for i in xrange(lines.NumLines()):
nesting_state.Update('foo.h', lines, i, error_collector)
cpplint.CheckForNamespaceIndentation('foo.h', nesting_state,
lines, i, error_collector)
return error_collector.Results()
def testForwardDeclarationNameSpaceIndentation(self):
lines = ['namespace Test {',
' class ForwardDeclaration;',
'} // namespace Test']
results = self.GetNamespaceResults(lines)
self.assertEquals(results, 'Do not indent within a namespace '
' [runtime/indentation_namespace] [4]')
def testNameSpaceIndentationForClass(self):
lines = ['namespace Test {',
'void foo() { }',
' class Test {',
' };',
'} // namespace Test']
results = self.GetNamespaceResults(lines)
self.assertEquals(results, 'Do not indent within a namespace '
' [runtime/indentation_namespace] [4]')
def testNameSpaceIndentationNoError(self):
lines = ['namespace Test {',
'void foo() { }',
'} // namespace Test']
results = self.GetNamespaceResults(lines)
self.assertEquals(results, '')
def testWhitespaceBeforeNamespace(self):
lines = [' namespace Test {',
' void foo() { }',
' } // namespace Test']
results = self.GetNamespaceResults(lines)
self.assertEquals(results, '')
def testFalsePositivesNoError(self):
lines = ['namespace Test {',
'struct OuterClass {',
' struct NoFalsePositivesHere;',
' struct NoFalsePositivesHere member_variable;',
'};',
'} // namespace Test']
results = self.GetNamespaceResults(lines)
self.assertEquals(results, '')
# Test get line width.
def testGetLineWidth(self):
self.assertEquals(0, cpplint.GetLineWidth(''))
self.assertEquals(10, cpplint.GetLineWidth(u'x' * 10))
self.assertEquals(16, cpplint.GetLineWidth(u'都|道|府|県|支庁'))
self.assertEquals(5 + 13 + 9, cpplint.GetLineWidth(
u'd𝐱/dt' + u'f : t ⨯ 𝐱 → ℝ' + u't ⨯ 𝐱 → ℝ'))
def testGetTextInside(self):
self.assertEquals('', cpplint._GetTextInside('fun()', r'fun\('))
self.assertEquals('x, y', cpplint._GetTextInside('f(x, y)', r'f\('))
self.assertEquals('a(), b(c())', cpplint._GetTextInside(
'printf(a(), b(c()))', r'printf\('))
self.assertEquals('x, y{}', cpplint._GetTextInside('f[x, y{}]', r'f\['))
self.assertEquals(None, cpplint._GetTextInside('f[a, b(}]', r'f\['))
self.assertEquals(None, cpplint._GetTextInside('f[x, y]', r'f\('))
self.assertEquals('y, h(z, (a + b))', cpplint._GetTextInside(
'f(x, g(y, h(z, (a + b))))', r'g\('))
self.assertEquals('f(f(x))', cpplint._GetTextInside('f(f(f(x)))', r'f\('))
# Supports multiple lines.
self.assertEquals('\n return loop(x);\n',
cpplint._GetTextInside(
'int loop(int x) {\n return loop(x);\n}\n', r'\{'))
# '^' matches the beginning of each line.
self.assertEquals('x, y',
cpplint._GetTextInside(
'#include "inl.h" // skip #define\n'
'#define A2(x, y) a_inl_(x, y, __LINE__)\n'
'#define A(x) a_inl_(x, "", __LINE__)\n',
r'^\s*#define\s*\w+\('))
def testFindNextMultiLineCommentStart(self):
self.assertEquals(1, cpplint.FindNextMultiLineCommentStart([''], 0))
lines = ['a', 'b', '/* c']
self.assertEquals(2, cpplint.FindNextMultiLineCommentStart(lines, 0))
lines = ['char a[] = "/*";'] # not recognized as comment.
self.assertEquals(1, cpplint.FindNextMultiLineCommentStart(lines, 0))
def testFindNextMultiLineCommentEnd(self):
self.assertEquals(1, cpplint.FindNextMultiLineCommentEnd([''], 0))
lines = ['a', 'b', ' c */']
self.assertEquals(2, cpplint.FindNextMultiLineCommentEnd(lines, 0))
def testRemoveMultiLineCommentsFromRange(self):
lines = ['a', ' /* comment ', ' * still comment', ' comment */ ', 'b']
cpplint.RemoveMultiLineCommentsFromRange(lines, 1, 4)
self.assertEquals(['a', '/**/', '/**/', '/**/', 'b'], lines)
def testSpacesAtEndOfLine(self):
self.TestLint(
'// Hello there ',
'Line ends in whitespace. Consider deleting these extra spaces.'
' [whitespace/end_of_line] [4]')
# Test line length check.
def testLineLengthCheck(self):
self.TestLint(
'// Hello',
'')
self.TestLint(
'// x' + ' x' * 40,
'Lines should be <= 80 characters long'
' [whitespace/line_length] [2]')
self.TestLint(
'// x' + ' x' * 50,
'Lines should be <= 80 characters long'
' [whitespace/line_length] [2]')
self.TestLint(
'// //some/path/to/f' + ('i' * 100) + 'le',
'')
self.TestLint(
'// //some/path/to/f' + ('i' * 100) + 'le',
'')
self.TestLint(
'// //some/path/to/f' + ('i' * 50) + 'le and some comments',
'Lines should be <= 80 characters long'
' [whitespace/line_length] [2]')
self.TestLint(
'// http://g' + ('o' * 100) + 'gle.com/',
'')
self.TestLint(
'// https://g' + ('o' * 100) + 'gle.com/',
'')
self.TestLint(
'// https://g' + ('o' * 60) + 'gle.com/ and some comments',
'Lines should be <= 80 characters long'
' [whitespace/line_length] [2]')
self.TestLint(
'// Read https://g' + ('o' * 60) + 'gle.com/',
'')
self.TestLint(
'// $Id: g' + ('o' * 80) + 'gle.cc#1 $',
'')
self.TestLint(
'// $Id: g' + ('o' * 80) + 'gle.cc#1',
'Lines should be <= 80 characters long'
' [whitespace/line_length] [2]')
self.TestMultiLineLint(
'static const char kCStr[] = "g' + ('o' * 50) + 'gle";\n',
'Lines should be <= 80 characters long'
' [whitespace/line_length] [2]')
self.TestMultiLineLint(
'static const char kRawStr[] = R"(g' + ('o' * 50) + 'gle)";\n',
'') # no warning because raw string content is elided
self.TestMultiLineLint(
'static const char kMultiLineRawStr[] = R"(\n'
'g' + ('o' * 80) + 'gle\n'
')";',
'')
self.TestMultiLineLint(
'static const char kL' + ('o' * 50) + 'ngIdentifier[] = R"()";\n',
'Lines should be <= 80 characters long'
' [whitespace/line_length] [2]')
# Test error suppression annotations.
def testErrorSuppression(self):
# Two errors on same line:
self.TestLint(
'long a = (int64) 65;',
['Using C-style cast. Use static_cast<int64>(...) instead'
' [readability/casting] [4]',
'Use int16/int64/etc, rather than the C type long'
' [runtime/int] [4]',
])
# One category of error suppressed:
self.TestLint(
'long a = (int64) 65; // NOLINT(runtime/int)',
'Using C-style cast. Use static_cast<int64>(...) instead'
' [readability/casting] [4]')
# All categories suppressed: (two aliases)
self.TestLint('long a = (int64) 65; // NOLINT', '')
self.TestLint('long a = (int64) 65; // NOLINT(*)', '')
# Malformed NOLINT directive:
self.TestLint(
'long a = 65; // NOLINT(foo)',
['Unknown NOLINT error category: foo'
' [readability/nolint] [5]',
'Use int16/int64/etc, rather than the C type long [runtime/int] [4]',
])
# Irrelevant NOLINT directive has no effect:
self.TestLint(
'long a = 65; // NOLINT(readability/casting)',
'Use int16/int64/etc, rather than the C type long'
' [runtime/int] [4]')
# NOLINTNEXTLINE silences warning for the next line instead of current line
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData('test.cc', 'cc',
['// Copyright 2014 Your Company.',
'// NOLINTNEXTLINE(whitespace/line_length)',
'// ./command' + (' -verbose' * 80),
''],
error_collector)
self.assertEquals('', error_collector.Results())
# LINT_C_FILE silences cast warnings for entire file.
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData('test.h', 'h',
['// Copyright 2014 Your Company.',
'// NOLINT(build/header_guard)',
'int64 a = (uint64) 65;',
'// LINT_C_FILE',
''],
error_collector)
self.assertEquals('', error_collector.Results())
# Vim modes silence cast warnings for entire file.
for modeline in ['vi:filetype=c',
'vi:sw=8 filetype=c',
'vi:sw=8 filetype=c ts=8',
'vi: filetype=c',
'vi: sw=8 filetype=c',
'vi: sw=8 filetype=c ts=8',
'vim:filetype=c',
'vim:sw=8 filetype=c',
'vim:sw=8 filetype=c ts=8',
'vim: filetype=c',
'vim: sw=8 filetype=c',
'vim: sw=8 filetype=c ts=8',
'vim: set filetype=c:',
'vim: set sw=8 filetype=c:',
'vim: set sw=8 filetype=c ts=8:',
'vim: set filetype=c :',
'vim: set sw=8 filetype=c :',
'vim: set sw=8 filetype=c ts=8 :',
'vim: se filetype=c:',
'vim: se sw=8 filetype=c:',
'vim: se sw=8 filetype=c ts=8:',
'vim: se filetype=c :',
'vim: se sw=8 filetype=c :',
'vim: se sw=8 filetype=c ts=8 :']:
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData('test.h', 'h',
['// Copyright 2014 Your Company.',
'// NOLINT(build/header_guard)',
'int64 a = (uint64) 65;',
'/* Prevent warnings about the modeline',
modeline,
'*/',
''],
error_collector)
self.assertEquals('', error_collector.Results())
# LINT_KERNEL_FILE silences whitespace/tab warnings for entire file.
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData('test.h', 'h',
['// Copyright 2014 Your Company.',
'// NOLINT(build/header_guard)',
'struct test {',
'\tint member;',
'};',
'// LINT_KERNEL_FILE',
''],
error_collector)
self.assertEquals('', error_collector.Results())
# NOLINT, NOLINTNEXTLINE silences the readability/braces warning for "};".
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData('test.cc', 'cc',
['// Copyright 2014 Your Company.',
'for (int i = 0; i != 100; ++i) {',
'\tstd::cout << i << std::endl;',
'}; // NOLINT',
'for (int i = 0; i != 100; ++i) {',
'\tstd::cout << i << std::endl;',
'// NOLINTNEXTLINE',
'};',
'// LINT_KERNEL_FILE',
''],
error_collector)
self.assertEquals('', error_collector.Results())
# Test Variable Declarations.
def testVariableDeclarations(self):
self.TestLint(
'long a = 65;',
'Use int16/int64/etc, rather than the C type long'
' [runtime/int] [4]')
self.TestLint(
'long double b = 65.0;',
'')
self.TestLint(
'long long aa = 6565;',
'Use int16/int64/etc, rather than the C type long'
' [runtime/int] [4]')
# Test C-style cast cases.
def testCStyleCast(self):
self.TestLint(
'int a = (int)1.0;',
'Using C-style cast. Use static_cast<int>(...) instead'
' [readability/casting] [4]')
self.TestLint(
'int a = (int)-1.0;',
'Using C-style cast. Use static_cast<int>(...) instead'
' [readability/casting] [4]')
self.TestLint(
'int *a = (int *)NULL;',
'Using C-style cast. Use reinterpret_cast<int *>(...) instead'
' [readability/casting] [4]')
self.TestLint(
'uint16 a = (uint16)1.0;',
'Using C-style cast. Use static_cast<uint16>(...) instead'
' [readability/casting] [4]')
self.TestLint(
'int32 a = (int32)1.0;',
'Using C-style cast. Use static_cast<int32>(...) instead'
' [readability/casting] [4]')
self.TestLint(
'uint64 a = (uint64)1.0;',
'Using C-style cast. Use static_cast<uint64>(...) instead'
' [readability/casting] [4]')
# These shouldn't be recognized casts.
self.TestLint('u a = (u)NULL;', '')
self.TestLint('uint a = (uint)NULL;', '')
self.TestLint('typedef MockCallback<int(int)> CallbackType;', '')
self.TestLint('scoped_ptr< MockCallback<int(int)> > callback_value;', '')
self.TestLint('std::function<int(bool)>', '')
self.TestLint('x = sizeof(int)', '')
self.TestLint('x = alignof(int)', '')
self.TestLint('alignas(int) char x[42]', '')
self.TestLint('alignas(alignof(x)) char y[42]', '')
self.TestLint('void F(int (func)(int));', '')
self.TestLint('void F(int (func)(int*));', '')
self.TestLint('void F(int (Class::member)(int));', '')
self.TestLint('void F(int (Class::member)(int*));', '')
self.TestLint('void F(int (Class::member)(int), int param);', '')
self.TestLint('void F(int (Class::member)(int*), int param);', '')
# These should not be recognized (lambda functions without arg names).
self.TestLint('[](int/*unused*/) -> bool {', '')
self.TestLint('[](int /*unused*/) -> bool {', '')
self.TestLint('auto f = [](MyStruct* /*unused*/)->int {', '')
self.TestLint('[](int) -> bool {', '')
self.TestLint('auto f = [](MyStruct*)->int {', '')
# Cast with brace initializers
self.TestLint('int64_t{4096} * 1000 * 1000', '')
self.TestLint('size_t{4096} * 1000 * 1000', '')
self.TestLint('uint_fast16_t{4096} * 1000 * 1000', '')
# Brace initializer with templated type
self.TestMultiLineLint(
"""
template <typename Type1,
typename Type2>
void Function(int arg1,
int arg2) {
variable &= ~Type1{0} - 1;
}""",
'')
self.TestMultiLineLint(
"""
template <typename Type>
class Class {
void Function() {
variable &= ~Type{0} - 1;
}
};""",
'')
self.TestMultiLineLint(
"""
template <typename Type>
class Class {
void Function() {
variable &= ~Type{0} - 1;
}
};""",
'')
self.TestMultiLineLint(
"""
namespace {
template <typename Type>
class Class {
void Function() {
if (block) {
variable &= ~Type{0} - 1;
}
}
};
}""",
'')
# Test taking address of casts (runtime/casting)
def testRuntimeCasting(self):
error_msg = ('Are you taking an address of a cast? '
'This is dangerous: could be a temp var. '
'Take the address before doing the cast, rather than after'
' [runtime/casting] [4]')
self.TestLint('int* x = &static_cast<int*>(foo);', error_msg)
self.TestLint('int* x = &reinterpret_cast<int *>(foo);', error_msg)
self.TestLint('int* x = &(int*)foo;',
['Using C-style cast. Use reinterpret_cast<int*>(...) '
'instead [readability/casting] [4]',
error_msg])
self.TestLint('BudgetBuckets&(BudgetWinHistory::*BucketFn)(void) const;',
'')
self.TestLint('&(*func_ptr)(arg)', '')
self.TestLint('Compute(arg, &(*func_ptr)(i, j));', '')
# Alternative error message
alt_error_msg = ('Are you taking an address of something dereferenced '
'from a cast? Wrapping the dereferenced expression in '
'parentheses will make the binding more obvious'
' [readability/casting] [4]')
self.TestLint('int* x = &down_cast<Obj*>(obj)->member_;', alt_error_msg)
self.TestLint('int* x = &down_cast<Obj*>(obj)[index];', alt_error_msg)
self.TestLint('int* x = &(down_cast<Obj*>(obj)->member_);', '')
self.TestLint('int* x = &(down_cast<Obj*>(obj)[index]);', '')
self.TestLint('int* x = &down_cast<Obj*>(obj)\n->member_;', alt_error_msg)
self.TestLint('int* x = &(down_cast<Obj*>(obj)\n->member_);', '')
# It's OK to cast an address.
self.TestLint('int* x = reinterpret_cast<int *>(&foo);', '')
# Function pointers returning references should not be confused
# with taking address of old-style casts.
self.TestLint('auto x = implicit_cast<string &(*)(int)>(&foo);', '')
def testRuntimeSelfinit(self):
self.TestLint(
'Foo::Foo(Bar r, Bel l) : r_(r_), l_(l_) { }',
'You seem to be initializing a member variable with itself.'
' [runtime/init] [4]')
self.TestLint(
'Foo::Foo(Bar r, Bel l) : r_(CHECK_NOTNULL(r_)) { }',
'You seem to be initializing a member variable with itself.'
' [runtime/init] [4]')
self.TestLint(
'Foo::Foo(Bar r, Bel l) : r_(r), l_(l) { }',
'')
self.TestLint(
'Foo::Foo(Bar r) : r_(r), l_(r_), ll_(l_) { }',
'')
# Test for unnamed arguments in a method.
def testCheckForUnnamedParams(self):
self.TestLint('virtual void Func(int*) const;', '')
self.TestLint('virtual void Func(int*);', '')
self.TestLint('void Method(char*) {', '')
self.TestLint('void Method(char*);', '')
self.TestLint('static void operator delete[](void*) throw();', '')
self.TestLint('int Method(int);', '')
self.TestLint('virtual void Func(int* p);', '')
self.TestLint('void operator delete(void* x) throw();', '')
self.TestLint('void Method(char* x) {', '')
self.TestLint('void Method(char* /*x*/) {', '')
self.TestLint('void Method(char* x);', '')
self.TestLint('typedef void (*Method)(int32 x);', '')
self.TestLint('static void operator delete[](void* x) throw();', '')
self.TestLint('static void operator delete[](void* /*x*/) throw();', '')
self.TestLint('X operator++(int);', '')
self.TestLint('X operator++(int) {', '')
self.TestLint('X operator--(int);', '')
self.TestLint('X operator--(int /*unused*/) {', '')
self.TestLint('MACRO(int);', '')
self.TestLint('MACRO(func(int));', '')
self.TestLint('MACRO(arg, func(int));', '')
self.TestLint('void (*func)(void*);', '')
self.TestLint('void Func((*func)(void*)) {}', '')
self.TestLint('template <void Func(void*)> void func();', '')
self.TestLint('virtual void f(int /*unused*/) {', '')
self.TestLint('void f(int /*unused*/) override {', '')
self.TestLint('void f(int /*unused*/) final {', '')
# Test deprecated casts such as int(d)
def testDeprecatedCast(self):
self.TestLint(
'int a = int(2.2);',
'Using deprecated casting style. '
'Use static_cast<int>(...) instead'
' [readability/casting] [4]')
self.TestLint(
'(char *) "foo"',
'Using C-style cast. '
'Use const_cast<char *>(...) instead'
' [readability/casting] [4]')
self.TestLint(
'(int*)foo',
'Using C-style cast. '
'Use reinterpret_cast<int*>(...) instead'
' [readability/casting] [4]')
# Checks for false positives...
self.TestLint('int a = int();', '') # constructor
self.TestLint('X::X() : a(int()) {}', '') # default constructor
self.TestLint('operator bool();', '') # Conversion operator
self.TestLint('new int64(123);', '') # "new" operator on basic type
self.TestLint('new int64(123);', '') # "new" operator on basic type
self.TestLint('new const int(42);', '') # "new" on const-qualified type
self.TestLint('using a = bool(int arg);', '') # C++11 alias-declaration
self.TestLint('x = bit_cast<double(*)[3]>(y);', '') # array of array
self.TestLint('void F(const char(&src)[N]);', '') # array of references
# Placement new
self.TestLint(
'new(field_ptr) int(field->default_value_enum()->number());',
'')
# C++11 function wrappers
self.TestLint('std::function<int(bool)>', '')
self.TestLint('std::function<const int(bool)>', '')
self.TestLint('std::function< int(bool) >', '')
self.TestLint('mfunction<int(bool)>', '')
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(
'test.cc', 'cc',
['// Copyright 2014 Your Company. All Rights Reserved.',
'typedef std::function<',
' bool(int)> F;',
''],
error_collector)
self.assertEquals('', error_collector.Results())
# Return types for function pointers
self.TestLint('typedef bool(FunctionPointer)();', '')
self.TestLint('typedef bool(FunctionPointer)(int param);', '')
self.TestLint('typedef bool(MyClass::*MemberFunctionPointer)();', '')
self.TestLint('typedef bool(MyClass::* MemberFunctionPointer)();', '')
self.TestLint('typedef bool(MyClass::*MemberFunctionPointer)() const;', '')
self.TestLint('void Function(bool(FunctionPointerArg)());', '')
self.TestLint('void Function(bool(FunctionPointerArg)()) {}', '')
self.TestLint('typedef set<int64, bool(*)(int64, int64)> SortedIdSet', '')
self.TestLint(
'bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *t)) {}',
'')
# The second parameter to a gMock method definition is a function signature
# that often looks like a bad cast but should not picked up by lint.
def testMockMethod(self):
self.TestLint(
'MOCK_METHOD0(method, int());',
'')
self.TestLint(
'MOCK_CONST_METHOD1(method, float(string));',
'')
self.TestLint(
'MOCK_CONST_METHOD2_T(method, double(float, float));',
'')
self.TestLint(
'MOCK_CONST_METHOD1(method, SomeType(int));',
'')
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData('mock.cc', 'cc',
['MOCK_METHOD1(method1,',
' bool(int));',
'MOCK_METHOD1(',
' method2,',
' bool(int));',
'MOCK_CONST_METHOD2(',
' method3, bool(int,',
' int));',
'MOCK_METHOD1(method4, int(bool));',
'const int kConstant = int(42);'], # true positive
error_collector)
self.assertEquals(
0,
error_collector.Results().count(
('Using deprecated casting style. '
'Use static_cast<bool>(...) instead '
'[readability/casting] [4]')))
self.assertEquals(
1,
error_collector.Results().count(
('Using deprecated casting style. '
'Use static_cast<int>(...) instead '
'[readability/casting] [4]')))
# Like gMock method definitions, MockCallback instantiations look very similar
# to bad casts.
def testMockCallback(self):
self.TestLint(
'MockCallback<bool(int)>',
'')
self.TestLint(
'MockCallback<int(float, char)>',
'')
# Test false errors that happened with some include file names
def testIncludeFilenameFalseError(self):
self.TestLint(
'#include "foo/long-foo.h"',
'')
self.TestLint(
'#include "foo/sprintf.h"',
'')
# Test typedef cases. There was a bug that cpplint misidentified
# typedef for pointer to function as C-style cast and produced
# false-positive error messages.
def testTypedefForPointerToFunction(self):
self.TestLint(
'typedef void (*Func)(int x);',
'')
self.TestLint(
'typedef void (*Func)(int *x);',
'')
self.TestLint(
'typedef void Func(int x);',
'')
self.TestLint(
'typedef void Func(int *x);',
'')
def testIncludeWhatYouUseNoImplementationFiles(self):
code = 'std::vector<int> foo;'
self.assertEquals('Add #include <vector> for vector<>'
' [build/include_what_you_use] [4]',
self.PerformIncludeWhatYouUse(code, 'foo.h'))
self.assertEquals('',
self.PerformIncludeWhatYouUse(code, 'foo.cc'))
def testIncludeWhatYouUse(self):
self.TestIncludeWhatYouUse(
"""#include <vector>
std::vector<int> foo;
""",
'')
self.TestIncludeWhatYouUse(
"""#include <map>
std::pair<int,int> foo;
""",
'Add #include <utility> for pair<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <multimap>
std::pair<int,int> foo;
""",
'Add #include <utility> for pair<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <hash_map>
std::pair<int,int> foo;
""",
'Add #include <utility> for pair<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <hash_map>
auto foo = std::make_pair(1, 2);
""",
'Add #include <utility> for make_pair'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <utility>
std::pair<int,int> foo;
""",
'')
self.TestIncludeWhatYouUse(
"""#include <vector>
DECLARE_string(foobar);
""",
'')
self.TestIncludeWhatYouUse(
"""#include <vector>
DEFINE_string(foobar, "", "");
""",
'')
self.TestIncludeWhatYouUse(
"""#include <vector>
std::pair<int,int> foo;
""",
'Add #include <utility> for pair<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include "base/foobar.h"
std::vector<int> foo;
""",
'Add #include <vector> for vector<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <vector>
std::set<int> foo;
""",
'Add #include <set> for set<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include "base/foobar.h"
hash_map<int, int> foobar;
""",
'Add #include <hash_map> for hash_map<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include "base/containers/hash_tables.h"
base::hash_map<int, int> foobar;
""",
'')
self.TestIncludeWhatYouUse(
"""#include "base/foobar.h"
bool foobar = std::less<int>(0,1);
""",
'Add #include <functional> for less<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include "base/foobar.h"
bool foobar = min<int>(0,1);
""",
'Add #include <algorithm> for min [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
'void a(const string &foobar);',
'Add #include <string> for string [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
'void a(const std::string &foobar);',
'Add #include <string> for string [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
'void a(const my::string &foobar);',
'') # Avoid false positives on strings in other namespaces.
self.TestIncludeWhatYouUse(
"""#include "base/foobar.h"
bool foobar = swap(0,1);
""",
'Add #include <utility> for swap [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include "base/foobar.h"
bool foobar = transform(a.begin(), a.end(), b.start(), Foo);
""",
'Add #include <algorithm> for transform '
'[build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include "base/foobar.h"
bool foobar = min_element(a.begin(), a.end());
""",
'Add #include <algorithm> for min_element '
'[build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""foo->swap(0,1);
foo.swap(0,1);
""",
'')
self.TestIncludeWhatYouUse(
"""#include <string>
void a(const std::multimap<int,string> &foobar);
""",
'Add #include <map> for multimap<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <string>
void a(const std::unordered_map<int,string> &foobar);
""",
'Add #include <unordered_map> for unordered_map<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <string>
void a(const std::unordered_set<int> &foobar);
""",
'Add #include <unordered_set> for unordered_set<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <queue>
void a(const std::priority_queue<int> &foobar);
""",
'')
self.TestIncludeWhatYouUse(
"""#include <assert.h>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/port.h"
vector<string> hajoa;""", '')
self.TestIncludeWhatYouUse(
"""#include <string>
int i = numeric_limits<int>::max()
""",
'Add #include <limits> for numeric_limits<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <limits>
int i = numeric_limits<int>::max()
""",
'')
self.TestIncludeWhatYouUse(
"""#include <string>
std::unique_ptr<int> x;
""",
'Add #include <memory> for unique_ptr<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <string>
auto x = std::make_unique<int>(0);
""",
'Add #include <memory> for make_unique<>'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <vector>
vector<int> foo(vector<int> x) { return std::move(x); }
""",
'Add #include <utility> for move'
' [build/include_what_you_use] [4]')
self.TestIncludeWhatYouUse(
"""#include <string>
int a, b;
std::swap(a, b);
""",
'Add #include <utility> for swap'
' [build/include_what_you_use] [4]')
# Test the UpdateIncludeState code path.
mock_header_contents = ['#include "blah/foo.h"', '#include "blah/bar.h"']
message = self.PerformIncludeWhatYouUse(
'#include "blah/a.h"',
filename='blah/a.cc',
io=MockIo(mock_header_contents))
self.assertEquals(message, '')
mock_header_contents = ['#include <set>']
message = self.PerformIncludeWhatYouUse(
"""#include "blah/a.h"
std::set<int> foo;""",
filename='blah/a.cc',
io=MockIo(mock_header_contents))
self.assertEquals(message, '')
# Make sure we can find the correct header file if the cc file seems to be
# a temporary file generated by Emacs's flymake.
mock_header_contents = ['']
message = self.PerformIncludeWhatYouUse(
"""#include "blah/a.h"
std::set<int> foo;""",
filename='blah/a_flymake.cc',
io=MockIo(mock_header_contents))
self.assertEquals(message, 'Add #include <set> for set<> '
'[build/include_what_you_use] [4]')
# If there's just a cc and the header can't be found then it's ok.
message = self.PerformIncludeWhatYouUse(
"""#include "blah/a.h"
std::set<int> foo;""",
filename='blah/a.cc')
self.assertEquals(message, '')
# Make sure we find the headers with relative paths.
mock_header_contents = ['']
message = self.PerformIncludeWhatYouUse(
"""#include "%s/a.h"
std::set<int> foo;""" % os.path.basename(os.getcwd()),
filename='a.cc',
io=MockIo(mock_header_contents))
self.assertEquals(message, 'Add #include <set> for set<> '
'[build/include_what_you_use] [4]')
def testFilesBelongToSameModule(self):
f = cpplint.FilesBelongToSameModule
self.assertEquals((True, ''), f('a.cc', 'a.h'))
self.assertEquals((True, ''), f('base/google.cc', 'base/google.h'))
self.assertEquals((True, ''), f('base/google_test.cc', 'base/google.h'))
self.assertEquals((True, ''),
f('base/google_unittest.cc', 'base/google.h'))
self.assertEquals((True, ''),
f('base/internal/google_unittest.cc',
'base/public/google.h'))
self.assertEquals((True, 'xxx/yyy/'),
f('xxx/yyy/base/internal/google_unittest.cc',
'base/public/google.h'))
self.assertEquals((True, 'xxx/yyy/'),
f('xxx/yyy/base/google_unittest.cc',
'base/public/google.h'))
self.assertEquals((True, ''),
f('base/google_unittest.cc', 'base/google-inl.h'))
self.assertEquals((True, '/home/build/google3/'),
f('/home/build/google3/base/google.cc', 'base/google.h'))
self.assertEquals((False, ''),
f('/home/build/google3/base/google.cc', 'basu/google.h'))
self.assertEquals((False, ''), f('a.cc', 'b.h'))
def testCleanseLine(self):
self.assertEquals('int foo = 0;',
cpplint.CleanseComments('int foo = 0; // danger!'))
self.assertEquals('int o = 0;',
cpplint.CleanseComments('int /* foo */ o = 0;'))
self.assertEquals('foo(int a, int b);',
cpplint.CleanseComments('foo(int a /* abc */, int b);'))
self.assertEqual('f(a, b);',
cpplint.CleanseComments('f(a, /* name */ b);'))
self.assertEqual('f(a, b);',
cpplint.CleanseComments('f(a /* name */, b);'))
self.assertEqual('f(a, b);',
cpplint.CleanseComments('f(a, /* name */b);'))
self.assertEqual('f(a, b, c);',
cpplint.CleanseComments('f(a, /**/b, /**/c);'))
self.assertEqual('f(a, b, c);',
cpplint.CleanseComments('f(a, /**/b/**/, c);'))
def testRawStrings(self):
self.TestMultiLineLint(
"""
void Func() {
static const char kString[] = R"(
#endif <- invalid preprocessor should be ignored
*/ <- invalid comment should be ignored too
)";
}""",
'')
self.TestMultiLineLint(
"""
void Func() {
string s = R"TrueDelimiter(
)"
)FalseDelimiter"
)TrueDelimiter";
}""",
'')
self.TestMultiLineLint(
"""
void Func() {
char char kString[] = R"( ";" )";
}""",
'')
self.TestMultiLineLint(
"""
static const char kRawString[] = R"(
\tstatic const int kLineWithTab = 1;
static const int kLineWithTrailingWhiteSpace = 1;\x20
void WeirdNumberOfSpacesAtLineStart() {
string x;
x += StrCat("Use StrAppend instead");
}
void BlankLineAtEndOfBlock() {
// TODO incorrectly formatted
//Badly formatted comment
}
)";""",
'')
self.TestMultiLineLint(
"""
void Func() {
string s = StrCat(R"TrueDelimiter(
)"
)FalseDelimiter"
)TrueDelimiter", R"TrueDelimiter2(
)"
)FalseDelimiter2"
)TrueDelimiter2");
}""",
'')
self.TestMultiLineLint(
"""
static SomeStruct kData = {
{0, R"(line1
line2
)"}
};""",
'')
def testMultiLineComments(self):
# missing explicit is bad
self.TestMultiLineLint(
r"""int a = 0;
/* multi-liner
class Foo {
Foo(int f); // should cause a lint warning in code
}
*/ """,
'')
self.TestMultiLineLint(
r"""/* int a = 0; multi-liner
static const int b = 0;""",
'Could not find end of multi-line comment'
' [readability/multiline_comment] [5]')
self.TestMultiLineLint(r""" /* multi-line comment""",
'Could not find end of multi-line comment'
' [readability/multiline_comment] [5]')
self.TestMultiLineLint(r""" // /* comment, but not multi-line""", '')
self.TestMultiLineLint(r"""/**********
*/""", '')
self.TestMultiLineLint(r"""/**
* Doxygen comment
*/""",
'')
self.TestMultiLineLint(r"""/*!
* Doxygen comment
*/""",
'')
def testMultilineStrings(self):
multiline_string_error_message = (
'Multi-line string ("...") found. This lint script doesn\'t '
'do well with such strings, and may give bogus warnings. '
'Use C++11 raw strings or concatenation instead.'
' [readability/multiline_string] [5]')
file_path = 'mydir/foo.cc'
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(file_path, 'cc',
['const char* str = "This is a\\',
' multiline string.";'],
error_collector)
self.assertEquals(
2, # One per line.
error_collector.ResultList().count(multiline_string_error_message))
# Test non-explicit single-argument constructors
def testExplicitSingleArgumentConstructors(self):
old_verbose_level = cpplint._cpplint_state.verbose_level
cpplint._cpplint_state.verbose_level = 0
try:
# missing explicit is bad
self.TestMultiLineLint(
"""
class Foo {
Foo(int f);
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# missing explicit is bad, even with whitespace
self.TestMultiLineLint(
"""
class Foo {
Foo (int f);
};""",
['Extra space before ( in function call [whitespace/parens] [4]',
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]'])
# missing explicit, with distracting comment, is still bad
self.TestMultiLineLint(
"""
class Foo {
Foo(int f); // simpler than Foo(blargh, blarg)
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# missing explicit, with qualified classname
self.TestMultiLineLint(
"""
class Qualifier::AnotherOne::Foo {
Foo(int f);
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# missing explicit for inline constructors is bad as well
self.TestMultiLineLint(
"""
class Foo {
inline Foo(int f);
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# missing explicit for constexpr constructors is bad as well
self.TestMultiLineLint(
"""
class Foo {
constexpr Foo(int f);
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# missing explicit for constexpr+inline constructors is bad as well
self.TestMultiLineLint(
"""
class Foo {
constexpr inline Foo(int f);
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
self.TestMultiLineLint(
"""
class Foo {
inline constexpr Foo(int f);
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# explicit with inline is accepted
self.TestMultiLineLint(
"""
class Foo {
inline explicit Foo(int f);
};""",
'')
self.TestMultiLineLint(
"""
class Foo {
explicit inline Foo(int f);
};""",
'')
# explicit with constexpr is accepted
self.TestMultiLineLint(
"""
class Foo {
constexpr explicit Foo(int f);
};""",
'')
self.TestMultiLineLint(
"""
class Foo {
explicit constexpr Foo(int f);
};""",
'')
# explicit with constexpr+inline is accepted
self.TestMultiLineLint(
"""
class Foo {
inline constexpr explicit Foo(int f);
};""",
'')
self.TestMultiLineLint(
"""
class Foo {
explicit inline constexpr Foo(int f);
};""",
'')
self.TestMultiLineLint(
"""
class Foo {
constexpr inline explicit Foo(int f);
};""",
'')
self.TestMultiLineLint(
"""
class Foo {
explicit constexpr inline Foo(int f);
};""",
'')
# structs are caught as well.
self.TestMultiLineLint(
"""
struct Foo {
Foo(int f);
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# Templatized classes are caught as well.
self.TestMultiLineLint(
"""
template<typename T> class Foo {
Foo(int f);
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# inline case for templatized classes.
self.TestMultiLineLint(
"""
template<typename T> class Foo {
inline Foo(int f);
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# constructors with a default argument should still be marked explicit
self.TestMultiLineLint(
"""
class Foo {
Foo(int f = 0);
};""",
'Constructors callable with one argument should be marked explicit.'
' [runtime/explicit] [5]')
# multi-argument constructors with all but one default argument should be
# marked explicit
self.TestMultiLineLint(
"""
class Foo {
Foo(int f, int g = 0);
};""",
'Constructors callable with one argument should be marked explicit.'
' [runtime/explicit] [5]')
# multi-argument constructors with all default arguments should be marked
# explicit
self.TestMultiLineLint(
"""
class Foo {
Foo(int f = 0, int g = 0);
};""",
'Constructors callable with one argument should be marked explicit.'
' [runtime/explicit] [5]')
# explicit no-argument constructors are bad
self.TestMultiLineLint(
"""
class Foo {
explicit Foo();
};""",
'Zero-parameter constructors should not be marked explicit.'
' [runtime/explicit] [5]')
# void constructors are considered no-argument
self.TestMultiLineLint(
"""
class Foo {
explicit Foo(void);
};""",
'Zero-parameter constructors should not be marked explicit.'
' [runtime/explicit] [5]')
# No warning for multi-parameter constructors
self.TestMultiLineLint(
"""
class Foo {
explicit Foo(int f, int g);
};""",
'')
self.TestMultiLineLint(
"""
class Foo {
explicit Foo(int f, int g = 0);
};""",
'')
# single-argument constructors that take a function that takes multiple
# arguments should be explicit
self.TestMultiLineLint(
"""
class Foo {
Foo(void (*f)(int f, int g));
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# single-argument constructors that take a single template argument with
# multiple parameters should be explicit
self.TestMultiLineLint(
"""
template <typename T, typename S>
class Foo {
Foo(Bar<T, S> b);
};""",
'Single-parameter constructors should be marked explicit.'
' [runtime/explicit] [5]')
# but copy constructors that take multiple template parameters are OK
self.TestMultiLineLint(
"""
template <typename T, S>
class Foo {
Foo(Foo<T, S>& f);
};""",
'')
# proper style is okay
self.TestMultiLineLint(
"""
class Foo {
explicit Foo(int f);
};""",
'')
# two argument constructor is okay
self.TestMultiLineLint(
"""
class Foo {
Foo(int f, int b);
};""",
'')
# two argument constructor, across two lines, is okay
self.TestMultiLineLint(
"""
class Foo {
Foo(int f,
int b);
};""",
'')
# non-constructor (but similar name), is okay
self.TestMultiLineLint(
"""
class Foo {
aFoo(int f);
};""",
'')
# constructor with void argument is okay
self.TestMultiLineLint(
"""
class Foo {
Foo(void);
};""",
'')
# single argument method is okay
self.TestMultiLineLint(
"""
class Foo {
Bar(int b);
};""",
'')
# comments should be ignored
self.TestMultiLineLint(
"""
class Foo {
// Foo(int f);
};""",
'')
# single argument function following class definition is okay
# (okay, it's not actually valid, but we don't want a false positive)
self.TestMultiLineLint(
"""
class Foo {
Foo(int f, int b);
};
Foo(int f);""",
'')
# single argument function is okay
self.TestMultiLineLint(
"""static Foo(int f);""",
'')
# single argument copy constructor is okay.
self.TestMultiLineLint(
"""
class Foo {
Foo(const Foo&);
};""",
'')
self.TestMultiLineLint(
"""
class Foo {
Foo(Foo const&);
};""",
'')
self.TestMultiLineLint(
"""
class Foo {
Foo(Foo&);
};""",
'')
# templatized copy constructor is okay.
self.TestMultiLineLint(
"""
template<typename T> class Foo {
Foo(const Foo<T>&);
};""",
'')
# Special case for std::initializer_list
self.TestMultiLineLint(
"""
class Foo {
Foo(std::initializer_list<T> &arg) {}
};""",
'')
# Anything goes inside an assembly block
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData('foo.cc', 'cc',
['void Func() {',
' __asm__ (',
' "hlt"',
' );',
' asm {',
' movdqa [edx + 32], xmm2',
' }',
'}'],
error_collector)
self.assertEquals(
0,
error_collector.ResultList().count(
'Extra space before ( in function call [whitespace/parens] [4]'))
self.assertEquals(
0,
error_collector.ResultList().count(
'Closing ) should be moved to the previous line '
'[whitespace/parens] [2]'))
self.assertEquals(
0,
error_collector.ResultList().count(
'Extra space before [ [whitespace/braces] [5]'))
finally:
cpplint._cpplint_state.verbose_level = old_verbose_level
def testSlashStarCommentOnSingleLine(self):
self.TestMultiLineLint(
"""/* static */ Foo(int f);""",
'')
self.TestMultiLineLint(
"""/*/ static */ Foo(int f);""",
'')
self.TestMultiLineLint(
"""/*/ static Foo(int f);""",
'Could not find end of multi-line comment'
' [readability/multiline_comment] [5]')
self.TestMultiLineLint(
""" /*/ static Foo(int f);""",
'Could not find end of multi-line comment'
' [readability/multiline_comment] [5]')
self.TestMultiLineLint(
""" /**/ static Foo(int f);""",
'')
# Test suspicious usage of "if" like this:
# if (a == b) {
# DoSomething();
# } if (a == c) { // Should be "else if".
# DoSomething(); // This gets called twice if a == b && a == c.
# }
def testSuspiciousUsageOfIf(self):
self.TestLint(
' if (a == b) {',
'')
self.TestLint(
' } if (a == b) {',
'Did you mean "else if"? If not, start a new line for "if".'
' [readability/braces] [4]')
# Test suspicious usage of memset. Specifically, a 0
# as the final argument is almost certainly an error.
def testSuspiciousUsageOfMemset(self):
# Normal use is okay.
self.TestLint(
' memset(buf, 0, sizeof(buf))',
'')
# A 0 as the final argument is almost certainly an error.
self.TestLint(
' memset(buf, sizeof(buf), 0)',
'Did you mean "memset(buf, 0, sizeof(buf))"?'
' [runtime/memset] [4]')
self.TestLint(
' memset(buf, xsize * ysize, 0)',
'Did you mean "memset(buf, 0, xsize * ysize)"?'
' [runtime/memset] [4]')
# There is legitimate test code that uses this form.
# This is okay since the second argument is a literal.
self.TestLint(
" memset(buf, 'y', 0)",
'')
self.TestLint(
' memset(buf, 4, 0)',
'')
self.TestLint(
' memset(buf, -1, 0)',
'')
self.TestLint(
' memset(buf, 0xF1, 0)',
'')
self.TestLint(
' memset(buf, 0xcd, 0)',
'')
def testRedundantVirtual(self):
self.TestLint('virtual void F()', '')
self.TestLint('virtual void F();', '')
self.TestLint('virtual void F() {}', '')
message_template = ('"%s" is redundant since function is already '
'declared as "%s" [readability/inheritance] [4]')
for virt_specifier in ['override', 'final']:
error_message = message_template % ('virtual', virt_specifier)
self.TestLint('virtual int F() %s' % virt_specifier, error_message)
self.TestLint('virtual int F() %s;' % virt_specifier, error_message)
self.TestLint('virtual int F() %s {' % virt_specifier, error_message)
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(
'foo.cc', 'cc',
['// Copyright 2014 Your Company.',
'virtual void F(int a,',
' int b) ' + virt_specifier + ';',
'virtual void F(int a,',
' int b) LOCKS_EXCLUDED(lock) ' + virt_specifier + ';',
'virtual void F(int a,',
' int b)',
' LOCKS_EXCLUDED(lock) ' + virt_specifier + ';',
''],
error_collector)
self.assertEquals(
[error_message, error_message, error_message],
error_collector.Results())
error_message = message_template % ('override', 'final')
self.TestLint('int F() override final', error_message)
self.TestLint('int F() override final;', error_message)
self.TestLint('int F() override final {}', error_message)
self.TestLint('int F() final override', error_message)
self.TestLint('int F() final override;', error_message)
self.TestLint('int F() final override {}', error_message)
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(
'foo.cc', 'cc',
['// Copyright 2014 Your Company.',
'struct A : virtual B {',
' ~A() override;'
'};',
'class C',
' : public D,',
' public virtual E {',
' void Func() override;',
'}',
''],
error_collector)
self.assertEquals('', error_collector.Results())
self.TestLint('void Finalize(AnnotationProto *final) override;', '')
def testCheckDeprecated(self):
self.TestLanguageRulesCheck('foo_test.cc', '#include <iostream>', '')
self.TestLanguageRulesCheck('foo_unittest.cc', '#include <iostream>', '')
def testCheckPosixThreading(self):
self.TestLint('var = sctime_r()', '')
self.TestLint('var = strtok_r()', '')
self.TestLint('var = strtok_r(foo, ba, r)', '')
self.TestLint('var = brand()', '')
self.TestLint('_rand()', '')
self.TestLint('.rand()', '')
self.TestLint('->rand()', '')
self.TestLint('ACMRandom rand(seed)', '')
self.TestLint('ISAACRandom rand()', '')
self.TestLint('var = rand()',
'Consider using rand_r(...) instead of rand(...)'
' for improved thread safety.'
' [runtime/threadsafe_fn] [2]')
self.TestLint('var = strtok(str, delim)',
'Consider using strtok_r(...) '
'instead of strtok(...)'
' for improved thread safety.'
' [runtime/threadsafe_fn] [2]')
def testVlogMisuse(self):
self.TestLint('VLOG(1)', '')
self.TestLint('VLOG(99)', '')
self.TestLint('LOG(ERROR)', '')
self.TestLint('LOG(INFO)', '')
self.TestLint('LOG(WARNING)', '')
self.TestLint('LOG(FATAL)', '')
self.TestLint('LOG(DFATAL)', '')
self.TestLint('VLOG(SOMETHINGWEIRD)', '')
self.TestLint('MYOWNVLOG(ERROR)', '')
errmsg = ('VLOG() should be used with numeric verbosity level. '
'Use LOG() if you want symbolic severity levels.'
' [runtime/vlog] [5]')
self.TestLint('VLOG(ERROR)', errmsg)
self.TestLint('VLOG(INFO)', errmsg)
self.TestLint('VLOG(WARNING)', errmsg)
self.TestLint('VLOG(FATAL)', errmsg)
self.TestLint('VLOG(DFATAL)', errmsg)
self.TestLint(' VLOG(ERROR)', errmsg)
self.TestLint(' VLOG(INFO)', errmsg)
self.TestLint(' VLOG(WARNING)', errmsg)
self.TestLint(' VLOG(FATAL)', errmsg)
self.TestLint(' VLOG(DFATAL)', errmsg)
# Test potential format string bugs like printf(foo).
def testFormatStrings(self):
self.TestLint('printf("foo")', '')
self.TestLint('printf("foo: %s", foo)', '')
self.TestLint('DocidForPrintf(docid)', '') # Should not trigger.
self.TestLint('printf(format, value)', '') # Should not trigger.
self.TestLint('printf(__VA_ARGS__)', '') # Should not trigger.
self.TestLint('printf(format.c_str(), value)', '') # Should not trigger.
self.TestLint('printf(format(index).c_str(), value)', '')
self.TestLint(
'printf(foo)',
'Potential format string bug. Do printf("%s", foo) instead.'
' [runtime/printf] [4]')
self.TestLint(
'printf(foo.c_str())',
'Potential format string bug. '
'Do printf("%s", foo.c_str()) instead.'
' [runtime/printf] [4]')
self.TestLint(
'printf(foo->c_str())',
'Potential format string bug. '
'Do printf("%s", foo->c_str()) instead.'
' [runtime/printf] [4]')
self.TestLint(
'StringPrintf(foo)',
'Potential format string bug. Do StringPrintf("%s", foo) instead.'
''
' [runtime/printf] [4]')
# Test disallowed use of operator& and other operators.
def testIllegalOperatorOverloading(self):
errmsg = ('Unary operator& is dangerous. Do not use it.'
' [runtime/operator] [4]')
self.TestLint('void operator=(const Myclass&)', '')
self.TestLint('void operator&(int a, int b)', '') # binary operator& ok
self.TestLint('void operator&() { }', errmsg)
self.TestLint('void operator & ( ) { }',
['Extra space after ( [whitespace/parens] [2]', errmsg])
# const string reference members are dangerous..
def testConstStringReferenceMembers(self):
errmsg = ('const string& members are dangerous. It is much better to use '
'alternatives, such as pointers or simple constants.'
' [runtime/member_string_references] [2]')
members_declarations = ['const string& church',
'const string &turing',
'const string & godel']
# TODO(unknown): Enable also these tests if and when we ever
# decide to check for arbitrary member references.
# "const Turing & a",
# "const Church& a",
# "const vector<int>& a",
# "const Kurt::Godel & godel",
# "const Kazimierz::Kuratowski& kk" ]
# The Good.
self.TestLint('void f(const string&)', '')
self.TestLint('const string& f(const string& a, const string& b)', '')
self.TestLint('typedef const string& A;', '')
for decl in members_declarations:
self.TestLint(decl + ' = b;', '')
self.TestLint(decl + ' =', '')
# The Bad.
for decl in members_declarations:
self.TestLint(decl + ';', errmsg)
# Variable-length arrays are not permitted.
def testVariableLengthArrayDetection(self):
errmsg = ('Do not use variable-length arrays. Use an appropriately named '
"('k' followed by CamelCase) compile-time constant for the size."
' [runtime/arrays] [1]')
self.TestLint('int a[any_old_variable];', errmsg)
self.TestLint('int doublesize[some_var * 2];', errmsg)
self.TestLint('int a[afunction()];', errmsg)
self.TestLint('int a[function(kMaxFooBars)];', errmsg)
self.TestLint('bool a_list[items_->size()];', errmsg)
self.TestLint('namespace::Type buffer[len+1];', errmsg)
self.TestLint('int a[64];', '')
self.TestLint('int a[0xFF];', '')
self.TestLint('int first[256], second[256];', '')
self.TestLint('int array_name[kCompileTimeConstant];', '')
self.TestLint('char buf[somenamespace::kBufSize];', '')
self.TestLint('int array_name[ALL_CAPS];', '')
self.TestLint('AClass array1[foo::bar::ALL_CAPS];', '')
self.TestLint('int a[kMaxStrLen + 1];', '')
self.TestLint('int a[sizeof(foo)];', '')
self.TestLint('int a[sizeof(*foo)];', '')
self.TestLint('int a[sizeof foo];', '')
self.TestLint('int a[sizeof(struct Foo)];', '')
self.TestLint('int a[128 - sizeof(const bar)];', '')
self.TestLint('int a[(sizeof(foo) * 4)];', '')
self.TestLint('int a[(arraysize(fixed_size_array)/2) << 1];', '')
self.TestLint('delete a[some_var];', '')
self.TestLint('return a[some_var];', '')
# DISALLOW_COPY_AND_ASSIGN and DISALLOW_IMPLICIT_CONSTRUCTORS should be at
# end of class if present.
def testDisallowMacrosAtEnd(self):
for macro_name in (
'DISALLOW_COPY_AND_ASSIGN',
'DISALLOW_IMPLICIT_CONSTRUCTORS'):
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(
'foo.cc', 'cc',
['// Copyright 2014 Your Company.',
'class SomeClass {',
' private:',
' %s(SomeClass);' % macro_name,
' int member_;',
'};',
''],
error_collector)
self.assertEquals(
('%s should be the last thing in the class' % macro_name) +
' [readability/constructors] [3]',
error_collector.Results())
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(
'foo.cc', 'cc',
['// Copyright 2014 Your Company.',
'class OuterClass {',
' private:',
' struct InnerClass {',
' private:',
' %s(InnerClass);' % macro_name,
' int member;',
' };',
'};',
''],
error_collector)
self.assertEquals(
('%s should be the last thing in the class' % macro_name) +
' [readability/constructors] [3]',
error_collector.Results())
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(
'foo.cc', 'cc',
['// Copyright 2014 Your Company.',
'class OuterClass1 {',
' private:',
' struct InnerClass1 {',
' private:',
' %s(InnerClass1);' % macro_name,
' };',
' %s(OuterClass1);' % macro_name,
'};',
'struct OuterClass2 {',
' private:',
' class InnerClass2 {',
' private:',
' %s(InnerClass2);' % macro_name,
' // comment',
' };',
'',
' %s(OuterClass2);' % macro_name,
'',
' // comment',
'};',
'void Func() {',
' struct LocalClass {',
' private:',
' %s(LocalClass);' % macro_name,
' } variable;',
'}',
''],
error_collector)
self.assertEquals('', error_collector.Results())
# Brace usage
def testBraces(self):
# Braces shouldn't be followed by a ; unless they're defining a struct
# or initializing an array
self.TestLint('int a[3] = { 1, 2, 3 };', '')
self.TestLint(
"""const int foo[] =
{1, 2, 3 };""",
'')
# For single line, unmatched '}' with a ';' is ignored (not enough context)
self.TestMultiLineLint(
"""int a[3] = { 1,
2,
3 };""",
'')
self.TestMultiLineLint(
"""int a[2][3] = { { 1, 2 },
{ 3, 4 } };""",
'')
self.TestMultiLineLint(
"""int a[2][3] =
{ { 1, 2 },
{ 3, 4 } };""",
'')
# CHECK/EXPECT_TRUE/EXPECT_FALSE replacements
def testCheckCheck(self):
self.TestLint('CHECK(x == 42);',
'Consider using CHECK_EQ instead of CHECK(a == b)'
' [readability/check] [2]')
self.TestLint('CHECK(x != 42);',
'Consider using CHECK_NE instead of CHECK(a != b)'
' [readability/check] [2]')
self.TestLint('CHECK(x >= 42);',
'Consider using CHECK_GE instead of CHECK(a >= b)'
' [readability/check] [2]')
self.TestLint('CHECK(x > 42);',
'Consider using CHECK_GT instead of CHECK(a > b)'
' [readability/check] [2]')
self.TestLint('CHECK(x <= 42);',
'Consider using CHECK_LE instead of CHECK(a <= b)'
' [readability/check] [2]')
self.TestLint('CHECK(x < 42);',
'Consider using CHECK_LT instead of CHECK(a < b)'
' [readability/check] [2]')
self.TestLint('DCHECK(x == 42);',
'Consider using DCHECK_EQ instead of DCHECK(a == b)'
' [readability/check] [2]')
self.TestLint('DCHECK(x != 42);',
'Consider using DCHECK_NE instead of DCHECK(a != b)'
' [readability/check] [2]')
self.TestLint('DCHECK(x >= 42);',
'Consider using DCHECK_GE instead of DCHECK(a >= b)'
' [readability/check] [2]')
self.TestLint('DCHECK(x > 42);',
'Consider using DCHECK_GT instead of DCHECK(a > b)'
' [readability/check] [2]')
self.TestLint('DCHECK(x <= 42);',
'Consider using DCHECK_LE instead of DCHECK(a <= b)'
' [readability/check] [2]')
self.TestLint('DCHECK(x < 42);',
'Consider using DCHECK_LT instead of DCHECK(a < b)'
' [readability/check] [2]')
self.TestLint(
'EXPECT_TRUE("42" == x);',
'Consider using EXPECT_EQ instead of EXPECT_TRUE(a == b)'
' [readability/check] [2]')
self.TestLint(
'EXPECT_TRUE("42" != x);',
'Consider using EXPECT_NE instead of EXPECT_TRUE(a != b)'
' [readability/check] [2]')
self.TestLint(
'EXPECT_TRUE(+42 >= x);',
'Consider using EXPECT_GE instead of EXPECT_TRUE(a >= b)'
' [readability/check] [2]')
self.TestLint(
'EXPECT_FALSE(x == 42);',
'Consider using EXPECT_NE instead of EXPECT_FALSE(a == b)'
' [readability/check] [2]')
self.TestLint(
'EXPECT_FALSE(x != 42);',
'Consider using EXPECT_EQ instead of EXPECT_FALSE(a != b)'
' [readability/check] [2]')
self.TestLint(
'EXPECT_FALSE(x >= 42);',
'Consider using EXPECT_LT instead of EXPECT_FALSE(a >= b)'
' [readability/check] [2]')
self.TestLint(
'ASSERT_FALSE(x > 42);',
'Consider using ASSERT_LE instead of ASSERT_FALSE(a > b)'
' [readability/check] [2]')
self.TestLint(
'ASSERT_FALSE(x <= 42);',
'Consider using ASSERT_GT instead of ASSERT_FALSE(a <= b)'
' [readability/check] [2]')
self.TestLint('CHECK(x<42);',
['Missing spaces around <'
' [whitespace/operators] [3]',
'Consider using CHECK_LT instead of CHECK(a < b)'
' [readability/check] [2]'])
self.TestLint('CHECK(x>42);',
['Missing spaces around >'
' [whitespace/operators] [3]',
'Consider using CHECK_GT instead of CHECK(a > b)'
' [readability/check] [2]'])
self.TestLint('using some::namespace::operator<<;', '')
self.TestLint('using some::namespace::operator>>;', '')
self.TestLint('CHECK(x->y == 42);',
'Consider using CHECK_EQ instead of CHECK(a == b)'
' [readability/check] [2]')
self.TestLint(
' EXPECT_TRUE(42 < x); // Random comment.',
'Consider using EXPECT_LT instead of EXPECT_TRUE(a < b)'
' [readability/check] [2]')
self.TestLint(
'EXPECT_TRUE( 42 < x );',
['Extra space after ( in function call'
' [whitespace/parens] [4]',
'Extra space before ) [whitespace/parens] [2]',
'Consider using EXPECT_LT instead of EXPECT_TRUE(a < b)'
' [readability/check] [2]'])
self.TestLint('CHECK(4\'2 == x);',
'Consider using CHECK_EQ instead of CHECK(a == b)'
' [readability/check] [2]')
def testCheckCheckFalsePositives(self):
self.TestLint('CHECK(some_iterator == obj.end());', '')
self.TestLint('EXPECT_TRUE(some_iterator == obj.end());', '')
self.TestLint('EXPECT_FALSE(some_iterator == obj.end());', '')
self.TestLint('CHECK(some_pointer != NULL);', '')
self.TestLint('EXPECT_TRUE(some_pointer != NULL);', '')
self.TestLint('EXPECT_FALSE(some_pointer != NULL);', '')
self.TestLint('CHECK(CreateTestFile(dir, (1 << 20)));', '')
self.TestLint('CHECK(CreateTestFile(dir, (1 >> 20)));', '')
self.TestLint('CHECK(x ^ (y < 42));', '')
self.TestLint('CHECK((x > 42) ^ (x < 54));', '')
self.TestLint('CHECK(a && b < 42);', '')
self.TestLint('CHECK(42 < a && a < b);', '')
self.TestLint('SOFT_CHECK(x > 42);', '')
self.TestMultiLineLint(
"""_STLP_DEFINE_BINARY_OP_CHECK(==, _OP_EQUAL);
_STLP_DEFINE_BINARY_OP_CHECK(!=, _OP_NOT_EQUAL);
_STLP_DEFINE_BINARY_OP_CHECK(<, _OP_LESS_THAN);
_STLP_DEFINE_BINARY_OP_CHECK(<=, _OP_LESS_EQUAL);
_STLP_DEFINE_BINARY_OP_CHECK(>, _OP_GREATER_THAN);
_STLP_DEFINE_BINARY_OP_CHECK(>=, _OP_GREATER_EQUAL);
_STLP_DEFINE_BINARY_OP_CHECK(+, _OP_PLUS);
_STLP_DEFINE_BINARY_OP_CHECK(*, _OP_TIMES);
_STLP_DEFINE_BINARY_OP_CHECK(/, _OP_DIVIDE);
_STLP_DEFINE_BINARY_OP_CHECK(-, _OP_SUBTRACT);
_STLP_DEFINE_BINARY_OP_CHECK(%, _OP_MOD);""",
'')
self.TestLint('CHECK(x < 42) << "Custom error message";', '')
# Alternative token to punctuation operator replacements
def testCheckAltTokens(self):
self.TestLint('true or true',
'Use operator || instead of or'
' [readability/alt_tokens] [2]')
self.TestLint('true and true',
'Use operator && instead of and'
' [readability/alt_tokens] [2]')
self.TestLint('if (not true)',
'Use operator ! instead of not'
' [readability/alt_tokens] [2]')
self.TestLint('1 bitor 1',
'Use operator | instead of bitor'
' [readability/alt_tokens] [2]')
self.TestLint('1 xor 1',
'Use operator ^ instead of xor'
' [readability/alt_tokens] [2]')
self.TestLint('1 bitand 1',
'Use operator & instead of bitand'
' [readability/alt_tokens] [2]')
self.TestLint('x = compl 1',
'Use operator ~ instead of compl'
' [readability/alt_tokens] [2]')
self.TestLint('x and_eq y',
'Use operator &= instead of and_eq'
' [readability/alt_tokens] [2]')
self.TestLint('x or_eq y',
'Use operator |= instead of or_eq'
' [readability/alt_tokens] [2]')
self.TestLint('x xor_eq y',
'Use operator ^= instead of xor_eq'
' [readability/alt_tokens] [2]')
self.TestLint('x not_eq y',
'Use operator != instead of not_eq'
' [readability/alt_tokens] [2]')
self.TestLint('line_continuation or',
'Use operator || instead of or'
' [readability/alt_tokens] [2]')
self.TestLint('if(true and(parentheses',
'Use operator && instead of and'
' [readability/alt_tokens] [2]')
self.TestLint('#include "base/false-and-false.h"', '')
self.TestLint('#error false or false', '')
self.TestLint('false nor false', '')
self.TestLint('false nand false', '')
# Passing and returning non-const references
def testNonConstReference(self):
# Passing a non-const reference as function parameter is forbidden.
operand_error_message = ('Is this a non-const reference? '
'If so, make const or use a pointer: %s'
' [runtime/references] [2]')
# Warn of use of a non-const reference in operators and functions
self.TestLint('bool operator>(Foo& s, Foo& f);',
[operand_error_message % 'Foo& s',
operand_error_message % 'Foo& f'])
self.TestLint('bool operator+(Foo& s, Foo& f);',
[operand_error_message % 'Foo& s',
operand_error_message % 'Foo& f'])
self.TestLint('int len(Foo& s);', operand_error_message % 'Foo& s')
# Allow use of non-const references in a few specific cases
self.TestLint('stream& operator>>(stream& s, Foo& f);', '')
self.TestLint('stream& operator<<(stream& s, Foo& f);', '')
self.TestLint('void swap(Bar& a, Bar& b);', '')
self.TestLint('ostream& LogFunc(ostream& s);', '')
self.TestLint('ostringstream& LogFunc(ostringstream& s);', '')
self.TestLint('istream& LogFunc(istream& s);', '')
self.TestLint('istringstream& LogFunc(istringstream& s);', '')
# Returning a non-const reference from a function is OK.
self.TestLint('int& g();', '')
# Passing a const reference to a struct (using the struct keyword) is OK.
self.TestLint('void foo(const struct tm& tm);', '')
# Passing a const reference to a typename is OK.
self.TestLint('void foo(const typename tm& tm);', '')
# Const reference to a pointer type is OK.
self.TestLint('void foo(const Bar* const& p) {', '')
self.TestLint('void foo(Bar const* const& p) {', '')
self.TestLint('void foo(Bar* const& p) {', '')
# Const reference to a templated type is OK.
self.TestLint('void foo(const std::vector<std::string>& v);', '')
# Non-const reference to a pointer type is not OK.
self.TestLint('void foo(Bar*& p);',
operand_error_message % 'Bar*& p')
self.TestLint('void foo(const Bar*& p);',
operand_error_message % 'const Bar*& p')
self.TestLint('void foo(Bar const*& p);',
operand_error_message % 'Bar const*& p')
self.TestLint('void foo(struct Bar*& p);',
operand_error_message % 'struct Bar*& p')
self.TestLint('void foo(const struct Bar*& p);',
operand_error_message % 'const struct Bar*& p')
self.TestLint('void foo(struct Bar const*& p);',
operand_error_message % 'struct Bar const*& p')
# Non-const reference to a templated type is not OK.
self.TestLint('void foo(std::vector<int>& p);',
operand_error_message % 'std::vector<int>& p')
# Returning an address of something is not prohibited.
self.TestLint('return &something;', '')
self.TestLint('if (condition) {return &something; }', '')
self.TestLint('if (condition) return &something;', '')
self.TestLint('if (condition) address = &something;', '')
self.TestLint('if (condition) result = lhs&rhs;', '')
self.TestLint('if (condition) result = lhs & rhs;', '')
self.TestLint('a = (b+c) * sizeof &f;', '')
self.TestLint('a = MySize(b) * sizeof &f;', '')
# We don't get confused by C++11 range-based for loops.
self.TestLint('for (const string& s : c)', '')
self.TestLint('for (auto& r : c)', '')
self.TestLint('for (typename Type& a : b)', '')
# We don't get confused by some other uses of '&'.
self.TestLint('T& operator=(const T& t);', '')
self.TestLint('int g() { return (a & b); }', '')
self.TestLint('T& r = (T&)*(vp());', '')
self.TestLint('T& r = v', '')
self.TestLint('static_assert((kBits & kMask) == 0, "text");', '')
self.TestLint('COMPILE_ASSERT((kBits & kMask) == 0, text);', '')
# Spaces before template arguments. This is poor style, but
# happens 0.15% of the time.
self.TestLint('void Func(const vector <int> &const_x, '
'vector <int> &nonconst_x) {',
operand_error_message % 'vector<int> &nonconst_x')
# Derived member functions are spared from override check
self.TestLint('void Func(X& x);', operand_error_message % 'X& x')
self.TestLint('void Func(X& x) {}', operand_error_message % 'X& x')
self.TestLint('void Func(X& x) override;', '')
self.TestLint('void Func(X& x) override {', '')
self.TestLint('void Func(X& x) const override;', '')
self.TestLint('void Func(X& x) const override {', '')
# Don't warn on out-of-line method definitions.
self.TestLint('void NS::Func(X& x) {', '')
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(
'foo.cc', 'cc',
['// Copyright 2014 Your Company. All Rights Reserved.',
'void a::b() {}',
'void f(int& q) {}',
''],
error_collector)
self.assertEquals(
operand_error_message % 'int& q',
error_collector.Results())
# Other potential false positives. These need full parser
# state to reproduce as opposed to just TestLint.
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(
'foo.cc', 'cc',
['// Copyright 2014 Your Company. All Rights Reserved.',
'void swap(int &x,',
' int &y) {',
'}',
'void swap(',
' sparsegroup<T, GROUP_SIZE, Alloc> &x,',
' sparsegroup<T, GROUP_SIZE, Alloc> &y) {',
'}',
'ostream& operator<<(',
' ostream& out',
' const dense_hash_set<Value, Hash, Equals, Alloc>& seq) {',
'}',
'class A {',
' void Function(',
' string &x) override {',
' }',
'};',
'void Derived::Function(',
' string &x) {',
'}',
'#define UNSUPPORTED_MASK(_mask) \\',
' if (flags & _mask) { \\',
' LOG(FATAL) << "Unsupported flag: " << #_mask; \\',
' }',
'Constructor::Constructor()',
' : initializer1_(a1 & b1),',
' initializer2_(a2 & b2) {',
'}',
'Constructor::Constructor()',
' : initializer1_{a3 & b3},',
' initializer2_(a4 & b4) {',
'}',
'Constructor::Constructor()',
' : initializer1_{a5 & b5},',
' initializer2_(a6 & b6) {}',
''],
error_collector)
self.assertEquals('', error_collector.Results())
# Multi-line references
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(
'foo.cc', 'cc',
['// Copyright 2014 Your Company. All Rights Reserved.',
'void Func(const Outer::',
' Inner& const_x,',
' const Outer',
' ::Inner& const_y,',
' const Outer<',
' int>::Inner& const_z,',
' Outer::',
' Inner& nonconst_x,',
' Outer',
' ::Inner& nonconst_y,',
' Outer<',
' int>::Inner& nonconst_z) {',
'}',
''],
error_collector)
self.assertEquals(
[operand_error_message % 'Outer::Inner& nonconst_x',
operand_error_message % 'Outer::Inner& nonconst_y',
operand_error_message % 'Outer<int>::Inner& nonconst_z'],
error_collector.Results())
# A peculiar false positive due to bad template argument parsing
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData(
'foo.cc', 'cc',
['// Copyright 2014 Your Company. All Rights Reserved.',
'inline RCULocked<X>::ReadPtr::ReadPtr(const RCULocked* rcu) {',
' DCHECK(!(data & kFlagMask)) << "Error";',
'}',
'',
'RCULocked<X>::WritePtr::WritePtr(RCULocked* rcu)',
' : lock_(&rcu_->mutex_) {',
'}',
''],
error_collector.Results())
self.assertEquals('', error_collector.Results())
def testBraceAtBeginOfLine(self):
self.TestLint('{',
'{ should almost always be at the end of the previous line'
' [whitespace/braces] [4]')
error_collector = ErrorCollector(self.assert_)
cpplint.ProcessFileData('foo.cc', 'cc',
['int function()',
'{', # warning here
' MutexLock l(&mu);',
'}',
'int variable;'
'{', # no warning
' MutexLock l(&mu);',
'}',
'MyType m = {',
' {value1, value2},',
' {', # no warning
' loooong_value1, looooong_value2',
' }',
'};',
'#if PREPROCESSOR',
'{', # no warning
' MutexLock l(&mu);',
'}',
'#endif'],
error_collector)
self.assertEquals(1, error_collector.Results().count(
'{ should almost always be at the end of the previous line'
' [whitespace/braces] [4]'))
self.TestMultiLineLint(
"""
foo(
{
loooooooooooooooong_value,
});""",
'')
def testMismatchingSpacesInParens(self):
self.TestLint('if (foo ) {', 'Mismatching spaces inside () in if'
' [whitespace/parens] [5]')
self.TestLint('switch ( foo) {', 'Mismatching spaces inside () in switch'
' [whitespace/parens] [5]')
self.TestLint('for (foo; ba; bar ) {', 'Mismatching spaces inside () in for'
' [whitespace/parens] [5]')
self.TestLint('for (; foo; bar) {', '')
self.TestLint('for ( ; foo; bar) {', '')
self.TestLint('for ( ; foo; bar ) {', '')
self.TestLint('for (foo; bar; ) {', '')
self.TestLint('while ( foo ) {', 'Should have zero or one spaces inside'
' ( and ) in while [whitespace/parens] [5]')
def testSpacingForFncall(self):
self.TestLint('if (foo) {', '')
self.TestLint('for (foo; bar; baz) {', '')
self.TestLint('for (;;) {', '')
# Space should be allowed in placement new operators.
self.TestLint('Something* p = new (place) Something();', '')
# Test that there is no warning when increment statement is empty.
self.TestLint('for (foo; baz;) {', '')
self.TestLint('for (foo;bar;baz) {', 'Missing space after ;'
' [whitespace/semicolon] [3]')
# we don't warn about this semicolon, at least for now
self.TestLint('if (condition) {return &something; }',
'')
# seen in some macros
self.TestLint('DoSth();\\', '')
# Test that there is no warning about semicolon here.
self.TestLint('abc;// this is abc',
'At least two spaces is best between code'
' and comments [whitespace/comments] [2]')
self.TestLint('while (foo) {', '')
self.TestLint('switch (foo) {', '')
self.TestLint('foo( bar)', 'Extra space after ( in function call'
' [whitespace/parens] [4]')
self.TestLint('foo( // comment', '')
self.TestLint('foo( // comment',
'At least two spaces is best between code'
' and comments [whitespace/comments] [2]')
self.TestLint('foobar( \\', '')
self.TestLint('foobar( \\', '')
self.TestLint('( a + b)', 'Extra space after ('
' [whitespace/parens] [2]')
self.TestLint('((a+b))', '')
self.TestLint('foo (foo)', 'Extra space before ( in function call'
' [whitespace/parens] [4]')
# asm volatile () may have a space, as it isn't a function call.
self.TestLint('asm volatile ("")', '')
self.TestLint('__asm__ __volatile__ ("")', '')
self.TestLint('} catch (const Foo& ex) {', '')
self.TestLint('case (42):', '')
self.TestLint('typedef foo (*foo)(foo)', '')
self.TestLint('typedef foo (*foo12bar_)(foo)', '')
self.TestLint('typedef foo (Foo::*bar)(foo)', '')
self.TestLint('using foo = type (Foo::*bar)(foo)', '')
self.TestLint('using foo = type (Foo::*bar)(', '')
self.TestLint('using foo = type (Foo::*)(', '')
self.TestLint('foo (Foo::*bar)(', '')
self.TestLint('foo (x::y::*z)(', '')
self.TestLint('foo (Foo::bar)(',
'Extra space before ( in function call'
' [whitespace/parens] [4]')
self.TestLint('foo (*bar)(', '')
self.TestLint('typedef foo (Foo::*bar)(', '')
self.TestLint('(foo)(bar)', '')
self.TestLint('Foo (*foo)(bar)', '')
self.TestLint('Foo (*foo)(Bar bar,', '')
self.TestLint('char (*p)[sizeof(foo)] = &foo', '')
self.TestLint('char (&ref)[sizeof(foo)] = &foo', '')
self.TestLint('const char32 (*table[])[6];', '')
# The sizeof operator is often written as if it were a function call, with
# an opening parenthesis directly following the operator name, but it can
# also be written like any other operator, with a space following the
# operator name, and the argument optionally in parentheses.
self.TestLint('sizeof(foo)', '')
self.TestLint('sizeof foo', '')
self.TestLint('sizeof (foo)', '')
def testSpacingBeforeBraces(self):
self.TestLint('if (foo){', 'Missing space before {'
' [whitespace/braces] [5]')
self.TestLint('for{', 'Missing space before {'
' [whitespace/braces] [5]')
self.TestLint('for {', '')
self.TestLint('EXPECT_DEBUG_DEATH({', '')
self.TestLint('std::is_convertible<A, B>{}', '')
self.TestLint('blah{32}', 'Missing space before {'
' [whitespace/braces] [5]')
self.TestLint('int8_t{3}', '')
self.TestLint('int16_t{3}', '')
self.TestLint('int32_t{3}', '')
self.TestLint('uint64_t{12345}', '')
self.TestLint('constexpr int64_t kBatchGapMicros ='
' int64_t{7} * 24 * 3600 * 1000000; // 1 wk.', '')
self.TestLint('MoveOnly(int i1, int i2) : ip1{new int{i1}}, '
'ip2{new int{i2}} {}',
'')
def testSemiColonAfterBraces(self):
self.TestLint('if (cond) { func(); };',
'You don\'t need a ; after a } [readability/braces] [4]')
self.TestLint('void Func() {};',
'You don\'t need a ; after a } [readability/braces] [4]')
self.TestLint('void Func() const {};',
'You don\'t need a ; after a } [readability/braces] [4]')
self.TestLint('class X {};', '')
for keyword in ['struct', 'union']:
for align in ['', ' alignas(16)']:
for typename in ['', ' X']:
for identifier in ['', ' x']:
self.TestLint(keyword + align + typename + ' {}' + identifier + ';',
'')
self.TestLint('class X : public Y {};', '')
self.TestLint('class X : public MACRO() {};', '')
self.TestLint('class X : public decltype(expr) {};', '')
self.TestLint('DEFINE_FACADE(PCQueue::Watcher, PCQueue) {};', '')
self.TestLint('VCLASS(XfaTest, XfaContextTest) {};', '')
self.TestLint('class STUBBY_CLASS(H, E) {};', '')
self.TestLint('class STUBBY2_CLASS(H, E) {};', '')
self.TestLint('TEST(TestCase, TestName) {};',
'You don\'t need a ; after a } [readability/braces] [4]')
self.TestLint('TEST_F(TestCase, TestName) {};',
'You don\'t need a ; after a } [readability/braces] [4]')
self.TestLint('file_tocs_[i] = (FileToc) {a, b, c};', '')
self.TestMultiLineLint('class X : public Y,\npublic Z {};', '')
def testLambda(self):
self.TestLint('auto x = []() {};', '')
self.TestLint('return []() {};', '')
self.TestMultiLineLint('auto x = []() {\n};\n', '')
self.TestLint('int operator[](int x) {};',
'You don\'t need a ; after a } [readability/braces] [4]')
self.TestMultiLineLint('auto x = [&a,\nb]() {};', '')
self.TestMultiLineLint('auto x = [&a,\nb]\n() {};', '')
self.TestMultiLineLint('auto x = [&a,\n'
' b](\n'
' int a,\n'
' int b) {\n'
' return a +\n'
' b;\n'
'};\n',
'')
# Avoid false positives with operator[]
self.TestLint('table_to_children[&*table].push_back(dependent);', '')
def testBraceInitializerList(self):
self.TestLint('MyStruct p = {1, 2};', '')
self.TestLint('MyStruct p{1, 2};', '')
self.TestLint('vector<int> p = {1, 2};', '')
self.TestLint('vector<int> p{1, 2};', '')
self.TestLint('x = vector<int>{1, 2};', '')
self.TestLint('x = (struct in_addr){ 0 };', '')
self.TestLint('Func(vector<int>{1, 2})', '')
self.TestLint('Func((struct in_addr){ 0 })', '')
self.TestLint('Func(vector<int>{1, 2}, 3)', '')
self.TestLint('Func((struct in_addr){ 0 }, 3)', '')
self.TestLint('LOG(INFO) << char{7};', '')
self.TestLint('LOG(INFO) << char{7} << "!";', '')
self.TestLint('int p[2] = {1, 2};', '')
self.TestLint('return {1, 2};', '')
self.TestLint('std::unique_ptr<Foo> foo{new Foo{}};', '')
self.TestLint('auto foo = std::unique_ptr<Foo>{new Foo{}};', '')
self.TestLint('static_assert(Max7String{}.IsValid(), "");', '')
self.TestLint('map_of_pairs[{1, 2}] = 3;', '')
self.TestLint('ItemView{has_offer() ? new Offer{offer()} : nullptr', '')
self.TestLint('template <class T, EnableIf<::std::is_const<T>{}> = 0>', '')
self.TestMultiLineLint('std::unique_ptr<Foo> foo{\n'
' new Foo{}\n'
'};\n', '')
self.TestMultiLineLint('std::unique_ptr<Foo> foo{\n'
' new Foo{\n'
' new Bar{}\n'
' }\n'
'};\n', '')
self.TestMultiLineLint('if (true) {\n'
' if (false){ func(); }\n'
'}\n',
'Missing space before { [whitespace/braces] [5]')
self.TestMultiLineLint('MyClass::MyClass()\n'
' : initializer_{\n'
' Func()} {\n'
'}\n', '')
self.TestLint('const pair<string, string> kCL' +
('o' * 41) + 'gStr[] = {\n',
'Lines should be <= 80 characters long'
' [whitespace/line_length] [2]')
self.TestMultiLineLint('const pair<string, string> kCL' +
('o' * 40) + 'ngStr[] =\n'
' {\n'
' {"gooooo", "oooogle"},\n'
'};\n', '')
self.TestMultiLineLint('const pair<string, string> kCL' +
('o' * 39) + 'ngStr[] =\n'
' {\n'
' {"gooooo", "oooogle"},\n'
'};\n', '{ should almost always be at the end of '
'the previous line [whitespace/braces] [4]')
def testSpacingAroundElse(self):
self.TestLint('}else {', 'Missing space before else'
' [whitespace/braces] [5]')
self.TestLint('} else{', 'Missing space before {'
' [whitespace/braces] [5]')
self.TestLint('} else {', '')
self.TestLint('} else if (foo) {', '')
def testSpacingWithInitializerLists(self):
self.TestLint('int v[1][3] = {{1, 2, 3}};', '')
self.TestLint('int v[1][1] = {{0}};', '')
def testSpacingForBinaryOps(self):
self.TestLint('if (foo||bar) {', 'Missing spaces around ||'
' [whitespace/operators] [3]')
self.TestLint('if (foo<=bar) {', 'Missing spaces around <='
' [whitespace/operators] [3]')
self.TestLint('if (foo<bar) {', 'Missing spaces around <'
' [whitespace/operators] [3]')
self.TestLint('if (foo>bar) {', 'Missing spaces around >'
' [whitespace/operators] [3]')
self.TestLint('if (foo<bar->baz) {', 'Missing spaces around <'
' [whitespace/operators] [3]')
self.TestLint('if (foo<bar->bar) {', 'Missing spaces around <'
' [whitespace/operators] [3]')
self.TestLint('template<typename T = double>', '')
self.TestLint('std::unique_ptr<No<Spaces>>', '')
self.TestLint('typedef hash_map<Foo, Bar>', '')
self.TestLint('10<<20', '')
self.TestLint('10<<a',
'Missing spaces around << [whitespace/operators] [3]')
self.TestLint('a<<20',
'Missing spaces around << [whitespace/operators] [3]')
self.TestLint('a<<b',
'Missing spaces around << [whitespace/operators] [3]')
self.TestLint('10LL<<20', '')
self.TestLint('10ULL<<20', '')
self.TestLint('a>>b',
'Missing spaces around >> [whitespace/operators] [3]')
self.TestLint('10>>b',
'Missing spaces around >> [whitespace/operators] [3]')
self.TestLint('LOG(ERROR)<<*foo',
'Missing spaces around << [whitespace/operators] [3]')
self.TestLint('LOG(ERROR)<<&foo',
'Missing spaces around << [whitespace/operators] [3]')
self.TestLint('StringCoder<vector<string>>::ToString()', '')
self.TestLint('map<pair<int, int>, map<int, int>>::iterator', '')
self.TestLint('func<int, pair<int, pair<int, int>>>()', '')
self.TestLint('MACRO1(list<list<int>>)', '')
self.TestLint('MACRO2(list<list<int>>, 42)', '')
self.TestLint('void DoFoo(const set<vector<string>>& arg1);', '')
self.TestLint('void SetFoo(set<vector<string>>* arg1);', '')
self.TestLint('foo = new set<vector<string>>;', '')
self.TestLint('reinterpret_cast<set<vector<string>>*>(a);', '')
self.TestLint('MACRO(<<)', '')
self.TestLint('MACRO(<<, arg)', '')
self.TestLint('MACRO(<<=)', '')
self.TestLint('MACRO(<<=, arg)', '')
self.TestLint('using Vector3<T>::operator==;', '')
self.TestLint('using Vector3<T>::operator!=;', '')
def testSpacingBeforeLastSemicolon(self):
self.TestLint('call_function() ;',
'Extra space before last semicolon. If this should be an '
'empty statement, use {} instead.'
' [whitespace/semicolon] [5]')
self.TestLint('while (true) ;',
'Extra space before last semicolon. If this should be an '
'empty statement, use {} instead.'
' [whitespace/semicolon] [5]')
self.TestLint('default:;',
'Semicolon defining empty statement. Use {} instead.'
' [whitespace/semicolon] [5]')
self.TestLint(' ;',
'Line contains only semicolon. If this should be an empty '
'statement, use {} instead.'
' [whitespace/semicolon] [5]')
self.TestLint('for (int i = 0; ;', '')
def testEmptyBlockBody(self):
self.TestLint('while (true);',
'Empty loop bodies should use {} or continue'
' [whitespace/empty_loop_body] [5]')
self.TestLint('if (true);',
'Empty conditional bodies should use {}'
' [whitespace/empty_conditional_body] [5]')
self.TestLint('while (true)', '')
self.TestLint('while (true) continue;', '')
self.TestLint('for (;;);',
'Empty loop bodies should use {} or continue'
' [whitespace/empty_loop_body] [5]')
self.TestLint('for (;;)', '')
self.TestLint('for (;;) continue;', '')
self.TestLint('for (;;) func();', '')
self.TestLint('if (test) {}',
'If statement had no body and no else clause'
' [whitespace/empty_if_body] [4]')
self.TestLint('if (test) func();', '')
self.TestLint('if (test) {} else {}', '')
self.TestMultiLineLint("""while (true &&
false);""",
'Empty loop bodies should use {} or continue'
' [whitespace/empty_loop_body] [5]')
self.TestMultiLineLint("""do {
} while (false);""",
'')
self.TestMultiLineLint("""#define MACRO \\
do { \\
} while (false);""",
'')
self.TestMultiLineLint("""do {
} while (false); // next line gets a warning
while (false);""",
'Empty loop bodies should use {} or continue'
' [whitespace/empty_loop_body] [5]')
self.TestMultiLineLint("""if (test) {
}""",
'If statement had no body and no else clause'
' [whitespace/empty_if_body] [4]')
self.TestMultiLineLint("""if (test,
func({})) {
}""",
'If statement had no body and no else clause'
' [whitespace/empty_if_body] [4]')
self.TestMultiLineLint("""if (test)
func();""", '')
self.TestLint('if (test) { hello; }', '')
self.TestLint('if (test({})) { hello; }', '')
self.TestMultiLineLint("""if (test) {
func();
}""", '')
self.TestMultiLineLint("""if (test) {
// multiline
// comment
}""", '')
self.TestMultiLineLint("""if (test) { // comment
}""", '')
self.