mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-04 21:00:40 +08:00
Compare commits
3 Commits
v0.28
...
tr/static_
Author | SHA1 | Date | |
---|---|---|---|
685f001298 | |||
88c2b90860 | |||
c84d84ace2 |
5
pr_agent/static_analysis/queries/Credits.md
Normal file
5
pr_agent/static_analysis/queries/Credits.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
# Credits
|
||||||
|
|
||||||
|
These queries, and some of the logic, were adopted from the excellent [Aider](https://github.com/paul-gauthier/aider/blob/main/aider/queries/README.md) project.
|
||||||
|
|
9
pr_agent/static_analysis/queries/tree-sitter-c-tags.scm
Normal file
9
pr_agent/static_analysis/queries/tree-sitter-c-tags.scm
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
(struct_specifier name: (type_identifier) @name.definition.class body:(_)) @definition.class
|
||||||
|
|
||||||
|
(declaration type: (union_specifier name: (type_identifier) @name.definition.class)) @definition.class
|
||||||
|
|
||||||
|
(function_declarator declarator: (identifier) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
(type_definition declarator: (type_identifier) @name.definition.type) @definition.type
|
||||||
|
|
||||||
|
(enum_specifier name: (type_identifier) @name.definition.type) @definition.type
|
@ -0,0 +1,46 @@
|
|||||||
|
(class_declaration
|
||||||
|
name: (identifier) @name.definition.class
|
||||||
|
) @definition.class
|
||||||
|
|
||||||
|
(class_declaration
|
||||||
|
bases: (base_list (_) @name.reference.class)
|
||||||
|
) @reference.class
|
||||||
|
|
||||||
|
(interface_declaration
|
||||||
|
name: (identifier) @name.definition.interface
|
||||||
|
) @definition.interface
|
||||||
|
|
||||||
|
(interface_declaration
|
||||||
|
bases: (base_list (_) @name.reference.interface)
|
||||||
|
) @reference.interface
|
||||||
|
|
||||||
|
(method_declaration
|
||||||
|
name: (identifier) @name.definition.method
|
||||||
|
) @definition.method
|
||||||
|
|
||||||
|
(object_creation_expression
|
||||||
|
type: (identifier) @name.reference.class
|
||||||
|
) @reference.class
|
||||||
|
|
||||||
|
(type_parameter_constraints_clause
|
||||||
|
target: (identifier) @name.reference.class
|
||||||
|
) @reference.class
|
||||||
|
|
||||||
|
(type_constraint
|
||||||
|
type: (identifier) @name.reference.class
|
||||||
|
) @reference.class
|
||||||
|
|
||||||
|
(variable_declaration
|
||||||
|
type: (identifier) @name.reference.class
|
||||||
|
) @reference.class
|
||||||
|
|
||||||
|
(invocation_expression
|
||||||
|
function:
|
||||||
|
(member_access_expression
|
||||||
|
name: (identifier) @name.reference.send
|
||||||
|
)
|
||||||
|
) @reference.send
|
||||||
|
|
||||||
|
(namespace_declaration
|
||||||
|
name: (identifier) @name.definition.module
|
||||||
|
) @definition.module
|
15
pr_agent/static_analysis/queries/tree-sitter-cpp-tags.scm
Normal file
15
pr_agent/static_analysis/queries/tree-sitter-cpp-tags.scm
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
(struct_specifier name: (type_identifier) @name.definition.class body:(_)) @definition.class
|
||||||
|
|
||||||
|
(declaration type: (union_specifier name: (type_identifier) @name.definition.class)) @definition.class
|
||||||
|
|
||||||
|
(function_declarator declarator: (identifier) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
(function_declarator declarator: (field_identifier) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
(function_declarator declarator: (qualified_identifier scope: (namespace_identifier) @scope name: (identifier) @name.definition.method)) @definition.method
|
||||||
|
|
||||||
|
(type_definition declarator: (type_identifier) @name.definition.type) @definition.type
|
||||||
|
|
||||||
|
(enum_specifier name: (type_identifier) @name.definition.type) @definition.type
|
||||||
|
|
||||||
|
(class_specifier name: (type_identifier) @name.definition.class) @definition.class
|
@ -0,0 +1,8 @@
|
|||||||
|
;; defun/defsubst
|
||||||
|
(function_definition name: (symbol) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
;; Treat macros as function definitions for the sake of TAGS.
|
||||||
|
(macro_definition name: (symbol) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
;; Match function calls
|
||||||
|
(list (symbol) @name.reference.function) @reference.function
|
54
pr_agent/static_analysis/queries/tree-sitter-elixir-tags.scm
Normal file
54
pr_agent/static_analysis/queries/tree-sitter-elixir-tags.scm
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
; Definitions
|
||||||
|
|
||||||
|
; * modules and protocols
|
||||||
|
(call
|
||||||
|
target: (identifier) @ignore
|
||||||
|
(arguments (alias) @name.definition.module)
|
||||||
|
(#match? @ignore "^(defmodule|defprotocol)$")) @definition.module
|
||||||
|
|
||||||
|
; * functions/macros
|
||||||
|
(call
|
||||||
|
target: (identifier) @ignore
|
||||||
|
(arguments
|
||||||
|
[
|
||||||
|
; zero-arity functions with no parentheses
|
||||||
|
(identifier) @name.definition.function
|
||||||
|
; regular function clause
|
||||||
|
(call target: (identifier) @name.definition.function)
|
||||||
|
; function clause with a guard clause
|
||||||
|
(binary_operator
|
||||||
|
left: (call target: (identifier) @name.definition.function)
|
||||||
|
operator: "when")
|
||||||
|
])
|
||||||
|
(#match? @ignore "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @definition.function
|
||||||
|
|
||||||
|
; References
|
||||||
|
|
||||||
|
; ignore calls to kernel/special-forms keywords
|
||||||
|
(call
|
||||||
|
target: (identifier) @ignore
|
||||||
|
(#match? @ignore "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defmodule|defprotocol|defimpl|defstruct|defexception|defoverridable|alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
|
||||||
|
|
||||||
|
; ignore module attributes
|
||||||
|
(unary_operator
|
||||||
|
operator: "@"
|
||||||
|
operand: (call
|
||||||
|
target: (identifier) @ignore))
|
||||||
|
|
||||||
|
; * function call
|
||||||
|
(call
|
||||||
|
target: [
|
||||||
|
; local
|
||||||
|
(identifier) @name.reference.call
|
||||||
|
; remote
|
||||||
|
(dot
|
||||||
|
right: (identifier) @name.reference.call)
|
||||||
|
]) @reference.call
|
||||||
|
|
||||||
|
; * pipe into function call
|
||||||
|
(binary_operator
|
||||||
|
operator: "|>"
|
||||||
|
right: (identifier) @name.reference.call) @reference.call
|
||||||
|
|
||||||
|
; * modules
|
||||||
|
(alias) @name.reference.module @reference.module
|
19
pr_agent/static_analysis/queries/tree-sitter-elm-tags.scm
Normal file
19
pr_agent/static_analysis/queries/tree-sitter-elm-tags.scm
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
(value_declaration (function_declaration_left (lower_case_identifier) @name.definition.function)) @definition.function
|
||||||
|
|
||||||
|
(function_call_expr (value_expr (value_qid) @name.reference.function)) @reference.function
|
||||||
|
(exposed_value (lower_case_identifier) @name.reference.function) @reference.function
|
||||||
|
(type_annotation ((lower_case_identifier) @name.reference.function) (colon)) @reference.function
|
||||||
|
|
||||||
|
(type_declaration ((upper_case_identifier) @name.definition.type)) @definition.type
|
||||||
|
|
||||||
|
(type_ref (upper_case_qid (upper_case_identifier) @name.reference.type)) @reference.type
|
||||||
|
(exposed_type (upper_case_identifier) @name.reference.type) @reference.type
|
||||||
|
|
||||||
|
(type_declaration (union_variant (upper_case_identifier) @name.definition.union)) @definition.union
|
||||||
|
|
||||||
|
(value_expr (upper_case_qid (upper_case_identifier) @name.reference.union)) @reference.union
|
||||||
|
|
||||||
|
|
||||||
|
(module_declaration
|
||||||
|
(upper_case_qid (upper_case_identifier)) @name.definition.module
|
||||||
|
) @definition.module
|
30
pr_agent/static_analysis/queries/tree-sitter-go-tags.scm
Normal file
30
pr_agent/static_analysis/queries/tree-sitter-go-tags.scm
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
(
|
||||||
|
(comment)* @doc
|
||||||
|
.
|
||||||
|
(function_declaration
|
||||||
|
name: (identifier) @name.definition.function) @definition.function
|
||||||
|
(#strip! @doc "^//\\s*")
|
||||||
|
(#set-adjacent! @doc @definition.function)
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)* @doc
|
||||||
|
.
|
||||||
|
(method_declaration
|
||||||
|
name: (field_identifier) @name.definition.method) @definition.method
|
||||||
|
(#strip! @doc "^//\\s*")
|
||||||
|
(#set-adjacent! @doc @definition.method)
|
||||||
|
)
|
||||||
|
|
||||||
|
(call_expression
|
||||||
|
function: [
|
||||||
|
(identifier) @name.reference.call
|
||||||
|
(parenthesized_expression (identifier) @name.reference.call)
|
||||||
|
(selector_expression field: (field_identifier) @name.reference.call)
|
||||||
|
(parenthesized_expression (selector_expression field: (field_identifier) @name.reference.call))
|
||||||
|
]) @reference.call
|
||||||
|
|
||||||
|
(type_spec
|
||||||
|
name: (type_identifier) @name.definition.type) @definition.type
|
||||||
|
|
||||||
|
(type_identifier) @name.reference.type @reference.type
|
20
pr_agent/static_analysis/queries/tree-sitter-java-tags.scm
Normal file
20
pr_agent/static_analysis/queries/tree-sitter-java-tags.scm
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
(class_declaration
|
||||||
|
name: (identifier) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(method_declaration
|
||||||
|
name: (identifier) @name.definition.method) @definition.method
|
||||||
|
|
||||||
|
(method_invocation
|
||||||
|
name: (identifier) @name.reference.call
|
||||||
|
arguments: (argument_list) @reference.call)
|
||||||
|
|
||||||
|
(interface_declaration
|
||||||
|
name: (identifier) @name.definition.interface) @definition.interface
|
||||||
|
|
||||||
|
(type_list
|
||||||
|
(type_identifier) @name.reference.implementation) @reference.implementation
|
||||||
|
|
||||||
|
(object_creation_expression
|
||||||
|
type: (type_identifier) @name.reference.class) @reference.class
|
||||||
|
|
||||||
|
(superclass (type_identifier) @name.reference.class) @reference.class
|
@ -0,0 +1,88 @@
|
|||||||
|
(
|
||||||
|
(comment)* @doc
|
||||||
|
.
|
||||||
|
(method_definition
|
||||||
|
name: (property_identifier) @name.definition.method) @definition.method
|
||||||
|
(#not-eq? @name.definition.method "constructor")
|
||||||
|
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
|
||||||
|
(#select-adjacent! @doc @definition.method)
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)* @doc
|
||||||
|
.
|
||||||
|
[
|
||||||
|
(class
|
||||||
|
name: (_) @name.definition.class)
|
||||||
|
(class_declaration
|
||||||
|
name: (_) @name.definition.class)
|
||||||
|
] @definition.class
|
||||||
|
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
|
||||||
|
(#select-adjacent! @doc @definition.class)
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)* @doc
|
||||||
|
.
|
||||||
|
[
|
||||||
|
(function
|
||||||
|
name: (identifier) @name.definition.function)
|
||||||
|
(function_declaration
|
||||||
|
name: (identifier) @name.definition.function)
|
||||||
|
(generator_function
|
||||||
|
name: (identifier) @name.definition.function)
|
||||||
|
(generator_function_declaration
|
||||||
|
name: (identifier) @name.definition.function)
|
||||||
|
] @definition.function
|
||||||
|
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
|
||||||
|
(#select-adjacent! @doc @definition.function)
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)* @doc
|
||||||
|
.
|
||||||
|
(lexical_declaration
|
||||||
|
(variable_declarator
|
||||||
|
name: (identifier) @name.definition.function
|
||||||
|
value: [(arrow_function) (function)]) @definition.function)
|
||||||
|
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
|
||||||
|
(#select-adjacent! @doc @definition.function)
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)* @doc
|
||||||
|
.
|
||||||
|
(variable_declaration
|
||||||
|
(variable_declarator
|
||||||
|
name: (identifier) @name.definition.function
|
||||||
|
value: [(arrow_function) (function)]) @definition.function)
|
||||||
|
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
|
||||||
|
(#select-adjacent! @doc @definition.function)
|
||||||
|
)
|
||||||
|
|
||||||
|
(assignment_expression
|
||||||
|
left: [
|
||||||
|
(identifier) @name.definition.function
|
||||||
|
(member_expression
|
||||||
|
property: (property_identifier) @name.definition.function)
|
||||||
|
]
|
||||||
|
right: [(arrow_function) (function)]
|
||||||
|
) @definition.function
|
||||||
|
|
||||||
|
(pair
|
||||||
|
key: (property_identifier) @name.definition.function
|
||||||
|
value: [(arrow_function) (function)]) @definition.function
|
||||||
|
|
||||||
|
(
|
||||||
|
(call_expression
|
||||||
|
function: (identifier) @name.reference.call) @reference.call
|
||||||
|
(#not-match? @name.reference.call "^(require)$")
|
||||||
|
)
|
||||||
|
|
||||||
|
(call_expression
|
||||||
|
function: (member_expression
|
||||||
|
property: (property_identifier) @name.reference.call)
|
||||||
|
arguments: (_) @reference.call)
|
||||||
|
|
||||||
|
(new_expression
|
||||||
|
constructor: (_) @name.reference.class) @reference.class
|
115
pr_agent/static_analysis/queries/tree-sitter-ocaml-tags.scm
Normal file
115
pr_agent/static_analysis/queries/tree-sitter-ocaml-tags.scm
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
; Modules
|
||||||
|
;--------
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)? @doc .
|
||||||
|
(module_definition (module_binding (module_name) @name.definition.module) @definition.module)
|
||||||
|
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||||
|
)
|
||||||
|
|
||||||
|
(module_path (module_name) @name.reference.module) @reference.module
|
||||||
|
|
||||||
|
; Module types
|
||||||
|
;--------------
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)? @doc .
|
||||||
|
(module_type_definition (module_type_name) @name.definition.interface) @definition.interface
|
||||||
|
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||||
|
)
|
||||||
|
|
||||||
|
(module_type_path (module_type_name) @name.reference.implementation) @reference.implementation
|
||||||
|
|
||||||
|
; Functions
|
||||||
|
;----------
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)? @doc .
|
||||||
|
(value_definition
|
||||||
|
[
|
||||||
|
(let_binding
|
||||||
|
pattern: (value_name) @name.definition.function
|
||||||
|
(parameter))
|
||||||
|
(let_binding
|
||||||
|
pattern: (value_name) @name.definition.function
|
||||||
|
body: [(fun_expression) (function_expression)])
|
||||||
|
] @definition.function
|
||||||
|
)
|
||||||
|
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)? @doc .
|
||||||
|
(external (value_name) @name.definition.function) @definition.function
|
||||||
|
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||||
|
)
|
||||||
|
|
||||||
|
(application_expression
|
||||||
|
function: (value_path (value_name) @name.reference.call)) @reference.call
|
||||||
|
|
||||||
|
(infix_expression
|
||||||
|
left: (value_path (value_name) @name.reference.call)
|
||||||
|
operator: (concat_operator) @reference.call
|
||||||
|
(#eq? @reference.call "@@"))
|
||||||
|
|
||||||
|
(infix_expression
|
||||||
|
operator: (rel_operator) @reference.call
|
||||||
|
right: (value_path (value_name) @name.reference.call)
|
||||||
|
(#eq? @reference.call "|>"))
|
||||||
|
|
||||||
|
; Operator
|
||||||
|
;---------
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)? @doc .
|
||||||
|
(value_definition
|
||||||
|
(let_binding
|
||||||
|
pattern: (parenthesized_operator (_) @name.definition.function)) @definition.function)
|
||||||
|
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||||
|
)
|
||||||
|
|
||||||
|
[
|
||||||
|
(prefix_operator)
|
||||||
|
(sign_operator)
|
||||||
|
(pow_operator)
|
||||||
|
(mult_operator)
|
||||||
|
(add_operator)
|
||||||
|
(concat_operator)
|
||||||
|
(rel_operator)
|
||||||
|
(and_operator)
|
||||||
|
(or_operator)
|
||||||
|
(assign_operator)
|
||||||
|
(hash_operator)
|
||||||
|
(indexing_operator)
|
||||||
|
(let_operator)
|
||||||
|
(let_and_operator)
|
||||||
|
(match_operator)
|
||||||
|
] @name.reference.call @reference.call
|
||||||
|
|
||||||
|
; Classes
|
||||||
|
;--------
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)? @doc .
|
||||||
|
[
|
||||||
|
(class_definition (class_binding (class_name) @name.definition.class) @definition.class)
|
||||||
|
(class_type_definition (class_type_binding (class_type_name) @name.definition.class) @definition.class)
|
||||||
|
]
|
||||||
|
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||||
|
)
|
||||||
|
|
||||||
|
[
|
||||||
|
(class_path (class_name) @name.reference.class)
|
||||||
|
(class_type_path (class_type_name) @name.reference.class)
|
||||||
|
] @reference.class
|
||||||
|
|
||||||
|
; Methods
|
||||||
|
;--------
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)? @doc .
|
||||||
|
(method_definition (method_name) @name.definition.method) @definition.method
|
||||||
|
(#strip! @doc "^\\(\\*\\*?\\s*|\\s\\*\\)$")
|
||||||
|
)
|
||||||
|
|
||||||
|
(method_invocation (method_name) @name.reference.call) @reference.call
|
26
pr_agent/static_analysis/queries/tree-sitter-php-tags.scm
Normal file
26
pr_agent/static_analysis/queries/tree-sitter-php-tags.scm
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
(class_declaration
|
||||||
|
name: (name) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(function_definition
|
||||||
|
name: (name) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
(method_declaration
|
||||||
|
name: (name) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
(object_creation_expression
|
||||||
|
[
|
||||||
|
(qualified_name (name) @name.reference.class)
|
||||||
|
(variable_name (name) @name.reference.class)
|
||||||
|
]) @reference.class
|
||||||
|
|
||||||
|
(function_call_expression
|
||||||
|
function: [
|
||||||
|
(qualified_name (name) @name.reference.call)
|
||||||
|
(variable_name (name)) @name.reference.call
|
||||||
|
]) @reference.call
|
||||||
|
|
||||||
|
(scoped_call_expression
|
||||||
|
name: (name) @name.reference.call) @reference.call
|
||||||
|
|
||||||
|
(member_call_expression
|
||||||
|
name: (name) @name.reference.call) @reference.call
|
12
pr_agent/static_analysis/queries/tree-sitter-python-tags.scm
Normal file
12
pr_agent/static_analysis/queries/tree-sitter-python-tags.scm
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
(class_definition
|
||||||
|
name: (identifier) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(function_definition
|
||||||
|
name: (identifier) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
(call
|
||||||
|
function: [
|
||||||
|
(identifier) @name.reference.call
|
||||||
|
(attribute
|
||||||
|
attribute: (identifier) @name.reference.call)
|
||||||
|
]) @reference.call
|
26
pr_agent/static_analysis/queries/tree-sitter-ql-tags.scm
Normal file
26
pr_agent/static_analysis/queries/tree-sitter-ql-tags.scm
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
(classlessPredicate
|
||||||
|
name: (predicateName) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
(memberPredicate
|
||||||
|
name: (predicateName) @name.definition.method) @definition.method
|
||||||
|
|
||||||
|
(aritylessPredicateExpr
|
||||||
|
name: (literalId) @name.reference.call) @reference.call
|
||||||
|
|
||||||
|
(module
|
||||||
|
name: (moduleName) @name.definition.module) @definition.module
|
||||||
|
|
||||||
|
(dataclass
|
||||||
|
name: (className) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(datatype
|
||||||
|
name: (className) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(datatypeBranch
|
||||||
|
name: (className) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(qualifiedRhs
|
||||||
|
name: (predicateName) @name.reference.call) @reference.call
|
||||||
|
|
||||||
|
(typeExpr
|
||||||
|
name: (className) @name.reference.type) @reference.type
|
64
pr_agent/static_analysis/queries/tree-sitter-ruby-tags.scm
Normal file
64
pr_agent/static_analysis/queries/tree-sitter-ruby-tags.scm
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
; Method definitions
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)* @doc
|
||||||
|
.
|
||||||
|
[
|
||||||
|
(method
|
||||||
|
name: (_) @name.definition.method) @definition.method
|
||||||
|
(singleton_method
|
||||||
|
name: (_) @name.definition.method) @definition.method
|
||||||
|
]
|
||||||
|
(#strip! @doc "^#\\s*")
|
||||||
|
(#select-adjacent! @doc @definition.method)
|
||||||
|
)
|
||||||
|
|
||||||
|
(alias
|
||||||
|
name: (_) @name.definition.method) @definition.method
|
||||||
|
|
||||||
|
(setter
|
||||||
|
(identifier) @ignore)
|
||||||
|
|
||||||
|
; Class definitions
|
||||||
|
|
||||||
|
(
|
||||||
|
(comment)* @doc
|
||||||
|
.
|
||||||
|
[
|
||||||
|
(class
|
||||||
|
name: [
|
||||||
|
(constant) @name.definition.class
|
||||||
|
(scope_resolution
|
||||||
|
name: (_) @name.definition.class)
|
||||||
|
]) @definition.class
|
||||||
|
(singleton_class
|
||||||
|
value: [
|
||||||
|
(constant) @name.definition.class
|
||||||
|
(scope_resolution
|
||||||
|
name: (_) @name.definition.class)
|
||||||
|
]) @definition.class
|
||||||
|
]
|
||||||
|
(#strip! @doc "^#\\s*")
|
||||||
|
(#select-adjacent! @doc @definition.class)
|
||||||
|
)
|
||||||
|
|
||||||
|
; Module definitions
|
||||||
|
|
||||||
|
(
|
||||||
|
(module
|
||||||
|
name: [
|
||||||
|
(constant) @name.definition.module
|
||||||
|
(scope_resolution
|
||||||
|
name: (_) @name.definition.module)
|
||||||
|
]) @definition.module
|
||||||
|
)
|
||||||
|
|
||||||
|
; Calls
|
||||||
|
|
||||||
|
(call method: (identifier) @name.reference.call) @reference.call
|
||||||
|
|
||||||
|
(
|
||||||
|
[(identifier) (constant)] @name.reference.call @reference.call
|
||||||
|
(#is-not? local)
|
||||||
|
(#not-match? @name.reference.call "^(lambda|load|require|require_relative|__FILE__|__LINE__)$")
|
||||||
|
)
|
60
pr_agent/static_analysis/queries/tree-sitter-rust-tags.scm
Normal file
60
pr_agent/static_analysis/queries/tree-sitter-rust-tags.scm
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
; ADT definitions
|
||||||
|
|
||||||
|
(struct_item
|
||||||
|
name: (type_identifier) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(enum_item
|
||||||
|
name: (type_identifier) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(union_item
|
||||||
|
name: (type_identifier) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
; type aliases
|
||||||
|
|
||||||
|
(type_item
|
||||||
|
name: (type_identifier) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
; method definitions
|
||||||
|
|
||||||
|
(declaration_list
|
||||||
|
(function_item
|
||||||
|
name: (identifier) @name.definition.method)) @definition.method
|
||||||
|
|
||||||
|
; function definitions
|
||||||
|
|
||||||
|
(function_item
|
||||||
|
name: (identifier) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
; trait definitions
|
||||||
|
(trait_item
|
||||||
|
name: (type_identifier) @name.definition.interface) @definition.interface
|
||||||
|
|
||||||
|
; module definitions
|
||||||
|
(mod_item
|
||||||
|
name: (identifier) @name.definition.module) @definition.module
|
||||||
|
|
||||||
|
; macro definitions
|
||||||
|
|
||||||
|
(macro_definition
|
||||||
|
name: (identifier) @name.definition.macro) @definition.macro
|
||||||
|
|
||||||
|
; references
|
||||||
|
|
||||||
|
(call_expression
|
||||||
|
function: (identifier) @name.reference.call) @reference.call
|
||||||
|
|
||||||
|
(call_expression
|
||||||
|
function: (field_expression
|
||||||
|
field: (field_identifier) @name.reference.call)) @reference.call
|
||||||
|
|
||||||
|
(macro_invocation
|
||||||
|
macro: (identifier) @name.reference.call) @reference.call
|
||||||
|
|
||||||
|
; implementations
|
||||||
|
|
||||||
|
(impl_item
|
||||||
|
trait: (type_identifier) @name.reference.implementation) @reference.implementation
|
||||||
|
|
||||||
|
(impl_item
|
||||||
|
type: (type_identifier) @name.reference.implementation
|
||||||
|
!trait) @reference.implementation
|
@ -0,0 +1,41 @@
|
|||||||
|
(function_signature
|
||||||
|
name: (identifier) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
(method_signature
|
||||||
|
name: (property_identifier) @name.definition.method) @definition.method
|
||||||
|
|
||||||
|
(abstract_method_signature
|
||||||
|
name: (property_identifier) @name.definition.method) @definition.method
|
||||||
|
|
||||||
|
(abstract_class_declaration
|
||||||
|
name: (type_identifier) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(module
|
||||||
|
name: (identifier) @name.definition.module) @definition.module
|
||||||
|
|
||||||
|
(interface_declaration
|
||||||
|
name: (type_identifier) @name.definition.interface) @definition.interface
|
||||||
|
|
||||||
|
(type_annotation
|
||||||
|
(type_identifier) @name.reference.type) @reference.type
|
||||||
|
|
||||||
|
(new_expression
|
||||||
|
constructor: (identifier) @name.reference.class) @reference.class
|
||||||
|
|
||||||
|
(function_declaration
|
||||||
|
name: (identifier) @name.definition.function) @definition.function
|
||||||
|
|
||||||
|
(method_definition
|
||||||
|
name: (property_identifier) @name.definition.method) @definition.method
|
||||||
|
|
||||||
|
(class_declaration
|
||||||
|
name: (type_identifier) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(interface_declaration
|
||||||
|
name: (type_identifier) @name.definition.class) @definition.class
|
||||||
|
|
||||||
|
(type_alias_declaration
|
||||||
|
name: (type_identifier) @name.definition.type) @definition.type
|
||||||
|
|
||||||
|
(enum_declaration
|
||||||
|
name: (identifier) @name.definition.enum) @definition.enum
|
150
pr_agent/static_analysis/src/file_summary.py
Normal file
150
pr_agent/static_analysis/src/file_summary.py
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from grep_ast import TreeContext
|
||||||
|
from grep_ast.parsers import PARSERS
|
||||||
|
# from pygments.lexers import guess_lexer_for_filename
|
||||||
|
# from pygments.token import Token
|
||||||
|
from tree_sitter_languages import get_language, get_parser
|
||||||
|
|
||||||
|
|
||||||
|
def filename_to_lang(filename):
|
||||||
|
file_extension = os.path.splitext(filename)[0]
|
||||||
|
lang = PARSERS.get(file_extension)
|
||||||
|
return lang
|
||||||
|
|
||||||
|
class FileSummary:
|
||||||
|
"""
|
||||||
|
This class is used to summarize the content of a file using tree-sitter queries.
|
||||||
|
Supported languages: C, C++, C#, elisp, elixir, go, java, javascript, ocaml, php, python, ql, ruby, rust, typescript
|
||||||
|
"""
|
||||||
|
def __init__(self, fname_full_path: str, project_base_path, parent_context=True, child_context=False, header_max=0):
|
||||||
|
self.fname_full_path = fname_full_path
|
||||||
|
self.project_base_path = project_base_path
|
||||||
|
self.fname_rel = os.path.relpath(fname_full_path, project_base_path)
|
||||||
|
self.main_queries_path = Path(__file__).parent.parent // 'queries'
|
||||||
|
if not os.path.exists(fname_full_path):
|
||||||
|
print(f"File {fname_full_path} does not exist")
|
||||||
|
with open(fname_full_path, "w") as f:
|
||||||
|
code = f.read()
|
||||||
|
self.code = code.rstrip("\n") + "\n"
|
||||||
|
self.parent_context = parent_context
|
||||||
|
self.child_context = child_context
|
||||||
|
self.header_max = header_max
|
||||||
|
|
||||||
|
def summarize(self):
|
||||||
|
query_results = self.get_query_results()
|
||||||
|
summary_str = self.query_processing(query_results)
|
||||||
|
return summary_str
|
||||||
|
|
||||||
|
def render_file_summary(self, lines_of_interest: list):
|
||||||
|
code = self.code
|
||||||
|
fname_rel = self.fname_rel
|
||||||
|
context = TreeContext(
|
||||||
|
fname_rel,
|
||||||
|
code,
|
||||||
|
color=False,
|
||||||
|
line_number=True, # number the lines (1-indexed)
|
||||||
|
parent_context=self.parent_context,
|
||||||
|
child_context=self.child_context,
|
||||||
|
last_line=False,
|
||||||
|
margin=0,
|
||||||
|
mark_lois=False,
|
||||||
|
loi_pad=0,
|
||||||
|
header_max=self.header_max, # max number of lines to show in a function header
|
||||||
|
show_top_of_file_parent_scope=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
context.lines_of_interest = set()
|
||||||
|
context.add_lines_of_interest(lines_of_interest)
|
||||||
|
context.add_context()
|
||||||
|
res = context.format()
|
||||||
|
return res
|
||||||
|
|
||||||
|
def query_processing(self, query_results: list):
|
||||||
|
if not query_results:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
output = ""
|
||||||
|
def_lines = [q['line'] for q in query_results if q['kind'] == "def"]
|
||||||
|
output += "\n"
|
||||||
|
output += query_results[0]['fname'] + ":\n"
|
||||||
|
output += self.render_file_summary(def_lines)
|
||||||
|
return output
|
||||||
|
|
||||||
|
def get_queries_scheme(self, lang) -> str:
|
||||||
|
try:
|
||||||
|
# Load the relevant queries
|
||||||
|
path = os.path.join(self.main_queries_path, f"tree-sitter-{lang}-tags.scm")
|
||||||
|
with open(path, "r") as f:
|
||||||
|
return f.read()
|
||||||
|
except KeyError:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_query_results(self):
|
||||||
|
fname_rel = self.fname_rel
|
||||||
|
code = self.code
|
||||||
|
lang = filename_to_lang(fname_rel)
|
||||||
|
if not lang:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
language = get_language(lang)
|
||||||
|
parser = get_parser(lang)
|
||||||
|
except Exception as err:
|
||||||
|
print(f"Skipping file {fname_rel}: {err}")
|
||||||
|
return
|
||||||
|
|
||||||
|
query_scheme_str = self.get_queries_scheme(lang)
|
||||||
|
tree = parser.parse(bytes(code, "utf-8"))
|
||||||
|
|
||||||
|
# Run the queries
|
||||||
|
query = language.query(query_scheme_str)
|
||||||
|
captures = list(query.captures(tree.root_node))
|
||||||
|
|
||||||
|
# Parse the results into a list of "def" and "ref" tags
|
||||||
|
visited_set = set()
|
||||||
|
results = []
|
||||||
|
for node, tag in captures:
|
||||||
|
if tag.startswith("name.definition."):
|
||||||
|
kind = "ref"
|
||||||
|
elif tag.startswith("name.reference."):
|
||||||
|
kind = "def"
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
visited_set.add(kind)
|
||||||
|
result = dict(
|
||||||
|
fname=fname_rel,
|
||||||
|
name=node.text.decode("utf-8"),
|
||||||
|
kind=kind,
|
||||||
|
line=node.start_point[0],
|
||||||
|
)
|
||||||
|
results.append(result)
|
||||||
|
|
||||||
|
if "ref" in visited_set:
|
||||||
|
return results
|
||||||
|
if "def" not in visited_set:
|
||||||
|
return results
|
||||||
|
|
||||||
|
## currently we are interested only in defs
|
||||||
|
# # We saw defs, without any refs
|
||||||
|
# # Some files only provide defs (cpp, for example)
|
||||||
|
# # Use pygments to backfill refs
|
||||||
|
# try:
|
||||||
|
# lexer = guess_lexer_for_filename(fname, code)
|
||||||
|
# except Exception:
|
||||||
|
# return
|
||||||
|
#
|
||||||
|
# tokens = list(lexer.get_tokens(code))
|
||||||
|
# tokens = [token[1] for token in tokens if token[0] in Token.Name]
|
||||||
|
#
|
||||||
|
# for t in tokens:
|
||||||
|
# result = dict(
|
||||||
|
# fname=fname,
|
||||||
|
# name=t,
|
||||||
|
# kind="ref",
|
||||||
|
# line=-1,
|
||||||
|
# )
|
||||||
|
# results.append(result)
|
||||||
|
return results
|
428
pr_agent/static_analysis/tests/example_files/AES.cpp
Normal file
428
pr_agent/static_analysis/tests/example_files/AES.cpp
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
// Taken from 'https://github.com/dolphin-emu/dolphin'
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <bit>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <mbedtls/aes.h>
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
|
#include "Common/CPUDetect.h"
|
||||||
|
#include "Common/Crypto/AES.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <intrin.h>
|
||||||
|
#else
|
||||||
|
#if defined(_M_X86_64)
|
||||||
|
#include <x86intrin.h>
|
||||||
|
#elif defined(_M_ARM_64)
|
||||||
|
#include <arm_acle.h>
|
||||||
|
#include <arm_neon.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define ATTRIBUTE_TARGET(x)
|
||||||
|
#else
|
||||||
|
#define ATTRIBUTE_TARGET(x) [[gnu::target(x)]]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Common::AES
|
||||||
|
{
|
||||||
|
// For x64 and arm64, it's very unlikely a user's cpu does not support the accelerated version,
|
||||||
|
// fallback is just in case.
|
||||||
|
template <Mode AesMode>
|
||||||
|
class ContextGeneric final : public Context
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ContextGeneric(const u8* key)
|
||||||
|
{
|
||||||
|
mbedtls_aes_init(&ctx);
|
||||||
|
if constexpr (AesMode == Mode::Encrypt)
|
||||||
|
ASSERT(!mbedtls_aes_setkey_enc(&ctx, key, 128));
|
||||||
|
else
|
||||||
|
ASSERT(!mbedtls_aes_setkey_dec(&ctx, key, 128));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
|
||||||
|
size_t len) const override
|
||||||
|
{
|
||||||
|
std::array<u8, BLOCK_SIZE> iv_tmp{};
|
||||||
|
if (iv)
|
||||||
|
std::memcpy(&iv_tmp[0], iv, BLOCK_SIZE);
|
||||||
|
|
||||||
|
constexpr int mode = (AesMode == Mode::Encrypt) ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT;
|
||||||
|
if (mbedtls_aes_crypt_cbc(const_cast<mbedtls_aes_context*>(&ctx), mode, len, &iv_tmp[0], buf_in,
|
||||||
|
buf_out))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (iv_out)
|
||||||
|
std::memcpy(iv_out, &iv_tmp[0], BLOCK_SIZE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mbedtls_aes_context ctx{};
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(_M_X86_64)
|
||||||
|
|
||||||
|
// Note that (for instructions with same data width) the actual instructions emitted vary depending
|
||||||
|
// on compiler and flags. The naming is somewhat confusing, because VAES cpuid flag was added after
|
||||||
|
// VAES(VEX.128):
|
||||||
|
// clang-format off
|
||||||
|
// instructions | cpuid flag | #define
|
||||||
|
// AES(128) | AES | -
|
||||||
|
// VAES(VEX.128) | AES & AVX | __AVX__
|
||||||
|
// VAES(VEX.256) | VAES | -
|
||||||
|
// VAES(EVEX.128) | VAES & AVX512VL | __AVX512VL__
|
||||||
|
// VAES(EVEX.256) | VAES & AVX512VL | __AVX512VL__
|
||||||
|
// VAES(EVEX.512) | VAES & AVX512F | __AVX512F__
|
||||||
|
// clang-format on
|
||||||
|
template <Mode AesMode>
|
||||||
|
class ContextAESNI final : public Context
|
||||||
|
{
|
||||||
|
static inline __m128i Aes128KeygenAssistFinish(__m128i key, __m128i kga)
|
||||||
|
{
|
||||||
|
__m128i tmp = _mm_shuffle_epi32(kga, _MM_SHUFFLE(3, 3, 3, 3));
|
||||||
|
tmp = _mm_xor_si128(tmp, key);
|
||||||
|
|
||||||
|
key = _mm_slli_si128(key, 4);
|
||||||
|
tmp = _mm_xor_si128(tmp, key);
|
||||||
|
key = _mm_slli_si128(key, 4);
|
||||||
|
tmp = _mm_xor_si128(tmp, key);
|
||||||
|
key = _mm_slli_si128(key, 4);
|
||||||
|
tmp = _mm_xor_si128(tmp, key);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t RoundIdx>
|
||||||
|
ATTRIBUTE_TARGET("aes")
|
||||||
|
inline constexpr void StoreRoundKey(__m128i rk)
|
||||||
|
{
|
||||||
|
if constexpr (AesMode == Mode::Encrypt)
|
||||||
|
round_keys[RoundIdx] = rk;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
constexpr size_t idx = NUM_ROUND_KEYS - RoundIdx - 1;
|
||||||
|
if constexpr (idx == 0 || idx == NUM_ROUND_KEYS - 1)
|
||||||
|
round_keys[idx] = rk;
|
||||||
|
else
|
||||||
|
round_keys[idx] = _mm_aesimc_si128(rk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t RoundIdx, int Rcon>
|
||||||
|
ATTRIBUTE_TARGET("aes")
|
||||||
|
inline constexpr __m128i Aes128Keygen(__m128i rk)
|
||||||
|
{
|
||||||
|
rk = Aes128KeygenAssistFinish(rk, _mm_aeskeygenassist_si128(rk, Rcon));
|
||||||
|
StoreRoundKey<RoundIdx>(rk);
|
||||||
|
return rk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
ContextAESNI(const u8* key)
|
||||||
|
{
|
||||||
|
__m128i rk = _mm_loadu_si128((const __m128i*)key);
|
||||||
|
StoreRoundKey<0>(rk);
|
||||||
|
rk = Aes128Keygen<1, 0x01>(rk);
|
||||||
|
rk = Aes128Keygen<2, 0x02>(rk);
|
||||||
|
rk = Aes128Keygen<3, 0x04>(rk);
|
||||||
|
rk = Aes128Keygen<4, 0x08>(rk);
|
||||||
|
rk = Aes128Keygen<5, 0x10>(rk);
|
||||||
|
rk = Aes128Keygen<6, 0x20>(rk);
|
||||||
|
rk = Aes128Keygen<7, 0x40>(rk);
|
||||||
|
rk = Aes128Keygen<8, 0x80>(rk);
|
||||||
|
rk = Aes128Keygen<9, 0x1b>(rk);
|
||||||
|
Aes128Keygen<10, 0x36>(rk);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATTRIBUTE_TARGET("aes")
|
||||||
|
inline void CryptBlock(__m128i* iv, const u8* buf_in, u8* buf_out) const
|
||||||
|
{
|
||||||
|
__m128i block = _mm_loadu_si128((const __m128i*)buf_in);
|
||||||
|
|
||||||
|
if constexpr (AesMode == Mode::Encrypt)
|
||||||
|
{
|
||||||
|
block = _mm_xor_si128(_mm_xor_si128(block, *iv), round_keys[0]);
|
||||||
|
|
||||||
|
for (size_t i = 1; i < Nr; ++i)
|
||||||
|
block = _mm_aesenc_si128(block, round_keys[i]);
|
||||||
|
block = _mm_aesenclast_si128(block, round_keys[Nr]);
|
||||||
|
|
||||||
|
*iv = block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__m128i iv_next = block;
|
||||||
|
|
||||||
|
block = _mm_xor_si128(block, round_keys[0]);
|
||||||
|
|
||||||
|
for (size_t i = 1; i < Nr; ++i)
|
||||||
|
block = _mm_aesdec_si128(block, round_keys[i]);
|
||||||
|
block = _mm_aesdeclast_si128(block, round_keys[Nr]);
|
||||||
|
|
||||||
|
block = _mm_xor_si128(block, *iv);
|
||||||
|
*iv = iv_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
_mm_storeu_si128((__m128i*)buf_out, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes advantage of instruction pipelining to parallelize.
|
||||||
|
template <size_t NumBlocks>
|
||||||
|
ATTRIBUTE_TARGET("aes")
|
||||||
|
inline void DecryptPipelined(__m128i* iv, const u8* buf_in, u8* buf_out) const
|
||||||
|
{
|
||||||
|
constexpr size_t Depth = NumBlocks;
|
||||||
|
|
||||||
|
__m128i block[Depth];
|
||||||
|
for (size_t d = 0; d < Depth; d++)
|
||||||
|
block[d] = _mm_loadu_si128(&((const __m128i*)buf_in)[d]);
|
||||||
|
|
||||||
|
__m128i iv_next[1 + Depth];
|
||||||
|
iv_next[0] = *iv;
|
||||||
|
for (size_t d = 0; d < Depth; d++)
|
||||||
|
iv_next[1 + d] = block[d];
|
||||||
|
|
||||||
|
for (size_t d = 0; d < Depth; d++)
|
||||||
|
block[d] = _mm_xor_si128(block[d], round_keys[0]);
|
||||||
|
|
||||||
|
// The main speedup is here
|
||||||
|
for (size_t i = 1; i < Nr; ++i)
|
||||||
|
for (size_t d = 0; d < Depth; d++)
|
||||||
|
block[d] = _mm_aesdec_si128(block[d], round_keys[i]);
|
||||||
|
for (size_t d = 0; d < Depth; d++)
|
||||||
|
block[d] = _mm_aesdeclast_si128(block[d], round_keys[Nr]);
|
||||||
|
|
||||||
|
for (size_t d = 0; d < Depth; d++)
|
||||||
|
block[d] = _mm_xor_si128(block[d], iv_next[d]);
|
||||||
|
*iv = iv_next[1 + Depth - 1];
|
||||||
|
|
||||||
|
for (size_t d = 0; d < Depth; d++)
|
||||||
|
_mm_storeu_si128(&((__m128i*)buf_out)[d], block[d]);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
|
||||||
|
size_t len) const override
|
||||||
|
{
|
||||||
|
if (len % BLOCK_SIZE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
__m128i iv_block = iv ? _mm_loadu_si128((const __m128i*)iv) : _mm_setzero_si128();
|
||||||
|
|
||||||
|
if constexpr (AesMode == Mode::Decrypt)
|
||||||
|
{
|
||||||
|
// On amd zen2...(benchmark, not real-world):
|
||||||
|
// With AES(128) instructions, BLOCK_DEPTH results in following speedup vs. non-pipelined: 4:
|
||||||
|
// 18%, 8: 22%, 9: 26%, 10-15: 31%. 16: 8% (register exhaustion). With VAES(VEX.128), 10 gives
|
||||||
|
// 36% speedup vs. its corresponding baseline. VAES(VEX.128) is ~4% faster than AES(128). The
|
||||||
|
// result is similar on zen3.
|
||||||
|
// Zen3 in general is 20% faster than zen2 in aes, and VAES(VEX.256) is 35% faster than
|
||||||
|
// zen3/VAES(VEX.128).
|
||||||
|
// It seems like VAES(VEX.256) should be faster?
|
||||||
|
constexpr size_t BLOCK_DEPTH = 10;
|
||||||
|
constexpr size_t CHUNK_LEN = BLOCK_DEPTH * BLOCK_SIZE;
|
||||||
|
while (len >= CHUNK_LEN)
|
||||||
|
{
|
||||||
|
DecryptPipelined<BLOCK_DEPTH>(&iv_block, buf_in, buf_out);
|
||||||
|
buf_in += CHUNK_LEN;
|
||||||
|
buf_out += CHUNK_LEN;
|
||||||
|
len -= CHUNK_LEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len /= BLOCK_SIZE;
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
|
CryptBlock(&iv_block, buf_in, buf_out);
|
||||||
|
buf_in += BLOCK_SIZE;
|
||||||
|
buf_out += BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iv_out)
|
||||||
|
_mm_storeu_si128((__m128i*)iv_out, iv_block);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<__m128i, NUM_ROUND_KEYS> round_keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_M_ARM_64)
|
||||||
|
|
||||||
|
template <Mode AesMode>
|
||||||
|
class ContextNeon final : public Context
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <size_t RoundIdx>
|
||||||
|
inline constexpr void StoreRoundKey(const u32* rk)
|
||||||
|
{
|
||||||
|
const uint8x16_t rk_block = vreinterpretq_u8_u32(vld1q_u32(rk));
|
||||||
|
if constexpr (AesMode == Mode::Encrypt)
|
||||||
|
round_keys[RoundIdx] = rk_block;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
constexpr size_t idx = NUM_ROUND_KEYS - RoundIdx - 1;
|
||||||
|
if constexpr (idx == 0 || idx == NUM_ROUND_KEYS - 1)
|
||||||
|
round_keys[idx] = rk_block;
|
||||||
|
else
|
||||||
|
round_keys[idx] = vaesimcq_u8(rk_block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextNeon(const u8* key)
|
||||||
|
{
|
||||||
|
constexpr u8 rcon[]{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
|
||||||
|
std::array<u32, Nb * NUM_ROUND_KEYS> rk{};
|
||||||
|
|
||||||
|
// This uses a nice trick I've seen in wolfssl (not sure original author),
|
||||||
|
// which uses vaeseq_u8 to assist keygen.
|
||||||
|
// vaeseq_u8: op1 = SubBytes(ShiftRows(AddRoundKey(op1, op2)))
|
||||||
|
// given RotWord == ShiftRows for row 1 (rol(x,8))
|
||||||
|
// Probably not super fast (moves to/from vector regs constantly), but it is nice and simple.
|
||||||
|
|
||||||
|
std::memcpy(&rk[0], key, KEY_SIZE);
|
||||||
|
StoreRoundKey<0>(&rk[0]);
|
||||||
|
for (size_t i = 0; i < rk.size() - Nk; i += Nk)
|
||||||
|
{
|
||||||
|
const uint8x16_t enc = vaeseq_u8(vreinterpretq_u8_u32(vmovq_n_u32(rk[i + 3])), vmovq_n_u8(0));
|
||||||
|
const u32 temp = vgetq_lane_u32(vreinterpretq_u32_u8(enc), 0);
|
||||||
|
rk[i + 4] = rk[i + 0] ^ std::rotr(temp, 8) ^ rcon[i / Nk];
|
||||||
|
rk[i + 5] = rk[i + 4] ^ rk[i + 1];
|
||||||
|
rk[i + 6] = rk[i + 5] ^ rk[i + 2];
|
||||||
|
rk[i + 7] = rk[i + 6] ^ rk[i + 3];
|
||||||
|
// clang-format off
|
||||||
|
// Not great
|
||||||
|
const size_t rki = 1 + i / Nk;
|
||||||
|
switch (rki)
|
||||||
|
{
|
||||||
|
case 1: StoreRoundKey< 1>(&rk[Nk * rki]); break;
|
||||||
|
case 2: StoreRoundKey< 2>(&rk[Nk * rki]); break;
|
||||||
|
case 3: StoreRoundKey< 3>(&rk[Nk * rki]); break;
|
||||||
|
case 4: StoreRoundKey< 4>(&rk[Nk * rki]); break;
|
||||||
|
case 5: StoreRoundKey< 5>(&rk[Nk * rki]); break;
|
||||||
|
case 6: StoreRoundKey< 6>(&rk[Nk * rki]); break;
|
||||||
|
case 7: StoreRoundKey< 7>(&rk[Nk * rki]); break;
|
||||||
|
case 8: StoreRoundKey< 8>(&rk[Nk * rki]); break;
|
||||||
|
case 9: StoreRoundKey< 9>(&rk[Nk * rki]); break;
|
||||||
|
case 10: StoreRoundKey<10>(&rk[Nk * rki]); break;
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CryptBlock(uint8x16_t* iv, const u8* buf_in, u8* buf_out) const
|
||||||
|
{
|
||||||
|
uint8x16_t block = vld1q_u8(buf_in);
|
||||||
|
|
||||||
|
if constexpr (AesMode == Mode::Encrypt)
|
||||||
|
{
|
||||||
|
block = veorq_u8(block, *iv);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < Nr - 1; ++i)
|
||||||
|
block = vaesmcq_u8(vaeseq_u8(block, round_keys[i]));
|
||||||
|
block = vaeseq_u8(block, round_keys[Nr - 1]);
|
||||||
|
block = veorq_u8(block, round_keys[Nr]);
|
||||||
|
|
||||||
|
*iv = block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint8x16_t iv_next = block;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < Nr - 1; ++i)
|
||||||
|
block = vaesimcq_u8(vaesdq_u8(block, round_keys[i]));
|
||||||
|
block = vaesdq_u8(block, round_keys[Nr - 1]);
|
||||||
|
block = veorq_u8(block, round_keys[Nr]);
|
||||||
|
|
||||||
|
block = veorq_u8(block, *iv);
|
||||||
|
*iv = iv_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
vst1q_u8(buf_out, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
|
||||||
|
size_t len) const override
|
||||||
|
{
|
||||||
|
if (len % BLOCK_SIZE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8x16_t iv_block = iv ? vld1q_u8(iv) : vmovq_n_u8(0);
|
||||||
|
|
||||||
|
len /= BLOCK_SIZE;
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
|
CryptBlock(&iv_block, buf_in, buf_out);
|
||||||
|
buf_in += BLOCK_SIZE;
|
||||||
|
buf_out += BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iv_out)
|
||||||
|
vst1q_u8(iv_out, iv_block);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<uint8x16_t, NUM_ROUND_KEYS> round_keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <Mode AesMode>
|
||||||
|
std::unique_ptr<Context> CreateContext(const u8* key)
|
||||||
|
{
|
||||||
|
if (cpu_info.bAES)
|
||||||
|
{
|
||||||
|
#if defined(_M_X86_64)
|
||||||
|
#if defined(__AVX__)
|
||||||
|
// If compiler enables AVX, the intrinsics will generate VAES(VEX.128) instructions.
|
||||||
|
// In the future we may want to compile the code twice and explicitly override the compiler
|
||||||
|
// flags. There doesn't seem to be much performance difference between AES(128) and
|
||||||
|
// VAES(VEX.128) at the moment, though.
|
||||||
|
if (cpu_info.bAVX)
|
||||||
|
#endif
|
||||||
|
return std::make_unique<ContextAESNI<AesMode>>(key);
|
||||||
|
#elif defined(_M_ARM_64)
|
||||||
|
return std::make_unique<ContextNeon<AesMode>>(key);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return std::make_unique<ContextGeneric<AesMode>>(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Context> CreateContextEncrypt(const u8* key)
|
||||||
|
{
|
||||||
|
return CreateContext<Mode::Encrypt>(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Context> CreateContextDecrypt(const u8* key)
|
||||||
|
{
|
||||||
|
return CreateContext<Mode::Decrypt>(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OFB encryption and decryption are the exact same. We don't encrypt though.
|
||||||
|
void CryptOFB(const u8* key, const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t size)
|
||||||
|
{
|
||||||
|
mbedtls_aes_context aes_ctx;
|
||||||
|
size_t iv_offset = 0;
|
||||||
|
|
||||||
|
std::array<u8, 16> iv_tmp{};
|
||||||
|
if (iv)
|
||||||
|
std::memcpy(&iv_tmp[0], iv, 16);
|
||||||
|
|
||||||
|
ASSERT(!mbedtls_aes_setkey_enc(&aes_ctx, key, 128));
|
||||||
|
mbedtls_aes_crypt_ofb(&aes_ctx, size, &iv_offset, &iv_tmp[0], buf_in, buf_out);
|
||||||
|
|
||||||
|
if (iv_out)
|
||||||
|
std::memcpy(iv_out, &iv_tmp[0], 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Common::AES
|
586
pr_agent/static_analysis/tests/example_files/calc.java
Normal file
586
pr_agent/static_analysis/tests/example_files/calc.java
Normal file
@ -0,0 +1,586 @@
|
|||||||
|
package com.houarizegai.calculator.ui;
|
||||||
|
|
||||||
|
import com.houarizegai.calculator.theme.properties.Theme;
|
||||||
|
import com.houarizegai.calculator.theme.ThemeLoader;
|
||||||
|
|
||||||
|
import java.awt.Cursor;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.event.ItemEvent;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.awt.Color;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import static com.houarizegai.calculator.util.ColorUtil.hex2Color;
|
||||||
|
|
||||||
|
public class CalculatorUI {
|
||||||
|
|
||||||
|
private static final String FONT_NAME = "Comic Sans MS";
|
||||||
|
private static final String DOUBLE_OR_NUMBER_REGEX = "([-]?\\d+[.]\\d*)|(\\d+)|(-\\d+)";
|
||||||
|
private static final String APPLICATION_TITLE = "Calculator";
|
||||||
|
private static final int WINDOW_WIDTH = 410;
|
||||||
|
private static final int WINDOW_HEIGHT = 600;
|
||||||
|
private static final int BUTTON_WIDTH = 80;
|
||||||
|
private static final int BUTTON_HEIGHT = 70;
|
||||||
|
private static final int MARGIN_X = 20;
|
||||||
|
private static final int MARGIN_Y = 60;
|
||||||
|
|
||||||
|
private final JFrame window;
|
||||||
|
private JComboBox<String> comboCalculatorType;
|
||||||
|
private JComboBox<String> comboTheme;
|
||||||
|
private JTextField inputScreen;
|
||||||
|
private JButton btnC;
|
||||||
|
private JButton btnBack;
|
||||||
|
private JButton btnMod;
|
||||||
|
private JButton btnDiv;
|
||||||
|
private JButton btnMul;
|
||||||
|
private JButton btnSub;
|
||||||
|
private JButton btnAdd;
|
||||||
|
private JButton btn0;
|
||||||
|
private JButton btn1;
|
||||||
|
private JButton btn2;
|
||||||
|
private JButton btn3;
|
||||||
|
private JButton btn4;
|
||||||
|
private JButton btn5;
|
||||||
|
private JButton btn6;
|
||||||
|
private JButton btn7;
|
||||||
|
private JButton btn8;
|
||||||
|
private JButton btn9;
|
||||||
|
private JButton btnPoint;
|
||||||
|
private JButton btnEqual;
|
||||||
|
private JButton btnRoot;
|
||||||
|
private JButton btnPower;
|
||||||
|
private JButton btnLog;
|
||||||
|
|
||||||
|
private char selectedOperator = ' ';
|
||||||
|
private boolean go = true; // For calculate with Opt != (=)
|
||||||
|
private boolean addToDisplay = true; // Connect numbers in display
|
||||||
|
private double typedValue = 0;
|
||||||
|
|
||||||
|
private final Map<String, Theme> themesMap;
|
||||||
|
|
||||||
|
public CalculatorUI() {
|
||||||
|
themesMap = ThemeLoader.loadThemes();
|
||||||
|
|
||||||
|
window = new JFrame(APPLICATION_TITLE);
|
||||||
|
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||||
|
window.setLocationRelativeTo(null);
|
||||||
|
|
||||||
|
int[] columns = {MARGIN_X, MARGIN_X + 90, MARGIN_X + 90 * 2, MARGIN_X + 90 * 3, MARGIN_X + 90 * 4};
|
||||||
|
int[] rows = {MARGIN_Y, MARGIN_Y + 100, MARGIN_Y + 100 + 80, MARGIN_Y + 100 + 80 * 2, MARGIN_Y + 100 + 80 * 3, MARGIN_Y + 100 + 80 * 4};
|
||||||
|
|
||||||
|
initInputScreen(columns, rows);
|
||||||
|
initButtons(columns, rows);
|
||||||
|
initCalculatorTypeSelector();
|
||||||
|
|
||||||
|
initThemeSelector();
|
||||||
|
|
||||||
|
window.setLayout(null);
|
||||||
|
window.setResizable(false);
|
||||||
|
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
window.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double calculate(double firstNumber, double secondNumber, char operator) {
|
||||||
|
switch (operator) {
|
||||||
|
case '+':
|
||||||
|
return firstNumber + secondNumber;
|
||||||
|
case '-':
|
||||||
|
return firstNumber - secondNumber;
|
||||||
|
case '*':
|
||||||
|
return firstNumber * secondNumber;
|
||||||
|
case '/':
|
||||||
|
return firstNumber / secondNumber;
|
||||||
|
case '%':
|
||||||
|
return firstNumber % secondNumber;
|
||||||
|
case '^':
|
||||||
|
return Math.pow(firstNumber, secondNumber);
|
||||||
|
default:
|
||||||
|
return secondNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initThemeSelector() {
|
||||||
|
comboTheme = createComboBox(themesMap.keySet().toArray(new String[0]), 230, 30, "Theme");
|
||||||
|
comboTheme.addItemListener(event -> {
|
||||||
|
if (event.getStateChange() != ItemEvent.SELECTED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
String selectedTheme = (String) event.getItem();
|
||||||
|
applyTheme(themesMap.get(selectedTheme));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (themesMap.entrySet().iterator().hasNext()) {
|
||||||
|
applyTheme(themesMap.entrySet().iterator().next().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initInputScreen(int[] columns, int[] rows) {
|
||||||
|
inputScreen = new JTextField("0");
|
||||||
|
inputScreen.setBounds(columns[0], rows[0], 350, 70);
|
||||||
|
inputScreen.setEditable(false);
|
||||||
|
inputScreen.setBackground(Color.WHITE);
|
||||||
|
inputScreen.setFont(new Font(FONT_NAME, Font.PLAIN, 33));
|
||||||
|
window.add(inputScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initCalculatorTypeSelector() {
|
||||||
|
comboCalculatorType = createComboBox(new String[]{"Standard", "Scientific"}, 20, 30, "Calculator type");
|
||||||
|
comboCalculatorType.addItemListener(event -> {
|
||||||
|
if (event.getStateChange() != ItemEvent.SELECTED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
String selectedItem = (String) event.getItem();
|
||||||
|
switch (selectedItem) {
|
||||||
|
case "Standard":
|
||||||
|
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||||
|
btnRoot.setVisible(false);
|
||||||
|
btnPower.setVisible(false);
|
||||||
|
btnLog.setVisible(false);
|
||||||
|
break;
|
||||||
|
case "Scientific":
|
||||||
|
window.setSize(WINDOW_WIDTH + 80, WINDOW_HEIGHT);
|
||||||
|
btnRoot.setVisible(true);
|
||||||
|
btnPower.setVisible(true);
|
||||||
|
btnLog.setVisible(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initButtons(int[] columns, int[] rows) {
|
||||||
|
btnC = createButton("C", columns[0], rows[1]);
|
||||||
|
btnC.addActionListener(event -> {
|
||||||
|
inputScreen.setText("0");
|
||||||
|
selectedOperator = ' ';
|
||||||
|
typedValue = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
btnBack = createButton("<-", columns[1], rows[1]);
|
||||||
|
btnBack.addActionListener(event -> {
|
||||||
|
String str = inputScreen.getText();
|
||||||
|
StringBuilder str2 = new StringBuilder();
|
||||||
|
for (int i = 0; i < (str.length() - 1); i++) {
|
||||||
|
str2.append(str.charAt(i));
|
||||||
|
}
|
||||||
|
if (str2.toString().equals("")) {
|
||||||
|
inputScreen.setText("0");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(str2.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
btnMod = createButton("%", columns[2], rows[1]);
|
||||||
|
btnMod.addActionListener(event -> {
|
||||||
|
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()) || !go)
|
||||||
|
return;
|
||||||
|
|
||||||
|
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||||
|
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||||
|
inputScreen.setText(String.valueOf((int) typedValue));
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(String.valueOf(typedValue));
|
||||||
|
}
|
||||||
|
selectedOperator = '%';
|
||||||
|
go = false;
|
||||||
|
addToDisplay = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
btnDiv = createButton("/", columns[3], rows[1]);
|
||||||
|
btnDiv.addActionListener(event -> {
|
||||||
|
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (go) {
|
||||||
|
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||||
|
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||||
|
inputScreen.setText(String.valueOf((int) typedValue));
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(String.valueOf(typedValue));
|
||||||
|
}
|
||||||
|
selectedOperator = '/';
|
||||||
|
go = false;
|
||||||
|
addToDisplay = false;
|
||||||
|
} else {
|
||||||
|
selectedOperator = '/';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
btn7 = createButton("7", columns[0], rows[2]);
|
||||||
|
btn7.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||||
|
inputScreen.setText("7");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(inputScreen.getText() + "7");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("7");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btn8 = createButton("8", columns[1], rows[2]);
|
||||||
|
btn8.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||||
|
inputScreen.setText("8");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(inputScreen.getText() + "8");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("8");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btn9 = createButton("9", columns[2], rows[2]);
|
||||||
|
btn9.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||||
|
inputScreen.setText("9");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(inputScreen.getText() + "9");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("9");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btnMul = createButton("*", columns[3], rows[2]);
|
||||||
|
btnMul.addActionListener(event -> {
|
||||||
|
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (go) {
|
||||||
|
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||||
|
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||||
|
inputScreen.setText(String.valueOf((int) typedValue));
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(String.valueOf(typedValue));
|
||||||
|
}
|
||||||
|
selectedOperator = '*';
|
||||||
|
go = false;
|
||||||
|
addToDisplay = false;
|
||||||
|
} else {
|
||||||
|
selectedOperator = '*';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
btn4 = createButton("4", columns[0], rows[3]);
|
||||||
|
btn4.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||||
|
inputScreen.setText("4");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(inputScreen.getText() + "4");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("4");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btn5 = createButton("5", columns[1], rows[3]);
|
||||||
|
btn5.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||||
|
inputScreen.setText("5");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(inputScreen.getText() + "5");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("5");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btn6 = createButton("6", columns[2], rows[3]);
|
||||||
|
btn6.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||||
|
inputScreen.setText("6");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(inputScreen.getText() + "6");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("6");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btnSub = createButton("-", columns[3], rows[3]);
|
||||||
|
btnSub.addActionListener(event -> {
|
||||||
|
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (go) {
|
||||||
|
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||||
|
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||||
|
inputScreen.setText(String.valueOf((int) typedValue));
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(String.valueOf(typedValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedOperator = '-';
|
||||||
|
go = false;
|
||||||
|
addToDisplay = false;
|
||||||
|
} else {
|
||||||
|
selectedOperator = '-';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
btn1 = createButton("1", columns[0], rows[4]);
|
||||||
|
btn1.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||||
|
inputScreen.setText("1");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(inputScreen.getText() + "1");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("1");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btn2 = createButton("2", columns[1], rows[4]);
|
||||||
|
btn2.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||||
|
inputScreen.setText("2");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(inputScreen.getText() + "2");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("2");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btn3 = createButton("3", columns[2], rows[4]);
|
||||||
|
btn3.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||||
|
inputScreen.setText("3");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(inputScreen.getText() + "3");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("3");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btnAdd = createButton("+", columns[3], rows[4]);
|
||||||
|
btnAdd.addActionListener(event -> {
|
||||||
|
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (go) {
|
||||||
|
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||||
|
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||||
|
inputScreen.setText(String.valueOf((int) typedValue));
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(String.valueOf(typedValue));
|
||||||
|
}
|
||||||
|
selectedOperator = '+';
|
||||||
|
go = false;
|
||||||
|
addToDisplay = false;
|
||||||
|
} else {
|
||||||
|
selectedOperator = '+';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
btnPoint = createButton(".", columns[0], rows[5]);
|
||||||
|
btnPoint.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (!inputScreen.getText().contains(".")) {
|
||||||
|
inputScreen.setText(inputScreen.getText() + ".");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("0.");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btn0 = createButton("0", columns[1], rows[5]);
|
||||||
|
btn0.addActionListener(event -> {
|
||||||
|
if (addToDisplay) {
|
||||||
|
if (Pattern.matches("[0]*", inputScreen.getText())) {
|
||||||
|
inputScreen.setText("0");
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(inputScreen.getText() + "0");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputScreen.setText("0");
|
||||||
|
addToDisplay = true;
|
||||||
|
}
|
||||||
|
go = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
btnEqual = createButton("=", columns[2], rows[5]);
|
||||||
|
btnEqual.addActionListener(event -> {
|
||||||
|
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (go) {
|
||||||
|
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||||
|
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||||
|
inputScreen.setText(String.valueOf((int) typedValue));
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(String.valueOf(typedValue));
|
||||||
|
}
|
||||||
|
selectedOperator = '=';
|
||||||
|
addToDisplay = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
btnEqual.setSize(2 * BUTTON_WIDTH + 10, BUTTON_HEIGHT);
|
||||||
|
|
||||||
|
btnRoot = createButton("√", columns[4], rows[1]);
|
||||||
|
btnRoot.addActionListener(event -> {
|
||||||
|
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (go) {
|
||||||
|
typedValue = Math.sqrt(Double.parseDouble(inputScreen.getText()));
|
||||||
|
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||||
|
inputScreen.setText(String.valueOf((int) typedValue));
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(String.valueOf(typedValue));
|
||||||
|
}
|
||||||
|
selectedOperator = '√';
|
||||||
|
addToDisplay = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
btnRoot.setVisible(false);
|
||||||
|
|
||||||
|
btnPower = createButton("pow", columns[4], rows[2]);
|
||||||
|
btnPower.addActionListener(event -> {
|
||||||
|
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (go) {
|
||||||
|
typedValue = calculate(typedValue, Double.parseDouble(inputScreen.getText()), selectedOperator);
|
||||||
|
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||||
|
inputScreen.setText(String.valueOf((int) typedValue));
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(String.valueOf(typedValue));
|
||||||
|
}
|
||||||
|
selectedOperator = '^';
|
||||||
|
go = false;
|
||||||
|
addToDisplay = false;
|
||||||
|
} else {
|
||||||
|
selectedOperator = '^';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
btnPower.setFont(new Font("Comic Sans MS", Font.PLAIN, 24));
|
||||||
|
btnPower.setVisible(false);
|
||||||
|
|
||||||
|
btnLog = createButton("ln", columns[4], rows[3]);
|
||||||
|
btnLog.addActionListener(event -> {
|
||||||
|
if (!Pattern.matches(DOUBLE_OR_NUMBER_REGEX, inputScreen.getText()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (go) {
|
||||||
|
typedValue = Math.log(Double.parseDouble(inputScreen.getText()));
|
||||||
|
if (Pattern.matches("[-]?[\\d]+[.][0]*", String.valueOf(typedValue))) {
|
||||||
|
inputScreen.setText(String.valueOf((int) typedValue));
|
||||||
|
} else {
|
||||||
|
inputScreen.setText(String.valueOf(typedValue));
|
||||||
|
}
|
||||||
|
selectedOperator = 'l';
|
||||||
|
addToDisplay = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
btnLog.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JComboBox<String> createComboBox(String[] items, int x, int y, String toolTip) {
|
||||||
|
JComboBox<String> combo = new JComboBox<>(items);
|
||||||
|
combo.setBounds(x, y, 140, 25);
|
||||||
|
combo.setToolTipText(toolTip);
|
||||||
|
combo.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||||
|
window.add(combo);
|
||||||
|
|
||||||
|
return combo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JButton createButton(String label, int x, int y) {
|
||||||
|
JButton btn = new JButton(label);
|
||||||
|
btn.setBounds(x, y, BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||||
|
btn.setFont(new Font("Comic Sans MS", Font.PLAIN, 28));
|
||||||
|
btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||||
|
btn.setFocusable(false);
|
||||||
|
window.add(btn);
|
||||||
|
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyTheme(Theme theme) {
|
||||||
|
window.getContentPane().setBackground(hex2Color(theme.getApplicationBackground()));
|
||||||
|
|
||||||
|
comboCalculatorType.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
comboTheme.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
inputScreen.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btn0.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btn1.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btn2.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btn3.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btn4.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btn5.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btn6.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btn7.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btn8.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btn9.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnPoint.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnC.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnBack.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnMod.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnDiv.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnMul.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnSub.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnAdd.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnRoot.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnLog.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnPower.setForeground(hex2Color(theme.getTextColor()));
|
||||||
|
btnEqual.setForeground(hex2Color(theme.getBtnEqualTextColor()));
|
||||||
|
|
||||||
|
comboCalculatorType.setBackground(hex2Color(theme.getApplicationBackground()));
|
||||||
|
comboTheme.setBackground(hex2Color(theme.getApplicationBackground()));
|
||||||
|
inputScreen.setBackground(hex2Color(theme.getApplicationBackground()));
|
||||||
|
btn0.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btn1.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btn2.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btn3.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btn4.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btn5.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btn6.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btn7.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btn8.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btn9.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btnPoint.setBackground(hex2Color(theme.getNumbersBackground()));
|
||||||
|
btnC.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||||
|
btnBack.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||||
|
btnMod.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||||
|
btnDiv.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||||
|
btnMul.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||||
|
btnSub.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||||
|
btnAdd.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||||
|
btnRoot.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||||
|
btnLog.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||||
|
btnPower.setBackground(hex2Color(theme.getOperatorBackground()));
|
||||||
|
btnEqual.setBackground(hex2Color(theme.getBtnEqualBackground()));
|
||||||
|
}
|
||||||
|
}
|
138
pr_agent/static_analysis/tests/example_files/match.ts
Normal file
138
pr_agent/static_analysis/tests/example_files/match.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
import { Pattern } from './types/Pattern'; // @ts-ignore
|
||||||
|
import { Match } from './types/Match'; // @ts-ignore
|
||||||
|
import * as symbols from './internals/symbols'; // @ts-ignore
|
||||||
|
import { matchPattern } from './internals/helpers'; // @ts-ignore
|
||||||
|
|
||||||
|
type MatchState<output> =
|
||||||
|
| { matched: true; value: output }
|
||||||
|
| { matched: false; value: undefined };
|
||||||
|
|
||||||
|
const unmatched: MatchState<never> = {
|
||||||
|
matched: false,
|
||||||
|
value: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `match` creates a **pattern matching expression**.
|
||||||
|
* * Use `.with(pattern, handler)` to pattern match on the input.
|
||||||
|
* * Use `.exhaustive()` or `.otherwise(() => defaultValue)` to end the expression and get the result.
|
||||||
|
*
|
||||||
|
* [Read the documentation for `match` on GitHub](https://github.com/gvergnaud/ts-pattern#match)
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* declare let input: "A" | "B";
|
||||||
|
*
|
||||||
|
* return match(input)
|
||||||
|
* .with("A", () => "It's an A!")
|
||||||
|
* .with("B", () => "It's a B!")
|
||||||
|
* .exhaustive();
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function match<const input, output = symbols.unset>(
|
||||||
|
value: input
|
||||||
|
): Match<input, output> {
|
||||||
|
return new MatchExpression(value, unmatched) as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a match expression. It follows the
|
||||||
|
* builder pattern, we chain methods to add features to the expression
|
||||||
|
* until we call `.exhaustive`, `.otherwise` or the unsafe `.run`
|
||||||
|
* method to execute it.
|
||||||
|
*
|
||||||
|
* The types of this class aren't public, the public type definition
|
||||||
|
* can be found in src/types/Match.ts.
|
||||||
|
*/
|
||||||
|
class MatchExpression<input, output> {
|
||||||
|
constructor(private input: input, private state: MatchState<output>) {}
|
||||||
|
|
||||||
|
with(...args: any[]): MatchExpression<input, output> {
|
||||||
|
if (this.state.matched) return this;
|
||||||
|
|
||||||
|
const handler: (selection: unknown, value: input) => output =
|
||||||
|
args[args.length - 1];
|
||||||
|
|
||||||
|
const patterns: Pattern<input>[] = [args[0]];
|
||||||
|
let predicate: ((value: input) => unknown) | undefined = undefined;
|
||||||
|
|
||||||
|
if (args.length === 3 && typeof args[1] === 'function') {
|
||||||
|
// case with guard as second argument
|
||||||
|
patterns.push(args[0]);
|
||||||
|
predicate = args[1];
|
||||||
|
} else if (args.length > 2) {
|
||||||
|
// case with several patterns
|
||||||
|
patterns.push(...args.slice(1, args.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasSelections = false;
|
||||||
|
let selected: Record<string, unknown> = {};
|
||||||
|
const select = (key: string, value: unknown) => {
|
||||||
|
hasSelections = true;
|
||||||
|
selected[key] = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const matched =
|
||||||
|
patterns.some((pattern) => matchPattern(pattern, this.input, select)) &&
|
||||||
|
(predicate ? Boolean(predicate(this.input)) : true);
|
||||||
|
|
||||||
|
const selections = hasSelections
|
||||||
|
? symbols.anonymousSelectKey in selected
|
||||||
|
? selected[symbols.anonymousSelectKey]
|
||||||
|
: selected
|
||||||
|
: this.input;
|
||||||
|
|
||||||
|
const state = matched
|
||||||
|
? {
|
||||||
|
matched: true as const,
|
||||||
|
value: handler(selections, this.input),
|
||||||
|
}
|
||||||
|
: unmatched;
|
||||||
|
|
||||||
|
return new MatchExpression(this.input, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
when(
|
||||||
|
predicate: (value: input) => unknown,
|
||||||
|
handler: (selection: input, value: input) => output
|
||||||
|
): MatchExpression<input, output> {
|
||||||
|
if (this.state.matched) return this;
|
||||||
|
|
||||||
|
const matched = Boolean(predicate(this.input));
|
||||||
|
|
||||||
|
return new MatchExpression<input, output>(
|
||||||
|
this.input,
|
||||||
|
matched
|
||||||
|
? { matched: true, value: handler(this.input, this.input) }
|
||||||
|
: unmatched
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
otherwise(handler: (value: input) => output): output {
|
||||||
|
if (this.state.matched) return this.state.value;
|
||||||
|
return handler(this.input);
|
||||||
|
}
|
||||||
|
|
||||||
|
exhaustive(): output {
|
||||||
|
return this.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
run(): output {
|
||||||
|
if (this.state.matched) return this.state.value;
|
||||||
|
|
||||||
|
let displayedValue;
|
||||||
|
try {
|
||||||
|
displayedValue = JSON.stringify(this.input);
|
||||||
|
} catch (e) {
|
||||||
|
displayedValue = this.input;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
`Pattern matching error: no pattern matches value ${displayedValue}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
returnType() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
43
pr_agent/static_analysis/tests/test_file_summary.py
Normal file
43
pr_agent/static_analysis/tests/test_file_summary.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from pr_agent.static_analysis.src.file_summary import FileSummary
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileSummary:
|
||||||
|
def setup_method(self):
|
||||||
|
self.base_path = Path(__file__).parent
|
||||||
|
self.project_base_path = Path(__file__).parent.parent.parent.parent
|
||||||
|
|
||||||
|
def test_file_summary_cpp(self):
|
||||||
|
fname = os.path.join(self.base_path, 'example_files/AES.cpp')
|
||||||
|
if not os.path.exists(fname):
|
||||||
|
print(f"File {fname} does not exist")
|
||||||
|
return False
|
||||||
|
fname_summary = FileSummary(fname, self.project_base_path, parent_context=False, child_context=False,
|
||||||
|
header_max=0)
|
||||||
|
output = fname_summary.summarize()
|
||||||
|
expected_output = '\npr_agent/static_analysis/tests/example_files/AES.cpp:\n...⋮...\n 32│namespace Common::AES\n 33│{\n...⋮...\n 36│template <Mode AesMode>\n 37│class ContextGeneric final : public Context\n 38│{\n 39│public:\n 40│ ContextGeneric(const u8* key)\n...⋮...\n 49│ virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,\n...⋮...\n 70│#if defined(_M_X86_64)\n 71│\n...⋮...\n 84│template <Mode AesMode>\n 85│class ContextAESNI final : public Context\n 86│{\n 87│ static inline __m128i Aes128KeygenAssistFinish(__m128i key, __m128i kga)\n...⋮...\n103│ inline constexpr void StoreRoundKey(__m128i rk)\n...⋮...\n119│ inline constexpr __m128i Aes128Keygen(__m128i rk)\n...⋮...\n127│ ContextAESNI(const u8* key)\n...⋮...\n144│ inline void CryptBlock(__m128i* iv, const u8* buf_in, u8* buf_out) const\n...⋮...\n178│ inline void DecryptPipelined(__m128i* iv, const u8* buf_in, u8* buf_out) const\n...⋮...\n209│ virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,\n...⋮...\n259│#if defined(_M_ARM_64)\n260│\n261│template <Mode AesMode>\n262│class ContextNeon final : public Context\n263│{\n264│public:\n265│ template <size_t RoundIdx>\n266│ inline constexpr void StoreRoundKey(const u32* rk)\n...⋮...\n281│ ContextNeon(const u8* key)\n...⋮...\n322│ inline void CryptBlock(uint8x16_t* iv, const u8* buf_in, u8* buf_out) const\n...⋮...\n353│ virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,\n...⋮...\n381│template <Mode AesMode>\n382│std::unique_ptr<Context> CreateContext(const u8* key)\n...⋮...\n402│std::unique_ptr<Context> CreateContextEncrypt(const u8* key)\n...⋮...\n407│std::unique_ptr<Context> CreateContextDecrypt(const u8* key)\n...⋮...\n413│void CryptOFB(const u8* key, const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t size)\n...⋮...\n'
|
||||||
|
assert output == expected_output
|
||||||
|
|
||||||
|
def test_file_typescript(self):
|
||||||
|
fname = os.path.join(self.base_path, 'example_files/match.ts')
|
||||||
|
if not os.path.exists(fname):
|
||||||
|
print(f"File {fname} does not exist")
|
||||||
|
return False
|
||||||
|
fname_summary = FileSummary(fname, self.project_base_path, parent_context=False, child_context=False,
|
||||||
|
header_max=0)
|
||||||
|
output = fname_summary.summarize()
|
||||||
|
expected_output = '\npr_agent/static_analysis/tests/example_files/match.ts:\n...⋮...\n 6│type MatchState<output> =\n...⋮...\n 31│export function match<const input, output = symbols.unset>(\n...⋮...\n 46│class MatchExpression<input, output> {\n 47│ constructor(private input: input, private state: MatchState<output>) {}\n 48│\n 49│ with(...args: any[]): MatchExpression<input, output> {\n...⋮...\n 94│ when(\n...⋮...\n110│ otherwise(handler: (value: input) => output): output {\n...⋮...\n115│ exhaustive(): output {\n...⋮...\n119│ run(): output {\n...⋮...\n134│ returnType() {\n...⋮...\n'
|
||||||
|
assert output == expected_output
|
||||||
|
|
||||||
|
def test_file_java(self):
|
||||||
|
fname = os.path.join(self.base_path, 'example_files/calc.java')
|
||||||
|
if not os.path.exists(fname):
|
||||||
|
print(f"File {fname} does not exist")
|
||||||
|
return False
|
||||||
|
fname_summary = FileSummary(fname, self.project_base_path, parent_context=False, child_context=False,
|
||||||
|
header_max=0)
|
||||||
|
output = fname_summary.summarize()
|
||||||
|
expected_output = '\npr_agent/static_analysis/tests/example_files/calc.java:\n...⋮...\n 16│public class CalculatorUI {\n 17│\n...⋮...\n 84│ public double calculate(double firstNumber, double secondNumber, char operator) {\n...⋮...\n103│ private void initThemeSelector() {\n...⋮...\n118│ private void initInputScreen(int[] columns, int[] rows) {\n...⋮...\n127│ private void initCalculatorTypeSelector() {\n...⋮...\n151│ private void initButtons(int[] columns, int[] rows) {\n...⋮...\n510│ private JComboBox<String> createComboBox(String[] items, int x, int y, String toolTip) {\n...⋮...\n520│ private JButton createButton(String label, int x, int y) {\n...⋮...\n531│ private void applyTheme(Theme theme) {\n...⋮...\n'
|
||||||
|
assert output == expected_output
|
@ -34,6 +34,12 @@ langchain-openai==0.2.0
|
|||||||
langchain-pinecone==0.2.0
|
langchain-pinecone==0.2.0
|
||||||
langchain-chroma==0.1.4
|
langchain-chroma==0.1.4
|
||||||
chromadb==0.5.7
|
chromadb==0.5.7
|
||||||
|
#
|
||||||
|
tree_sitter==0.21.3
|
||||||
|
tree_sitter_languages==1.10.2
|
||||||
|
grep_ast==0.3.3
|
||||||
|
#Pygments==2.18.0
|
||||||
|
|
||||||
# Uncomment the following lines to enable the 'similar issue' tool
|
# Uncomment the following lines to enable the 'similar issue' tool
|
||||||
# pinecone-client
|
# pinecone-client
|
||||||
# pinecone-datasets @ git+https://github.com/mrT23/pinecone-datasets.git@main
|
# pinecone-datasets @ git+https://github.com/mrT23/pinecone-datasets.git@main
|
||||||
|
Reference in New Issue
Block a user