diff --git a/infer/src/clang/cFrontend.ml b/infer/src/clang/cFrontend.ml index 2d7d4fe7c..2dc5e897b 100644 --- a/infer/src/clang/cFrontend.ml +++ b/infer/src/clang/cFrontend.ml @@ -77,7 +77,8 @@ let rec translate_one_declaration tenv cg cfg parent_dec dec = | _ -> ()) | CXXMethodDecl (decl_info, name_info, type_ptr, function_decl_info, _) - | CXXConstructorDecl (decl_info, name_info, type_ptr, function_decl_info, _) -> + | CXXConstructorDecl (decl_info, name_info, type_ptr, function_decl_info, _) + | CXXDestructorDecl (decl_info, name_info, type_ptr, function_decl_info, _) -> (* di_parent_pointer has pointer to lexical context such as class.*) (* If it's not defined, then it's the same as parent in AST *) let class_decl = match decl_info.Clang_ast_t.di_parent_pointer with diff --git a/infer/src/clang/cMethod_decl.ml b/infer/src/clang/cMethod_decl.ml index e1616bc34..6117d7dd8 100644 --- a/infer/src/clang/cMethod_decl.ml +++ b/infer/src/clang/cMethod_decl.ml @@ -95,7 +95,7 @@ struct let process_one_method_decl tenv cg cfg curr_class dec = let open Clang_ast_t in match dec with - | CXXMethodDecl _ | CXXConstructorDecl _ -> + | CXXMethodDecl _ | CXXConstructorDecl _ | CXXDestructorDecl _ -> process_method_decl tenv cg cfg curr_class dec ~is_objc:false | ObjCMethodDecl _ -> process_method_decl tenv cg cfg curr_class dec ~is_objc:true diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index d5e943064..c91fb7344 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -124,7 +124,8 @@ let method_signature_of_decl meth_decl block_data_opt = let extra_instrs = get_assume_not_null_calls fdi.Clang_ast_t.fdi_parameters in ms, fdi.Clang_ast_t.fdi_body, extra_instrs | CXXMethodDecl (decl_info, name_info, tp, fdi, mdi), _ - | CXXConstructorDecl (decl_info, name_info, tp, fdi, mdi), _ -> + | CXXConstructorDecl (decl_info, name_info, tp, fdi, mdi), _ + | CXXDestructorDecl (decl_info, name_info, tp, fdi, mdi), _ -> let method_name = Ast_utils.get_unqualified_name name_info in let class_name = Ast_utils.get_class_name_from_member name_info in let procname = General_utils.mk_procname_from_cpp_method class_name method_name tp in diff --git a/infer/src/clang/cTypes_decl.ml b/infer/src/clang/cTypes_decl.ml index c1c005696..56b82fd6d 100644 --- a/infer/src/clang/cTypes_decl.ml +++ b/infer/src/clang/cTypes_decl.ml @@ -102,7 +102,7 @@ let get_record_name decl = snd (get_record_name_csu decl) let get_method_decls parent decl_list = let open Clang_ast_t in let rec traverse_decl parent decl = match decl with - | CXXMethodDecl _ | CXXConstructorDecl _ -> [(parent, decl)] + | CXXMethodDecl _ | CXXConstructorDecl _ | CXXDestructorDecl _ -> [(parent, decl)] | FunctionTemplateDecl (_, _, template_decl_info) -> let decl_list' = template_decl_info.Clang_ast_t.tdi_specializations in traverse_decl_list parent decl_list' @@ -116,7 +116,8 @@ let get_method_decls parent decl_list = let get_class_methods tenv class_name decl_list = let process_method_decl = function | Clang_ast_t.CXXMethodDecl (decl_info, name_info, tp, function_decl_info, _) - | Clang_ast_t.CXXConstructorDecl (decl_info, name_info, tp, function_decl_info, _) -> + | Clang_ast_t.CXXConstructorDecl (decl_info, name_info, tp, function_decl_info, _) + | Clang_ast_t.CXXDestructorDecl (decl_info, name_info, tp, function_decl_info, _) -> let method_name = name_info.Clang_ast_t.ni_name in Printing.log_out " ...Declaring method '%s'.\n" method_name; let method_proc = General_utils.mk_procname_from_cpp_method class_name method_name tp in diff --git a/infer/tests/codetoanalyze/cpp/frontend/destructors/simple_decl.cpp b/infer/tests/codetoanalyze/cpp/frontend/destructors/simple_decl.cpp new file mode 100644 index 000000000..9e7cbbf6c --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/destructors/simple_decl.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2015 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +struct A { + int f; + ~A() { + f = 0; + } +}; + +struct B { + int f; + ~B(); +}; + +B::~B() { + f = 1; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/destructors/simple_decl.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/destructors/simple_decl.cpp.dot new file mode 100644 index 000000000..13c218382 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/destructors/simple_decl.cpp.dot @@ -0,0 +1,24 @@ +digraph iCFG { +6 [label="6: BinaryOperatorStmt: Assign \n n$0=*&this:class B * [line 23]\n *n$0.f:int =1 [line 23]\n REMOVE_TEMPS(n$0); [line 23]\n NULLIFY(&this,false); [line 23]\n APPLY_ABSTRACTION; [line 23]\n " shape="box"] + + + 6 -> 5 ; +5 [label="5: Exit B_~B \n " color=yellow style=filled] + + +4 [label="4: Start B_~B\nFormals: this:class B *\nLocals: \n DECLARE_LOCALS(&return); [line 22]\n " color=yellow style=filled] + + + 4 -> 6 ; +3 [label="3: BinaryOperatorStmt: Assign \n n$0=*&this:class A * [line 13]\n *n$0.f:int =0 [line 13]\n REMOVE_TEMPS(n$0); [line 13]\n NULLIFY(&this,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit A_~A \n " color=yellow style=filled] + + +1 [label="1: Start A_~A\nFormals: this:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 12]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/frontend/cpp/DestructorsTest.java b/infer/tests/frontend/cpp/DestructorsTest.java new file mode 100644 index 000000000..bb478070d --- /dev/null +++ b/infer/tests/frontend/cpp/DestructorsTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package frontend.cpp; + +import org.junit.Rule; +import org.junit.Test; + +import java.io.IOException; + +import utils.DebuggableTemporaryFolder; +import utils.InferException; +import utils.ClangFrontendUtils; + +public class DestructorsTest { + + String basePath = "infer/tests/codetoanalyze/cpp/frontend/destructors/"; + + @Rule + public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder(); + + void frontendTest(String fileRelative) throws InterruptedException, IOException, InferException { + ClangFrontendUtils.createAndCompareCppDotFiles(folder, basePath + fileRelative); + } + + @Test + public void testSimpleDeclDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("simple_decl.cpp"); + } + +}