Kaynağa Gözat

Fix for C# parser (functions are not detected within attributes any more). Support for Java.

avkonst 12 yıl önce
ebeveyn
işleme
0c93e25a9d
21 değiştirilmiş dosya ile 3531 ekleme ve 36 silme
  1. 17 2
      mainline/doc/limitations.txt
  2. 6 0
      mainline/ext/std/code/complexity.py
  3. 2 0
      mainline/ext/std/code/cpp.py
  4. 20 24
      mainline/ext/std/code/cs.py
  5. 26 0
      mainline/ext/std/code/java.ini
  6. 277 0
      mainline/ext/std/code/java.py
  7. 3 0
      mainline/tests/general/test_basic/test_help_collect_default_stdout.gold.txt
  8. 2 0
      mainline/tests/general/test_basic/test_workflow_info_default_stdout.gold.txt
  9. 2 0
      mainline/tests/general/test_basic/test_workflow_info_second_stdout.gold.txt
  10. 1 1
      mainline/tests/general/test_basic/test_workflow_limit_default_stderr.gold.txt
  11. 1 0
      mainline/tests/general/test_std_code_cs/sources/interface.cs
  12. 9 9
      mainline/tests/general/test_std_code_cs/test_parser_export_files_stdout.gold.txt
  13. 49 0
      mainline/tests/general/test_std_code_java.py
  14. 24 0
      mainline/tests/general/test_std_code_java/readme.txt
  15. 461 0
      mainline/tests/general/test_std_code_java/sources/ArrayUtils.java
  16. 518 0
      mainline/tests/general/test_std_code_java/sources/BinaryHeapPriorityQueue.java
  17. 231 0
      mainline/tests/general/test_std_code_java/sources/Generics.java
  18. 0 0
      mainline/tests/general/test_std_code_java/test_parser_collect_default_stdout.gold.txt
  19. 17 0
      mainline/tests/general/test_std_code_java/test_parser_export_default_stdout.gold.txt
  20. 1817 0
      mainline/tests/general/test_std_code_java/test_parser_export_files_stdout.gold.txt
  21. 48 0
      mainline/tests/general/test_std_code_java/test_parser_limit_default_stdout.gold.txt

+ 17 - 2
mainline/doc/limitations.txt

@@ -21,7 +21,7 @@
 
 *** Known Limitations ***
 
-1) C/C++ parser and C# parser do not recognise definition of functions or overloaded operators
+1) C/C++, C# and Java parsers do not recognise definition of functions or overloaded operators
    in case of embeded comments after identifier name and before the list of arguments.
 
      This function is not detected by Metrix++: | This function is detected:
@@ -31,6 +31,7 @@
          {                                      |     {
              /* ... */                          |         /* ... */
          }                                      |     }
+
 2) C/C++ parser does not recognise comments within preprocessor statements.
    These comments are considered to be parts of a define.
 
@@ -43,7 +44,7 @@
               */                     \          |     #define GET_MAX(a, b) \
              ((a > b) ? a : b)                  |         ((a > b) ? a : b)
 
-2) C# parser does not recognise getters/setters for properties, if there is a comment before a block.
+3) C# parser does not recognise getters/setters for properties, if there is a comment before a block.
    These comments are considered to be parts of a define.
 
      This function is not detected by Metrix++: | This function is detected:
@@ -52,3 +53,17 @@
          {                                      |     { /* here comment is fine */
              /* ... */                          |         /* ... */
          }                                      |     }
+
+4) Java parser does not recognise anonymous inner classes.
+
+5) C/C++, C# and Java parsers do not recognise definition of classes/structs/namespaces/interface)
+   in case of embeded comments after keyword and identifier name.
+
+     This class is not detected by Metrix++:    | This class is detected:
+     -------------------------------------------|-------------------------------------------
+         class /* comment */ MyClass            |     class MyClass /* here is fine */
+         {                                      |     {
+             /* ... */                          |         /* ... */
+         }                                      |     }
+
+6) Java parser does not support parsing of identifiers which have got unicode symbols in name.

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

@@ -38,6 +38,7 @@ class Plugin(core.api.Plugin, core.api.Child, core.api.IConfigurable):
             namespace.add_field('cyclomatic', int)
             core.api.subscribe_by_parents_name('std.code.cpp', self, 'callback_cpp')
             core.api.subscribe_by_parents_name('std.code.cs', self, 'callback_cs')
+            core.api.subscribe_by_parents_name('std.code.java', self, 'callback_java')
 
     # cyclomatic complexity pattern
     # - C/C++
@@ -45,6 +46,8 @@ class Plugin(core.api.Plugin, core.api.Child, core.api.IConfigurable):
     # - C#
     #   supports Null-coalescing '??' and conditional '?:'
     pattern_cs = re.compile(r'''([^0-9A-Za-z_]((if)|(case)|(for)|(foreach)|(while)|(catch))[^0-9A-Za-z_])|[&][&]|[|][|]|[?][?]?''')
+    # - Java
+    pattern_java = re.compile(r'''([^0-9A-Za-z_]((if)|(case)|(for)|(while)|(catch))[^0-9A-Za-z_])|[&][&]|[|][|]|[?]''')
 
     def callback_cpp(self, parent, data, is_updated):
         self.callback_common(parent, data, is_updated, self.pattern_cpp)
@@ -52,6 +55,9 @@ class Plugin(core.api.Plugin, core.api.Child, core.api.IConfigurable):
     def callback_cs(self, parent, data, is_updated):
         self.callback_common(parent, data, is_updated, self.pattern_cs)
 
+    def callback_java(self, parent, data, is_updated):
+        self.callback_common(parent, data, is_updated, self.pattern_java)
+
     def callback_common(self, parent, data, is_updated, pattern):
         is_updated = is_updated or self.is_updated
         if is_updated == True:

+ 2 - 0
mainline/ext/std/code/cpp.py

@@ -269,6 +269,8 @@ class CppCodeParser(object):
             # Potential function name detected...
             elif m.group('fn_name') != None:
                 # ... if outside of a function (do not detect enclosed functions, unless classes are matched)
+                # wander why 'or next_block['type'] != 'function'' is in the condition?
+                # - remove it, run the tests and will see
                 if blocks[curblk]['type'] != 'function' and (next_block['name'] == "" or next_block['type'] != 'function'):
                     # - 'name'
                     next_block['name'] = m.group('fn_name').strip()

+ 20 - 24
mainline/ext/std/code/cs.py

@@ -48,11 +48,11 @@ class Plugin(core.api.Plugin, core.api.Parent, core.api.IParser, core.api.IConfi
         is_updated = is_updated or self.is_updated
         count_mismatched_brackets = 0
         if is_updated == True:
-            count_mismatched_brackets = CppCodeParser().run(data)
+            count_mismatched_brackets = CsCodeParser().run(data)
         self.notify_children(data, is_updated)
         return count_mismatched_brackets
             
-class CppCodeParser(object):
+class CsCodeParser(object):
     
     regex_cpp = re.compile(r'''
                    //(?=\n|\r|\r\n)                                   # Match C# style comments (empty comment line)
@@ -95,7 +95,7 @@ class CppCodeParser(object):
                                                                       # NOTE: names can have sub-names separated by dots
                                                                       # LIMITATION: if there are comments between keyword and name,
                                                                       # it is not detected
-                | [{};]                                               # Match block start/end and statement separator
+                | [\[\]{};]                                               # Match block start/end and statement separator
                                                                       # NOTE: C++ parser includes processing of <> and : 
                                                                       #       to handle template definitions, it is easier in C#
                 | ((?:\n|\r|\r\n)\s*(?:\n|\r|\r\n))                   # Match double empty line
@@ -168,7 +168,7 @@ class CppCodeParser(object):
     def parse(self, data):
         
         def reset_next_block(start):
-            return {'name':'', 'start':start, 'cursor':0, 'type':'', 'confirmed':False}
+            return {'name':'', 'start':start, 'cursor':0, 'type':'', 'inside_attribute':False}
         
         count_mismatched_brackets = 0
         
@@ -204,20 +204,17 @@ class CppCodeParser(object):
                 next_block['name'] = ""
                 next_block['start'] = m.end() # potential region start
 
-            # Template argument closing bracket
-            elif text[m.start()] == '>':
-                assert(False) # TODO should not happen
-                # Reset next block name and start (in order to skip class names in templates), if has not been confirmed before
-                if next_block['confirmed'] == False and (next_block['type'] == 'class' or next_block['type'] == 'struct'):
-                    next_block['name'] = ""
-                    next_block['start'] = m.end() # potential region start
-                    
-            # Template argument opening bracket or after class inheritance specification
-            elif text[m.start()] == ':' or text[m.start()] == '<':
-                assert(False) # TODO should not happen
-                # .. if goes after calss definition
-                if next_block['type'] == 'class' or next_block['type'] == 'struct':
-                    next_block['confirmed'] = True
+            # Block openned by '[' bracket...
+            elif text[m.start()] == '[':
+                # ... may include attributes, so do not capture function names inside
+                next_block['inside_attribute'] = True
+
+            # Block closed by ']' bracket...
+            # note: do not care about nesting for simplicity -
+            #       because attribute's statement can not have symbol ']' inside 
+            elif text[m.start()] == ']':
+                # ... may include attributes, so do not capture function names inside
+                next_block['inside_attribute'] = False
 
             # Double end line
             elif text[m.start()] == '\n' or text[m.start()] == '\r':
@@ -274,9 +271,6 @@ class CppCodeParser(object):
                 if next_block['name'] == "":
                     # - 'name'
                     next_block['name'] = m.group('block_name').strip()
-                    if next_block['name'] == "":
-                        assert(False) # impossible in C#
-                        next_block['name'] = '__noname__'
                     # - 'cursor'
                     cursor_current += len(self.regex_ln.findall(text, cursor_last_pos, m.start('block_name')))
                     cursor_last_pos = m.start('block_name')
@@ -287,9 +281,11 @@ class CppCodeParser(object):
 
             # Potential function name detected...
             elif m.group('fn_name') != None:
-                # ... if outside of a function (do not detect enclosed functions, unless classes are matched)
-                # different with C++: in C# function name can not go after class keyword declaration
-                if blocks[curblk]['type'] != 'function' and (next_block['name'] == ""):
+                # ... if outside of a function
+                #     (do not detect functions enclosed directly in a function, i.e. without classes)
+                # ... and other name before has not been matched 
+                if blocks[curblk]['type'] != 'function' and (next_block['name'] == "") \
+                       and next_block['inside_attribute'] == False:
                     # - 'name'
                     next_block['name'] = m.group('fn_name').strip()
                     # - 'cursor'

+ 26 - 0
mainline/ext/std/code/java.ini

@@ -0,0 +1,26 @@
+;
+;    Metrix++, Copyright 2009-2013, Metrix++ Project
+;    Link: http://metrixplusplus.sourceforge.net
+;    
+;    This file is a part of Metrix++ Tool.
+;    
+;    Metrix++ is free software: you can redistribute it and/or modify
+;    it under the terms of the GNU General Public License as published by
+;    the Free Software Foundation, version 3 of the License.
+;    
+;    Metrix++ is distributed in the hope that it will be useful,
+;    but WITHOUT ANY WARRANTY; without even the implied warranty of
+;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;    GNU General Public License for more details.
+;    
+;    You should have received a copy of the GNU General Public License
+;    along with Metrix++.  If not, see <http://www.gnu.org/licenses/>.
+;
+
+[Plugin]
+version: 1.0
+package: std.code
+module:  java
+class:   Plugin
+depends: None
+enabled: True

+ 277 - 0
mainline/ext/std/code/java.py

@@ -0,0 +1,277 @@
+#
+#    Metrix++, Copyright 2009-2013, Metrix++ Project
+#    Link: http://metrixplusplus.sourceforge.net
+#    
+#    This file is a part of Metrix++ Tool.
+#    
+#    Metrix++ is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, version 3 of the License.
+#    
+#    Metrix++ is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#    GNU General Public License for more details.
+#    
+#    You should have received a copy of the GNU General Public License
+#    along with Metrix++.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+
+import re
+import binascii
+import logging
+
+import core.api
+
+class Plugin(core.api.Plugin, core.api.Parent, core.api.IParser, core.api.IConfigurable, core.api.ICode):
+    
+    def declare_configuration(self, parser):
+        parser.add_option("--std.code.java.files", default="*.java",
+                         help="Enumerates filename extensions to match Java files [default: %default]")
+    
+    def configure(self, options):
+        self.files = options.__dict__['std.code.java.files'].split(',')
+        self.files.sort() # sorted list goes to properties
+        
+    def initialize(self):
+        # trigger version property set
+        core.api.Plugin.initialize(self)
+        db_loader = self.get_plugin_loader().get_database_loader()
+        prev_ext = db_loader.set_property(self.get_name() + ":files", ','.join(self.files))
+        if prev_ext != ','.join(self.files):
+            self.is_updated = True
+
+        self.get_plugin_loader().register_parser(self.files, self)
+        
+    def process(self, parent, data, is_updated):
+        is_updated = is_updated or self.is_updated
+        count_mismatched_brackets = 0
+        if is_updated == True:
+            count_mismatched_brackets = JavaCodeParser().run(data)
+        self.notify_children(data, is_updated)
+        return count_mismatched_brackets
+            
+class JavaCodeParser(object):
+    
+    regex_cpp = re.compile(r'''
+                   //(?=\n|\r|\r\n)                                   # Match Java style comments (empty comment line)
+                |  //.*?(?=\n|\r|\r\n)                                # Match Java style comments
+                                                                      # NOTE: end of line is NOT consumed
+                                                                      # NOTE: it is slightly different in C++
+                | /\*\*/                                              # Match C style comments (empty comment line)
+                                                                      # NOTE: it is slightly different in C++
+                | /\*.*?\*/                                           # Match C style comments
+                                                                      # NOTE: it is slightly different in C++
+                | \'(?:\\.|[^\\\'])*\'                                # Match quoted strings
+                | "(?:\\.|[^\\"])*"                                   # Match double quoted strings
+                | (?P<fn_name>([_$a-zA-Z][_$a-zA-Z0-9]*))\s*[(]       # Match function
+                                                                      # NOTE: Java may include $ in the name
+                                                                      # LIMITATION: if there are comments after function name
+                                                                      # and before '(', it is not detected
+                | ((?P<block_type>class|interface)                    # Match class or namespace
+                    (?P<block_name>(\s+[_$a-zA-Z][_$a-zA-Z0-9]*)))
+                                                                      # NOTE: noname instances are impossible in Java
+                                                                      # LIMITATION: if there are comments between keyword and name,
+                                                                      # it is not detected
+                | [{};]                                               # Match block start/end and statement separator
+                                                                      # NOTE: C++ parser includes processing of <> and : 
+                                                                      #       to handle template definitions, it is easier in Java
+                | ((?:\n|\r|\r\n)\s*(?:\n|\r|\r\n))                   # Match double empty line
+            ''',
+            re.DOTALL | re.MULTILINE | re.VERBOSE
+        )
+
+    regex_ln = re.compile(r'(\n)|(\r)|(\r\n)')
+
+    def run(self, data):
+        self.__init__() # Go to initial state if it is called twice
+        return self.parse(data)
+        
+    def finalize_block(self, text, block, block_end):
+        space_match = re.match('^\s*', text[block['start']:block_end], re.MULTILINE)
+        block['start'] += space_match.end() # trim spaces at the beginning
+        block['end'] = block_end
+
+        start_pos = block['start']
+        crc32 = 0
+        for child in block['children']:
+            # exclude children
+            crc32 = binascii.crc32(text[start_pos:child['start']], crc32)
+            start_pos = child['end']
+        block['checksum'] = binascii.crc32(text[start_pos:block['end']], crc32) & 0xffffffff # to match python 3
+        
+    def add_lines_data(self, text, blocks):
+        def add_lines_data_rec(self, text, blocks):
+            for each in blocks:
+                # add line begin
+                self.total_current += len(self.regex_ln.findall(text, self.total_last_pos, each['start']))
+                each['line_begin'] = self.total_current
+                self.total_last_pos = each['start']
+                # process enclosed
+                add_lines_data_rec(self, text, each['children'])
+                # add line end
+                self.total_current += len(self.regex_ln.findall(text, self.total_last_pos, each['end']))
+                each['line_end'] = self.total_current
+                self.total_last_pos = each['end']
+        self.total_last_pos = 0
+        self.total_current = 1
+        add_lines_data_rec(self, text, blocks)
+
+    def add_regions(self, data, blocks):
+        # Note: data.add_region() internals depend on special ordering of regions
+        # in order to identify enclosed regions efficiently
+        def add_regions_rec(self, data, blocks):
+            def get_type_id(data, named_type):
+                if named_type == "function":
+                    return data.get_region_types().FUNCTION
+                elif named_type == "class":
+                    return data.get_region_types().CLASS
+                elif named_type == "interface":
+                    return data.get_region_types().INTERFACE
+                elif named_type == "__global__":
+                    return data.get_region_types().GLOBAL
+                else:
+                    assert(False)
+            for each in blocks:
+                data.add_region(each['name'], each['start'], each['end'],
+                                each['line_begin'], each['line_end'], each['cursor'],
+                                get_type_id(data, each['type']), each['checksum'])
+                add_regions_rec(self, data, each['children'])
+        add_regions_rec(self, data, blocks)
+        
+    def parse(self, data):
+        
+        def reset_next_block(start):
+            return {'name':'', 'start':start, 'cursor':0, 'type':''}
+        
+        count_mismatched_brackets = 0
+        
+        text = data.get_content()
+        indent_current = 0;
+        
+        blocks = [{'name':'__global__', 'start':0, 'cursor':0, 'type':'__global__', 'indent_start':indent_current, 'children':[]}]
+        curblk = 0
+        
+        next_block = reset_next_block(0)
+        
+        cursor_last_pos = 0
+        cursor_current = 1
+        
+        for m in re.finditer(self.regex_cpp, text):
+            # Comment
+            if text[m.start()] == '/':
+                data.add_marker(m.start(), m.end(), data.get_marker_types().COMMENT)
+                if text[m.start():m.end()].startswith("//\n"):
+                    print text[m.start():m.end()]
+            
+            # String
+            elif text[m.start()] == '"' or text[m.start()] == '\'':
+                data.add_marker(m.start() + 1, m.end() - 1, data.get_marker_types().STRING)
+            
+            # Statement end
+            elif text[m.start()] == ';':
+                # Reset next block name and start
+                next_block['name'] = ""
+                next_block['start'] = m.end() # potential region start
+
+            # Double end line
+            elif text[m.start()] == '\n' or text[m.start()] == '\r':
+                # Reset next block start, if has not been named yet
+                if next_block['name'] == "":
+                    next_block['start'] = m.end() # potential region start
+
+            # Block start...
+            elif text[m.start()] == '{':
+                # shift indent right
+                indent_current += 1
+                
+                # ... if name detected previously
+                if next_block['name'] != '': # - Start of enclosed block
+                    blocks.append({'name':next_block['name'],
+                                   'start':next_block['start'],
+                                   'cursor':next_block['cursor'],
+                                   'type':next_block['type'],
+                                   'indent_start':indent_current,
+                                   'children':[]})
+                    next_block = reset_next_block(m.end())
+                    curblk += 1
+                # ... reset next block start, otherwise
+                else: # - unknown type of block start
+                    next_block['start'] = m.end() # potential region start
+            
+            # Block end...
+            elif text[m.start()] == '}':
+                # ... if indent level matches the start
+                if blocks[curblk]['indent_start'] == indent_current:
+                    next_block = reset_next_block(m.end())
+                    if curblk == 0:
+                        logging.warning("Non-matching closing bracket '}' detected: " + data.get_path() + ":" +
+                                        str(cursor_current + len(self.regex_ln.findall(text, cursor_last_pos, m.start()))))
+                        count_mismatched_brackets += 1
+                        continue
+                    
+                    self.finalize_block(text, blocks[curblk], m.end())
+                    assert(blocks[curblk]['type'] != '__global__')
+                    
+                    curblk -= 1
+                    assert(curblk >= 0)
+                    blocks[curblk]['children'].append(blocks.pop())
+
+                # shift indent left
+                indent_current -= 1
+                if indent_current < 0:
+                    logging.warning("Non-matching closing bracket '}' detected")
+                    count_mismatched_brackets += 1
+                    indent_current = 0
+
+            # Potential class, interface
+            elif m.group('block_type') != None:
+                if next_block['name'] == "":
+                    # - 'name'
+                    next_block['name'] = m.group('block_name').strip()
+                    # - 'cursor'
+                    cursor_current += len(self.regex_ln.findall(text, cursor_last_pos, m.start('block_name')))
+                    cursor_last_pos = m.start('block_name')
+                    next_block['cursor'] = cursor_current
+                    # - 'type'
+                    next_block['type'] = m.group('block_type').strip()
+                    # - 'start' detected earlier
+
+            # Potential function name detected...
+            elif m.group('fn_name') != None:
+                # ... if outside of a function
+                #     (do not detect functions enclosed directly in a function, i.e. without classes)
+                # ... and other name before has not been matched 
+                if blocks[curblk]['type'] != 'function' and (next_block['name'] == ""):
+                    # - 'name'
+                    next_block['name'] = m.group('fn_name').strip()
+                    # - 'cursor'
+                    cursor_current += len(self.regex_ln.findall(text, cursor_last_pos, m.start('fn_name')))
+                    cursor_last_pos = m.start('fn_name')
+                    # NOTE: cursor could be collected together with line_begin, line_end,
+                    # but we keep it here separately for easier debugging of file parsing problems
+                    next_block['cursor'] = cursor_current
+                    # - 'type'
+                    next_block['type'] = 'function'
+                    # - 'start' detected earlier
+            else:
+                assert(len("Unknown match by regular expression") == 0)
+
+        while indent_current > 0:
+            # log all
+            logging.warning("Non-matching opening bracket '{' detected")
+            count_mismatched_brackets += 1
+            indent_current -= 1
+
+        for (ind, each) in enumerate(blocks):
+            each = each # used
+            block = blocks[len(blocks) - 1 - ind]
+            self.finalize_block(text, block, len(text))
+
+        self.add_lines_data(text, blocks)
+        self.add_regions(data, blocks)
+        
+        return count_mismatched_brackets
+
+            

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

@@ -38,3 +38,6 @@ Options:
   --std.code.cs.files=STD.CODE.CS.FILES
                         Enumerates filename extensions to match C# files
                         [default: *.cs]
+  --std.code.java.files=STD.CODE.JAVA.FILES
+                        Enumerates filename extensions to match Java files
+                        [default: *.java]

+ 2 - 0
mainline/tests/general/test_basic/test_workflow_info_default_stdout.gold.txt

@@ -6,6 +6,8 @@ Properties:
 	std.code.cpp:files	=>	*.c,*.cc,*.cpp,*.cxx,*.h,*.hh,*.hpp,*.hxx
 	std.code.cs:version	=>	1.0
 	std.code.cs:files	=>	*.cs
+	std.code.java:version	=>	1.0
+	std.code.java:files	=>	*.java
 Namespaces:
 	std.code.complexity
 		- cyclomatic

+ 2 - 0
mainline/tests/general/test_basic/test_workflow_info_second_stdout.gold.txt

@@ -6,6 +6,8 @@ Properties:
 	std.code.cpp:files	=>	*.c,*.cc,*.cpp,*.cxx,*.h,*.hh,*.hpp,*.hxx
 	std.code.cs:version	=>	1.0
 	std.code.cs:files	=>	*.cs
+	std.code.java:version	=>	1.0
+	std.code.java:files	=>	*.java
 Namespaces:
 	std.code.complexity
 		- cyclomatic

+ 1 - 1
mainline/tests/general/test_basic/test_workflow_limit_default_stderr.gold.txt

@@ -1,4 +1,4 @@
 [LOG]: WARNING:	Logging enabled with INFO level
 [LOG]: INFO:	Processing: 
 [LOG]: INFO:	Applying limit: namespace 'std.code.complexity', filter '('cyclomatic', '>', 0.0)'
-[LOG]: WARNING:	Exit code: 4. Time spent: 0.01 seconds. Done
+[LOG]: WARNING:	Exit code: 4. Time spent: 0.0 seconds. Done

+ 1 - 0
mainline/tests/general/test_std_code_cs/sources/interface.cs

@@ -207,6 +207,7 @@ public class TextInfo : IDeserializationCallback
             }
 
     // Implement IDeserializationCallback.
+    [MethodImpl(MethodImplOptions.InternalCall)]
     void IDeserializationCallback.OnDeserialization(Object sender)
             {
                 // Nothing to do here.

+ 9 - 9
mainline/tests/general/test_std_code_cs/test_parser_export_files_stdout.gold.txt

@@ -558,10 +558,10 @@ data:
 .   .   .   .   info: 
 .   .   .   .   .   cursor="0"
 .   .   .   .   .   name="__global__"
-.   .   .   .   .   offset_end="6535"
+.   .   .   .   .   offset_end="6584"
 .   .   .   .   .   line_begin="1"
 .   .   .   .   .   type="global"
-.   .   .   .   .   line_end="218"
+.   .   .   .   .   line_end="219"
 .   .   .   .   .   offset_begin="0"
 .   .   .   .   data: 
 .   .   .   .   subregions:
@@ -594,10 +594,10 @@ data:
 .   .   .   .   .   .   info: 
 .   .   .   .   .   .   .   cursor="61"
 .   .   .   .   .   .   .   name="System.Globalization"
-.   .   .   .   .   .   .   offset_end="6499"
+.   .   .   .   .   .   .   offset_end="6548"
 .   .   .   .   .   .   .   line_begin="61"
 .   .   .   .   .   .   .   type="namespace"
-.   .   .   .   .   .   .   line_end="217"
+.   .   .   .   .   .   .   line_end="218"
 .   .   .   .   .   .   .   offset_begin="2040"
 .   .   .   .   .   .   data: 
 .   .   .   .   .   .   subregions:
@@ -606,10 +606,10 @@ data:
 .   .   .   .   .   .   .   .   info: 
 .   .   .   .   .   .   .   .   .   cursor="69"
 .   .   .   .   .   .   .   .   .   name="TextInfo"
-.   .   .   .   .   .   .   .   .   offset_end="6477"
+.   .   .   .   .   .   .   .   .   offset_end="6526"
 .   .   .   .   .   .   .   .   .   line_begin="69"
 .   .   .   .   .   .   .   .   .   type="class"
-.   .   .   .   .   .   .   .   .   line_end="215"
+.   .   .   .   .   .   .   .   .   line_end="216"
 .   .   .   .   .   .   .   .   .   offset_begin="2183"
 .   .   .   .   .   .   .   .   data: 
 .   .   .   .   .   .   .   .   subregions:
@@ -770,12 +770,12 @@ data:
 .   .   .   .   .   .   .   .   
 .   .   .   .   .   .   .   .   .   subregion:  
 .   .   .   .   .   .   .   .   .   .   info: 
-.   .   .   .   .   .   .   .   .   .   .   cursor="210"
+.   .   .   .   .   .   .   .   .   .   .   cursor="211"
 .   .   .   .   .   .   .   .   .   .   .   name="IDeserializationCallback.OnDeserialization"
-.   .   .   .   .   .   .   .   .   .   .   offset_end="6474"
+.   .   .   .   .   .   .   .   .   .   .   offset_end="6523"
 .   .   .   .   .   .   .   .   .   .   .   line_begin="209"
 .   .   .   .   .   .   .   .   .   .   .   type="function"
-.   .   .   .   .   .   .   .   .   .   .   line_end="213"
+.   .   .   .   .   .   .   .   .   .   .   line_end="214"
 .   .   .   .   .   .   .   .   .   .   .   offset_begin="6302"
 .   .   .   .   .   .   .   .   .   .   data:  
 .   .   .   .   .   .   .   .   .   .   .   std.code.complexity: 

+ 49 - 0
mainline/tests/general/test_std_code_java.py

@@ -0,0 +1,49 @@
+#
+#    Metrix++, Copyright 2009-2013, Metrix++ Project
+#    Link: http://metrixplusplus.sourceforge.net
+#    
+#    This file is a part of Metrix++ Tool.
+#    
+#    Metrix++ is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, version 3 of the License.
+#    
+#    Metrix++ is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#    GNU General Public License for more details.
+#    
+#    You should have received a copy of the GNU General Public License
+#    along with Metrix++.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+
+import unittest
+import os
+
+import tests.common
+
+class Test(tests.common.TestCase):
+
+    def test_parser(self):
+        
+        runner = tests.common.ToolRunner('collect', ['--std.code.complexity.on'])
+        self.assertExec(runner.run())
+
+        runner = tests.common.ToolRunner('export', ['--general.nest-regions'])
+        self.assertExec(runner.run())
+
+        dirs_list = [os.path.join('.', each) for each in os.listdir(self.get_content_paths().cwd)]
+        runner = tests.common.ToolRunner('export',
+                                         opts_list=['--general.nest-regions', '--general.format=txt'],
+                                         dirs_list=dirs_list,
+                                         prefix='files')
+        self.assertExec(runner.run())
+
+        runner = tests.common.ToolRunner('limit',
+                                         ['--general.max-limit=std.code.complexity:cyclomatic:5'],
+                                         exit_code=6)
+        self.assertExec(runner.run())
+
+if __name__ == '__main__':
+    unittest.main()

+ 24 - 0
mainline/tests/general/test_std_code_java/readme.txt

@@ -0,0 +1,24 @@
+#
+#    Metrix++, Copyright 2009-2013, Metrix++ Project
+#    Link: http://metrixplusplus.sourceforge.net
+#    
+#    This file is a part of Metrix++ Tool.
+#    
+#    Metrix++ is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, version 3 of the License.
+#    
+#    Metrix++ is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#    GNU General Public License for more details.
+#    
+#    You should have received a copy of the GNU General Public License
+#    along with Metrix++.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+===============================================================================
+
+NOTE: Some code samples are copied from other open source projects
+
+===============================================================================

+ 461 - 0
mainline/tests/general/test_std_code_java/sources/ArrayUtils.java

@@ -0,0 +1,461 @@
+package edu.stanford.nlp.util;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Static utility methods for operating on arrays.
+ *
+ * @author Huy Nguyen (htnguyen@cs.stanford.edu)
+ * @author Michel Galley (mgalley@stanford.edu)
+ */
+public class ArrayUtils {
+  /**
+   * Should not be instantiated
+   */
+  protected ArrayUtils() {
+  }
+
+  public static double[] flatten(double[][] array) {
+    int size = 0;
+    for (double[] a : array) {
+      size += a.length;
+    }
+    double[] newArray = new double[size];
+    int i = 0;
+    for (double[] a : array) {
+      for (double d : a) {
+        newArray[i++] = d;
+      }
+    }
+    return newArray;
+  }
+
+  public static double[][] to2D(double[] array, int dim1Size) {
+    int dim2Size = array.length/dim1Size;
+    return to2D(array, dim1Size, dim2Size);
+  }
+
+  public static double[][] to2D(double[] array, int dim1Size, int dim2Size) {
+    double[][] newArray = new double[dim1Size][dim2Size];
+    int k = 0;
+    for (int i = 0; i < newArray.length; i++) {
+      for (int j = 0; j < newArray[i].length; j++) {
+        newArray[i][j] = array[k++];
+      }
+    }
+    return newArray;
+  }
+
+  /**
+   * Removes the element at the specified index from the array, and returns
+   * a new array containing the remaining elements.  If <tt>index</tt> is
+   * invalid, returns <tt>array</tt> unchanged.
+   */
+  public static double[] removeAt(double[] array, int index) {
+    if (array == null) {
+      return null;
+    }
+    if (index < 0 || index >= array.length) {
+      return array;
+    }
+
+    double[] retVal = new double[array.length - 1];
+    for (int i = 0; i < array.length; i++) {
+      if (i < index) {
+        retVal[i] = array[i];
+      } else if (i > index) {
+        retVal[i - 1] = array[i];
+      }
+    }
+    return retVal;
+  }
+
+  /**
+   * Removes the element at the specified index from the array, and returns
+   * a new array containing the remaining elements.  If <tt>index</tt> is
+   * invalid, returns <tt>array</tt> unchanged.  Uses reflection to determine
+   * the type of the array and returns an array of the appropriate type.
+   */
+  public static Object[] removeAt(Object[] array, int index) {
+    if (array == null) {
+      return null;
+    }
+    if (index < 0 || index >= array.length) {
+      return array;
+    }
+
+    Object[] retVal = (Object[]) Array.newInstance(array[0].getClass(), array.length - 1);
+    for (int i = 0; i < array.length; i++) {
+      if (i < index) {
+        retVal[i] = array[i];
+      } else if (i > index) {
+        retVal[i - 1] = array[i];
+      }
+    }
+    return retVal;
+  }
+
+  public static String toString(int[][] a) {
+    StringBuilder result = new StringBuilder("[");
+    for (int i = 0; i < a.length; i++) {
+      result.append(Arrays.toString(a[i]));
+      if(i < a.length-1)
+        result.append(",");
+      }
+    result.append("]");
+    return result.toString();
+  }
+
+  /**
+   * Tests two int[][] arrays for having equal contents.
+   * @param xs
+   * @param ys
+   * @return true iff for each i, <code>equalContents(xs[i],ys[i])</code> is true
+   */
+  public static boolean equalContents(int[][] xs, int[][] ys) {
+    if(xs == null && ys != null)
+      return false;
+    if(ys == null)
+      return false;
+    if(xs.length != ys.length)
+      return false;
+    for(int i = xs.length-1; i >= 0; i--) {
+      if(! equalContents(xs[i],ys[i]))
+        return false;
+    }
+    return true;
+  }
+
+  /**
+   * Tests two double[][] arrays for having equal contents.
+   * @param xs
+   * @param ys
+   * @return true iff for each i, <code>equals(xs[i],ys[i])</code> is true
+   */
+  public static boolean equals(double[][] xs, double[][] ys) {
+    if(xs == null && ys != null)
+      return false;
+    if(ys == null)
+      return false;
+    if(xs.length != ys.length)
+      return false;
+    for(int i = xs.length-1; i >= 0; i--) {
+      if(!Arrays.equals(xs[i],ys[i]))
+        return false;
+    }
+    return true;
+  }
+
+  
+  /**
+   * tests two int[] arrays for having equal contents
+   * @param xs
+   * @param ys
+   * @return true iff xs and ys have equal length, and for each i, <code>xs[i]==ys[i]</code>
+   */
+  public static boolean equalContents(int[] xs, int[] ys) {
+    if(xs.length != ys.length)
+      return false;
+    for(int i = xs.length-1; i >= 0; i--) {
+      if(xs[i] != ys[i])
+        return false;
+    }
+    return true;
+  }
+
+  /**
+   * Tests two boolean[][] arrays for having equal contents.
+   * @param xs
+   * @param ys
+   * @return true iff for each i, <code>Arrays.equals(xs[i],ys[i])</code> is true
+   */
+  public static boolean equals(boolean[][] xs, boolean[][] ys) {
+    if(xs == null && ys != null)
+      return false;
+    if(ys == null)
+      return false;
+    if(xs.length != ys.length)
+      return false;
+    for(int i = xs.length-1; i >= 0; i--) {
+      if(! Arrays.equals(xs[i],ys[i]))
+        return false;
+    }
+    return true;
+  }
+
+
+  /** Returns true iff object o equals (not ==) some element of array a. */
+  public static <T> boolean contains(T[] a, T o) {
+    for (T item : a) {
+      if (item.equals(o)) return true;
+    }
+    return false;
+  }
+
+  /** Return a set containing the same elements as the specified array.
+   */
+  public static <T> Set<T> asSet(T[] a) {
+    return new HashSet<T>(Arrays.asList(a));
+  }
+
+  public static void fill(double[][] d, double val) {
+    for (int i = 0; i < d.length; i++) {
+      Arrays.fill(d[i], val);
+    }
+  }
+
+  public static void fill(double[][][] d, double val) {
+    for (int i = 0; i < d.length; i++) {
+      fill(d[i], val);
+    }
+  }
+
+  public static void fill(double[][][][] d, double val) {
+    for (int i = 0; i < d.length; i++) {
+      fill(d[i], val);
+    }
+  }
+
+  public static void fill(boolean[][] d, boolean val) {
+    for (int i = 0; i < d.length; i++) {
+      Arrays.fill(d[i], val);
+    }
+  }
+
+  public static void fill(boolean[][][] d, boolean val) {
+    for (int i = 0; i < d.length; i++) {
+      fill(d[i], val);
+    }
+  }
+
+  public static void fill(boolean[][][][] d, boolean val) {
+    for (int i = 0; i < d.length; i++) {
+      fill(d[i], val);
+    }
+  }
+
+
+
+  /**
+  * Casts to a double array
+  */
+  public static double[] toDouble(float[] a) {
+    double[] d = new double[a.length];
+    for (int i = 0; i < a.length; i++) {
+      d[i] = a[i];
+    }
+    return d;
+  }
+
+  /**
+   * Casts to a double array.
+   */
+  public static double[] toDouble(int[] array) {
+    double[] rv = new double[array.length];
+    for (int i = 0; i < array.length; i++) {
+      rv[i] = array[i];
+    }
+    return rv;
+  }
+  
+  /** needed because Arrays.asList() won't to autoboxing,
+   * so if you give it a primitive array you get a
+   * singleton list back with just that array as an element.
+   */
+  public static List<Integer> asList(int[] array) {
+    List<Integer> l = new ArrayList<Integer>();
+    for (int i : array) {
+      l.add(i);
+    }
+    return l;
+  }
+
+  public static double[] asArray(List<Double> d) {
+    double[] newD = new double[d.size()];
+    int i = 0;
+    for (Double j : d) {
+      newD[i++] = j;
+    }
+    return newD;
+  }
+
+  
+  /**
+   * For internal debugging purposes only
+   */
+  public static void main(String[] args) {
+    String[] strings = new String[]{"a", "b", "c"};
+    strings = (String[]) ArrayUtils.removeAt(strings, 2);
+    for (String string : strings) {
+      System.err.println(string);
+    }
+
+    System.err.println(asSet(new String[] {"larry", "moe", "curly"}));
+  }
+
+  public static int[] copy(int[] i) {
+    if (i == null) { return null; }
+    int[] newI = new int[i.length];
+    System.arraycopy(i, 0, newI, 0, i.length);
+    return newI;
+  }
+
+  public static int[][] copy(int[][] i) {
+    if (i == null) { return null; }
+    int[][] newI = new int[i.length][];
+    for (int j = 0; j < newI.length; j++) {
+      newI[j] = copy(i[j]);
+    }
+    return newI;
+  }
+
+  
+  public static double[] copy(double[] d) {
+    if (d == null) { return null; }
+    double[] newD = new double[d.length];
+    System.arraycopy(d, 0, newD, 0, d.length);
+    return newD;
+  }
+  
+  public static double[][] copy(double[][] d) {
+    if (d == null) { return null; }
+    double[][] newD = new double[d.length][];
+    for (int i = 0; i < newD.length; i++) {
+      newD[i] = copy(d[i]);
+    }
+    return newD;
+  }
+
+  public static double[][][] copy(double[][][] d) {
+    if (d == null) { return null; }
+    double[][][] newD = new double[d.length][][];
+    for (int i = 0; i < newD.length; i++) {
+      newD[i] = copy(d[i]);
+    }
+    return newD;
+  }
+
+  public static float[] copy(float[] d) {
+    if (d == null) { return null; }
+    float[] newD = new float[d.length];
+    System.arraycopy(d, 0, newD, 0, d.length);
+    return newD;
+  }
+  
+  public static float[][] copy(float[][] d) {
+    if (d == null) { return null; }
+    float[][] newD = new float[d.length][];
+    for (int i = 0; i < newD.length; i++) {
+      newD[i] = copy(d[i]);
+    }
+    return newD;
+  }
+
+  public static float[][][] copy(float[][][] d) {
+    if (d == null) { return null; }
+    float[][][] newD = new float[d.length][][];
+    for (int i = 0; i < newD.length; i++) {
+      newD[i] = copy(d[i]);
+    }
+    return newD;
+  }
+
+  
+  public static String toString(boolean[][] b) {
+    String result = "[";
+    for (int i = 0; i < b.length; i++) {
+      result += Arrays.toString(b[i]);
+      if(i < b.length-1)
+        result += ",";
+      }
+    result += "]";
+    return result;
+  }
+
+  public static long[] toPrimitive(Long[] in) {
+    return toPrimitive(in,0L);
+  }
+
+  public static int[] toPrimitive(Integer[] in) {
+    return toPrimitive(in,0);
+  }
+
+  public static short[] toPrimitive(Short[] in) {
+    return toPrimitive(in,(short)0);
+  }
+
+  public static char[] toPrimitive(Character[] in) {
+    return toPrimitive(in,(char)0);
+  }
+
+  public static double[] toPrimitive(Double[] in) {
+    return toPrimitive(in,0.0);
+  }
+
+  public static long[] toPrimitive(Long[] in, long valueForNull) {
+    if (in == null)
+      return null;
+    final long[] out = new long[in.length];
+    for (int i = 0; i < in.length; i++) {
+      Long b = in[i];
+      out[i] = (b == null ? valueForNull : b);
+    }
+    return out;
+  }
+
+  public static int[] toPrimitive(Integer[] in, int valueForNull) {
+    if (in == null)
+      return null;
+    final int[] out = new int[in.length];
+    for (int i = 0; i < in.length; i++) {
+      Integer b = in[i];
+      out[i] = (b == null ? valueForNull : b);
+    }
+    return out;
+  }
+
+   public static short[] toPrimitive(Short[] in, short valueForNull) {
+    if (in == null)
+      return null;
+    final short[] out = new short[in.length];
+    for (int i = 0; i < in.length; i++) {
+      Short b = in[i];
+      out[i] = (b == null ? valueForNull : b);
+    }
+    return out;
+  }
+
+   public static char[] toPrimitive(Character[] in, char valueForNull) {
+    if (in == null)
+      return null;
+    final char[] out = new char[in.length];
+    for (int i = 0; i < in.length; i++) {
+      Character b = in[i];
+      out[i] = (b == null ? valueForNull : b);
+    }
+    return out;
+  }
+
+  public static double[] toPrimitive(Double[] in, double valueForNull) {
+    if (in == null)
+      return null;
+    final double[] out = new double[in.length];
+    for (int i = 0; i < in.length; i++) {
+      Double b = in[i];
+      out[i] = (b == null ? valueForNull : b);
+    }
+    return out;
+  }
+}
+
+package example.serverscript.connector;
+
+public interface Interface extends java.rmi.Remote {
+    public java.lang.String request(java.lang.String string_1, java.lang.String string_2)
+        throws java.rmi.RemoteException;
+}

+ 518 - 0
mainline/tests/general/test_std_code_java/sources/BinaryHeapPriorityQueue.java

@@ -0,0 +1,518 @@
+package edu.stanford.nlp.util;
+
+import java.util.*;
+
+/**
+ * PriorityQueue with explicit double priority values.  Larger doubles are higher priorities.  BinaryHeap-backed.
+ *
+ * @author Dan Klein
+ * @author Christopher Manning
+ *         For each entry, uses ~ 24 (entry) + 16? (Map.Entry) + 4 (List entry) = 44 bytes?
+ */
+public class BinaryHeapPriorityQueue<E> extends AbstractSet<E> implements PriorityQueue<E>, Iterator<E> {
+
+  /**
+   * An <code>Entry</code> stores an object in the queue along with
+   * its current location (array position) and priority.
+   * uses ~ 8 (self) + 4 (key ptr) + 4 (index) + 8 (priority) = 24 bytes?
+   */
+  private static final class Entry<E> {
+    public E key;
+    public int index;
+    public double priority;
+
+    @Override
+    public String toString() {
+      return key + " at " + index + " (" + priority + ")";
+    }
+  }
+
+  public boolean hasNext() {
+    return size() > 0;
+  }
+
+  public E next() {
+    return removeFirst();
+  }
+
+  public void remove() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * <code>indexToEntry</code> maps linear array locations (not
+   * priorities) to heap entries.
+   */
+  private List<Entry<E>> indexToEntry;
+
+  /**
+   * <code>keyToEntry</code> maps heap objects to their heap
+   * entries.
+   */
+  private Map<Object,Entry<E>> keyToEntry;
+
+  private Entry<E> parent(Entry<E> entry) {
+    int index = entry.index;
+    return (index > 0 ? getEntry((index - 1) / 2) : null);
+  }
+
+  private Entry<E> leftChild(Entry<E> entry) {
+    int leftIndex = entry.index * 2 + 1;
+    return (leftIndex < size() ? getEntry(leftIndex) : null);
+  }
+
+  private Entry<E> rightChild(Entry<E> entry) {
+    int index = entry.index;
+    int rightIndex = index * 2 + 2;
+    return (rightIndex < size() ? getEntry(rightIndex) : null);
+  }
+
+  private int compare(Entry<E> entryA, Entry<E> entryB) {
+    return compare(entryA.priority, entryB.priority);
+  }
+
+  private static int compare(double a, double b) {
+    double diff = a - b;
+    if (diff > 0.0) {
+      return 1;
+    }
+    if (diff < 0.0) {
+      return -1;
+    }
+    return 0;
+  }
+
+  /**
+   * Structural swap of two entries.
+   *
+   * @param entryA
+   * @param entryB
+   */
+  private void swap(Entry<E> entryA, Entry<E> entryB) {
+    int indexA = entryA.index;
+    int indexB = entryB.index;
+    entryA.index = indexB;
+    entryB.index = indexA;
+    indexToEntry.set(indexA, entryB);
+    indexToEntry.set(indexB, entryA);
+  }
+
+  /**
+   * Remove the last element of the heap (last in the index array).
+   */
+  private void removeLastEntry() {
+    Entry<E> entry = indexToEntry.remove(size() - 1);
+    keyToEntry.remove(entry.key);
+  }
+
+  /**
+   * Get the entry by key (null if none).
+   */
+  private Entry<E> getEntry(E key) {
+    return keyToEntry.get(key);
+  }
+
+  /**
+   * Get entry by index, exception if none.
+   */
+  private Entry<E> getEntry(int index) {
+    Entry<E> entry = indexToEntry.get(index);
+    return entry;
+  }
+
+  private Entry<E> makeEntry(E key) {
+    Entry<E> entry = new Entry<E>();
+    entry.index = size();
+    entry.key = key;
+    entry.priority = Double.NEGATIVE_INFINITY;
+    indexToEntry.add(entry);
+    keyToEntry.put(key, entry);
+    return entry;
+  }
+
+  /**
+   * iterative heapify up: move item o at index up until correctly placed
+   */
+  private void heapifyUp(Entry<E> entry) {
+    while (true) {
+      if (entry.index == 0) {
+        break;
+      }
+      Entry<E> parentEntry = parent(entry);
+      if (compare(entry, parentEntry) <= 0) {
+        break;
+      }
+      swap(entry, parentEntry);
+    }
+  }
+
+  /**
+   * On the assumption that
+   * leftChild(entry) and rightChild(entry) satisfy the heap property,
+   * make sure that the heap at entry satisfies this property by possibly
+   * percolating the element o downwards.  I've replaced the obvious
+   * recursive formulation with an iterative one to gain (marginal) speed
+   */
+  private void heapifyDown(Entry<E> entry) {
+    Entry<E> currentEntry = entry;
+    Entry<E> bestEntry; // initialized below
+
+    do {
+      bestEntry = currentEntry;
+
+      Entry<E> leftEntry = leftChild(currentEntry);
+      if (leftEntry != null) {
+        if (compare(bestEntry, leftEntry) < 0) {
+          bestEntry = leftEntry;
+        }
+      }
+
+      Entry<E> rightEntry = rightChild(currentEntry);
+      if (rightEntry != null) {
+        if (compare(bestEntry, rightEntry) < 0) {
+          bestEntry = rightEntry;
+        }
+      }
+
+      if (bestEntry != currentEntry) {
+        // Swap min and current
+        swap(bestEntry, currentEntry);
+        // at start of next loop, we set currentIndex to largestIndex
+        // this indexation now holds current, so it is unchanged
+      }
+    } while (bestEntry != currentEntry);
+    // System.err.println("Done with heapify down");
+    // verify();
+  }
+
+  private void heapify(Entry<E> entry) {
+    heapifyUp(entry);
+    heapifyDown(entry);
+  }
+
+
+  /**
+   * Finds the object with the highest priority, removes it,
+   * and returns it.
+   *
+   * @return the object with highest priority
+   */
+  public E removeFirst() {
+    E first = getFirst();
+    remove(first);
+    return first;
+  }
+
+  /**
+   * Finds the object with the highest priority and returns it, without
+   * modifying the queue.
+   *
+   * @return the object with minimum key
+   */
+  public E getFirst() {
+    if (isEmpty()) {
+      throw new NoSuchElementException();
+    }
+    return getEntry(0).key;
+  }
+
+  /**
+   * Gets the priority of the highest-priority element of the queue.
+   */
+  public double getPriority() {
+    if (isEmpty()) {
+      throw new NoSuchElementException();
+    }
+    return getEntry(0).priority;
+  }
+
+  /**
+   * Searches for the object in the queue and returns it.  May be useful if
+   * you can create a new object that is .equals() to an object in the queue
+   * but is not actually identical, or if you want to modify an object that is
+   * in the queue.
+   * @return null if the object is not in the queue, otherwise returns the
+   * object.
+   */
+  public E getObject(E key) {
+    if ( ! contains(key)) return null;
+    Entry<E> e = getEntry(key);
+    return e.key;
+  }
+
+  /**
+   * Get the priority of a key -- if the key is not in the queue, Double.NEGATIVE_INFINITY is returned.
+   *
+   * @param key
+   * @return
+   */
+  public double getPriority(E key) {
+    Entry<E> entry = getEntry(key);
+    if (entry == null) {
+      return Double.NEGATIVE_INFINITY;
+    }
+    return entry.priority;
+  }
+
+  /**
+   * Adds an object to the queue with the minimum priority
+   * (Double.NEGATIVE_INFINITY).  If the object is already in the queue
+   * with worse priority, this does nothing.  If the object is
+   * already present, with better priority, it will NOT cause an
+   * a decreasePriority.
+   *
+   * @param key an <code>Object</code> value
+   * @return whether the key was present before
+   */
+  @Override
+  public boolean add(E key) {
+    if (contains(key)) {
+      return false;
+    }
+    makeEntry(key);
+    return true;
+  }
+
+  /**
+   * Convenience method for if you want to pretend relaxPriority doesn't exist, or if you really want add's return conditions.
+   */
+  public boolean add(E key, double priority) {
+//    System.err.println("Adding " + key + " with priority " + priority);
+    if (add(key)) {
+      relaxPriority(key, priority);
+      return true;
+    }
+    return false;
+  }
+
+
+  @Override
+  public boolean remove(Object key) {
+    E eKey = (E) key;
+    Entry<E> entry = getEntry(eKey);
+    if (entry == null) {
+      return false;
+    }
+    removeEntry(entry);
+    return true;
+  }
+
+  private void removeEntry(Entry<E> entry) {
+    Entry<E> lastEntry = getLastEntry();
+    if (entry != lastEntry) {
+      swap(entry, lastEntry);
+      removeLastEntry();
+      heapify(lastEntry);
+    } else {
+      removeLastEntry();
+    }
+  }
+
+  private Entry<E> getLastEntry() {
+    return getEntry(size() - 1);
+  }
+
+  /**
+   * Promotes a key in the queue, adding it if it wasn't there already.  If the specified priority is worse than the current priority, nothing happens.  Faster than add if you don't care about whether the key is new.
+   *
+   * @param key an <code>Object</code> value
+   * @return whether the priority actually improved.
+   */
+  public boolean relaxPriority(E key, double priority) {
+    Entry<E> entry = getEntry(key);
+    if (entry == null) {
+      entry = makeEntry(key);
+    }
+    if (compare(priority, entry.priority) <= 0) {
+      return false;
+    }
+    entry.priority = priority;
+    heapifyUp(entry);
+    return true;
+  }
+
+  /**
+   * Demotes a key in the queue, adding it if it wasn't there already.  If the specified priority is better than the current priority, nothing happens.  If you decrease the priority on a non-present key, it will get added, but at it's old implicit priority of Double.NEGATIVE_INFINITY.
+   *
+   * @param key an <code>Object</code> value
+   * @return whether the priority actually improved.
+   */
+  public boolean decreasePriority(E key, double priority) {
+    Entry<E> entry = getEntry(key);
+    if (entry == null) {
+      entry = makeEntry(key);
+    }
+    if (compare(priority, entry.priority) >= 0) {
+      return false;
+    }
+    entry.priority = priority;
+    heapifyDown(entry);
+    return true;
+  }
+
+  /**
+   * Changes a priority, either up or down, adding the key it if it wasn't there already.
+   *
+   * @param key an <code>Object</code> value
+   * @return whether the priority actually changed.
+   */
+  public boolean changePriority(E key, double priority) {
+    Entry<E> entry = getEntry(key);
+    if (entry == null) {
+      entry = makeEntry(key);
+    }
+    if (compare(priority, entry.priority) == 0) {
+      return false;
+    }
+    entry.priority = priority;
+    heapify(entry);
+    return true;
+  }
+
+  /**
+   * Checks if the queue is empty.
+   *
+   * @return a <code>boolean</code> value
+   */
+  @Override
+  public boolean isEmpty() {
+    return indexToEntry.isEmpty();
+  }
+
+  /**
+   * Get the number of elements in the queue.
+   *
+   * @return queue size
+   */
+  @Override
+  public int size() {
+    return indexToEntry.size();
+  }
+
+  /**
+   * Returns whether the queue contains the given key.
+   */
+  @Override
+  public boolean contains(Object key) {
+    return keyToEntry.containsKey(key);
+  }
+
+  public List<E> toSortedList() {
+    List<E> sortedList = new ArrayList<E>(size());
+    BinaryHeapPriorityQueue<E> queue = this.deepCopy();
+    while (!queue.isEmpty()) {
+      sortedList.add(queue.removeFirst());
+    }
+    return sortedList;
+  }
+
+  public BinaryHeapPriorityQueue<E> deepCopy(MapFactory<Object, Entry<E>> mapFactory) {
+    BinaryHeapPriorityQueue<E> queue =
+      new BinaryHeapPriorityQueue<E>(mapFactory);
+    for (Entry<E> entry : keyToEntry.values()) {
+      queue.relaxPriority(entry.key, entry.priority);
+    }
+    return queue;
+  }
+
+  public BinaryHeapPriorityQueue<E> deepCopy() {
+    return deepCopy(MapFactory.HASH_MAP_FACTORY);
+  }
+
+  @Override
+  public Iterator<E> iterator() {
+    return Collections.unmodifiableCollection(toSortedList()).iterator();
+  }
+
+  /**
+   * Clears the queue.
+   */
+  @Override
+  public void clear() {
+    indexToEntry.clear();
+    keyToEntry.clear();
+  }
+
+  //  private void verify() {
+  //    for (int i = 0; i < indexToEntry.size(); i++) {
+  //      if (i != 0) {
+  //        // check ordering
+  //        if (compare(getEntry(i), parent(getEntry(i))) < 0) {
+  //          System.err.println("Error in the ordering of the heap! ("+i+")");
+  //          System.exit(0);
+  //        }
+  //      }
+  //      // check placement
+  //      if (i != ((Entry)indexToEntry.get(i)).index)
+  //        System.err.println("Error in placement in the heap!");
+  //    }
+  //  }
+
+  @Override
+  public String toString() {
+    return toString(0);
+  }
+
+  /** {@inheritDoc} */
+  public String toString(int maxKeysToPrint) {
+    if (maxKeysToPrint <= 0) maxKeysToPrint = Integer.MAX_VALUE;
+    List<E> sortedKeys = toSortedList();
+    StringBuilder sb = new StringBuilder("[");
+    for (int i = 0; i < maxKeysToPrint && i < sortedKeys.size(); i++) {
+      E key = sortedKeys.get(i);
+      sb.append(key).append("=").append(getPriority(key));
+      if (i < maxKeysToPrint - 1 && i < sortedKeys.size() - 1) {
+        sb.append(", ");
+      }
+    }
+    sb.append("]");
+    return sb.toString();
+  }
+
+  public String toVerticalString() {
+    List<E> sortedKeys = toSortedList();
+    StringBuilder sb = new StringBuilder();
+    for (Iterator<E> keyI = sortedKeys.iterator(); keyI.hasNext();) {
+      E key = keyI.next();
+      sb.append(key);
+      sb.append("\t");
+      sb.append(getPriority(key));
+      if (keyI.hasNext()) {
+        sb.append("\n");
+      }
+    }
+    return sb.toString();
+  }
+
+
+  public BinaryHeapPriorityQueue() {
+    this(MapFactory.HASH_MAP_FACTORY);
+  }
+
+  public BinaryHeapPriorityQueue(MapFactory<Object, Entry<E>> mapFactory) {
+    indexToEntry = new ArrayList<Entry<E>>();
+    keyToEntry = mapFactory.newMap();
+  }
+
+  public static void main(String[] args) {
+    BinaryHeapPriorityQueue<String> queue =
+      new BinaryHeapPriorityQueue<String>();
+    queue.add("a", 1.0);
+    System.out.println("Added a:1 " + queue);
+    queue.add("b", 2.0);
+    System.out.println("Added b:2 " + queue);
+    queue.add("c", 1.5);
+    System.out.println("Added c:1.5 " + queue);
+    queue.relaxPriority("a", 3.0);
+    System.out.println("Increased a to 3 " + queue);
+    queue.decreasePriority("b", 0.0);
+    System.out.println("Decreased b to 0 " + queue);
+    System.out.println("removeFirst()=" + queue.removeFirst());
+    System.out.println("queue=" + queue);
+    System.out.println("removeFirst()=" + queue.removeFirst());
+    System.out.println("queue=" + queue);
+    System.out.println("removeFirst()=" + queue.removeFirst());
+    System.out.println("queue=" + queue);
+  }
+
+}

+ 231 - 0
mainline/tests/general/test_std_code_java/sources/Generics.java

@@ -0,0 +1,231 @@
+package edu.stanford.nlp.util;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.Stack;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+import edu.stanford.nlp.util.concurrent.SynchronizedInterner;
+
+/**
+ * A collection of utilities to make dealing with Java generics less
+ * painful and verbose.  For example, rather than declaring
+ * 
+ * <pre>
+ * {@code Map<String, List<Pair<IndexedWord, GrammaticalRelation>>> = new HashMap<String, List<Pair<IndexedWord, GrammaticalRelation>>>()}
+ * </pre>
+ * 
+ * you just call <code>Generics.newHashMap()</code>:
+ * 
+ * <pre>
+ * {@code Map<String, List<Pair<IndexedWord, GrammaticalRelation>>> = Generics.newHashMap()}
+ * </pre>
+ *
+ * Java type-inference will almost always just <em>do the right thing</em>
+ * (every once in a while, the compiler will get confused before you do,
+ * so you might still occasionally have to specify the appropriate types).
+ * 
+ * This class is based on the examples in Brian Goetz's article
+ * <a href="http://www.ibm.com/developerworks/library/j-jtp02216.html">Java
+ * theory and practice: The pseudo-typedef antipattern</a>. 
+ *
+ * @author Ilya Sherman
+ */
+public class Generics {
+
+  /* Collections */
+  public static <E> ArrayList<E> newArrayList() {
+    return new ArrayList<E>();
+  }
+  
+  public static <E> ArrayList<E> newArrayList(int size) {
+    return new ArrayList<E>(size);
+  }
+  
+  public static <E> ArrayList<E> newArrayList(Collection<? extends E> c) {
+    return new ArrayList<E>(c);
+  }
+  
+  public static <E> LinkedList<E> newLinkedList() {
+    return new LinkedList<E>();
+  }
+  
+  public static <E> LinkedList<E> newLinkedList(Collection<? extends E> c) {
+    return new LinkedList<E>(c);
+  }
+
+  public static <E> HashSet<E> newHashSet() {
+    return new HashSet<E>();
+  }
+
+  public static <E> HashSet<E> newHashSet(int initialCapacity) {
+    return new HashSet<E>(initialCapacity);
+  }
+  
+  public static <E> HashSet<E> newHashSet(Collection<? extends E> c) {
+    return new HashSet<E>(c);
+  }
+  
+  public static <E> TreeSet<E> newTreeSet() {
+    return new TreeSet<E>();
+  }
+  
+  public static <E> TreeSet<E> newTreeSet(Comparator<? super E> comparator) {
+    return new TreeSet<E>(comparator);
+  }
+  
+  public static <E> TreeSet<E> newTreeSet(SortedSet<E> s) {
+    return new TreeSet<E>(s);
+  }
+  
+  public static <E> Stack<E> newStack() {
+    return new Stack<E>();
+  }
+  
+  public static <E> BinaryHeapPriorityQueue<E> newBinaryHeapPriorityQueue() {
+    return new BinaryHeapPriorityQueue<E>();
+  }
+
+  
+  /* Maps */
+  public static <K,V> HashMap<K,V> newHashMap() {
+    return new HashMap<K,V>();
+  }
+  
+  public static <K,V> HashMap<K,V> newHashMap(int initialCapacity) {
+    return new HashMap<K,V>(initialCapacity);
+  }
+  
+  public static <K,V> HashMap<K,V> newHashMap(Map<? extends K,? extends V> m) {
+    return new HashMap<K,V>(m);
+  }
+  
+  public static <K,V> WeakHashMap<K,V> newWeakHashMap() {
+    return new WeakHashMap<K,V>();
+  }
+  
+  public static <K,V> ConcurrentHashMap<K,V> newConcurrentHashMap() {
+    return new ConcurrentHashMap<K,V>();
+  }
+  
+  public static <K,V> ConcurrentHashMap<K,V> newConcurrentHashMap(int initialCapacity) {
+    return new ConcurrentHashMap<K,V>(initialCapacity);
+  }
+  
+  public static <K,V> ConcurrentHashMap<K,V> newConcurrentHashMap(int initialCapacity,
+      float loadFactor, int concurrencyLevel) {
+    return new ConcurrentHashMap<K,V>(initialCapacity, loadFactor, concurrencyLevel);
+  }
+  
+  public static <K,V> TreeMap<K,V> newTreeMap() {
+    return new TreeMap<K,V>();
+  }
+  
+  public static <E> Index<E> newIndex() {
+    return new Index<E>();
+  }
+  
+  
+  /* Other */
+  public static <T1,T2> Pair<T1,T2> newPair(T1 first, T2 second) {
+    return new Pair<T1,T2>(first, second);
+  }
+
+  public static <T1,T2, T3> Triple<T1,T2, T3> newTriple(T1 first, T2 second, T3 third) {
+    return new Triple<T1,T2, T3>(first, second, third);
+  }
+
+  public static <T> Interner<T> newInterner() {
+    return new Interner<T>();
+  }
+  
+  public static <T> SynchronizedInterner<T> newSynchronizedInterner(Interner<T> interner) {
+    return new SynchronizedInterner<T>(interner);
+  }
+  
+  public static <T> SynchronizedInterner<T> newSynchronizedInterner(Interner<T> interner,
+                                                                    Object mutex) {
+    return new SynchronizedInterner<T>(interner, mutex);
+  }
+  
+  public static <T> WeakReference<T> newWeakReference(T referent) {
+    return new WeakReference<T>(referent);
+  }
+}
+
+
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.test.codegen;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ *
+ * @author Martin Matula
+ */
+public class Generics<T extends Collection> extends java.util.AbstractList<T> implements List<T> {
+    private final List<T> inner;
+
+    /** Creates a new instance of Generics */
+    public Generics(List<T> innerList) {
+        inner = innerList;
+    }
+
+    public T get(int index) {
+        return inner.get(index);
+    }
+
+    public int size() {
+        return inner.size();
+    }
+}

+ 0 - 0
mainline/tests/general/test_std_code_java/test_parser_collect_default_stdout.gold.txt


+ 17 - 0
mainline/tests/general/test_std_code_java/test_parser_export_default_stdout.gold.txt

@@ -0,0 +1,17 @@
+<export>
+
+    <data>
+        <info path="" id="1" />
+        <file-data />
+        <subfiles>
+        </subfiles>
+        <subdirs>
+            <subdir>.</subdir>
+        </subdirs>
+        <aggregated-data>
+            <std.code.complexity>
+                <cyclomatic max="6" total="126.0" avg="1.06779661017" min="0" />
+            </std.code.complexity>
+        </aggregated-data>
+    </data>
+</export>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1817 - 0
mainline/tests/general/test_std_code_java/test_parser_export_files_stdout.gold.txt


+ 48 - 0
mainline/tests/general/test_std_code_java/test_parser_limit_default_stdout.gold.txt

@@ -0,0 +1,48 @@
+./ArrayUtils.java:59: warning: Metric 'std.code.complexity/cyclomatic' for region 'removeAt' exceeds the limit.
+	Metric name    : std.code.complexity/cyclomatic
+	Region name    : removeAt
+	Metric value   : 6
+	Modified       : None
+	Change trend   : None
+	Limit          : 5.0
+
+./ArrayUtils.java:84: warning: Metric 'std.code.complexity/cyclomatic' for region 'removeAt' exceeds the limit.
+	Metric name    : std.code.complexity/cyclomatic
+	Region name    : removeAt
+	Metric value   : 6
+	Modified       : None
+	Change trend   : None
+	Limit          : 5.0
+
+./ArrayUtils.java:120: warning: Metric 'std.code.complexity/cyclomatic' for region 'equalContents' exceeds the limit.
+	Metric name    : std.code.complexity/cyclomatic
+	Region name    : equalContents
+	Metric value   : 6
+	Modified       : None
+	Change trend   : None
+	Limit          : 5.0
+
+./ArrayUtils.java:140: warning: Metric 'std.code.complexity/cyclomatic' for region 'equals' exceeds the limit.
+	Metric name    : std.code.complexity/cyclomatic
+	Region name    : equals
+	Metric value   : 6
+	Modified       : None
+	Change trend   : None
+	Limit          : 5.0
+
+./ArrayUtils.java:177: warning: Metric 'std.code.complexity/cyclomatic' for region 'equals' exceeds the limit.
+	Metric name    : std.code.complexity/cyclomatic
+	Region name    : equals
+	Metric value   : 6
+	Modified       : None
+	Change trend   : None
+	Limit          : 5.0
+
+./BinaryHeapPriorityQueue.java:156: warning: Metric 'std.code.complexity/cyclomatic' for region 'heapifyDown' exceeds the limit.
+	Metric name    : std.code.complexity/cyclomatic
+	Region name    : heapifyDown
+	Metric value   : 6
+	Modified       : None
+	Change trend   : None
+	Limit          : 5.0
+