From 68c551e243546a5cd2b480bd1b9f4aade6f03f10 Mon Sep 17 00:00:00 2001 From: Geoffrey Viola Date: Sun, 6 Jul 2025 16:37:51 +0000 Subject: [PATCH 1/7] enhance_using_directives_267 --- cpplint.py | 40 +++++++------ cpplint_unittest.py | 63 +++++++++++++++----- samples/silly-sample/filters.def | 2 +- samples/silly-sample/includeorder_cfirst.def | 2 +- samples/silly-sample/sed.def | 2 +- samples/silly-sample/simple.def | 2 +- 6 files changed, 74 insertions(+), 37 deletions(-) diff --git a/cpplint.py b/cpplint.py index e400b05..9f3dcdd 100755 --- a/cpplint.py +++ b/cpplint.py @@ -308,8 +308,14 @@ "build/include_order", "build/include_what_you_use", "build/namespaces_headers", - "build/namespaces_literals", - "build/namespaces", + "build/namespaces/header/block/literals", + "build/namespaces/header/block/nonliterals", + "build/namespaces/header/namespace/literals", + "build/namespaces/header/namespace/nonliterals", + "build/namespaces/source/block/literals", + "build/namespaces/source/block/nonliterals", + "build/namespaces/source/namespace/literals", + "build/namespaces/source/namespace/nonliterals", "build/printf_format", "build/storage_class", "legal/copyright", @@ -6021,22 +6027,20 @@ def CheckLanguage( ) if re.search(r"\busing namespace\b", line): - if re.search(r"\bliterals\b", line): - error( - filename, - linenum, - "build/namespaces_literals", - 5, - "Do not use namespace using-directives. Use using-declarations instead.", - ) - else: - error( - filename, - linenum, - "build/namespaces", - 5, - "Do not use namespace using-directives. Use using-declarations instead.", - ) + is_literals = re.search(r"\bliterals\b", line) is not None + is_header = not _IsSourceExtension(file_extension) + file_type = "header" if is_header else "source" + + is_block_scope = nesting_state.stack or not line.startswith("using namespace") + + scope_type = "block" if is_block_scope else "namespace" + literal_type = "literals" if is_literals else "nonliterals" + + specific_category = f"build/namespaces/{file_type}/{scope_type}/{literal_type}" + + error(filename, linenum, specific_category, 5, + "Do not use namespace using-directives. " + "Use using-declarations instead.") # Detect variable-length arrays. match = re.match(r"\s*(.+::)?(\w+) [a-z]\w*\[(.+)];", line) diff --git a/cpplint_unittest.py b/cpplint_unittest.py index e36093f..d8e8b37 100755 --- a/cpplint_unittest.py +++ b/cpplint_unittest.py @@ -3640,7 +3640,7 @@ def DoTest(self, lines): assert ( error_collector.Results().count( "Do not use namespace using-directives. Use using-declarations instead. " - "[build/namespaces] [5]" + "[build/namespaces/source/namespace/nonliterals] [5]" ) == 1 ) @@ -3649,20 +3649,6 @@ def DoTest(self, lines): 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) @@ -4203,6 +4189,53 @@ def testEndOfNamespaceComments(self): == 0 ) + def testUsingNamespacesGranular(self): + """Test granular using namespace checks for different contexts.""" + + self.TestLanguageRulesCheck("foo.h", "using namespace std;", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/header/namespace/nonliterals] [5]") + + self.TestLanguageRulesCheck("foo.h", "using namespace std::chrono::literals;", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/header/namespace/literals] [5]") + + self.TestLanguageRulesCheck( + "foo.cc", "using namespace std;", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/source/namespace/nonliterals] [5]") + + self.TestLanguageRulesCheck( + "foo.cc", "using namespace std::chrono::literals;", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/source/namespace/literals] [5]") + + self.TestLanguageRulesCheck("foo.h", "{ using namespace std; }", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/header/block/nonliterals] [5]") + + self.TestLanguageRulesCheck("foo.h", "{ using namespace std::chrono::literals; }", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/header/block/literals] [5]") + + self.TestLanguageRulesCheck( + "foo.cc", "{ using namespace std; }", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/source/block/nonliterals] [5]") + + self.TestLanguageRulesCheck( + "foo.cc", "{ using namespace std::chrono::literals; }", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/source/block/literals] [5]") + def testComma(self): self.TestLint("a = f(1,2);", "Missing space after , [whitespace/comma] [3]") self.TestLint( diff --git a/samples/silly-sample/filters.def b/samples/silly-sample/filters.def index e0fac32..5780b3e 100644 --- a/samples/silly-sample/filters.def +++ b/samples/silly-sample/filters.def @@ -13,7 +13,7 @@ src/sillycode.cpp:1: Include the directory when naming header files [build/inc src/sillycode.cpp:2: is an unapproved C++11 header. [build/c++11] [5] src/sillycode.cpp:3: Found C system header after other header. Should be: sillycode.h, c system, c++ system, other. [build/include_order] [4] src/sillycode.cpp:4: Found C system header after other header. Should be: sillycode.h, c system, c++ system, other. [build/include_order] [4] -src/sillycode.cpp:5: Do not use namespace using-directives. Use using-declarations instead. [build/namespaces] [5] +src/sillycode.cpp:5: Do not use namespace using-directives. Use using-declarations instead. [build/namespaces/source/namespace/nonliterals] [5] src/sillycode.cpp:40: If/else bodies with multiple statements require braces [readability/braces] [4] src/sillycode.cpp:66: Single-parameter constructors should be marked explicit. [runtime/explicit] [4] src/sillycode.cpp:76: Single-parameter constructors should be marked explicit. [runtime/explicit] [4] diff --git a/samples/silly-sample/includeorder_cfirst.def b/samples/silly-sample/includeorder_cfirst.def index a3b30a4..9be5e44 100644 --- a/samples/silly-sample/includeorder_cfirst.def +++ b/samples/silly-sample/includeorder_cfirst.def @@ -11,7 +11,7 @@ src/sillycode.cpp:2: Should have a space between // and comment [whitespace/co src/sillycode.cpp:2: is an unapproved C++11 header. [build/c++11] [5] src/sillycode.cpp:3: Found other system header after other header. Should be: sillycode.h, c system, c++ system, other. [build/include_order] [4] src/sillycode.cpp:4: Found other system header after other header. Should be: sillycode.h, c system, c++ system, other. [build/include_order] [4] -src/sillycode.cpp:5: Do not use namespace using-directives. Use using-declarations instead. [build/namespaces] [5] +src/sillycode.cpp:5: Do not use namespace using-directives. Use using-declarations instead. [build/namespaces/source/namespace/nonliterals] [5] src/sillycode.cpp:8: public: should be indented +1 space inside class Date [whitespace/indent] [3] src/sillycode.cpp:15: { should almost always be at the end of the previous line [whitespace/braces] [4] src/sillycode.cpp:39: { should almost always be at the end of the previous line [whitespace/braces] [4] diff --git a/samples/silly-sample/sed.def b/samples/silly-sample/sed.def index b3778ee..850a16d 100644 --- a/samples/silly-sample/sed.def +++ b/samples/silly-sample/sed.def @@ -15,7 +15,7 @@ sed -i '249s/\([^ ]\){/\1 {/' src/sillycode.cpp # Missing space before { [white # src/sillycode.cpp:2: " is an unapproved C++11 header." [build/c++11] [5] # src/sillycode.cpp:3: "Found C system header after other header. Should be: sillycode.h, c system, c++ system, other." [build/include_order] [4] # src/sillycode.cpp:4: "Found C system header after other header. Should be: sillycode.h, c system, c++ system, other." [build/include_order] [4] -# src/sillycode.cpp:5: "Do not use namespace using-directives. Use using-declarations instead." [build/namespaces] [5] +# src/sillycode.cpp:5: "Do not use namespace using-directives. Use using-declarations instead." [build/namespaces/source/namespace/nonliterals] [5] # src/sillycode.cpp:8: "public: should be indented +1 space inside class Date" [whitespace/indent] [3] # src/sillycode.cpp:15: "{ should almost always be at the end of the previous line" [whitespace/braces] [4] # src/sillycode.cpp:39: "{ should almost always be at the end of the previous line" [whitespace/braces] [4] diff --git a/samples/silly-sample/simple.def b/samples/silly-sample/simple.def index 7bc1dc6..b7ce111 100644 --- a/samples/silly-sample/simple.def +++ b/samples/silly-sample/simple.def @@ -12,7 +12,7 @@ src/sillycode.cpp:2: Should have a space between // and comment [whitespace/co src/sillycode.cpp:2: is an unapproved C++11 header. [build/c++11] [5] src/sillycode.cpp:3: Found C system header after other header. Should be: sillycode.h, c system, c++ system, other. [build/include_order] [4] src/sillycode.cpp:4: Found C system header after other header. Should be: sillycode.h, c system, c++ system, other. [build/include_order] [4] -src/sillycode.cpp:5: Do not use namespace using-directives. Use using-declarations instead. [build/namespaces] [5] +src/sillycode.cpp:5: Do not use namespace using-directives. Use using-declarations instead. [build/namespaces/source/namespace/nonliterals] [5] src/sillycode.cpp:8: public: should be indented +1 space inside class Date [whitespace/indent] [3] src/sillycode.cpp:15: { should almost always be at the end of the previous line [whitespace/braces] [4] src/sillycode.cpp:39: { should almost always be at the end of the previous line [whitespace/braces] [4] From d3271dd73cb5ecd5ad709bf8b8ca6a06089305f2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 20:19:24 +0000 Subject: [PATCH 2/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cpplint.py | 10 +++++-- cpplint_unittest.py | 68 +++++++++++++++++++++++++++++---------------- 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/cpplint.py b/cpplint.py index 9f3dcdd..ec88eb4 100755 --- a/cpplint.py +++ b/cpplint.py @@ -6038,9 +6038,13 @@ def CheckLanguage( specific_category = f"build/namespaces/{file_type}/{scope_type}/{literal_type}" - error(filename, linenum, specific_category, 5, - "Do not use namespace using-directives. " - "Use using-declarations instead.") + error( + filename, + linenum, + specific_category, + 5, + "Do not use namespace using-directives. Use using-declarations instead.", + ) # Detect variable-length arrays. match = re.match(r"\s*(.+::)?(\w+) [a-z]\w*\[(.+)];", line) diff --git a/cpplint_unittest.py b/cpplint_unittest.py index d8e8b37..574e5fd 100755 --- a/cpplint_unittest.py +++ b/cpplint_unittest.py @@ -4192,49 +4192,69 @@ def testEndOfNamespaceComments(self): def testUsingNamespacesGranular(self): """Test granular using namespace checks for different contexts.""" - self.TestLanguageRulesCheck("foo.h", "using namespace std;", - "Do not use namespace using-directives. " - "Use using-declarations instead." - " [build/namespaces/header/namespace/nonliterals] [5]") + self.TestLanguageRulesCheck( + "foo.h", + "using namespace std;", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/header/namespace/nonliterals] [5]", + ) - self.TestLanguageRulesCheck("foo.h", "using namespace std::chrono::literals;", - "Do not use namespace using-directives. " - "Use using-declarations instead." - " [build/namespaces/header/namespace/literals] [5]") + self.TestLanguageRulesCheck( + "foo.h", + "using namespace std::chrono::literals;", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/header/namespace/literals] [5]", + ) self.TestLanguageRulesCheck( - "foo.cc", "using namespace std;", + "foo.cc", + "using namespace std;", "Do not use namespace using-directives. " "Use using-declarations instead." - " [build/namespaces/source/namespace/nonliterals] [5]") + " [build/namespaces/source/namespace/nonliterals] [5]", + ) self.TestLanguageRulesCheck( - "foo.cc", "using namespace std::chrono::literals;", + "foo.cc", + "using namespace std::chrono::literals;", "Do not use namespace using-directives. " "Use using-declarations instead." - " [build/namespaces/source/namespace/literals] [5]") + " [build/namespaces/source/namespace/literals] [5]", + ) - self.TestLanguageRulesCheck("foo.h", "{ using namespace std; }", - "Do not use namespace using-directives. " - "Use using-declarations instead." - " [build/namespaces/header/block/nonliterals] [5]") + self.TestLanguageRulesCheck( + "foo.h", + "{ using namespace std; }", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/header/block/nonliterals] [5]", + ) - self.TestLanguageRulesCheck("foo.h", "{ using namespace std::chrono::literals; }", - "Do not use namespace using-directives. " - "Use using-declarations instead." - " [build/namespaces/header/block/literals] [5]") + self.TestLanguageRulesCheck( + "foo.h", + "{ using namespace std::chrono::literals; }", + "Do not use namespace using-directives. " + "Use using-declarations instead." + " [build/namespaces/header/block/literals] [5]", + ) self.TestLanguageRulesCheck( - "foo.cc", "{ using namespace std; }", + "foo.cc", + "{ using namespace std; }", "Do not use namespace using-directives. " "Use using-declarations instead." - " [build/namespaces/source/block/nonliterals] [5]") + " [build/namespaces/source/block/nonliterals] [5]", + ) self.TestLanguageRulesCheck( - "foo.cc", "{ using namespace std::chrono::literals; }", + "foo.cc", + "{ using namespace std::chrono::literals; }", "Do not use namespace using-directives. " "Use using-declarations instead." - " [build/namespaces/source/block/literals] [5]") + " [build/namespaces/source/block/literals] [5]", + ) def testComma(self): self.TestLint("a = f(1,2);", "Missing space after , [whitespace/comma] [3]") From b03e86a7c03a1e2fdd2062b18593342beb1edc34 Mon Sep 17 00:00:00 2001 From: Geoffrey Viola Date: Wed, 9 Jul 2025 14:21:34 +0000 Subject: [PATCH 3/7] improve types and add a method to nesting state --- cpplint.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cpplint.py b/cpplint.py index ec88eb4..aebb51d 100755 --- a/cpplint.py +++ b/cpplint.py @@ -3293,6 +3293,14 @@ def InAsmBlock(self): """ return self.stack and self.stack[-1].inline_asm != _NO_ASM + def InBlockScope(self): + """Check if we are currently one level inside a block scope. + + Returns: + True if top of the stack is a block scope, False otherwise. + """ + return len(self.stack) > 0 and not isinstance(self.stack[-1], _NamespaceInfo) + def InTemplateArgumentList(self, clean_lines, linenum, pos): """Check if current position is inside template argument list. @@ -6031,7 +6039,9 @@ def CheckLanguage( is_header = not _IsSourceExtension(file_extension) file_type = "header" if is_header else "source" - is_block_scope = nesting_state.stack or not line.startswith("using namespace") + # Check for the block scope for multi line blocks. + # Check if the line starts with the using directive as a hueristic in case it's all one line + is_block_scope = nesting_state.IsInBlockScope() and not line.startswith("using namespace") scope_type = "block" if is_block_scope else "namespace" literal_type = "literals" if is_literals else "nonliterals" From acb2d3b77992055259dc0a704ae9d170bd6fd84c Mon Sep 17 00:00:00 2001 From: Geoffrey Viola Date: Wed, 9 Jul 2025 14:24:25 +0000 Subject: [PATCH 4/7] test fix --- cpplint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpplint.py b/cpplint.py index aebb51d..b1e638e 100755 --- a/cpplint.py +++ b/cpplint.py @@ -6041,7 +6041,7 @@ def CheckLanguage( # Check for the block scope for multi line blocks. # Check if the line starts with the using directive as a hueristic in case it's all one line - is_block_scope = nesting_state.IsInBlockScope() and not line.startswith("using namespace") + is_block_scope = nesting_state.InBlockScope() and not line.startswith("using namespace") scope_type = "block" if is_block_scope else "namespace" literal_type = "literals" if is_literals else "nonliterals" From 283885f042e9673ccb01fb95b84df020af6f203b Mon Sep 17 00:00:00 2001 From: Geoffrey Viola Date: Wed, 9 Jul 2025 14:43:53 +0000 Subject: [PATCH 5/7] or --- cpplint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpplint.py b/cpplint.py index b1e638e..5e20ef6 100755 --- a/cpplint.py +++ b/cpplint.py @@ -6041,7 +6041,7 @@ def CheckLanguage( # Check for the block scope for multi line blocks. # Check if the line starts with the using directive as a hueristic in case it's all one line - is_block_scope = nesting_state.InBlockScope() and not line.startswith("using namespace") + is_block_scope = nesting_state.InBlockScope() or not line.startswith("using namespace") scope_type = "block" if is_block_scope else "namespace" literal_type = "literals" if is_literals else "nonliterals" From 2df2e9797e7a98bcdd03e786c5153023c5c57148 Mon Sep 17 00:00:00 2001 From: Geoffrey Viola Date: Wed, 9 Jul 2025 15:02:21 +0000 Subject: [PATCH 6/7] add shortcut --- cpplint.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/cpplint.py b/cpplint.py index 5e20ef6..37a5855 100755 --- a/cpplint.py +++ b/cpplint.py @@ -941,6 +941,14 @@ "Missing space after ,": r"s/,\([^ ]\)/, \1/g", } + # Used for backwards compatibility and ease of use +_FILTER_SHORTCUTS = { + "build/namespaces_literals" : ["build/namespaces/header/block/literals", + "build/namespaces/header/namespace/literals", + "build/namespaces/source/block/literals", + "build/namespaces/source/namespace/literals"] +} + # The root directory used for deriving header guard CPP variable. # This is set by --root flag. _root = None @@ -1463,7 +1471,12 @@ def AddFilters(self, filters): for filt in filters.split(","): clean_filt = filt.strip() if clean_filt: - self.filters.append(clean_filt) + if len(clean_filt) > 1 and clean_filt[1:] in _FILTER_SHORTCUTS: + starting_char = clean_filt[0] + new_filters = [starting_char + x for x in _FILTER_SHORTCUTS[clean_filt[1:]]] + self.filters.extend(new_filters) + else: + self.filters.append(clean_filt) for filt in self.filters: if not filt.startswith(("+", "-")): msg = f"Every filter in --filters must start with + or - ({filt} does not)" @@ -6039,8 +6052,8 @@ def CheckLanguage( is_header = not _IsSourceExtension(file_extension) file_type = "header" if is_header else "source" - # Check for the block scope for multi line blocks. - # Check if the line starts with the using directive as a hueristic in case it's all one line + # Check for the block scope for multiline blocks. + # Check if the line starts with the using directive as a heuristic in case it's all one line is_block_scope = nesting_state.InBlockScope() or not line.startswith("using namespace") scope_type = "block" if is_block_scope else "namespace" From 01268de91a6fbe8be10db91dc994eed8f8694bd8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:03:16 +0000 Subject: [PATCH 7/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cpplint.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cpplint.py b/cpplint.py index 37a5855..24897da 100755 --- a/cpplint.py +++ b/cpplint.py @@ -941,12 +941,14 @@ "Missing space after ,": r"s/,\([^ ]\)/, \1/g", } - # Used for backwards compatibility and ease of use +# Used for backwards compatibility and ease of use _FILTER_SHORTCUTS = { - "build/namespaces_literals" : ["build/namespaces/header/block/literals", - "build/namespaces/header/namespace/literals", - "build/namespaces/source/block/literals", - "build/namespaces/source/namespace/literals"] + "build/namespaces_literals": [ + "build/namespaces/header/block/literals", + "build/namespaces/header/namespace/literals", + "build/namespaces/source/block/literals", + "build/namespaces/source/namespace/literals", + ] } # The root directory used for deriving header guard CPP variable.