You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
3.1 KiB

// Copyright (c) 2018-present, Facebook, Inc.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
// Requirements for stateless component implemented in this rule:
// 1. Subclass of CKCompositeComponent
// 2. Has only 1 method, which is constructor class method newWith...
// 3. Does not conform to any protocols
// 4. Does not have any ivars
// 5. Does not have any properties
// 6. Does not have any methods
// 7. Does not have a view configuration. Which means, it should only have a call to either of:
// a. [super(or self) newWithComponent: ....];
// b. [super(or self) newWithView:{} component: ...];
// 8. Does not declare a scope in the constructor: which means does call *CKComponentScope *nameOfLocalScopeVariable(....);
DEFINE-CHECKER CKSTATELESS_COMPONENT = {
LET is_subclass_of(x) =
is_class(x) HOLDS-IN-SOME-SUPERCLASS-OF ObjCInterfaceDecl;
LET receiver_is_super_or_self = is_receiver_super() OR is_receiver_self();
LET eventually_call_newWithComponent =
IN-NODE ObjCMethodDecl WITH-TRANSITION Body
((call_method(REGEXP("newWithComponent:.*")) AND receiver_is_super_or_self) HOLDS-EVENTUALLY)
HOLDS-EVENTUALLY;
// ObjCMessageExpr -> MaterializeTemporaryExpr -> CXXBindTemporaryExpr -> CXXConstructExpr[]
LET view_is_empty =
WHEN
(is_node("MaterializeTemporaryExpr") AND
(is_node("CXXBindTemporaryExpr") AND
(cxx_construct_expr_has_no_parameters() HOLDS-NEXT)
) HOLDS-NEXT
) HOLDS-NEXT
HOLDS-IN-NODE ObjCMessageExpr;
LET eventually_call_newWithViewcomponent =
IN-NODE ObjCMethodDecl WITH-TRANSITION Body
((call_method(REGEXP("newWithView:component:.*")) AND receiver_is_super_or_self
AND
view_is_empty)
HOLDS-EVENTUALLY)
HOLDS-EVENTUALLY;
LET is_scope_declaration =
WHEN
(cxx_construct_expr_has_name("CKComponentScope") HOLDS-NEXT)
HOLDS-IN-NODE DeclStmt;
LET eventually_declare_scope =
IN-NODE ObjCMethodDecl WITH-TRANSITION Body
(is_scope_declaration HOLDS-EVENTUALLY)
HOLDS-EVENTUALLY;
LET implementation_requirements =
WHEN
objc_class_has_only_one_constructor_method_named(REGEXP("newWith.+"))
AND (NOT (is_objc_instance_method_named(REGEXP(".*")) HOLDS-NEXT)) // has not instance methods
AND (eventually_call_newWithViewcomponent OR eventually_call_newWithComponent) // has view configuration
AND (NOT eventually_declare_scope)
AND (NOT (is_node("ObjCIvarDecl") HOLDS-EVENTUALLY))
AND (NOT (is_node("ObjCPropertyDecl") HOLDS-EVENTUALLY))
HOLDS-IN-NODE ObjCImplementationDecl;
LET interface_requirements =
WHEN
is_subclass_of("CKCompositeComponent") AND
(NOT adhere_to_protocol()) AND
(NOT (is_node("ObjCPropertyDecl") HOLDS-EVENTUALLY))
AND (NOT (is_node("ObjCIvarDecl") HOLDS-EVENTUALLY))
HOLDS-IN-NODE ObjCInterfaceDecl;
SET report_when = WHEN
INTERFACE [interface_requirements]
IMPLEMENTATION [implementation_requirements]
HOLDS-IN-OBJC-CLASS;
SET message = "This is a CKStateless Component and, for performance reason, can be replaced by a C function";
SET mode = "ON";
};