CMake: cleanup
[blender.git] / build_files / cmake / clang_array_check.py
index df45648f975e243f3ccf97761264637f89d6cd61..6eaaebce52fc187af94ab9825b74dc5c00260db2 100644 (file)
@@ -19,12 +19,16 @@ Invocation:
 
 """
 
+# delay parsing functions until we need them
+USE_LAZY_INIT = True
+USE_EXACT_COMPARE = False
+
 # -----------------------------------------------------------------------------
 # predefined function/arg sizes, handy sometimes, but not complete...
 
 defs_precalc = {
-    "glColor3bv":  {0: 3},
-    "glColor4bv":  {0: 4},
+    "glColor3bv": {0: 3},
+    "glColor4bv": {0: 4},
 
     "glColor3ubv": {0: 3},
     "glColor4ubv": {0: 4},
@@ -32,12 +36,12 @@ defs_precalc = {
     "glColor4usv": {0: 3},
     "glColor4usv": {0: 4},
 
-    "glColor3fv":  {0: 3},
-    "glColor4fv":  {0: 4},
+    "glColor3fv": {0: 3},
+    "glColor4fv": {0: 4},
+
+    "glColor3dv": {0: 3},
+    "glColor4dv": {0: 4},
 
-    "glColor3dv":  {0: 3},
-    "glColor4dv":  {0: 4},
-    
     "glVertex2fv": {0: 2},
     "glVertex3fv": {0: 3},
     "glVertex4fv": {0: 4},
@@ -46,27 +50,27 @@ defs_precalc = {
     "glEvalCoord1dv": {0: 1},
     "glEvalCoord2fv": {0: 2},
     "glEvalCoord2dv": {0: 2},
-    
+
     "glRasterPos2dv": {0: 2},
     "glRasterPos3dv": {0: 3},
     "glRasterPos4dv": {0: 4},
-    
+
     "glRasterPos2fv": {0: 2},
-    "glRasterPos3fv": {0: 3},    
+    "glRasterPos3fv": {0: 3},
     "glRasterPos4fv": {0: 4},
-    
+
     "glRasterPos2sv": {0: 2},
-    "glRasterPos3sv": {0: 3},    
-    "glRasterPos4sv": {0: 4},   
-    
+    "glRasterPos3sv": {0: 3},
+    "glRasterPos4sv": {0: 4},
+
     "glTexCoord2fv": {0: 2},
     "glTexCoord3fv": {0: 3},
     "glTexCoord4fv": {0: 4},
-    
+
     "glTexCoord2dv": {0: 2},
     "glTexCoord3dv": {0: 3},
     "glTexCoord4dv": {0: 4},
-    
+
     "glNormal3fv": {0: 3},
     "glNormal3dv": {0: 3},
     "glNormal3bv": {0: 3},
@@ -80,17 +84,17 @@ import sys
 
 if 0:
     # Examples with LLVM as the root dir: '/dsk/src/llvm'
-    
+
     # path containing 'clang/__init__.py'
     CLANG_BIND_DIR = "/dsk/src/llvm/tools/clang/bindings/python"
-    
+
     # path containing libclang.so
     CLANG_LIB_DIR = "/opt/llvm/lib"
 else:
     import os
     CLANG_BIND_DIR = os.environ.get("CLANG_BIND_DIR")
     CLANG_LIB_DIR = os.environ.get("CLANG_LIB_DIR")
-    
+
     if CLANG_BIND_DIR is None:
         print("$CLANG_BIND_DIR python binding dir not set")
     if CLANG_LIB_DIR is None:
@@ -112,17 +116,19 @@ args = sys.argv[2:]
 # print(args)
 
 tu = index.parse(sys.argv[1], args)
-print 'Translation unit:', tu.spelling
+# print('Translation unit: %s' % tu.spelling)
+filepath = tu.spelling
 
 # -----------------------------------------------------------------------------
 
+
 def function_parm_wash_tokens(parm):
     # print(parm.kind)
     assert parm.kind in (CursorKind.PARM_DECL,
                          CursorKind.VAR_DECL,  # XXX, double check this
                          CursorKind.FIELD_DECL,
                          )
-    
+
     """
     Return tolens without trailing commads and 'const'
     """
@@ -130,14 +136,14 @@ def function_parm_wash_tokens(parm):
     tokens = [t for t in parm.get_tokens()]
     if not tokens:
         return tokens
-    
-    #if tokens[-1].kind == To
+
+    # if tokens[-1].kind == To
     # remove trailing char
     if tokens[-1].kind == TokenKind.PUNCTUATION:
         if tokens[-1].spelling in (",", ")", ";"):
             tokens.pop()
-        #else:
-        #    print(tokens[-1].spelling)
+        # else:
+        #     print(tokens[-1].spelling)
 
     t_new = []
     for t in tokens:
@@ -151,17 +157,17 @@ def function_parm_wash_tokens(parm):
                 ok = False  # __restrict
         elif t_kind in (TokenKind.COMMENT, ):
             ok = False
-            
+
             # Use these
         elif t_kind in (TokenKind.LITERAL,
                         TokenKind.PUNCTUATION,
                         TokenKind.IDENTIFIER):
             # use but ignore
             pass
-        
+
         else:
             print("Unknown!", t_kind, t_spelling)
-        
+
         # if its OK we will add
         if ok:
             t_new.append(t)
@@ -170,40 +176,37 @@ def function_parm_wash_tokens(parm):
 
 def parm_size(node_child):
     tokens = function_parm_wash_tokens(node_child)
-    
+
     # print(" ".join([t.spelling for t in tokens]))
-    
+
     # NOT PERFECT CODE, EXTRACT SIZE FROM TOKENS
-    if len(tokens) >= 3: # foo [ 1 ]
-        if ((tokens[-3].kind == TokenKind.PUNCTUATION and tokens[-3].spelling == "[") and
-            (tokens[-2].kind == TokenKind.LITERAL     and tokens[-2].spelling.isdigit()) and
-            (tokens[-1].kind == TokenKind.PUNCTUATION and tokens[-1].spelling == "]")):
+    if len(tokens) >= 3:  # foo [ 1 ]
+        if      ((tokens[-3].kind == TokenKind.PUNCTUATION and tokens[-3].spelling == "[") and
+                 (tokens[-2].kind == TokenKind.LITERAL and tokens[-2].spelling.isdigit()) and
+                 (tokens[-1].kind == TokenKind.PUNCTUATION and tokens[-1].spelling == "]")):
             # ---
             return int(tokens[-2].spelling)
     return -1
 
 
-
 def function_get_arg_sizes(node):
     # Return a dict if (index: size) items
     # {arg_indx: arg_array_size, ... ]
     arg_sizes = {}
 
-    if node.spelling == "BM_vert_create" or 1:
+    if 1:  # node.spelling == "BM_vert_create", for debugging
         node_parms = [node_child for node_child in node.get_children()
                       if node_child.kind == CursorKind.PARM_DECL]
 
         for i, node_child in enumerate(node_parms):
 
             # print(node_child.kind, node_child.spelling)
-            #print(node_child.type.kind, node_child.spelling)  # TypeKind.POINTER
-            
-            if node_child.type.kind == TypeKind.POINTER:
+            # print(node_child.type.kind, node_child.spelling)
+            if node_child.type.kind == TypeKind.CONSTANTARRAY:
                 pointee = node_child.type.get_pointee()
-                if pointee.is_pod():
-                    size = parm_size(node_child)
-                    if size != -1:
-                        arg_sizes[i] = size
+                size = parm_size(node_child)
+                if size != -1:
+                    arg_sizes[i] = size
 
     return arg_sizes
 
@@ -211,30 +214,44 @@ def function_get_arg_sizes(node):
 # -----------------------------------------------------------------------------
 _defs = {}
 
+
 def lookup_function_size_def(func_id):
-    return _defs.get(func_id, ())
+    if USE_LAZY_INIT:
+        result = _defs.get(func_id, {})
+        if type(result) != dict:
+            result = _defs[func_id] = function_get_arg_sizes(result)
+        return result
+    else:
+        return _defs.get(func_id, {})
 
 # -----------------------------------------------------------------------------
 
+
 def file_check_arg_sizes(tu):
-    
+
     # main checking function
     def validate_arg_size(node):
         """
         Loop over args and validate sizes for args we KNOW the size of.
         """
         assert node.kind == CursorKind.CALL_EXPR
-        # print("---", " <~> ".join([" ".join([t.spelling for t in C.get_tokens()]) for C in node.get_children()]))
+
+        if 0:
+            print("---",
+                  " <~> ".join(
+                      [" ".join([t.spelling for t in C.get_tokens()])
+                       for C in node.get_children()]
+                  ))
         # print(node.location)
-        
+
         # first child is the function call, skip that.
         children = list(node.get_children())
 
         if not children:
             return  # XXX, look into this, happens on C++
-        
+
         func = children[0]
-        
+
         # get the func declaration!
         # works but we can better scan for functions ahead of time.
         if 0:
@@ -246,73 +263,79 @@ def file_check_arg_sizes(tu):
                 print("AA", " ".join([t.spelling for t in node.get_tokens()]))
         else:
             args_size_definition = ()  # dummy
-            
+
             # get the key
             tok = list(func.get_tokens())
             if tok:
                 func_id = tok[0].spelling
                 args_size_definition = lookup_function_size_def(func_id)
-        
+
         if not args_size_definition:
             return
 
         children = children[1:]
         for i, node_child in enumerate(children):
             children = list(node_child.get_children())
-            
+
             # skip if we dont have an index...
             size_def = args_size_definition.get(i, -1)
 
             if size_def == -1:
                 continue
-            
-            #print([c.kind for c in children])
+
+            # print([c.kind for c in children])
             # print(" ".join([t.spelling for t in node_child.get_tokens()]))
-            
+
             if len(children) == 1:
                 arg = children[0]
                 if arg.kind in (CursorKind.DECL_REF_EXPR,
                                 CursorKind.UNEXPOSED_EXPR):
 
-                    if arg.type.kind == TypeKind.POINTER:
+                    if arg.type.kind == TypeKind.CONSTANTARRAY:
                         dec = arg.get_definition()
                         if dec:
                             size = parm_size(dec)
-                            
+
                             # size == 0 is for 'float *a'
                             if size != -1 and size != 0:
-                                
+
                                 # nice print!
-                                '''
-                                print("".join([t.spelling for t in func.get_tokens()]),
-                                      i,
-                                      " ".join([t.spelling for t in dec.get_tokens()]))
-                                '''
+                                if 0:
+                                    print("".join([t.spelling for t in func.get_tokens()]),
+                                          i,
+                                          " ".join([t.spelling for t in dec.get_tokens()]))
 
                                 # testing
                                 # size_def = 100
-
-                                if size < size_def:
-                                    location = node.location
-                                    print("%s:%d:%d: argument %d is size %d, should be %d" %
-                                          (location.file,
-                                           location.line,
-                                            location.column,
-                                            i + 1, size, size_def
-                                            ))
-
+                                if size != 1:
+                                    if USE_EXACT_COMPARE:
+                                        # is_err = (size != size_def) and (size != 4 and size_def != 3)
+                                        is_err = (size != size_def)
+                                    else:
+                                        is_err = (size < size_def)
+
+                                    if is_err:
+                                        location = node.location
+                                        # if "math_color_inline.c" not in str(location.file):
+                                        if 1:
+                                            print("%s:%d:%d: argument %d is size %d, should be %d (from %s)" %
+                                                  (location.file,
+                                                   location.line,
+                                                   location.column,
+                                                   i + 1, size, size_def,
+                                                   filepath  # always the same but useful when running threaded
+                                                   ))
 
     # we dont really care what we are looking at, just scan entire file for
     # function calls.
-    
+
     def recursive_func_call_check(node):
-        
         if node.kind == CursorKind.CALL_EXPR:
             validate_arg_size(node)
-        
+
         for c in node.get_children():
             recursive_func_call_check(c)
-    
+
     recursive_func_call_check(tu.cursor)
 
 
@@ -322,9 +345,12 @@ def file_check_arg_sizes(tu):
 def recursive_arg_sizes(node, ):
     # print(node.kind, node.spelling)
     if node.kind == CursorKind.FUNCTION_DECL:
-        args_sizes = function_get_arg_sizes(node)
-        #if args_sizes:
-        #    print(node.spelling, args_sizes)
+        if USE_LAZY_INIT:
+            args_sizes = node
+        else:
+            args_sizes = function_get_arg_sizes(node)
+        # if args_sizes:
+        #     print(node.spelling, args_sizes)
         _defs[node.spelling] = args_sizes
         # print("adding", node.spelling)
     for c in node.get_children():