Browse Source

maxindent level metric implemented

avkonst 11 năm trước cách đây
mục cha
commit
80566d933e

+ 28 - 0
mainline/ext/std/code/complexity.py

@@ -26,9 +26,12 @@ class Plugin(mpp.api.Plugin, mpp.api.MetricPluginMixin, mpp.api.Child, mpp.api.I
     def declare_configuration(self, parser):
         parser.add_option("--std.code.complexity.cyclomatic", "--sccc", action="store_true", default=False,
                          help="Enables collection of cyclomatic complexity metric (McCabe) [default: %default]")
+        parser.add_option("--std.code.complexity.maxindent", "--sccmi", action="store_true", default=False,
+                         help="Enables collection of maximum indent level metric [default: %default]")
     
     def configure(self, options):
         self.is_active_cyclomatic = options.__dict__['std.code.complexity.cyclomatic']
+        self.is_active_maxindent = options.__dict__['std.code.complexity.maxindent']
         
     # cyclomatic complexity pattern
     # - C/C++
@@ -39,6 +42,8 @@ class Plugin(mpp.api.Plugin, mpp.api.MetricPluginMixin, mpp.api.Child, mpp.api.I
     # - Java
     pattern_java = re.compile(r'''([^0-9A-Za-z_]((if)|(case)|(for)|(while)|(catch))[^0-9A-Za-z_])|[&][&]|[|][|]|[?]''')
 
+    pattern_indent = re.compile(r'''[}{]''')
+
     def initialize(self):
         self.declare_metric(self.is_active_cyclomatic,
                             self.Field('cyclomatic', int),
@@ -49,6 +54,15 @@ class Plugin(mpp.api.Plugin, mpp.api.MetricPluginMixin, mpp.api.Child, mpp.api.I
                             },
                             marker_type_mask=mpp.api.Marker.T.CODE,
                             region_type_mask=mpp.api.Region.T.FUNCTION)
+        self.declare_metric(self.is_active_maxindent,
+                            self.Field('maxindent', int),
+                            {
+                                'cpp': self.pattern_indent,
+                                'cs': self.pattern_indent,
+                                'java': self.pattern_indent,
+                            },
+                            marker_type_mask=mpp.api.Marker.T.CODE,
+                            region_type_mask=mpp.api.Region.T.ANY)
         
         super(Plugin, self).initialize(fields=self.get_fields())
         
@@ -70,4 +84,18 @@ class Plugin(mpp.api.Plugin, mpp.api.MetricPluginMixin, mpp.api.Child, mpp.api.I
         is_updated = is_updated or self.is_updated
         if is_updated == True:
             self.count_if_active('cyclomatic', data, alias=alias)
+            self.count_if_active('maxindent', data, alias=alias)
 
+    def _maxindent_count_initialize(self, data, alias):
+        return (0, {'cur_level': 0})
+    
+    def _maxindent_count(self, data, alias, text, begin, end, m, count, counter_data):
+        if m.group(0) == '{':
+            counter_data['cur_level'] += 1
+            if counter_data['cur_level'] > count:
+                count = counter_data['cur_level']
+        elif m.group(0) == '}':
+            counter_data['cur_level'] -= 1
+        else:
+            assert False
+        return count

+ 28 - 9
mainline/mpp/api.py

@@ -18,6 +18,7 @@
 #
 
 import os.path
+
 import mpp.internal.dbwrap
 
 ##############################################################################
@@ -1138,15 +1139,33 @@ class MetricPluginMixin(object):
             raise self.AliasError(alias)
         pattern_to_search = field_data[4][alias]
         
-        for region in data.iterate_regions(filter_group=field_data[5]):
-            count = 0
-            for marker in data.iterate_markers(
-                            filter_group = field_data[1],
-                            region_id = region.get_id(),
-                            exclude_children = field_data[2],
-                            merge=field_data[3]):
-                count += len(pattern_to_search.findall(text, marker.get_offset_begin(), marker.get_offset_end()))
-            region.set_data(namespace, metric_name, count)
+        if hasattr(self, '_' + metric_name + '_count'):
+            counter_callback = self.__getattribute__('_' + metric_name + '_count')
+            for region in data.iterate_regions(filter_group=field_data[5]):
+                counter_data = {}
+                count = 0
+                if hasattr(self, '_' + metric_name + '_count_initialize'):
+                    (count, counter_data) = self.__getattribute__('_' + metric_name + '_count_initialize')(data, alias)
+                for marker in data.iterate_markers(
+                                filter_group = field_data[1],
+                                region_id = region.get_id(),
+                                exclude_children = field_data[2],
+                                merge=field_data[3]):
+                    begin = marker.get_offset_begin()
+                    end = marker.get_offset_end()
+                    for m in pattern_to_search.finditer(text, begin, end):
+                        count = counter_callback(data, alias, text, begin, end, m, count, counter_data)
+                region.set_data(namespace, metric_name, count)
+        else:
+            for region in data.iterate_regions(filter_group=field_data[5]):
+                count = 0
+                for marker in data.iterate_markers(
+                                filter_group = field_data[1],
+                                region_id = region.get_id(),
+                                exclude_children = field_data[2],
+                                merge=field_data[3]):
+                    count += len(pattern_to_search.findall(text, marker.get_offset_begin(), marker.get_offset_end()))
+                region.set_data(namespace, metric_name, count)
 
 class InterfaceNotImplemented(Exception):
     def __init__(self, obj):

+ 15 - 0
mainline/tests/general/test_basic.py

@@ -295,6 +295,21 @@ class Test(tests.common.TestCase):
         runner = tests.common.ToolRunner('view', ['--format=txt'], prefix='txt')
         self.assertExec(runner.run())
 
+    def test_std_complexity_maxindent(self):
+
+        runner = tests.common.ToolRunner('collect',
+                                         ['--std.code.complexity.maxindent'])
+        self.assertExec(runner.run())
+
+        runner = tests.common.ToolRunner('view',
+                                         ['--nest-regions'],
+                                         prefix='nest_per_file',
+                                         dirs_list=['./simple.cpp'])
+        self.assertExec(runner.run())
+
+        runner = tests.common.ToolRunner('view')
+        self.assertExec(runner.run())
+
     def test_debug_tool(self):
 
         runner = tests.common.ToolRunner('collect')

+ 3 - 0
mainline/tests/general/test_basic/test_help_collect_default_stdout.gold.txt

@@ -21,6 +21,9 @@ Options:
   --std.code.complexity.cyclomatic, --sccc
                         Enables collection of cyclomatic complexity metric
                         (McCabe) [default: False]
+  --std.code.complexity.maxindent, --sccmi
+                        Enables collection of maximum indent level metric
+                        [default: False]
   --std.code.cpp.files=STD.CODE.CPP.FILES
                         Enumerates filename extensions to match C/C++ files
                         [default: *.c,*.h,*.cpp,*.hpp,*.cc,*.hh,*.cxx,*.hxx]

+ 0 - 0
mainline/tests/general/test_basic/test_std_complexity_maxindent_collect_default_stdout.gold.txt


+ 16 - 0
mainline/tests/general/test_basic/test_std_complexity_maxindent_view_default_stdout.gold.txt

@@ -0,0 +1,16 @@
+:: info: Overall metrics for 'std.code.complexity:maxindent' metric
+	Average        : 1.3125
+	Minimum        : 0
+	Maximum        : 3
+	Total          : 21.0
+	Distribution   : 16 regions in total (including 0 suppressed)
+	  Metric value : Ratio : R-sum : Number of regions
+	             0 : 0.125 : 0.125 :  2	|||||||||||||
+	             1 : 0.500 : 0.625 :  8	||||||||||||||||||||||||||||||||||||||||||||||||||
+	             2 : 0.312 : 0.938 :  5	|||||||||||||||||||||||||||||||
+	             3 : 0.062 : 1.000 :  1	||||||
+
+:: info: Directory content:
+	Directory      : .
+
+

+ 101 - 0
mainline/tests/general/test_basic/test_std_complexity_maxindent_view_nest_per_file_stdout.gold.txt

@@ -0,0 +1,101 @@
+./simple.cpp:0: info: Metrics per '__global__' region
+	Region name    : __global__
+	Region type    : global
+	Offsets        : 0-697
+	Line numbers   : 1-71
+	Modified       : None
+	std.code.complexity:maxindent: 0
+
+.   ./simple.cpp:4: info: Metrics per 'hmm' region
+    	Region name    : hmm
+    	Region type    : namespace
+    	Offsets        : 2-696
+    	Line numbers   : 3-70
+    	Modified       : None
+    	std.code.complexity:maxindent: 1
+
+.   .   ./simple.cpp:9: info: Metrics per 'A' region
+        	Region name    : A
+        	Region type    : class
+        	Offsets        : 94-692
+        	Line numbers   : 9-68
+        	Modified       : None
+        	std.code.complexity:maxindent: 1
+
+.   .   .   ./simple.cpp:12: info: Metrics per 'A' region
+            	Region name    : A
+            	Region type    : function
+            	Offsets        : 106-252
+            	Line numbers   : 12-23
+            	Modified       : None
+            	std.code.complexity:maxindent: 3
+
+.   .   .   ./simple.cpp:26: info: Metrics per 'func' region
+            	Region name    : func
+            	Region type    : function
+            	Offsets        : 256-405
+            	Line numbers   : 26-40
+            	Modified       : None
+            	std.code.complexity:maxindent: 1
+
+.   .   .   .   ./simple.cpp:28: info: Metrics per 'embeded' region
+                	Region name    : embeded
+                	Region type    : class
+                	Offsets        : 285-391
+                	Line numbers   : 28-38
+                	Modified       : None
+                	std.code.complexity:maxindent: 1
+
+.   .   .   .   .   ./simple.cpp:30: info: Metrics per 'embeded' region
+                    	Region name    : embeded
+                    	Region type    : function
+                    	Offsets        : 306-387
+                    	Line numbers   : 30-37
+                    	Modified       : None
+                    	std.code.complexity:maxindent: 2
+
+.   .   .   ./simple.cpp:42: info: Metrics per 'func_to_be_removed_in_new_sources' region
+            	Region name    : func_to_be_removed_in_new_sources
+            	Region type    : function
+            	Offsets        : 408-596
+            	Line numbers   : 42-56
+            	Modified       : None
+            	std.code.complexity:maxindent: 1
+
+.   .   .   .   ./simple.cpp:44: info: Metrics per 'embeded' region
+                	Region name    : embeded
+                	Region type    : class
+                	Offsets        : 466-577
+                	Line numbers   : 44-54
+                	Modified       : None
+                	std.code.complexity:maxindent: 1
+
+.   .   .   .   .   ./simple.cpp:46: info: Metrics per 'embeded' region
+                    	Region name    : embeded
+                    	Region type    : function
+                    	Offsets        : 487-573
+                    	Line numbers   : 46-53
+                    	Modified       : None
+                    	std.code.complexity:maxindent: 2
+
+.   .   .   ./simple.cpp:58: info: Metrics per 'never' region
+            	Region name    : never
+            	Region type    : function
+            	Offsets        : 599-669
+            	Line numbers   : 58-65
+            	Modified       : None
+            	std.code.complexity:maxindent: 2
+
+./simple.cpp:: info: Overall metrics for 'std.code.complexity:maxindent' metric
+	Average        : 1.36363636364
+	Minimum        : 0
+	Maximum        : 3
+	Total          : 15.0
+	Distribution   : 11 regions in total (including 0 suppressed)
+	  Metric value : Ratio : R-sum : Number of regions
+	             0 : 0.091 : 0.091 :  1	|||||||||
+	             1 : 0.545 : 0.636 :  6	|||||||||||||||||||||||||||||||||||||||||||||||||||||||
+	             2 : 0.273 : 0.909 :  3	|||||||||||||||||||||||||||
+	             3 : 0.091 : 1.000 :  1	|||||||||
+
+