Reviewed By: jberdine Differential Revision: D10161169 fbshipit-source-id: dd82e48eemaster
parent
371e1267d9
commit
2e64566a6c
@ -0,0 +1,86 @@
|
||||
// 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";
|
||||
|
||||
};
|
Loading…
Reference in new issue