Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'build_files/cmake/clang_array_check.py')
-rw-r--r--build_files/cmake/clang_array_check.py337
1 files changed, 337 insertions, 0 deletions
diff --git a/build_files/cmake/clang_array_check.py b/build_files/cmake/clang_array_check.py
new file mode 100644
index 00000000000..df45648f975
--- /dev/null
+++ b/build_files/cmake/clang_array_check.py
@@ -0,0 +1,337 @@
+# ---
+# * Licensed under the Apache License, Version 2.0 (the "License");
+# * you may not use this file except in compliance with the License.
+# * You may obtain a copy of the License at
+# *
+# * http://www.apache.org/licenses/LICENSE-2.0
+# ---
+# by Campbell Barton
+
+"""
+Invocation:
+
+ export CLANG_BIND_DIR="/dsk/src/llvm/tools/clang/bindings/python"
+ export CLANG_LIB_DIR="/opt/llvm/lib"
+
+ python2 clang_array_check.py somefile.c -DSOME_DEFINE -I/some/include
+
+... defines and includes are optional
+
+"""
+
+# -----------------------------------------------------------------------------
+# predefined function/arg sizes, handy sometimes, but not complete...
+
+defs_precalc = {
+ "glColor3bv": {0: 3},
+ "glColor4bv": {0: 4},
+
+ "glColor3ubv": {0: 3},
+ "glColor4ubv": {0: 4},
+
+ "glColor4usv": {0: 3},
+ "glColor4usv": {0: 4},
+
+ "glColor3fv": {0: 3},
+ "glColor4fv": {0: 4},
+
+ "glColor3dv": {0: 3},
+ "glColor4dv": {0: 4},
+
+ "glVertex2fv": {0: 2},
+ "glVertex3fv": {0: 3},
+ "glVertex4fv": {0: 4},
+
+ "glEvalCoord1fv": {0: 1},
+ "glEvalCoord1dv": {0: 1},
+ "glEvalCoord2fv": {0: 2},
+ "glEvalCoord2dv": {0: 2},
+
+ "glRasterPos2dv": {0: 2},
+ "glRasterPos3dv": {0: 3},
+ "glRasterPos4dv": {0: 4},
+
+ "glRasterPos2fv": {0: 2},
+ "glRasterPos3fv": {0: 3},
+ "glRasterPos4fv": {0: 4},
+
+ "glRasterPos2sv": {0: 2},
+ "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},
+ "glNormal3iv": {0: 3},
+ "glNormal3sv": {0: 3},
+}
+
+# -----------------------------------------------------------------------------
+
+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:
+ print("$CLANG_LIB_DIR clang lib dir not set")
+
+sys.path.append(CLANG_BIND_DIR)
+
+import clang
+import clang.cindex
+from clang.cindex import (CursorKind,
+ TypeKind,
+ TokenKind)
+
+clang.cindex.Config.set_library_path(CLANG_LIB_DIR)
+
+index = clang.cindex.Index.create()
+
+args = sys.argv[2:]
+# print(args)
+
+tu = index.parse(sys.argv[1], args)
+print 'Translation unit:', 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'
+ """
+
+ tokens = [t for t in parm.get_tokens()]
+ if not tokens:
+ return tokens
+
+ #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)
+
+ t_new = []
+ for t in tokens:
+ t_kind = t.kind
+ t_spelling = t.spelling
+ ok = True
+ if t_kind == TokenKind.KEYWORD:
+ if t_spelling in ("const", "restrict", "volatile"):
+ ok = False
+ elif t_spelling.startswith("__"):
+ 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)
+ return t_new
+
+
+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 == "]")):
+ # ---
+ 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:
+ 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:
+ pointee = node_child.type.get_pointee()
+ if pointee.is_pod():
+ size = parm_size(node_child)
+ if size != -1:
+ arg_sizes[i] = size
+
+ return arg_sizes
+
+
+# -----------------------------------------------------------------------------
+_defs = {}
+
+def lookup_function_size_def(func_id):
+ 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()]))
+ # 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:
+ func_dec = func.get_definition()
+ if func_dec:
+ print("FD", " ".join([t.spelling for t in func_dec.get_tokens()]))
+ else:
+ # HRMP'f - why does this fail?
+ 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(" ".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:
+ 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()]))
+ '''
+
+ # 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
+ ))
+
+
+ # 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)
+
+
+# -- first pass, cache function definitions sizes
+
+# PRINT FUNC DEFINES
+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)
+ _defs[node.spelling] = args_sizes
+ # print("adding", node.spelling)
+ for c in node.get_children():
+ recursive_arg_sizes(c)
+# cache function sizes
+recursive_arg_sizes(tu.cursor)
+_defs.update(defs_precalc)
+
+# --- second pass, check against def's
+file_check_arg_sizes(tu)