| #!/usr/bin/env python3 |
| # |
| # 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(google): Add a good test that tests UpdateIncludeState. |
| |
| import codecs |
| import os |
| import platform |
| import random |
| import re |
| import shutil |
| import subprocess |
| import sys |
| import tempfile |
| |
| import pytest |
| |
| import cpplint |
| |
| |
| def codecs_latin_encode(x): |
| return codecs.latin_1_encode(x)[0] |
| |
| |
| # 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: |
| # These are a global list, covering all categories seen ever. |
| _ERROR_CATEGORIES = cpplint._ERROR_CATEGORIES |
| _SEEN_ERROR_CATEGORIES: set[str] = set() |
| |
| 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, 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.add(category) |
| if cpplint._ShouldPrintError(category, confidence, filename, 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. |
| 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: |
| def __init__(self, mock_file): |
| # wrap list to allow "with open(mock)" |
| class EnterableList(list): |
| def __enter__(self): |
| return self |
| |
| def __exit__(self, type, value, tb): # noqa: A002 |
| return self |
| |
| self.mock_file = EnterableList(mock_file) |
| |
| def open( |
| self, # pylint: disable=C6409 |
| unused_filename, |
| unused_mode, |
| unused_encoding, |
| _, |
| ): |
| return self.mock_file |
| |
| |
| class CpplintTestBase: |
| """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 |
| |
| def assertTrue(self, condition, message=""): |
| assert condition, message |
| |
| # Perform lint on single line of input and return the error message. |
| def PerformSingleLineLint(self, code): |
| error_collector = ErrorCollector(self.assertTrue) |
| 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.assertTrue) |
| lines = code.split("\n") |
| cpplint.RemoveMultiLineComments("foo.h", lines, error_collector) |
| lines = cpplint.CleansedLines(lines) |
| nesting_state = cpplint.NestingState() |
| for i in range(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) |
| return error_collector.Results() |
| |
| # Similar to PerformMultiLineLint, but calls CheckLanguage instead of |
| # CheckForNonStandardConstructs |
| def PerformLanguageRulesCheck(self, file_name, code): |
| error_collector = ErrorCollector(self.assertTrue) |
| 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 range(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.assertTrue) |
| function_state = cpplint._FunctionState() |
| lines = code.split("\n") |
| cpplint.RemoveMultiLineComments(file_name, lines, error_collector) |
| lines = cpplint.CleansedLines(lines) |
| for i in range(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.assertTrue) |
| 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 range(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 make sure one of the errors is what we want |
| def TestLintContains(self, code, expected_message): |
| assert expected_message in self.PerformSingleLineLint(code) |
| |
| def TestLintNotContains(self, code, expected_message): |
| assert expected_message not in self.PerformSingleLineLint(code) |
| |
| # Perform lint and compare the error message with "expected_message". |
| def TestLint(self, code, expected_message): |
| assert expected_message == self.PerformSingleLineLint(code) |
| |
| def TestMultiLineLint(self, code, expected_message): |
| assert expected_message == self.PerformMultiLineLint(code) |
| |
| def TestMultiLineLintRE(self, code, expected_message_re): |
| message = self.PerformMultiLineLint(code) |
| assert re.search(expected_message_re, message) |
| |
| def TestLanguageRulesCheck(self, file_name, code, expected_message): |
| assert expected_message == self.PerformLanguageRulesCheck(file_name, code) |
| |
| def TestIncludeWhatYouUse(self, code, expected_message): |
| assert expected_message == self.PerformIncludeWhatYouUse(code) |
| |
| def TestBlankLinesCheck(self, lines, start_errors, end_errors): |
| for extension in ["c", "cc", "cpp", "cxx", "c++", "cu"]: |
| self.doTestBlankLinesCheck(lines, start_errors, end_errors, extension) |
| |
| def doTestBlankLinesCheck(self, lines, start_errors, end_errors, extension): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData("foo." + extension, extension, lines, error_collector) |
| assert start_errors == error_collector.Results().count( |
| "Redundant blank line at the start of a code block should be deleted. " |
| "[whitespace/blank_line] [2]" |
| ) |
| assert end_errors == error_collector.Results().count( |
| "Redundant blank line at the end of a code block should be deleted. " |
| "[whitespace/blank_line] [3]" |
| ) |
| |
| |
| class TestCpplint(CpplintTestBase): |
| def GetNamespaceResults(self, lines): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.RemoveMultiLineComments("foo.h", lines, error_collector) |
| lines = cpplint.CleansedLines(lines) |
| nesting_state = cpplint.NestingState() |
| for i in range(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) |
| assert results == "Do not indent within a namespace. [whitespace/indent_namespace] [4]" |
| |
| def testNamespaceIndentationForClass(self): |
| lines = [ |
| "namespace Test {", |
| "void foo() { }", |
| " class Test {", |
| " };", |
| "} // namespace Test", |
| ] |
| |
| results = self.GetNamespaceResults(lines) |
| assert results == [ |
| "Do not indent within a namespace. [whitespace/indent_namespace] [4]", |
| "Do not indent within a namespace. [whitespace/indent_namespace] [4]", |
| ] |
| |
| def testNamespaceIndentationIndentedParameter(self): |
| lines = [ |
| "namespace Test {", |
| "void foo(SuperLongTypeName d = 418,", |
| " SuperLongTypeName e = 2.71) { }", |
| "} // namespace Test", |
| ] |
| |
| results = self.GetNamespaceResults(lines) |
| assert results == "" |
| |
| def testNamespaceIndentationMemberInitializerList(self): |
| lines = [ |
| "namespace Opossum {", |
| "", |
| "Acme::Acme(const std::shared_ptr<const AbstractOperator> left,", |
| " const std::shared_ptr<const AbstractOperator> nigh)", |
| " : _left(left), _behind(nigh) {}", |
| "", |
| "} // namespace Opossum", |
| ] |
| assert self.GetNamespaceResults(lines) == "" |
| |
| # Multiline member initializer List |
| lines = [ |
| "namespace Rosenfield {", |
| "class Crush : public Habitual {", |
| " public:", |
| " Crush() : _a(1),", |
| " _b(2)", |
| " {}", |
| "};", |
| "} // namespace Rosenfield", |
| ] |
| assert self.GetNamespaceResults(lines) == "" |
| |
| # Same line as constructor declaration |
| lines = [ |
| "namespace Boucher {", |
| " X::X() : _s(2) {}", |
| " A::A() : _e(12) {", |
| ] |
| assert self.GetNamespaceResults(lines) == [ |
| "Do not indent within a namespace. [whitespace/indent_namespace] [4]", |
| "Do not indent within a namespace. [whitespace/indent_namespace] [4]", |
| ] |
| |
| # Definition on indented line |
| lines = [ |
| "namespace Store {", |
| "", |
| " Color::Color() : my_name_is('b')", |
| " this_is_true(true) {", |
| ] |
| assert ( |
| self.GetNamespaceResults(lines) |
| == "Do not indent within a namespace. [whitespace/indent_namespace] [4]" |
| ) |
| |
| def testNestingInNamespace(self): |
| lines = [ |
| "namespace Test {", |
| "struct OuterClass {", |
| " struct NoFalsePositivesHere;", |
| " struct NoFalsePositivesHere member_variable;", |
| "};", |
| "void foo() {", |
| " const int no_positives_eh = 418;", |
| "}", |
| "} // namespace Test", |
| ] |
| |
| results = self.GetNamespaceResults(lines) |
| assert results == "" |
| |
| # Test get line width. |
| def testGetLineWidth(self): |
| assert cpplint.GetLineWidth("") == 0 |
| assert cpplint.GetLineWidth("x" * 10) == 10 |
| assert cpplint.GetLineWidth("都|道|府|県|支庁") == 16 |
| assert cpplint.GetLineWidth("都|道|府|県|支庁") == 16 |
| assert cpplint.GetLineWidth("d𝐱/dt" + "f : t ⨯ 𝐱 → ℝ" + "t ⨯ 𝐱 → ℝ") == 5 + 13 + 9 |
| |
| def testGetTextInside(self): |
| assert cpplint._GetTextInside("fun()", r"fun\(") == "" |
| assert cpplint._GetTextInside("f(x, y)", r"f\(") == "x, y" |
| assert cpplint._GetTextInside("printf(a(), b(c()))", r"printf\(") == "a(), b(c())" |
| assert cpplint._GetTextInside("f[x, y{}]", r"f\[") == "x, y{}" |
| assert None is cpplint._GetTextInside("f[a, b(}]", r"f\[") |
| assert None is cpplint._GetTextInside("f[x, y]", r"f\(") |
| assert cpplint._GetTextInside("f(x, g(y, h(z, (a + b))))", r"g\(") == "y, h(z, (a + b))" |
| assert cpplint._GetTextInside("f(f(f(x)))", r"f\(") == "f(f(x))" |
| # Supports multiple lines. |
| assert ( |
| cpplint._GetTextInside("int loop(int x) {\n return loop(x);\n}\n", r"\{") |
| == "\n return loop(x);\n" |
| ) |
| # '^' matches the beginning of each line. |
| assert ( |
| 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+\(", |
| ) |
| == "x, y" |
| ) |
| |
| def testFindNextMultiLineCommentStart(self): |
| assert cpplint.FindNextMultiLineCommentStart([""], 0) == 1 |
| |
| lines = ["a", "b", "/* c"] |
| assert cpplint.FindNextMultiLineCommentStart(lines, 0) == 2 |
| |
| lines = ['char a[] = "/*";'] # not recognized as comment. |
| assert cpplint.FindNextMultiLineCommentStart(lines, 0) == 1 |
| |
| def testFindNextMultiLineCommentEnd(self): |
| assert cpplint.FindNextMultiLineCommentEnd([""], 0) == 1 |
| lines = ["a", "b", " c */"] |
| assert cpplint.FindNextMultiLineCommentEnd(lines, 0) == 2 |
| |
| def testRemoveMultiLineCommentsFromRange(self): |
| lines = ["a", " /* comment ", " * still comment", " comment */ ", "b"] |
| cpplint.RemoveMultiLineCommentsFromRange(lines, 1, 4) |
| assert lines == ["a", "/**/", "/**/", "/**/", "b"] |
| |
| 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"(\ng' + ("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]", |
| ) |
| self.TestLint(" /// @copydoc " + ("o" * (cpplint._line_length * 2)), "") |
| self.TestLint(" /// @copydetails " + ("o" * (cpplint._line_length * 2)), "") |
| self.TestLint(" /// @copybrief " + ("o" * (cpplint._line_length * 2)), "") |
| |
| # Test error suppression annotations. |
| def testErrorSuppression(self): |
| # Two errors on same line: |
| self.TestLint( |
| "long a = (int64_t) 65;", |
| [ |
| "Using C-style cast. Use static_cast<int64_t>(...) instead" |
| " [readability/casting] [4]", |
| "Use int16_t/int64_t/etc, rather than the C type long [runtime/int] [4]", |
| ], |
| ) |
| # One category of error suppressed: |
| self.TestLint( |
| "long a = (int64_t) 65; // NOLINT(runtime/int)", |
| "Using C-style cast. Use static_cast<int64_t>(...) instead [readability/casting] [4]", |
| ) |
| # Two categories of errors suppressed: |
| self.TestLint("long a = (int64_t) 65; // NOLINT(runtime/int,readability/casting)", "") |
| |
| # All categories suppressed: (two aliases) |
| self.TestLint("long a = (int64_t) 65; // NOLINT", "") |
| self.TestLint("long a = (int64_t) 65; // NOLINT(*)", "") |
| |
| # Linting a C file |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.c", |
| "c", |
| ["// Copyright 2014 Your Majesty.", "int64_t a = (int64_t) 65;", ""], |
| error_collector, |
| ) |
| assert error_collector.Results() == "" |
| |
| # Malformed NOLINT directive: |
| self.TestLint( |
| "long a = 65; // NOLINT(foo)", |
| [ |
| "Unknown NOLINT error category: foo [readability/nolint] [5]", |
| "Use int16_t/int64_t/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_t/int64_t/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.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINTNEXTLINE(whitespace/line_length)", |
| "// ./command" + (" -verbose" * 80), |
| "", |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == "" |
| # NOLINTNEXTLINE multiple categories silences warning for the next line instead of current |
| # line |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINTNEXTLINE(runtime/int,readability/casting)", |
| "long a = (int64_t) 65;", |
| "", |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == "" |
| # LINT_C_FILE silences cast warnings for entire file. |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.h", |
| "h", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINT(build/header_guard)", |
| "int64_t a = (uint64_t) 65;", |
| "// LINT_C_FILE", |
| "", |
| ], |
| error_collector, |
| ) |
| assert 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.assertTrue) |
| cpplint.ProcessFileData( |
| "test.h", |
| "h", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINT(build/header_guard)", |
| "int64_t a = (uint64_t) 65;", |
| "/* Prevent warnings about the modeline", |
| modeline, |
| "*/", |
| "", |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == "" |
| # LINT_KERNEL_FILE silences whitespace/tab warnings for entire file. |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.h", |
| "h", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINT(build/header_guard)", |
| "struct test {", |
| "\tint member;", |
| "};", |
| "// LINT_KERNEL_FILE", |
| "", |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == "" |
| # NOLINT, NOLINTNEXTLINE silences the readability/braces warning for "};". |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "#include <iostream>", |
| "for (int i = 0; i != 100; ++i) {", |
| " std::cout << i << std::endl;", |
| "}; // NOLINT", |
| "for (int i = 0; i != 100; ++i) {", |
| " std::cout << i << std::endl;", |
| "// NOLINTNEXTLINE", |
| "};", |
| "// LINT_KERNEL_FILE", |
| "", |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == "" |
| # NOLINTBEGIN and silences all warnings after it |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINTBEGIN", |
| "long a = (int64_t) 65;long a = 65;", |
| "// ./command" + (" -verbose" * 80), |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == "" |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINTBEGIN(*)", |
| "long a = (int64_t) 65;long a = 65;", |
| "// ./command" + (" -verbose" * 80), |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == "" |
| # NOLINTEND will show warnings after that point |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINTBEGIN", |
| "long a = (int64_t) 65;long a = 65;", |
| "// NOLINTEND", |
| "// ./command" + (" -verbose" * 80), |
| "", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results() |
| == "Lines should be <= 80 characters long [whitespace/line_length] [2]" |
| ) |
| # NOLINTBEGIN(category) silences category warnings after it |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINTBEGIN(readability/casting,runtime/int)", |
| "long a = (int64_t) 65;", |
| "long a = 65;", |
| "// ./command" + (" -verbose" * 80), |
| "// NOLINTEND", |
| "", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results() |
| == "Lines should be <= 80 characters long [whitespace/line_length] [2]" |
| ) |
| # NOLINTEND(category) will generate an error that categories are not supported |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINTBEGIN(readability/casting,runtime/int)", |
| "long a = (int64_t) 65;", |
| "long a = 65;", |
| "// NOLINTEND(readability/casting)", |
| "", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results() |
| == "NOLINT categories not supported in block END: readability/casting " |
| "[readability/nolint] [5]" |
| ) |
| # nested NOLINTBEGIN is not allowed |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINTBEGIN(readability/casting,runtime/int)", |
| "long a = (int64_t) 65;", |
| "// NOLINTBEGIN(runtime/int)", |
| "long a = 65;", |
| "// NOLINTEND(*)", |
| "", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results() |
| == "NONLINT block already defined on line 2 [readability/nolint] [5]" |
| ) |
| # error if NOLINGBEGIN is not ended |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "// NOLINTBEGIN(readability/casting,runtime/int)", |
| "long a = (int64_t) 65;", |
| "long a = 65;", |
| "", |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == "NONLINT block never ended [readability/nolint] [5]" |
| # error if unmatched NOLINTEND |
| self.TestLint("// NOLINTEND", "Not in a NOLINT block [readability/nolint] [5]") |
| self.TestLint("// NOLINTEND(*)", "Not in a NOLINT block [readability/nolint] [5]") |
| |
| # Test Variable Declarations. |
| def testVariableDeclarations(self): |
| self.TestLint( |
| "long a = 65;", |
| "Use int16_t/int64_t/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_t/int64_t/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_t a = (uint16_t)1.0;", |
| "Using C-style cast. Use static_cast<uint16_t>(...) instead" |
| " [readability/casting] [4]", |
| ) |
| self.TestLint( |
| "int32_t a = (int32_t)1.0;", |
| "Using C-style cast. Use static_cast<int32_t>(...) instead [readability/casting] [4]", |
| ) |
| self.TestLint( |
| "uint64_t a = (uint64_t)1.0;", |
| "Using C-style cast. Use static_cast<uint64_t>(...) instead" |
| " [readability/casting] [4]", |
| ) |
| self.TestLint( |
| "size_t a = (size_t)1.0;", |
| "Using C-style cast. Use static_cast<size_t>(...) 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);", "") |
| self.TestLint("X Class::operator++(int)", "") |
| self.TestLint("X Class::operator--(int)", "") |
| |
| # 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_t 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_t(123);", "") # "new" operator on basic type |
| self.TestLint("new int64_t(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.assertTrue) |
| cpplint.ProcessFileData( |
| "test.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company. All Rights Reserved.", |
| "typedef std::function<", |
| " bool(int)> F;", |
| "", |
| ], |
| error_collector, |
| ) |
| assert 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_t, bool(*)(int64_t, int64_t)> 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.assertTrue) |
| 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, |
| ) |
| assert ( |
| error_collector.Results().count( |
| "Using deprecated casting style. Use static_cast<bool>(...) instead " |
| "[readability/casting] [4]" |
| ) |
| == 0 |
| ) |
| assert ( |
| error_collector.Results().count( |
| "Using deprecated casting style. Use static_cast<int>(...) instead " |
| "[readability/casting] [4]" |
| ) |
| == 1 |
| ) |
| |
| # 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;" |
| for extension in ["h", "hpp", "hxx", "h++", "cuh", "c", "cc", "cpp", "cxx", "c++", "cu"]: |
| assert ( |
| self.PerformIncludeWhatYouUse(code, "foo." + extension) |
| == "Add #include <vector> for vector<> [build/include_what_you_use] [4]" |
| ) |
| |
| 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( |
| 'cout << "hello world" << endl;', |
| "Add #include <iostream> for cout [build/include_what_you_use] [4]", |
| ) |
| self.TestIncludeWhatYouUse( |
| 'printf("hello world");', |
| "Add #include <cstdio> for printf [build/include_what_you_use] [4]", |
| ) |
| self.TestIncludeWhatYouUse( |
| """#include <stdio.h> |
| printf("hello world");""", |
| "", |
| ) # Avoid false positives w/ c-style include |
| 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" |
| boost::range::transform(input, std::back_inserter(output), square); |
| """, |
| "", |
| ) # Avoid false positives on transform in other namespaces. |
| self.TestIncludeWhatYouUse( |
| """#include "base/foobar.h" |
| bool foobar = std::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]", |
| ) |
| # False positive for std::set |
| self.TestIncludeWhatYouUse( |
| """ |
| #include <string> |
| struct Foo { |
| template <typename T> |
| void set(const std::string& name, const T& value); |
| }; |
| Foo bar; |
| Foo* pbar = &bar; |
| bar.set<int>("int", 5); |
| pbar->set<bool>("bool", false);""", |
| "", |
| ) |
| # False positive for std::map |
| self.TestIncludeWhatYouUse( |
| """ |
| template <typename T> |
| struct Foo { |
| T t; |
| }; |
| template <typename T> |
| Foo<T> map(T t) { |
| return Foo<T>{ t }; |
| } |
| struct Bar { |
| }; |
| auto res = map<Bar>(); |
| """, |
| "", |
| ) |
| # False positive for boost::container::set |
| self.TestIncludeWhatYouUse( |
| """ |
| boost::container::set<int> foo; |
| """, |
| "", |
| ) |
| |
| def testFilesBelongToSameModule(self): |
| f = cpplint.FilesBelongToSameModule |
| assert f("a.cc", "a.h") == (True, "") |
| assert f("base/google.cc", "base/google.h") == (True, "") |
| assert f("base/google_test.c", "base/google.h") == (True, "") |
| assert f("base/google_test.cc", "base/google.h") == (True, "") |
| assert f("base/google_test.cc", "base/google.hpp") == (True, "") |
| assert f("base/google_test.cxx", "base/google.hxx") == (True, "") |
| assert f("base/google_test.cpp", "base/google.hpp") == (True, "") |
| assert f("base/google_test.c++", "base/google.h++") == (True, "") |
| assert f("base/google_test.cu", "base/google.cuh") == (True, "") |
| assert f("base/google_unittest.cc", "base/google.h") == (True, "") |
| assert f("base/internal/google_unittest.cc", "base/public/google.h") == (True, "") |
| assert f("xxx/yyy/base/internal/google_unittest.cc", "base/public/google.h") == ( |
| True, |
| "xxx/yyy/", |
| ) |
| assert f("xxx/yyy/base/google_unittest.cc", "base/public/google.h") == (True, "xxx/yyy/") |
| assert f("base/google_unittest.cc", "base/google-inl.h") == (True, "") |
| assert f("/home/build/google3/base/google.cc", "base/google.h") == ( |
| True, |
| "/home/build/google3/", |
| ) |
| |
| assert f("/home/build/google3/base/google.cc", "basu/google.h") == (False, "") |
| assert f("a.cc", "b.h") == (False, "") |
| |
| def testCleanseLine(self): |
| assert cpplint.CleanseComments("int foo = 0; // danger!") == "int foo = 0;" |
| assert cpplint.CleanseComments("int /* foo */ o = 0;") == "int o = 0;" |
| assert cpplint.CleanseComments("foo(int a /* abc */, int b);") == "foo(int a, int b);" |
| assert cpplint.CleanseComments("f(a, /* name */ b);") == "f(a, b);" |
| assert cpplint.CleanseComments("f(a /* name */, b);") == "f(a, b);" |
| assert cpplint.CleanseComments("f(a, /* name */b);") == "f(a, b);" |
| assert cpplint.CleanseComments("f(a, /**/b, /**/c);") == "f(a, b, c);" |
| assert cpplint.CleanseComments("f(a, /**/b/**/, c);") == "f(a, b, c);" |
| |
| def testRawStrings(self): |
| self.TestMultiLineLint( |
| """ |
| int main() { |
| struct A { |
| A(std::string s, A&& a); |
| }; |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| template <class T, class D = default_delete<T>> class unique_ptr { |
| public: |
| unique_ptr(unique_ptr&& u) noexcept; |
| };""", |
| "", |
| ) |
| 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]" |
| ) |
| |
| for extension in ["c", "cc", "cpp", "cxx", "c++", "cu"]: |
| file_path = "mydir/foo." + extension |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, |
| extension, |
| ['const char* str = "This is a\\', ' multiline string.";'], |
| error_collector, |
| ) |
| # One per line. |
| assert error_collector.ResultList().count(multiline_string_error_message) == 2 |
| |
| # 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] [4]", |
| ) |
| # 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] [4]", |
| ], |
| ) |
| # 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] [4]", |
| ) |
| # missing explicit, with qualified classname |
| self.TestMultiLineLint( |
| """ |
| class Qualifier::AnotherOne::Foo { |
| Foo(int f); |
| };""", |
| "Single-parameter constructors should be marked explicit. [runtime/explicit] [4]", |
| ) |
| # 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] [4]", |
| ) |
| # 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] [4]", |
| ) |
| # 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] [4]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| class Foo { |
| inline constexpr Foo(int f); |
| };""", |
| "Single-parameter constructors should be marked explicit. [runtime/explicit] [4]", |
| ) |
| # 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] [4]", |
| ) |
| # 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] [4]", |
| ) |
| # 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] [4]", |
| ) |
| # 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] [4]", |
| ) |
| # 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] [4]", |
| ) |
| # 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] [4]", |
| ) |
| # explicit no-argument constructors are just fine |
| self.TestMultiLineLint( |
| """ |
| class Foo { |
| explicit Foo(); |
| };""", |
| "", |
| ) |
| # void constructors are considered no-argument |
| self.TestMultiLineLint( |
| """ |
| class Foo { |
| explicit Foo(void); |
| };""", |
| "", |
| ) |
| # 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] [4]", |
| ) |
| # 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] [4]", |
| ) |
| # 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(volatile Foo&); |
| };""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| class Foo { |
| Foo(volatile const Foo&); |
| };""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| class Foo { |
| Foo(const volatile 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) {} |
| };""", |
| "", |
| ) |
| # Special case for variadic arguments |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "class Foo {", |
| " template<typename... Args>", |
| " explicit Foo(const int arg, Args&&... args) {}", |
| "};", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "Constructors that require multiple arguments should not be marked explicit. " |
| "[runtime/explicit] [0]" |
| ) |
| == 0 |
| ) |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "class Foo {", |
| " template<typename... Args>", |
| " explicit Foo(Args&&... args) {}", |
| "};", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "Constructors that require multiple arguments should not be marked explicit. " |
| "[runtime/explicit] [0]" |
| ) |
| == 0 |
| ) |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "class Foo {", |
| " template<typename... Args>", |
| " Foo(const int arg, Args&&... args) {}", |
| "};", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "Constructors callable with one argument should be marked explicit. " |
| "[runtime/explicit] [4]" |
| ) |
| == 1 |
| ) |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| ["class Foo {", " template<typename... Args>", " Foo(Args&&... args) {}", "};"], |
| error_collector, |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "Constructors callable with one argument should be marked explicit. " |
| "[runtime/explicit] [4]" |
| ) |
| == 1 |
| ) |
| # Anything goes inside an assembly block |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "void Func() {", |
| " __asm__ (", |
| ' "hlt"', |
| " );", |
| " asm {", |
| " movdqa [edx + 32], xmm2", |
| " }", |
| "}", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "Extra space before ( in function call [whitespace/parens] [4]" |
| ) |
| == 0 |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "Closing ) should be moved to the previous line [whitespace/parens] [2]" |
| ) |
| == 0 |
| ) |
| assert ( |
| error_collector.ResultList().count("Extra space before [ [whitespace/braces] [5]") |
| == 0 |
| ) |
| 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.assertTrue) |
| 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, |
| ) |
| assert [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.assertTrue) |
| 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, |
| ) |
| assert 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(google): 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.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "class SomeClass {", |
| " private:", |
| " %s(SomeClass);" % macro_name, |
| " int member_;", |
| "};", |
| "", |
| ], |
| error_collector, |
| ) |
| assert ( |
| "%s should be the last thing in the class" % macro_name |
| + " [readability/constructors] [3]" |
| == error_collector.Results() |
| ) |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "class OuterClass {", |
| " private:", |
| " struct InnerClass {", |
| " private:", |
| " %s(InnerClass);" % macro_name, |
| " int member;", |
| " };", |
| "};", |
| "", |
| ], |
| error_collector, |
| ) |
| assert ( |
| "%s should be the last thing in the class" % macro_name |
| + " [readability/constructors] [3]" |
| == error_collector.Results() |
| ) |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| 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, |
| ) |
| assert 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 } };""", |
| "", |
| ) |
| self.TestMultiLineLint( # should not claim else should have braces on both sides |
| """if (foo) { |
| bar; |
| } |
| else { |
| baz; |
| }""", |
| "An else should appear on the same line as the preceding } [whitespace/newline] [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; }", |
| "Controlled statements inside brackets of if clause should be on a separate line" |
| " [whitespace/newline] [5]", |
| ) |
| 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.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company. All Rights Reserved.", |
| "void a::b() {}", |
| "void f(int& q) {}", |
| "", |
| ], |
| error_collector, |
| ) |
| assert 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.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company. All Rights Reserved.", |
| "#include <string>", |
| "#include <utility>", |
| "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, |
| ) |
| assert error_collector.Results() == "" |
| |
| # Multi-line references |
| error_collector = ErrorCollector(self.assertTrue) |
| 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, |
| ) |
| assert [ |
| 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.assertTrue) |
| 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(), |
| ) |
| assert 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.assertTrue) |
| 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, |
| ) |
| assert ( |
| error_collector.Results().count( |
| "{ should almost always be at the end of the previous line [whitespace/braces] [4]" |
| ) |
| == 1 |
| ) |
| |
| 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.TestLintNotContains( |
| "if (condition) { return &something; }", |
| "Missing space after ; [whitespace/semicolon] [3]", |
| ) |
| # 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 testReplaceAlternateTokens(self): |
| assert cpplint.ReplaceAlternateTokens("tor or orc") == "tor || orc" |
| assert cpplint.ReplaceAlternateTokens("orc or tor") == "orc || tor" |
| assert cpplint.ReplaceAlternateTokens("tor or (orc)") == "tor || (orc)" |
| assert cpplint.ReplaceAlternateTokens("tor or(orc)") == "tor ||(orc)" |
| assert cpplint.ReplaceAlternateTokens("sand and(android)") == "sand &&(android)" |
| assert cpplint.ReplaceAlternateTokens("(sand) and (android)") == "(sand) && (android)" |
| assert cpplint.ReplaceAlternateTokens(" not note") == " !note" |
| assert cpplint.ReplaceAlternateTokens(")not note") == ")!note" |
| assert cpplint.ReplaceAlternateTokens("(not note") == "(!note" |
| assert cpplint.ReplaceAlternateTokens(" not(note)") == " !(note)" |
| assert cpplint.ReplaceAlternateTokens(" not (splinot)") == " !(splinot)" |
| assert cpplint.ReplaceAlternateTokens("tor and orc or android") == "tor && orc || android" |
| assert ( |
| cpplint.ReplaceAlternateTokens("tor or orc and ands not note") |
| == "tor || orc && ands !note" |
| ) |
| |
| def testSpacingAfterAlternateToken(self): |
| try: |
| cpplint._cpplint_state.AddFilters("-readability/alt_tokens") |
| self.TestLint("if (foo or (bar) or foobar) {", "") |
| self.TestLint("if (foo or (bar)) {", "") |
| self.TestLint("if ((foo) or (bar)) {", "") |
| self.TestLint("if (not foo) {", "") |
| self.TestLint("if (not (foo)) {", "") |
| self.TestLint("if (not(foo)) {", "") |
| self.TestLint( |
| "if ((foo)or(bar)) {", "Missing spaces around || [whitespace/operators] [3]" |
| ) |
| finally: |
| cpplint._cpplint_state.SetFilters("") |
| |
| 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.TestLintContains( |
| "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 {};", "") |
| self.TestMultiLineLint( |
| "template<typename T>\nconcept Addable = requires(T x) { x + x; };", "" |
| ) |
| self.TestMultiLineLint( |
| "template <typename T>\nconcept C = requires(T a, T b) {\n requires a == b;\n};", "" |
| ) |
| self.TestMultiLineLint( |
| "template <typename T, typename U>\n" |
| "concept C = (std::integral<T> || std::floating_point<T>) &&\n" |
| " (std::integral<U> || std::floating_point<U>) &&\n" |
| " requires(T t, U u) {\n" |
| " std::min(static_cast<float>(t), static_cast<float>(u));\n" |
| "};", |
| "", |
| ) |
| |
| def testSpacingBeforeBrackets(self): |
| self.TestLint( |
| "int numbers [] = { 1, 2, 3 };", "Extra space before [ [whitespace/braces] [5]" |
| ) |
| # space allowed in some cases |
| self.TestLint("auto [abc, def] = func();", "") |
| self.TestLint("#define NODISCARD [[nodiscard]]", "") |
| self.TestLint("void foo(int param [[maybe_unused]]);", "") |
| |
| 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){\n 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; }", |
| "Controlled statements inside brackets of if clause should be on a separate line" |
| " [whitespace/newline] [5]", |
| ) |
| self.TestLint( |
| "if (test({})) { hello; }", |
| "Controlled statements inside brackets of if clause should be on a separate line" |
| " [whitespace/newline] [5]", |
| ) |
| self.TestMultiLineLint( |
| """if (test) { |
| func(); |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """if (test) { |
| // multiline |
| // comment |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """if (test) { // comment |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """if (test) { |
| } else { |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """if (func(p1, |
| p2, |
| p3)) { |
| func(); |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """if (func({}, p1)) { |
| func(); |
| }""", |
| "", |
| ) |
| |
| def testSpacingForRangeBasedFor(self): |
| # Basic correctly formatted case: |
| self.TestLint("for (int i : numbers) {", "") |
| |
| # Missing space before colon: |
| self.TestLint( |
| "for (int i: numbers) {", |
| "Missing space around colon in range-based for loop [whitespace/forcolon] [2]", |
| ) |
| # Missing space after colon: |
| self.TestLint( |
| "for (int i :numbers) {", |
| "Missing space around colon in range-based for loop [whitespace/forcolon] [2]", |
| ) |
| # Missing spaces both before and after the colon. |
| self.TestLint( |
| "for (int i:numbers) {", |
| "Missing space around colon in range-based for loop [whitespace/forcolon] [2]", |
| ) |
| |
| # The scope operator '::' shouldn't cause warnings... |
| self.TestLint("for (std::size_t i : sizes) {}", "") |
| # ...but it shouldn't suppress them either. |
| self.TestLint( |
| "for (std::size_t i: sizes) {}", |
| "Missing space around colon in range-based for loop [whitespace/forcolon] [2]", |
| ) |
| |
| # Static or global STL strings. |
| def testStaticOrGlobalSTLStrings(self): |
| # A template for the error message for a const global/static string. |
| error_msg = ( |
| "For a static/global string constant, use a C style " |
| 'string instead: "%s[]". [runtime/string] [4]' |
| ) |
| # The error message for a non-const global/static string variable. |
| nonconst_error_msg = ( |
| "Static/global string variables are not permitted. [runtime/string] [4]" |
| ) |
| |
| self.TestLint("string foo;", nonconst_error_msg) |
| self.TestLint('string kFoo = "hello"; // English', nonconst_error_msg) |
| self.TestLint("static string foo;", nonconst_error_msg) |
| self.TestLint("static const string foo;", error_msg % "static const char foo") |
| self.TestLint("static const std::string foo;", error_msg % "static const char foo") |
| self.TestLint("string Foo::bar;", nonconst_error_msg) |
| |
| self.TestLint("std::string foo;", nonconst_error_msg) |
| self.TestLint('std::string kFoo = "hello"; // English', nonconst_error_msg) |
| self.TestLint("static std::string foo;", nonconst_error_msg) |
| self.TestLint("static const std::string foo;", error_msg % "static const char foo") |
| self.TestLint("std::string Foo::bar;", nonconst_error_msg) |
| |
| self.TestLint("::std::string foo;", nonconst_error_msg) |
| self.TestLint('::std::string kFoo = "hello"; // English', nonconst_error_msg) |
| self.TestLint("static ::std::string foo;", nonconst_error_msg) |
| self.TestLint("static const ::std::string foo;", error_msg % "static const char foo") |
| self.TestLint("::std::string Foo::bar;", nonconst_error_msg) |
| |
| self.TestLint("string* pointer", "") |
| self.TestLint("string *pointer", "") |
| self.TestLint("string* pointer = Func();", "") |
| self.TestLint("string *pointer = Func();", "") |
| self.TestLint("const string* pointer", "") |
| self.TestLint("const string *pointer", "") |
| self.TestLint("const string* pointer = Func();", "") |
| self.TestLint("const string *pointer = Func();", "") |
| self.TestLint("string const* pointer", "") |
| self.TestLint("string const *pointer", "") |
| self.TestLint("string const* pointer = Func();", "") |
| self.TestLint("string const *pointer = Func();", "") |
| self.TestLint("string* const pointer", "") |
| self.TestLint("string *const pointer", "") |
| self.TestLint("string* const pointer = Func();", "") |
| self.TestLint("string *const pointer = Func();", "") |
| self.TestLint("string Foo::bar() {}", "") |
| self.TestLint("string Foo::operator*() {}", "") |
| # Rare case. |
| self.TestLint('string foo("foobar");', nonconst_error_msg) |
| # Should not catch local or member variables. |
| self.TestLint(" string foo", "") |
| # Should not catch functions. |
| self.TestLint('string EmptyString() { return ""; }', "") |
| self.TestLint('string EmptyString () { return ""; }', "") |
| self.TestLint("string const& FileInfo::Pathname() const;", "") |
| self.TestLint("string const &FileInfo::Pathname() const;", "") |
| self.TestLint( |
| "string VeryLongNameFunctionSometimesEndsWith(\n" |
| " VeryLongNameType very_long_name_variable) {}", |
| "", |
| ) |
| self.TestLint( |
| "template<>\n" |
| "string FunctionTemplateSpecialization<SomeType>(\n" |
| ' int x) { return ""; }', |
| "", |
| ) |
| self.TestLint( |
| "template<>\n" |
| "string FunctionTemplateSpecialization<vector<A::B>* >(\n" |
| ' int x) { return ""; }', |
| "", |
| ) |
| |
| # should not catch methods of template classes. |
| self.TestLint('string Class<Type>::Method() const {\n return "";\n}\n', "") |
| self.TestLint('string Class<Type>::Method(\n int arg) const {\n return "";\n}\n', "") |
| |
| # Check multiline cases. |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "#include <string>", |
| "string Class", |
| "::MemberFunction1();", |
| "string Class::", |
| "MemberFunction2();", |
| "string Class::", |
| "NestedClass::MemberFunction3();", |
| "string TemplateClass<T>::", |
| "NestedClass::MemberFunction4();", |
| "const string Class", |
| "::static_member_variable1;", |
| "const string Class::", |
| "static_member_variable2;", |
| "const string Class", |
| '::static_member_variable3 = "initial value";', |
| "const string Class::", |
| 'static_member_variable4 = "initial value";', |
| "string Class::", |
| "static_member_variable5;", |
| "", |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == [ |
| error_msg % "const char Class::static_member_variable1", |
| error_msg % "const char Class::static_member_variable2", |
| error_msg % "const char Class::static_member_variable3", |
| error_msg % "const char Class::static_member_variable4", |
| nonconst_error_msg, |
| ] |
| |
| def testNoSpacesInFunctionCalls(self): |
| self.TestLint("TellStory(1, 3);", "") |
| self.TestLint("TellStory(1, 3 );", "Extra space before ) [whitespace/parens] [2]") |
| self.TestLint("TellStory(1 /* wolf */, 3 /* pigs */);", "") |
| self.TestMultiLineLint( |
| """TellStory(1, 3 |
| );""", |
| "Closing ) should be moved to the previous line [whitespace/parens] [2]", |
| ) |
| self.TestMultiLineLint( |
| """TellStory(Wolves(1), |
| Pigs(3 |
| ));""", |
| "Closing ) should be moved to the previous line [whitespace/parens] [2]", |
| ) |
| self.TestMultiLineLint( |
| """TellStory(1, |
| 3 );""", |
| "Extra space before ) [whitespace/parens] [2]", |
| ) |
| |
| def testToDoComments(self): |
| start_space = "Too many spaces before TODO [whitespace/todo] [2]" |
| missing_username = ( |
| "Missing username in TODO; it should look like " |
| '"// TODO(my_username): Stuff."' |
| " [readability/todo] [2]" |
| ) |
| end_space = "TODO(my_username) should be followed by a space [whitespace/todo] [2]" |
| |
| self.TestLint("// TODOfix this", [start_space, missing_username, end_space]) |
| self.TestLint("// TODO(ljenkins)fix this", [start_space, end_space]) |
| self.TestLint("// TODO fix this", [start_space, missing_username]) |
| self.TestLint("// TODO fix this", missing_username) |
| self.TestLint("// TODO: fix this", missing_username) |
| self.TestLint( |
| "//TODO(ljenkins): Fix this", |
| "Should have a space between // and comment [whitespace/comments] [4]", |
| ) |
| self.TestLint("// TODO(ljenkins):Fix this", end_space) |
| self.TestLint("// TODO(ljenkins):", "") |
| self.TestLint("// TODO(ljenkins): fix this", "") |
| self.TestLint("// TODO(ljenkins): Fix this", "") |
| self.TestLint("#if 1 // TEST_URLTODOCID_WHICH_HAS_THAT_WORD_IN_IT_H_", "") |
| self.TestLint("// See also similar TODO above", "") |
| self.TestLint( |
| r'EXPECT_EQ("\\", ' |
| r'NormalizePath("/./../foo///bar/..//x/../..", ""));', |
| "", |
| ) |
| |
| def testTwoSpacesBetweenCodeAndComments(self): |
| self.TestLint( |
| "} // namespace foo", |
| "At least two spaces is best between code and comments [whitespace/comments] [2]", |
| ) |
| self.TestLint( |
| "}// namespace foo", |
| "At least two spaces is best between code and comments [whitespace/comments] [2]", |
| ) |
| self.TestLint( |
| 'printf("foo"); // Outside quotes.', |
| "At least two spaces is best between code and comments [whitespace/comments] [2]", |
| ) |
| self.TestLint("int i = 0; // Having two spaces is fine.", "") |
| self.TestLint("int i = 0; // Having three spaces is OK.", "") |
| self.TestLint("// Top level comment", "") |
| self.TestLint(" // Line starts with two spaces.", "") |
| self.TestMultiLineLint("void foo() {\n { // A scope is opening.\n int a;", "") |
| self.TestMultiLineLint( |
| "void foo() {\n { // A scope is opening.\n#define A a", |
| "At least two spaces is best between code and comments [whitespace/comments] [2]", |
| ) |
| self.TestMultiLineLint(" foo();\n { // An indented scope is opening.\n int a;", "") |
| self.TestMultiLineLint( |
| "vector<int> my_elements = {// first\n 1,", "" |
| ) |
| self.TestMultiLineLint( |
| "vector<int> my_elements = {// my_elements is ..\n 1,", |
| "At least two spaces is best between code and comments [whitespace/comments] [2]", |
| ) |
| self.TestLint( |
| "if (foo) { // not a pure scope; comment is too close!", |
| "At least two spaces is best between code and comments [whitespace/comments] [2]", |
| ) |
| self.TestLint('printf("// In quotes.")', "") |
| self.TestLint('printf("\\"%s // In quotes.")', "") |
| self.TestLint('printf("%s", "// In quotes.")', "") |
| |
| def testSpaceAfterCommentMarker(self): |
| self.TestLint("//", "") |
| self.TestLint( |
| "//x", "Should have a space between // and comment [whitespace/comments] [4]" |
| ) |
| self.TestLint("// x", "") |
| self.TestLint("///", "") |
| self.TestLint("/// x", "") |
| self.TestLint("//!", "") |
| self.TestLint("//----", "") |
| self.TestLint("//====", "") |
| self.TestLint("//////", "") |
| self.TestLint("////// x", "") |
| self.TestLint("///< x", "") # After-member Doxygen comment |
| self.TestLint("//!< x", "") # After-member Doxygen comment |
| self.TestLint( |
| "////x", "Should have a space between // and comment [whitespace/comments] [4]" |
| ) |
| self.TestLint("//}", "") |
| self.TestLint( |
| "//}x", "Should have a space between // and comment [whitespace/comments] [4]" |
| ) |
| self.TestLint( |
| "//!<x", "Should have a space between // and comment [whitespace/comments] [4]" |
| ) |
| self.TestLint( |
| "///<x", "Should have a space between // and comment [whitespace/comments] [4]" |
| ) |
| |
| # Test a line preceded by empty or comment lines. There was a bug |
| # that caused it to print the same warning N times if the erroneous |
| # line was preceded by N lines of empty or comment lines. To be |
| # precise, the '// marker so line numbers and indices both start at |
| # 1' line was also causing the issue. |
| def testLinePrecededByEmptyOrCommentLines(self): |
| def DoTest(self, lines): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData("foo.cc", "cc", lines, error_collector) |
| # The warning appears only once. |
| assert ( |
| error_collector.Results().count( |
| "Do not use namespace using-directives. Use using-declarations instead. " |
| "[build/namespaces] [5]" |
| ) |
| == 1 |
| ) |
| |
| DoTest(self, ["using namespace foo;"]) |
| DoTest(self, ["", "", "", "using namespace foo;"]) |
| DoTest(self, ["// hello", "using namespace foo;"]) |
| |
| def testUsingLiteralsNamespaces(self): |
| self.TestLint( |
| "using namespace std::literals;", |
| "Do not use namespace" |
| " using-directives. Use using-declarations instead." |
| " [build/namespaces_literals] [5]", |
| ) |
| self.TestLint( |
| "using namespace std::literals::chrono_literals;", |
| "Do" |
| " not use namespace using-directives. Use using-declarations instead." |
| " [build/namespaces_literals] [5]", |
| ) |
| |
| def testNewlineAtEOF(self): |
| def DoTest(self, data, is_missing_eof): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData("foo.cc", "cc", data.split("\n"), error_collector) |
| # The warning appears only once. |
| assert int(is_missing_eof) == error_collector.Results().count( |
| "Could not find a newline character at the end of the file. " |
| "[whitespace/ending_newline] [5]" |
| ) |
| |
| DoTest(self, "// Newline\n// at EOF\n", False) |
| DoTest(self, "// No newline\n// at EOF", True) |
| |
| def testInvalidUtf8(self): |
| def DoTest(self, raw_bytes, has_invalid_utf8): |
| error_collector = ErrorCollector(self.assertTrue) |
| unidata = str(raw_bytes, "utf8", "replace").split("\n") |
| cpplint.ProcessFileData("foo.cc", "cc", unidata, error_collector) |
| # The warning appears only once. |
| assert int(has_invalid_utf8) == error_collector.Results().count( |
| "Line contains invalid UTF-8 (or Unicode replacement character). " |
| "[readability/utf8] [5]" |
| ) |
| |
| DoTest(self, codecs_latin_encode("Hello world\n"), False) |
| DoTest(self, codecs_latin_encode("\xe9\x8e\xbd\n"), False) |
| DoTest(self, codecs_latin_encode("\xe9x\x8e\xbd\n"), True) |
| # This is the encoding of the replacement character itself (which |
| # you can see by evaluating codecs.getencoder('utf8')(u'\ufffd')). |
| DoTest(self, codecs_latin_encode("\xef\xbf\xbd\n"), True) |
| |
| def testBadCharacters(self): |
| # Test for NUL bytes only |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "nul_input.cc", "cc", ["// Copyright 2014 Your Company.", "\0", ""], error_collector |
| ) |
| assert error_collector.Results() == "Line contains NUL byte. [readability/nul] [5]" |
| |
| # Make sure both NUL bytes and UTF-8 are caught if they appear on |
| # the same line. |
| error_collector = ErrorCollector(self.assertTrue) |
| raw_bytes = codecs_latin_encode("\xe9x\0") |
| unidata = str(raw_bytes, "utf8", "replace") |
| cpplint.ProcessFileData( |
| "nul_utf8.cc", "cc", ["// Copyright 2014 Your Company.", unidata, ""], error_collector |
| ) |
| assert error_collector.Results() == [ |
| "Line contains invalid UTF-8 (or Unicode replacement character). " |
| "[readability/utf8] [5]", |
| "Line contains NUL byte. [readability/nul] [5]", |
| ] |
| |
| def testIsBlankLine(self): |
| assert cpplint.IsBlankLine("") |
| assert cpplint.IsBlankLine(" ") |
| assert cpplint.IsBlankLine(" \t\r\n") |
| assert not cpplint.IsBlankLine("int a;") |
| assert not cpplint.IsBlankLine("{") |
| |
| def testBlankLinesCheck(self): |
| self.TestBlankLinesCheck(["{\n", "\n", "\n", "}\n"], 1, 1) |
| self.TestBlankLinesCheck([" if (foo) {\n", "\n", " }\n"], 1, 1) |
| self.TestBlankLinesCheck(["\n", "// {\n", "\n", "\n", "// Comment\n", "{\n", "}\n"], 0, 0) |
| self.TestBlankLinesCheck(["\n", 'run("{");\n', "\n"], 0, 0) |
| self.TestBlankLinesCheck(["\n", " if (foo) { return 0; }\n", "\n"], 0, 0) |
| self.TestBlankLinesCheck(["int x(\n", " int a) {\n", "\n", "return 0;\n", "}"], 0, 0) |
| self.TestBlankLinesCheck( |
| ["int x(\n", " int a) const {\n", "\n", "return 0;\n", "}"], 0, 0 |
| ) |
| self.TestBlankLinesCheck(["int x(\n", " int a) {\n", "\n", "return 0;\n", "}"], 1, 0) |
| self.TestBlankLinesCheck(["int x(\n", " int a) {\n", "\n", "return 0;\n", "}"], 1, 0) |
| |
| def testAllowBlankLineBeforeClosingNamespace(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "namespace {", |
| "", |
| "} // namespace", |
| "namespace another_namespace {", |
| "", |
| "}", |
| "namespace {", |
| "", |
| "template<class T, ", |
| " class A = hoge<T>, ", |
| " class B = piyo<T>, ", |
| " class C = fuga<T> >", |
| "class D {", |
| " public:", |
| "};", |
| "", |
| "", |
| "", |
| "", |
| "}", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results().count( |
| "Redundant blank line at the end of a code block should be deleted. " |
| "[whitespace/blank_line] [3]" |
| ) |
| == 0 |
| ) |
| |
| def testAllowBlankLineBeforeIfElseChain(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "if (hoge) {", |
| "", # No warning |
| "} else if (piyo) {", |
| "", # No warning |
| "} else if (piyopiyo) {", |
| " hoge = true;", # No warning |
| "} else {", |
| "", # Warning on this line |
| "}", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results().count( |
| "Redundant blank line at the end of a code block should be deleted. " |
| "[whitespace/blank_line] [3]" |
| ) |
| == 1 |
| ) |
| |
| def testAllowBlankLineAfterExtern(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| ['extern "C" {', "", "EXPORTAPI void APICALL Some_function() {}", "", "}"], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results().count( |
| "Redundant blank line at the start of a code block should be deleted. " |
| "[whitespace/blank_line] [2]" |
| ) |
| == 0 |
| ) |
| assert ( |
| error_collector.Results().count( |
| "Redundant blank line at the end of a code block should be deleted. " |
| "[whitespace/blank_line] [3]" |
| ) |
| == 0 |
| ) |
| |
| def testBlankLineBeforeSectionKeyword(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "class A {", |
| " public:", |
| " protected:", # warning 1 |
| " private:", # warning 2 |
| " struct B {", |
| " public:", |
| " private:", |
| ] # warning 3 |
| + ([""] * 100) # Make A and B longer than 100 lines |
| + [ |
| " };", |
| " struct C {", |
| " protected:", |
| " private:", # C is too short for warnings |
| " };", |
| "};", |
| "class D", |
| " : public {", |
| " public:", # no warning |
| "};", |
| "class E {\\", |
| " public:\\", |
| ] |
| + (["\\"] * 100) # Makes E > 100 lines |
| + [ |
| " int non_empty_line;\\", |
| " private:\\", # no warning |
| " int a;\\", |
| "};", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results().count( |
| '"private:" should be preceded by a blank line [whitespace/blank_line] [3]' |
| ) |
| == 2 |
| ) |
| assert ( |
| error_collector.Results().count( |
| '"protected:" should be preceded by a blank line [whitespace/blank_line] [3]' |
| ) |
| == 1 |
| ) |
| |
| def testNoBlankLineAfterSectionKeyword(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "class A {", |
| " public:", |
| "", # warning 1 |
| " private:", |
| "", # warning 2 |
| " struct B {", |
| " protected:", |
| "", # warning 3 |
| " };", |
| "};", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results().count( |
| 'Do not leave a blank line after "public:" [whitespace/blank_line] [3]' |
| ) |
| == 1 |
| ) |
| assert ( |
| error_collector.Results().count( |
| 'Do not leave a blank line after "protected:" [whitespace/blank_line] [3]' |
| ) |
| == 1 |
| ) |
| assert ( |
| error_collector.Results().count( |
| 'Do not leave a blank line after "private:" [whitespace/blank_line] [3]' |
| ) |
| == 1 |
| ) |
| |
| def testAllowBlankLinesInRawStrings(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| 'static const char *kData[] = {R"(', |
| "", |
| ')", R"(', |
| "", |
| ')"};', |
| "", |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == "" |
| |
| def testElseOnSameLineAsClosingBraces(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "if (hoge) {", |
| "}", |
| "else if (piyo) {", # Warning on this line |
| "}", |
| " else {" # Warning on this line |
| "", |
| "}", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results().count( |
| "An else should appear on the same line as the preceding } " |
| "[whitespace/newline] [4]" |
| ) |
| == 2 |
| ) |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "if (hoge) {", |
| "", |
| "}", |
| "else", # Warning on this line |
| "{", |
| "", |
| "}", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results().count( |
| "An else should appear on the same line as the preceding } " |
| "[whitespace/newline] [4]" |
| ) |
| == 1 |
| ) |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", "cc", ["if (hoge) {", "", "}", "else_function();"], error_collector |
| ) |
| assert ( |
| error_collector.Results().count( |
| "An else should appear on the same line as the preceding } " |
| "[whitespace/newline] [4]" |
| ) |
| == 0 |
| ) |
| |
| def testMultipleStatementsOnSameLine(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "for (int i = 0; i < 1; i++) {}", |
| "switch (x) {", |
| " case 0: func(); break; ", |
| "}", |
| "sum += MathUtil::SafeIntRound(x); x += 0.1;", |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results().count( |
| "More than one command on the same line [whitespace/newline] [0]" |
| ) |
| == 0 |
| ) |
| |
| old_verbose_level = cpplint._cpplint_state.verbose_level |
| cpplint._cpplint_state.verbose_level = 0 |
| cpplint.ProcessFileData( |
| "foo.cc", "cc", ["sum += MathUtil::SafeIntRound(x); x += 0.1;"], error_collector |
| ) |
| cpplint._cpplint_state.verbose_level = old_verbose_level |
| |
| def testLambdasOnSameLine(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| old_verbose_level = cpplint._cpplint_state.verbose_level |
| cpplint._cpplint_state.verbose_level = 0 |
| cpplint.ProcessFileData( |
| "foo.cc", "cc", ["const auto lambda = [](const int i) { return i; };"], error_collector |
| ) |
| cpplint._cpplint_state.verbose_level = old_verbose_level |
| assert ( |
| error_collector.Results().count( |
| "More than one command on the same line [whitespace/newline] [0]" |
| ) |
| == 0 |
| ) |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| old_verbose_level = cpplint._cpplint_state.verbose_level |
| cpplint._cpplint_state.verbose_level = 0 |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "const auto result = std::any_of(vector.begin(), " |
| "vector.end(), " |
| "[](const int i) { return i > 0; });" |
| ], |
| error_collector, |
| ) |
| cpplint._cpplint_state.verbose_level = old_verbose_level |
| assert ( |
| error_collector.Results().count( |
| "More than one command on the same line [whitespace/newline] [0]" |
| ) |
| == 0 |
| ) |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| old_verbose_level = cpplint._cpplint_state.verbose_level |
| cpplint._cpplint_state.verbose_level = 0 |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "return mutex::Lock<void>([this]() { " |
| "this->ReadLock(); }, [this]() { " |
| "this->ReadUnlock(); });" |
| ], |
| error_collector, |
| ) |
| cpplint._cpplint_state.verbose_level = old_verbose_level |
| assert ( |
| error_collector.Results().count( |
| "More than one command on the same line [whitespace/newline] [0]" |
| ) |
| == 0 |
| ) |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| old_verbose_level = cpplint._cpplint_state.verbose_level |
| cpplint._cpplint_state.verbose_level = 0 |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "return mutex::Lock<void>([this]() { " |
| "this->ReadLock(); }, [this]() { " |
| "this->ReadUnlock(); }, object);" |
| ], |
| error_collector, |
| ) |
| cpplint._cpplint_state.verbose_level = old_verbose_level |
| assert ( |
| error_collector.Results().count( |
| "More than one command on the same line [whitespace/newline] [0]" |
| ) |
| == 0 |
| ) |
| |
| def testEndOfNamespaceComments(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "namespace {", |
| "", |
| "}", # No warning (too short) |
| "namespace expected {", |
| "} // namespace mismatched", # Warning here |
| "namespace {", |
| "} // namespace mismatched", # Warning here |
| "namespace outer { namespace nested {", |
| ] |
| + ([""] * 10) |
| + [ |
| "}", # Warning here |
| "}", # Warning here |
| "namespace {", |
| ] |
| + ([""] * 10) |
| + [ |
| "}", # Warning here |
| "namespace {", |
| ] |
| + ([""] * 10) |
| + [ |
| "} // namespace some description", # Anon warning |
| "namespace {", |
| ] |
| + ([""] * 10) |
| + [ |
| "} // namespace anonymous", # Variant warning |
| "namespace {", |
| ] |
| + ([""] * 10) |
| + [ |
| "} // anonymous namespace (utils)", # Variant |
| "namespace {", |
| ] |
| + ([""] * 10) |
| + [ |
| "} // anonymous namespace", # No warning |
| "namespace missing_comment {", |
| ] |
| + ([""] * 10) |
| + [ |
| "}", # Warning here |
| "namespace no_warning {", |
| ] |
| + ([""] * 10) |
| + ["} // namespace no_warning", "namespace no_warning {"] |
| + ([""] * 10) |
| + ["}; // end namespace no_warning", "#define MACRO \\", "namespace c_style { \\"] |
| + (["\\"] * 10) |
| + ["} /* namespace c_style. */ \\", ";"], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results().count( |
| 'Namespace should be terminated with "// namespace expected"' |
| " [readability/namespace] [5]" |
| ) |
| == 1 |
| ) |
| assert ( |
| error_collector.Results().count( |
| 'Namespace should be terminated with "// namespace outer"' |
| " [readability/namespace] [5]" |
| ) |
| == 1 |
| ) |
| assert ( |
| error_collector.Results().count( |
| 'Namespace should be terminated with "// namespace nested"' |
| " [readability/namespace] [5]" |
| ) |
| == 1 |
| ) |
| assert ( |
| error_collector.Results().count( |
| 'Anonymous namespace should be terminated with "// namespace"' |
| " [readability/namespace] [5]" |
| ) |
| == 3 |
| ) |
| assert ( |
| error_collector.Results().count( |
| 'Anonymous namespace should be terminated with "// namespace" or ' |
| '"// anonymous namespace" [readability/namespace] [5]"' |
| ) |
| == 0 # 2 |
| ) |
| assert ( |
| error_collector.Results().count( |
| 'Namespace should be terminated with "// namespace missing_comment"' |
| " [readability/namespace] [5]" |
| ) |
| == 1 |
| ) |
| assert ( |
| error_collector.Results().count( |
| 'Namespace should be terminated with "// namespace no_warning"' |
| " [readability/namespace] [5]" |
| ) |
| == 0 |
| ) |
| |
| def testComma(self): |
| self.TestLint("a = f(1,2);", "Missing space after , [whitespace/comma] [3]") |
| self.TestLint( |
| "int tmp=a,a=b,b=tmp;", |
| [ |
| "Missing spaces around = [whitespace/operators] [4]", |
| "Missing space after , [whitespace/comma] [3]", |
| ], |
| ) |
| self.TestLint("f(a, /* name */ b);", "") |
| self.TestLint("f(a, /* name */b);", "") |
| self.TestLint("f(a, /* name */-1);", "") |
| self.TestLint('f(a, /* name */"1");', "") |
| self.TestLint("f(1, /* empty macro arg */, 2)", "") |
| self.TestLint("f(1,, 2)", "") |
| self.TestLint("operator,()", "") |
| self.TestLint("operator,(a,b)", "Missing space after , [whitespace/comma] [3]") |
| self.TestLint("__VA_OPT__(,)", "") |
| self.TestLint( |
| "__VA_OPT__ (,)", "Extra space before ( in function call [whitespace/parens] [4]" |
| ) |
| |
| def testEqualsOperatorSpacing(self): |
| self.TestLint("int tmp= a;", "Missing spaces around = [whitespace/operators] [4]") |
| self.TestLint("int tmp =a;", "Missing spaces around = [whitespace/operators] [4]") |
| self.TestLint("int tmp=a;", "Missing spaces around = [whitespace/operators] [4]") |
| self.TestLint("int tmp= 7;", "Missing spaces around = [whitespace/operators] [4]") |
| self.TestLint("int tmp =7;", "Missing spaces around = [whitespace/operators] [4]") |
| self.TestLint("int tmp=7;", "Missing spaces around = [whitespace/operators] [4]") |
| self.TestLint("int* tmp=*p;", "Missing spaces around = [whitespace/operators] [4]") |
| self.TestLint("int* tmp= *p;", "Missing spaces around = [whitespace/operators] [4]") |
| self.TestMultiLineLint( |
| TrimExtraIndent(""" |
| lookahead_services_= |
| ::strings::Split(FLAGS_ls, ",", ::strings::SkipEmpty());"""), |
| "Missing spaces around = [whitespace/operators] [4]", |
| ) |
| self.TestLint( |
| "bool result = a>=42;", "Missing spaces around >= [whitespace/operators] [3]" |
| ) |
| self.TestLint( |
| "bool result = a<=42;", "Missing spaces around <= [whitespace/operators] [3]" |
| ) |
| self.TestLint( |
| "bool result = a==42;", "Missing spaces around == [whitespace/operators] [3]" |
| ) |
| self.TestLint( |
| "auto result = a!=42;", "Missing spaces around != [whitespace/operators] [3]" |
| ) |
| self.TestLint("int a = b!=c;", "Missing spaces around != [whitespace/operators] [3]") |
| self.TestLint("a&=42;", "") |
| self.TestLint("a|=42;", "") |
| self.TestLint("a^=42;", "") |
| self.TestLint("a+=42;", "") |
| self.TestLint("a*=42;", "") |
| self.TestLint("a/=42;", "") |
| self.TestLint("a%=42;", "") |
| self.TestLint("a>>=5;", "") |
| self.TestLint("a<<=5;", "") |
| |
| def testShiftOperatorSpacing(self): |
| self.TestLint("a<<b", "Missing spaces around << [whitespace/operators] [3]") |
| self.TestLint("a>>b", "Missing spaces around >> [whitespace/operators] [3]") |
| self.TestLint("1<<20", "") |
| self.TestLint("1024>>10", "") |
| self.TestLint("Kernel<<<1, 2>>>()", "") |
| |
| def testIndent(self): |
| self.TestLint("static int noindent;", "") |
| self.TestLint(" int two_space_indent;", "") |
| self.TestLint(" int four_space_indent;", "") |
| self.TestLint( |
| " int one_space_indent;", |
| "Weird number of spaces at line-start. " |
| "Are you using a 2-space indent? [whitespace/indent] [3]", |
| ) |
| self.TestLint( |
| " int three_space_indent;", |
| "Weird number of spaces at line-start. " |
| "Are you using a 2-space indent? [whitespace/indent] [3]", |
| ) |
| self.TestLint( |
| ' char* one_space_indent = "public:";', |
| "Weird number of spaces at line-start. " |
| "Are you using a 2-space indent? [whitespace/indent] [3]", |
| ) |
| self.TestLint(" public:", "") |
| self.TestLint(" protected:", "") |
| self.TestLint(" private:", "") |
| self.TestLint(" protected: \\", "") |
| self.TestLint(" public: \\", "") |
| self.TestLint(" private: \\", "") |
| # examples using QT signals/slots macro |
| self.TestMultiLineLint( |
| TrimExtraIndent(""" |
| class foo { |
| public slots: |
| void bar(); |
| signals: |
| };"""), |
| "", |
| ) |
| self.TestMultiLineLint( |
| TrimExtraIndent(""" |
| class foo { |
| public slots: |
| void bar(); |
| };"""), |
| "public slots: should be indented +1 space inside class foo [whitespace/indent] [3]", |
| ) |
| self.TestMultiLineLint( |
| TrimExtraIndent(""" |
| class foo { |
| signals: |
| void bar(); |
| };"""), |
| "signals: should be indented +1 space inside class foo [whitespace/indent] [3]", |
| ) |
| self.TestMultiLineLint( |
| TrimExtraIndent(""" |
| static const char kRawString[] = R"(" |
| ")";"""), |
| "", |
| ) |
| self.TestMultiLineLint( |
| TrimExtraIndent(""" |
| KV<Query, |
| Tuple<TaxonomyId, PetacatCategoryId, double>>"""), |
| "", |
| ) |
| self.TestMultiLineLint( |
| ' static const char kSingleLineRawString[] = R"(...)";', |
| "Weird number of spaces at line-start. " |
| "Are you using a 2-space indent? [whitespace/indent] [3]", |
| ) |
| |
| def testSectionIndent(self): |
| self.TestMultiLineLint( |
| """ |
| class A { |
| public: // no warning |
| private: // warning here |
| };""", |
| "private: should be indented +1 space inside class A [whitespace/indent] [3]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| class B { |
| public: // no warning |
| template<> struct C { |
| public: // warning here |
| protected: // no warning |
| }; |
| };""", |
| "public: should be indented +1 space inside struct C [whitespace/indent] [3]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| struct D { |
| };""", |
| "Closing brace should be aligned with beginning of struct D [whitespace/indent] [3]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| template<typename E> class F { |
| };""", |
| "Closing brace should be aligned with beginning of class F [whitespace/indent] [3]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| class G { |
| Q_OBJECT |
| public slots: |
| signals: |
| };""", |
| [ |
| "public slots: should be indented +1 space inside class G [whitespace/indent] [3]", |
| "signals: should be indented +1 space inside class G [whitespace/indent] [3]", |
| ], |
| ) |
| self.TestMultiLineLint( |
| """ |
| class H { |
| /* comments */ class I { |
| public: // no warning |
| private: // warning here |
| }; |
| };""", |
| "private: should be indented +1 space inside class I [whitespace/indent] [3]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| class J |
| : public ::K { |
| public: // no warning |
| protected: // warning here |
| };""", |
| "protected: should be indented +1 space inside class J [whitespace/indent] [3]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| class L |
| : public M, |
| public ::N { |
| };""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| template <class O, |
| class P, |
| class Q, |
| typename R> |
| static void Func() { |
| }""", |
| "", |
| ) |
| |
| def testConditionals(self): |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| goto fail; |
| goto fail;""", |
| "If/else bodies with multiple statements require braces [readability/braces] [4]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| goto fail; goto fail;""", |
| "If/else bodies with multiple statements require braces [readability/braces] [4]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| foo; |
| else |
| goto fail; |
| goto fail;""", |
| "If/else bodies with multiple statements require braces [readability/braces] [4]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) goto fail; |
| goto fail;""", |
| "If/else bodies with multiple statements require braces [readability/braces] [4]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if constexpr (foo) { |
| goto fail; |
| goto fail; |
| } else if constexpr (bar) { |
| hello(); |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| if (bar) |
| baz; |
| else |
| qux;""", |
| "Else clause should be indented at the same level as if. Ambiguous" |
| " nested if/else chains require braces. [readability/braces] [4]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| if (bar) |
| baz; |
| else |
| qux;""", |
| "Else clause should be indented at the same level as if. Ambiguous" |
| " nested if/else chains require braces. [readability/braces] [4]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) { |
| bar; |
| baz; |
| } else |
| qux;""", |
| "If an else has a brace on one side, it should have it on both" |
| " [readability/braces] [5]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| bar; |
| else { |
| baz; |
| }""", |
| "If an else has a brace on one side, it should have it on both" |
| " [readability/braces] [5]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| bar; |
| else if (baz) { |
| qux; |
| }""", |
| "If an else has a brace on one side, it should have it on both" |
| " [readability/braces] [5]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) { |
| bar; |
| } else if (baz) |
| qux;""", |
| "If an else has a brace on one side, it should have it on both" |
| " [readability/braces] [5]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| goto fail; |
| bar;""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo |
| && bar) { |
| baz; |
| qux; |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| goto |
| fail;""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| bar; |
| else |
| baz; |
| qux;""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| for (;;) { |
| if (foo) |
| bar; |
| else |
| baz; |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| bar; |
| else if (baz) |
| baz;""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| bar; |
| else |
| baz;""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) { |
| bar; |
| } else { |
| baz; |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| if (foo) { |
| bar; |
| } else if (baz) { |
| qux; |
| }""", |
| "", |
| ) |
| # Note: this is an error for a different reason, but should not trigger the |
| # single-line if error. |
| self.TestMultiLineLint( |
| """ |
| if (foo) |
| { |
| bar; |
| baz; |
| }""", |
| "{ should almost always be at the end of the previous line [whitespace/braces] [4]", |
| ) |
| self.TestMultiLineLint( |
| """ |
| void foo() { if (bar) baz; }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| #if foo |
| bar; |
| #else |
| baz; |
| qux; |
| #endif""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """void F() { |
| variable = [] { if (true); }; |
| variable = |
| [] { if (true); }; |
| Call( |
| [] { if (true); }, |
| [] { if (true); }); |
| }""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| #if(A == 0) |
| foo(); |
| #elif(A == 1) |
| bar(); |
| #endif""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| #if (A == 0) |
| foo(); |
| #elif (A == 1) |
| bar(); |
| #endif""", |
| "", |
| ) |
| |
| @pytest.mark.parametrize("keyword", ["else if", "if", "while", "for", "switch"]) |
| def testControlClauseWithParensNewline(self, keyword): |
| # The % 2 part is pseudorandom whitespace-support testing |
| self.TestLintContains( |
| f"{keyword}{['', ' '][len(keyword) % 2]}(condition)" |
| f"{[' ', ''][len(keyword) % 2]}[[unlikely]]" |
| f"{[' ', ''][len(keyword) % 2]}{{" |
| f"{['', ' '][len(keyword) % 2]}do_something(); }}", |
| f"Controlled statements inside brackets of {keyword} clause" |
| f" should be on a separate line [whitespace/newline] [5]", |
| ) |
| |
| @pytest.mark.parametrize("keyword", ["else", "do", "try"]) |
| def testControlClauseWithoutParensNewline(self, keyword): |
| # The % 2 part is pseudorandom whitespace-support testing |
| self.TestLintContains( |
| f"{keyword}{['', ' '][len(keyword) % 2]}{{" |
| f"{[' ', ''][len(keyword) % 2]}do_something(); }}", |
| f"Controlled statements inside brackets of {keyword} clause" |
| f" should be on a separate line [whitespace/newline] [5]", |
| ) |
| |
| def testControlClauseNewlineNameFalsePositives(self): |
| self.TestLint(" else if_condition_do_something();", "") |
| self.TestLint(" } else if (blah) {", "") |
| self.TestLint(" variable_ends_in_else = true;", "") |
| |
| def testTab(self): |
| self.TestLint("\tint a;", "Tab found; better to use spaces [whitespace/tab] [1]") |
| self.TestLint( |
| "int a = 5;\t\t// set a to 5", "Tab found; better to use spaces [whitespace/tab] [1]" |
| ) |
| |
| def testParseArguments(self): |
| old_output_format = cpplint._cpplint_state.output_format |
| old_verbose_level = cpplint._cpplint_state.verbose_level |
| old_headers = cpplint._hpp_headers |
| old_filters = cpplint._cpplint_state.filters |
| old_line_length = cpplint._line_length |
| old_valid_extensions = cpplint._valid_extensions |
| try: |
| # Don't print usage during the tests, or filter categories |
| sys.stdout = open(os.devnull, "w") |
| sys.stderr = open(os.devnull, "w") |
| |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments([]) |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments(["--badopt"]) |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments(["--help"]) |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments(["--version"]) |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments(["--v=0"]) |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments(["--filter="]) |
| # This is illegal because all filters must start with + or - |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments(["--filter=foo"]) |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments(["--filter=+a,b,-c"]) |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments(["--linelength=0"]) |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments(["--headers"]) |
| |
| assert cpplint.ParseArguments(["foo.cc"]) == ["foo.cc"] |
| assert old_output_format == cpplint._cpplint_state.output_format |
| assert old_verbose_level == cpplint._cpplint_state.verbose_level |
| |
| assert cpplint.ParseArguments(["--v=1", "foo.cc"]) == ["foo.cc"] |
| assert cpplint._cpplint_state.verbose_level == 1 |
| assert cpplint.ParseArguments(["--v=3", "foo.h"]) == ["foo.h"] |
| assert cpplint._cpplint_state.verbose_level == 3 |
| assert cpplint.ParseArguments(["--verbose=5", "foo.cpp"]) == ["foo.cpp"] |
| assert cpplint._cpplint_state.verbose_level == 5 |
| with pytest.raises( |
| ValueError, match=re.escape("invalid literal for int() with base 10: 'f'") |
| ): |
| cpplint.ParseArguments(["--v=f", "foo.cc"]) |
| |
| assert cpplint.ParseArguments(["--output=emacs", "foo.cc"]) == ["foo.cc"] |
| assert cpplint._cpplint_state.output_format == "emacs" |
| assert cpplint.ParseArguments(["--output=vs7", "foo.h"]) == ["foo.h"] |
| assert cpplint._cpplint_state.output_format == "vs7" |
| with pytest.raises(SystemExit): |
| cpplint.ParseArguments(["--output=blah", "foo.cc"]) |
| |
| filt = "-,+whitespace,-whitespace/indent" |
| assert cpplint.ParseArguments(["--filter=" + filt, "foo.h"]) == ["foo.h"] |
| assert cpplint._cpplint_state.filters == ["-", "+whitespace", "-whitespace/indent"] |
| |
| assert cpplint.ParseArguments(["foo.cc", "foo.h"]) == ["foo.cc", "foo.h"] |
| |
| cpplint._hpp_headers = old_headers |
| cpplint._valid_extensions = old_valid_extensions |
| assert cpplint.ParseArguments(["--linelength=120", "foo.h"]) == ["foo.h"] |
| assert cpplint._line_length == 120 |
| assert { |
| "h", |
| "hh", |
| "hpp", |
| "hxx", |
| "h++", |
| "cuh", |
| } == cpplint.GetHeaderExtensions() # Default value |
| |
| cpplint._hpp_headers = old_headers |
| cpplint._valid_extensions = old_valid_extensions |
| assert cpplint.ParseArguments(["--headers=h", "foo.h"]) == ["foo.h"] |
| assert {"h", "c", "cc", "cpp", "cxx", "c++", "cu"} == cpplint.GetAllExtensions() |
| |
| cpplint._hpp_headers = old_headers |
| cpplint._valid_extensions = old_valid_extensions |
| assert cpplint.ParseArguments(["--extensions=hpp,cpp,cpp", "foo.h"]) == ["foo.h"] |
| assert {"hpp", "cpp"} == cpplint.GetAllExtensions() |
| assert {"hpp"} == cpplint.GetHeaderExtensions() |
| |
| cpplint._hpp_headers = old_headers |
| cpplint._valid_extensions = old_valid_extensions |
| assert cpplint.ParseArguments(["--extensions=cpp,cpp", "--headers=hpp,h", "foo.h"]) == [ |
| "foo.h" |
| ] |
| assert {"hpp", "h"} == cpplint.GetHeaderExtensions() |
| assert {"hpp", "h", "cpp"} == cpplint.GetAllExtensions() |
| |
| finally: |
| sys.stdout = sys.__stdout__ |
| sys.stderr = sys.__stderr__ |
| cpplint._cpplint_state.output_format = old_output_format |
| cpplint._cpplint_state.verbose_level = old_verbose_level |
| cpplint._cpplint_state.filters = old_filters |
| cpplint._line_length = old_line_length |
| cpplint._valid_extensions = old_valid_extensions |
| cpplint._hpp_headers = old_headers |
| |
| def testRecursiveArgument(self): |
| working_dir = os.getcwd() |
| temp_dir = os.path.realpath(tempfile.mkdtemp()) |
| try: |
| src_dir = os.path.join(temp_dir, "src") |
| nested_dir = os.path.join(temp_dir, "src", "nested") |
| os.makedirs(nested_dir) |
| open(os.path.join(temp_dir, "one.cpp"), "w").close() |
| open(os.path.join(src_dir, "two.cpp"), "w").close() |
| open(os.path.join(nested_dir, "three.cpp"), "w").close() |
| os.chdir(temp_dir) |
| expected = [ |
| "one.cpp", |
| os.path.join("src", "two.cpp"), |
| os.path.join("src", "nested", "three.cpp"), |
| ] |
| cpplint._excludes = None |
| actual = cpplint.ParseArguments(["--recursive", "one.cpp", "src"]) |
| assert set(expected) == set(actual) |
| finally: |
| os.chdir(working_dir) |
| shutil.rmtree(temp_dir) |
| |
| def testRecursiveExcludeInvalidFileExtension(self): |
| working_dir = os.getcwd() |
| temp_dir = os.path.realpath(tempfile.mkdtemp()) |
| try: |
| src_dir = os.path.join(temp_dir, "src") |
| os.makedirs(src_dir) |
| open(os.path.join(temp_dir, "one.cpp"), "w").close() |
| open(os.path.join(src_dir, "two.cpp"), "w").close() |
| open(os.path.join(src_dir, "three.cc"), "w").close() |
| os.chdir(temp_dir) |
| expected = ["one.cpp", os.path.join("src", "two.cpp")] |
| cpplint._excludes = None |
| actual = cpplint.ParseArguments(["--recursive", "--extensions=cpp", "one.cpp", "src"]) |
| assert set(expected) == set(actual) |
| finally: |
| os.chdir(working_dir) |
| shutil.rmtree(temp_dir) |
| cpplint._hpp_headers = set() |
| cpplint._valid_extensions = set() |
| |
| def testRecursiveExclude(self): |
| working_dir = os.getcwd() |
| temp_dir = os.path.realpath(tempfile.mkdtemp()) |
| try: |
| src_dir = os.path.join(temp_dir, "src") |
| src2_dir = os.path.join(temp_dir, "src2") |
| os.makedirs(src_dir) |
| os.makedirs(src2_dir) |
| open(os.path.join(src_dir, "one.cc"), "w").close() |
| open(os.path.join(src_dir, "two.cc"), "w").close() |
| open(os.path.join(src_dir, "three.cc"), "w").close() |
| open(os.path.join(src2_dir, "one.cc"), "w").close() |
| open(os.path.join(src2_dir, "two.cc"), "w").close() |
| open(os.path.join(src2_dir, "three.cc"), "w").close() |
| os.chdir(temp_dir) |
| |
| expected = [ |
| os.path.join("src", "one.cc"), |
| os.path.join("src", "two.cc"), |
| os.path.join("src", "three.cc"), |
| ] |
| cpplint._excludes = None |
| actual = cpplint.ParseArguments(["src"]) |
| assert {"src"} == set(actual) |
| |
| cpplint._excludes = None |
| actual = cpplint.ParseArguments(["--recursive", "src"]) |
| assert set(expected) == set(actual) |
| |
| expected = [os.path.join("src", "one.cc")] |
| cpplint._excludes = None |
| actual = cpplint.ParseArguments(["--recursive", f"--exclude=src{os.sep}t*", "src"]) |
| assert set(expected) == set(actual) |
| |
| expected = [os.path.join("src", "one.cc")] |
| cpplint._excludes = None |
| actual = cpplint.ParseArguments( |
| ["--recursive", "--exclude=src/two.cc", "--exclude=src/three.cc", "src"] |
| ) |
| assert set(expected) == set(actual) |
| |
| expected = { |
| os.path.join("src2", "one.cc"), |
| os.path.join("src2", "two.cc"), |
| os.path.join("src2", "three.cc"), |
| } |
| cpplint._excludes = None |
| actual = cpplint.ParseArguments(["--recursive", "--exclude=src", "."]) |
| assert expected == set(actual) |
| finally: |
| os.chdir(working_dir) |
| shutil.rmtree(temp_dir) |
| |
| def testJUnitXML(self): |
| try: |
| cpplint._cpplint_state._junit_errors = [] |
| cpplint._cpplint_state._junit_failures = [] |
| expected = ( |
| '<?xml version="1.0" encoding="UTF-8" ?>\n' |
| '<testsuite errors="0" failures="0" name="cpplint" tests="1">' |
| '<testcase name="passed" />' |
| "</testsuite>" |
| ) |
| assert expected == cpplint._cpplint_state.FormatJUnitXML() |
| |
| cpplint._cpplint_state._junit_errors = ["ErrMsg1"] |
| cpplint._cpplint_state._junit_failures = [] |
| expected = ( |
| '<?xml version="1.0" encoding="UTF-8" ?>\n' |
| '<testsuite errors="1" failures="0" name="cpplint" tests="1">' |
| '<testcase name="errors"><error>ErrMsg1</error></testcase>' |
| "</testsuite>" |
| ) |
| assert expected == cpplint._cpplint_state.FormatJUnitXML() |
| |
| cpplint._cpplint_state._junit_errors = ["ErrMsg1", "ErrMsg2"] |
| cpplint._cpplint_state._junit_failures = [] |
| expected = ( |
| '<?xml version="1.0" encoding="UTF-8" ?>\n' |
| '<testsuite errors="2" failures="0" name="cpplint" tests="2">' |
| '<testcase name="errors"><error>ErrMsg1\nErrMsg2</error></testcase>' |
| "</testsuite>" |
| ) |
| assert expected == cpplint._cpplint_state.FormatJUnitXML() |
| |
| cpplint._cpplint_state._junit_errors = ["ErrMsg"] |
| cpplint._cpplint_state._junit_failures = [ |
| ("File", 5, "FailMsg", "category/subcategory", 3) |
| ] |
| expected = ( |
| '<?xml version="1.0" encoding="UTF-8" ?>\n' |
| '<testsuite errors="1" failures="1" name="cpplint" tests="2">' |
| '<testcase name="errors"><error>ErrMsg</error></testcase>' |
| '<testcase name="File"><failure>5: FailMsg [category/subcategory] ' |
| "[3]</failure></testcase></testsuite>" |
| ) |
| assert expected == cpplint._cpplint_state.FormatJUnitXML() |
| |
| cpplint._cpplint_state._junit_errors = [] |
| cpplint._cpplint_state._junit_failures = [ |
| ("File1", 5, "FailMsg1", "category/subcategory", 3), |
| ("File2", 99, "FailMsg2", "category/subcategory", 3), |
| ("File1", 19, "FailMsg3", "category/subcategory", 3), |
| ] |
| expected = ( |
| '<?xml version="1.0" encoding="UTF-8" ?>\n' |
| '<testsuite errors="0" failures="3" name="cpplint" tests="3">' |
| '<testcase name="File1"><failure>5: FailMsg1 [category/subcategory]' |
| " [3]\n19: FailMsg3 [category/subcategory] [3]</failure></testcase>" |
| '<testcase name="File2"><failure>99: FailMsg2 ' |
| "[category/subcategory] [3]</failure></testcase></testsuite>" |
| ) |
| assert expected == cpplint._cpplint_state.FormatJUnitXML() |
| |
| cpplint._cpplint_state._junit_errors = ["&</error>"] |
| cpplint._cpplint_state._junit_failures = [ |
| ("File1", 5, "&</failure>", "category/subcategory", 3) |
| ] |
| expected = ( |
| '<?xml version="1.0" encoding="UTF-8" ?>\n' |
| '<testsuite errors="1" failures="1" name="cpplint" tests="2">' |
| '<testcase name="errors"><error>&</error></error>' |
| '</testcase><testcase name="File1"><failure>5: ' |
| "&</failure> [category/subcategory] [3]</failure>" |
| "</testcase></testsuite>" |
| ) |
| assert expected == cpplint._cpplint_state.FormatJUnitXML() |
| |
| finally: |
| cpplint._cpplint_state._junit_errors = [] |
| cpplint._cpplint_state._junit_failures = [] |
| |
| def testQuiet(self): |
| assert cpplint._cpplint_state.quiet is False |
| cpplint.ParseArguments(["--quiet", "one.cpp"]) |
| assert cpplint._cpplint_state.quiet is True |
| |
| def testLineLength(self): |
| old_line_length = cpplint._line_length |
| try: |
| cpplint._line_length = 80 |
| self.TestLint("// H %s" % ("H" * 75), "") |
| self.TestLint( |
| "// H %s" % ("H" * 76), |
| "Lines should be <= 80 characters long [whitespace/line_length] [2]", |
| ) |
| cpplint._line_length = 120 |
| self.TestLint("// H %s" % ("H" * 115), "") |
| self.TestLint( |
| "// H %s" % ("H" * 116), |
| "Lines should be <= 120 characters long [whitespace/line_length] [2]", |
| ) |
| finally: |
| cpplint._line_length = old_line_length |
| |
| def testFilter(self): |
| old_filters = cpplint._cpplint_state.filters |
| try: |
| cpplint._cpplint_state.SetFilters("-,+whitespace,-whitespace/indent") |
| self.TestLint( |
| "// Hello there ", |
| "Line ends in whitespace. Consider deleting these extra spaces." |
| " [whitespace/end_of_line] [4]", |
| ) |
| self.TestLint("int a = (int)1.0;", "") |
| self.TestLint(" weird opening space", "") |
| finally: |
| cpplint._cpplint_state.filters = old_filters |
| |
| def testDefaultFilter(self): |
| default_filters = cpplint._DEFAULT_FILTERS |
| old_filters = cpplint._cpplint_state.filters |
| cpplint._DEFAULT_FILTERS = ["-whitespace"] |
| try: |
| # Reset filters |
| cpplint._cpplint_state.SetFilters("") |
| self.TestLint("// Hello there ", "") |
| cpplint._cpplint_state.SetFilters("+whitespace/end_of_line") |
| self.TestLint( |
| "// Hello there ", |
| "Line ends in whitespace. Consider deleting these extra spaces." |
| " [whitespace/end_of_line] [4]", |
| ) |
| self.TestLint(" weird opening space", "") |
| finally: |
| cpplint._cpplint_state.filters = old_filters |
| cpplint._DEFAULT_FILTERS = default_filters |
| |
| def testFileSpecificFilter(self): |
| old_filters = cpplint._cpplint_state.filters |
| try: |
| test_code = """ |
| class Foo { |
| Foo(int f) |
| { |
| } |
| };""" |
| cpplint._cpplint_state.SetFilters("") |
| self.TestMultiLineLint( |
| test_code, |
| [ |
| "Single-parameter constructors should be marked explicit." |
| " [runtime/explicit] [4]", |
| "{ should almost always be at the end of the previous line" |
| " [whitespace/braces] [4]", |
| ], |
| ) |
| |
| cpplint._cpplint_state.SetFilters("-runtime/explicit:foo.h") |
| self.TestMultiLineLint( |
| test_code, |
| "{ should almost always be at the end of the previous line" |
| " [whitespace/braces] [4]", |
| ) |
| |
| cpplint._cpplint_state.SetFilters("-runtime/explicit:foo.h:2") |
| self.TestMultiLineLint( |
| test_code, |
| "{ should almost always be at the end of the previous line" |
| " [whitespace/braces] [4]", |
| ) |
| |
| cpplint._cpplint_state.SetFilters( |
| "-runtime/explicit:foo.h:14,-whitespace/braces:otherfile.h:3" |
| ) |
| self.TestMultiLineLint( |
| test_code, |
| [ |
| "Single-parameter constructors should be marked explicit." |
| " [runtime/explicit] [4]", |
| "{ should almost always be at the end of the previous line" |
| " [whitespace/braces] [4]", |
| ], |
| ) |
| |
| cpplint._cpplint_state.SetFilters( |
| "-runtime/explicit:foo.h:2,-whitespace/braces:foo.h:3" |
| ) |
| self.TestMultiLineLint(test_code, "") |
| finally: |
| cpplint._cpplint_state.filters = old_filters |
| |
| def testDuplicateHeader(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "path/self.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company. All Rights Reserved.", |
| '#include "path/self.h"', |
| '#include "path/duplicate.h"', |
| '#include "path/duplicate.h"', |
| "#ifdef MACRO", |
| '#include "path/unique.h"', |
| "#else", |
| '#include "path/unique.h"', |
| "#endif", |
| "", |
| ], |
| error_collector, |
| ) |
| assert error_collector.ResultList() == [ |
| '"path/duplicate.h" already included at path/self.cc:3 [build/include] [4]' |
| ] |
| |
| def testUnnamedNamespacesInHeaders(self): |
| for extension in ["h", "hpp", "hxx", "h++", "cuh"]: |
| self.doTestUnnamedNamespacesInHeaders(extension) |
| |
| def doTestUnnamedNamespacesInHeaders(self, extension): |
| self.TestLanguageRulesCheck( |
| "foo." + extension, |
| "namespace {", |
| "Do not use unnamed namespaces in header files. See" |
| " https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces" |
| " for more information. [build/namespaces_headers] [4]", |
| ) |
| # namespace registration macros are OK. |
| self.TestLanguageRulesCheck("foo." + extension, "namespace { \\", "") |
| # named namespaces are OK. |
| self.TestLanguageRulesCheck("foo." + extension, "namespace foo {", "") |
| self.TestLanguageRulesCheck("foo." + extension, "namespace foonamespace {", "") |
| |
| def testUnnamedNamespacesInNonHeaders(self): |
| for extension in ["c", "cc", "cpp", "cxx", "c++", "cu"]: |
| self.TestLanguageRulesCheck("foo." + extension, "namespace {", "") |
| self.TestLanguageRulesCheck("foo." + extension, "namespace foo {", "") |
| |
| def testBuildClass(self): |
| # Test that the linter can parse to the end of class definitions, |
| # and that it will report when it can't. |
| # Don't warn on forward declarations of various types. |
| self.TestMultiLineLint("class Foo;", "") |
| self.TestMultiLineLint( |
| """struct Foo* |
| foo = NewFoo();""", |
| "", |
| ) |
| # Test preprocessor. |
| self.TestMultiLineLint( |
| """#ifdef DERIVE_FROM_GOO |
| struct Foo : public Goo { |
| #else |
| struct Foo : public Hoo { |
| #endif |
| };""", |
| "", |
| ) |
| self.TestMultiLineLint( |
| """ |
| class Foo |
| #ifdef DERIVE_FROM_GOO |
| : public Goo { |
| #else |
| : public Hoo { |
| #endif |
| };""", |
| "", |
| ) |
| |
| def testBuildEndComment(self): |
| # The crosstool compiler we currently use will fail to compile the |
| # code in this test, so we might consider removing the lint check. |
| self.TestMultiLineLint( |
| """#if 0 |
| #endif Not a comment""", |
| "Uncommented text after #endif is non-standard. Use a comment." |
| " [build/endif_comment] [5]", |
| ) |
| |
| def testBuildForwardDecl(self): |
| # The crosstool compiler we currently use will fail to compile the |
| # code in this test, so we might consider removing the lint check. |
| self.TestLint( |
| "class Foo::Goo;", |
| "Inner-style forward declarations are invalid." |
| " Remove this line." |
| " [build/forward_decl] [5]", |
| ) |
| |
| def testBuildDeprecated(self): |
| self.TestLint( |
| "a <? b", |
| ">? and <? (max and min) operators are non-standard and deprecated." |
| " [build/deprecated] [3]", |
| ) |
| self.TestLint( |
| "c >?= b", |
| ">? and <? (max and min) operators are non-standard and deprecated." |
| " [build/deprecated] [3]", |
| ) |
| |
| def GetBuildHeaderGuardPreprocessorSymbol(self, file_path): |
| # Figure out the expected header guard by processing an empty file. |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData(file_path, "h", [], error_collector) |
| for error in error_collector.ResultList(): |
| matched = re.search( |
| "No #ifndef header guard found, suggested CPP variable is: ([A-Z0-9_]+)", error |
| ) |
| if matched is not None: |
| return matched.group(1) |
| return None |
| |
| def testBuildHeaderGuard(self): |
| file_path = "mydir/foo.h" |
| expected_guard = self.GetBuildHeaderGuardPreprocessorSymbol(file_path) |
| assert re.search("MYDIR_FOO_H_$", expected_guard) |
| |
| # No guard at all: expect one error. |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData(file_path, "h", [], error_collector) |
| assert ( |
| error_collector.ResultList().count( |
| "No #ifndef header guard found, suggested CPP variable is: %s " |
| "[build/header_guard] [5]" % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| |
| # No header guard, but the error is suppressed. |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, |
| "h", |
| ["// Copyright 2014 Your Company.", "// NOLINT(build/header_guard)", ""], |
| error_collector, |
| ) |
| assert error_collector.ResultList() == [] |
| |
| # Wrong guard |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData(file_path, "h", ["#ifndef FOO_H", "#define FOO_H"], error_collector) |
| assert ( |
| error_collector.ResultList().count( |
| "#ifndef header guard has wrong style, please use: %s [build/header_guard] [5]" |
| % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| |
| # No define |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData(file_path, "h", ["#ifndef %s" % expected_guard], error_collector) |
| assert ( |
| error_collector.ResultList().count( |
| "No #ifndef header guard found, suggested CPP variable is: %s " |
| "[build/header_guard] [5]" % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| |
| # Mismatched define |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, "h", ["#ifndef %s" % expected_guard, "#define FOO_H"], error_collector |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "No #ifndef header guard found, suggested CPP variable is: %s " |
| "[build/header_guard] [5]" % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| |
| # No endif |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, |
| "h", |
| ["#ifndef %s" % expected_guard, "#define %s" % expected_guard, ""], |
| error_collector, |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| '#endif line should be "#endif // %s" [build/header_guard] [5]' % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| |
| # Commentless endif |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, |
| "h", |
| ["#ifndef %s" % expected_guard, "#define %s" % expected_guard, "#endif"], |
| error_collector, |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| '#endif line should be "#endif // %s" [build/header_guard] [5]' % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| |
| # Commentless endif for old-style guard |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, |
| "h", |
| ["#ifndef %s_" % expected_guard, "#define %s_" % expected_guard, "#endif"], |
| error_collector, |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| '#endif line should be "#endif // %s" [build/header_guard] [5]' % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| |
| # No header guard errors |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, |
| "h", |
| [ |
| "#ifndef %s" % expected_guard, |
| "#define %s" % expected_guard, |
| "#endif // %s" % expected_guard, |
| ], |
| error_collector, |
| ) |
| for line in error_collector.ResultList(): |
| assert "build/header_guard" not in line |
| |
| # No header guard errors for old-style guard |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, |
| "h", |
| [ |
| "#ifndef %s_" % expected_guard, |
| "#define %s_" % expected_guard, |
| "#endif // %s_" % expected_guard, |
| ], |
| error_collector, |
| ) |
| for line in error_collector.ResultList(): |
| assert "build/header_guard" not in line |
| |
| old_verbose_level = cpplint._cpplint_state.verbose_level |
| try: |
| cpplint._cpplint_state.verbose_level = 0 |
| # Warn on old-style guard if verbosity is 0. |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, |
| "h", |
| [ |
| "#ifndef %s_" % expected_guard, |
| "#define %s_" % expected_guard, |
| "#endif // %s_" % expected_guard, |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "#ifndef header guard has wrong style, please use: %s [build/header_guard] [0]" |
| % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| finally: |
| cpplint._cpplint_state.verbose_level = old_verbose_level |
| |
| # Completely incorrect header guard |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, "h", ["#ifndef FOO", "#define FOO", "#endif // FOO"], error_collector |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "#ifndef header guard has wrong style, please use: %s [build/header_guard] [5]" |
| % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| assert ( |
| error_collector.ResultList().count( |
| '#endif line should be "#endif // %s" [build/header_guard] [5]' % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| |
| # incorrect header guard with nolint |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, |
| "h", |
| ["#ifndef FOO // NOLINT", "#define FOO", "#endif // FOO NOLINT"], |
| error_collector, |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "#ifndef header guard has wrong style, please use: %s [build/header_guard] [5]" |
| % expected_guard |
| ) |
| == 0 |
| ), error_collector.ResultList() |
| assert ( |
| error_collector.ResultList().count( |
| '#endif line should be "#endif // %s" [build/header_guard] [5]' % expected_guard |
| ) |
| == 0 |
| ), error_collector.ResultList() |
| |
| # Special case for flymake |
| for test_file in ["mydir/foo_flymake.h", "mydir/.flymake/foo.h"]: |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| test_file, "h", ["// Copyright 2014 Your Company.", ""], error_collector |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "No #ifndef header guard found, suggested CPP variable is: %s " |
| "[build/header_guard] [5]" % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| |
| # Cuda guard |
| file_path = "mydir/foo.cuh" |
| expected_guard = self.GetBuildHeaderGuardPreprocessorSymbol(file_path) |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, "cuh", ["#ifndef FOO", "#define FOO", "#endif // FOO"], error_collector |
| ) |
| assert ( |
| error_collector.ResultList().count( |
| "#ifndef header guard has wrong style, please use: %s [build/header_guard] [5]" |
| % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| assert ( |
| error_collector.ResultList().count( |
| '#endif line should be "#endif // %s" [build/header_guard] [5]' % expected_guard |
| ) |
| == 1 |
| ), error_collector.ResultList() |
| |
| def testPragmaOnce(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "mydir/foo.h", |
| "h", |
| ["// Copyright 2014 Your Company.", "#pragma once", ""], |
| error_collector, |
| ) |
| assert error_collector.ResultList() == [] |
| |
| def testBuildHeaderGuardWithRoot(self): |
| temp_directory = os.path.realpath(tempfile.mkdtemp()) |
| try: |
| test_directory = os.path.join(temp_directory, "test") |
| os.makedirs(test_directory) |
| os.makedirs(os.path.join(test_directory, ".svn")) |
| header_directory = os.path.join(test_directory, "cpplint") |
| os.makedirs(header_directory) |
| self.doTestBuildHeaderGuardWithRoot(header_directory) |
| finally: |
| shutil.rmtree(temp_directory) |
| |
| def doTestBuildHeaderGuardWithRoot(self, header_directory): |
| # note: Tested file paths must be real, otherwise |
| # the repository name lookup will fail. |
| file_path = os.path.join(header_directory, "cpplint_test_header.h") |
| open(file_path, "a").close() |
| file_info = cpplint.FileInfo(file_path) |
| if file_info.FullName() == file_info.RepositoryName(): |
| # When FileInfo cannot deduce the root directory of the repository, |
| # FileInfo.RepositoryName returns the same value as FileInfo.FullName. |
| # This can happen when this source file was obtained without .svn or |
| # .git directory. (e.g. using 'svn export' or 'git archive'). |
| # Skip this test in such a case because --root flag makes sense only |
| # when the root directory of the repository is properly deduced. |
| return |
| |
| assert cpplint.GetHeaderGuardCPPVariable(file_path) == "CPPLINT_CPPLINT_TEST_HEADER_H_" |
| # |
| # test --root flags: |
| # this changes the cpp header guard prefix |
| # |
| |
| # left-strip the header guard by using a root dir inside of the repo dir. |
| # relative directory |
| cpplint._root = "cpplint" |
| assert cpplint.GetHeaderGuardCPPVariable(file_path) == "CPPLINT_TEST_HEADER_H_" |
| |
| nested_header_directory = os.path.join(header_directory, "nested") |
| nested_file_path = os.path.join(nested_header_directory, "cpplint_test_header.h") |
| os.makedirs(nested_header_directory) |
| open(nested_file_path, "a").close() |
| |
| cpplint._root = os.path.join("cpplint", "nested") |
| actual = cpplint.GetHeaderGuardCPPVariable(nested_file_path) |
| assert actual == "CPPLINT_TEST_HEADER_H_" |
| |
| # absolute directory |
| # (note that CPPLINT.cfg root=setting is always made absolute) |
| cpplint._root = header_directory |
| assert cpplint.GetHeaderGuardCPPVariable(file_path) == "CPPLINT_TEST_HEADER_H_" |
| |
| cpplint._root = nested_header_directory |
| assert cpplint.GetHeaderGuardCPPVariable(nested_file_path) == "CPPLINT_TEST_HEADER_H_" |
| |
| # --root flag is ignored if an non-existent directory is specified. |
| cpplint._root = "NON_EXISTENT_DIR" |
| assert cpplint.GetHeaderGuardCPPVariable(file_path) == "CPPLINT_CPPLINT_TEST_HEADER_H_" |
| |
| # prepend to the header guard by using a root dir that is more outer |
| # than the repo dir |
| |
| # (using absolute paths) |
| # (note that CPPLINT.cfg root=setting is always made absolute) |
| this_files_path = os.path.dirname(os.path.abspath(file_path)) |
| (styleguide_path, this_files_dir) = os.path.split(this_files_path) |
| (styleguide_parent_path, styleguide_dir_name) = os.path.split(styleguide_path) |
| # parent dir of styleguide |
| cpplint._root = styleguide_parent_path |
| assert styleguide_parent_path is not None |
| # do not hardcode the 'styleguide' repository name, it could be anything. |
| expected_prefix = re.sub(r"[^a-zA-Z0-9]", "_", styleguide_dir_name).upper() + "_" |
| # do not have 'styleguide' repo in '/' |
| assert ( |
| "%sCPPLINT_CPPLINT_TEST_HEADER_H_" % expected_prefix |
| == cpplint.GetHeaderGuardCPPVariable(file_path) |
| ) |
| |
| # To run the 'relative path' tests, we must be in the directory of this test file. |
| cur_dir = os.getcwd() |
| os.chdir(this_files_path) |
| |
| # (using relative paths) |
| styleguide_rel_path = os.path.relpath(styleguide_path, this_files_path) |
| # '..' |
| cpplint._root = styleguide_rel_path |
| assert cpplint.GetHeaderGuardCPPVariable(file_path) == "CPPLINT_CPPLINT_TEST_HEADER_H_" |
| |
| styleguide_rel_path = os.path.relpath(styleguide_parent_path, this_files_path) # '../..' |
| cpplint._root = styleguide_rel_path |
| assert ( |
| "%sCPPLINT_CPPLINT_TEST_HEADER_H_" % expected_prefix |
| == cpplint.GetHeaderGuardCPPVariable(file_path) |
| ) |
| |
| cpplint._root = None |
| |
| # Restore previous CWD. |
| os.chdir(cur_dir) |
| |
| def testIncludeItsHeader(self): |
| temp_directory = os.path.realpath(tempfile.mkdtemp()) |
| cur_dir = os.getcwd() |
| try: |
| test_directory = os.path.join(temp_directory, "test") |
| os.makedirs(test_directory) |
| file_path = os.path.join(test_directory, "foo.h") |
| open(file_path, "a").close() |
| file_path = os.path.join(test_directory, "Bar.h") |
| open(file_path, "a").close() |
| |
| os.chdir(temp_directory) |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData("test/foo.cc", "cc", [""], error_collector) |
| |
| if platform.system() == "Windows": |
| test_directory = test_directory.replace("\\", "/") |
| fmt = "{dir}/{fn}.cc should include its header file {dir}/{fn}.h [build/include] [5]" |
| expected = fmt.format(fn="foo", dir=test_directory) |
| assert error_collector.Results().count(expected) == 1 |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test/foo.cc", "cc", [r'#include "test/foo.h"', ""], error_collector |
| ) |
| assert error_collector.Results().count(expected) == 0 |
| |
| # Unix directory aliases are not allowed, and should trigger the |
| # "include itse header file" error |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test/foo.cc", "cc", [r'#include "./test/foo.h"', ""], error_collector |
| ) |
| fmt = "{dir}/{fn}.cc should include its header file {dir}/{fn}.h{unix_text}" |
| expected = ( |
| fmt.format( |
| fn="foo", |
| dir=test_directory, |
| unix_text=". Relative paths like . and .. are not allowed.", |
| ) |
| + " [build/include] [5]" |
| ) |
| assert error_collector.Results().count(expected) == 1 |
| |
| # This should continue to work |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "test/Bar.cc", "cc", [r'#include "test/Bar.h"', ""], error_collector |
| ) |
| fmt = "{dir}/{fn}.cc should include its header file {dir}/{fn}.h [build/include] [5]" |
| expected = fmt.format(fn="Bar", dir=test_directory) |
| assert error_collector.Results().count(expected) == 0 |
| |
| # Since Bar.cc & Bar.h look 3rd party-ish, it should be ok without the include dir |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData("test/Bar.cc", "cc", [r'#include "Bar.h"', ""], error_collector) |
| assert error_collector.Results().count(expected) == 0 |
| |
| # Test edge case in which multiple files have the same base name |
| open(os.path.join(test_directory, "foo.hpp"), "a").close() |
| cpplint.ProcessFileData( |
| "test/foo.cc", "cc", [r'#include "foo.hpp"', ""], error_collector |
| ) |
| assert error_collector.Results().count(expected) == 0 |
| |
| finally: |
| # Restore previous CWD. |
| os.chdir(cur_dir) |
| shutil.rmtree(temp_directory) |
| |
| def testPathSplitToList(self): |
| assert cpplint.PathSplitToList(os.path.join("")) == [""] |
| |
| assert cpplint.PathSplitToList(os.path.join(".")) == ["."] |
| |
| assert cpplint.PathSplitToList(os.path.join("..")) == [".."] |
| |
| assert cpplint.PathSplitToList(os.path.join("..", "a", "b")) == ["..", "a", "b"] |
| |
| assert cpplint.PathSplitToList(os.path.join("a", "b", "c", "d")) == ["a", "b", "c", "d"] |
| |
| def testBuildHeaderGuardWithRepository(self): |
| temp_directory = os.path.realpath(tempfile.mkdtemp()) |
| temp_directory2 = os.path.realpath(tempfile.mkdtemp()) |
| |
| # On Windows, os.path.relpath fails when the input is on |
| # a different drive than the current drive. |
| # In GitHub Actions CI, TEMP is set to C: drive, while the |
| # repository clone is on D: drive. |
| current_directory = os.getcwd() |
| try: |
| os.chdir(temp_directory) |
| |
| os.makedirs(os.path.join(temp_directory, ".svn")) |
| trunk_dir = os.path.join(temp_directory, "trunk") |
| os.makedirs(trunk_dir) |
| header_directory = os.path.join(trunk_dir, "cpplint") |
| os.makedirs(header_directory) |
| file_path = os.path.join(header_directory, "cpplint_test_header.h") |
| open(file_path, "a").close() |
| |
| # search for .svn if _repository is not specified |
| assert ( |
| cpplint.GetHeaderGuardCPPVariable(file_path) |
| == "TRUNK_CPPLINT_CPPLINT_TEST_HEADER_H_" |
| ) |
| |
| # use the provided repository root for header guards |
| cpplint._repository = os.path.relpath(trunk_dir) |
| assert cpplint.GetHeaderGuardCPPVariable(file_path) == "CPPLINT_CPPLINT_TEST_HEADER_H_" |
| cpplint._repository = os.path.abspath(trunk_dir) |
| assert cpplint.GetHeaderGuardCPPVariable(file_path) == "CPPLINT_CPPLINT_TEST_HEADER_H_" |
| |
| # ignore _repository if it doesn't exist |
| cpplint._repository = os.path.join(temp_directory, "NON_EXISTENT") |
| assert ( |
| cpplint.GetHeaderGuardCPPVariable(file_path) |
| == "TRUNK_CPPLINT_CPPLINT_TEST_HEADER_H_" |
| ) |
| |
| # ignore _repository if it exists but file isn't in it |
| cpplint._repository = os.path.relpath(temp_directory2) |
| assert ( |
| cpplint.GetHeaderGuardCPPVariable(file_path) |
| == "TRUNK_CPPLINT_CPPLINT_TEST_HEADER_H_" |
| ) |
| |
| # _root should be relative to _repository |
| cpplint._repository = os.path.relpath(trunk_dir) |
| cpplint._root = "cpplint" |
| assert cpplint.GetHeaderGuardCPPVariable(file_path) == "CPPLINT_TEST_HEADER_H_" |
| |
| finally: |
| os.chdir(current_directory) |
| shutil.rmtree(temp_directory) |
| shutil.rmtree(temp_directory2) |
| cpplint._repository = None |
| cpplint._root = None |
| |
| def testBuildInclude(self): |
| # Test that include statements have slashes in them. |
| self.TestLint( |
| '#include "foo.h"', |
| "Include the directory when naming header files [build/include_subdir] [4]", |
| ) |
| self.TestLint( |
| '#include "bar.hh"', |
| "Include the directory when naming header files [build/include_subdir] [4]", |
| ) |
| self.TestLint('#include "baz.aa"', "") |
| self.TestLint('#include "dir/foo.h"', "") |
| self.TestLint('#include "Python.h"', "") |
| self.TestLint('#include "lua.h"', "") |
| |
| def testHppInclude(self): |
| code = "\n".join(["#include <vector>", "#include <boost/any.hpp>"]) |
| self.TestLanguageRulesCheck("foo.h", code, "") |
| |
| def testBuildPrintfFormat(self): |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| r'printf("\%%d", value);', |
| r'snprintf(buffer, sizeof(buffer), "\[%d", value);', |
| r'fprintf(file, "\(%d", value);', |
| r'vsnprintf(buffer, sizeof(buffer), "\\\{%d", ap);', |
| ], |
| error_collector, |
| ) |
| assert ( |
| error_collector.Results().count( |
| "%, [, (, and { are undefined character escapes. Unescape them. " |
| "[build/printf_format] [3]" |
| ) |
| == 4 |
| ) |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| "foo.cc", |
| "cc", |
| [ |
| "// Copyright 2014 Your Company.", |
| "#include <cstdio>", |
| r'printf("\\%%%d", value);', |
| r'printf(R"(\[)");', |
| r'printf(R"(\[%s)", R"(\])");', |
| "", |
| ], |
| error_collector, |
| ) |
| assert error_collector.Results() == "" |
| |
| def testRuntimePrintfFormat(self): |
| self.TestLint( |
| r'fprintf(file, "%q", value);', |
| "%q in format strings is deprecated. Use %ll instead. [runtime/printf_format] [3]", |
| ) |
| |
| self.TestLint( |
| r'aprintf(file, "The number is %12q", value);', |
| "%q in format strings is deprecated. Use %ll instead. [runtime/printf_format] [3]", |
| ) |
| |
| self.TestLint( |
| r'printf(file, "The number is" "%-12q", value);', |
| "%q in format strings is deprecated. Use %ll instead. [runtime/printf_format] [3]", |
| ) |
| |
| self.TestLint( |
| r'printf(file, "The number is" "%+12q", value);', |
| "%q in format strings is deprecated. Use %ll instead. [runtime/printf_format] [3]", |
| ) |
| |
| self.TestLint( |
| r'printf(file, "The number is" "% 12q", value);', |
| "%q in format strings is deprecated. Use %ll instead. [runtime/printf_format] [3]", |
| ) |
| |
| self.TestLint( |
| r'snprintf(file, "Never mix %d and %1$d parameters!", value);', |
| "%N$ formats are unconventional. Try rewriting to avoid them." |
| " [runtime/printf_format] [2]", |
| ) |
| |
| def TestLintLogCodeOnError(self, code, expected_message): |
| # Special TestLint which logs the input code on error. |
| assert (result := self.PerformSingleLineLint(code)) == expected_message, ( |
| f'For code: "{code}"\nGot: "{result}"\nExpected: "{expected_message}"' |
| ) |
| |
| def testBuildStorageClass(self): |
| qualifiers = [None, "const", "volatile"] |
| signs = [None, "signed", "unsigned"] |
| types = [ |
| "void", |
| "char", |
| "int", |
| "float", |
| "double", |
| "schar", |
| "int8_t", |
| "uint8_t", |
| "int16_t", |
| "uint16_t", |
| "int32_t", |
| "uint32_t", |
| "int64_t", |
| "uint64_t", |
| ] |
| storage_classes = ["extern", "register", "static", "typedef"] |
| |
| build_storage_class_error_message = ( |
| "Storage-class specifier (static, extern, typedef, etc) should be " |
| "at the beginning of the declaration. [build/storage_class] [5]" |
| ) |
| |
| # Some explicit cases. Legal in C++, deprecated in C99. |
| self.TestLint("const int static foo = 5;", build_storage_class_error_message) |
| |
| self.TestLint("char static foo;", build_storage_class_error_message) |
| |
| self.TestLint("double const static foo = 2.0;", build_storage_class_error_message) |
| |
| self.TestLint("uint64_t typedef unsigned_long_long;", build_storage_class_error_message) |
| |
| self.TestLint("int register foo = 0;", build_storage_class_error_message) |
| |
| # Since there are a very large number of possibilities, randomly |
| # construct declarations. |
| # Make sure that the declaration is logged if there's an error. |
| # Seed generator with an integer for absolute reproducibility. |
| random.seed(25) |
| for _i in range(10): |
| # Build up random list of non-storage-class declaration specs. |
| other_decl_specs = [ |
| random.choice(qualifiers), |
| random.choice(signs), |
| random.choice(types), |
| ] |
| # remove None |
| other_decl_specs = [x for x in other_decl_specs if x is not None] |
| |
| # shuffle |
| random.shuffle(other_decl_specs) |
| |
| # insert storage class after the first |
| storage_class = random.choice(storage_classes) |
| insertion_point = random.randint(1, len(other_decl_specs)) |
| decl_specs = ( |
| other_decl_specs[0:insertion_point] |
| + [storage_class] |
| + other_decl_specs[insertion_point:] |
| ) |
| |
| self.TestLintLogCodeOnError( |
| " ".join(decl_specs) + ";", build_storage_class_error_message |
| ) |
| |
| # but no error if storage class is first |
| self.TestLintLogCodeOnError(storage_class + " " + " ".join(other_decl_specs), "") |
| |
| def testLegalCopyright(self): |
| legal_copyright_message = ( |
| "No copyright message found. " |
| 'You should have a line: "Copyright [year] <Copyright Owner>"' |
| " [legal/copyright] [5]" |
| ) |
| |
| copyright_line = "// Copyright 2014 Google Inc. All Rights Reserved." |
| |
| file_path = "mydir/googleclient/foo.cc" |
| |
| # There should be a copyright message in the first 10 lines |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData(file_path, "cc", [], error_collector) |
| assert error_collector.ResultList().count(legal_copyright_message) == 1 |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, "cc", ["" for unused_i in range(10)] + [copyright_line], error_collector |
| ) |
| assert error_collector.ResultList().count(legal_copyright_message) == 1 |
| |
| # Test that warning isn't issued if Copyright line appears early enough. |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData(file_path, "cc", [copyright_line], error_collector) |
| for line in error_collector.ResultList(): |
| assert "legal/copyright" not in line |
| |
| error_collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData( |
| file_path, "cc", ["" for unused_i in range(9)] + [copyright_line], error_collector |
| ) |
| for line in error_collector.ResultList(): |
| assert "legal/copyright" not in line |
| |
| def testInvalidIncrement(self): |
| self.TestLint( |
| "*count++;", |
| "Changing pointer instead of value (or unused value of " |
| "operator*). [runtime/invalid_increment] [5]", |
| ) |
| |
| def testSnprintfSize(self): |
| self.TestLint("vsnprintf(NULL, 0, format)", "") |
| self.TestLint( |
| "snprintf(fisk, 1, format)", |
| "If you can, use sizeof(fisk) instead of 1 as the 2nd arg " |
| "to snprintf. [runtime/printf] [3]", |
| ) |
| |
| |
| class TestCxx(CpplintTestBase): |
| def Helper(self, package, extension, lines, count): |
| filename = package + "/foo." + extension |
| lines = lines[:] |
| |
| # Header files need to have an ifdef guard wrapped around their code. |
| if extension.startswith("h"): |
| guard = filename.upper().replace("/", "_").replace(".", "_") + "_" |
| lines.insert(0, "#ifndef " + guard) |
| lines.insert(1, "#define " + guard) |
| lines.append("#endif // " + guard) |
| |
| # All files need a final blank line. |
| lines.append("") |
| |
| # Process the file and check resulting error count. |
| collector = ErrorCollector(self.assertTrue) |
| cpplint.ProcessFileData(filename, extension, lines, collector) |
| error_list = collector.ResultList() |
| assert count == len(error_list), error_list |
| |
| def TestCxxFeature(self, code, expected_error): |
| lines = code.split("\n") |
| collector = ErrorCollector(self.assertTrue) |
| cpplint.RemoveMultiLineComments("foo.h", lines, collector) |
| clean_lines = cpplint.CleansedLines(lines) |
| cpplint.FlagCxxHeaders("foo.cc", clean_lines, 0, collector) |
| assert expected_error == collector.Results() |
| |
| def testBlockedHeaders(self): |
| self.TestCxxFeature( |
| "#include <ratio>", "<ratio> is an unapproved C++11 header. [build/c++11] [5]" |
| ) |
| self.TestCxxFeature( |
| "#include <fenv.h>", "<fenv.h> is an unapproved C++11 header. [build/c++11] [5]" |
| ) |
| self.TestCxxFeature( |
| "#include <filesystem>", |
| "<filesystem> is an unapproved C++17 header. [build/c++17] [5]", |
| ) |
| |
| def testExplicitMakePair(self): |
| self.TestLint("make_pair", "") |
| self.TestLint("make_pair(42, 42)", "") |
| self.TestLint( |
| "make_pair<", |
| "For C++11-compatibility, omit template arguments from" |
| " make_pair OR use pair directly OR if appropriate," |
| " construct a pair directly" |
| " [build/explicit_make_pair] [4]", |
| ) |
| self.TestLint( |
| "make_pair <", |
| "For C++11-compatibility, omit template arguments from" |
| " make_pair OR use pair directly OR if appropriate," |
| " construct a pair directly" |
| " [build/explicit_make_pair] [4]", |
| ) |
| self.TestLint("my_make_pair<int, int>", "") |
| |
| |
| class TestCleansedLines: |
| def testInit(self): |
| lines = [ |
| "Line 1", |
| "Line 2", |
| "Line 3 // Comment test", |
| "Line 4 /* Comment test */", |
| 'Line 5 "foo"', |
| ] |
| |
| clean_lines = cpplint.CleansedLines(lines) |
| assert lines == clean_lines.raw_lines |
| assert clean_lines.NumLines() == 5 |
| |
| assert clean_lines.lines == ["Line 1", "Line 2", "Line 3", "Line 4", 'Line 5 "foo"'] |
| |
| assert clean_lines.elided == ["Line 1", "Line 2", "Line 3", "Line 4", 'Line 5 ""'] |
| |
| def testInitEmpty(self): |
| clean_lines = cpplint.CleansedLines([]) |
| assert clean_lines.raw_lines == [] |
| assert clean_lines.NumLines() == 0 |
| |
| def testCollapseStrings(self): |
| collapse = cpplint.CleansedLines._CollapseStrings |
| assert collapse('""') == '""' # "" (empty) |
| assert collapse('"""') == '"""' # """ (bad) |
| assert collapse('"xyz"') == '""' # "xyz" (string) |
| assert collapse('"\\""') == '""' # "\"" (string) |
| assert collapse('"\'"') == '""' # "'" (string) |
| assert collapse('""') == '""' # "\" (bad) |
| assert collapse('"\\\\"') == '""' # "\\" (string) |
| assert collapse('"\\\\\\"') == '"' # "\\\" (bad) |
| assert collapse('"\\\\\\\\"') == '""' # "\\\\" (string) |
| |
| assert collapse("''") == "''" # '' (empty) |
| assert collapse("'a'") == "''" # 'a' (char) |
| assert collapse("'\\''") == "''" # '\'' (char) |
| assert collapse("'\\'") == "'" # '\' (bad) |
| assert collapse("\\012") == "" # '\012' (char) |
| assert collapse("\\xfF0") == "" # '\xfF0' (char) |
| assert collapse("\\n") == "" # '\n' (char) |
| assert collapse("\\#") == r"\#" # '\#' (bad) |
| |
| assert collapse('"\'" + "\'"') == '"" + ""' |
| assert collapse("'\"', '\"'") == "'', ''" |
| assert collapse("\"a'b\"[0b1'0]") == '""[0b10]' |
| |
| assert collapse("4'2") == "42" |
| assert collapse("0b0'1'0'1") == "0b0101" |
| assert collapse("1'048'576") == "1048576" |
| assert collapse("0X10'0000") == "0X100000" |
| assert collapse("0'004'000'000") == "0004000000" |
| assert collapse("1.602'176'565e-19") == "1.602176565e-19" |
| assert collapse("'i' + 0xf'f'f'f") == "'' + 0xffff" |
| assert collapse("sizeof'x' == 1") == "sizeof'' == 1" |
| assert collapse("0x.0'3p1'0'0") == "0x.03p100" |
| assert collapse("1'23.4'5") == "123.45" |
| |
| assert ( |
| collapse('StringReplace(body, "\\\\", "\\\\\\\\");') == 'StringReplace(body, "", "");' |
| ) |
| assert collapse('\'"\' "foo"') == "'' \"\"" |
| |
| |
| class TestOrderOfIncludes(CpplintTestBase): |
| @pytest.fixture(autouse=True) |
| def setUp(self): |
| CpplintTestBase.setUp(self) |
| self.include_state = cpplint._IncludeState() |
| os.path.abspath = lambda value: value |
| |
| def testCheckNextIncludeOrder_OtherThenCpp(self): |
| assert self.include_state.CheckNextIncludeOrder(cpplint._OTHER_HEADER) == "" |
| assert ( |
| self.include_state.CheckNextIncludeOrder(cpplint._CPP_SYS_HEADER) |
| == "Found C++ system header after other header" |
| ) |
| |
| def testCheckNextIncludeOrder_CppThenC(self): |
| assert self.include_state.CheckNextIncludeOrder(cpplint._CPP_SYS_HEADER) == "" |
| assert ( |
| self.include_state.CheckNextIncludeOrder(cpplint._C_SYS_HEADER) |
| == "Found C system header after C++ system header" |
| ) |
| |
| def testCheckNextIncludeOrder_OtherSysThenC(self): |
| assert self.include_state.CheckNextIncludeOrder(cpplint._OTHER_SYS_HEADER) == "" |
| assert ( |
| self.include_state.CheckNextIncludeOrder(cpplint._C_SYS_HEADER) |
| == "Found C system header after other system header" |
| ) |
| |
| def testCheckNextIncludeOrder_OtherSysThenCpp(self): |
| assert self.include_state.CheckNextIncludeOrder(cpplint._OTHER_SYS_HEADER) == "" |
| assert ( |
| self.include_state.CheckNextIncludeOrder(cpplint._CPP_SYS_HEADER) |
| == "Found C++ system header after other system header" |
| ) |
| |
| def testCheckNextIncludeOrder_LikelyThenCpp(self): |
| assert self.include_state.CheckNextIncludeOrder(cpplint._LIKELY_MY_HEADER) == "" |
| assert self.include_state.CheckNextIncludeOrder(cpplint._CPP_SYS_HEADER) == "" |
| |
| def testCheckNextIncludeOrder_PossibleThenCpp(self): |
| assert self.include_state.CheckNextIncludeOrder(cpplint._POSSIBLE_MY_HEADER) == "" |
| assert self.include_state.CheckNextIncludeOrder(cpplint._CPP_SYS_HEADER) == "" |
| |
| def testCheckNextIncludeOrder_CppThenLikely(self): |
| assert self.include_state.CheckNextIncludeOrder(cpplint._CPP_SYS_HEADER) == "" |
| # This will eventually fail. |
| assert self.include_state.CheckNextIncludeOrder(cpplint._LIKELY_MY_HEADER) == "" |
| |
| def testCheckNextIncludeOrder_CppThenPossible(self): |
| assert self.include_state.CheckNextIncludeOrder(cpplint._CPP_SYS_HEADER) == "" |
| assert self.include_state.CheckNextIncludeOrder(cpplint._POSSIBLE_MY_HEADER) == "" |
| |
| def testCheckNextIncludeOrder_CppThenOtherSys(self): |
| assert self.include_state.CheckNextIncludeOrder(cpplint._CPP_SYS_HEADER) == "" |
| assert self.include_state.CheckNextIncludeOrder(cpplint._OTHER_SYS_HEADER) == "" |
| |
| def testCheckNextIncludeOrder_OtherSysThenPossible(self): |
| assert self.include_state.CheckNextIncludeOrder(cpplint._OTHER_SYS_HEADER) == "" |
| assert self.include_state.CheckNextIncludeOrder(cpplint._POSSIBLE_MY_HEADER) == "" |
| |
| def testClassifyInclude(self): |
| file_info = cpplint.FileInfo |
| classify_include = cpplint._ClassifyInclude |
| assert classify_include(file_info("foo/foo.cc"), "stdio.h", True) == cpplint._C_SYS_HEADER |
| assert ( |
| classify_include(file_info("foo/foo.cc"), "sys/time.h", True) == cpplint._C_SYS_HEADER |
| ) |
| assert ( |
| classify_include(file_info("foo/foo.cc"), "netipx/ipx.h", True) == cpplint._C_SYS_HEADER |
| ) |
| assert ( |
| classify_include(file_info("foo/foo.cc"), "arpa/ftp.h", True) == cpplint._C_SYS_HEADER |
| ) |
| assert classify_include(file_info("foo/foo.cc"), "string", True) == cpplint._CPP_SYS_HEADER |
| assert ( |
| classify_include(file_info("foo/foo.cc"), "typeinfo", True) == cpplint._CPP_SYS_HEADER |
| ) |
| assert classify_include(file_info("foo/foo.cc"), "foo/foo.h", True) == cpplint._C_SYS_HEADER |
| assert ( |
| classify_include(file_info("foo/foo.cc"), "foo/foo.h", True, "standardcfirst") |
| == cpplint._OTHER_SYS_HEADER |
| ) |
| assert classify_include(file_info("foo/foo.cc"), "string", False) == cpplint._OTHER_HEADER |
| assert ( |
| classify_include(file_info("foo/foo.cc"), "boost/any.hpp", True) |
| == cpplint._OTHER_HEADER |
| ) |
| assert ( |
| classify_include(file_info("foo/foo.hxx"), "boost/any.hpp", True) |
| == cpplint._OTHER_HEADER |
| ) |
| assert ( |
| classify_include(file_info("foo/foo.h++"), "boost/any.hpp", True) |
| == cpplint._OTHER_HEADER |
| ) |
| assert ( |
| classify_include(file_info("foo/foo.cc"), "foo/foo-inl.h", False) |
| == cpplint._LIKELY_MY_HEADER |
| ) |
| assert ( |
| classify_include(file_info("foo/internal/foo.cc"), "foo/public/foo.h", False) |
| == cpplint._LIKELY_MY_HEADER |
| ) |
| assert ( |
| classify_include(file_info("foo/internal/foo.cc"), "foo/other/public/foo.h", False) |
| == cpplint._POSSIBLE_MY_HEADER |
| ) |
| assert ( |
| classify_include(file_info("foo/internal/foo.cc"), "foo/other/public/foop.h", False) |
| == cpplint._OTHER_HEADER |
| ) |
| |
| def testTryDropCommonSuffixes(self): |
| cpplint._hpp_headers = set() |
| cpplint._valid_extensions = set() |
| assert cpplint._DropCommonSuffixes("foo/foo-inl.h") == "foo/foo" |
| assert cpplint._DropCommonSuffixes("foo/foo-inl.hxx") == "foo/foo" |
| assert cpplint._DropCommonSuffixes("foo/foo-inl.h++") == "foo/foo" |
| assert cpplint._DropCommonSuffixes("foo/foo-inl.hpp") == "foo/foo" |
| assert cpplint._DropCommonSuffixes("foo/bar/foo_inl.h") == "foo/bar/foo" |
| assert cpplint._DropCommonSuffixes("foo/foo.cc") == "foo/foo" |
| assert cpplint._DropCommonSuffixes("foo/foo.cxx") == "foo/foo" |
| assert cpplint._DropCommonSuffixes("foo/foo.c") == "foo/foo" |
| assert cpplint._DropCommonSuffixes("foo/foo_unusualinternal.h") == "foo/foo_unusualinternal" |
| assert ( |
| cpplint._DropCommonSuffixes("foo/foo_unusualinternal.hpp") == "foo/foo_unusualinternal" |
| ) |
| assert cpplint._DropCommonSuffixes("_test.cc") == "" |
| assert cpplint._DropCommonSuffixes("_test.c") == "" |
| assert cpplint._DropCommonSuffixes("_test.c++") == "" |
| assert cpplint._DropCommonSuffixes("test.c") == "test" |
| assert cpplint._DropCommonSuffixes("test.cc") == "test" |
| assert cpplint._DropCommonSuffixes("test.c++") == "test" |
| |
| def testRegression(self): |
| def Format(includes): |
| include_list = [] |
| for item in includes: |
| if item.startswith(('"', "<")): |
| include_list.append("#include %s\n" % item) |
| else: |
| include_list.append(item + "\n") |
| return "".join(include_list) |
| |
| # Test singleton cases first. |
| self.TestLanguageRulesCheck("foo/foo.cc", Format(['"foo/foo.h"']), "") |
| self.TestLanguageRulesCheck("foo/foo.cc", Format(["<stdio.h>"]), "") |
| self.TestLanguageRulesCheck("foo/foo.cc", Format(["<string>"]), "") |
| self.TestLanguageRulesCheck("foo/foo.cc", Format(['"foo/foo-inl.h"']), "") |
| self.TestLanguageRulesCheck("foo/foo.cc", Format(['"bar/bar-inl.h"']), "") |
| self.TestLanguageRulesCheck("foo/foo.cc", Format(['"bar/bar.h"']), "") |
| |
| # Test everything in a good and new order. |
| self.TestLanguageRulesCheck( |
| "foo/foo.cc", |
| Format( |
| [ |
| '"foo/foo.h"', |
| '"foo/foo-inl.h"', |
| "<stdio.h>", |
| "<string>", |
| "<unordered_map>", |
| '"bar/bar-inl.h"', |
| '"bar/bar.h"', |
| ] |
| ), |
| "", |
| ) |
| |
| # Test bad orders. |
| self.TestLanguageRulesCheck( |
| "foo/foo.cc", |
| Format(["<string>", "<stdio.h>"]), |
| "Found C system header after C++ system header." |
| " Should be: foo.h, c system, c++ system, other." |
| " [build/include_order] [4]", |
| ) |
| self.TestLanguageRulesCheck( |
| "foo/foo.cc", Format(['"foo/bar-inl.h"', '"foo/foo-inl.h"']), "" |
| ) |
| self.TestLanguageRulesCheck( |
| "foo/foo.cc", |
| Format( |
| [ |
| '"foo/e.h"', |
| '"foo/b.h"', # warning here (e>b) |
| '"foo/c.h"', |
| '"foo/d.h"', |
| '"foo/a.h"', |
| ] |
| ), # warning here (d>a) |
| [ |
| 'Include "foo/b.h" not in alphabetical order [build/include_alpha] [4]', |
| 'Include "foo/a.h" not in alphabetical order [build/include_alpha] [4]', |
| ], |
| ) |
| # -inl.h headers are no longer special. |
| self.TestLanguageRulesCheck("foo/foo.cc", Format(['"foo/foo-inl.h"', "<string>"]), "") |
| self.TestLanguageRulesCheck("foo/foo.cc", Format(['"foo/bar.h"', '"foo/bar-inl.h"']), "") |
| # Test componentized header. OK to have my header in ../public dir. |
| self.TestLanguageRulesCheck( |
| "foo/internal/foo.cc", Format(['"foo/public/foo.h"', "<string>"]), "" |
| ) |
| # OK to have my header in other dir (not stylistically, but |
| # cpplint isn't as good as a human). |
| self.TestLanguageRulesCheck( |
| "foo/internal/foo.cc", Format(['"foo/other/public/foo.h"', "<string>"]), "" |
| ) |
| self.TestLanguageRulesCheck( |
| "foo/foo.cc", |
| Format(['"foo/foo.h"', "<string>", '"base/google.h"', '"base/flags.h"']), |
| 'Include "base/flags.h" not in alphabetical order [build/include_alpha] [4]', |
| ) |
| # According to the style, -inl.h should come before .h, but we don't |
| # complain about that. |
| self.TestLanguageRulesCheck( |
| "foo/foo.cc", |
| Format(['"foo/foo-inl.h"', '"foo/foo.h"', '"base/google.h"', '"base/google-inl.h"']), |
| "", |
| ) |
| # Allow project includes to be separated by blank lines |
| self.TestLanguageRulesCheck( |
| "a/a.cc", |
| Format( |
| ['"a/a.h"', "<string>", '"base/google.h"', "", '"b/c.h"', "", "MACRO", '"a/b.h"'] |
| ), |
| "", |
| ) |
| self.TestLanguageRulesCheck( |
| "a/a.cc", |
| Format(['"a/a.h"', "<string>", '"base/google.h"', '"a/b.h"']), |
| 'Include "a/b.h" not in alphabetical order [build/include_alpha] [4]', |
| ) |
| |
| # Test conditional includes |
| self.TestLanguageRulesCheck( |
| "a/a.cc", |
| "".join( |
| [ |
| "#include <string.h>\n", |
| '#include "base/port.h"\n', |
| "#include <initializer_list>\n", |
| ] |
| ), |
| ( |
| "Found C++ system header after other header. " |
| "Should be: a.h, c system, c++ system, other. " |
| "[build/include_order] [4]" |
| ), |
| ) |
| self.TestLanguageRulesCheck( |
| "a/a.cc", |
| "".join( |
| [ |
| "#include <string.h>\n", |
| '#include "base/port.h"\n', |
| "#ifdef LANG_CXX11\n", |
| "#include <initializer_list>\n", |
| "#endif // LANG_CXX11\n", |
| ] |
| ), |
| "", |
| ) |
| self.TestLanguageRulesCheck( |
| "a/a.cc", |
| "".join( |
| [ |
| "#include <string.h>\n", |
| "#ifdef LANG_CXX11\n", |
| '#include "base/port.h"\n', |
| "#include <initializer_list>\n", |
| "#endif // LANG_CXX11\n", |
| ] |
| ), |
| ( |
| "Found C++ system header after other header. " |
| "Should be: a.h, c system, c++ system, other. " |
| "[build/include_order] [4]" |
| ), |
| ) |
| |
| # Third party headers are exempt from order checks |
| self.TestLanguageRulesCheck( |
| "foo/foo.cc", Format(["<string>", '"Python.h"', "<vector>"]), "" |
| ) |
| |
| |
| class TestCheckForFunctionLengths(CpplintTestBase): |
| @pytest.fixture(autouse=True) |
| def setUp(self): |
| # Reducing these thresholds for the tests speeds up tests significantly. |
| CpplintTestBase.setUp(self) |
| self.old_normal_trigger = cpplint._FunctionState._NORMAL_TRIGGER |
| self.old_test_trigger = cpplint._FunctionState._TEST_TRIGGER |
| |
| cpplint._FunctionState._NORMAL_TRIGGER = 10 |
| cpplint._FunctionState._TEST_TRIGGER = 25 |
| |
| def tearDown(self): |
| cpplint._FunctionState._NORMAL_TRIGGER = self.old_normal_trigger |
| cpplint._FunctionState._TEST_TRIGGER = self.old_test_trigger |
| |
| def TestFunctionLengthsCheck(self, code, expected_message): |
| """Check warnings for long function bodies are as expected. |
| |
| Args: |
| code: C++ source code expected to generate a warning message. |
| expected_message: Message expected to be generated by the C++ code. |
| """ |
| assert expected_message == self.PerformFunctionLengthsCheck(code) |
| |
| def TriggerLines(self, error_level): |
| """Return number of lines needed to trigger a function length warning. |
| |
| Args: |
| error_level: --v setting for cpplint. |
| |
| Returns: |
| Number of lines needed to trigger a function length warning. |
| """ |
| return cpplint._FunctionState._NORMAL_TRIGGER * 2**error_level |
| |
| def TestLines(self, error_level): |
| """Return number of lines needed to trigger a test function length warning. |
| |
| Args: |
| error_level: --v setting for cpplint. |
| |
| Returns: |
| Number of lines needed to trigger a test function length warning. |
| """ |
| return cpplint._FunctionState._TEST_TRIGGER * 2**error_level |
| |
| def TestFunctionLengthCheckDefinition(self, lines, error_level): |
| """Generate long function definition and check warnings are as expected. |
| |
| Args: |
| lines: Number of lines to generate. |
| error_level: --v setting for cpplint. |
| """ |
| trigger_level = self.TriggerLines(cpplint._VerboseLevel()) |
| self.TestFunctionLengthsCheck( |
| "void test(int x)" + self.FunctionBody(lines), |
| ( |
| "Small and focused functions are preferred: " |
| "test() has %d non-comment lines " |
| "(error triggered by exceeding %d lines)." |
| " [readability/fn_size] [%d]" % (lines, trigger_level, error_level) |
| ), |
| ) |
| |
| def TestFunctionLengthCheckDefinitionOK(self, lines): |
| """Generate shorter function definition and check no warning is produced. |
| |
| Args: |
| lines: Number of lines to generate. |
| """ |
| self.TestFunctionLengthsCheck("void test(int x)" + self.FunctionBody(lines), "") |
| |
| def TestFunctionLengthCheckAtErrorLevel(self, error_level): |
| """Generate and check function at the trigger level for --v setting. |
| |
| Args: |
| error_level: --v setting for cpplint. |
| """ |
| self.TestFunctionLengthCheckDefinition(self.TriggerLines(error_level), error_level) |
| |
| def TestFunctionLengthCheckBelowErrorLevel(self, error_level): |
| """Generate and check function just below the trigger level for --v setting. |
| |
| Args: |
| error_level: --v setting for cpplint. |
| """ |
| self.TestFunctionLengthCheckDefinition(self.TriggerLines(error_level) - 1, error_level - 1) |
| |
| def TestFunctionLengthCheckAboveErrorLevel(self, error_level): |
| """Generate and check function just above the trigger level for --v setting. |
| |
| Args: |
| error_level: --v setting for cpplint. |
| """ |
| self.TestFunctionLengthCheckDefinition(self.TriggerLines(error_level) + 1, error_level) |
| |
| def FunctionBody(self, number_of_lines): |
| return " {\n" + " this_is_just_a_test();\n" * number_of_lines + "}" |
| |
| def FunctionBodyWithBlankLines(self, number_of_lines): |
| return " {\n" + " this_is_just_a_test();\n\n" * number_of_lines + "}" |
| |
| def FunctionBodyWithNoLints(self, number_of_lines): |
| return " {\n" + " this_is_just_a_test(); // NOLINT\n" * number_of_lines + "}" |
| |
| # Test line length checks. |
| def testFunctionLengthCheckDeclaration(self): |
| self.TestFunctionLengthsCheck( |
| "void test();", # Not a function definition |
| "", |
| ) |
| |
| def testFunctionLengthCheckDeclarationWithBlockFollowing(self): |
| self.TestFunctionLengthsCheck( |
| ("void test();\n" + self.FunctionBody(66)), # Not a function definition |
| "", |
| ) |
| |
| def testFunctionLengthCheckClassDefinition(self): |
| self.TestFunctionLengthsCheck( # Not a function definition |
| "class Test" + self.FunctionBody(66) + ";", "" |
| ) |
| |
| def testFunctionLengthCheckTrivial(self): |
| self.TestFunctionLengthsCheck( |
| "void test() {}", # Not counted |
| "", |
| ) |
| |
| def testFunctionLengthCheckEmpty(self): |
| self.TestFunctionLengthsCheck("void test() {\n}", "") |
| |
| def testFunctionLengthCheckDefinitionBelowSeverity0(self): |
| old_verbosity = cpplint._SetVerboseLevel(0) |
| self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(0) - 1) |
| cpplint._SetVerboseLevel(old_verbosity) |
| |
| def testFunctionLengthCheckDefinitionAtSeverity0(self): |
| old_verbosity = cpplint._SetVerboseLevel(0) |
| self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(0)) |
| cpplint._SetVerboseLevel(old_verbosity) |
| |
| def testFunctionLengthCheckDefinitionAboveSeverity0(self): |
| old_verbosity = cpplint._SetVerboseLevel(0) |
| self.TestFunctionLengthCheckAboveErrorLevel(0) |
| cpplint._SetVerboseLevel(old_verbosity) |
| |
| def testFunctionLengthCheckDefinitionBelowSeverity1v0(self): |
| old_verbosity = cpplint._SetVerboseLevel(0) |
| self.TestFunctionLengthCheckBelowErrorLevel(1) |
| cpplint._SetVerboseLevel(old_verbosity) |
| |
| def testFunctionLengthCheckDefinitionAtSeverity1v0(self): |
| old_verbosity = cpplint._SetVerboseLevel(0) |
| self.TestFunctionLengthCheckAtErrorLevel(1) |
| cpplint._SetVerboseLevel(old_verbosity) |
| |
| def testFunctionLengthCheckDefinitionBelowSeverity1(self): |
| self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(1) - 1) |
| |
| def testFunctionLengthCheckDefinitionAtSeverity1(self): |
| self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(1)) |
| |
| def testFunctionLengthCheckDefinitionAboveSeverity1(self): |
| self.TestFunctionLengthCheckAboveErrorLevel(1) |
| |
| def testFunctionLengthCheckDefinitionSeverity1PlusBlanks(self): |
| error_level = 1 |
| error_lines = self.TriggerLines(error_level) + 1 |
| trigger_level = self.TriggerLines(cpplint._VerboseLevel()) |
| self.TestFunctionLengthsCheck( |
| "void test_blanks(int x)" + self.FunctionBody(error_lines), |
| ( |
| "Small and focused functions are preferred: " |
| "test_blanks() has %d non-comment lines " |
| "(error triggered by exceeding %d lines)." |
| " [readability/fn_size] [%d]" |
| ) |
| % (error_lines, trigger_level, error_level), |
| ) |
| |
| def testFunctionLengthCheckComplexDefinitionSeverity1(self): |
| error_level = 1 |
| error_lines = self.TriggerLines(error_level) + 1 |
| trigger_level = self.TriggerLines(cpplint._VerboseLevel()) |
| self.TestFunctionLengthsCheck( |
| ( |
| "my_namespace::my_other_namespace::MyVeryLongTypeName*\n" |
| "my_namespace::my_other_namespace::MyFunction(int arg1, char* arg2)" |
| + self.FunctionBody(error_lines) |
| ), |
| ( |
| "Small and focused functions are preferred: " |
| "my_namespace::my_other_namespace::MyFunction()" |
| " has %d non-comment lines " |
| "(error triggered by exceeding %d lines)." |
| " [readability/fn_size] [%d]" |
| ) |
| % (error_lines, trigger_level, error_level), |
| ) |
| |
| def testFunctionLengthCheckDefinitionSeverity1ForTest(self): |
| error_level = 1 |
| error_lines = self.TestLines(error_level) + 1 |
| trigger_level = self.TestLines(cpplint._VerboseLevel()) |
| self.TestFunctionLengthsCheck( |
| "TEST_F(Test, Mutator)" + self.FunctionBody(error_lines), |
| ( |
| "Small and focused functions are preferred: " |
| "TEST_F(Test, Mutator) has %d non-comment lines " |
| "(error triggered by exceeding %d lines)." |
| " [readability/fn_size] [%d]" |
| ) |
| % (error_lines, trigger_level, error_level), |
| ) |
| |
| def testFunctionLengthCheckDefinitionSeverity1ForSplitLineTest(self): |
| error_level = 1 |
| error_lines = self.TestLines(error_level) + 1 |
| trigger_level = self.TestLines(cpplint._VerboseLevel()) |
| self.TestFunctionLengthsCheck( |
| ( |
| "TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,\n" |
| " FixGoogleUpdate_AllValues_MachineApp)" # note: 4 spaces |
| + self.FunctionBody(error_lines) |
| ), |
| ( |
| "Small and focused functions are preferred: " |
| "TEST_F(GoogleUpdateRecoveryRegistryProtectedTest, " # 1 space |
| "FixGoogleUpdate_AllValues_MachineApp) has %d non-comment lines " |
| "(error triggered by exceeding %d lines)." |
| " [readability/fn_size] [%d]" |
| ) |
| % (error_lines + 1, trigger_level, error_level), |
| ) |
| |
| def testFunctionLengthCheckDefinitionSeverity1ForBadTestDoesntBreak(self): |
| error_level = 1 |
| error_lines = self.TestLines(error_level) + 1 |
| trigger_level = self.TestLines(cpplint._VerboseLevel()) |
| self.TestFunctionLengthsCheck( |
| ("TEST_F(" + self.FunctionBody(error_lines)), |
| ( |
| "Small and focused functions are preferred: " |
| "TEST_F has %d non-comment lines " |
| "(error triggered by exceeding %d lines)." |
| " [readability/fn_size] [%d]" |
| ) |
| % (error_lines, trigger_level, error_level), |
| ) |
| |
| def testFunctionLengthCheckDefinitionSeverity1WithEmbeddedNoLints(self): |
| error_level = 1 |
| error_lines = self.TriggerLines(error_level) + 1 |
| trigger_level = self.TriggerLines(cpplint._VerboseLevel()) |
| self.TestFunctionLengthsCheck( |
| "void test(int x)" + self.FunctionBodyWithNoLints(error_lines), |
| ( |
| "Small and focused functions are preferred: " |
| "test() has %d non-comment lines " |
| "(error triggered by exceeding %d lines)." |
| " [readability/fn_size] [%d]" |
| ) |
| % (error_lines, trigger_level, error_level), |
| ) |
| |
| def testFunctionLengthCheckDefinitionSeverity1WithNoLint(self): |
| self.TestFunctionLengthsCheck( |
| ( |
| "void test(int x)" |
| + self.FunctionBody(self.TriggerLines(1)) |
| + " // NOLINT -- long function" |
| ), |
| "", |
| ) |
| |
| def testFunctionLengthCheckDefinitionBelowSeverity2(self): |
| self.TestFunctionLengthCheckBelowErrorLevel(2) |
| |
| def testFunctionLengthCheckDefinitionSeverity2(self): |
| self.TestFunctionLengthCheckAtErrorLevel(2) |
| |
| def testFunctionLengthCheckDefinitionAboveSeverity2(self): |
| self.TestFunctionLengthCheckAboveErrorLevel(2) |
| |
| def testFunctionLengthCheckDefinitionBelowSeverity3(self): |
| self.TestFunctionLengthCheckBelowErrorLevel(3) |
| |
| def testFunctionLengthCheckDefinitionSeverity3(self): |
| self.TestFunctionLengthCheckAtErrorLevel(3) |
| |
| def testFunctionLengthCheckDefinitionAboveSeverity3(self): |
| self.TestFunctionLengthCheckAboveErrorLevel(3) |
| |
| def testFunctionLengthCheckDefinitionBelowSeverity4(self): |
| self.TestFunctionLengthCheckBelowErrorLevel(4) |
| |
| def testFunctionLengthCheckDefinitionSeverity4(self): |
| self.TestFunctionLengthCheckAtErrorLevel(4) |
| |
| def testFunctionLengthCheckDefinitionAboveSeverity4(self): |
| self.TestFunctionLengthCheckAboveErrorLevel(4) |
| |
| def testFunctionLengthCheckDefinitionBelowSeverity5(self): |
| self.TestFunctionLengthCheckBelowErrorLevel(5) |
| |
| def testFunctionLengthCheckDefinitionAtSeverity5(self): |
| self.TestFunctionLengthCheckAtErrorLevel(5) |
| |
| def testFunctionLengthCheckDefinitionAboveSeverity5(self): |
| self.TestFunctionLengthCheckAboveErrorLevel(5) |
| |
| def testFunctionLengthCheckDefinitionHugeLines(self): |
| # 5 is the limit |
| self.TestFunctionLengthCheckDefinition(self.TriggerLines(10), 5) |
| |
| def testFunctionLengthNotDeterminable(self): |
| # Macro invocation without terminating semicolon. |
| self.TestFunctionLengthsCheck("MACRO(arg)", "") |
| |
| # Macro with underscores |
| self.TestFunctionLengthsCheck("MACRO_WITH_UNDERSCORES(arg1, arg2, arg3)", "") |
| |
| self.TestFunctionLengthsCheck( |
| "NonMacro(arg)", |
| "Lint failed to find start of function body. [readability/fn_size] [5]", |
| ) |
| |
| def testFunctionLengthCheckWithNamespace(self): |
| old_verbosity = cpplint._SetVerboseLevel(1) |
| self.TestFunctionLengthsCheck( |
| ( |
| "namespace {\n" |
| "void CodeCoverageCL35256059() {\n" + (" X++;\n" * 3000) + "}\n" |
| "} // namespace\n" |
| ), |
| ( |
| "Small and focused functions are preferred: " |
| "CodeCoverageCL35256059() has 3000 non-comment lines " |
| "(error triggered by exceeding 20 lines)." |
| " [readability/fn_size] [5]" |
| ), |
| ) |
| cpplint._SetVerboseLevel(old_verbosity) |
| |
| |
| def TrimExtraIndent(text_block): |
| """Trim a uniform amount of whitespace off of each line in a string. |
| |
| Compute the minimum indent on all non blank lines and trim that from each, so |
| that the block of text has no extra indentation. |
| |
| Args: |
| text_block: a multiline string |
| |
| Returns: |
| text_block with the common whitespace indent of each line removed. |
| """ |
| |
| def CountLeadingWhitespace(s): |
| count = 0 |
| for c in s: |
| if not c.isspace(): |
| break |
| count += 1 |
| return count |
| |
| # find the minimum indent (except for blank lines) |
| min_indent = min([CountLeadingWhitespace(line) for line in text_block.split("\n") if line]) |
| return "\n".join([line[min_indent:] for line in text_block.split("\n")]) |
| |
| |
| class TestCloseExpression: |
| @pytest.fixture(autouse=True) |
| def setUp(self): |
| self.lines = cpplint.CleansedLines( |
| # 1 2 3 4 5 |
| # 0123456789012345678901234567890123456789012345678901234567890 |
| [ |
| "// Line 0", |
| "inline RCULocked<X>::ReadPtr::ReadPtr(const RCULocked* rcu) {", |
| ' DCHECK(!(data & kFlagMask)) << "Error";', |
| "}", |
| "// Line 4", |
| "RCULocked<X>::WritePtr::WritePtr(RCULocked* rcu)", |
| " : lock_(&rcu_->mutex_) {", |
| "}", |
| "// Line 8", |
| "template <typename T, typename... A>", |
| "typename std::enable_if<", |
| " std::is_array<T>::value && (std::extent<T>::value > 0)>::type", |
| "MakeUnique(A&&... a) = delete;", |
| "// Line 13", |
| "auto x = []() {};", |
| "// Line 15", |
| "template <typename U>", |
| "friend bool operator==(const reffed_ptr& a,", |
| " const reffed_ptr<U>& b) {", |
| " return a.get() == b.get();", |
| "}", |
| "// Line 21", |
| ] |
| ) |
| |
| def testCloseExpression(self): |
| # List of positions to test: |
| # (start line, start position, end line, end position + 1) |
| positions = [ |
| (1, 16, 1, 19), |
| (1, 37, 1, 59), |
| (1, 60, 3, 1), |
| (2, 8, 2, 29), |
| (2, 30, 22, -1), # Left shift operator |
| (9, 9, 9, 36), |
| (10, 23, 11, 59), |
| (11, 54, 22, -1), # Greater than operator |
| (14, 9, 14, 11), |
| (14, 11, 14, 13), |
| (14, 14, 14, 16), |
| (17, 22, 18, 46), |
| (18, 47, 20, 1), |
| ] |
| for p in positions: |
| (_, line, column) = cpplint.CloseExpression(self.lines, p[0], p[1]) |
| assert (p[2], p[3]) == (line, column) |
| |
| def testReverseCloseExpression(self): |
| # List of positions to test: |
| # (end line, end position, start line, start position) |
| positions = [ |
| (1, 18, 1, 16), |
| (1, 58, 1, 37), |
| (2, 27, 2, 10), |
| (2, 28, 2, 8), |
| (6, 18, 0, -1), # -> operator |
| (9, 35, 9, 9), |
| (11, 54, 0, -1), # Greater than operator |
| (11, 57, 11, 31), |
| (14, 10, 14, 9), |
| (14, 12, 14, 11), |
| (14, 15, 14, 14), |
| (18, 45, 17, 22), |
| (20, 0, 18, 47), |
| ] |
| for p in positions: |
| (_, line, column) = cpplint.ReverseCloseExpression(self.lines, p[0], p[1]) |
| assert (p[2], p[3]) == (line, column) |
| |
| |
| class TestNestingState: |
| @pytest.fixture(autouse=True) |
| def setUp(self): |
| self.nesting_state = cpplint.NestingState() |
| self.error_collector = ErrorCollector(self.assertTrue) |
| |
| def assertTrue(self, condition, message=""): |
| assert condition, message |
| |
| def UpdateWithLines(self, lines): |
| clean_lines = cpplint.CleansedLines(lines) |
| for line in range(clean_lines.NumLines()): |
| self.nesting_state.Update("test.cc", clean_lines, line, self.error_collector) |
| |
| def testEmpty(self): |
| self.UpdateWithLines([]) |
| assert self.nesting_state.stack == [] |
| |
| def testNamespace(self): |
| self.UpdateWithLines(["namespace {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._NamespaceInfo) |
| assert self.nesting_state.stack[0].seen_open_brace |
| assert self.nesting_state.stack[0].name == "" |
| |
| self.UpdateWithLines(["namespace outer { namespace inner"]) |
| assert len(self.nesting_state.stack) == 3 |
| assert self.nesting_state.stack[0].seen_open_brace |
| assert self.nesting_state.stack[1].seen_open_brace |
| assert not self.nesting_state.stack[2].seen_open_brace |
| assert self.nesting_state.stack[0].name == "" |
| assert self.nesting_state.stack[1].name == "outer" |
| assert self.nesting_state.stack[2].name == "inner" |
| |
| self.UpdateWithLines(["{"]) |
| assert self.nesting_state.stack[2].seen_open_brace |
| |
| self.UpdateWithLines(["}", "}}"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| def testDecoratedClass(self): |
| self.UpdateWithLines(["class Decorated_123 API A {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "A" |
| assert not self.nesting_state.stack[0].is_derived |
| assert self.nesting_state.stack[0].class_indent == 0 |
| self.UpdateWithLines(["}"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| def testInnerClass(self): |
| self.UpdateWithLines(["class A::B::C {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "A::B::C" |
| assert not self.nesting_state.stack[0].is_derived |
| assert self.nesting_state.stack[0].class_indent == 0 |
| self.UpdateWithLines(["}"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| def testClass(self): |
| self.UpdateWithLines(["class A {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "A" |
| assert not self.nesting_state.stack[0].is_derived |
| assert self.nesting_state.stack[0].class_indent == 0 |
| |
| self.UpdateWithLines(["};", "struct B : public A {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "B" |
| assert self.nesting_state.stack[0].is_derived |
| |
| self.UpdateWithLines(["};", "class C", ": public A {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "C" |
| assert self.nesting_state.stack[0].is_derived |
| |
| self.UpdateWithLines(["};", "template<T>"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| self.UpdateWithLines(["class D {", " class E {"]) |
| assert len(self.nesting_state.stack) == 2 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "D" |
| assert not self.nesting_state.stack[0].is_derived |
| assert isinstance(self.nesting_state.stack[1], cpplint._ClassInfo) |
| assert self.nesting_state.stack[1].name == "E" |
| assert not self.nesting_state.stack[1].is_derived |
| assert self.nesting_state.stack[1].class_indent == 2 |
| assert self.nesting_state.InnermostClass().name == "E" |
| |
| self.UpdateWithLines(["}", "}"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| def testClassAccess(self): |
| self.UpdateWithLines(["class A {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].access == "private" |
| |
| self.UpdateWithLines([" public:"]) |
| assert self.nesting_state.stack[0].access == "public" |
| self.UpdateWithLines([" protracted:"]) |
| assert self.nesting_state.stack[0].access == "public" |
| self.UpdateWithLines([" protected:"]) |
| assert self.nesting_state.stack[0].access == "protected" |
| self.UpdateWithLines([" private:"]) |
| assert self.nesting_state.stack[0].access == "private" |
| |
| self.UpdateWithLines([" struct B {"]) |
| assert len(self.nesting_state.stack) == 2 |
| assert isinstance(self.nesting_state.stack[1], cpplint._ClassInfo) |
| assert self.nesting_state.stack[1].access == "public" |
| assert self.nesting_state.stack[0].access == "private" |
| |
| self.UpdateWithLines([" protected :"]) |
| assert self.nesting_state.stack[1].access == "protected" |
| assert self.nesting_state.stack[0].access == "private" |
| |
| self.UpdateWithLines([" }", "}"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| def testStruct(self): |
| self.UpdateWithLines(["struct A {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "A" |
| assert not self.nesting_state.stack[0].is_derived |
| |
| self.UpdateWithLines(["}", "void Func(struct B arg) {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert not isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| |
| self.UpdateWithLines(["}"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| def testPreprocessor(self): |
| assert len(self.nesting_state.pp_stack) == 0 |
| self.UpdateWithLines(["#if MACRO1"]) |
| assert len(self.nesting_state.pp_stack) == 1 |
| self.UpdateWithLines(["#endif"]) |
| assert len(self.nesting_state.pp_stack) == 0 |
| |
| self.UpdateWithLines(["#ifdef MACRO2"]) |
| assert len(self.nesting_state.pp_stack) == 1 |
| self.UpdateWithLines(["#else"]) |
| assert len(self.nesting_state.pp_stack) == 1 |
| self.UpdateWithLines(["#ifdef MACRO3"]) |
| assert len(self.nesting_state.pp_stack) == 2 |
| self.UpdateWithLines(["#elif MACRO4"]) |
| assert len(self.nesting_state.pp_stack) == 2 |
| self.UpdateWithLines(["#endif"]) |
| assert len(self.nesting_state.pp_stack) == 1 |
| self.UpdateWithLines(["#endif"]) |
| assert len(self.nesting_state.pp_stack) == 0 |
| |
| self.UpdateWithLines( |
| [ |
| "#ifdef MACRO5", |
| "class A {", |
| "#elif MACRO6", |
| "class B {", |
| "#else", |
| "class C {", |
| "#endif", |
| ] |
| ) |
| assert len(self.nesting_state.pp_stack) == 0 |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "A" |
| self.UpdateWithLines(["};"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| self.UpdateWithLines(["class D", "#ifdef MACRO7"]) |
| assert len(self.nesting_state.pp_stack) == 1 |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "D" |
| assert not self.nesting_state.stack[0].is_derived |
| |
| self.UpdateWithLines(["#elif MACRO8", ": public E"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[0].name == "D" |
| assert self.nesting_state.stack[0].is_derived |
| assert not self.nesting_state.stack[0].seen_open_brace |
| |
| self.UpdateWithLines(["#else", "{"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[0].name == "D" |
| assert not self.nesting_state.stack[0].is_derived |
| assert self.nesting_state.stack[0].seen_open_brace |
| |
| self.UpdateWithLines(["#endif"]) |
| assert len(self.nesting_state.pp_stack) == 0 |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[0].name == "D" |
| assert not self.nesting_state.stack[0].is_derived |
| assert not self.nesting_state.stack[0].seen_open_brace |
| |
| self.UpdateWithLines([";"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| def testTemplate(self): |
| self.UpdateWithLines(["template <T,", " class Arg1 = tmpl<T> >"]) |
| assert len(self.nesting_state.stack) == 0 |
| self.UpdateWithLines(["class A {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "A" |
| |
| self.UpdateWithLines( |
| ["};", "template <T,", " template <typename, typename> class B>", "class C"] |
| ) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "C" |
| self.UpdateWithLines([";"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| self.UpdateWithLines(["class D : public Tmpl<E>"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "D" |
| |
| self.UpdateWithLines(["{", "};"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| self.UpdateWithLines( |
| [ |
| "template <class F,", |
| " class G,", |
| " class H,", |
| " typename I>", |
| "static void Func() {", |
| ] |
| ) |
| assert len(self.nesting_state.stack) == 1 |
| assert not isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| self.UpdateWithLines(["}", "template <class J> class K {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "K" |
| |
| def testTemplateDefaultArg(self): |
| self.UpdateWithLines(["template <class T, class D = default_delete<T>> class unique_ptr {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[0], isinstance( |
| self.nesting_state.stack[0], cpplint._ClassInfo |
| ) |
| |
| def testTemplateInnerClass(self): |
| self.UpdateWithLines(["class A {", " public:"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| |
| self.UpdateWithLines([" template <class B>", " class C<alloc<B> >", " : public A {"]) |
| assert len(self.nesting_state.stack) == 2 |
| assert isinstance(self.nesting_state.stack[1], cpplint._ClassInfo) |
| |
| def testArguments(self): |
| self.UpdateWithLines(["class A {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "A" |
| assert self.nesting_state.stack[-1].open_parentheses == 0 |
| |
| self.UpdateWithLines([" void Func(", " struct X arg1,"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 1 |
| self.UpdateWithLines([" struct X *arg2);"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 0 |
| |
| self.UpdateWithLines(["};"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| self.UpdateWithLines(["struct B {"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert isinstance(self.nesting_state.stack[0], cpplint._ClassInfo) |
| assert self.nesting_state.stack[0].name == "B" |
| |
| self.UpdateWithLines(["#ifdef MACRO", " void Func(", " struct X arg1"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 1 |
| self.UpdateWithLines(["#else"]) |
| |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 0 |
| self.UpdateWithLines([" void Func(", " struct X arg1"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 1 |
| |
| self.UpdateWithLines(["#endif"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 1 |
| self.UpdateWithLines([" struct X *arg2);"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 0 |
| |
| self.UpdateWithLines(["};"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| def testInlineAssembly(self): |
| self.UpdateWithLines( |
| [ |
| "void CopyRow_SSE2(const uint8_t* src, uint8_t* dst,", |
| " int count) {", |
| ] |
| ) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 0 |
| assert self.nesting_state.stack[-1].inline_asm == cpplint._NO_ASM |
| |
| self.UpdateWithLines([" asm volatile ("]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 1 |
| assert self.nesting_state.stack[-1].inline_asm == cpplint._INSIDE_ASM |
| |
| self.UpdateWithLines( |
| [ |
| ' "sub %0,%1 \\n"', |
| ' "1: \\n"', |
| ' "movdqa (%0),%%xmm0 \\n"', |
| ' "movdqa 0x10(%0),%%xmm1 \\n"', |
| ' "movdqa %%xmm0,(%0,%1) \\n"', |
| ' "movdqa %%xmm1,0x10(%0,%1) \\n"', |
| ' "lea 0x20(%0),%0 \\n"', |
| ' "sub $0x20,%2 \\n"', |
| ' "jg 1b \\n"', |
| ' : "+r"(src), // %0', |
| ' "+r"(dst), // %1', |
| ' "+r"(count) // %2', |
| " :", |
| ' : "memory", "cc"', |
| ] |
| ) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 1 |
| assert self.nesting_state.stack[-1].inline_asm == cpplint._INSIDE_ASM |
| |
| self.UpdateWithLines(["#if defined(__SSE2__)", ' , "xmm0", "xmm1"']) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 1 |
| assert self.nesting_state.stack[-1].inline_asm == cpplint._INSIDE_ASM |
| |
| self.UpdateWithLines(["#endif"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 1 |
| assert self.nesting_state.stack[-1].inline_asm == cpplint._INSIDE_ASM |
| |
| self.UpdateWithLines([" );"]) |
| assert len(self.nesting_state.stack) == 1 |
| assert self.nesting_state.stack[-1].open_parentheses == 0 |
| assert self.nesting_state.stack[-1].inline_asm == cpplint._END_ASM |
| |
| self.UpdateWithLines(["__asm {"]) |
| assert len(self.nesting_state.stack) == 2 |
| assert self.nesting_state.stack[-1].open_parentheses == 0 |
| assert self.nesting_state.stack[-1].inline_asm == cpplint._BLOCK_ASM |
| |
| self.UpdateWithLines(["}"]) |
| assert len(self.nesting_state.stack) == 1 |
| |
| self.UpdateWithLines(["}"]) |
| assert len(self.nesting_state.stack) == 0 |
| |
| |
| class TestQuiet: |
| @pytest.fixture(autouse=True) |
| def setUp(self): |
| self.temp_dir = os.path.realpath(tempfile.mkdtemp()) |
| self.this_dir_path = os.path.abspath(self.temp_dir) |
| self.python_executable = sys.executable or "python" |
| self.cpplint_test_h = os.path.join(self.this_dir_path, "cpplint_test_header.h") |
| open(self.cpplint_test_h, "w").close() |
| |
| def tearDown(self): |
| shutil.rmtree(self.temp_dir) |
| |
| def _runCppLint(self, *args): |
| cpplint_abspath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cpplint.py") |
| |
| cmd_line = [self.python_executable, cpplint_abspath] + list(args) + [self.cpplint_test_h] |
| |
| return_code = 0 |
| try: |
| output = subprocess.check_output(cmd_line, stderr=subprocess.STDOUT) |
| except subprocess.CalledProcessError as err: |
| return_code = err.returncode |
| output = err.output |
| if isinstance(output, bytes): |
| output = output.decode("utf-8") |
| return (return_code, output) |
| |
| def testNonQuietWithErrors(self): |
| # This will fail: the test header is missing a copyright and header guard. |
| (return_code, output) = self._runCppLint() |
| assert return_code == 1 |
| # Always-on behavior: Print error messages as they come up. |
| assert "[legal/copyright]" in output |
| assert "[build/header_guard]" in output |
| # If --quiet was unspecified: Print 'Done processing' and 'Total errors..' |
| assert "Done processing" in output |
| assert "Total errors found:" in output |
| |
| def testQuietWithErrors(self): |
| # When there are errors, behavior is identical to not passing --quiet. |
| (return_code, output) = self._runCppLint("--quiet") |
| assert return_code == 1 |
| assert "[legal/copyright]" in output |
| assert "[build/header_guard]" in output |
| # Even though --quiet was used, print these since there were errors. |
| assert "Done processing" in output |
| assert "Total errors found:" in output |
| |
| def testNonQuietWithoutErrors(self): |
| # This will succeed. We filtered out all the known errors for that file. |
| (return_code, output) = self._runCppLint( |
| "--filter=" + "-legal/copyright," + "-build/header_guard" |
| ) |
| assert return_code == 0, output |
| # No cpplint errors are printed since there were no errors. |
| assert "[legal/copyright]" not in output |
| assert "[build/header_guard]" not in output |
| # Print 'Done processing' since |
| # --quiet was not specified. |
| assert "Done processing" in output |
| |
| def testQuietWithoutErrors(self): |
| # This will succeed. We filtered out all the known errors for that file. |
| (return_code, output) = self._runCppLint( |
| "--quiet", "--filter=" + "-legal/copyright," + "-build/header_guard" |
| ) |
| assert return_code == 0, output |
| # No cpplint errors are printed since there were no errors. |
| assert "[legal/copyright]" not in output |
| assert "[build/header_guard]" not in output |
| # --quiet was specified and there were no errors: |
| # skip the printing of 'Done processing' and 'Total errors..' |
| assert "Done processing" not in output |
| assert "Total errors found:" not in output |
| # Output with no errors must be completely blank! |
| assert output == "" |
| |
| |
| # class FileFilterTest(unittest.TestCase): |
| # def testFilterExcludedFiles(self): |
| # self.assertEqual([], _FilterExcludedFiles([])) |
| |
| |
| # pylint: disable=C6409 |
| def setUp(): |
| """Runs before all tests are executed.""" |
| # Enable all filters, so we don't miss anything that is off by default. |
| cpplint._DEFAULT_FILTERS = [] |
| cpplint._cpplint_state.SetFilters("") |
| |
| |
| @pytest.fixture(autouse=True, scope="session") |
| def run_around_tests(pytestconfig: pytest.Config): |
| setUp() |
| yield |
| # We don't want to run the VerifyAllCategoriesAreSeen() test unless |
| # we're running the full test suite: if we only run one test, |
| # obviously we're not going to see all the error categories. So we |
| # only run VerifyAllCategoriesAreSeen() when we don't filter for |
| # specific tests. |
| if pytestconfig.getoption("-k", default=None) in {None, ""} and not any( |
| "::" in arg for arg in pytestconfig.args |
| ): |
| ErrorCollector(None).VerifyAllCategoriesAreSeen() |
| |
| |
| if __name__ == "__main__": |
| pytest.main([__file__]) |