Skip to content
Snippets Groups Projects
Commit 19223f7a authored by Campbell Barton's avatar Campbell Barton
Browse files

check_style_c: support for caching results

Stores hash of script and text files,
allows to re-run quickly on changed files.
parent 5162393c
Branches
Tags
No related merge requests found
...@@ -48,6 +48,12 @@ def is_ignore(f): ...@@ -48,6 +48,12 @@ def is_ignore(f):
return False return False
def hash_of_file(fp):
import hashlib
with open(fp, 'rb') as fh:
return hashlib.sha512(fh.read()).digest()
# TODO # TODO
# #
# Add checks for: # Add checks for:
...@@ -238,7 +244,7 @@ def extract_ws_indent(index): ...@@ -238,7 +244,7 @@ def extract_ws_indent(index):
return text[:len(text) - len(text.lstrip("\t"))] return text[:len(text) - len(text.lstrip("\t"))]
def extract_statement_if(index_kw): def extract_statement_if(fn, index_kw):
# assert(tokens[index_kw].text == "if") # assert(tokens[index_kw].text == "if")
# ignore preprocessor # ignore preprocessor
...@@ -257,7 +263,7 @@ def extract_statement_if(index_kw): ...@@ -257,7 +263,7 @@ def extract_statement_if(index_kw):
# print(tokens[i_next]) # print(tokens[i_next])
if tokens[i_next].type != Token.Punctuation or tokens[i_next].text != "(": if tokens[i_next].type != Token.Punctuation or tokens[i_next].text != "(":
warning("E105", "no '(' after '%s'" % tokens[index_kw].text, i_start, i_next) warning(fn, "E105", "no '(' after '%s'" % tokens[index_kw].text, i_start, i_next)
return None return None
i_end = tk_match_backet(i_next) i_end = tk_match_backet(i_next)
...@@ -372,20 +378,20 @@ def tk_range_find_by_type(index_start, index_end, type_, filter_tk=None): ...@@ -372,20 +378,20 @@ def tk_range_find_by_type(index_start, index_end, type_, filter_tk=None):
return -1 return -1
def warning(id_, message, index_kw_start, index_kw_end): def warning(fn, id_, message, index_kw_start, index_kw_end):
if PRINT_QTC_TASKFORMAT: if PRINT_QTC_TASKFORMAT:
print("%s\t%d\t%s\t%s %s" % (filepath, tokens[index_kw_start].line, "comment", id_, message)) fn("%s\t%d\t%s\t%s %s" % (filepath, tokens[index_kw_start].line, "comment", id_, message))
else: else:
print("%s:%d: %s: %s" % (filepath, tokens[index_kw_start].line, id_, message)) fn("%s:%d: %s: %s" % (filepath, tokens[index_kw_start].line, id_, message))
if WARN_TEXT: if WARN_TEXT:
print(tk_range_to_str(index_kw_start, index_kw_end, expand_tabs=True)) fn(tk_range_to_str(index_kw_start, index_kw_end, expand_tabs=True))
def warning_lineonly(id_, message, line): def warning_lineonly(fn, id_, message, line):
if PRINT_QTC_TASKFORMAT: if PRINT_QTC_TASKFORMAT:
print("%s\t%d\t%s\t%s %s" % (filepath, line, "comment", id_, message)) fn("%s\t%d\t%s\t%s %s" % (filepath, line, "comment", id_, message))
else: else:
print("%s:%d: %s: %s" % (filepath, line, id_, message)) fn("%s:%d: %s: %s" % (filepath, line, id_, message))
# print(tk_range_to_str(index_kw_start, index_kw_end)) # print(tk_range_to_str(index_kw_start, index_kw_end))
...@@ -393,17 +399,17 @@ def warning_lineonly(id_, message, line): ...@@ -393,17 +399,17 @@ def warning_lineonly(id_, message, line):
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# Own Blender rules here! # Own Blender rules here!
def blender_check_kw_if(index_kw_start, index_kw, index_kw_end): def blender_check_kw_if(fn, index_kw_start, index_kw, index_kw_end):
# check if we have: 'if(' # check if we have: 'if('
if not tk_item_is_ws(tokens[index_kw + 1]): if not tk_item_is_ws(tokens[index_kw + 1]):
warning("E106", "no white space between '%s('" % tokens[index_kw].text, index_kw_start, index_kw_end) warning(fn, "E106", "no white space between '%s('" % tokens[index_kw].text, index_kw_start, index_kw_end)
# check for: ){ # check for: ){
index_next = tk_advance_ws_newline(index_kw_end, 1) index_next = tk_advance_ws_newline(index_kw_end, 1)
if tokens[index_next].type == Token.Punctuation and tokens[index_next].text == "{": if tokens[index_next].type == Token.Punctuation and tokens[index_next].text == "{":
if not tk_item_is_ws_newline(tokens[index_next - 1]): if not tk_item_is_ws_newline(tokens[index_next - 1]):
warning("E107", "no white space between trailing bracket '%s (){'" % warning(fn, "E107", "no white space between trailing bracket '%s (){'" %
tokens[index_kw].text, index_kw_start, index_kw_end) tokens[index_kw].text, index_kw_start, index_kw_end)
# check for: if () # check for: if ()
...@@ -420,7 +426,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end): ...@@ -420,7 +426,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end):
# allow this to go unnoticed # allow this to go unnoticed
pass pass
else: else:
warning("E108", "if body brace on a new line '%s ()\\n{'" % warning(fn, "E108", "if body brace on a new line '%s ()\\n{'" %
tokens[index_kw].text, index_kw, index_kw_end) tokens[index_kw].text, index_kw, index_kw_end)
else: else:
# no '{' on a multi-line if # no '{' on a multi-line if
...@@ -437,7 +443,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end): ...@@ -437,7 +443,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end):
# b); # b);
# #
if not (tokens[index_next].type == Token.Punctuation and tokens[index_next].text == ";"): if not (tokens[index_next].type == Token.Punctuation and tokens[index_next].text == ";"):
warning("E109", "multi-line if should use a brace '%s (\\n\\n) statement;'" % warning(fn, "E109", "multi-line if should use a brace '%s (\\n\\n) statement;'" %
tokens[index_kw].text, index_kw, index_kw_end) tokens[index_kw].text, index_kw, index_kw_end)
# check for correct single line use & indentation # check for correct single line use & indentation
...@@ -461,7 +467,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end): ...@@ -461,7 +467,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end):
has_sep = True has_sep = True
break break
if not has_sep: if not has_sep:
warning("E200", "bad single line indent '%s (...) {'" % warning(fn, "E200", "bad single line indent '%s (...) {'" %
tokens[index_kw].text, index_kw, index_next) tokens[index_kw].text, index_kw, index_next)
del has_sep del has_sep
del ws_kw, ws_end del ws_kw, ws_end
...@@ -479,7 +485,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end): ...@@ -479,7 +485,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end):
ws_kw = extract_ws_indent(index_kw) ws_kw = extract_ws_indent(index_kw)
ws_end = extract_ws_indent(index_end) ws_end = extract_ws_indent(index_end)
if len(ws_kw) + 1 != len(ws_end): if len(ws_kw) + 1 != len(ws_end):
warning("E201", "bad single line indent '%s (...) {'" % warning(fn, "E201", "bad single line indent '%s (...) {'" %
tokens[index_kw].text, index_kw, index_end) tokens[index_kw].text, index_kw, index_end)
del ws_kw, ws_end del ws_kw, ws_end
del index_end del index_end
...@@ -492,7 +498,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end): ...@@ -492,7 +498,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end):
# #
if tokens[index_kw_end].line == tokens[index_next].line: if tokens[index_kw_end].line == tokens[index_next].line:
if not (tokens[index_next].type == Token.Punctuation and tokens[index_next].text == ";"): if not (tokens[index_next].type == Token.Punctuation and tokens[index_next].text == ";"):
warning("E103", "multi-line should use a on a new line '%s (\\n\\n) {'" % warning(fn, "E103", "multi-line should use a on a new line '%s (\\n\\n) {'" %
tokens[index_kw].text, index_kw, index_kw_end) tokens[index_kw].text, index_kw, index_kw_end)
# Note: this could be split into its own function # Note: this could be split into its own function
...@@ -538,7 +544,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end): ...@@ -538,7 +544,7 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end):
# needed for some comments # needed for some comments
pass pass
else: else:
warning("E110", "if body brace mult-line indent mismatch", i, i) warning(fn, "E110", "if body brace mult-line indent mismatch", i, i)
del index_kw_bracket del index_kw_bracket
del ws_indent del ws_indent
del l_last del l_last
...@@ -550,18 +556,18 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end): ...@@ -550,18 +556,18 @@ def blender_check_kw_if(index_kw_start, index_kw, index_kw_end):
index_final = tk_match_backet(index_next) index_final = tk_match_backet(index_next)
index_final_step = tk_advance_no_ws(index_final, 1) index_final_step = tk_advance_no_ws(index_final, 1)
if tokens[index_final_step].text == ";": if tokens[index_final_step].text == ";":
warning("E111", "semi-colon after brace '%s () { ... };'" % warning(fn, "E111", "semi-colon after brace '%s () { ... };'" %
tokens[index_kw].text, index_final_step, index_final_step) tokens[index_kw].text, index_final_step, index_final_step)
def blender_check_kw_else(index_kw): def blender_check_kw_else(fn, index_kw):
# for 'else if' use the if check. # for 'else if' use the if check.
i_next = tk_advance_ws_newline(index_kw, 1) i_next = tk_advance_ws_newline(index_kw, 1)
# check there is at least one space between: # check there is at least one space between:
# else{ # else{
if index_kw + 1 == i_next: if index_kw + 1 == i_next:
warning("E112", "else has no space between following brace 'else{'", index_kw, i_next) warning(fn, "E112", "else has no space between following brace 'else{'", index_kw, i_next)
# check if there are more than 1 spaces after else, but nothing after the following brace # check if there are more than 1 spaces after else, but nothing after the following brace
# else { # else {
...@@ -577,7 +583,7 @@ def blender_check_kw_else(index_kw): ...@@ -577,7 +583,7 @@ def blender_check_kw_else(index_kw):
# check if the next data after { is on a newline # check if the next data after { is on a newline
i_next_next = tk_advance_ws_newline(i_next, 1) i_next_next = tk_advance_ws_newline(i_next, 1)
if tokens[i_next].line != tokens[i_next_next].line: if tokens[i_next].line != tokens[i_next_next].line:
warning("E113", "unneeded whitespace before brace 'else ... {'", index_kw, i_next) warning(fn, "E113", "unneeded whitespace before brace 'else ... {'", index_kw, i_next)
# this check only tests for: # this check only tests for:
# else # else
...@@ -596,7 +602,7 @@ def blender_check_kw_else(index_kw): ...@@ -596,7 +602,7 @@ def blender_check_kw_else(index_kw):
if tokens[i_newline].text.startswith("#"): if tokens[i_newline].text.startswith("#"):
pass pass
else: else:
warning("E114", "else body brace on a new line 'else\\n{'", index_kw, i_next) warning(fn, "E114", "else body brace on a new line 'else\\n{'", index_kw, i_next)
# this check only tests for: # this check only tests for:
# else # else
...@@ -629,7 +635,7 @@ def blender_check_kw_else(index_kw): ...@@ -629,7 +635,7 @@ def blender_check_kw_else(index_kw):
# allow this to go unnoticed # allow this to go unnoticed
pass pass
else: else:
warning("E115", "else if is split by a new line 'else\\nif'", index_kw, i_next) warning(fn, "E115", "else if is split by a new line 'else\\nif'", index_kw, i_next)
# check # check
# } else # } else
...@@ -637,10 +643,10 @@ def blender_check_kw_else(index_kw): ...@@ -637,10 +643,10 @@ def blender_check_kw_else(index_kw):
i_prev = tk_advance_no_ws(index_kw, -1) i_prev = tk_advance_no_ws(index_kw, -1)
if tokens[i_prev].type == Token.Punctuation and tokens[i_prev].text == "}": if tokens[i_prev].type == Token.Punctuation and tokens[i_prev].text == "}":
if tokens[index_kw].line == tokens[i_prev].line: if tokens[index_kw].line == tokens[i_prev].line:
warning("E116", "else has no newline before the brace '} else'", i_prev, index_kw) warning(fn, "E116", "else has no newline before the brace '} else'", i_prev, index_kw)
def blender_check_kw_switch(index_kw_start, index_kw, index_kw_end): def blender_check_kw_switch(fn, index_kw_start, index_kw, index_kw_end):
# In this function we check the body of the switch # In this function we check the body of the switch
# switch (value) { # switch (value) {
...@@ -680,7 +686,7 @@ def blender_check_kw_switch(index_kw_start, index_kw, index_kw_end): ...@@ -680,7 +686,7 @@ def blender_check_kw_switch(index_kw_start, index_kw, index_kw_end):
if ws_other_indent.isspace(): if ws_other_indent.isspace():
ws_test_other = ws_test[tokens[i].text] ws_test_other = ws_test[tokens[i].text]
if not ws_other_indent.startswith(ws_test_other): if not ws_other_indent.startswith(ws_test_other):
warning("E117", "%s is not indented enough" % tokens[i].text, i, i) warning(fn, "E117", "%s is not indented enough" % tokens[i].text, i, i)
if tokens[i].text == "case": if tokens[i].text == "case":
# while where here, check: # while where here, check:
...@@ -691,27 +697,27 @@ def blender_check_kw_switch(index_kw_start, index_kw, index_kw_end): ...@@ -691,27 +697,27 @@ def blender_check_kw_switch(index_kw_start, index_kw, index_kw_end):
# can be None when the identifier isn't an 'int' # can be None when the identifier isn't an 'int'
if i_case is not None: if i_case is not None:
if tokens[i_case - 1].text.isspace(): if tokens[i_case - 1].text.isspace():
warning("E132", "%s space before colon" % tokens[i].text, i, i_case) warning(fn, "E132", "%s space before colon" % tokens[i].text, i, i_case)
del i_case del i_case
else: else:
warning("E119", "switch isn't the first token in the line", index_kw_start, index_kw_end) warning(fn, "E119", "switch isn't the first token in the line", index_kw_start, index_kw_end)
else: else:
warning("E120", "switch brace missing", index_kw_start, index_kw_end) warning(fn, "E120", "switch brace missing", index_kw_start, index_kw_end)
def blender_check_kw_sizeof(index_kw): def blender_check_kw_sizeof(index_kw):
if tokens[index_kw + 1].text != "(": if tokens[index_kw + 1].text != "(":
warning("E121", "expected '%s('" % tokens[index_kw].text, index_kw, index_kw + 1) warning(fn, "E121", "expected '%s('" % tokens[index_kw].text, index_kw, index_kw + 1)
def blender_check_cast(index_kw_start, index_kw_end): def blender_check_cast(fn, index_kw_start, index_kw_end):
# detect: '( float...' # detect: '( float...'
if tokens[index_kw_start + 1].text.isspace(): if tokens[index_kw_start + 1].text.isspace():
warning("E122", "cast has space after first bracket '( type...'", index_kw_start, index_kw_end) warning(fn, "E122", "cast has space after first bracket '( type...'", index_kw_start, index_kw_end)
# detect: '...float )' # detect: '...float )'
if tokens[index_kw_end - 1].text.isspace(): if tokens[index_kw_end - 1].text.isspace():
warning("E123", "cast has space before last bracket '... )'", index_kw_start, index_kw_end) warning(fn, "E123", "cast has space before last bracket '... )'", index_kw_start, index_kw_end)
# detect no space before operator: '(float*)' # detect no space before operator: '(float*)'
for i in range(index_kw_start + 1, index_kw_end): for i in range(index_kw_start + 1, index_kw_end):
...@@ -722,10 +728,10 @@ def blender_check_cast(index_kw_start, index_kw_end): ...@@ -722,10 +728,10 @@ def blender_check_cast(index_kw_start, index_kw_end):
elif tokens[i - 1].text.isspace(): elif tokens[i - 1].text.isspace():
pass pass
else: else:
warning("E124", "cast has no preceding whitespace '(type*)'", index_kw_start, index_kw_end) warning(fn, "E124", "cast has no preceding whitespace '(type*)'", index_kw_start, index_kw_end)
def blender_check_comma(index_kw): def blender_check_comma(fn, index_kw):
i_next = tk_advance_ws_newline(index_kw, 1) i_next = tk_advance_ws_newline(index_kw, 1)
# check there is at least one space between: # check there is at least one space between:
...@@ -733,13 +739,13 @@ def blender_check_comma(index_kw): ...@@ -733,13 +739,13 @@ def blender_check_comma(index_kw):
if index_kw + 1 == i_next: if index_kw + 1 == i_next:
# allow: (struct FooBar){ .a, .b, .c,} # allow: (struct FooBar){ .a, .b, .c,}
if tokens[i_next].text != "}": if tokens[i_next].text != "}":
warning("E125", "comma has no space after it ',sometext'", index_kw, i_next) warning(fn, "E125", "comma has no space after it ',sometext'", index_kw, i_next)
if tokens[index_kw - 1].type == Token.Text and tokens[index_kw - 1].text.isspace(): if tokens[index_kw - 1].type == Token.Text and tokens[index_kw - 1].text.isspace():
warning("E126", "comma space before it 'sometext ,", index_kw, i_next) warning(fn, "E126", "comma space before it 'sometext ,", index_kw, i_next)
def blender_check_period(index_kw): def blender_check_period(fn, index_kw):
# check we're now apart of ... # check we're now apart of ...
if (tokens[index_kw - 1].text == ".") or (tokens[index_kw + 1].text == "."): if (tokens[index_kw - 1].text == ".") or (tokens[index_kw + 1].text == "."):
return return
...@@ -751,9 +757,9 @@ def blender_check_period(index_kw): ...@@ -751,9 +757,9 @@ def blender_check_period(index_kw):
# ... check for this case by allowing comma or brace beforehand. # ... check for this case by allowing comma or brace beforehand.
i_prev = tk_advance_ws_newline(index_kw - 1, -1) i_prev = tk_advance_ws_newline(index_kw - 1, -1)
if tokens[i_prev].text not in {",", "{"}: if tokens[i_prev].text not in {",", "{"}:
warning("E127", "period space before it 'sometext .", index_kw, index_kw) warning(fn, "E127", "period space before it 'sometext .", index_kw, index_kw)
if tokens[index_kw + 1].type == Token.Text and tokens[index_kw + 1].text.isspace(): if tokens[index_kw + 1].type == Token.Text and tokens[index_kw + 1].text.isspace():
warning("E128", "period space after it '. sometext", index_kw, index_kw) warning(fn, "E128", "period space after it '. sometext", index_kw, index_kw)
def _is_ws_pad(index_start, index_end): def _is_ws_pad(index_start, index_end):
...@@ -761,7 +767,7 @@ def _is_ws_pad(index_start, index_end): ...@@ -761,7 +767,7 @@ def _is_ws_pad(index_start, index_end):
tokens[index_end + 1].text.isspace()) tokens[index_end + 1].text.isspace())
def blender_check_operator(index_start, index_end, op_text, is_cpp): def blender_check_operator(fn, index_start, index_end, op_text, is_cpp):
if op_text == "->": if op_text == "->":
# allow compiler to handle # allow compiler to handle
return return
...@@ -783,17 +789,17 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp): ...@@ -783,17 +789,17 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp):
# Or: (struct FooBar)&var # Or: (struct FooBar)&var
(tokens[index_prev].flag & IS_CAST) (tokens[index_prev].flag & IS_CAST)
): ):
warning("E130", "no space before operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "no space before operator '%s'" % op_text, index_start, index_end)
if (not tokens[index_end + 1].text.isspace() and if (not tokens[index_end + 1].text.isspace() and
tokens[index_end + 1].text not in {"]", ")", "}"}): tokens[index_end + 1].text not in {"]", ")", "}"}):
# TODO, needs work to be useful # TODO, needs work to be useful
# warning("E130", "no space after operator '%s'" % op_text, index_start, index_end) # warning(fn, "E130", "no space after operator '%s'" % op_text, index_start, index_end)
pass pass
elif op_text in {"/", "%", "^", "|", "=", "<", ">", "?"}: elif op_text in {"/", "%", "^", "|", "=", "<", ">", "?"}:
if not _is_ws_pad(index_start, index_end): if not _is_ws_pad(index_start, index_end):
if not (is_cpp and ("<" in op_text or ">" in op_text)): if not (is_cpp and ("<" in op_text or ">" in op_text)):
warning("E130", "no space around operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "no space around operator '%s'" % op_text, index_start, index_end)
elif op_text == ":": elif op_text == ":":
# check we're not # check we're not
# case 1: # case 1:
...@@ -804,7 +810,7 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp): ...@@ -804,7 +810,7 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp):
if not (tokens[index_start - 1].text.isspace() or tokens[index_start - 1].text == "default"): if not (tokens[index_start - 1].text.isspace() or tokens[index_start - 1].text == "default"):
i_case = tk_advance_line_to_token(index_start, -1, "case", Token.Keyword) i_case = tk_advance_line_to_token(index_start, -1, "case", Token.Keyword)
if i_case is None: if i_case is None:
warning("E130", "no space around operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "no space around operator '%s'" % op_text, index_start, index_end)
elif op_text == "&": elif op_text == "&":
pass # TODO, check if this is a pointer reference or not pass # TODO, check if this is a pointer reference or not
elif op_text == "*": elif op_text == "*":
...@@ -826,9 +832,9 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp): ...@@ -826,9 +832,9 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp):
pass pass
elif ((tokens[index_start - 1].type in Token.Number) or elif ((tokens[index_start - 1].type in Token.Number) or
(tokens[index_start + 1].type in Token.Number)): (tokens[index_start + 1].type in Token.Number)):
warning("E130", "no space around operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "no space around operator '%s'" % op_text, index_start, index_end)
elif not (tokens[index_start - 1].text.isspace() or tokens[index_start - 1].text in {"(", "[", "{"}): elif not (tokens[index_start - 1].text.isspace() or tokens[index_start - 1].text in {"(", "[", "{"}):
warning("E130", "no space before operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "no space before operator '%s'" % op_text, index_start, index_end)
elif len(op_text) == 2: elif len(op_text) == 2:
# todo, remove operator check from `if` # todo, remove operator check from `if`
if op_text in {"+=", "-=", "*=", "/=", "&=", "|=", "^=", if op_text in {"+=", "-=", "*=", "/=", "&=", "|=", "^=",
...@@ -841,20 +847,20 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp): ...@@ -841,20 +847,20 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp):
}: }:
if not _is_ws_pad(index_start, index_end): if not _is_ws_pad(index_start, index_end):
if not (is_cpp and ("<" in op_text or ">" in op_text)): if not (is_cpp and ("<" in op_text or ">" in op_text)):
warning("E130", "no space around operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "no space around operator '%s'" % op_text, index_start, index_end)
elif op_text in {"++", "--"}: elif op_text in {"++", "--"}:
pass # TODO, figure out the side we are adding to! pass # TODO, figure out the side we are adding to!
''' '''
if (tokens[index_start - 1].text.isspace() or if (tokens[index_start - 1].text.isspace() or
tokens[index_end + 1].text.isspace()): tokens[index_end + 1].text.isspace()):
warning("E130", "spaces surrounding operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "spaces surrounding operator '%s'" % op_text, index_start, index_end)
''' '''
elif op_text in {"!!", "!*"}: elif op_text in {"!!", "!*"}:
# operators we _dont_ want whitespace after (pointers mainly) # operators we _dont_ want whitespace after (pointers mainly)
# we can assume these are pointers # we can assume these are pointers
if tokens[index_end + 1].text.isspace(): if tokens[index_end + 1].text.isspace():
warning("E130", "spaces after operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "spaces after operator '%s'" % op_text, index_start, index_end)
elif op_text == "**": elif op_text == "**":
pass # handle below pass # handle below
...@@ -865,12 +871,12 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp): ...@@ -865,12 +871,12 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp):
elif op_text == "*>": elif op_text == "*>":
pass # ignore for now, C++ <Class *> pass # ignore for now, C++ <Class *>
else: else:
warning("E000.0", "unhandled operator 2 '%s'" % op_text, index_start, index_end) warning(fn, "E000.0", "unhandled operator 2 '%s'" % op_text, index_start, index_end)
elif len(op_text) == 3: elif len(op_text) == 3:
if op_text in {">>=", "<<="}: if op_text in {">>=", "<<="}:
if not _is_ws_pad(index_start, index_end): if not _is_ws_pad(index_start, index_end):
if not (is_cpp and ("<" in op_text or ">" in op_text)): if not (is_cpp and ("<" in op_text or ">" in op_text)):
warning("E130", "no space around operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "no space around operator '%s'" % op_text, index_start, index_end)
elif op_text == "***": elif op_text == "***":
pass pass
elif op_text in {"*--", "*++"}: elif op_text in {"*--", "*++"}:
...@@ -882,22 +888,22 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp): ...@@ -882,22 +888,22 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp):
elif op_text == "::~": elif op_text == "::~":
pass pass
else: else:
warning("E000.1", "unhandled operator 3 '%s'" % op_text, index_start, index_end) warning(fn, "E000.1", "unhandled operator 3 '%s'" % op_text, index_start, index_end)
elif len(op_text) == 4: elif len(op_text) == 4:
if op_text == "*>::": if op_text == "*>::":
pass pass
else: else:
warning("E000.2", "unhandled operator 4 '%s'" % op_text, index_start, index_end) warning(fn, "E000.2", "unhandled operator 4 '%s'" % op_text, index_start, index_end)
else: else:
warning("E000.3", "unhandled operator (len > 4) '%s'" % op_text, index_start, index_end) warning(fn, "E000.3", "unhandled operator (len > 4) '%s'" % op_text, index_start, index_end)
if len(op_text) > 1: if len(op_text) > 1:
if op_text[0] == "*" and op_text[-1] == "*": if op_text[0] == "*" and op_text[-1] == "*":
if ((not tokens[index_start - 1].text.isspace()) and if ((not tokens[index_start - 1].text.isspace()) and
(not tokens[index_start - 1].type == Token.Punctuation)): (not tokens[index_start - 1].type == Token.Punctuation)):
warning("E130", "no space before pointer operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "no space before pointer operator '%s'" % op_text, index_start, index_end)
if tokens[index_end + 1].text.isspace(): if tokens[index_end + 1].text.isspace():
warning("E130", "space before pointer operator '%s'" % op_text, index_start, index_end) warning(fn, "E130", "space before pointer operator '%s'" % op_text, index_start, index_end)
# check if we are first in the line # check if we are first in the line
if op_text[0] == "!": if op_text[0] == "!":
...@@ -930,18 +936,18 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp): ...@@ -930,18 +936,18 @@ def blender_check_operator(index_start, index_end, op_text, is_cpp):
pass pass
else: else:
if tk_index_is_linestart(index_start): if tk_index_is_linestart(index_start):
warning("E143", "operator starts a new line '%s'" % op_text, index_start, index_end) warning(fn, "E143", "operator starts a new line '%s'" % op_text, index_start, index_end)
def blender_check_linelength(index_start, index_end, length): def blender_check_linelength(fn, index_start, index_end, length):
if length > LIN_SIZE: if length > LIN_SIZE:
text = tk_range_to_str(index_start, index_end, expand_tabs=True) text = tk_range_to_str(index_start, index_end, expand_tabs=True)
for l in text.split("\n"): for l in text.split("\n"):
if len(l) > LIN_SIZE: if len(l) > LIN_SIZE:
warning("E144", "line length %d > %d" % (len(l), LIN_SIZE), index_start, index_end) warning(fn, "E144", "line length %d > %d" % (len(l), LIN_SIZE), index_start, index_end)
def blender_check_function_definition(i): def blender_check_function_definition(fn, i):
# Warning, this is a fairly slow check and guesses # Warning, this is a fairly slow check and guesses
# based on some fuzzy rules # based on some fuzzy rules
...@@ -1006,10 +1012,10 @@ def blender_check_function_definition(i): ...@@ -1006,10 +1012,10 @@ def blender_check_function_definition(i):
i_begin += 1 i_begin += 1
# now we are done skipping stuff # now we are done skipping stuff
warning("E101", "function's '{' must be on a newline", i_begin, i) warning(fn, "E101", "function's '{' must be on a newline", i_begin, i)
def blender_check_brace_indent(i): def blender_check_brace_indent(fn, i):
# assert(tokens[index].text == "{") # assert(tokens[index].text == "{")
i_match = tk_match_backet(i) i_match = tk_match_backet(i)
...@@ -1028,10 +1034,10 @@ def blender_check_brace_indent(i): ...@@ -1028,10 +1034,10 @@ def blender_check_brace_indent(i):
ws_i = ws_i[:len(ws_i) - len(ws_i.lstrip())] ws_i = ws_i[:len(ws_i) - len(ws_i.lstrip())]
ws_i_match = ws_i_match[:len(ws_i_match) - len(ws_i_match_lstrip)] ws_i_match = ws_i_match[:len(ws_i_match) - len(ws_i_match_lstrip)]
if ws_i != ws_i_match: if ws_i != ws_i_match:
warning("E104", "indentation '{' does not match brace", i, i_match) warning(fn, "E104", "indentation '{' does not match brace", i, i_match)
def quick_check_includes(lines): def quick_check_includes(fn, lines):
# Find overly relative headers (could check other things here too...) # Find overly relative headers (could check other things here too...)
# header dupes # header dupes
...@@ -1051,19 +1057,19 @@ def quick_check_includes(lines): ...@@ -1051,19 +1057,19 @@ def quick_check_includes(lines):
if os.path.exists(l_header_full): if os.path.exists(l_header_full):
l_header_rel = os.path.relpath(l_header_full, base) l_header_rel = os.path.relpath(l_header_full, base)
if l_header.count("/") != l_header_rel.count("/"): if l_header.count("/") != l_header_rel.count("/"):
warning_lineonly("E170", "overly relative include %r" % l_header, i + 1) warning_lineonly(fn, "E170", "overly relative include %r" % l_header, i + 1)
# check if we're in mode than once # check if we're in mode than once
len_inc = len(inc) len_inc = len(inc)
inc.add(l_header) inc.add(l_header)
if len(inc) == len_inc: if len(inc) == len_inc:
warning_lineonly("E171", "duplicate includes %r" % l_header, i + 1) warning_lineonly(fn, "E171", "duplicate includes %r" % l_header, i + 1)
quick_check_includes.re_inc_match = re.compile(r"\s*#\s*include\s+\"([a-zA-Z0-9_\-\.\/]+)\"").match quick_check_includes.re_inc_match = re.compile(r"\s*#\s*include\s+\"([a-zA-Z0-9_\-\.\/]+)\"").match
def quick_check_indentation(lines): def quick_check_indentation(fn, lines):
""" """
Quick check for multiple tab indents. Quick check for multiple tab indents.
""" """
...@@ -1091,7 +1097,8 @@ def quick_check_indentation(lines): ...@@ -1091,7 +1097,8 @@ def quick_check_indentation(lines):
# we have indent, check previous line # we have indent, check previous line
if not ls_prev.rstrip().endswith("\\"): if not ls_prev.rstrip().endswith("\\"):
# report indented line # report indented line
warning_lineonly("E145", "indentation found with preprocessor " warning_lineonly(
fn, "E145", "indentation found with preprocessor "
"(expected none or after '#')", i + 1) "(expected none or after '#')", i + 1)
skip = True skip = True
...@@ -1126,7 +1133,8 @@ def quick_check_indentation(lines): ...@@ -1126,7 +1133,8 @@ def quick_check_indentation(lines):
tabs = l[:len(l) - len(ls)] tabs = l[:len(l) - len(ls)]
t = len(tabs) t = len(tabs)
if (t > t_prev + 1) and (t_prev != -1): if (t > t_prev + 1) and (t_prev != -1):
warning_lineonly("E146", "indentation mismatch (indent of %d) '%s'" % warning_lineonly(
fn, "E146", "indentation mismatch (indent of %d) '%s'" %
(t - t_prev, tabs), i + 1) (t - t_prev, tabs), i + 1)
t_prev = t t_prev = t
...@@ -1135,7 +1143,8 @@ def quick_check_indentation(lines): ...@@ -1135,7 +1143,8 @@ def quick_check_indentation(lines):
ws_expand = ws.expandtabs(4) ws_expand = ws.expandtabs(4)
if ws_expand == ws_prev_expand: if ws_expand == ws_prev_expand:
if ws != ws_prev: if ws != ws_prev:
warning_lineonly("E152", "indentation tab/space mismatch", warning_lineonly(
fn, "E152", "indentation tab/space mismatch",
i + 1) i + 1)
ws_prev = ws ws_prev = ws
ws_prev_expand = ws_expand ws_prev_expand = ws_expand
...@@ -1146,7 +1155,7 @@ re_ifndef = re.compile(r"^\s*#\s*ifndef\s+([A-z0-9_]+).*$") ...@@ -1146,7 +1155,7 @@ re_ifndef = re.compile(r"^\s*#\s*ifndef\s+([A-z0-9_]+).*$")
re_define = re.compile(r"^\s*#\s*define\s+([A-z0-9_]+).*$") re_define = re.compile(r"^\s*#\s*define\s+([A-z0-9_]+).*$")
def quick_check_include_guard(lines): def quick_check_include_guard(fn, lines):
# found = 0 # found = 0
def_value = "" def_value = ""
ok = False ok = False
...@@ -1182,13 +1191,15 @@ def quick_check_include_guard(lines): ...@@ -1182,13 +1191,15 @@ def quick_check_include_guard(lines):
# print("found:", def_value, "->", filepath) # print("found:", def_value, "->", filepath)
if def_value != guard: if def_value != guard:
# print("%s: %s -> %s" % (filepath, def_value, guard)) # print("%s: %s -> %s" % (filepath, def_value, guard))
warning_lineonly("E147", "non-conforming include guard (found %r, expected %r)" % warning_lineonly(
fn, "E147", "non-conforming include guard (found %r, expected %r)" %
(def_value, guard), i + 1) (def_value, guard), i + 1)
else: else:
warning_lineonly("E148", "missing include guard %r" % guard, 1) warning_lineonly(
fn, "E148", "missing include guard %r" % guard, 1)
def quick_check_source(fp, code, args): def quick_check_source(fp, code, args, fn):
global filepath global filepath
...@@ -1199,14 +1210,14 @@ def quick_check_source(fp, code, args): ...@@ -1199,14 +1210,14 @@ def quick_check_source(fp, code, args):
lines = code.split("\n") lines = code.split("\n")
if is_header: if is_header:
quick_check_include_guard(lines) quick_check_include_guard(fn, lines)
quick_check_includes(lines) quick_check_includes(fn, lines)
quick_check_indentation(lines) quick_check_indentation(fn, lines)
def scan_source(fp, code, args): def scan_source(fp, code, args, fn):
# print("scanning: %r" % fp) # print("scanning: %r" % fp)
global filepath global filepath
...@@ -1238,20 +1249,20 @@ def scan_source(fp, code, args): ...@@ -1238,20 +1249,20 @@ def scan_source(fp, code, args):
# print(tok.type, tok.text) # print(tok.type, tok.text)
if tok.type == Token.Keyword: if tok.type == Token.Keyword:
if tok.text in {"switch", "while", "if", "for"}: if tok.text in {"switch", "while", "if", "for"}:
item_range = extract_statement_if(i) item_range = extract_statement_if(fn, i)
if item_range is not None: if item_range is not None:
blender_check_kw_if(item_range[0], i, item_range[1]) blender_check_kw_if(fn, item_range[0], i, item_range[1])
if tok.text == "switch": if tok.text == "switch":
blender_check_kw_switch(item_range[0], i, item_range[1]) blender_check_kw_switch(fn, item_range[0], i, item_range[1])
elif tok.text == "else": elif tok.text == "else":
blender_check_kw_else(i) blender_check_kw_else(fn, i)
elif tok.text == "sizeof": elif tok.text == "sizeof":
blender_check_kw_sizeof(i) blender_check_kw_sizeof(i)
elif tok.type == Token.Punctuation: elif tok.type == Token.Punctuation:
if tok.text == ",": if tok.text == ",":
blender_check_comma(i) blender_check_comma(fn, i)
elif tok.text == ".": elif tok.text == ".":
blender_check_period(i) blender_check_period(fn, i)
elif tok.text == "[": elif tok.text == "[":
# note, we're quite relaxed about this but # note, we're quite relaxed about this but
# disallow 'foo [' # disallow 'foo ['
...@@ -1260,16 +1271,16 @@ def scan_source(fp, code, args): ...@@ -1260,16 +1271,16 @@ def scan_source(fp, code, args):
# c++ can do delete [] # c++ can do delete []
pass pass
else: else:
warning("E149", "space before '['", i, i) warning(fn, "E149", "space before '['", i, i)
elif tok.text == "(": elif tok.text == "(":
# check if this is a cast, eg: # check if this is a cast, eg:
# (char), (char **), (float (*)[3]) # (char), (char **), (float (*)[3])
item_range = extract_cast(i) item_range = extract_cast(i)
if item_range is not None: if item_range is not None:
blender_check_cast(item_range[0], item_range[1]) blender_check_cast(fn, item_range[0], item_range[1])
elif tok.text == "{": elif tok.text == "{":
# check matching brace is indented correctly (slow!) # check matching brace is indented correctly (slow!)
blender_check_brace_indent(i) blender_check_brace_indent(fn, i)
# check previous character is either a '{' or whitespace. # check previous character is either a '{' or whitespace.
if ((tokens[i - 1].line == tok.line) and if ((tokens[i - 1].line == tok.line) and
...@@ -1277,15 +1288,15 @@ def scan_source(fp, code, args): ...@@ -1277,15 +1288,15 @@ def scan_source(fp, code, args):
tokens[i - 1].text == "{" or tokens[i - 1].text == "{" or
tokens[i - 1].flag & IS_CAST) tokens[i - 1].flag & IS_CAST)
): ):
warning("E150", "no space before '{'", i, i) warning(fn, "E150", "no space before '{'", i, i)
blender_check_function_definition(i) blender_check_function_definition(fn, i)
elif tok.type == Token.Operator: elif tok.type == Token.Operator:
# we check these in pairs, only want first # we check these in pairs, only want first
if tokens[i - 1].type != Token.Operator: if tokens[i - 1].type != Token.Operator:
op, index_kw_end = extract_operator(i) op, index_kw_end = extract_operator(i)
blender_check_operator(i, index_kw_end, op, is_cpp) blender_check_operator(fn, i, index_kw_end, op, is_cpp)
elif tok.type in Token.Comment: elif tok.type in Token.Comment:
doxyfn = None doxyfn = None
if "\\file" in tok.text: if "\\file" in tok.text:
...@@ -1296,12 +1307,12 @@ def scan_source(fp, code, args): ...@@ -1296,12 +1307,12 @@ def scan_source(fp, code, args):
if doxyfn is not None: if doxyfn is not None:
doxyfn_base = os.path.basename(doxyfn) doxyfn_base = os.path.basename(doxyfn)
if doxyfn_base != filepath_base: if doxyfn_base != filepath_base:
warning("E151", "doxygen filename mismatch %s != %s" % (doxyfn_base, filepath_base), i, i) warning(fn, "E151", "doxygen filename mismatch %s != %s" % (doxyfn_base, filepath_base), i, i)
doxyfn_split = doxyfn.split("/") doxyfn_split = doxyfn.split("/")
if len(doxyfn_split) > 1: if len(doxyfn_split) > 1:
fp_split = filepath_split[-len(doxyfn_split):] fp_split = filepath_split[-len(doxyfn_split):]
if doxyfn_split != fp_split: if doxyfn_split != fp_split:
warning("E151", "doxygen filepath mismatch %s != %s" % (doxyfn, "/".join(fp_split)), i, i) warning(fn, "E151", "doxygen filepath mismatch %s != %s" % (doxyfn, "/".join(fp_split)), i, i)
del fp_split del fp_split
del doxyfn_base, doxyfn_split del doxyfn_base, doxyfn_split
del doxyfn del doxyfn
...@@ -1309,7 +1320,7 @@ def scan_source(fp, code, args): ...@@ -1309,7 +1320,7 @@ def scan_source(fp, code, args):
# ensure line length # ensure line length
if (not args.no_length_check) and tok.type == Token.Text and tok.text == "\n": if (not args.no_length_check) and tok.type == Token.Text and tok.text == "\n":
# check line len # check line len
blender_check_linelength(index_line_start, i - 1, col) blender_check_linelength(fn, index_line_start, i - 1, col)
col = 0 col = 0
index_line_start = i + 1 index_line_start = i + 1
...@@ -1326,21 +1337,51 @@ def scan_source(fp, code, args): ...@@ -1326,21 +1337,51 @@ def scan_source(fp, code, args):
# #print(value, end="") # #print(value, end="")
def scan_source_filepath(filepath, args): def scan_source_filepath__cached(filepath, args, fn, cache):
cache_files_src, cache_files_dst = cache
h_code = hash_of_file(filepath)
info_src = cache_files_src.get(filepath)
if info_src is not None and info_src[0] == h_code:
for a in info_src[1]:
fn(*a)
cache_files_dst[filepath] = info_src
return None
else:
lines = []
info_dst = (h_code, lines)
def fn_wrap(*a):
fn_wrap.lines.append(a)
fn_wrap.fn(*a)
fn_wrap.fn = fn
fn_wrap.lines = lines
cache_files_dst[filepath] = info_dst
return cache_files_src, cache_files_dst, fn_wrap
def scan_source_filepath(filepath, args, fn, cache=None):
# for quick tests # for quick tests
# ~ if not filepath.endswith("creator.c"): # ~ if not filepath.endswith("creator.c"):
# ~ return # ~ return
code = open(filepath, 'r', encoding="utf-8").read() code = open(filepath, 'r', encoding="utf-8").read()
if cache:
cache_result = scan_source_filepath__cached(filepath, args, fn, cache)
if cache_result is None:
# No need to ececute
return
else:
cache_files_src, cache_files_dst, fn = cache_result
del cache_result
# fast checks which don't require full parsing # fast checks which don't require full parsing
quick_check_source(filepath, code, args) quick_check_source(filepath, code, args, fn)
# use lexer # use lexer
scan_source(filepath, code, args) scan_source(filepath, code, args, fn)
def scan_source_recursive(dirpath, args): def scan_source_recursive(dirpath, args, fn, cache=None):
import os import os
from os.path import join, splitext from os.path import join, splitext
...@@ -1367,7 +1408,7 @@ def scan_source_recursive(dirpath, args): ...@@ -1367,7 +1408,7 @@ def scan_source_recursive(dirpath, args):
if is_ignore(filepath): if is_ignore(filepath):
continue continue
scan_source_filepath(filepath, args) scan_source_filepath(filepath, args, fn, cache)
def create_parser(): def create_parser():
...@@ -1394,6 +1435,9 @@ def main(argv=None): ...@@ -1394,6 +1435,9 @@ def main(argv=None):
import sys import sys
import os import os
# For cache
import pickle
if argv is None: if argv is None:
argv = sys.argv[1:] argv = sys.argv[1:]
...@@ -1403,6 +1447,7 @@ def main(argv=None): ...@@ -1403,6 +1447,7 @@ def main(argv=None):
print("Scanning:", SOURCE_DIR) print("Scanning:", SOURCE_DIR)
if 0: if 0:
# SOURCE_DIR = os.path.normpath( # SOURCE_DIR = os.path.normpath(
# os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "..", "..")))) # os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))))
...@@ -1410,13 +1455,35 @@ def main(argv=None): ...@@ -1410,13 +1455,35 @@ def main(argv=None):
scan_source_recursive(os.path.join(SOURCE_DIR, "source/blender/makesrna/intern"), args) scan_source_recursive(os.path.join(SOURCE_DIR, "source/blender/makesrna/intern"), args)
sys.exit(0) sys.exit(0)
cache_filename = os.environ.get("CHECK_STYLE_C_CACHE", "")
if cache_filename:
if os.path.exists(cache_filename):
with open(cache_filename, 'rb') as fh:
(hash_of_script_src, cache_files_src) = pickle.load(fh)
else:
hash_of_script_src = b''
cache_files_dst = {}
hash_of_script_dst = hash_of_file(__file__)
# If we change the Python code, ignore old cache.
if hash_of_script_src != hash_of_script_dst:
cache_files_src = {}
cache = (cache_files_src, cache_files_dst)
else:
cache = None
for filepath in args.paths: for filepath in args.paths:
if os.path.isdir(filepath): if os.path.isdir(filepath):
# recursive search # recursive search
scan_source_recursive(filepath, args) scan_source_recursive(filepath, args, print, cache)
else: else:
# single file # single file
scan_source_filepath(filepath, args) scan_source_filepath(filepath, args, print, cache)
if cache_filename:
with open(cache_filename, 'wb') as fh:
pickle.dump((hash_of_script_dst, cache_files_dst), fh)
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -14,9 +14,7 @@ sys.path.append( ...@@ -14,9 +14,7 @@ sys.path.append(
import unittest import unittest
warnings = []
import check_style_c import check_style_c
check_style_c.print = warnings.append
# ---- # ----
parser = check_style_c.create_parser() parser = check_style_c.create_parser()
...@@ -36,8 +34,8 @@ FUNC_END = """ ...@@ -36,8 +34,8 @@ FUNC_END = """
def test_code(code): def test_code(code):
warnings.clear() warnings = []
check_style_c.scan_source("test.c", code, args) check_style_c.scan_source("test.c", code, args, warnings.append)
err_found = [w.split(":", 3)[2].strip() for w in warnings] err_found = [w.split(":", 3)[2].strip() for w in warnings]
# print(warnings) # print(warnings)
return err_found return err_found
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment