From 14452c3bf6331b2eea3ab79ee599c77de6392947 Mon Sep 17 00:00:00 2001 From: likith viswanath Date: Tue, 21 Jul 2026 12:00:53 +0530 Subject: [PATCH] Release 0.7.1 Deprecate alpha parser. --- CMakeLists.txt | 11 +- src/alpha/include/ast_normalized_context.hpp | 153 ------ src/alpha/include/astnormalizer.hpp | 66 +-- src/alpha/include/diffengine.hpp | 12 +- src/alpha/include/header_processor.hpp | 4 + src/alpha/include/node.hpp | 32 -- src/alpha/include/preprocesor.hpp | 15 +- src/alpha/include/session.hpp | 59 --- src/alpha/include/tree_builder.hpp | 63 --- src/alpha/src/ast_normalized_context.cpp | 66 --- src/alpha/src/astnormalizer.cpp | 197 +------- src/alpha/src/diffengine.cpp | 261 +--------- src/alpha/src/header_processor.cpp | 162 +------ src/alpha/src/node.cpp | 83 ---- src/alpha/src/preprocessor.cpp | 37 +- src/alpha/src/session.cpp | 95 ---- src/alpha/src/tree_builder.cpp | 457 ------------------ src/armor/CMakeLists.txt | 1 + src/armor/include/options_handler.hpp | 2 - src/armor/src/options_handler.cpp | 24 +- src/beta/include/ast_normalized_context.hpp | 222 --------- src/beta/include/astnormalizer.hpp | 34 +- src/beta/include/comment_handler.hpp | 16 +- src/beta/include/diffengine.hpp | 16 +- src/beta/include/header_processor.hpp | 4 + src/beta/include/preprocesor.hpp | 12 +- src/beta/include/session.hpp | 61 --- src/beta/include/tree_builder.hpp | 33 +- src/beta/src/ast_normalized_context.cpp | 123 ----- src/beta/src/astnormalizer.cpp | 37 +- src/beta/src/comment_handler.cpp | 16 +- src/beta/src/diffengine.cpp | 52 +- src/beta/src/header_processor.cpp | 166 +------ src/beta/src/preprocessor.cpp | 18 +- src/beta/src/session.cpp | 94 ---- src/beta/src/tree_builder.cpp | 283 ++++++----- src/common/CMakeLists.txt | 12 +- src/common/include/ast_normalized_context.hpp | 113 +++++ src/common/include/categorization.hpp | 2 +- src/common/include/custom_usr_generator.hpp | 2 - src/common/include/diff_utils.hpp | 2 + src/common/include/header_processor_utils.hpp | 29 ++ src/{beta => common}/include/node.hpp | 14 +- src/common/include/nsr_generator.hpp | 1 - src/common/include/options_handler.hpp | 2 - .../include/qualified_name_generator.hpp | 3 - src/common/include/session.hpp | 53 ++ src/common/include/tree_builder_utils.hpp | 4 +- src/common/src/ast_normalized_context.cpp | 140 ++++++ src/common/src/diff_utils.cpp | 2 + src/common/src/header_processor_utils.cpp | 155 ++++++ src/{beta => common}/src/node.cpp | 52 +- src/common/src/report_utils.cpp | 11 +- src/common/src/session.cpp | 132 +++++ src/common/src/tree_builder_utils.cpp | 79 ++- src/tests/__init__.py | 1 - src/tests/alpha/{src => }/CMakeLists.txt | 4 - src/tests/alpha/__init__.py | 1 - src/tests/alpha/functional/__init__.py | 1 - .../anonymous_type_changes/__init__.py | 2 - .../expected_output.json | 35 -- .../test_alpha_anonymous_type_changes.py | 51 -- .../anonymous_type_changes/v1/mylib.h | 143 ------ .../anonymous_type_changes/v2/mylib.h | 147 ------ src/tests/alpha/functional/conftest.py | 6 +- .../alpha/functional/enum_changes/__init__.py | 2 - .../enum_changes/expected_output.json | 28 -- .../enum_changes/test_alpha_enum_changes.py | 51 -- .../alpha/functional/enum_changes/v1/mylib.h | 18 - .../alpha/functional/enum_changes/v2/mylib.h | 21 - .../fatal_errors/expected_output.json | 82 +--- .../expected_output.json | 179 ------- .../field_variable_changes/v1/mylib.h | 25 - .../field_variable_changes/v2/mylib.h | 25 - .../functional/function_changes/__init__.py | 2 - .../function_changes/expected_output.json | 300 ------------ .../test_alpha_function_changes.py | 51 -- .../functional/function_changes/v1/mylib.h | 31 -- .../functional/function_changes/v2/mylib.h | 40 -- .../function_pointer_changes/__init__.py | 2 - .../expected_output.json | 128 ----- .../test_alpha_function_pointer_changes.py | 32 -- .../function_pointer_changes/v1/mylib.h | 21 - .../function_pointer_changes/v2/mylib.h | 15 - .../global_variable_changes/__init__.py | 2 - .../expected_output.json | 54 --- .../test_alpha_global_variable_changes.py | 51 -- .../global_variable_changes/v1/mylib.h | 10 - .../global_variable_changes/v2/mylib.h | 11 - src/tests/alpha/functional/sanity/__init__.py | 2 - .../functional/sanity/expected_output.json | 119 ----- .../functional/sanity/test_alpha_sanity.py | 30 -- src/tests/alpha/functional/sanity/v1/mylib.h | 115 ----- src/tests/alpha/functional/sanity/v2/mylib.h | 115 ----- .../functional/struct_changes/__init__.py | 2 - .../struct_changes/expected_output.json | 99 ---- .../test_alpha_struct_changes.py | 51 -- .../functional/struct_changes/v1/mylib.h | 40 -- .../functional/struct_changes/v2/mylib.h | 45 -- .../functional/template_changes/__init__.py | 2 - .../template_changes/expected_output.json | 41 -- .../test_alpha_template_changes.py | 30 -- .../functional/template_changes/v1/mylib.h | 174 ------- .../functional/template_changes/v2/mylib.h | 223 --------- .../functional/type_def_changes/__init__.py | 2 - .../type_def_changes/expected_output.json | 27 -- .../test_alpha_type_def_changes.py | 51 -- .../functional/type_def_changes/v1/mylib.h | 119 ----- .../functional/type_def_changes/v2/mylib.h | 117 ----- .../functional/union_changes/__init__.py | 2 - .../union_changes/expected_output.json | 59 --- .../union_changes/test_alpha_union_changes.py | 51 -- .../alpha/functional/union_changes/v1/mylib.h | 23 - .../alpha/functional/union_changes/v2/mylib.h | 20 - src/tests/alpha/src/main.cpp | 5 +- src/tests/alpha/src/options_handler.cpp | 203 ++------ src/tests/armor/{src => }/CMakeLists.txt | 0 .../alpha_parsing/expected_output.json | 248 +--------- .../alpha_parsing/test_alpha_parsing.py | 46 +- src/tests/armor/functional/conftest.py | 2 +- .../armor/functional/lang_options/v1/mylib.h | 5 - src/tests/armor/src/options_handler.cpp | 8 +- src/tests/beta/{src => }/CMakeLists.txt | 1 - src/tests/beta/__init__.py | 1 - src/tests/beta/functional/__init__.py | 1 - .../access_spec_decl_changes/__init__.py | 2 +- src/tests/beta/functional/conftest.py | 6 +- .../cxx_node_caching/expected_output.json | 298 ++++++++++++ .../test_cxx_node_caching.py} | 3 +- .../functional/cxx_node_caching/v1/mylib.h | 85 ++++ .../functional/cxx_node_caching/v2/mylib.h | 85 ++++ .../v2/mylib.h | 2 +- .../flow_cxx_categorisation/v2/mylib.h | 2 +- .../flow_cxx_edge_categorisation/v2/mylib.h | 2 +- .../v2/mylib.h | 2 +- .../flow_decl_init_categorisation/v2/mylib.h | 2 +- .../flow_macros_categorisation/v2/mylib.h | 2 +- .../beta/functional/struct_changes/v2/mylib.h | 6 - src/tests/beta/src/options_handler.cpp | 202 ++------ src/tests/common/CMakeLists.txt | 2 - 140 files changed, 1785 insertions(+), 6362 deletions(-) delete mode 100644 src/alpha/include/ast_normalized_context.hpp delete mode 100644 src/alpha/include/node.hpp delete mode 100644 src/alpha/include/session.hpp delete mode 100644 src/alpha/include/tree_builder.hpp delete mode 100644 src/alpha/src/ast_normalized_context.cpp delete mode 100644 src/alpha/src/node.cpp delete mode 100644 src/alpha/src/session.cpp delete mode 100644 src/alpha/src/tree_builder.cpp delete mode 100644 src/beta/include/ast_normalized_context.hpp delete mode 100644 src/beta/include/session.hpp delete mode 100644 src/beta/src/ast_normalized_context.cpp delete mode 100644 src/beta/src/session.cpp create mode 100644 src/common/include/ast_normalized_context.hpp create mode 100644 src/common/include/header_processor_utils.hpp rename src/{beta => common}/include/node.hpp (82%) create mode 100644 src/common/include/session.hpp create mode 100644 src/common/src/ast_normalized_context.cpp create mode 100644 src/common/src/header_processor_utils.cpp rename src/{beta => common}/src/node.cpp (72%) create mode 100644 src/common/src/session.cpp rename src/tests/alpha/{src => }/CMakeLists.txt (88%) delete mode 100644 src/tests/alpha/functional/anonymous_type_changes/__init__.py delete mode 100644 src/tests/alpha/functional/anonymous_type_changes/expected_output.json delete mode 100644 src/tests/alpha/functional/anonymous_type_changes/test_alpha_anonymous_type_changes.py delete mode 100644 src/tests/alpha/functional/anonymous_type_changes/v1/mylib.h delete mode 100644 src/tests/alpha/functional/anonymous_type_changes/v2/mylib.h delete mode 100644 src/tests/alpha/functional/enum_changes/__init__.py delete mode 100644 src/tests/alpha/functional/enum_changes/expected_output.json delete mode 100644 src/tests/alpha/functional/enum_changes/test_alpha_enum_changes.py delete mode 100644 src/tests/alpha/functional/enum_changes/v1/mylib.h delete mode 100644 src/tests/alpha/functional/enum_changes/v2/mylib.h delete mode 100644 src/tests/alpha/functional/field_variable_changes/expected_output.json delete mode 100644 src/tests/alpha/functional/field_variable_changes/v1/mylib.h delete mode 100644 src/tests/alpha/functional/field_variable_changes/v2/mylib.h delete mode 100644 src/tests/alpha/functional/function_changes/__init__.py delete mode 100644 src/tests/alpha/functional/function_changes/expected_output.json delete mode 100644 src/tests/alpha/functional/function_changes/test_alpha_function_changes.py delete mode 100644 src/tests/alpha/functional/function_changes/v1/mylib.h delete mode 100644 src/tests/alpha/functional/function_changes/v2/mylib.h delete mode 100644 src/tests/alpha/functional/function_pointer_changes/__init__.py delete mode 100644 src/tests/alpha/functional/function_pointer_changes/expected_output.json delete mode 100644 src/tests/alpha/functional/function_pointer_changes/test_alpha_function_pointer_changes.py delete mode 100644 src/tests/alpha/functional/function_pointer_changes/v1/mylib.h delete mode 100644 src/tests/alpha/functional/function_pointer_changes/v2/mylib.h delete mode 100644 src/tests/alpha/functional/global_variable_changes/__init__.py delete mode 100644 src/tests/alpha/functional/global_variable_changes/expected_output.json delete mode 100644 src/tests/alpha/functional/global_variable_changes/test_alpha_global_variable_changes.py delete mode 100644 src/tests/alpha/functional/global_variable_changes/v1/mylib.h delete mode 100644 src/tests/alpha/functional/global_variable_changes/v2/mylib.h delete mode 100644 src/tests/alpha/functional/sanity/__init__.py delete mode 100644 src/tests/alpha/functional/sanity/expected_output.json delete mode 100644 src/tests/alpha/functional/sanity/test_alpha_sanity.py delete mode 100644 src/tests/alpha/functional/sanity/v1/mylib.h delete mode 100644 src/tests/alpha/functional/sanity/v2/mylib.h delete mode 100644 src/tests/alpha/functional/struct_changes/__init__.py delete mode 100644 src/tests/alpha/functional/struct_changes/expected_output.json delete mode 100644 src/tests/alpha/functional/struct_changes/test_alpha_struct_changes.py delete mode 100644 src/tests/alpha/functional/struct_changes/v1/mylib.h delete mode 100644 src/tests/alpha/functional/struct_changes/v2/mylib.h delete mode 100644 src/tests/alpha/functional/template_changes/__init__.py delete mode 100644 src/tests/alpha/functional/template_changes/expected_output.json delete mode 100644 src/tests/alpha/functional/template_changes/test_alpha_template_changes.py delete mode 100644 src/tests/alpha/functional/template_changes/v1/mylib.h delete mode 100644 src/tests/alpha/functional/template_changes/v2/mylib.h delete mode 100644 src/tests/alpha/functional/type_def_changes/__init__.py delete mode 100644 src/tests/alpha/functional/type_def_changes/expected_output.json delete mode 100644 src/tests/alpha/functional/type_def_changes/test_alpha_type_def_changes.py delete mode 100644 src/tests/alpha/functional/type_def_changes/v1/mylib.h delete mode 100644 src/tests/alpha/functional/type_def_changes/v2/mylib.h delete mode 100644 src/tests/alpha/functional/union_changes/__init__.py delete mode 100644 src/tests/alpha/functional/union_changes/expected_output.json delete mode 100644 src/tests/alpha/functional/union_changes/test_alpha_union_changes.py delete mode 100644 src/tests/alpha/functional/union_changes/v1/mylib.h delete mode 100644 src/tests/alpha/functional/union_changes/v2/mylib.h rename src/tests/armor/{src => }/CMakeLists.txt (100%) rename src/tests/beta/{src => }/CMakeLists.txt (96%) create mode 100644 src/tests/beta/functional/cxx_node_caching/expected_output.json rename src/tests/{alpha/functional/field_variable_changes/test_alpha_field_variable_changes.py => beta/functional/cxx_node_caching/test_cxx_node_caching.py} (96%) create mode 100644 src/tests/beta/functional/cxx_node_caching/v1/mylib.h create mode 100644 src/tests/beta/functional/cxx_node_caching/v2/mylib.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d06f4fb..99317a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,14 @@ cmake_minimum_required(VERSION 3.14) project(armor) -set(TOOL_VERSION "0.6.9") +set(TOOL_VERSION "0.7.1") set(TOOL_DOCS_URL "https://github.com/qualcomm/armor/blob/main/README.md") set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem /usr/include/c++/11 -isystem /usr/include/x86_64-linux-gnu/c++/11") + execute_process( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE DETECTED_GCC_VERSION @@ -47,15 +49,16 @@ llvm_map_components_to_libnames(LLVM_LIBS ) add_definitions(-DTOOL_VERSION="${TOOL_VERSION}") +add_definitions(-DTOOL_DOCS_URL="${TOOL_DOCS_URL}") add_subdirectory(src/common) add_subdirectory(src/alpha) add_subdirectory(src/beta) add_subdirectory(src/armor) -add_subdirectory(src/tests/alpha/src) -add_subdirectory(src/tests/beta/src) -add_subdirectory(src/tests/armor/src) +add_subdirectory(src/tests/alpha) +add_subdirectory(src/tests/beta) +add_subdirectory(src/tests/armor) add_subdirectory(src/tests/common) diff --git a/src/alpha/include/ast_normalized_context.hpp b/src/alpha/include/ast_normalized_context.hpp deleted file mode 100644 index 8148207..0000000 --- a/src/alpha/include/ast_normalized_context.hpp +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#pragma once - -#include "node.hpp" -#include "clang/AST/ASTContext.h" -#include -#include -#include - -namespace alpha{ - -/** - * @class SourceRangeTracker - * @brief Tracks fatal preprocessor directives found during AST traversal. - * - * This class manages a collection of fatal directive references that need to be - * tracked for error reporting or analysis purposes. - */ -class SourceRangeTracker { - /** - * @struct FatalDirectiveRef - * @brief References to a fatal preprocessor directive and its source file. - */ - struct FatalDirectiveRef { - std::string Header; ///< The directive text (e.g., "#error message") - std::string File; ///< The source file containing the directive - - FatalDirectiveRef(llvm::StringRef header, llvm::StringRef file) : Header(header), File(file) {} - }; - - public: - /** - * @brief Constructs an empty SourceRangeTracker. - */ - SourceRangeTracker() = default; - - /** - * @brief Adds a fatal directive reference. - * @param header The directive text. - * @param file The source file path. - */ - void addFatalDirective(llvm::StringRef header, llvm::StringRef file); - - /** - * @brief Returns all fatal directive references. - */ - const llvm::SmallVector& getFatalDirectives() const; - - /** - * @brief Clears all tracked fatal directives. - */ - void clear(); - - /** - * @brief Checks if the tracker is empty. - * @return True if no fatal directives are tracked. - */ - bool empty() const; - -private: - llvm::SmallVector fatalDirectives; -}; - -/** - * @class ASTNormalizedContext - * @brief Manages a collection of API nodes parsed from an Abstract Syntax Tree (AST). - * - * This class serves as the central repository for all unique API nodes found during - * an AST traversal. It maintains two primary data structures: - * - * 1. A map (`normalizedTree`) from a unique identifier (like a USR) to the - * corresponding `APINode`. This ensures that each API entity is represented by - * a single, unique object, preventing duplication. - * - * 2. A vector (`rootApiNodes`) of nodes that are considered top-level or - * "root" elements of the API (e.g., free functions, global variables, or - * classes in the global namespace). - */ - -class ASTNormalizedContext { -public: - - /** - * @brief Constructs an empty ASTNormalizedContext. - */ - ASTNormalizedContext(); - - /** - * @brief Adds a new node to the normalized tree. - * - * If a node with the same key already exists, it is not replaced. - * Use addOrUpdateNode if overwriting is desired. - * - * @param key The unique string identifier for the node (e.g., USR). - * @param node A shared pointer to the APINode. - */ - void addNode(llvm::StringRef key,const std::shared_ptr node); - - /** - * @brief Adds a node to the list of root API nodes. - * - * @param rootNode A const shared pointer to the APINode. - */ - void addRootNode(const std::shared_ptr rootNode); - - /** - * @brief Returns a const reference to the entire normalized tree map. - */ - const llvm::StringMap>& getTree() const; - - /** - * @brief Returns a const reference to the list of root API nodes. - */ - const llvm::SmallVector,64>& getRootNodes() const; - - /** - * @brief Checks if the context contains any nodes. - * @return True if both the tree and root nodes list are empty, false otherwise. - */ - bool empty() const; - - /** - * @brief Clears all stored nodes, resetting the context to an empty state. - */ - void clear(); - - void addClangASTContext(clang::ASTContext *ASTContext); - - clang::ASTContext* getClangASTContext() const; - - /** - * @brief Returns a reference to the source range tracker. - */ - SourceRangeTracker& getSourceRangeTracker(); - - /** - * @brief Returns a const reference to the source range tracker. - */ - const SourceRangeTracker& getSourceRangeTracker() const; - - llvm::StringSet<> excludeNodes; - llvm::StringSet<> hashSet; - -private: - llvm::StringMap> apiNodesMap; - llvm::SmallVector,64> apiNodes; - - SourceRangeTracker sourceRangeTracker; - clang::ASTContext* clangContext; -}; - -} \ No newline at end of file diff --git a/src/alpha/include/astnormalizer.hpp b/src/alpha/include/astnormalizer.hpp index 8b9f219..c068ba3 100644 --- a/src/alpha/include/astnormalizer.hpp +++ b/src/alpha/include/astnormalizer.hpp @@ -3,78 +3,40 @@ #pragma once #include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Tooling/Tooling.h" -#include "node.hpp" #include "ast_normalized_context.hpp" #include "session.hpp" -#include "tree_builder.hpp" +#include "preprocesor.hpp" -namespace alpha{ - -class ASTNormalize : public clang::RecursiveASTVisitor { - public: - - alpha::APISession* session; - ASTNormalizedContext* context; - clang::ASTContext *clangContext; - - alpha::TreeBuilder treeBuilder; - - ASTNormalize(alpha::APISession* session, alpha::ASTNormalizedContext* context, clang::ASTContext* clangContext); - - bool TraverseNamespaceDecl(clang::NamespaceDecl *Decl); - bool TraverseRecordDecl(clang::RecordDecl *Decl); - bool TraverseCXXRecordDecl(clang::CXXRecordDecl *Decl); - bool TraverseCXXConstructorDecl(clang::CXXConstructorDecl *Decl); - bool TraverseCXXMethodDecl(clang::CXXMethodDecl *Decl); - bool TraverseFunctionTemplateDecl(clang::FunctionTemplateDecl *Decl); - bool TraverseEnumDecl(clang::EnumDecl *Decl); - bool TraverseFunctionDecl(clang::FunctionDecl *Decl); - bool TraverseTypeAliasDecl(clang::TypeAliasDecl *Decl); - bool TraverseVarDecl(clang::VarDecl *Decl); - bool TraverseFieldDecl(clang::FieldDecl *Decl); - bool TraverseTypedefDecl(clang::TypedefDecl *Decl); - bool TraverseClassTemplateDecl(clang::ClassTemplateDecl *Decl); - bool TraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *Decl); - bool TraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl *Decl); - - bool VisitNamespaceDecl(clang::NamespaceDecl *Decl); - bool VisitRecordDecl(clang::RecordDecl *Decl); - bool VisitCXXRecordDecl(clang::CXXRecordDecl *Decl); - bool VisitEnumDecl(clang::EnumDecl *Decl); - bool VisitFieldDecl(clang::FieldDecl *Decl); - bool VisitFunctionDecl(clang::FunctionDecl *Decl); - bool VisitTypeAliasDecl(clang::TypeAliasDecl *Decl); - bool VisitVarDecl(clang::VarDecl *Decl); - bool VisitTypedefDecl(clang::TypedefDecl *Decl); -}; +namespace armor { namespace alpha { class ASTNormalizeConsumer : public clang::ASTConsumer { public: - alpha::APISession* session; - alpha::ASTNormalizedContext* context; - ASTNormalize *visitor; - ASTNormalizeConsumer(alpha::APISession* session, alpha::ASTNormalizedContext* context); + armor::APISession* session; + armor::ASTNormalizedContext* context; + ASTNormalizeConsumer(armor::APISession* session, armor::ASTNormalizedContext* context); void HandleTranslationUnit(clang::ASTContext &Context) override; }; class NormalizeAction : public clang::ASTFrontendAction { public: - alpha::APISession* session; - ASTNormalizedContext* context; - NormalizeAction(alpha::APISession* session, alpha::ASTNormalizedContext* context); + armor::APISession* session; + armor::ASTNormalizedContext* context; + NormalizeAction(armor::APISession* session, armor::ASTNormalizedContext* context); std::unique_ptr CreateASTConsumer(clang::CompilerInstance &, clang::StringRef) override; }; class NormalizeActionFactory : public clang::tooling::FrontendActionFactory { public: - alpha::APISession* session; + armor::APISession* session; const std::string& fileName; - explicit NormalizeActionFactory(alpha::APISession* session, const std::string& fileName); + explicit NormalizeActionFactory(armor::APISession* session, const std::string& fileName); std::unique_ptr create() override; }; -} \ No newline at end of file +std::unique_ptr +createNormalizeActionFactory(armor::APISession* session, const std::string& fileName); + +} } // namespace armor::alpha diff --git a/src/alpha/include/diffengine.hpp b/src/alpha/include/diffengine.hpp index 3538939..720b0cb 100644 --- a/src/alpha/include/diffengine.hpp +++ b/src/alpha/include/diffengine.hpp @@ -2,10 +2,14 @@ // SPDX-License-Identifier: BSD-3-Clause #pragma once -#include "node.hpp" #include "ast_normalized_context.hpp" +#include + +namespace armor { namespace alpha { nlohmann::json diffTrees( - const alpha::ASTNormalizedContext* context1, - const alpha::ASTNormalizedContext* context2 -); \ No newline at end of file + const armor::ASTNormalizedContext* context1, + const armor::ASTNormalizedContext* context2 +); + +} } // namespace armor::alpha diff --git a/src/alpha/include/header_processor.hpp b/src/alpha/include/header_processor.hpp index c154a82..36ff80b 100644 --- a/src/alpha/include/header_processor.hpp +++ b/src/alpha/include/header_processor.hpp @@ -7,6 +7,8 @@ #include "comm_def.hpp" #include "session.hpp" +namespace armor { namespace alpha { + PARSING_STATUS processHeaderPairAlpha(const std::string& projectRoot1, const std::string& file1, const std::string& projectRoot2, @@ -15,3 +17,5 @@ PARSING_STATUS processHeaderPairAlpha(const std::string& projectRoot1, const std::vector& IncludePaths, const std::vector& macroFlags, const LANG_OPTIONS lang); + +} } // namespace armor::alpha diff --git a/src/alpha/include/node.hpp b/src/alpha/include/node.hpp deleted file mode 100644 index 5549618..0000000 --- a/src/alpha/include/node.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#pragma once - -#include -#include -#include - -#include "comm_def.hpp" -#include "nlohmann/json.hpp" -#include "nlohmann/json_fwd.hpp" - -// Main Node structure -// string can be optimized by string_view powered by stringRef - -namespace alpha{ - -struct APINode { - NodeKind kind = NodeKind::Unknown; - std::string hash; - std::string qualifiedName; - std::string dataType; // Underlying datatype of variables .... (int/float/...) - bool isInclined = false; - bool isConstExpr = false; - APINodeStorageClass storage = APINodeStorageClass::None; - - std::unique_ptr,16>> children; - - nlohmann::json diff(const std::shared_ptr& other) const; -}; - -} \ No newline at end of file diff --git a/src/alpha/include/preprocesor.hpp b/src/alpha/include/preprocesor.hpp index 1ec68cb..87df126 100644 --- a/src/alpha/include/preprocesor.hpp +++ b/src/alpha/include/preprocesor.hpp @@ -1,20 +1,19 @@ // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause -#include "clang/AST/ASTContext.h" +#pragma once + #include "clang/Basic/SourceManager.h" -#include "clang/Lex/MacroInfo.h" #include "clang/Lex/PPCallbacks.h" -#include "node.hpp" #include "ast_normalized_context.hpp" -namespace alpha { +namespace armor { namespace alpha { class ASTNormalizerPreprocessor : public clang::PPCallbacks { public: - ASTNormalizerPreprocessor(clang::SourceManager* SM, ASTNormalizedContext* context); + ASTNormalizerPreprocessor(clang::SourceManager* SM, armor::ASTNormalizedContext* context); void InclusionDirective( clang::SourceLocation HashLoc, @@ -27,11 +26,11 @@ class ASTNormalizerPreprocessor : public clang::PPCallbacks { clang::StringRef RelativePath, const clang::Module *Imported, clang::SrcMgr::CharacteristicKind FileType); - + private: clang::SourceManager* SM; - ASTNormalizedContext* context; + armor::ASTNormalizedContext* context; }; -} \ No newline at end of file +} } // namespace armor::alpha diff --git a/src/alpha/include/session.hpp b/src/alpha/include/session.hpp deleted file mode 100644 index 7e54efc..0000000 --- a/src/alpha/include/session.hpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#pragma once - -#include "ast_normalized_context.hpp" -#include "clang/Tooling/CompilationDatabase.h" - -// Forward declarations to avoid including heavy Clang headers here -namespace clang { namespace tooling { class CompilationDatabase; } } - -/** - * @class APISession - * @brief Manages a session for comparing multiple source files. - * - * This class orchestrates the process of parsing and normalizing ASTs from - * one or more source files. It holds: - * - * 1. A map from filenames to their corresponding `ASTNormalizedContext`. - * 2. A central string pool to unify and reduce memory usage for common strings. - * 3. A reference to the Clang Compilation Database used for parsing. - */ -namespace alpha { - -class APISession { -public: - /** - * @brief Constructs an APISession. - * @param compDB A unique_ptr to the compilation database to be used for all parsing. - * The session takes ownership of the database. - */ - /** - * @brief Processes a source file, normalizing its AST and storing the context. - * - * Runs a Clang tool on the specified file, populates an ASTNormalizedContext, - * and stores it in the session, mapped by the filename. - * - * @param filename The path to the source file to process. - */ - PARSING_STATUS processFile(std::string fileName, std::unique_ptr m_compDB); - - /** - * @brief Retrieves the normalized context for a previously processed file. - * @param filename The path to the source file. - * @return A pointer to the ASTNormalizedContext if the file was processed, - * otherwise nullptr. - */ - ASTNormalizedContext* getContext(llvm::StringRef fileName) const; - - ASTNormalizedContext* getContext(const std::string& fileName) const; - - - void createNormalizedASTContext(const std::string& key); - -private: - // A map from a filename to its fully normalized AST context - llvm::StringMap> m_contexts; -}; - -} \ No newline at end of file diff --git a/src/alpha/include/tree_builder.hpp b/src/alpha/include/tree_builder.hpp deleted file mode 100644 index 1d754f3..0000000 --- a/src/alpha/include/tree_builder.hpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#pragma once - -#include "clang/AST/ASTContext.h" -#include "clang/AST/TypeLoc.h" - -#include "ast_normalized_context.hpp" -#include "node.hpp" -#include "qualified_name_builder.hpp" - -/** - * @class TreeBuilder - * @brief Builds an API node tree from Clang AST declarations. - * - * This class encapsulates all the logic for creating and organizing APINode objects - * based on Clang AST declarations. It works with an ASTNormalizedContext to store - * the resulting nodes. - */ - -namespace alpha{ - -class TreeBuilder { -private: - alpha::ASTNormalizedContext* context; - StringBuilder qualifiedNames; - std::vector> nodeStack; -public: - /** - * @brief Constructs a TreeBuilder with the given context. - * - * @param context The ASTNormalizedContext to store the resulting nodes. - */ - explicit TreeBuilder(alpha::ASTNormalizedContext* context); - - // Node management - void AddNode(const std::shared_ptr& node); - void PushNode(const std::shared_ptr& node); - void PopNode(); - - // Name management - void PushName(llvm::StringRef name); - void PopName(); - const std::string GetCurrentQualifiedName(); - - // Utility methods - bool IsFromMainFileAndNotLocal(const clang::Decl* Decl); - void normalizeFunctionPointerType(const std::string& dataType, clang::FunctionProtoTypeLoc FTL); - void normalizeValueDeclNode(const clang::ValueDecl *Decl, unsigned int pos = -1); - - // Node building methods - bool BuildRecordNode(clang::RecordDecl* Decl); - bool BuildCXXRecordNode(clang::CXXRecordDecl* Decl); - bool BuildEnumNode(clang::EnumDecl* Decl); - bool BuildFunctionNode(clang::FunctionDecl* Decl); - bool BuildTypedefDecl(clang::TypedefDecl *Decl); - bool BuildVarDecl(clang::VarDecl *Decl); - bool BuildFieldDecl(clang::FieldDecl *Decl); - - void BuildReturnTypeNode(clang::QualType type); -}; - -} \ No newline at end of file diff --git a/src/alpha/src/ast_normalized_context.cpp b/src/alpha/src/ast_normalized_context.cpp deleted file mode 100644 index e1b15e8..0000000 --- a/src/alpha/src/ast_normalized_context.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#include "node.hpp" -#include "ast_normalized_context.hpp" - -alpha::ASTNormalizedContext::ASTNormalizedContext() = default; - -void alpha::ASTNormalizedContext::addNode(llvm::StringRef key, std::shared_ptr node) { - apiNodesMap.try_emplace(key, std::move(node)); -} - -void alpha::ASTNormalizedContext::addRootNode(std::shared_ptr rootNode) { - if (rootNode) { - apiNodes.emplace_back(std::move(rootNode)); - } -} - -const llvm::StringMap>& alpha::ASTNormalizedContext::getTree() const { - return apiNodesMap; -} - -const llvm::SmallVector,64>& alpha::ASTNormalizedContext::getRootNodes() const { - return apiNodes; -} - -bool alpha::ASTNormalizedContext::empty() const { - return apiNodesMap.empty() && apiNodes.empty(); -} - -void alpha::ASTNormalizedContext::clear() { - apiNodesMap.clear(); - apiNodes.clear(); - sourceRangeTracker.clear(); -} - -void alpha::ASTNormalizedContext::addClangASTContext(clang::ASTContext *ASTContext){ - clangContext = ASTContext; -} - -clang::ASTContext* alpha::ASTNormalizedContext::getClangASTContext() const { - return clangContext; -} - -alpha::SourceRangeTracker& alpha::ASTNormalizedContext::getSourceRangeTracker() { - return sourceRangeTracker; -} - -const alpha::SourceRangeTracker& alpha::ASTNormalizedContext::getSourceRangeTracker() const { - return sourceRangeTracker; -} - -void alpha::SourceRangeTracker::addFatalDirective(llvm::StringRef header, llvm::StringRef file) { - fatalDirectives.emplace_back(header, file); -} - -const llvm::SmallVector& alpha::SourceRangeTracker::getFatalDirectives() const { - return fatalDirectives; -} - -void alpha::SourceRangeTracker::clear() { - fatalDirectives.clear(); -} - -bool alpha::SourceRangeTracker::empty() const { - return fatalDirectives.empty(); -} \ No newline at end of file diff --git a/src/alpha/src/astnormalizer.cpp b/src/alpha/src/astnormalizer.cpp index a9a4535..8e93e8b 100644 --- a/src/alpha/src/astnormalizer.cpp +++ b/src/alpha/src/astnormalizer.cpp @@ -1,201 +1,56 @@ // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause #include "astnormalizer.hpp" -#include "node.hpp" #include "session.hpp" -#include "tree_builder.hpp" #include "preprocesor.hpp" -#include #include "clang/Frontend/CompilerInstance.h" -// --- alpha::ASTNormalize --- -alpha::ASTNormalize::ASTNormalize(alpha::APISession* session, alpha::ASTNormalizedContext* context, clang::ASTContext* clangContext) - : session(session), context(context), clangContext(clangContext), treeBuilder(alpha::TreeBuilder(context)) {} -// (Implementation of visitor methods remains the same conceptually) +namespace armor { namespace alpha { +// --- ASTNormalizeConsumer --- -// --- alpha::ASTNormalizeConsumer --- -// Constructor simply stores the pointers. -alpha::ASTNormalizeConsumer::ASTNormalizeConsumer(alpha::APISession* session, alpha::ASTNormalizedContext* context) +ASTNormalizeConsumer::ASTNormalizeConsumer(armor::APISession* session, armor::ASTNormalizedContext* context) : session(session), context(context) {} -void alpha::ASTNormalizeConsumer::HandleTranslationUnit(clang::ASTContext &clangContext) { - // Creates the visitor, passing along the pointers to the session and the pre-existing context. +void ASTNormalizeConsumer::HandleTranslationUnit(clang::ASTContext &clangContext) { context->addClangASTContext(&clangContext); - alpha::ASTNormalize visitor(session, context, &clangContext); - visitor.TraverseDecl(clangContext.getTranslationUnitDecl()); + // Alpha is parse-error detection only: no AST traversal, no node building. + // Fatal include failures are already collected by ASTNormalizerPreprocessor. } // --- NormalizeAction --- -// Constructor now receives the pre-existing context pointer. -alpha::NormalizeAction::NormalizeAction(alpha::APISession* session, alpha::ASTNormalizedContext* context) + +NormalizeAction::NormalizeAction(armor::APISession* session, armor::ASTNormalizedContext* context) : session(session), context(context) {} -std::unique_ptr alpha::NormalizeAction::CreateASTConsumer(clang::CompilerInstance & CI, clang::StringRef) { - // Set up preprocessor callbacks - auto preprocessor = std::make_unique(&CI.getSourceManager(), context); +std::unique_ptr NormalizeAction::CreateASTConsumer( + clang::CompilerInstance &CI, clang::StringRef) +{ + auto preprocessor = std::make_unique( + &CI.getSourceManager(), context); CI.getPreprocessor().addPPCallbacks(std::move(preprocessor)); - - return std::make_unique(session, context); + return std::make_unique(session, context); } -// --- NormalizeActionFactory (The "Get and Pass" Logic) --- -alpha::NormalizeActionFactory::NormalizeActionFactory(alpha::APISession* session, const std::string& fileName) : session(session), fileName(fileName) {} - -std::unique_ptr alpha::NormalizeActionFactory::create() { - // 2. Use the filename to get the pre-existing context from the session. - alpha::ASTNormalizedContext* contextForThisFile = session->getContext(fileName); - - // --- Error Handling --- - if (!contextForThisFile) { - // This is a critical logic error. The context should have been created before processing. - throw std::runtime_error("No alpha::ASTNormalizedContext was created for file: " + fileName); - } - - // 3. Create the action, efficiently passing pointers to the session and the retrieved context. - return std::make_unique(session, contextForThisFile); -} -// === Visit and Traverse Methods === -bool alpha::ASTNormalize::TraverseNamespaceDecl(clang::NamespaceDecl *Decl) { - RecursiveASTVisitor::TraverseNamespaceDecl(Decl); - return true; -} +// --- NormalizeActionFactory --- -bool alpha::ASTNormalize::TraverseRecordDecl(clang::RecordDecl *Decl) { - // Only handle pure C RecordDecl — CXXRecordDecl is a subclass and has its own Traverse - if (llvm::isa(Decl)) { - return RecursiveASTVisitor::TraverseRecordDecl(Decl); - } - - RecursiveASTVisitor::TraverseRecordDecl(Decl); - - llvm::SmallString<128> nameBuf; - llvm::raw_svector_ostream OS(nameBuf); - Decl->printName(OS); - - if (treeBuilder.IsFromMainFileAndNotLocal(Decl) && Decl->isThisDeclarationADefinition() && !nameBuf.empty()) { - treeBuilder.PopName(); - treeBuilder.PopNode(); - } - - return true; -} +NormalizeActionFactory::NormalizeActionFactory(armor::APISession* session, const std::string& fileName) + : session(session), fileName(fileName) {} -bool alpha::ASTNormalize::TraverseCXXRecordDecl(clang::CXXRecordDecl *Decl) { - - RecursiveASTVisitor::TraverseCXXRecordDecl(Decl); - - llvm::SmallString<128> nameBuf; - llvm::raw_svector_ostream OS(nameBuf); - Decl->printName(OS); - - if(treeBuilder.IsFromMainFileAndNotLocal(Decl) && !Decl->isClass() && !Decl->isTemplateDecl() - && Decl->isThisDeclarationADefinition() && !llvm::isa(Decl) - && !nameBuf.empty()){ - treeBuilder.PopName(); - treeBuilder.PopNode(); +std::unique_ptr NormalizeActionFactory::create() { + armor::ASTNormalizedContext* contextForThisFile = session->getAlphaContext(fileName); + if (!contextForThisFile) { + throw std::runtime_error("No armor::ASTNormalizedContext was created for file: " + fileName); } - - return true; -} - -bool alpha::ASTNormalize::TraverseCXXConstructorDecl(clang::CXXConstructorDecl *Decl) { - RecursiveASTVisitor::TraverseCXXConstructorDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseCXXMethodDecl(clang::CXXMethodDecl *Decl){ - RecursiveASTVisitor::TraverseCXXMethodDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseClassTemplateDecl(clang::ClassTemplateDecl *Decl){ - RecursiveASTVisitor::TraverseClassTemplateDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl *Decl){ - RecursiveASTVisitor::TraverseClassTemplateSpecializationDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl *Decl){ - RecursiveASTVisitor::TraverseClassTemplatePartialSpecializationDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseFunctionTemplateDecl(clang::FunctionTemplateDecl *Decl){ - RecursiveASTVisitor::TraverseFunctionTemplateDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseEnumDecl(clang::EnumDecl *Decl){ - RecursiveASTVisitor::TraverseEnumDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseFunctionDecl(clang::FunctionDecl *Decl){ - RecursiveASTVisitor::TraverseFunctionDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseTypeAliasDecl(clang::TypeAliasDecl *Decl){ - RecursiveASTVisitor::TraverseTypeAliasDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseVarDecl(clang::VarDecl *Decl){ - RecursiveASTVisitor::TraverseVarDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseFieldDecl(clang::FieldDecl *Decl){ - RecursiveASTVisitor::TraverseFieldDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::TraverseTypedefDecl(clang::TypedefDecl *Decl){ - RecursiveASTVisitor::TraverseTypedefDecl(Decl); - return true; -} - -bool alpha::ASTNormalize::VisitNamespaceDecl(clang::NamespaceDecl *Decl) { - return false; -} - -bool alpha::ASTNormalize::VisitRecordDecl(clang::RecordDecl *Decl) { - // Only handle pure C RecordDecl — skip if this is actually a CXXRecordDecl - if (llvm::isa(Decl)) return true; - return treeBuilder.BuildRecordNode(Decl); -} - -bool alpha::ASTNormalize::VisitCXXRecordDecl(clang::CXXRecordDecl *Decl) { - return treeBuilder.BuildCXXRecordNode(Decl); -} - -bool alpha::ASTNormalize::VisitEnumDecl(clang::EnumDecl *Decl) { - return treeBuilder.BuildEnumNode(Decl); -} - -bool alpha::ASTNormalize::VisitFunctionDecl(clang::FunctionDecl *Decl) { - return treeBuilder.BuildFunctionNode(Decl); -} - -bool alpha::ASTNormalize::VisitTypeAliasDecl(clang::TypeAliasDecl *Decl) { - return true; -} - -bool alpha::ASTNormalize::VisitTypedefDecl(clang::TypedefDecl *Decl) { - return treeBuilder.BuildTypedefDecl(Decl); + return std::make_unique(session, contextForThisFile); } -bool alpha::ASTNormalize::VisitVarDecl(clang::VarDecl *Decl) { - return treeBuilder.BuildVarDecl(Decl); +std::unique_ptr +createNormalizeActionFactory(armor::APISession* session, const std::string& fileName) { + return std::make_unique(session, fileName); } -bool alpha::ASTNormalize::VisitFieldDecl(clang::FieldDecl *Decl) { - return treeBuilder.BuildFieldDecl(Decl); -} \ No newline at end of file +} } // namespace armor::alpha diff --git a/src/alpha/src/diffengine.cpp b/src/alpha/src/diffengine.cpp index 0e9eb59..185a45a 100644 --- a/src/alpha/src/diffengine.cpp +++ b/src/alpha/src/diffengine.cpp @@ -1,266 +1,55 @@ // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause -#include -#include - #include "diffengine.hpp" #include "diff_utils.hpp" #include "logger.hpp" using json = nlohmann::json; -auto byHash = [](const std::shared_ptr& node) -> const std::string& { - return node->hash; -}; - -template -std::vector, std::shared_ptr>> intersection( - const llvm::SmallVector, 16>& a, - const llvm::SmallVector, 16>& b, - KeyFunc&& keyFunc -) { - std::unordered_multimap> map_b; - map_b.reserve(b.size()); - for (const auto& node : b) { - map_b.emplace(keyFunc(node), node); - } +namespace armor { namespace alpha { - std::vector, std::shared_ptr>> result; - result.reserve(std::min(a.size(), b.size())); +namespace { - for (const auto& node_a : a) { - const auto& key = keyFunc(node_a); - auto it = map_b.find(key); - if (it != map_b.end()) { - result.emplace_back(node_a, std::move(it->second)); - map_b.erase(it); - } +json createHeaderResolutionFailures(const armor::SourceRangeTracker& tracker) { + json failures = json::array(); + for (const auto& directive : tracker.getFatalDirectives()) { + json failure; + failure[HEADER] = directive.Header; + failure[FILE_PATH] = directive.File; + failures.emplace_back(failure); } - - return result; - + return failures; } -template -std::vector> difference( - const llvm::SmallVector, 16>& a, - const llvm::SmallVector, 16>& b, - KeyFunc&& keyFunc -) { - std::unordered_multimap> map_b; - map_b.reserve(b.size()); - for (const auto& node : b) { - map_b.emplace(keyFunc(node), node); - } - - std::vector> result; - result.reserve(std::min(a.size(), b.size())); - - for (const auto& node : a) { - const auto& key = keyFunc(node); - auto it = map_b.find(key); - if (it != map_b.end()) { - map_b.erase(it); // remove one occurrence - } else { - result.emplace_back(node); - } - } - - return result; -} - -const bool inline checkLayoutChange(const std::shared_ptr node){ - return node->kind != NodeKind::Enum; -} - -const bool inline hasChildren(const std::shared_ptr& node) { - return node->children == nullptr ? false : !node->children->empty(); -} - -namespace{ - const json toJson(const std::shared_ptr& node) { - - json json_node; - - if(!node->qualifiedName.empty()) json_node[QUALIFIED_NAME] = node->qualifiedName; - json_node[NODE_TYPE] = serialize(node->kind); - - if(hasChildren(node)) { - json_node[CHILDREN] = json::array(); - for (const auto& childNode : *node->children) { - json_node[CHILDREN].emplace_back(toJson(childNode)); - } - } - - if(!node->dataType.empty()) json_node[DATA_TYPE] = node->dataType; - - return json_node; - } - - const json get_json_from_node(const std::shared_ptr node, const std::string& tag) { - json json_node = toJson(node); - json_node[TAG] = tag; - return json_node; - } - - const json createHeaderResolutionFailures(const alpha::SourceRangeTracker& tracker) { - json failures = json::array(); - for (const auto& directive : tracker.getFatalDirectives()) { - json failure; - failure["header"] = directive.Header; - failure["file"] = directive.File; - failures.emplace_back(failure); - } - return failures; - } -} - - -json diffNodes( - const std::shared_ptr& a, - const std::shared_ptr& b -){ - - // Any node can have children. - - if ( hasChildren(a) && hasChildren(b) ) { - - json childrenDiff = json::array(); - - const std::vector> removed_nodes = difference( - *a->children, - *b->children, - byHash - ); - const std::vector> added_nodes = difference( - *b->children, - *a->children, - byHash - ); - - const std::vector, std::shared_ptr>> common_nodes = intersection( - *a->children, - *b->children, - byHash - ); - - for (const auto& removedNode : removed_nodes) { - childrenDiff.emplace_back(get_json_from_node(removedNode, REMOVED)); - } - - for (const auto& addedNode : added_nodes) { - childrenDiff.emplace_back(get_json_from_node(addedNode, ADDED)); - } - - for (const auto& commonNodePair : common_nodes) { - /* - Comparing nodes of same scope. No name conflicts for const alpha::APINodes in same scope. - Here scope can be Main Header file or inside a CXXRecordDecl, EnumDecl, FunctionDecl - */ - json sameScopeDiff = diffNodes(commonNodePair.first,commonNodePair.second); - - if(!sameScopeDiff.is_null() && !sameScopeDiff.empty()){ - if(sameScopeDiff.is_array()){ - childrenDiff.insert(childrenDiff.end(), sameScopeDiff.begin(), sameScopeDiff.end()); - } - else childrenDiff.emplace_back(sameScopeDiff); - } - } - - // For functions, we check return type and for other future use-cases. - - json APINodeDiff = a->diff(b); - if (!APINodeDiff.empty()) { - if(APINodeDiff.is_array()){ - childrenDiff.insert(childrenDiff.end(), APINodeDiff.begin(), APINodeDiff.end()); - } - else childrenDiff.emplace_back(APINodeDiff); - } - - if(!childrenDiff.empty()){ - json diff; - diff[QUALIFIED_NAME] = a->qualifiedName; - diff[NODE_TYPE] = serialize(a->kind); - if(!childrenDiff.empty()) diff[CHILDREN] = childrenDiff; - diff[TAG] = MODIFIED; - return json::array().emplace_back(diff); - } - - } - else return a->diff(b); - - return json::array(); - -} +} // namespace json diffTrees( - const alpha::ASTNormalizedContext* context1, - const alpha::ASTNormalizedContext* context2 -) { - - json astDiffs = json::array(); - llvm::StringMap> tree1 = context1->getTree(); - llvm::StringMap> tree2 = context2->getTree(); - - for (auto const &rootNode1 : context1->getRootNodes()) { - - if(context1->excludeNodes.count(rootNode1->hash) || context2->excludeNodes.count(rootNode1->hash)){ - armor::info() << "Excluding : " << rootNode1->hash << "\n"; - continue; - } - - if (tree2.find(rootNode1->hash) == tree2.end()) { - astDiffs.emplace_back(get_json_from_node(rootNode1, REMOVED)); - } - else { - const std::shared_ptr rootNode2 = tree2.find(rootNode1->hash)->second; - json sameScopeDiff = diffNodes(rootNode1, rootNode2); - /* - Comparing nodes of same scope. No name conflicts for alpha::APINodes in same scope. - Here scope can be Main Header file or inside a CXXRecordDecl - */ - if (!sameScopeDiff.is_null() && !sameScopeDiff.empty()){ - if (sameScopeDiff.is_array()){ - astDiffs.insert(astDiffs.end(), sameScopeDiff.begin(), sameScopeDiff.end()); - } - else astDiffs.emplace_back(sameScopeDiff); - } - } - - } - - for (const auto & rootNode2 : context2->getRootNodes()) { - - if(context1->excludeNodes.count(rootNode2->hash) || context2->excludeNodes.count(rootNode2->hash)){ - armor::info() << "Excluding : " << rootNode2->hash << "\n"; - continue; - } - - if (tree1.find(rootNode2->hash) == tree1.end()) { - astDiffs.emplace_back(get_json_from_node(rootNode2, ADDED)); - } - } - + const armor::ASTNormalizedContext* context1, + const armor::ASTNormalizedContext* context2) +{ json report; - - report[PARSED_STATUS] = ParsedDiffStatus::FATAL_ERRORS; + + report[AST_DIFF] = {}; + report[PARSED_STATUS] = ParsedDiffStatus::FATAL_ERRORS; report[UNPARSED_STATUS] = nullptr; json headerFailures = json::array(); - + json failures1 = createHeaderResolutionFailures(context1->getSourceRangeTracker()); if (!failures1.empty()) { headerFailures.insert(headerFailures.end(), failures1.begin(), failures1.end()); } - + json failures2 = createHeaderResolutionFailures(context2->getSourceRangeTracker()); if (!failures2.empty()) { headerFailures.insert(headerFailures.end(), failures2.begin(), failures2.end()); } - + report[HEADER_RESOLUTION_FAILURES] = headerFailures; - report[AST_DIFF] = astDiffs; - + report[AST_DIFF] = json::array(); + return report; -} \ No newline at end of file +} + +} } // namespace armor::alpha diff --git a/src/alpha/src/header_processor.cpp b/src/alpha/src/header_processor.cpp index f357a44..3000d6f 100644 --- a/src/alpha/src/header_processor.cpp +++ b/src/alpha/src/header_processor.cpp @@ -1,126 +1,29 @@ // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause #include -#include #include #include -#include #include #include -#include -#include -#include #include #include "clang/Tooling/CompilationDatabase.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "comm_def.hpp" #include "node.hpp" #include "session.hpp" -#include "report_generator.hpp" -#include "report_utils.hpp" +#include "astnormalizer.hpp" #include "diffengine.hpp" #include "logger.hpp" #include "header_processor.hpp" -#include "session.hpp" +#include "header_processor_utils.hpp" -namespace fs = std::filesystem; using namespace clang; using namespace clang::tooling; using namespace llvm; -namespace { - - std::vector getClangFlags(const std::vector& includePaths, - const std::vector& macroFlags, - const LANG_OPTIONS lang) { - std::vector flags; - - const char* rawFlags; - switch (lang) { - case LANG_OPTIONS::C: - rawFlags = CLANG_FLAGS_C; - break; - case LANG_OPTIONS::CPP: - rawFlags = CLANG_FLAGS_CPP; - break; - default: - rawFlags = CLANG_FLAGS_CPP; - break; - } - - std::istringstream iss(rawFlags); - std::string flag; - while (iss >> flag) { - flags.emplace_back(std::move(flag)); - } - - // Add runtime include paths - for (const auto& path : includePaths) { - flags.emplace_back("-I" + path); - } - - // Add full macro flags directly - for (const auto& macro : macroFlags) { - flags.emplace_back(macro); - } - - return flags; - } - - - std::vector resolveInternalIncludePaths(const std::vector& internalPaths, - const std::string& workspacePath) { - - std::vector resolvedPaths; - for (const auto& path : internalPaths) { - resolvedPaths.push_back(workspacePath + "/" + path); - } - return resolvedPaths; - } - - std::vector generateIncludePaths(const std::string& projectPath, const std::string& headerPath) { - std::vector includePaths; - - // Ensure the header path starts with the project path - if (headerPath.find(projectPath) != 0) { - armor::user_error() << "Warning: Header file " << headerPath << " is not within project path " << projectPath << "\n"; - return includePaths; - } - - // Get the directory of the header file - llvm::SmallString<256> headerDir(headerPath); - llvm::sys::path::remove_filename(headerDir); - - // Start with the directory containing the header file - llvm::SmallString<256> currentPath = headerDir; - - // Add all parent directories up to and including the project path - while (llvm::StringRef(currentPath).str().length() >= projectPath.length()) { - includePaths.push_back("-I" + llvm::StringRef(currentPath).str()); - - // Move up one directory - llvm::sys::path::remove_filename(currentPath); - - // If we've reached the root directory, break - if (currentPath.empty()) { - break; - } - } - - // Make sure the project path itself is included - if (std::find(includePaths.begin(), includePaths.end(), "-I" + projectPath) == includePaths.end()) { - includePaths.push_back("-I" + projectPath); - } - - return includePaths; - } -} - +namespace armor { namespace alpha { PARSING_STATUS processHeaderPairAlpha(const std::string& project1, const std::string& file1, @@ -150,7 +53,7 @@ PARSING_STATUS processHeaderPairAlpha(const std::string& project1, // 1. Set up the Session auto compDB1 = std::make_unique(project1, Flags1); auto compDB2 = std::make_unique(project2, Flags2); - auto session = std::make_unique(); + auto session = std::make_unique(); armor::info() << "Processing File1 : " << file1 << "\n"; for (auto& x : Flags1) { @@ -158,18 +61,20 @@ PARSING_STATUS processHeaderPairAlpha(const std::string& project1, } // 2. Process the files. The session handles the tools and contexts. - PARSING_STATUS header1ParsingStatus = session->processFile(file1, std::move(compDB1)); + PARSING_STATUS header1ParsingStatus = session->processFileAlpha( + file1, std::move(compDB1), createNormalizeActionFactory(session.get(), file1)); armor::info() << "Processing File2 : " << file2 << "\n"; for (auto& x : Flags2) { armor::info() << "Clang search path : " << x << "\n"; } - PARSING_STATUS header2ParsingStatus = session->processFile(file2, std::move(compDB2)); + PARSING_STATUS header2ParsingStatus = session->processFileAlpha( + file2, std::move(compDB2), createNormalizeActionFactory(session.get(), file2)); // 3. Retrieve the results from the session - const alpha::ASTNormalizedContext* context1 = session->getContext(file1); - const alpha::ASTNormalizedContext* context2 = session->getContext(file2); + armor::ASTNormalizedContext* context1 = session->getAlphaContext(file1); + armor::ASTNormalizedContext* context2 = session->getAlphaContext(file2); PARSING_STATUS finalParsingStatus = header1ParsingStatus == header2ParsingStatus ? header1ParsingStatus : FATAL_ERRORS; @@ -181,51 +86,12 @@ PARSING_STATUS processHeaderPairAlpha(const std::string& project1, // 4. Perform the diff using the retrieved contexts nlohmann::json diffResult = diffTrees(context1, context2); - std::string headerName = std::filesystem::path(file1).filename().string(); - - std::string dumpDir = "debug_output/ast_diffs"; - std::filesystem::create_directories(dumpDir); - std::string outputFile = dumpDir + "/ast_diff_output_" + headerName + ".json"; - - try { - if (!diffResult.empty()) { - std::ofstream out(outputFile); - out << diffResult.dump(4); - out.close(); - } - } - catch (const std::exception& e) { - armor::user_error() << "Error generating AST diff: " << e.what() << "\n"; - } - - std::string reportDir = "armor_reports/html_reports"; - std::filesystem::create_directories(reportDir); - std::string htmlReportFile = reportDir + "/api_diff_report_" + headerName + ".html"; - - if (!diffResult.empty()) { - bool generate_json = (reportFormat == "json"); - std::string jsonReportFile; - if (generate_json) { - std::string jsonReportDir = "armor_reports/json_reports"; - std::filesystem::create_directories(jsonReportDir); - jsonReportFile = jsonReportDir + "/api_diff_report_" + headerName + ".json"; - } - fs::path relative_path = fs::relative(file1, project1); - std::string trimmed_path = relative_path.string(); - report_generator(outputFile, trimmed_path, htmlReportFile, jsonReportFile, ALPHA_PARSER, generate_json); - } - else { - try { - std::vector emptyData; - // generate_html_report(emptyData, htmlReportFile, BETA_PARSER); - armor::user_print() << "HTML report generated at: " << htmlReportFile << "\n"; - } catch (const std::exception& e) { - armor::user_error() << "Failed to generate HTML report: " << e.what() << "\n"; - } - } + armor::emitHeaderDiffReport(diffResult, file1, project1, reportFormat, ALPHA_PARSER); DebugConfig::getInstance().flush(); return finalParsingStatus; -} \ No newline at end of file +} + +} } // namespace armor::alpha \ No newline at end of file diff --git a/src/alpha/src/node.cpp b/src/alpha/src/node.cpp deleted file mode 100644 index 13b3abc..0000000 --- a/src/alpha/src/node.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#include "diff_utils.hpp" -#include "node.hpp" - -nlohmann::json alpha::APINode::diff(const std::shared_ptr& other) const { - nlohmann::json result, removed, added; - - // Helper to add metadata to a diff JSON node - auto appendNodeMetadata = [&](nlohmann::json& node) { - node[NODE_TYPE] = serialize(kind); - node[QUALIFIED_NAME] = qualifiedName; - }; - - // Define a lambda function to compare fields - auto compare = [&](const std::string& field, const auto &lhs, const auto &rhs, const auto &emptyValue) { - if (lhs != rhs) { - if (lhs != emptyValue) { - removed[field] = serialize(lhs); - } - if (rhs != emptyValue) { - added[field] = serialize(rhs); - } - } - }; - - // Compare fields - if(dataType != DATA_TYPE_PLACE_HOLDER && other->dataType != DATA_TYPE_PLACE_HOLDER){ - compare(DATA_TYPE, dataType, other->dataType, std::string{}); - } - compare( - STORAGE_QUALIFIER, - storage, - other->storage, - APINodeStorageClass::None - ); - compare( - INLINE, - isInclined, - other->isInclined, - false - ); - compare( - CONST_EXPR, - isConstExpr, - other->isConstExpr, - false - ); - - // If there are any changes - if (!removed.empty() || !added.empty()) { - // Helper to process removed and added changes - auto processChanges = [&](nlohmann::json& parent) { - if (!removed.empty()) { - removed[TAG] = REMOVED; - appendNodeMetadata(removed); - parent.emplace_back(std::move(removed)); - } - if (!added.empty()) { - added[TAG] = ADDED; - appendNodeMetadata(added); - parent.emplace_back(std::move(added)); - } - }; - - if (this->children == nullptr) { - nlohmann::json children = nlohmann::json::array(); - processChanges(children); - - if (!children.empty()) { - result[CHILDREN] = std::move(children); - appendNodeMetadata(result); - result[TAG] = MODIFIED; - } - } - else { - result = nlohmann::json::array(); - processChanges(result); - } - } - - return result; -} \ No newline at end of file diff --git a/src/alpha/src/preprocessor.cpp b/src/alpha/src/preprocessor.cpp index ac43833..440a5b8 100644 --- a/src/alpha/src/preprocessor.cpp +++ b/src/alpha/src/preprocessor.cpp @@ -11,39 +11,36 @@ #include #include "logger.hpp" -namespace alpha{ +namespace armor { namespace alpha { -ASTNormalizerPreprocessor::ASTNormalizerPreprocessor(clang::SourceManager* SM, ASTNormalizedContext* context) +ASTNormalizerPreprocessor::ASTNormalizerPreprocessor(clang::SourceManager* SM, armor::ASTNormalizedContext* context) : SM(SM), context(context) {} void ASTNormalizerPreprocessor::InclusionDirective( - clang::SourceLocation HashLoc, - const clang::Token &IncludeTok, - clang::StringRef FileName, - bool IsAngled, - clang::CharSourceRange FilenameRange, - const clang::FileEntry *File, - clang::StringRef SearchPath, - clang::StringRef RelativePath, - const clang::Module *Imported, - clang::SrcMgr::CharacteristicKind FileType){ - + clang::SourceLocation HashLoc, + const clang::Token &IncludeTok, + clang::StringRef FileName, + bool IsAngled, + clang::CharSourceRange FilenameRange, + const clang::FileEntry *File, + clang::StringRef SearchPath, + clang::StringRef RelativePath, + const clang::Module *Imported, + clang::SrcMgr::CharacteristicKind FileType) { + if (!HashLoc.isValid()) return; - - if(!File){ + if (!File) { if (HashLoc.isValid()) { clang::PresumedLoc PLoc = SM->getPresumedLoc(HashLoc); if (PLoc.isValid()) { - if(llvm::StringRef fileName = PLoc.getFilename(); !fileName.empty() && !RelativePath.empty()){ + if (llvm::StringRef fileName = PLoc.getFilename(); !fileName.empty() && !RelativePath.empty()) { armor::debug() << "Failed include - RelativePath: " << RelativePath << " at " << PLoc.getFilename() << "\n"; - context->getSourceRangeTracker().addFatalDirective(RelativePath,PLoc.getFilename()); + context->getSourceRangeTracker().addFatalDirective(RelativePath, PLoc.getFilename()); } } } - } - } -} \ No newline at end of file +} } // namespace armor::alpha diff --git a/src/alpha/src/session.cpp b/src/alpha/src/session.cpp deleted file mode 100644 index ee6256e..0000000 --- a/src/alpha/src/session.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#include -#include -#include -#include - -#include "clang/Tooling/CompilationDatabase.h" -#include "clang/Tooling/Tooling.h" -#include "clang/Tooling/ArgumentsAdjusters.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" - -#include "session.hpp" -#include "astnormalizer.hpp" -#include "ast_normalized_context.hpp" -#include "logger.hpp" - -void alpha::APISession::createNormalizedASTContext(const std::string& key){ - const auto pair = m_contexts.try_emplace(key, std::make_unique()); - if (!pair.second) { - throw std::runtime_error("AST context already exists for key: " + key); - } -} - -PARSING_STATUS alpha::APISession::processFile(std::string fileName, std::unique_ptr m_compDB) { - // Initialize DebugConfig2 with diagnostics log path if not already initialized - DebugConfig& debugConfig = DebugConfig::getInstance(); - - // Get the sink from DebugConfig2 (handles file creation and fallback) - llvm::raw_ostream* sink = debugConfig.getSink(); - - // Diagnostic options - static llvm::IntrusiveRefCntPtr sDiagOpts; - if (!sDiagOpts) { - sDiagOpts = llvm::IntrusiveRefCntPtr(new clang::DiagnosticOptions()); - sDiagOpts->ShowColors = 0; // cleaner logs - } - - // Now it is safe to do any logging before/after this point - createNormalizedASTContext(fileName); - - clang::tooling::ClangTool tool(*m_compDB, {fileName}); - - // Build the diagnostic consumer using the shared sink - std::unique_ptr diagPrinter = - std::make_unique(*sink, &*sDiagOpts); - - // Hand ownership of the consumer to the tool - tool.setDiagnosticConsumer(diagPrinter.release()); - - // Make logged diagnostics clean and informative - tool.appendArgumentsAdjuster( - clang::tooling::getInsertArgumentAdjuster("-fno-color-diagnostics")); - tool.appendArgumentsAdjuster( - clang::tooling::getInsertArgumentAdjuster("-fno-caret-diagnostics")); - tool.appendArgumentsAdjuster( - clang::tooling::getInsertArgumentAdjuster("-fdiagnostics-show-note-include-stack")); - tool.appendArgumentsAdjuster( - clang::tooling::getInsertArgumentAdjuster("-fdiagnostics-absolute-paths")); - - //suppress ClangTool'son stderr - tool.setPrintErrorMessage(false); - int rc = tool.run(new NormalizeActionFactory(this, fileName)); - if (rc != 0) { - armor::error() << "Error while processing " << fileName << "." << "\n"; - debugConfig.flush(); - return rc == 1 ? FATAL_ERRORS : NO_FATAL_ERRORS; - } - debugConfig.flush(); - - return NO_FATAL_ERRORS; - -} - -alpha::ASTNormalizedContext* alpha::APISession::getContext(const std::string& fileName) const { - auto it = m_contexts.find(fileName); - if (it != m_contexts.end()) return it->second.get(); - else { - throw std::out_of_range("AST context does not exist for file: " + fileName); - } -} - -alpha::ASTNormalizedContext* alpha::APISession::getContext(llvm::StringRef fileName) const { - auto it = m_contexts.find(fileName); - if (it != m_contexts.end()) return it->second.get(); - else { - throw std::out_of_range("AST context does not exist for file: " + fileName.str()); - } -} diff --git a/src/alpha/src/tree_builder.cpp b/src/alpha/src/tree_builder.cpp deleted file mode 100644 index 67bc812..0000000 --- a/src/alpha/src/tree_builder.cpp +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#include "tree_builder.hpp" -#include "ast_normalized_context.hpp" -#include "astnormalizer.hpp" -#include "comm_def.hpp" -#include "tree_builder_utils.hpp" -#include "iostream" -#include "node.hpp" -#include "logger.hpp" -#include "diff_utils.hpp" -#include "clang/AST/Decl.h" -#include "clang/Basic/Diagnostic.h" -#include -#include -#include - -alpha::TreeBuilder::TreeBuilder(alpha::ASTNormalizedContext* context): context(context) {} - -inline bool alpha::TreeBuilder::IsFromMainFileAndNotLocal(const clang::Decl* Decl) { - clang::ASTContext* clangContext = &Decl->getASTContext(); - return clangContext->getSourceManager().isInMainFile(Decl->getLocation()) && Decl->getParentFunctionOrMethod() == nullptr; -} - -inline void alpha::TreeBuilder::AddNode(const std::shared_ptr& node) { - - assert(!node->hash.empty()); - - if (!nodeStack.empty()) { - if (nodeStack.back()->children == nullptr) { - nodeStack.back()->children = std::make_unique, 16>>(); - } - nodeStack.back()->children->push_back(node); - } - else context->addRootNode(node); - - if (nodeStack.empty()) context->addNode(node->hash, node); -} - -inline void alpha::TreeBuilder::PushNode(const std::shared_ptr& node) { - nodeStack.push_back(node); -} - -inline void alpha::TreeBuilder::PopNode() { - if (!nodeStack.empty()) { - nodeStack.pop_back(); - } -} - -inline void alpha::TreeBuilder::PushName(llvm::StringRef name) { - qualifiedNames.push(name); -} - -inline void alpha::TreeBuilder::PopName() { - qualifiedNames.pop(); -} - -inline const std::string alpha::TreeBuilder::GetCurrentQualifiedName() { - return qualifiedNames.getAsString(); -} - -void alpha::TreeBuilder::BuildReturnTypeNode(clang::QualType type) { - auto returnNode = std::make_shared(); - returnNode->kind = NodeKind::ReturnType; - PushName("(ReturnType)"); - returnNode->dataType = type.getAsString(); - returnNode->qualifiedName = GetCurrentQualifiedName(); - returnNode->hash = generateHash(returnNode->qualifiedName, NodeKind::ReturnType); - AddNode(returnNode); - PopName(); - - armor::debug() << "BuildReturnType : " << returnNode->dataType << "\n"; -} - -void alpha::TreeBuilder::normalizeFunctionPointerType(const std::string& dataType, clang::FunctionProtoTypeLoc FTL) { - - auto functionPointerNode = std::make_shared(); - functionPointerNode->kind = NodeKind::FunctionPointer; - functionPointerNode->qualifiedName = GetCurrentQualifiedName(); - functionPointerNode->dataType = dataType; - functionPointerNode->hash = generateHash(functionPointerNode->qualifiedName, NodeKind::FunctionPointer); - - AddNode(functionPointerNode); - PushNode(functionPointerNode); - - const size_t numParams = FTL.getNumParams(); - for (unsigned int pos=0 ; pos < numParams ; ++pos) { - normalizeValueDeclNode(FTL.getParam(pos),pos); - } - - BuildReturnTypeNode(FTL.getReturnLoc().getType()); - PopNode(); -} - -void alpha::TreeBuilder::normalizeValueDeclNode(const clang::ValueDecl *Decl, unsigned int pos) { - - auto ValueNode = std::make_shared(); - clang::QualType unDecayedDeclType; - clang::TypeSourceInfo *TSI = nullptr; - llvm::SmallString<128> nameBuf; - llvm::raw_svector_ostream OS(nameBuf); - - if (const auto *paramDecl = llvm::dyn_cast_or_null(Decl)) { - ValueNode->kind = NodeKind::Parameter; - unDecayedDeclType = paramDecl->getOriginalType(); - TSI = paramDecl->getTypeSourceInfo(); - assert(pos != -1); - pos++; - PushName(std::to_string(pos)); - } - else if (const auto *fieldDecl = llvm::dyn_cast_or_null(Decl)) { - ValueNode->kind = NodeKind::Field; - unDecayedDeclType = fieldDecl->getType(); - TSI = fieldDecl->getTypeSourceInfo(); - Decl->printName(OS); - PushName(nameBuf); - } - else if (const auto *varDecl = llvm::dyn_cast_or_null(Decl)) { - ValueNode->kind = varDecl->isCXXClassMember() ? NodeKind::Field : NodeKind::Variable; - ValueNode->storage = getStorageClass(varDecl->getStorageClass()); - ValueNode->isInclined = varDecl->isInlineSpecified(); - ValueNode->isConstExpr = varDecl->isConstexpr(); - unDecayedDeclType = varDecl->getType(); - TSI = varDecl->getTypeSourceInfo(); - Decl->printName(OS); - PushName(nameBuf); - } - else return; - - const std::string dataType = Decl->isInvalidDecl() ? DATA_TYPE_PLACE_HOLDER : unDecayedDeclType.getAsString(); - ValueNode->qualifiedName = GetCurrentQualifiedName(); - ValueNode->hash = generateHash(ValueNode->qualifiedName, ValueNode->kind); - - if (llvm::isa(Decl)) { - armor::debug() << "VisitParamDecl : " << ValueNode->qualifiedName << "\n"; - } - else if (llvm::isa(Decl)) { - armor::debug() << "VisitFieldDecl : " << ValueNode->qualifiedName << "\n"; - } - else if (llvm::isa(Decl)) { - armor::debug() << "VisitVarDecl : " << ValueNode->qualifiedName << "\n"; - } - - AddNode(ValueNode); - - if (TSI) { - auto [typeModifiers, unwrappedTL] = unwrapTypeLoc(TSI->getTypeLoc()); - if (const clang::FunctionProtoTypeLoc FTL = unwrappedTL.getAs()) { - PushNode(ValueNode); - normalizeFunctionPointerType(typeModifiers, FTL); - PopNode(); - } - else ValueNode->dataType = dataType; - } - - PopName(); -} - -bool alpha::TreeBuilder::BuildRecordNode(clang::RecordDecl* Decl) { - - // Building RecordDecl for C specifaically - if (llvm::isa(Decl)) return true; - - llvm::SmallString<128> nameBuf; - llvm::raw_svector_ostream OS(nameBuf); - Decl->printName(OS); - - if (!IsFromMainFileAndNotLocal(Decl) || !Decl->isThisDeclarationADefinition() || nameBuf.empty()) { - return false; - } - - if (Decl->getTypedefNameForAnonDecl()) { - return false; - } else { - if (Decl->hasNameForLinkage()) { - PushName(nameBuf); - } - } - - const std::string qualifiedName = GetCurrentQualifiedName(); - auto recordNode = std::make_shared(); - - recordNode->qualifiedName = qualifiedName; - - armor::debug() << "VisitRecordDecl (C): " << qualifiedName << "\n"; - - if (Decl->isStruct()) { - recordNode->kind = NodeKind::Struct; - recordNode->hash = generateHash(qualifiedName, NodeKind::Struct); - } else if (Decl->isUnion()) { - recordNode->kind = NodeKind::Union; - recordNode->hash = generateHash(qualifiedName, NodeKind::Union); - } - - AddNode(recordNode); - PushNode(recordNode); - - return true; -} - -bool alpha::TreeBuilder::BuildCXXRecordNode(clang::CXXRecordDecl* Decl) { - - llvm::SmallString<128> nameBuf; - llvm::raw_svector_ostream OS(nameBuf); - Decl->printName(OS); - - if (!IsFromMainFileAndNotLocal(Decl) || Decl->isClass() || Decl->isTemplateDecl() || !Decl->isThisDeclarationADefinition() - || llvm::isa(Decl) || nameBuf.empty()) return false; - - if (Decl->getTypedefNameForAnonDecl()) { - return false; - } - else{ - if(Decl->hasNameForLinkage()){ - PushName(nameBuf); - } - } - - const std::string qualifiedName = GetCurrentQualifiedName(); - auto cxxRecordNode = std::make_shared(); - - cxxRecordNode->qualifiedName = qualifiedName; - - armor::debug() << "VisitCxxRecordDecl : " << qualifiedName << "\n"; - - if( Decl->isStruct() ){ - cxxRecordNode->kind = NodeKind::Struct; - cxxRecordNode->hash = generateHash(qualifiedName, NodeKind::Struct); - } - else if (Decl->isUnion()) { - cxxRecordNode->kind = NodeKind::Union; - cxxRecordNode->hash = generateHash(qualifiedName, NodeKind::Union); - } - - AddNode(cxxRecordNode); - PushNode(cxxRecordNode); - - return true; -} - -bool alpha::TreeBuilder::BuildEnumNode(clang::EnumDecl* Decl){ - - llvm::SmallString<128> nameBuf; - llvm::raw_svector_ostream OS(nameBuf); - Decl->printName(OS); - - if (!IsFromMainFileAndNotLocal(Decl) || Decl->isClass() || Decl->isTemplated() || nameBuf.empty()) return false; - - if (const clang::CXXRecordDecl* recordDecl = llvm::dyn_cast_or_null( - Decl->getParent()); recordDecl && recordDecl->isClass()) { - return false; - } - - bool isAnonymousEnumFieldVar = false; - - if (Decl->getIdentifier() == nullptr) { - if (clang::Decl *Next = Decl->getNextDeclInContext()) { - if (const clang::FieldDecl *fieldDecl = clang::dyn_cast_or_null(Next)) { - if (auto *ET = fieldDecl->getType()->getAs()) { - if (ET->getDecl() == Decl) isAnonymousEnumFieldVar = true; - } - } - else if (const clang::VarDecl *varDecl = clang::dyn_cast_or_null(Next)) { - if (auto *ET = varDecl->getType()->getAs()) { - if (ET->getDecl() == Decl) isAnonymousEnumFieldVar = true; - } - } - } - } - - if(isAnonymousEnumFieldVar) return false; - - auto enumNode = std::make_shared(); - - if (Decl->getTypedefNameForAnonDecl()) return false; - else{ - if( nameBuf.empty() ) return false; - PushName(nameBuf); - enumNode->qualifiedName = GetCurrentQualifiedName(); - } - - armor::debug() << "VisitEnumDecl: " << enumNode->qualifiedName << "\n"; - - enumNode->kind = NodeKind::Enum; - enumNode->hash = generateHash(enumNode->qualifiedName, NodeKind::Enum); - - if(!Decl->enumerators().empty()) nodeStack.push_back(enumNode); - - const clang::QualType enumType = Decl->getIntegerType(); - std::string enumaratorDataType = Decl->isInvalidDecl() ? DATA_TYPE_PLACE_HOLDER : enumType.getAsString(); - - for (const auto* EnumConstDecl : Decl->enumerators()) { - auto enumValNode = std::make_shared(); - PushName(EnumConstDecl->getName()); - enumValNode->qualifiedName = GetCurrentQualifiedName(); - enumValNode->hash = generateHash(enumValNode->qualifiedName, NodeKind::Enumerator); - enumValNode->dataType = enumaratorDataType; - PopName(); - enumValNode->kind = NodeKind::Enumerator; - AddNode(enumValNode); - } - - if(!Decl->enumerators().empty()) PopNode(); - - PopName(); - AddNode(enumNode); - - return true; -} - - -bool alpha::TreeBuilder::BuildFunctionNode(clang::FunctionDecl* Decl){ - - if (!IsFromMainFileAndNotLocal(Decl) || Decl->isTemplated()) return false; - - if (const clang::CXXRecordDecl* recordDecl = llvm::dyn_cast_or_null( - Decl->getParent()); recordDecl && recordDecl->isClass()) { - return false; - } - - llvm::SmallString<128> nameBuf; - llvm::raw_svector_ostream OS(nameBuf); - - auto functionNode = std::make_shared(); - Decl->printName(OS); - PushName(nameBuf); - std::string qualifiedName = GetCurrentQualifiedName(); - std::string hash = generateHash(qualifiedName, NodeKind::Function); - - if(context->hashSet.contains(hash)){ - context->excludeNodes.insert(hash); - armor::debug() << "Excluding Function Overloads : " << qualifiedName << "\n"; - PopName(); - return true; - } - - functionNode->qualifiedName = qualifiedName; - functionNode->kind = NodeKind::Function; - functionNode->hash = hash; - functionNode->storage = getStorageClass(Decl->getStorageClass()); - functionNode->isInclined = Decl->isInlined(); - - armor::debug() << "VisitFunctionDecl : " << functionNode->qualifiedName << "\n"; - context->hashSet.try_emplace(hash); - - AddNode(functionNode); - PushNode(functionNode); - - const size_t numParams = Decl->param_size(); - for (unsigned int pos = 0; pos < numParams ; ++pos) { - normalizeValueDeclNode(Decl->getParamDecl(pos), pos); - } - - BuildReturnTypeNode(Decl->getReturnType()); - - PopName(); - PopNode(); - - return true; -} - - -bool alpha::TreeBuilder::BuildTypedefDecl(clang::TypedefDecl *Decl) { - if(!IsFromMainFileAndNotLocal(Decl) || Decl->isTemplated()) return false; - - const clang::QualType underlyingType = Decl->getUnderlyingType(); - const clang::Type *typePtr = underlyingType.getTypePtr(); - - llvm::SmallString<128> nameBuf; - llvm::raw_svector_ostream OS(nameBuf); - - if (const clang::TagDecl *tagDecl = unwrapType(underlyingType)->getAsTagDecl()) { - if (tagDecl->isEmbeddedInDeclarator()) { - if (const clang::Decl * nextDecl = tagDecl->getNextDeclInContext()) { - if(!nextDecl->isInvalidDecl()){ - const clang::TagDecl* nextTagDecl = nullptr; - - switch (nextDecl->getKind()) { - case clang::Decl::Var: - if (const clang::VarDecl* varDecl = llvm::dyn_cast_or_null(nextDecl)) - nextTagDecl = unwrapType(varDecl->getType())->getAsTagDecl(); - break; - - case clang::Decl::Field: - if (const clang::FieldDecl* fieldDecl = llvm::dyn_cast_or_null(nextDecl)) - nextTagDecl = unwrapType(fieldDecl->getType())->getAsTagDecl(); - break; - default: break; - } - - if (nextTagDecl == tagDecl) return false; - } - } - - tagDecl->printName(OS); - PushName(nameBuf); - - NodeKind kind; - - if(tagDecl->isStruct()){ - kind = NodeKind::Struct; - } - else if(tagDecl->isUnion()){ - kind = NodeKind::Union; - } - else if(tagDecl->isEnum()){ - kind = NodeKind::Enum; - } - else{ - kind = NodeKind::Class; - } - - std::string hash = generateHash(GetCurrentQualifiedName(), kind); - - context->excludeNodes.try_emplace(hash); - PopName(); - } - } - else if (Decl->getTypeSourceInfo()) { - auto [_, unwrappedTL] = unwrapTypeLoc(Decl->getTypeSourceInfo()->getTypeLoc()); - if (unwrappedTL.getAs()) { - Decl->printName(OS); - PushName(nameBuf); - std::string hash = generateHash(GetCurrentQualifiedName(), NodeKind::Typedef); - context->excludeNodes.try_emplace(hash); - PopName(); - } - } - - return false; - -} - -bool alpha::TreeBuilder::BuildVarDecl(clang::VarDecl *Decl) { - if (!IsFromMainFileAndNotLocal(Decl) || !Decl->hasGlobalStorage() || Decl->isInvalidDecl() || Decl->isTemplated()) return false; - - if(llvm::isa(Decl) || llvm::isa(Decl) - || llvm::isa(Decl)) return true; - - if(const clang::TagDecl* tagDecl = unwrapType(Decl->getType())->getAsTagDecl()){ - if(IsFromMainFileAndNotLocal(tagDecl) && !tagDecl->hasNameForLinkage()) return false; - } - - normalizeValueDeclNode(Decl); - return true; -} - -bool alpha::TreeBuilder::BuildFieldDecl(clang::FieldDecl *Decl) { - if (!IsFromMainFileAndNotLocal(Decl) || Decl->isTemplated()) return false; - - if(const clang::TagDecl* tagDecl = unwrapType(Decl->getType())->getAsTagDecl()){ - if(IsFromMainFileAndNotLocal(tagDecl) && !tagDecl->hasNameForLinkage()) return false; - } - - normalizeValueDeclNode(Decl); - return true; -} \ No newline at end of file diff --git a/src/armor/CMakeLists.txt b/src/armor/CMakeLists.txt index 88cd016..fb767ba 100644 --- a/src/armor/CMakeLists.txt +++ b/src/armor/CMakeLists.txt @@ -25,6 +25,7 @@ target_link_libraries(armor ${LLVM_LIBS} clangTooling clangIndex + clangFrontend nlohmann_json::nlohmann_json CLI11::CLI11 ) diff --git a/src/armor/include/options_handler.hpp b/src/armor/include/options_handler.hpp index 9de311f..3691aae 100644 --- a/src/armor/include/options_handler.hpp +++ b/src/armor/include/options_handler.hpp @@ -3,8 +3,6 @@ #ifndef OPTIONS_HANDLER_HPP #define OPTIONS_HANDLER_HPP -#include - bool runArmorTool(int argc, const char **argv); #endif diff --git a/src/armor/src/options_handler.cpp b/src/armor/src/options_handler.cpp index 3800b61..9d43124 100644 --- a/src/armor/src/options_handler.cpp +++ b/src/armor/src/options_handler.cpp @@ -14,7 +14,7 @@ #include "git_utils.hpp" #include -#include +#include "session.hpp" #include "alpha/include/header_processor.hpp" #include "beta/include/header_processor.hpp" @@ -31,7 +31,7 @@ LANG_OPTIONS stringToLangOption(const std::string& lang) { std::string lowerLang = lang; std::transform(lowerLang.begin(), lowerLang.end(), lowerLang.begin(), [](unsigned char c){ return std::tolower(c); }); - + if (lowerLang == LANG_C) { return LANG_OPTIONS::C; } else if (lowerLang == LANG_CPP) { @@ -270,7 +270,7 @@ bool runArmorTool(int argc, const char **argv) { } // Set level and announce (now goes to the file) - + DebugConfig& debugConfig = DebugConfig::getInstance(); debugConfig.initialize(); @@ -326,7 +326,7 @@ bool runArmorTool(int argc, const char **argv) { if (!headerSubDir.empty()) { file1 = projectRoot1 + "/" + headerSubDir + "/" + header; file2 = projectRoot2 + "/" + headerSubDir + "/" + header; - } + } else { file1 = projectRoot1 + "/" + header; file2 = projectRoot2 + "/" + header; @@ -361,7 +361,7 @@ bool runArmorTool(int argc, const char **argv) { "Missing header in older version", {false, true} ); - } + } else if (!std::filesystem::exists(file2)) { armor::user_error() << "Missing header in newer version: " << file2 << "\n"; std::string headerName = std::filesystem::path(file1).filename().string(); @@ -389,12 +389,12 @@ bool runArmorTool(int argc, const char **argv) { } else{ if (filesAreDifferentUsingDiff(file1, file2)) { - PARSING_STATUS parsingStatus = processHeaderPairAlpha(projectRoot1, file1, projectRoot2, file2, reportFormat, + PARSING_STATUS parsingStatus = armor::alpha::processHeaderPairAlpha(projectRoot1, file1, projectRoot2, file2, reportFormat, IncludePaths, macros, langOption); switch (parsingStatus) { case NO_FATAL_ERRORS: armor::info() << "Processing Headers again via beta parser\n"; - processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, reportFormat, + armor::beta::processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, reportFormat, IncludePaths, macros, langOption); break; case FATAL_ERRORS: @@ -404,7 +404,7 @@ bool runArmorTool(int argc, const char **argv) { processed = true; if (gitDiff) printHeaderSummary(header); - } + } else { armor::user_print() << "No differences found between: " << file1 << " and " << file2 << "\n"; return true; @@ -479,15 +479,15 @@ bool runArmorTool(int argc, const char **argv) { "Missing header in newer version", {true, false} ); - } + } else{ if (filesAreDifferentUsingDiff(file1, file2)) { - PARSING_STATUS parsingStatus = processHeaderPairAlpha(projectRoot1, file1, projectRoot2, file2, reportFormat, + PARSING_STATUS parsingStatus = armor::alpha::processHeaderPairAlpha(projectRoot1, file1, projectRoot2, file2, reportFormat, IncludePaths, macros, langOption); switch (parsingStatus) { case NO_FATAL_ERRORS: armor::info() << "Processing Headers again via v2\n"; - processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, reportFormat, + armor::beta::processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, reportFormat, IncludePaths, macros, langOption); break; case FATAL_ERRORS: @@ -497,7 +497,7 @@ bool runArmorTool(int argc, const char **argv) { processed = true; if (gitDiff) printHeaderSummary(header); - } + } else { llvm::outs()<<"No diff beta\n"; armor::user_print() << "No differences found between: " << file1 << " and " << file2 << "\n"; diff --git a/src/beta/include/ast_normalized_context.hpp b/src/beta/include/ast_normalized_context.hpp deleted file mode 100644 index 75d86d6..0000000 --- a/src/beta/include/ast_normalized_context.hpp +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#pragma once - -#include "node.hpp" -#include "clang/AST/ASTContext.h" -#include "clang/Basic/SourceLocation.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace beta{ - -/** - * @class SourceRangeTracker - * @brief Tracks various source ranges found during AST traversal. - * - * ⚠️ IMPORTANT LIFETIME CONSTRAINT: - * SourceRange objects stored in this tracker are ONLY VALID while the - * ASTContext is alive. After AST destruction, accessing SourceRange objects - * results in undefined behavior. All processing using SourceRange objects - * must complete before the AST is destroyed. - * - * Hash values (unhandledDeclsHash, inactiveUnhandledDeclsHash) remain - * valid after AST destruction and can be safely used for comparison. - * - * This class manages collections of source ranges for different categories: - * - Comments - * - Preprocessor directives (active and inactive) - * - Unhandled declarations - * - * Each category maintains both ranges (valid during AST lifetime) and - * hash maps (valid after AST destruction) for efficient deduplication. - */ -class SourceRangeTracker { -public: - /** - * @brief Constructs an empty SourceRangeTracker. - */ - SourceRangeTracker() = default; - - /** - * @brief Returns all comment source ranges. - */ - const llvm::SmallVector& getComments() const; - - /** - * @brief Returns all inactive preprocessor directive source ranges. - */ - const std::map& getInactivePPDirectives() const; - - std::map& getInactivePPDirectives(); - - void moveInactivePPDirectives(std::map& map); - - void moveComments(llvm::SmallVector& ranges); - - /** - * @brief Moves inactive unhandled declarations hash map into the tracker. - * @param hashMap The hash map to move from. - */ - void moveInactiveUnhandledDeclsHashMap(llvm::DenseMap& hashMap); - - /** - * @brief Moves comments hash map into the tracker. - * @param hashMap The hash map to move from. - */ - void moveCommentsHashMap(llvm::DenseMap& hashMap); - - /** - * @brief Adds a hash to the unhandled declarations hash map. - * @param hash The hash value to add/increment. - */ - void addUnhandledDeclHash(uint64_t hash); - - /** - * @brief Returns all unhandled declaration hashes (mutable). - */ - llvm::DenseMap& getUnhandledDeclsHashMap(); - - /** - * @brief Returns all unhandled declaration hashes (const). - */ - const llvm::DenseMap& getUnhandledDeclsHashMap() const; - - /** - * @brief Returns all inactive unhandled declaration hashes (mutable). - */ - llvm::DenseMap& getInactiveUnhandledDeclsHashMap(); - - /** - * @brief Returns all inactive unhandled declaration hashes (const). - */ - const llvm::DenseMap& getInactiveUnhandledDeclsHashMap() const; - - /** - * @brief Returns all comments hashes (mutable). - */ - llvm::DenseMap& getCommentsHashMap(); - - /** - * @brief Returns all comments hashes (const). - */ - const llvm::DenseMap& getCommentsHashMap() const; - - /** - * @brief Clears all tracked source ranges. - */ - void clear(); - - /** - * @brief Checks if the tracker is empty. - * @return True if no source ranges are tracked. - */ - bool empty() const; - -private: - llvm::SmallVector comments; - std::map inactivePPDirectives; - - llvm::DenseMap unhandledDeclsHashMap; - llvm::DenseMap commentsHashMap; - llvm::DenseMap inactiveUnhandledDeclsHashMap; -}; - -/** - * @class ASTNormalizedContext - * @brief Manages a collection of API nodes parsed from an Abstract Syntax Tree (AST). - * - * This class serves as the central repository for all unique API nodes found during - * an AST traversal. It maintains two primary data structures: - * - * 1. A map (`apiNodesMap`) from a unique identifier (like a USR) to the - * corresponding `APINode`. This ensures that each API entity is represented by - * a single, unique object, preventing duplication. - * - * 2. A vector (`apiNodes`) of nodes that are considered top-level or - * "root" elements of the API (e.g., free functions, global variables, or - * classes in the global namespace). - */ -class ASTNormalizedContext { -public: - - /** - * @brief Constructs an empty ASTNormalizedContext. - * Reserves space for the usrNodeMap. - */ - ASTNormalizedContext(); - - /** - * @brief Adds a new node to the normalized tree. - * - * If a node with the same key already exists, it is not replaced. - * Use addOrUpdateNode if overwriting is desired. - * - * @param key The unique string identifier for the node (e.g., USR). - * @param node A shared pointer to the APINode. - */ - void addNode(llvm::StringRef key, const std::shared_ptr node); - - /** - * @brief Adds a node to the list of root API nodes. - * - * @param rootNode A const shared pointer to the APINode. - */ - void addRootNode(const std::shared_ptr rootNode); - - /** - * @brief Returns a const reference to the entire normalized tree map. - */ - const llvm::StringMap,16>>& getTree() const; - - /** - * @brief Returns a const reference to the list of root API nodes. - */ - const llvm::SmallVector,64>& getRootNodes() const; - - /** - * @brief Checks if the context contains any nodes. - * @return True if both the tree and root nodes list are empty, false otherwise. - */ - bool empty() const; - - /** - * @brief Clears all stored nodes, resetting the context to an empty state. - */ - void clear(); - - void addClangASTContext(clang::ASTContext *ASTContext); - - clang::ASTContext* getClangASTContext() const; - - /** - * @brief Returns a reference to the source range tracker (mutable). - */ - SourceRangeTracker& getSourceRangeTracker(); - - /** - * @brief Returns a const reference to the source range tracker. - */ - const SourceRangeTracker& getSourceRangeTracker() const; - - llvm::StringMap> usrNodeMap; - llvm::StringSet<> unSupportedUsrNodeMap; - -private: - llvm::StringMap,16>> apiNodesMap; - llvm::SmallVector,64> apiNodes; - - SourceRangeTracker sourceRangeTracker; - clang::ASTContext* clangContext; -}; - -} \ No newline at end of file diff --git a/src/beta/include/astnormalizer.hpp b/src/beta/include/astnormalizer.hpp index 1005fd1..51afb21 100644 --- a/src/beta/include/astnormalizer.hpp +++ b/src/beta/include/astnormalizer.hpp @@ -17,17 +17,17 @@ #include "comment_handler.hpp" #include "preprocesor.hpp" -namespace beta{ +namespace armor { namespace beta { class ASTNormalize : public clang::RecursiveASTVisitor { public: - beta::APISession* session; - ASTNormalizedContext* context; + armor::APISession* session; + armor::ASTNormalizedContext* context; clang::ASTContext *clangContext; beta::TreeBuilder treeBuilder; - ASTNormalize(beta::APISession* session, beta::ASTNormalizedContext* context, clang::ASTContext* clangContext); + ASTNormalize(armor::APISession* session, armor::ASTNormalizedContext* context, clang::ASTContext* clangContext); bool TraverseNamespaceDecl(clang::NamespaceDecl *Decl); bool TraverseRecordDecl(clang::RecordDecl *Decl); @@ -80,40 +80,42 @@ class ASTNormalize : public clang::RecursiveASTVisitor { bool VisitVarTemplateSpecializationDecl(clang::VarTemplateSpecializationDecl *Decl); bool VisitVarTemplatePartialSpecializationDecl(clang::VarTemplatePartialSpecializationDecl *Decl); bool VisitTypeAliasTemplateDecl(clang::TypeAliasTemplateDecl *Decl); - }; class ASTNormalizeConsumer : public clang::ASTConsumer { public: - beta::APISession* session; - ASTNormalizedContext* context; + armor::APISession* session; + armor::ASTNormalizedContext* context; ASTNormalize *visitor; - ASTNormalizeConsumer(beta::APISession* session, beta::ASTNormalizedContext* context); + ASTNormalizeConsumer(armor::APISession* session, armor::ASTNormalizedContext* context); void HandleTranslationUnit(clang::ASTContext &Context) override; }; class NormalizeAction : public clang::ASTFrontendAction { public: - beta::APISession* session; - ASTNormalizedContext* context; + armor::APISession* session; + armor::ASTNormalizedContext* context; beta::CommentHandler* commentHandler; - beta::ASTNormalizerPreprocessor* preprocessor; // Raw pointer, ownership transferred to Preprocessor + beta::ASTNormalizerPreprocessor* preprocessor; - NormalizeAction(beta::APISession* session, beta::ASTNormalizedContext* context); + NormalizeAction(armor::APISession* session, armor::ASTNormalizedContext* context); std::unique_ptr CreateASTConsumer(clang::CompilerInstance &, clang::StringRef) override; void EndSourceFileAction() override; private: - clang::CompilerInstance* CI; // Store CI reference for cleanup + clang::CompilerInstance* CI; }; class NormalizeActionFactory : public clang::tooling::FrontendActionFactory { public: - beta::APISession* session; + armor::APISession* session; const std::string& fileName; - explicit NormalizeActionFactory(beta::APISession* session, const std::string& fileName); + explicit NormalizeActionFactory(armor::APISession* session, const std::string& fileName); std::unique_ptr create() override; }; -} \ No newline at end of file +std::unique_ptr +createNormalizeActionFactory(armor::APISession* session, const std::string& fileName); + +} } // namespace armor::beta diff --git a/src/beta/include/comment_handler.hpp b/src/beta/include/comment_handler.hpp index ba67bdb..e2a0d93 100644 --- a/src/beta/include/comment_handler.hpp +++ b/src/beta/include/comment_handler.hpp @@ -13,15 +13,15 @@ #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" -namespace beta { +namespace armor { namespace beta { -void filterCommentsInInactiveRegions(beta::ASTNormalizedContext* context, clang::SourceManager* SM); +void filterCommentsInInactiveRegions(armor::ASTNormalizedContext* context, clang::SourceManager* SM); class CommentHandler : public clang::CommentHandler { public: - explicit CommentHandler(clang::SourceManager* SM, beta::ASTNormalizedContext* context); - + explicit CommentHandler(clang::SourceManager* SM, armor::ASTNormalizedContext* context); + bool HandleComment(clang::Preprocessor& PP, clang::SourceRange Comment) override; uint64_t generateHashFromSourceRange(clang::SourceRange Range); @@ -31,11 +31,11 @@ class CommentHandler : public clang::CommentHandler { private: - llvm::SmallVector comments; + llvm::SmallVector comments; llvm::DenseMap commentsHashMap; - + clang::SourceManager* SM; - beta::ASTNormalizedContext* context; + armor::ASTNormalizedContext* context; }; -} \ No newline at end of file +} } // namespace armor::beta \ No newline at end of file diff --git a/src/beta/include/diffengine.hpp b/src/beta/include/diffengine.hpp index c6c8823..c100dae 100644 --- a/src/beta/include/diffengine.hpp +++ b/src/beta/include/diffengine.hpp @@ -7,9 +7,11 @@ #include "ast_normalized_context.hpp" #include "comm_def.hpp" +namespace armor { namespace beta { + /** * @brief Computes the difference between two AST contexts and returns a structured JSON result. - * + * * The returned JSON has the following structure: * { * "parsed_status": , @@ -17,18 +19,20 @@ * "headerResolutionFailures": [...], * "astDiff": [...] * } - * + * * Status codes: * - UNSUPPORTED (1): At least one change is not supported * - SUPPORTED (2): All changes are supported * - COMMENTS_UPDATED (3): Only comments or whitespace/formatting were modified * - WHITESPACES_UPDATED (5): No code changes - * + * * @param context1 The first (old) AST context * @param context2 The second (new) AST context * @return nlohmann::json A structured JSON object containing diff results and status codes */ nlohmann::json diffTrees( - beta::ASTNormalizedContext* context1, - beta::ASTNormalizedContext* context2 -); \ No newline at end of file + armor::ASTNormalizedContext* context1, + armor::ASTNormalizedContext* context2 +); + +} } // namespace armor::beta \ No newline at end of file diff --git a/src/beta/include/header_processor.hpp b/src/beta/include/header_processor.hpp index 67b2f0b..67add19 100644 --- a/src/beta/include/header_processor.hpp +++ b/src/beta/include/header_processor.hpp @@ -6,6 +6,8 @@ #include #include "session.hpp" +namespace armor { namespace beta { + PARSING_STATUS processHeaderPairBeta(const std::string& projectRoot1, const std::string& file1, const std::string& projectRoot2, @@ -14,3 +16,5 @@ PARSING_STATUS processHeaderPairBeta(const std::string& projectRoot1, const std::vector& IncludePaths, const std::vector& macroFlags, const LANG_OPTIONS lang); + +} } // namespace armor::beta diff --git a/src/beta/include/preprocesor.hpp b/src/beta/include/preprocesor.hpp index 5e1a3cb..011f4fd 100644 --- a/src/beta/include/preprocesor.hpp +++ b/src/beta/include/preprocesor.hpp @@ -12,13 +12,13 @@ #include "node.hpp" #include "ast_normalized_context.hpp" -namespace beta { +namespace armor { namespace beta { class ASTNormalizerPreprocessor : public clang::PPCallbacks { public: - ASTNormalizerPreprocessor(clang::SourceManager* SM, ASTNormalizedContext* context); + ASTNormalizerPreprocessor(clang::SourceManager* SM, armor::ASTNormalizedContext* context); void InclusionDirective( clang::SourceLocation HashLoc, @@ -65,11 +65,11 @@ class ASTNormalizerPreprocessor : public clang::PPCallbacks { private: clang::SourceManager* SM; - ASTNormalizedContext* context; + armor::ASTNormalizedContext* context; // Temporary storage for preprocessing - llvm::SmallVector PPDirectives; - std::map inactivePPDirectives; + llvm::SmallVector PPDirectives; + std::map inactivePPDirectives; llvm::DenseMap inactiveUnhandledDeclsHash; uint64_t generateHashFromOffsets(unsigned startOffset, unsigned endOffset, bool isActive); @@ -78,4 +78,4 @@ class ASTNormalizerPreprocessor : public clang::PPCallbacks { void printRanges(); }; -} \ No newline at end of file +} } // namespace armor::beta \ No newline at end of file diff --git a/src/beta/include/session.hpp b/src/beta/include/session.hpp deleted file mode 100644 index 728c54e..0000000 --- a/src/beta/include/session.hpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#pragma once - -#include "ast_normalized_context.hpp" -#include "comm_def.hpp" - -#include "clang/Tooling/CompilationDatabase.h" - -// Forward declarations to avoid including heavy Clang headers here -namespace clang { namespace tooling { class CompilationDatabase; } } - -/** - * @class APISession - * @brief Manages a session for comparing multiple source files. - * - * This class orchestrates the process of parsing and normalizing ASTs from - * one or more source files. It holds: - * - * 1. A map from filenames to their corresponding `ASTNormalizedContext`. - * 2. A central string pool to unify and reduce memory usage for common strings. - * 3. A reference to the Clang Compilation Database used for parsing. - */ -namespace beta{ - -class APISession { -public: - /** - * @brief Constructs an APISession. - * @param compDB A unique_ptr to the compilation database to be used for all parsing. - * The session takes ownership of the database. - */ - /** - * @brief Processes a source file, normalizing its AST and storing the context. - * - * Runs a Clang tool on the specified file, populates an ASTNormalizedContext, - * and stores it in the session, mapped by the filename. - * - * @param filename The path to the source file to process. - */ - PARSING_STATUS processFile(std::string fileName, std::unique_ptr m_compDB); - - /** - * @brief Retrieves the normalized context for a previously processed file. - * @param filename The path to the source file. - * @return A pointer to the ASTNormalizedContext if the file was processed, - * otherwise nullptr. - */ - beta::ASTNormalizedContext* getContext(llvm::StringRef fileName) const; - - beta::ASTNormalizedContext* getContext(const std::string& fileName) const; - - - void createNormalizedASTContext(const std::string& key); - -private: - // A map from a filename to its fully normalized AST context - llvm::StringMap> m_contexts; -}; - -} \ No newline at end of file diff --git a/src/beta/include/tree_builder.hpp b/src/beta/include/tree_builder.hpp index 87faf1b..e0f78a7 100644 --- a/src/beta/include/tree_builder.hpp +++ b/src/beta/include/tree_builder.hpp @@ -19,33 +19,19 @@ #include "qualified_name_builder.hpp" #include "fibonacci_hash.hpp" -/** - * @class TreeBuilder - * @brief Builds an API node tree from Clang AST declarations. - * - * This class encapsulates all the logic for creating and organizing APINode objects - * based on Clang AST declarations. It works with an ASTNormalizedContext to store - * the resulting nodes. - */ - -namespace beta{ +namespace armor { namespace beta { class TreeBuilder { private: - beta::ASTNormalizedContext* context; + armor::ASTNormalizedContext* context; StringBuilder qualifiedName; - std::vector> nodeStack; + std::vector> nodeStack; public: - /** - * @brief Constructs a TreeBuilder with the given context. - * - * @param context The ASTNormalizedContext to store the resulting nodes. - */ - explicit TreeBuilder(beta::ASTNormalizedContext* context); + explicit TreeBuilder(armor::ASTNormalizedContext* context); // Node management - void AddNode(const std::shared_ptr& node); - void PushNode(const std::shared_ptr& node); + void AddNode(const std::shared_ptr& node); + void PushNode(const std::shared_ptr& node); void PopNode(); // Name management @@ -61,7 +47,7 @@ class TreeBuilder { bool isInTemplatedClass(const clang::Decl* Decl); bool isWrittenInTemplatedClass(const clang::Decl* TD); void processUnhandledDecl(const clang::Decl* Decl); - void processUnhandledStmt(const clang::Stmt* Stmt, const std::shared_ptr& node); + void processUnhandledStmt(const clang::Stmt* Stmt, const std::shared_ptr& node); uint64_t generateSemanticHashFromDecl(const clang::Decl* Decl); uint64_t generateSemanticHashFromStmt(const clang::Stmt* Stmt); void normalizeFunctionPointerType(std::string_view typeModifiers, clang::FunctionProtoTypeLoc FTL, const clang::NamedDecl* Decl); @@ -82,7 +68,6 @@ class TreeBuilder { void BuildFriendFunctionDecl(const clang::FunctionDecl *Decl, const clang::FriendDecl *FriendDecl); // Unsupported declaration handlers (hash-only) - // void BuildNamespaceDecl(clang::NamespaceDecl* Decl); void BuildFunctionTemplateDecl(clang::FunctionTemplateDecl* Decl); void BuildClassTemplateDecl(clang::ClassTemplateDecl* Decl); void BuildClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* Decl); @@ -96,7 +81,7 @@ class TreeBuilder { void BuildVarTemplateSpecializationDecl(clang::VarTemplateSpecializationDecl* Decl); void BuildVarTemplatePartialSpecializationDecl(clang::VarTemplatePartialSpecializationDecl* Decl); void BuildTypeAliasTemplateDecl(clang::TypeAliasTemplateDecl* Decl); - void BuildValueInitExpr(const clang::Expr* Expr, const std::shared_ptr& node); + void BuildValueInitExpr(const clang::Expr* Expr, const std::shared_ptr& node); }; -} \ No newline at end of file +} } // namespace armor::beta diff --git a/src/beta/src/ast_normalized_context.cpp b/src/beta/src/ast_normalized_context.cpp deleted file mode 100644 index b282ca2..0000000 --- a/src/beta/src/ast_normalized_context.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#include "node.hpp" -#include "ast_normalized_context.hpp" -#include -#include -#include -#include -#include - -beta::ASTNormalizedContext::ASTNormalizedContext() = default; - -void beta::ASTNormalizedContext::addNode(llvm::StringRef key, std::shared_ptr node) { - apiNodesMap[key].emplace_back(std::move(node)); -} - -void beta::ASTNormalizedContext::addRootNode(std::shared_ptr rootNode) { - if (rootNode) { - apiNodes.push_back(std::move(rootNode)); - } -} - -const llvm::StringMap,16>>& beta::ASTNormalizedContext::getTree() const { - return apiNodesMap; -} - -const llvm::SmallVector,64>& beta::ASTNormalizedContext::getRootNodes() const { - return apiNodes; -} - -bool beta::ASTNormalizedContext::empty() const { - return apiNodesMap.empty() && apiNodes.empty(); -} - -void beta::ASTNormalizedContext::clear() { - apiNodesMap.clear(); - apiNodes.clear(); - sourceRangeTracker.clear(); -} - -void beta::ASTNormalizedContext::addClangASTContext(clang::ASTContext *ASTContext){ - clangContext = ASTContext; -} - -clang::ASTContext* beta::ASTNormalizedContext::getClangASTContext() const { - return clangContext; -} - -const llvm::SmallVector& beta::SourceRangeTracker::getComments() const { - return comments; -} - -const std::map& beta::SourceRangeTracker::getInactivePPDirectives() const { - return inactivePPDirectives; -} - -std::map& beta::SourceRangeTracker::getInactivePPDirectives(){ - return inactivePPDirectives; -} - -void beta::SourceRangeTracker::moveInactivePPDirectives(std::map& ranges) { - inactivePPDirectives = std::move(ranges); -} - -void beta::SourceRangeTracker::moveComments(llvm::SmallVector &ranges){ - comments = std::move(ranges); -} - -void beta::SourceRangeTracker::moveInactiveUnhandledDeclsHashMap(llvm::DenseMap& hashMap) { - inactiveUnhandledDeclsHashMap = std::move(hashMap); -} - -void beta::SourceRangeTracker::moveCommentsHashMap(llvm::DenseMap& hashMap) { - commentsHashMap = std::move(hashMap); -} - -llvm::DenseMap& beta::SourceRangeTracker::getUnhandledDeclsHashMap() { - return unhandledDeclsHashMap; -} - -void beta::SourceRangeTracker::addUnhandledDeclHash(uint64_t hash) { - unhandledDeclsHashMap[hash]++; -} - -const llvm::DenseMap& beta::SourceRangeTracker::getUnhandledDeclsHashMap() const { - return unhandledDeclsHashMap; -} - -llvm::DenseMap& beta::SourceRangeTracker::getInactiveUnhandledDeclsHashMap() { - return inactiveUnhandledDeclsHashMap; -} - -const llvm::DenseMap& beta::SourceRangeTracker::getInactiveUnhandledDeclsHashMap() const { - return inactiveUnhandledDeclsHashMap; -} - -llvm::DenseMap& beta::SourceRangeTracker::getCommentsHashMap(){ - return commentsHashMap; -} - -const llvm::DenseMap& beta::SourceRangeTracker::getCommentsHashMap() const { - return commentsHashMap; -} - -void beta::SourceRangeTracker::clear() { - comments.clear(); - inactivePPDirectives.clear(); - unhandledDeclsHashMap.clear(); - inactiveUnhandledDeclsHashMap.clear(); -} - -bool beta::SourceRangeTracker::empty() const { - return comments.empty() && - inactivePPDirectives.empty(); -} - -beta::SourceRangeTracker& beta::ASTNormalizedContext::getSourceRangeTracker() { - return sourceRangeTracker; -} - -const beta::SourceRangeTracker& beta::ASTNormalizedContext::getSourceRangeTracker() const { - return sourceRangeTracker; -} \ No newline at end of file diff --git a/src/beta/src/astnormalizer.cpp b/src/beta/src/astnormalizer.cpp index 1f4a77a..a872e62 100644 --- a/src/beta/src/astnormalizer.cpp +++ b/src/beta/src/astnormalizer.cpp @@ -23,15 +23,17 @@ #include "clang/Basic/SourceManager.h" #include "clang/Frontend/CompilerInstance.h" +namespace armor { namespace beta { + // --- beta::ASTNormalize --- -beta::ASTNormalize::ASTNormalize(beta::APISession* session, beta::ASTNormalizedContext* context, clang::ASTContext* clangContext) +beta::ASTNormalize::ASTNormalize(armor::APISession* session, armor::ASTNormalizedContext* context, clang::ASTContext* clangContext) : session(session), context(context), clangContext(clangContext), treeBuilder(beta::TreeBuilder(context)) {} // (Implementation of visitor methods remains the same conceptually) // --- beta::ASTNormalizeConsumer --- // Constructor simply stores the pointers. -beta::ASTNormalizeConsumer::ASTNormalizeConsumer(APISession* session, beta::ASTNormalizedContext* context) +beta::ASTNormalizeConsumer::ASTNormalizeConsumer(armor::APISession* session, armor::ASTNormalizedContext* context) : session(session), context(context) {} void beta::ASTNormalizeConsumer::HandleTranslationUnit(clang::ASTContext &clangContext) { @@ -44,18 +46,18 @@ void beta::ASTNormalizeConsumer::HandleTranslationUnit(clang::ASTContext &clangC // --- NormalizeAction --- // Constructor now receives the pre-existing context pointer. -beta::NormalizeAction::NormalizeAction(APISession* session, beta::ASTNormalizedContext* context) +beta::NormalizeAction::NormalizeAction(armor::APISession* session, armor::ASTNormalizedContext* context) : session(session), context(context), commentHandler(nullptr), preprocessor(nullptr), CI(nullptr) {} std::unique_ptr beta::NormalizeAction::CreateASTConsumer(clang::CompilerInstance& CI, clang::StringRef) { // Store CI reference for cleanup this->CI = &CI; - + // Set up comment handler auto commentHandlerPtr = std::make_unique(&CI.getSourceManager(), context); commentHandler = commentHandlerPtr.get(); // Store reference before releasing CI.getPreprocessor().addCommentHandler(commentHandlerPtr.release()); - + // Set up preprocessor callbacks auto preprocessorPtr = std::make_unique(&CI.getSourceManager(), context); preprocessor = preprocessorPtr.get(); // Store reference before moving @@ -66,22 +68,27 @@ std::unique_ptr beta::NormalizeAction::CreateASTConsumer(cla } // --- NormalizeActionFactory (The "Get and Pass" Logic) --- -beta::NormalizeActionFactory::NormalizeActionFactory(APISession* session, const std::string& fileName) : session(session), fileName(fileName) {} +beta::NormalizeActionFactory::NormalizeActionFactory(armor::APISession* session, const std::string& fileName) : session(session), fileName(fileName) {} std::unique_ptr beta::NormalizeActionFactory::create() { // 2. Use the filename to get the pre-existing context from the session. - beta::ASTNormalizedContext* contextForThisFile = session->getContext(fileName); + armor::ASTNormalizedContext* contextForThisFile = session->getBetaContext(fileName); // --- Error Handling --- if (!contextForThisFile) { // This is a critical logic error. The context should have been created before processing. - throw std::runtime_error("No beta::ASTNormalizedContext was created for file: " + fileName); + throw std::runtime_error("No armor::ASTNormalizedContext was created for file: " + fileName); } // 3. Create the action, efficiently passing pointers to the session and the retrieved context. return std::make_unique(session, contextForThisFile); } +std::unique_ptr +createNormalizeActionFactory(armor::APISession* session, const std::string& fileName) { + return std::make_unique(session, fileName); +} + void beta::NormalizeAction::EndSourceFileAction() { // Finalize preprocessor callbacks (must be done before Preprocessor is destroyed) @@ -98,9 +105,9 @@ void beta::NormalizeAction::EndSourceFileAction() { delete commentHandler; // Now we can safely delete it commentHandler = nullptr; } - + filterCommentsInInactiveRegions(context, &context->getClangASTContext()->getSourceManager()); - + // Call parent implementation clang::ASTFrontendAction::EndSourceFileAction(); } @@ -133,7 +140,7 @@ bool beta::ASTNormalize::TraverseRecordDecl(clang::RecordDecl *Decl) { RecursiveASTVisitor::TraverseRecordDecl(Decl); if (!llvm::isa(Decl) && treeBuilder.IsDeclFromMainFileAndNotLocal(Decl)) { - const std::string USR = generateUSRForDecl(Decl); + const std::string USR = ::generateUSRForDecl(Decl); if( treeBuilder.isQualifiedNameOverriden(USR) ){ treeBuilder.popOverridenQualifiedName(USR); } @@ -145,11 +152,11 @@ bool beta::ASTNormalize::TraverseRecordDecl(clang::RecordDecl *Decl) { } bool beta::ASTNormalize::TraverseCXXRecordDecl(clang::CXXRecordDecl *Decl) { - + RecursiveASTVisitor::TraverseCXXRecordDecl(Decl); - if(treeBuilder.IsDeclFromMainFileAndNotLocal(Decl) && !Decl->isTemplated() + if(treeBuilder.IsDeclFromMainFileAndNotLocal(Decl) && !Decl->isTemplated() && !llvm::isa(Decl)){ - const std::string USR = generateUSRForDecl(Decl); + const std::string USR = ::generateUSRForDecl(Decl); if( treeBuilder.isQualifiedNameOverriden(USR) ){ treeBuilder.popOverridenQualifiedName(USR); } @@ -393,3 +400,5 @@ bool beta::ASTNormalize::VisitTypeAliasTemplateDecl(clang::TypeAliasTemplateDecl treeBuilder.BuildTypeAliasTemplateDecl(Decl); return true; } + +} } // namespace armor::beta diff --git a/src/beta/src/comment_handler.cpp b/src/beta/src/comment_handler.cpp index 3905f36..dd78404 100644 --- a/src/beta/src/comment_handler.cpp +++ b/src/beta/src/comment_handler.cpp @@ -10,9 +10,9 @@ #include #include -namespace beta { +namespace armor { namespace beta { -CommentHandler::CommentHandler(clang::SourceManager* SM, beta::ASTNormalizedContext* context) +CommentHandler::CommentHandler(clang::SourceManager* SM, armor::ASTNormalizedContext* context) : SM(SM), context(context) {} uint64_t CommentHandler::generateHashFromSourceRange(clang::SourceRange Range) { @@ -63,25 +63,25 @@ bool CommentHandler::HandleComment(clang::Preprocessor& PP, clang::SourceRange C uint64_t hash = generateHashFromSourceRange(Comment); unsigned startOffset = SM->getFileOffset(Comment.getBegin()); unsigned endOffset = SM->getFileOffset(Comment.getEnd()); - comments.emplace_back(beta::Range(startOffset,endOffset,hash,true)); + comments.emplace_back(armor::Range(startOffset,endOffset,hash,true)); commentsHashMap[hash]++; return false; } void CommentHandler::finalize(){ - beta::SourceRangeTracker& SRT = context->getSourceRangeTracker(); + armor::SourceRangeTracker& SRT = context->getSourceRangeTracker(); SRT.moveComments(comments); SRT.moveCommentsHashMap(commentsHashMap); } -void filterCommentsInInactiveRegions(beta::ASTNormalizedContext* context, clang::SourceManager* SM) { +void filterCommentsInInactiveRegions(armor::ASTNormalizedContext* context, clang::SourceManager* SM) { if (!context || !SM) return; auto& tracker = context->getSourceRangeTracker(); - const llvm::SmallVector& comments = tracker.getComments(); - const std::map& inactiveRegions = tracker.getInactivePPDirectives(); + const llvm::SmallVector& comments = tracker.getComments(); + const std::map& inactiveRegions = tracker.getInactivePPDirectives(); llvm::DenseMap& commentsHashMap = tracker.getCommentsHashMap(); if (inactiveRegions.empty()) return; @@ -123,4 +123,4 @@ void filterCommentsInInactiveRegions(beta::ASTNormalizedContext* context, clang: } -} \ No newline at end of file +} } // namespace armor::beta \ No newline at end of file diff --git a/src/beta/src/diffengine.cpp b/src/beta/src/diffengine.cpp index 3436823..524e02b 100644 --- a/src/beta/src/diffengine.cpp +++ b/src/beta/src/diffengine.cpp @@ -18,7 +18,9 @@ using json = nlohmann::json; -const bool inline hasChildren(const std::shared_ptr& node) { +namespace armor { namespace beta { + +const bool inline hasChildren(const std::shared_ptr& node) { return node->children == nullptr ? false : !node->children->empty(); } @@ -38,7 +40,7 @@ namespace{ } #endif - const json toJson(const std::shared_ptr& node) { + const json toJson(const std::shared_ptr& node) { json json_node; @@ -57,14 +59,14 @@ namespace{ return json_node; } - const json get_json_from_node(const std::shared_ptr node, const std::string& tag) { + const json get_json_from_node(const std::shared_ptr node, const std::string& tag) { json json_node = toJson(node); json_node[TAG] = tag; return json_node; } - void reconcileUnhandledDeclHashes(beta::ASTNormalizedContext* context, const std::shared_ptr& node){ - beta::SourceRangeTracker& tracker = context->getSourceRangeTracker(); + void reconcileUnhandledDeclHashes(armor::ASTNormalizedContext* context, const std::shared_ptr& node){ + armor::SourceRangeTracker& tracker = context->getSourceRangeTracker(); llvm::DenseMap& unhandledDeclsHashMap = tracker.getUnhandledDeclsHashMap(); if(node->stmtHashes.size()) TEST_LOG << "reconcileUnhandledDeclHashes\n" << node->qualifiedName << "\n"; for(uint64_t stmtHash : node->stmtHashes ){ @@ -116,10 +118,10 @@ namespace{ } json diffNodes( - beta::ASTNormalizedContext* contextA, - beta::ASTNormalizedContext* contextB, - const std::shared_ptr& a, - const std::shared_ptr& b) // we are not using the map for now. + armor::ASTNormalizedContext* contextA, + armor::ASTNormalizedContext* contextB, + const std::shared_ptr& a, + const std::shared_ptr& b) // we are not using the map for now. { // Any node can have children. @@ -129,10 +131,10 @@ json diffNodes( json childrenDiff = json::array(); // Create StringMaps for a->children and b->children - llvm::StringMap,16>> aNSRMap; - llvm::StringMap,16>> bNSRMap; - llvm::StringMap> aUSRMap; - llvm::StringMap> bUSRMap; + llvm::StringMap,16>> aNSRMap; + llvm::StringMap,16>> bNSRMap; + llvm::StringMap> aUSRMap; + llvm::StringMap> bUSRMap; // Populate maps for (const auto& childNode : *a->children) { @@ -163,7 +165,7 @@ json diffNodes( key = childNodeA->USR; auto usrIt = bUSRMap.find(key); if (usrIt != bUSRMap.end()) { - const std::shared_ptr childNodeB = usrIt->second; + const std::shared_ptr childNodeB = usrIt->second; json sameScopeDiff = diffNodes(contextA, contextB,childNodeA, childNodeB); if (!sameScopeDiff.is_null() && !sameScopeDiff.empty()) { if (sameScopeDiff.is_array()) { @@ -180,7 +182,7 @@ json diffNodes( } else { assert(countA+countB == 2); - const std::shared_ptr childNodeB = it->second[0]; + const std::shared_ptr childNodeB = it->second[0]; json sameScopeDiff = diffNodes(contextA, contextB,childNodeA, childNodeB); if (!sameScopeDiff.is_null() && !sameScopeDiff.empty()) { if (sameScopeDiff.is_array()) { @@ -282,13 +284,13 @@ json diffNodes( json diffTrees( - beta::ASTNormalizedContext* context1, - beta::ASTNormalizedContext* context2 + armor::ASTNormalizedContext* context1, + armor::ASTNormalizedContext* context2 ) { json astDiff = json::array(); - llvm::StringMap,16>> tree1 = context1->getTree(); - llvm::StringMap,16>> tree2 = context2->getTree(); + llvm::StringMap,16>> tree1 = context1->getTree(); + llvm::StringMap,16>> tree2 = context2->getTree(); for (auto const &rootNode1 : context1->getRootNodes()) { @@ -306,7 +308,7 @@ json diffTrees( key = rootNode1->USR; auto usrIt = context2->usrNodeMap.find(key); if (usrIt != context2->usrNodeMap.end()) { - const std::shared_ptr rootNode2 = usrIt->second; + const std::shared_ptr rootNode2 = usrIt->second; json sameScopeDiff = diffNodes(context1, context2, rootNode1, rootNode2); if (!sameScopeDiff.is_null() && !sameScopeDiff.empty()){ if (sameScopeDiff.is_array()){ @@ -319,7 +321,7 @@ json diffTrees( } else { assert(count1+count2 == 2); - const std::shared_ptr rootNode2 = it->second[0]; + const std::shared_ptr rootNode2 = it->second[0]; json sameScopeDiff = diffNodes(context1, context2, rootNode1, rootNode2); if (!sameScopeDiff.is_null() && !sameScopeDiff.empty()){ if (sameScopeDiff.is_array()){ @@ -356,8 +358,8 @@ json diffTrees( } } - const beta::SourceRangeTracker& tracker1 = context1->getSourceRangeTracker(); - const beta::SourceRangeTracker& tracker2 = context2->getSourceRangeTracker(); + const armor::SourceRangeTracker& tracker1 = context1->getSourceRangeTracker(); + const armor::SourceRangeTracker& tracker2 = context2->getSourceRangeTracker(); const llvm::DenseMap& commentsHashMap1 = tracker1.getCommentsHashMap(); const llvm::DenseMap& commentsHashMap2 = tracker2.getCommentsHashMap(); @@ -401,4 +403,6 @@ json diffTrees( result[AST_DIFF] = astDiff; return result; -} \ No newline at end of file +} + +} } // namespace armor::beta \ No newline at end of file diff --git a/src/beta/src/header_processor.cpp b/src/beta/src/header_processor.cpp index bd94032..7baa5db 100644 --- a/src/beta/src/header_processor.cpp +++ b/src/beta/src/header_processor.cpp @@ -1,124 +1,28 @@ // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause -#include #include -#include #include #include -#include #include #include -#include -#include -#include #include #include "clang/Tooling/CompilationDatabase.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "comm_def.hpp" -#include "report_generator.hpp" -#include "report_utils.hpp" #include "diffengine.hpp" #include "logger.hpp" #include "header_processor.hpp" +#include "header_processor_utils.hpp" #include "session.hpp" +#include "astnormalizer.hpp" -namespace fs = std::filesystem; using namespace clang; using namespace clang::tooling; using namespace llvm; -namespace { - - std::vector getClangFlags(const std::vector& includePaths, - const std::vector& macroFlags, - const LANG_OPTIONS lang) { - std::vector flags; - - const char* rawFlags; - switch (lang) { - case LANG_OPTIONS::C: - rawFlags = CLANG_FLAGS_C; - break; - case LANG_OPTIONS::CPP: - rawFlags = CLANG_FLAGS_CPP; - break; - default: - rawFlags = CLANG_FLAGS_CPP; - break; - } - - std::istringstream iss(rawFlags); - std::string flag; - while (iss >> flag) { - flags.emplace_back(std::move(flag)); - } - - // Add runtime include paths - for (const auto& path : includePaths) { - flags.emplace_back("-I" + path); - } - - // Add full macro flags directly - for (const auto& macro : macroFlags) { - flags.emplace_back(macro); - } - - return flags; - } - - - std::vector resolveInternalIncludePaths(const std::vector& internalPaths, - const std::string& workspacePath) { - - std::vector resolvedPaths; - for (const auto& path : internalPaths) { - resolvedPaths.push_back(workspacePath + "/" + path); - } - return resolvedPaths; - } - - std::vector generateIncludePaths(const std::string& projectPath, const std::string& headerPath) { - std::vector includePaths; - - // Ensure the header path starts with the project path - if (headerPath.find(projectPath) != 0) { - armor::user_error() << "Warning: Header file " << headerPath << " is not within project path " << projectPath << "\n"; - return includePaths; - } - - // Get the directory of the header file - llvm::SmallString<256> headerDir(headerPath); - llvm::sys::path::remove_filename(headerDir); - - // Start with the directory containing the header file - llvm::SmallString<256> currentPath = headerDir; - - // Add all parent directories up to and including the project path - while (llvm::StringRef(currentPath).str().length() >= projectPath.length()) { - includePaths.push_back("-I" + llvm::StringRef(currentPath).str()); - - // Move up one directory - llvm::sys::path::remove_filename(currentPath); - - // If we've reached the root directory, break - if (currentPath.empty()) { - break; - } - } - - // Make sure the project path itself is included - if (std::find(includePaths.begin(), includePaths.end(), "-I" + projectPath) == includePaths.end()) { - includePaths.push_back("-I" + projectPath); - } - - return includePaths; - } -} +namespace armor { namespace beta { PARSING_STATUS processHeaderPairBeta(const std::string& project1, const std::string& file1, @@ -148,9 +52,7 @@ PARSING_STATUS processHeaderPairBeta(const std::string& project1, // 1. Set up the Session auto compDB1 = std::make_unique(project1, Flags1); auto compDB2 = std::make_unique(project2, Flags2); - auto session = std::make_unique(); - - std::string headerName = std::filesystem::path(file1).filename().c_str(); + auto session = std::make_unique(); armor::info() << "Processing File1 : " << file1 << "\n"; for (auto& x : Flags1) { @@ -158,18 +60,20 @@ PARSING_STATUS processHeaderPairBeta(const std::string& project1, } // 2. Process the files. The session handles the tools and contexts. - PARSING_STATUS header1ParsingStatus = session->processFile(file1, std::move(compDB1)); + PARSING_STATUS header1ParsingStatus = session->processFileBeta( + file1, std::move(compDB1), createNormalizeActionFactory(session.get(), file1)); armor::info() << "Processing File2 : " << file2 << "\n"; for (auto& x : Flags2) { armor::info() << "Clang search path : " << x << "\n"; } - PARSING_STATUS header2ParsingStatus = session->processFile(file2, std::move(compDB2)); + PARSING_STATUS header2ParsingStatus = session->processFileBeta( + file2, std::move(compDB2), createNormalizeActionFactory(session.get(), file2)); // 3. Retrieve the results from the session - beta::ASTNormalizedContext* context1 = session->getContext(file1); - beta::ASTNormalizedContext* context2 = session->getContext(file2); + armor::ASTNormalizedContext* context1 = session->getBetaContext(file1); + armor::ASTNormalizedContext* context2 = session->getBetaContext(file2); if (!context1 || !context2) { armor::user_error() << "Failed to retrieve processing results from session\n"; @@ -177,56 +81,14 @@ PARSING_STATUS processHeaderPairBeta(const std::string& project1, } // 4. Perform the diff using the retrieved contexts - nlohmann::json diffResult; - - diffResult = diffTrees( - context1, - context2 - ); - - std::string dumpDir = "debug_output/ast_diffs"; - std::filesystem::create_directories(dumpDir); - std::string outputFile = dumpDir + "/ast_diff_output_" + headerName + ".json"; - - try { - if (!diffResult.empty()) { - std::ofstream out(outputFile,std::ios::trunc); - out << diffResult.dump(4); - out.close(); - } - } catch (const std::exception& e) { - armor::user_error() << "Error generating AST diff: " << e.what() << "\n"; - } + nlohmann::json diffResult = diffTrees(context1, context2); - std::string reportDir = "armor_reports/html_reports"; - std::filesystem::create_directories(reportDir); - std::string htmlReportFile = reportDir + "/api_diff_report_" + headerName + ".html"; - - if (!diffResult.empty()) { - bool generate_json = (reportFormat == "json"); - std::string jsonReportFile; - if (generate_json) { - std::string jsonReportDir = "armor_reports/json_reports"; - std::filesystem::create_directories(jsonReportDir); - jsonReportFile = jsonReportDir + "/api_diff_report_" + headerName + ".json"; - } - fs::path relative_path = fs::relative(file1, project1); - std::string trimmed_path = relative_path.string(); - report_generator(outputFile, trimmed_path, htmlReportFile, jsonReportFile, BETA_PARSER, generate_json); - } - else { - try { - std::vector emptyData; - // generate_html_report(emptyData, htmlReportFile, BETA_PARSER); - armor::user_print() << "HTML report generated at: " << htmlReportFile << "\n"; - } - catch (const std::exception& e) { - armor::user_error() << "Failed to generate HTML report: " << e.what() << "\n"; - } - } + armor::emitHeaderDiffReport(diffResult, file1, project1, reportFormat, BETA_PARSER); DebugConfig::getInstance().flush(); return header1ParsingStatus == header2ParsingStatus ? header1ParsingStatus : FATAL_ERRORS; } + +} } // namespace armor::beta diff --git a/src/beta/src/preprocessor.cpp b/src/beta/src/preprocessor.cpp index 63306aa..9a23058 100644 --- a/src/beta/src/preprocessor.cpp +++ b/src/beta/src/preprocessor.cpp @@ -19,7 +19,7 @@ #include #include "logger.hpp" -namespace beta{ +namespace armor { namespace beta { inline bool isLocationInMainFile(clang::SourceManager* SM, clang::SourceLocation Loc) { if (!Loc.isValid()) return false; @@ -63,17 +63,17 @@ inline bool isBuiltinOrPredefinedInclude(clang::SourceManager* SM, clang::Source return false; } -ASTNormalizerPreprocessor::ASTNormalizerPreprocessor(clang::SourceManager* SM, ASTNormalizedContext* context) +ASTNormalizerPreprocessor::ASTNormalizerPreprocessor(clang::SourceManager* SM, armor::ASTNormalizedContext* context) : SM(SM), context(context) {} void ASTNormalizerPreprocessor::finalize(){ removeNestedRanges(); - beta::SourceRangeTracker& SRT = context->getSourceRangeTracker(); + armor::SourceRangeTracker& SRT = context->getSourceRangeTracker(); llvm::StringRef buffer = SM->getBufferData(SM->getMainFileID()); - for(beta::Range& R : PPDirectives){ + for(armor::Range& R : PPDirectives){ uint64_t hash = generateHashFromOffsets(R.startOffset, R.endOffset,R.isActive); if(hash != 0) { R.hash = hash; @@ -123,13 +123,13 @@ void ASTNormalizerPreprocessor::addRange(clang::SourceRange range, bool active) range.getEnd(), 0, *SM, clang::LangOptions()); unsigned endOffset = SM->getFileOffset(endLoc); - PPDirectives.emplace_back(beta::Range(startOffset, endOffset, -1, active)); + PPDirectives.emplace_back(armor::Range(startOffset, endOffset, -1, active)); } void ASTNormalizerPreprocessor::removeNestedRanges() { if (PPDirectives.size() <= 1) return; - llvm::SmallVector filteredRanges; + llvm::SmallVector filteredRanges; size_t size = PPDirectives.size(); unsigned refStartOffset = PPDirectives[size-1].startOffset; @@ -147,7 +147,7 @@ void ASTNormalizerPreprocessor::removeNestedRanges() { continue; } else if (currentStart < refStartOffset && (currentEnd <= refStartOffset || refStartOffset < currentEnd)) { - filteredRanges.emplace_back(beta::Range(refStartOffset, refEndOffset,-1,refStatus)); + filteredRanges.emplace_back(armor::Range(refStartOffset, refEndOffset,-1,refStatus)); refStatus = currentStatus; refStartOffset = currentStart; refEndOffset = currentEnd; @@ -162,7 +162,7 @@ void ASTNormalizerPreprocessor::removeNestedRanges() { } filteredRanges.emplace_back( - beta::Range( + armor::Range( refStartOffset, refEndOffset , -1, @@ -427,4 +427,4 @@ void ASTNormalizerPreprocessor::SourceRangeSkipped(clang::SourceRange Range, cla } -} \ No newline at end of file +} } // namespace armor::beta \ No newline at end of file diff --git a/src/beta/src/session.cpp b/src/beta/src/session.cpp deleted file mode 100644 index 48bf9ff..0000000 --- a/src/beta/src/session.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#include -#include -#include -#include - -#include "clang/Tooling/CompilationDatabase.h" -#include "clang/Tooling/Tooling.h" -#include "clang/Tooling/ArgumentsAdjusters.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" - -#include "session.hpp" -#include "astnormalizer.hpp" -#include "ast_normalized_context.hpp" -#include "logger.hpp" - -void beta::APISession::createNormalizedASTContext(const std::string& key){ - const auto pair = m_contexts.try_emplace(key, std::make_unique()); - if (!pair.second) { - throw std::runtime_error("AST context already exists for key: " + key); - } -} - -PARSING_STATUS beta::APISession::processFile(std::string fileName, std::unique_ptr m_compDB) { - // Initialize DebugConfig2 with diagnostics log path if not already initialized - DebugConfig& debugConfig = DebugConfig::getInstance(); - - // Get the sink from DebugConfig2 (handles file creation and fallback) - llvm::raw_ostream* sink = debugConfig.getSink(); - - // Diagnostic options - static llvm::IntrusiveRefCntPtr sDiagOpts; - if (!sDiagOpts) { - sDiagOpts = llvm::IntrusiveRefCntPtr(new clang::DiagnosticOptions()); - sDiagOpts->ShowColors = 0; // cleaner logs - } - - createNormalizedASTContext(fileName); - - clang::tooling::ClangTool tool(*m_compDB, {fileName}); - - // Build the diagnostic consumer using the shared sink - std::unique_ptr diagPrinter = - std::make_unique(*sink, &*sDiagOpts); - - // Hand ownership of the consumer to the tool - tool.setDiagnosticConsumer(diagPrinter.release()); - - // Make logged diagnostics clean and informative - tool.appendArgumentsAdjuster( - clang::tooling::getInsertArgumentAdjuster("-fno-color-diagnostics")); - tool.appendArgumentsAdjuster( - clang::tooling::getInsertArgumentAdjuster("-fno-caret-diagnostics")); - tool.appendArgumentsAdjuster( - clang::tooling::getInsertArgumentAdjuster("-fdiagnostics-show-note-include-stack")); - tool.appendArgumentsAdjuster( - clang::tooling::getInsertArgumentAdjuster("-fdiagnostics-absolute-paths")); - - //suppress ClangTool'son stderr - tool.setPrintErrorMessage(false); - int rc = tool.run(new NormalizeActionFactory(this, fileName)); - if (rc != 0) { - armor::error() << "Error while processing " << fileName << "." << "\n"; - debugConfig.flush(); - return rc == 1 ? FATAL_ERRORS : NO_FATAL_ERRORS; - } - debugConfig.flush(); - - return NO_FATAL_ERRORS; - -} - -beta::ASTNormalizedContext* beta::APISession::getContext(const std::string& fileName) const { - auto it = m_contexts.find(fileName); - if (it != m_contexts.end()) return it->second.get(); - else { - throw std::out_of_range("AST context does not exist for file: " + fileName); - } -} - -beta::ASTNormalizedContext* beta::APISession::getContext(llvm::StringRef fileName) const { - auto it = m_contexts.find(fileName); - if (it != m_contexts.end()) return it->second.get(); - else { - throw std::out_of_range("AST context does not exist for file: " + fileName.str()); - } -} diff --git a/src/beta/src/tree_builder.cpp b/src/beta/src/tree_builder.cpp index b518fb3..356b8d5 100644 --- a/src/beta/src/tree_builder.cpp +++ b/src/beta/src/tree_builder.cpp @@ -36,7 +36,9 @@ #include #include "logger.hpp" -beta::TreeBuilder::TreeBuilder(beta::ASTNormalizedContext* context): context(context) {} +namespace armor { namespace beta { + +beta::TreeBuilder::TreeBuilder(armor::ASTNormalizedContext* context): context(context) {} inline bool beta::TreeBuilder::IsDeclFromMainFileAndNotLocal(const clang::Decl* Decl) { clang::ASTContext* clangContext = &Decl->getASTContext(); @@ -45,10 +47,10 @@ inline bool beta::TreeBuilder::IsDeclFromMainFileAndNotLocal(const clang::Decl* inline bool beta::TreeBuilder::IsStmtFromMainFile(const clang::Stmt* Stmt) { if (!Stmt) return false; - + clang::SourceManager& SM = context->getClangASTContext()->getSourceManager(); clang::SourceLocation StartLoc = Stmt->getBeginLoc(); - + return StartLoc.isValid() && SM.isInMainFile(StartLoc); } @@ -58,11 +60,11 @@ inline bool beta::TreeBuilder::isInTemplatedClass(const clang::Decl* Decl){ while(DC && !DC->isTranslationUnit()){ - if(const clang::CXXRecordDecl* RD = + if(const clang::CXXRecordDecl* RD = llvm::dyn_cast_or_null(DC); RD && RD->isTemplateDecl()){ return true; } - + if(llvm::isa(DC)){ return true; } @@ -75,25 +77,25 @@ inline bool beta::TreeBuilder::isInTemplatedClass(const clang::Decl* Decl){ } inline bool beta::TreeBuilder::isWrittenInTemplatedClass(const clang::Decl* D) { - + if (!D) return false; - + const clang::DeclContext* LexicalDC = D->getLexicalDeclContext(); - + while (LexicalDC && !LexicalDC->isTranslationUnit()) { - - if (const clang::CXXRecordDecl* RD = + + if (const clang::CXXRecordDecl* RD = llvm::dyn_cast(LexicalDC); RD && RD->isTemplated()) { return true; } - + if (llvm::isa(LexicalDC)) { return true; } - + LexicalDC = LexicalDC->getParent(); } - + return false; } @@ -102,12 +104,12 @@ uint64_t beta::TreeBuilder::generateSemanticHashFromDecl(const clang::Decl* Decl clang::SourceManager& SM = Decl->getASTContext().getSourceManager(); clang::SourceLocation StartLoc = Decl->getBeginLoc(); clang::SourceLocation EndLoc = Decl->getEndLoc(); - + llvm::StringRef sourceText; - + llvm::SmallString<128> nameBuf; llvm::raw_svector_ostream OS(nameBuf); - + if(llvm::isa(Decl)){ llvm::dyn_cast(Decl)->printName(OS); armor::debug()<< "Excluding : " << nameBuf << "\n"; @@ -130,13 +132,13 @@ uint64_t beta::TreeBuilder::generateSemanticHashFromDecl(const clang::Decl* Decl uint64_t beta::TreeBuilder::generateSemanticHashFromStmt(const clang::Stmt* Stmt) { if (!Stmt) return 0; - + clang::SourceManager& SM = context->getClangASTContext()->getSourceManager(); clang::SourceLocation StartLoc = Stmt->getBeginLoc(); clang::SourceLocation EndLoc = Stmt->getEndLoc(); - + llvm::StringRef sourceText; - + if (StartLoc.isValid() && EndLoc.isValid()) { clang::CharSourceRange Range = clang::CharSourceRange::getTokenRange(StartLoc, EndLoc); sourceText = clang::Lexer::getSourceText(Range, SM, context->getClangASTContext()->getLangOpts()); @@ -154,28 +156,28 @@ void beta::TreeBuilder::processUnhandledDecl(const clang::Decl* Decl) { context->getSourceRangeTracker().addUnhandledDeclHash(hash); } -void beta::TreeBuilder::processUnhandledStmt(const clang::Stmt* Stmt, const std::shared_ptr& node) { +void beta::TreeBuilder::processUnhandledStmt(const clang::Stmt* Stmt, const std::shared_ptr& node) { uint64_t hash = generateSemanticHashFromStmt(Stmt); context->getSourceRangeTracker().addUnhandledDeclHash(hash); node->stmtHashes.emplace_back(hash); } -inline void beta::TreeBuilder::AddNode(const std::shared_ptr& node) { - +inline void beta::TreeBuilder::AddNode(const std::shared_ptr& node) { + assert(!node->NSR.empty()); - + if (!nodeStack.empty()) { if (nodeStack.back()->children == nullptr) { - nodeStack.back()->children = std::make_unique, 16>>(); + nodeStack.back()->children = std::make_unique, 16>>(); } nodeStack.back()->children->push_back(node); } else context->addRootNode(node); - + if (nodeStack.empty()) context->addNode(node->NSR, node); } -inline void beta::TreeBuilder::PushNode(const std::shared_ptr& node) { +inline void beta::TreeBuilder::PushNode(const std::shared_ptr& node) { nodeStack.push_back(node); } @@ -206,9 +208,9 @@ void beta::TreeBuilder::popOverridenQualifiedName(llvm::StringRef usr){ } void beta::TreeBuilder::BuildReturnTypeNode(clang::QualType type) { - auto returnNode = std::make_shared(); + auto returnNode = std::make_shared(); returnNode->kind = NodeKind::ReturnType; - auto [dataType,canonicalType] = getTypesWithAndWithoutTypeResolution(type, *context->getClangASTContext()); + auto [dataType,canonicalType] = getTypesWithAndWithoutTypeResolution(type, *context->getClangASTContext()); PushName("(ReturnType)"); returnNode->dataType = dataType; returnNode->caonicalType = canonicalType; @@ -221,7 +223,7 @@ void beta::TreeBuilder::BuildReturnTypeNode(clang::QualType type) { } void beta::TreeBuilder::normalizeFunctionPointerType(std::string_view typeModifiers, const clang::FunctionProtoTypeLoc FTL, const clang::NamedDecl* Decl) { - auto functionPointerNode = std::make_shared(); + auto functionPointerNode = std::make_shared(); functionPointerNode->kind = NodeKind::FunctionPointer; functionPointerNode->qualifiedName = GetCurrentQualifiedName(); functionPointerNode->dataType = typeModifiers; @@ -230,30 +232,30 @@ void beta::TreeBuilder::normalizeFunctionPointerType(std::string_view typeModifi functionPointerNode->NSR = functionPointerNode->qualifiedName; } else{ - functionPointerNode->NSR = generateNSRForDecl(Decl); - functionPointerNode->USR = generateUSRForDecl(Decl); + functionPointerNode->NSR = ::generateNSRForDecl(Decl); + functionPointerNode->USR = ::generateUSRForDecl(Decl); } - + AddNode(functionPointerNode); PushNode(functionPointerNode); - + armor::debug() << "BuildFunctionPointerType V2: " << functionPointerNode->qualifiedName << "\n"; - + const size_t numParams = FTL.getNumParams(); for (unsigned int pos=0 ; pos < numParams ; ++pos) { normalizeValueDeclNode(FTL.getParam(pos),pos); } - + BuildReturnTypeNode(FTL.getReturnLoc().getType()); PopNode(); } void beta::TreeBuilder::normalizeValueDeclNode(const clang::ValueDecl *Decl, unsigned int pos) { - - const std::string USR = generateUSRForDecl(Decl); + + const std::string USR = ::generateUSRForDecl(Decl); const auto it = context->usrNodeMap.find(USR); bool isCached = (it != context->usrNodeMap.end()); - std::shared_ptr ValueNode = isCached ? it->second : std::make_shared(); + std::shared_ptr ValueNode = isCached ? it->second : std::make_shared(); clang::QualType unDecayedDeclType = clang::QualType(); clang::TypeSourceInfo *TSI = nullptr; llvm::SmallString<128> nameBuf; @@ -271,7 +273,7 @@ void beta::TreeBuilder::normalizeValueDeclNode(const clang::ValueDecl *Decl, uns TEST_LOG<<"ParamVar init\n"; BuildValueInitExpr( paramDecl->getInit(),ValueNode); } - } + } else if (const auto *fieldDecl = llvm::dyn_cast_or_null(Decl)) { ValueNode->kind = NodeKind::Field; unDecayedDeclType = fieldDecl->getType(); @@ -299,7 +301,7 @@ void beta::TreeBuilder::normalizeValueDeclNode(const clang::ValueDecl *Decl, uns TEST_LOG<<"Var init\n" << nameBuf << "\n"; BuildValueInitExpr(varDecl->getInit(), ValueNode); } - } + } else return; auto [dataType, canonicalType] = getTypesWithAndWithoutTypeResolution(unDecayedDeclType, Decl->getASTContext()); @@ -309,21 +311,21 @@ void beta::TreeBuilder::normalizeValueDeclNode(const clang::ValueDecl *Decl, uns ValueNode->NSR = std::to_string(pos); if (it == context->usrNodeMap.end()) ValueNode->qualifiedName = GetCurrentQualifiedName(); armor::debug() << "VisitParamDecl V2: " << ValueNode->qualifiedName << "\n"; - } + } else if (llvm::isa(Decl)) { if (it == context->usrNodeMap.end()) ValueNode->qualifiedName = GetCurrentQualifiedName(); - ValueNode->NSR = generateNSRForDecl(Decl); + ValueNode->NSR = ::generateNSRForDecl(Decl); ValueNode->USR = USR; context->usrNodeMap.insert_or_assign(std::move(USR),ValueNode); armor::debug() << "VisitFeildDecl V2: " << ValueNode->qualifiedName << "\n"; - } + } else if (llvm::dyn_cast_or_null(Decl)) { if (it == context->usrNodeMap.end()) ValueNode->qualifiedName = GetCurrentQualifiedName(); - ValueNode->NSR = generateNSRForDecl(Decl); + ValueNode->NSR = ::generateNSRForDecl(Decl); ValueNode->USR = USR; context->usrNodeMap.insert_or_assign(std::move(USR),ValueNode); armor::debug() << "VisitVarDecl V2: " << ValueNode->qualifiedName << "\n"; - } + } if(!isCached){ @@ -342,19 +344,19 @@ void beta::TreeBuilder::normalizeValueDeclNode(const clang::ValueDecl *Decl, uns } } } - + PopName(); } bool beta::TreeBuilder::BuildRecordNode(clang::RecordDecl* Decl) { - + // Building RecordDecl for C specifaically if (!IsDeclFromMainFileAndNotLocal(Decl)) return false; if(llvm::isa(Decl)) return true; - const std::string USR = generateUSRForDecl(Decl); - const std::string NSR = generateNSRForDecl(Decl); + const std::string USR = ::generateUSRForDecl(Decl); + const std::string NSR = ::generateNSRForDecl(Decl); const auto it = context->usrNodeMap.find(USR); const bool isCached = (it != context->usrNodeMap.end()); @@ -398,7 +400,7 @@ bool beta::TreeBuilder::BuildRecordNode(clang::RecordDecl* Decl) { } } - std::shared_ptr recordNode = isCached ? it->second : std::make_shared(); + std::shared_ptr recordNode = isCached ? it->second : std::make_shared(); recordNode->NSR = NSR; recordNode->USR = USR; if (!isCached) { @@ -424,7 +426,7 @@ bool beta::TreeBuilder::BuildRecordNode(clang::RecordDecl* Decl) { bool beta::TreeBuilder::BuildCXXRecordNode(clang::CXXRecordDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl)) return false; - + if( isInTemplatedClass(Decl) || Decl->isTemplated() || llvm::isa(Decl) ){ if(!isWrittenInTemplatedClass(Decl)){ armor::debug()<<"Excluding CXXRecordNode\n"; @@ -433,11 +435,12 @@ bool beta::TreeBuilder::BuildCXXRecordNode(clang::CXXRecordDecl* Decl) { } return true; } - - const std::string USR = generateUSRForDecl(Decl); - const std::string NSR = generateNSRForDecl(Decl); + + const std::string USR = ::generateUSRForDecl(Decl); + const std::string NSR = ::generateNSRForDecl(Decl); const auto it = context->usrNodeMap.find(USR); const bool isCached = (it != context->usrNodeMap.end()); + const bool isForwardDeclUsedAsAdjacentDeclType = isInlineForwardDeclOfDeclType(Decl); llvm::SmallString<128> nameBuf; llvm::raw_svector_ostream OS(nameBuf); @@ -445,13 +448,18 @@ bool beta::TreeBuilder::BuildCXXRecordNode(clang::CXXRecordDecl* Decl) { if (!isCached) { if(!nameBuf.empty()){ - PushName(nameBuf); - } + if(isForwardDeclUsedAsAdjacentDeclType){ + armor::debug() << "If Embededed ForwardDecl Field is found\n"; + } + else{ + PushName(nameBuf); + } + } else{ if (const auto *typedefForAnon = Decl->getTypedefNameForAnonDecl()) { typedefForAnon->printName(OS); PushName(nameBuf); - } + } else{ if(Decl->isEmbeddedInDeclarator() && !Decl->isFreeStanding()){ if(const clang::ValueDecl * ValueDecl = llvm::dyn_cast_or_null(Decl->getNextDeclInContext())){ @@ -476,15 +484,20 @@ bool beta::TreeBuilder::BuildCXXRecordNode(clang::CXXRecordDecl* Decl) { } } } - - std::shared_ptr cxxRecordNode = isCached ? it->second : std::make_shared(); + + std::shared_ptr cxxRecordNode = isCached ? it->second : std::make_shared(); cxxRecordNode->NSR = NSR; cxxRecordNode->USR = USR; - + if (!isCached) { - cxxRecordNode->qualifiedName = GetCurrentQualifiedName(); + if(isForwardDeclUsedAsAdjacentDeclType){ + cxxRecordNode->qualifiedName = nameBuf.c_str(); + } + else{ + cxxRecordNode->qualifiedName = GetCurrentQualifiedName(); + } AddNode(cxxRecordNode); - } + } else { qualifiedName.overridePush(cxxRecordNode->qualifiedName, USR); } @@ -505,7 +518,7 @@ bool beta::TreeBuilder::BuildCXXRecordNode(clang::CXXRecordDecl* Decl) { else{ cxxRecordNode->kind = NodeKind::Class; } - + PushNode(cxxRecordNode); if ( (Decl->isClass() || Decl->isStruct()) && Decl->isThisDeclarationADefinition()){ @@ -538,8 +551,8 @@ bool beta::TreeBuilder::BuildEnumNode(clang::EnumDecl* Decl){ return true; } - const std::string USR = generateUSRForDecl(Decl); - const std::string NSR = generateNSRForDecl(Decl); + const std::string USR = ::generateUSRForDecl(Decl); + const std::string NSR = ::generateNSRForDecl(Decl); const auto it = context->usrNodeMap.find(USR); const bool isCached = (it != context->usrNodeMap.end()); @@ -550,12 +563,12 @@ bool beta::TreeBuilder::BuildEnumNode(clang::EnumDecl* Decl){ if (!isCached) { if(!nameBuf.empty()){ PushName(nameBuf); - } + } else{ if (const auto *typedefForAnon = Decl->getTypedefNameForAnonDecl()) { typedefForAnon->printName(OS); PushName(nameBuf); - } + } else{ if(Decl->isEmbeddedInDeclarator() && !Decl->isFreeStanding()){ if(const clang::ValueDecl * ValueDecl = llvm::dyn_cast_or_null(Decl->getNextDeclInContext())){ @@ -580,7 +593,7 @@ bool beta::TreeBuilder::BuildEnumNode(clang::EnumDecl* Decl){ } } - std::shared_ptr enumNode = isCached ? it->second : std::make_shared(); + std::shared_ptr enumNode = isCached ? it->second : std::make_shared(); enumNode->NSR = NSR; enumNode->USR = USR; @@ -592,25 +605,25 @@ bool beta::TreeBuilder::BuildEnumNode(clang::EnumDecl* Decl){ qualifiedName.overridePush(enumNode->qualifiedName, USR); } context->usrNodeMap.insert_or_assign(std::move(USR), enumNode); - + armor::debug() << "VisitEnumDecl V2: " << enumNode->qualifiedName << "\n"; - + enumNode->kind = NodeKind::Enum; PushNode(enumNode); const clang::QualType enumType = Decl->getIntegerType(); std::string enumaratorDataType = enumType.getAsString(); enumNode->access = getAccessSpecifier(Decl->getAccess()); - + for (const auto* EnumConstDecl : Decl->enumerators()) { if(!Decl->isThisDeclarationADefinition()) continue; - auto enumValNode = std::make_shared(); + auto enumValNode = std::make_shared(); llvm::StringRef enumConstName = EnumConstDecl->getName(); PushName(enumConstName); enumValNode->qualifiedName = GetCurrentQualifiedName(); enumValNode->dataType = enumaratorDataType; - enumValNode->NSR = generateNSRForDecl(EnumConstDecl); - enumValNode->USR = generateUSRForDecl(EnumConstDecl); + enumValNode->NSR = ::generateNSRForDecl(EnumConstDecl); + enumValNode->USR = ::generateUSRForDecl(EnumConstDecl); const clang::Expr* expr = EnumConstDecl->getInitExpr(); if(expr){ armor::debug() << "Excluding EnumConst\n" << nameBuf << ":" << enumConstName << "\n"; @@ -649,16 +662,16 @@ bool beta::TreeBuilder::BuildFunctionNode(clang::FunctionDecl* Decl){ return true; } - const std::string USR = generateUSRForDecl(Decl); + const std::string USR = ::generateUSRForDecl(Decl); const auto it = context->usrNodeMap.find(USR); const bool isCached = (it != context->usrNodeMap.end()); llvm::SmallString<128> nameBuf; llvm::raw_svector_ostream OS(nameBuf); - auto functionNode = isCached ? it->second : std::make_shared(); + auto functionNode = isCached ? it->second : std::make_shared(); Decl->printName(OS); - + if(Decl->isThisDeclarationADefinition() && Decl->getBody() && !Decl->isExplicitlyDefaulted()){ armor::debug()<<"Excluding Function Body : "<< nameBuf << "\n"; TEST_LOG<<"Function Body\n" << nameBuf << "\n"; @@ -668,7 +681,7 @@ bool beta::TreeBuilder::BuildFunctionNode(clang::FunctionDecl* Decl){ functionNode->kind = NodeKind::Function; functionNode->isInlined = Decl->isInlined(); functionNode->storage = getStorageClass(Decl->getStorageClass()); - functionNode->NSR = generateNSRForDecl(Decl); + functionNode->NSR = ::generateNSRForDecl(Decl); functionNode->USR = USR; functionNode->access = getAccessSpecifier(Decl->getAccess()); functionNode->virtualQualifier = Decl->isPure() ? VirtualQualifier::PureVirtual : VirtualQualifier::None; @@ -680,7 +693,7 @@ bool beta::TreeBuilder::BuildFunctionNode(clang::FunctionDecl* Decl){ functionNode->isVolatile = methodDecl->isVolatile(); if (const auto *constructorDecl = llvm::dyn_cast(methodDecl)) { functionNode->isExplicit = constructorDecl->isExplicit(); - } + } else if (const auto *conversionDecl = llvm::dyn_cast(methodDecl)) { functionNode->isExplicit = conversionDecl->isExplicit(); } @@ -705,12 +718,12 @@ bool beta::TreeBuilder::BuildFunctionNode(clang::FunctionDecl* Decl){ if(!isCached){ AddNode(functionNode); PushNode(functionNode); - + const size_t numParams = Decl->param_size(); for (unsigned int pos = 0; pos < numParams ; ++pos) { normalizeValueDeclNode(Decl->getParamDecl(pos), pos); } - + BuildReturnTypeNode(Decl->getReturnType()); PopName(); PopNode(); @@ -718,7 +731,7 @@ bool beta::TreeBuilder::BuildFunctionNode(clang::FunctionDecl* Decl){ else{ qualifiedName.overridePop(USR); } - + return true; } @@ -734,7 +747,7 @@ bool beta::TreeBuilder::BuildTypedefDecl(clang::TypedefDecl *Decl) { return false; } - const std::string USR = generateUSRForDecl(Decl); + const std::string USR = ::generateUSRForDecl(Decl); if( context->usrNodeMap.find(USR) != context->usrNodeMap.end() ) return true; llvm::SmallString<128> nameBuf; @@ -742,7 +755,7 @@ bool beta::TreeBuilder::BuildTypedefDecl(clang::TypedefDecl *Decl) { const clang::QualType underlyingType = Decl->getUnderlyingType(); - auto typeDefNode = std::make_shared(); + auto typeDefNode = std::make_shared(); Decl->printName(OS); PushName(nameBuf); typeDefNode->qualifiedName = GetCurrentQualifiedName(); @@ -751,10 +764,10 @@ bool beta::TreeBuilder::BuildTypedefDecl(clang::TypedefDecl *Decl) { typeDefNode->dataType = dataType; typeDefNode->caonicalType = canonicalType; typeDefNode->USR = USR; - typeDefNode->NSR = generateNSRForDecl(Decl); + typeDefNode->NSR = ::generateNSRForDecl(Decl); typeDefNode->access = getAccessSpecifier(Decl->getAccess()); context->usrNodeMap.insert_or_assign(std::move(USR), typeDefNode); - + armor::debug() << "VisitTypeDefDecl V2: " << typeDefNode->qualifiedName << "\n"; if (!llvm::isa(underlyingType)) { @@ -771,23 +784,23 @@ bool beta::TreeBuilder::BuildTypedefDecl(clang::TypedefDecl *Decl) { PopName(); AddNode(typeDefNode); - + return true; } bool beta::TreeBuilder::BuildVarDecl(clang::VarDecl *Decl) { - if (!IsDeclFromMainFileAndNotLocal(Decl) || isInTemplatedClass(Decl) || !Decl->hasGlobalStorage() + if (!IsDeclFromMainFileAndNotLocal(Decl) || isInTemplatedClass(Decl) || !Decl->hasGlobalStorage() || Decl->isTemplated()){ if(Decl->hasGlobalStorage() && IsDeclFromMainFileAndNotLocal(Decl) && !isWrittenInTemplatedClass(Decl) && (isInTemplatedClass(Decl) || Decl->isTemplated())){ armor::debug()<<"Excluding TemplatedVarDecl\n"; TEST_LOG<<"TemplatedVarDecl\n"; processUnhandledDecl(Decl); - } + } return false; } - if(llvm::isa(Decl) || llvm::isa(Decl) + if(llvm::isa(Decl) || llvm::isa(Decl) || llvm::isa(Decl)){ if(!isWrittenInTemplatedClass(Decl)){ armor::debug()<<"Excluding TempletSpecVarDecl\n"; @@ -802,7 +815,7 @@ bool beta::TreeBuilder::BuildVarDecl(clang::VarDecl *Decl) { } bool beta::TreeBuilder::BuildFieldDecl(clang::FieldDecl *Decl) { - if (!IsDeclFromMainFileAndNotLocal(Decl) || isInTemplatedClass(Decl) + if (!IsDeclFromMainFileAndNotLocal(Decl) || isInTemplatedClass(Decl) || Decl->isTemplated()){ return false; } @@ -816,12 +829,12 @@ void inline beta::TreeBuilder::BuildBaseClassDecl(clang::CXXBaseSpecifier Decl){ if(Type->getAsCXXRecordDecl() == nullptr) return; const clang::CXXRecordDecl * cxxBaseRecordDecl = Type->getAsCXXRecordDecl(); - const auto cxxBaseRecord = std::make_shared(); - cxxBaseRecord->qualifiedName = generateQualifiedNameForDecl(cxxBaseRecordDecl); + const auto cxxBaseRecord = std::make_shared(); + cxxBaseRecord->qualifiedName = ::generateQualifiedNameForDecl(cxxBaseRecordDecl); cxxBaseRecord->kind = NodeKind::BaseClass; - cxxBaseRecord->NSR = generateNSRForDecl(cxxBaseRecordDecl); + cxxBaseRecord->NSR = ::generateNSRForDecl(cxxBaseRecordDecl); cxxBaseRecord->access = getAccessSpecifier(Decl.getAccessSpecifier()); - + armor::info()<<"VisitBaseClassDecl V2 : "<< cxxBaseRecord->qualifiedName << "\n"; auto [dataType, canonicalType] = getTypesWithAndWithoutTypeResolution(Type, *context->getClangASTContext()); @@ -839,7 +852,7 @@ void inline beta::TreeBuilder::BuildFriendDecl(clang::FriendDecl *Decl){ TEST_LOG<<"FriendDecl\n"; processUnhandledDecl(Decl); } - return; + return; } if (const clang::NamedDecl* namedDecl = Decl->getFriendDecl()) { @@ -856,15 +869,15 @@ void inline beta::TreeBuilder::BuildFriendDecl(clang::FriendDecl *Decl){ else return; } else return; - + armor::debug()<<"VisitFriendDecl V2 \n"; } void beta::TreeBuilder::BuildFriendCxxRecordDecl(const clang::CXXRecordDecl *Decl, const clang::FriendDecl *FriendDecl){ // Friend Decl can be in the same file or a different file as well - const std::string USR = generateUSRForDecl(FriendDecl); - const std::string NSR = generateNSRForDecl(FriendDecl); + const std::string USR = ::generateUSRForDecl(FriendDecl); + const std::string NSR = ::generateNSRForDecl(FriendDecl); llvm::SmallString<256> keyBuf; llvm::raw_svector_ostream OS(keyBuf); @@ -872,11 +885,11 @@ void beta::TreeBuilder::BuildFriendCxxRecordDecl(const clang::CXXRecordDecl *Dec OS << nodeStack.back()->USR << ':' << USR; const auto it = context->usrNodeMap.find(keyBuf); - std::shared_ptr friendCxxRecordNode = (it != context->usrNodeMap.end()) ? it->second : std::make_shared(); + std::shared_ptr friendCxxRecordNode = (it != context->usrNodeMap.end()) ? it->second : std::make_shared(); friendCxxRecordNode->NSR = NSR; friendCxxRecordNode->USR = USR; friendCxxRecordNode->access = getAccessSpecifier(Decl->getAccess()); - + const clang::QualType Type = FriendDecl->getFriendType()->getType(); auto [dataType, canonicalType] = getTypesWithAndWithoutTypeResolution(Type, Decl->getASTContext()); friendCxxRecordNode->dataType = dataType; @@ -892,8 +905,8 @@ void beta::TreeBuilder::BuildFriendCxxRecordDecl(const clang::CXXRecordDecl *Dec } if(it == context->usrNodeMap.end()) AddNode(friendCxxRecordNode); - - friendCxxRecordNode->qualifiedName = generateQualifiedNameForDecl(Decl); + + friendCxxRecordNode->qualifiedName = ::generateQualifiedNameForDecl(Decl); context->usrNodeMap.insert_or_assign(std::move(keyBuf),friendCxxRecordNode); armor::debug()<<"VisitFriendCxxRecordDecl V2 : " << friendCxxRecordNode->qualifiedName << "\n"; @@ -901,7 +914,7 @@ void beta::TreeBuilder::BuildFriendCxxRecordDecl(const clang::CXXRecordDecl *Dec void beta::TreeBuilder::BuildFriendFunctionDecl(const clang::FunctionDecl *Decl, const clang::FriendDecl *FriendDecl){ - const std::string USR = generateUSRForDecl(FriendDecl); + const std::string USR = ::generateUSRForDecl(FriendDecl); llvm::SmallString<256> keyBuf; llvm::raw_svector_ostream OS(keyBuf); @@ -910,14 +923,14 @@ void beta::TreeBuilder::BuildFriendFunctionDecl(const clang::FunctionDecl *Decl, if( context->usrNodeMap.find(keyBuf) != context->usrNodeMap.end() ) return; - auto friendFunctionNode = std::make_shared(); - friendFunctionNode->qualifiedName = generateQualifiedNameForDecl(Decl); + auto friendFunctionNode = std::make_shared(); + friendFunctionNode->qualifiedName = ::generateQualifiedNameForDecl(Decl); qualifiedName.overridePush(friendFunctionNode->qualifiedName, USR); friendFunctionNode->kind = NodeKind::FriendFunction; friendFunctionNode->storage = getStorageClass(Decl->getStorageClass()); - friendFunctionNode->NSR = generateNSRForDecl(FriendDecl); + friendFunctionNode->NSR = ::generateNSRForDecl(FriendDecl); friendFunctionNode->USR = USR; friendFunctionNode->access = getAccessSpecifier(Decl->getAccess()); friendFunctionNode->virtualQualifier = Decl->isPure() ? VirtualQualifier::PureVirtual : VirtualQualifier::None; @@ -928,7 +941,7 @@ void beta::TreeBuilder::BuildFriendFunctionDecl(const clang::FunctionDecl *Decl, friendFunctionNode->isVolatile = methodDecl->isVolatile(); if (const auto *constructorDecl = llvm::dyn_cast(methodDecl)) { friendFunctionNode->isExplicit = constructorDecl->isExplicit(); - } + } else if (const auto *conversionDecl = llvm::dyn_cast(methodDecl)) { friendFunctionNode->isExplicit = conversionDecl->isExplicit(); } @@ -944,12 +957,12 @@ void beta::TreeBuilder::BuildFriendFunctionDecl(const clang::FunctionDecl *Decl, AddNode(friendFunctionNode); PushNode(friendFunctionNode); - + const size_t numParams = Decl->param_size(); for (unsigned int pos = 0; pos < numParams ; ++pos) { normalizeValueDeclNode(Decl->getParamDecl(pos), pos); } - + BuildReturnTypeNode(Decl->getReturnType()); PopNode(); @@ -961,7 +974,7 @@ void beta::TreeBuilder::BuildFriendFunctionDecl(const clang::FunctionDecl *Decl, // void beta::TreeBuilder::BuildNamespaceDecl(clang::NamespaceDecl* Decl) { // if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + // armor::debug()<<"Excluding NamespaceDecl\n"; // TEST_LOG<<"NamespaceDecl\n"; @@ -979,25 +992,25 @@ void beta::TreeBuilder::BuildFunctionTemplateDecl(clang::FunctionTemplateDecl* D void beta::TreeBuilder::BuildClassTemplateDecl(clang::ClassTemplateDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding ClassTemplateDecl\n"; TEST_LOG << "ClassTemplateDecl\n"; - + processUnhandledDecl(Decl); } void beta::TreeBuilder::BuildClassTemplateSpecializationDecl(clang::ClassTemplateSpecializationDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding ClassTemplateSpecializationDecl\n"; TEST_LOG << "ClassTemplateSpecializationDecl\n"; - + processUnhandledDecl(Decl); } void beta::TreeBuilder::BuildClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding ClassTemplatePartialSpecializationDecl\n"; TEST_LOG << "ClassTemplatePartialSpecializationDecl\n"; @@ -1006,7 +1019,7 @@ void beta::TreeBuilder::BuildClassTemplatePartialSpecializationDecl(clang::Class void beta::TreeBuilder::BuildTypeAliasDecl(clang::TypeAliasDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding TypeAliasDecl\n"; TEST_LOG << "TypeAliasDecl\n"; @@ -1015,25 +1028,25 @@ void beta::TreeBuilder::BuildTypeAliasDecl(clang::TypeAliasDecl* Decl) { void beta::TreeBuilder::BuildUsingDecl(clang::UsingDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding UsingDecl\n"; TEST_LOG << "UsingDecl\n"; - + processUnhandledDecl(Decl); } void beta::TreeBuilder::BuildUsingDirectiveDecl(clang::UsingDirectiveDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding UsingDirectiveDecl\n"; TEST_LOG << "UsingDirectiveDecl\n"; - + processUnhandledDecl(Decl); } void beta::TreeBuilder::BuildNamespaceAliasDecl(clang::NamespaceAliasDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding NamespaceAliasDecl\n"; TEST_LOG << "NamespaceAliasDecl\n"; @@ -1042,50 +1055,50 @@ void beta::TreeBuilder::BuildNamespaceAliasDecl(clang::NamespaceAliasDecl* Decl) void beta::TreeBuilder::BuildStaticAssertDecl(clang::StaticAssertDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding StaticAssertDecl\n"; TEST_LOG << "StaticAssertDecl\n"; - + processUnhandledDecl(Decl); } void beta::TreeBuilder::BuildVarTemplateDecl(clang::VarTemplateDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding VarTemplateDecl\n"; TEST_LOG << "VarTemplateDecl\n"; - + processUnhandledDecl(Decl); } void beta::TreeBuilder::BuildVarTemplateSpecializationDecl(clang::VarTemplateSpecializationDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding VarTemplateSpecializationDecl\n"; TEST_LOG << "VarTemplateSpecializationDecl\n"; - + processUnhandledDecl(Decl); } void beta::TreeBuilder::BuildVarTemplatePartialSpecializationDecl(clang::VarTemplatePartialSpecializationDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding VarTemplatePartialSpecializationDecl\n"; TEST_LOG << "VarTemplatePartialSpecializationDecl\n"; - + processUnhandledDecl(Decl); } void beta::TreeBuilder::BuildTypeAliasTemplateDecl(clang::TypeAliasTemplateDecl* Decl) { if (!IsDeclFromMainFileAndNotLocal(Decl) || isWrittenInTemplatedClass(Decl)) return; - + armor::debug() << "Excluding TypeAliasTemplateDecl\n"; TEST_LOG << "TypeAliasTemplateDecl\n"; - + processUnhandledDecl(Decl); } -void beta::TreeBuilder::BuildValueInitExpr(const clang::Expr* Expr, const std::shared_ptr& node){ +void beta::TreeBuilder::BuildValueInitExpr(const clang::Expr* Expr, const std::shared_ptr& node){ if (Expr && !IsStmtFromMainFile(Expr)) return; if (const clang::CXXConstructExpr* cxxConstructExpr = llvm::dyn_cast(Expr)) { @@ -1103,4 +1116,6 @@ void beta::TreeBuilder::BuildValueInitExpr(const clang::Expr* Expr, const std::s else{ processUnhandledStmt(Expr, node); } -} \ No newline at end of file +} + +} } // namespace armor::beta \ No newline at end of file diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index db63fc2..c521d6a 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -14,13 +14,13 @@ FetchContent_Declare( FetchContent_MakeAvailable(nlohmann_json CLI11) -file(GLOB_RECURSE SOURCES "src/*.cpp") +file(GLOB_RECURSE COMMON_SOURCES "src/*.cpp") add_library(common_lib STATIC - ${SOURCES} + ${COMMON_SOURCES} ) -target_include_directories(common_lib PRIVATE +target_include_directories(common_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ) @@ -28,15 +28,16 @@ target_link_libraries(common_lib ${LLVM_LIBS} clangTooling clangIndex + clangFrontend nlohmann_json::nlohmann_json CLI11::CLI11 ) add_library(common_lib_test STATIC - ${SOURCES} + ${COMMON_SOURCES} ) -target_include_directories(common_lib_test PRIVATE +target_include_directories(common_lib_test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ) @@ -46,6 +47,7 @@ target_link_libraries(common_lib_test ${LLVM_LIBS} clangTooling clangIndex + clangFrontend nlohmann_json::nlohmann_json CLI11::CLI11 ) \ No newline at end of file diff --git a/src/common/include/ast_normalized_context.hpp b/src/common/include/ast_normalized_context.hpp new file mode 100644 index 0000000..908f8ea --- /dev/null +++ b/src/common/include/ast_normalized_context.hpp @@ -0,0 +1,113 @@ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause +#pragma once + +#include "node.hpp" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceLocation.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace armor { + +/** + * @class SourceRangeTracker + * @brief Unified tracker for source range information from both parsers. + * + * Alpha uses only the fatal directives interface. + * Beta uses the full interface (comments, inactive PP directives, hash maps). + */ +class SourceRangeTracker { +public: + SourceRangeTracker() = default; + + struct FatalDirectiveRef { + std::string Header; + std::string File; + FatalDirectiveRef(llvm::StringRef header, llvm::StringRef file) + : Header(header), File(file) {} + }; + + // --- Alpha: fatal include directives --- + void addFatalDirective(llvm::StringRef header, llvm::StringRef file); + const llvm::SmallVector& getFatalDirectives() const; + + // --- Beta: comments --- + const llvm::SmallVector& getComments() const; + void moveComments(llvm::SmallVector& ranges); + llvm::DenseMap& getCommentsHashMap(); + const llvm::DenseMap& getCommentsHashMap() const; + void moveCommentsHashMap(llvm::DenseMap& hashMap); + + // --- Beta: inactive PP directives --- + const std::map& getInactivePPDirectives() const; + std::map& getInactivePPDirectives(); + void moveInactivePPDirectives(std::map& map); + + // --- Beta: unhandled decl hashes --- + void addUnhandledDeclHash(uint64_t hash); + llvm::DenseMap& getUnhandledDeclsHashMap(); + const llvm::DenseMap& getUnhandledDeclsHashMap() const; + void moveInactiveUnhandledDeclsHashMap(llvm::DenseMap& hashMap); + llvm::DenseMap& getInactiveUnhandledDeclsHashMap(); + const llvm::DenseMap& getInactiveUnhandledDeclsHashMap() const; + + void clear(); + bool empty() const; + +private: + llvm::SmallVector fatalDirectives; + + llvm::SmallVector comments; + std::map inactivePPDirectives; + llvm::DenseMap unhandledDeclsHashMap; + llvm::DenseMap commentsHashMap; + llvm::DenseMap inactiveUnhandledDeclsHashMap; +}; + +/** + * @class ASTNormalizedContext + * @brief Unified context for both alpha (parse-only) and beta (full tree) parsers. + * + * Alpha uses only: addClangASTContext, getSourceRangeTracker (fatal directives). + * Beta uses the full interface: node maps, root nodes, source range tracker. + */ +class ASTNormalizedContext { +public: + ASTNormalizedContext(); + + // Node management (beta only) + void addNode(llvm::StringRef key, const std::shared_ptr node); + void addRootNode(const std::shared_ptr rootNode); + const llvm::StringMap, 16>>& getTree() const; + const llvm::SmallVector, 64>& getRootNodes() const; + + bool empty() const; + void clear(); + + void addClangASTContext(clang::ASTContext* ASTContext); + clang::ASTContext* getClangASTContext() const; + + SourceRangeTracker& getSourceRangeTracker(); + const SourceRangeTracker& getSourceRangeTracker() const; + + // Beta-specific lookup maps + llvm::StringMap> usrNodeMap; + llvm::StringSet<> unSupportedUsrNodeMap; + +private: + llvm::StringMap, 16>> apiNodesMap; + llvm::SmallVector, 64> apiNodes; + SourceRangeTracker sourceRangeTracker; + clang::ASTContext* clangContext = nullptr; +}; + +} // namespace armor diff --git a/src/common/include/categorization.hpp b/src/common/include/categorization.hpp index d557965..f293efa 100644 --- a/src/common/include/categorization.hpp +++ b/src/common/include/categorization.hpp @@ -1,6 +1,6 @@ // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause -#include +#pragma once constexpr const char* CRITICAL_PARSING_ERRORS = "Critical parsing errors occurred."; diff --git a/src/common/include/custom_usr_generator.hpp b/src/common/include/custom_usr_generator.hpp index a983254..31a6779 100644 --- a/src/common/include/custom_usr_generator.hpp +++ b/src/common/include/custom_usr_generator.hpp @@ -3,12 +3,10 @@ #pragma once #include "clang/AST/ASTContext.h" -#include "clang/AST/DeclVisitor.h" #include "clang/Lex/PreprocessingRecord.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "clang/Basic/LLVM.h" -#include "llvm/ADT/StringRef.h" namespace armor { diff --git a/src/common/include/diff_utils.hpp b/src/common/include/diff_utils.hpp index 30765bb..3df11bd 100644 --- a/src/common/include/diff_utils.hpp +++ b/src/common/include/diff_utils.hpp @@ -38,6 +38,8 @@ extern std::string IS_EXPLICIT; extern std::string IS_VOLATILE; extern std::string IS_CONST; extern std::string IS_FRIEND; +extern std::string HEADER; +extern std::string FILE_PATH; enum class ParsedDiffStatus { FATAL_ERRORS = 0, // Critical errors occurred (e.g., header resolution failures) diff --git a/src/common/include/header_processor_utils.hpp b/src/common/include/header_processor_utils.hpp new file mode 100644 index 0000000..73f1dcf --- /dev/null +++ b/src/common/include/header_processor_utils.hpp @@ -0,0 +1,29 @@ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause +#pragma once + +#include +#include +#include + +#include "comm_def.hpp" + +namespace armor { + +std::vector getClangFlags(const std::vector& includePaths, + const std::vector& macroFlags, + LANG_OPTIONS lang); + +std::vector resolveInternalIncludePaths(const std::vector& internalPaths, + const std::string& workspacePath); + +std::vector generateIncludePaths(const std::string& projectPath, + const std::string& headerPath); + +void emitHeaderDiffReport(const nlohmann::json& diffResult, + const std::string& file1, + const std::string& project1, + const std::string& reportFormat, + PARSER parser); + +} // namespace armor diff --git a/src/beta/include/node.hpp b/src/common/include/node.hpp similarity index 82% rename from src/beta/include/node.hpp rename to src/common/include/node.hpp index 9ee2390..f987450 100644 --- a/src/beta/include/node.hpp +++ b/src/common/include/node.hpp @@ -13,16 +13,13 @@ #include "nlohmann/json_fwd.hpp" #include "clang/Basic/SourceLocation.h" -// Main Node structure -// string can be optimized by SmallString - -namespace beta { +namespace armor { struct APINode { NodeKind kind = NodeKind::Unknown; std::string qualifiedName; - std::string dataType; // datatype of variables as written .... (int/float/...) - std::string caonicalType; // underlying datatype of variable after parsing through typedef/typealias chain + std::string dataType; + std::string caonicalType; bool isInlined = false; bool isConstExpr = false; AccessSpec access = AccessSpec::None; @@ -44,10 +41,9 @@ struct APINode { std::unique_ptr,16>> children; nlohmann::json diff(const std::shared_ptr& other) const; - }; -struct Range{ +struct Range { unsigned startOffset; unsigned endOffset; uint64_t hash; @@ -59,4 +55,4 @@ struct Range{ : startOffset(start), endOffset(end), hash(hash), isActive(active) {} }; -} \ No newline at end of file +} // namespace armor diff --git a/src/common/include/nsr_generator.hpp b/src/common/include/nsr_generator.hpp index 7dbeef0..2d3234a 100644 --- a/src/common/include/nsr_generator.hpp +++ b/src/common/include/nsr_generator.hpp @@ -3,7 +3,6 @@ #pragma once #include "clang/AST/ASTContext.h" -#include "clang/AST/DeclVisitor.h" #include "clang/Lex/PreprocessingRecord.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" diff --git a/src/common/include/options_handler.hpp b/src/common/include/options_handler.hpp index 9de311f..3691aae 100644 --- a/src/common/include/options_handler.hpp +++ b/src/common/include/options_handler.hpp @@ -3,8 +3,6 @@ #ifndef OPTIONS_HANDLER_HPP #define OPTIONS_HANDLER_HPP -#include - bool runArmorTool(int argc, const char **argv); #endif diff --git a/src/common/include/qualified_name_generator.hpp b/src/common/include/qualified_name_generator.hpp index 44fcccb..0663908 100644 --- a/src/common/include/qualified_name_generator.hpp +++ b/src/common/include/qualified_name_generator.hpp @@ -3,12 +3,9 @@ #pragma once #include "clang/AST/ASTContext.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/Lex/PreprocessingRecord.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "clang/Basic/LLVM.h" -#include "llvm/ADT/StringRef.h" namespace armor { diff --git a/src/common/include/session.hpp b/src/common/include/session.hpp new file mode 100644 index 0000000..0573f6f --- /dev/null +++ b/src/common/include/session.hpp @@ -0,0 +1,53 @@ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause +#pragma once + +#include "ast_normalized_context.hpp" +#include "comm_def.hpp" +#include "clang/Tooling/CompilationDatabase.h" + +namespace clang { namespace tooling { + class FixedCompilationDatabase; + class FrontendActionFactory; +} } + +namespace armor { + +/** + * @class APISession + * @brief Unified session managing both alpha and beta parser contexts per file. + * + * - processFileAlpha: runs the alpha preprocessor-only pass (detects fatal includes), + * using the caller-supplied FrontendActionFactory (armor::alpha::createNormalizeActionFactory). + * - processFileBeta: runs the full beta AST + node-tree building pass, + * using the caller-supplied FrontendActionFactory (armor::beta::createNormalizeActionFactory). + * + * Each file gets two independent ASTNormalizedContext entries, one per parser. + * Alpha contexts only contain SourceRangeTracker data. + * Beta contexts contain the full node tree plus source range data. + */ +class APISession { +public: + PARSING_STATUS processFileAlpha(std::string fileName, + std::unique_ptr compDB, + std::unique_ptr factory); + + PARSING_STATUS processFileBeta(std::string fileName, + std::unique_ptr compDB, + std::unique_ptr factory); + + ASTNormalizedContext* getAlphaContext(const std::string& fileName) const; + ASTNormalizedContext* getAlphaContext(llvm::StringRef fileName) const; + + ASTNormalizedContext* getBetaContext(const std::string& fileName) const; + ASTNormalizedContext* getBetaContext(llvm::StringRef fileName) const; + + void createAlphaContext(const std::string& key); + void createBetaContext(const std::string& key); + +private: + llvm::StringMap> m_alphaContexts; + llvm::StringMap> m_betaContexts; +}; + +} // namespace armor diff --git a/src/common/include/tree_builder_utils.hpp b/src/common/include/tree_builder_utils.hpp index 3937c65..9484000 100644 --- a/src/common/include/tree_builder_utils.hpp +++ b/src/common/include/tree_builder_utils.hpp @@ -29,4 +29,6 @@ const std::string generateQualifiedNameForDecl(const clang::NamedDecl *Decl); const std::pair getTypesWithAndWithoutTypeResolution(const clang::QualType T, const clang::ASTContext &Ctx); -const std::string generateHash( llvm::StringRef qualifiedName , const NodeKind& node ); \ No newline at end of file +const std::string generateHash( llvm::StringRef qualifiedName , const NodeKind& node ); + +bool isInlineForwardDeclOfDeclType(const clang::CXXRecordDecl* Decl); \ No newline at end of file diff --git a/src/common/src/ast_normalized_context.cpp b/src/common/src/ast_normalized_context.cpp new file mode 100644 index 0000000..5127e87 --- /dev/null +++ b/src/common/src/ast_normalized_context.cpp @@ -0,0 +1,140 @@ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause +#include "node.hpp" +#include "ast_normalized_context.hpp" +#include +#include +#include +#include + +// --- ASTNormalizedContext --- + +armor::ASTNormalizedContext::ASTNormalizedContext() = default; + +void armor::ASTNormalizedContext::addNode(llvm::StringRef key, std::shared_ptr node) { + apiNodesMap[key].emplace_back(std::move(node)); +} + +void armor::ASTNormalizedContext::addRootNode(std::shared_ptr rootNode) { + if (rootNode) { + apiNodes.push_back(std::move(rootNode)); + } +} + +const llvm::StringMap, 16>>& +armor::ASTNormalizedContext::getTree() const { + return apiNodesMap; +} + +const llvm::SmallVector, 64>& +armor::ASTNormalizedContext::getRootNodes() const { + return apiNodes; +} + +bool armor::ASTNormalizedContext::empty() const { + return apiNodesMap.empty() && apiNodes.empty(); +} + +void armor::ASTNormalizedContext::clear() { + apiNodesMap.clear(); + apiNodes.clear(); + sourceRangeTracker.clear(); +} + +void armor::ASTNormalizedContext::addClangASTContext(clang::ASTContext* ASTContext) { + clangContext = ASTContext; +} + +clang::ASTContext* armor::ASTNormalizedContext::getClangASTContext() const { + return clangContext; +} + +armor::SourceRangeTracker& armor::ASTNormalizedContext::getSourceRangeTracker() { + return sourceRangeTracker; +} + +const armor::SourceRangeTracker& armor::ASTNormalizedContext::getSourceRangeTracker() const { + return sourceRangeTracker; +} + +// --- SourceRangeTracker --- + +void armor::SourceRangeTracker::addFatalDirective(llvm::StringRef header, llvm::StringRef file) { + fatalDirectives.emplace_back(header, file); +} + +const llvm::SmallVector& +armor::SourceRangeTracker::getFatalDirectives() const { + return fatalDirectives; +} + +const llvm::SmallVector& armor::SourceRangeTracker::getComments() const { + return comments; +} + +void armor::SourceRangeTracker::moveComments(llvm::SmallVector& ranges) { + comments = std::move(ranges); +} + +llvm::DenseMap& armor::SourceRangeTracker::getCommentsHashMap() { + return commentsHashMap; +} + +const llvm::DenseMap& armor::SourceRangeTracker::getCommentsHashMap() const { + return commentsHashMap; +} + +void armor::SourceRangeTracker::moveCommentsHashMap(llvm::DenseMap& hashMap) { + commentsHashMap = std::move(hashMap); +} + +const std::map& armor::SourceRangeTracker::getInactivePPDirectives() const { + return inactivePPDirectives; +} + +std::map& armor::SourceRangeTracker::getInactivePPDirectives() { + return inactivePPDirectives; +} + +void armor::SourceRangeTracker::moveInactivePPDirectives(std::map& ranges) { + inactivePPDirectives = std::move(ranges); +} + +void armor::SourceRangeTracker::addUnhandledDeclHash(uint64_t hash) { + unhandledDeclsHashMap[hash]++; +} + +llvm::DenseMap& armor::SourceRangeTracker::getUnhandledDeclsHashMap() { + return unhandledDeclsHashMap; +} + +const llvm::DenseMap& armor::SourceRangeTracker::getUnhandledDeclsHashMap() const { + return unhandledDeclsHashMap; +} + +void armor::SourceRangeTracker::moveInactiveUnhandledDeclsHashMap(llvm::DenseMap& hashMap) { + inactiveUnhandledDeclsHashMap = std::move(hashMap); +} + +llvm::DenseMap& armor::SourceRangeTracker::getInactiveUnhandledDeclsHashMap() { + return inactiveUnhandledDeclsHashMap; +} + +const llvm::DenseMap& armor::SourceRangeTracker::getInactiveUnhandledDeclsHashMap() const { + return inactiveUnhandledDeclsHashMap; +} + +void armor::SourceRangeTracker::clear() { + fatalDirectives.clear(); + comments.clear(); + inactivePPDirectives.clear(); + unhandledDeclsHashMap.clear(); + inactiveUnhandledDeclsHashMap.clear(); + commentsHashMap.clear(); +} + +bool armor::SourceRangeTracker::empty() const { + return fatalDirectives.empty() && + comments.empty() && + inactivePPDirectives.empty(); +} diff --git a/src/common/src/diff_utils.cpp b/src/common/src/diff_utils.cpp index 5c728ba..a4f1485 100644 --- a/src/common/src/diff_utils.cpp +++ b/src/common/src/diff_utils.cpp @@ -36,6 +36,8 @@ std::string IS_EXPLICIT = "isExplicit"; std::string IS_VOLATILE = "isVolatile"; std::string IS_CONST = "isConst"; std::string IS_FRIEND = "isFriend"; +std::string HEADER = "header"; +std::string FILE_PATH = "file"; const std::string serialize(const APINodeStorageClass& storageClass) { switch (storageClass) { diff --git a/src/common/src/header_processor_utils.cpp b/src/common/src/header_processor_utils.cpp new file mode 100644 index 0000000..69fd21b --- /dev/null +++ b/src/common/src/header_processor_utils.cpp @@ -0,0 +1,155 @@ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause +#include +#include +#include +#include +#include +#include +#include + +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Path.h" + +#include "comm_def.hpp" +#include "header_processor_utils.hpp" +#include "logger.hpp" +#include "report_generator.hpp" + +namespace fs = std::filesystem; + +namespace armor { + +std::vector getClangFlags(const std::vector& includePaths, + const std::vector& macroFlags, + const LANG_OPTIONS lang) { + std::vector flags; + + const char* rawFlags; + switch (lang) { + case LANG_OPTIONS::C: + rawFlags = CLANG_FLAGS_C; + break; + case LANG_OPTIONS::CPP: + rawFlags = CLANG_FLAGS_CPP; + break; + default: + rawFlags = CLANG_FLAGS_CPP; + break; + } + + std::istringstream iss(rawFlags); + std::string flag; + while (iss >> flag) { + flags.emplace_back(std::move(flag)); + } + + // Add runtime include paths + for (const auto& path : includePaths) { + flags.emplace_back("-I" + path); + } + + // Add full macro flags directly + for (const auto& macro : macroFlags) { + flags.emplace_back(macro); + } + + return flags; +} + +std::vector resolveInternalIncludePaths(const std::vector& internalPaths, + const std::string& workspacePath) { + + std::vector resolvedPaths; + for (const auto& path : internalPaths) { + resolvedPaths.push_back(workspacePath + "/" + path); + } + return resolvedPaths; +} + +std::vector generateIncludePaths(const std::string& projectPath, const std::string& headerPath) { + std::vector includePaths; + + // Ensure the header path starts with the project path + if (headerPath.find(projectPath) != 0) { + armor::user_error() << "Warning: Header file " << headerPath << " is not within project path " << projectPath << "\n"; + return includePaths; + } + + // Get the directory of the header file + llvm::SmallString<256> headerDir(headerPath); + llvm::sys::path::remove_filename(headerDir); + + // Start with the directory containing the header file + llvm::SmallString<256> currentPath = headerDir; + + // Add all parent directories up to and including the project path + while (llvm::StringRef(currentPath).str().length() >= projectPath.length()) { + includePaths.push_back("-I" + llvm::StringRef(currentPath).str()); + + // Move up one directory + llvm::sys::path::remove_filename(currentPath); + + // If we've reached the root directory, break + if (currentPath.empty()) { + break; + } + } + + // Make sure the project path itself is included + if (std::find(includePaths.begin(), includePaths.end(), "-I" + projectPath) == includePaths.end()) { + includePaths.push_back("-I" + projectPath); + } + + return includePaths; +} + +void emitHeaderDiffReport(const nlohmann::json& diffResult, + const std::string& file1, + const std::string& project1, + const std::string& reportFormat, + PARSER parser) { + + std::string headerName = std::filesystem::path(file1).filename().string(); + + std::string dumpDir = "debug_output/ast_diffs"; + std::filesystem::create_directories(dumpDir); + std::string outputFile = dumpDir + "/ast_diff_output_" + headerName + ".json"; + + try { + if (!diffResult.empty()) { + std::ofstream out(outputFile, std::ios::trunc); + out << diffResult.dump(4); + out.close(); + } + } + catch (const std::exception& e) { + armor::user_error() << "Error generating AST diff: " << e.what() << "\n"; + } + + std::string reportDir = "armor_reports/html_reports"; + std::filesystem::create_directories(reportDir); + std::string htmlReportFile = reportDir + "/api_diff_report_" + headerName + ".html"; + + if (!diffResult.empty()) { + bool generate_json = (reportFormat == "json"); + std::string jsonReportFile; + if (generate_json) { + std::string jsonReportDir = "armor_reports/json_reports"; + std::filesystem::create_directories(jsonReportDir); + jsonReportFile = jsonReportDir + "/api_diff_report_" + headerName + ".json"; + } + fs::path relative_path = fs::relative(file1, project1); + std::string trimmed_path = relative_path.string(); + report_generator(outputFile, trimmed_path, htmlReportFile, jsonReportFile, parser, generate_json); + } + else { + try { + armor::user_print() << "HTML report generated at: " << htmlReportFile << "\n"; + } catch (const std::exception& e) { + armor::user_error() << "Failed to generate HTML report: " << e.what() << "\n"; + } + } +} + +} // namespace armor diff --git a/src/beta/src/node.cpp b/src/common/src/node.cpp similarity index 72% rename from src/beta/src/node.cpp rename to src/common/src/node.cpp index 01d24d0..1b270eb 100644 --- a/src/beta/src/node.cpp +++ b/src/common/src/node.cpp @@ -6,16 +6,14 @@ #include #include -nlohmann::json beta::APINode::diff(const std::shared_ptr& other) const { +nlohmann::json armor::APINode::diff(const std::shared_ptr& other) const { nlohmann::json result, removed, added; - // Helper to add metadata to a diff JSON node - auto appendNodeMetadata = [&](nlohmann::json& node) { + auto appendNodeMetadata = [&](nlohmann::json& node) { node[NODE_TYPE] = serialize(kind); node[QUALIFIED_NAME] = qualifiedName; }; - // Define a lambda function to compare fields auto compare = [&](const std::string& field, const auto &lhs, const auto &rhs, const auto &emptyValue) { if (lhs != rhs) { if (lhs != emptyValue) { @@ -27,43 +25,20 @@ nlohmann::json beta::APINode::diff(const std::shared_ptr& o } }; - // Compare fields - if( dataType != other->dataType ){ - - if(kind == NodeKind::FunctionPointer){ + if (dataType != other->dataType) { + if (kind == NodeKind::FunctionPointer) { compare(DATA_TYPE, dataType, other->dataType, std::string{}); - } - else{ + } else { assert(!caonicalType.empty()); assert(!other->caonicalType.empty()); compare(DATA_TYPE, caonicalType, other->caonicalType, std::string{}); } } - compare( - STORAGE_QUALIFIER, - storage, - other->storage, - APINodeStorageClass::None - ); - compare( - VIRTUAL_QUALIFIER, - virtualQualifier, - other->virtualQualifier, - VirtualQualifier::None - ); - compare( - INLINE, - isInlined, - other->isInlined, - false - ); - compare( - CONST_EXPR, - isConstExpr, - other->isConstExpr, - false - ); + compare(STORAGE_QUALIFIER, storage, other->storage, APINodeStorageClass::None); + compare(VIRTUAL_QUALIFIER, virtualQualifier, other->virtualQualifier, VirtualQualifier::None); + compare(INLINE, isInlined, other->isInlined, false); + compare(CONST_EXPR, isConstExpr, other->isConstExpr, false); compare(ACCESS_SPECIFIER, access, other->access, AccessSpec::None); compare(IS_OVERRIDE, isOveride, other->isOveride, false); compare(IS_FINAL, isFinal, other->isFinal, false); @@ -73,9 +48,8 @@ nlohmann::json beta::APINode::diff(const std::shared_ptr& o compare(IS_VOLATILE, isVolatile, other->isVolatile, false); compare(IS_CONST, isConst, other->isConst, false); compare(IS_FRIEND, isFriend, other->isFriend, false); - // If there are any changes + if (!removed.empty() || !added.empty()) { - // Helper to process removed and added changes auto processChanges = [&](nlohmann::json& parent) { if (!removed.empty()) { removed[TAG] = REMOVED; @@ -92,18 +66,16 @@ nlohmann::json beta::APINode::diff(const std::shared_ptr& o if (this->children == nullptr) { nlohmann::json children = nlohmann::json::array(); processChanges(children); - if (!children.empty()) { result[CHILDREN] = std::move(children); appendNodeMetadata(result); result[TAG] = MODIFIED; } - } - else { + } else { result = nlohmann::json::array(); processChanges(result); } } return result; -} \ No newline at end of file +} diff --git a/src/common/src/report_utils.cpp b/src/common/src/report_utils.cpp index a0f596f..a3a14c0 100644 --- a/src/common/src/report_utils.cpp +++ b/src/common/src/report_utils.cpp @@ -1,6 +1,5 @@ // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause -// report_utils.cpp #include #include #include @@ -1598,15 +1597,15 @@ void generate_html_report(const std::vector& processed_data, } else{ assert( file1_exists | file2_exists ); - html << SIMPLE_HEADER; + html << SIMPLE_HEADER; html << "
\n"; html << "Overall status: " << overall_status << "
\n"; html << "Reason: " << reason << "
\n"; html << "
\n"; - + } - } + } else { switch (parser) { @@ -1619,7 +1618,7 @@ void generate_html_report(const std::vector& processed_data, default: break; } - + auto grouped = group_records_by_function(processed_data); for (const auto& entry : grouped) { html << "\n"; @@ -1663,7 +1662,7 @@ void generate_json_report(const std::vector& processed_data, wrapper["unparsed_staus"] = serialize(unParsedStatus); wrapper["compatibility"] = agg_compatibility; wrapper["overall_status"] = overall_status; - wrapper["reason"] = reason; + wrapper["reason"] = reason; jf << wrapper.dump(4); jf.close(); } diff --git a/src/common/src/session.cpp b/src/common/src/session.cpp new file mode 100644 index 0000000..782f2d6 --- /dev/null +++ b/src/common/src/session.cpp @@ -0,0 +1,132 @@ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause +#include +#include +#include +#include + +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Tooling.h" +#include "clang/Tooling/ArgumentsAdjusters.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +#include "session.hpp" +#include "ast_normalized_context.hpp" +#include "logger.hpp" + +namespace { + +void setupClangTool(clang::tooling::ClangTool& tool, llvm::raw_ostream* sink, + llvm::IntrusiveRefCntPtr diagOpts) { + std::unique_ptr diagPrinter = + std::make_unique(*sink, &*diagOpts); + tool.setDiagnosticConsumer(diagPrinter.release()); + tool.appendArgumentsAdjuster(clang::tooling::getInsertArgumentAdjuster("-fno-color-diagnostics")); + tool.appendArgumentsAdjuster(clang::tooling::getInsertArgumentAdjuster("-fno-caret-diagnostics")); + tool.appendArgumentsAdjuster(clang::tooling::getInsertArgumentAdjuster("-fdiagnostics-show-note-include-stack")); + tool.appendArgumentsAdjuster(clang::tooling::getInsertArgumentAdjuster("-fdiagnostics-absolute-paths")); + tool.setPrintErrorMessage(false); +} + +} // namespace + +static llvm::IntrusiveRefCntPtr sDiagOpts; + +static void ensureDiagOpts() { + if (!sDiagOpts) { + sDiagOpts = llvm::IntrusiveRefCntPtr(new clang::DiagnosticOptions()); + sDiagOpts->ShowColors = 0; + } +} + +void armor::APISession::createAlphaContext(const std::string& key) { + const auto pair = m_alphaContexts.try_emplace(key, std::make_unique()); + if (!pair.second) { + throw std::runtime_error("Alpha AST context already exists for key: " + key); + } +} + +void armor::APISession::createBetaContext(const std::string& key) { + const auto pair = m_betaContexts.try_emplace(key, std::make_unique()); + if (!pair.second) { + throw std::runtime_error("Beta AST context already exists for key: " + key); + } +} + +PARSING_STATUS armor::APISession::processFileAlpha( + std::string fileName, + std::unique_ptr compDB, + std::unique_ptr factory) +{ + DebugConfig& debugConfig = DebugConfig::getInstance(); + llvm::raw_ostream* sink = debugConfig.getSink(); + ensureDiagOpts(); + + createAlphaContext(fileName); + + clang::tooling::ClangTool tool(*compDB, {fileName}); + setupClangTool(tool, sink, sDiagOpts); + + int rc = tool.run(factory.get()); + if (rc != 0) { + armor::error() << "Alpha: error while processing " << fileName << ".\n"; + debugConfig.flush(); + return rc == 1 ? FATAL_ERRORS : NO_FATAL_ERRORS; + } + debugConfig.flush(); + return NO_FATAL_ERRORS; +} + +PARSING_STATUS armor::APISession::processFileBeta( + std::string fileName, + std::unique_ptr compDB, + std::unique_ptr factory) +{ + DebugConfig& debugConfig = DebugConfig::getInstance(); + llvm::raw_ostream* sink = debugConfig.getSink(); + ensureDiagOpts(); + + createBetaContext(fileName); + + clang::tooling::ClangTool tool(*compDB, {fileName}); + setupClangTool(tool, sink, sDiagOpts); + + int rc = tool.run(factory.get()); + if (rc != 0) { + armor::error() << "Beta: error while processing " << fileName << ".\n"; + debugConfig.flush(); + return rc == 1 ? FATAL_ERRORS : NO_FATAL_ERRORS; + } + debugConfig.flush(); + return NO_FATAL_ERRORS; +} + +armor::ASTNormalizedContext* armor::APISession::getAlphaContext(const std::string& fileName) const { + auto it = m_alphaContexts.find(fileName); + if (it != m_alphaContexts.end()) return it->second.get(); + throw std::out_of_range("Alpha AST context does not exist for file: " + fileName); +} + +armor::ASTNormalizedContext* armor::APISession::getAlphaContext(llvm::StringRef fileName) const { + auto it = m_alphaContexts.find(fileName); + if (it != m_alphaContexts.end()) return it->second.get(); + throw std::out_of_range("Alpha AST context does not exist for file: " + fileName.str()); +} + +armor::ASTNormalizedContext* armor::APISession::getBetaContext(const std::string& fileName) const { + auto it = m_betaContexts.find(fileName); + if (it != m_betaContexts.end()) return it->second.get(); + throw std::out_of_range("Beta AST context does not exist for file: " + fileName); +} + +armor::ASTNormalizedContext* armor::APISession::getBetaContext(llvm::StringRef fileName) const { + auto it = m_betaContexts.find(fileName); + if (it != m_betaContexts.end()) return it->second.get(); + throw std::out_of_range("Beta AST context does not exist for file: " + fileName.str()); +} diff --git a/src/common/src/tree_builder_utils.cpp b/src/common/src/tree_builder_utils.cpp index e933419..95429c0 100644 --- a/src/common/src/tree_builder_utils.cpp +++ b/src/common/src/tree_builder_utils.cpp @@ -6,6 +6,7 @@ #include "nsr_generator.hpp" #include "qualified_name_generator.hpp" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/Lex/Lexer.h" @@ -16,9 +17,9 @@ clang::QualType unwrapType(clang::QualType type) { if (type.isNull()) return type; - + while (true) { - + clang::QualType unqualifiedType = type.getUnqualifiedType(); if (unqualifiedType != type) { type = unqualifiedType; @@ -27,16 +28,16 @@ clang::QualType unwrapType(clang::QualType type) { if (const auto* parenType = type->getAs()) { type = parenType->getInnerType(); - } + } else if (type->isPointerType() || type->isReferenceType()) { type = type->getPointeeType(); - } + } else if (const auto* arrayType = type->getAsArrayTypeUnsafe()) { type = arrayType->getElementType(); - } + } else if (const auto* attributedType = type->getAs()) { type = attributedType->getModifiedType(); - } + } else break; } return type; @@ -60,7 +61,7 @@ std::pair unwrapTypeLoc(clang::TypeLoc TL) { TL = TL.getUnqualifiedLoc(); unwrappedThisIteration = true; } - + switch (TL.getTypePtr()->getTypeClass()) { case clang::Type::Pointer: modifiers.emplace_back("*"); @@ -88,7 +89,7 @@ std::pair unwrapTypeLoc(clang::TypeLoc TL) { TL = TL.getAs().getElementLoc(); unwrappedThisIteration = true; break; - + default: break; } @@ -137,13 +138,13 @@ AccessSpec getAccessSpecifier(const clang::AccessSpecifier spec) { } const std::string generateUSRForDecl(const clang::Decl * Decl){ - - if (llvm::isa(Decl)|| llvm::isa(Decl) + + if (llvm::isa(Decl)|| llvm::isa(Decl) || llvm::isa(Decl) || llvm::isa(Decl)) { armor::info() << "No USR for Param type declerations \n"; return std::string{}; } - + llvm::SmallString<256> Buf; armor::generateUSRForDecl(Decl, Buf); @@ -153,7 +154,7 @@ const std::string generateUSRForDecl(const clang::Decl * Decl){ const std::string generateNSRForDecl(const clang::Decl * Decl){ - if (llvm::isa(Decl)|| llvm::isa(Decl) + if (llvm::isa(Decl)|| llvm::isa(Decl) || llvm::isa(Decl) || llvm::isa(Decl)) { armor::info() << "No NSR for Param type declerations \n"; return std::string{}; @@ -168,24 +169,24 @@ const std::string generateNSRForDecl(const clang::Decl * Decl){ const std::pair getTypesWithAndWithoutTypeResolution(const clang::QualType T, const clang::ASTContext &Ctx) { - + if (T.isNull()) { return {std::string{}, std::string{}}; } - + clang::PrintingPolicy Policy1(Ctx.getLangOpts()); Policy1.SuppressTagKeyword = false; Policy1.SuppressScope = false; Policy1.FullyQualifiedName = true; Policy1.AnonymousTagLocations = false; Policy1.PrintCanonicalTypes = false; - + std::string TypeStr; llvm::raw_string_ostream OS(TypeStr); - + try { T.print(OS, Policy1); - } + } catch (...) { TypeStr = std::string{}; } @@ -203,22 +204,22 @@ const std::pair getTypesWithAndWithoutTypeR try { T.getCanonicalType().print(COS, Policy2); - } + } catch (...) { CanonicalTypeStr = std::string{}; } - + return {TypeStr,CanonicalTypeStr}; - + } const std::string generateQualifiedNameForDecl(const clang::NamedDecl *Decl){ - if (llvm::isa(Decl)|| llvm::isa(Decl) + if (llvm::isa(Decl)|| llvm::isa(Decl) || llvm::isa(Decl) || llvm::isa(Decl)) { armor::info() << "No QualifiedName for Param type declerations \n"; return std::string{}; } - + llvm::SmallString<256> Buf; armor::generateQualifiedNameForDecl(Decl, Buf); @@ -226,12 +227,40 @@ const std::string generateQualifiedNameForDecl(const clang::NamedDecl *Decl){ } const std::string generateHash( llvm::StringRef qualifiedName , const NodeKind& node ){ - + llvm::SmallString<128> hashBuf; llvm::raw_svector_ostream OS(hashBuf); OS << serialize(node) << ":" << qualifiedName; - + return hashBuf.c_str(); -} \ No newline at end of file +} + +bool isInlineForwardDeclOfDeclType(const clang::CXXRecordDecl* Decl) { + + if (Decl->isThisDeclarationADefinition()) return false; + + const clang::Decl* next = Decl->getNextDeclInContext(); + if (!next) return false; + + clang::QualType FT; + + if (const auto* FD = llvm::dyn_cast(next)) + FT = unwrapType(FD->getType()); + else if (const auto* FnD = llvm::dyn_cast(next)){ + FT = unwrapType(FnD->getReturnType()); + } + else if (const auto* VD = llvm::dyn_cast(next)) + FT = unwrapType(VD->getType()); + else if (const auto* TD = llvm::dyn_cast(next)) + FT = unwrapType(TD->getUnderlyingType()); + else return false; + + if (FT.isNull()) return false; + + const clang::CXXRecordDecl* RD = FT->getAsCXXRecordDecl(); + if (!RD) return false; + + return RD->getCanonicalDecl()->Equals(Decl->getCanonicalDecl()); +} diff --git a/src/tests/__init__.py b/src/tests/__init__.py index 6ffd676..21749a9 100644 --- a/src/tests/__init__.py +++ b/src/tests/__init__.py @@ -1,3 +1,2 @@ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. # SPDX-License-Identifier: BSD-3-Clause -# Make tests directory a Python package \ No newline at end of file diff --git a/src/tests/alpha/src/CMakeLists.txt b/src/tests/alpha/CMakeLists.txt similarity index 88% rename from src/tests/alpha/src/CMakeLists.txt rename to src/tests/alpha/CMakeLists.txt index 1307028..c5620c6 100644 --- a/src/tests/alpha/src/CMakeLists.txt +++ b/src/tests/alpha/CMakeLists.txt @@ -24,7 +24,6 @@ target_compile_definitions(alpha PRIVATE TESTING_ENABLED=1) # Include project headers target_include_directories(alpha PRIVATE - ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/common/include ${CMAKE_SOURCE_DIR}/src/alpha/include ${LLVM_INCLUDE_DIRS} @@ -41,6 +40,3 @@ target_link_libraries(alpha nlohmann_json::nlohmann_json CLI11::CLI11 ) - -# Enable testing mode -target_compile_definitions(alpha PRIVATE TESTING_ENABLED=1) diff --git a/src/tests/alpha/__init__.py b/src/tests/alpha/__init__.py index 9924184..21749a9 100644 --- a/src/tests/alpha/__init__.py +++ b/src/tests/alpha/__init__.py @@ -1,3 +1,2 @@ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. # SPDX-License-Identifier: BSD-3-Clause -# Make alpha directory a Python package \ No newline at end of file diff --git a/src/tests/alpha/functional/__init__.py b/src/tests/alpha/functional/__init__.py index d920b29..21749a9 100644 --- a/src/tests/alpha/functional/__init__.py +++ b/src/tests/alpha/functional/__init__.py @@ -1,3 +1,2 @@ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. # SPDX-License-Identifier: BSD-3-Clause -# Make functional directory a Python package \ No newline at end of file diff --git a/src/tests/alpha/functional/anonymous_type_changes/__init__.py b/src/tests/alpha/functional/anonymous_type_changes/__init__.py deleted file mode 100644 index 21749a9..0000000 --- a/src/tests/alpha/functional/anonymous_type_changes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/alpha/functional/anonymous_type_changes/expected_output.json b/src/tests/alpha/functional/anonymous_type_changes/expected_output.json deleted file mode 100644 index f7bf961..0000000 --- a/src/tests/alpha/functional/anonymous_type_changes/expected_output.json +++ /dev/null @@ -1,35 +0,0 @@ -[ - { - "children": [ - { - "children": [ - { - "children": [ - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "funcPtr::1", - "tag": "removed" - }, - { - "dataType": "float", - "nodeType": "Parameter", - "qualifiedName": "funcPtr::1", - "tag": "added" - } - ], - "nodeType": "Parameter", - "qualifiedName": "funcPtr::1", - "tag": "modified" - } - ], - "nodeType": "FunctionPointer", - "qualifiedName": "funcPtr", - "tag": "modified" - } - ], - "nodeType": "Variable", - "qualifiedName": "funcPtr", - "tag": "modified" - } -] \ No newline at end of file diff --git a/src/tests/alpha/functional/anonymous_type_changes/test_alpha_anonymous_type_changes.py b/src/tests/alpha/functional/anonymous_type_changes/test_alpha_anonymous_type_changes.py deleted file mode 100644 index eaae678..0000000 --- a/src/tests/alpha/functional/anonymous_type_changes/test_alpha_anonymous_type_changes.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause -import os -import json -import subprocess -from deepdiff import DeepDiff - - -def test_cpp_ast_diff(binary_path, binary_args, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} - -def test_c_ast_diff(binary_path, binary_args_c, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args_c, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} diff --git a/src/tests/alpha/functional/anonymous_type_changes/v1/mylib.h b/src/tests/alpha/functional/anonymous_type_changes/v1/mylib.h deleted file mode 100644 index d1c3b33..0000000 --- a/src/tests/alpha/functional/anonymous_type_changes/v1/mylib.h +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -// Normal enum -typedef enum { - POWER_LOW, - POWER_MEDIUM, - POWER_HIGH -} PowerLevel; - -// Normal struct -typedef struct { - int voltage; - PowerLevel level; -} PowerConfig; - -// Struct with nested types -typedef struct { - int id; - char label[32]; - - // Nested enum - enum { - MODE_OFF, - MODE_ON, - MODE_STANDBY - } mode; - - enum { - MODE_POWER_SAVING, - MODE_PERFORMANCE, - } mode2; - - float y; - - // Nested struct - struct { - int year; - int month; - int day; - } manufactureDate; - - double x; - - struct test{ - int a; - int b; - }; - -} Device; - -// Struct with nested enum and struct -typedef struct { - char systemName[64]; - int deviceCount; - - struct { - Device devices[10]; - - enum { - STATUS_OK, - STATUS_FAIL, - STATUS_UNKNOWN - } systemStatus; - - struct { - int a; - int b; - - struct beta{ - int a; - int b; - }; - - enum{ - alpha, - beta - }; - - struct{ - int x; - int y; - }; - - struct{ - int a; - int b; - } gamma; - - } alpha; - - - typedef struct{ - int a; - int b; - } gamma; - - } systemDetails; - - int x; - - struct { - int ok; - }; - - int y; - - enum{ - alpha, - beta - }; - -} System; - - -enum{ - alpha, - beta -}; - - -struct{ - int a; - int b; -} alpha_beta; - -typedef Device i; - -typedef i k; - -int (*********** funcPtr )( int , float ); - -Device ***** *const* ** y; - -Device ** *const ** a [30][10][200][20]; - -int ***const*** omega; - -typedef Device******const********* mydefptr; - -typedef int myInt; - -typedef myInt asMyInt; \ No newline at end of file diff --git a/src/tests/alpha/functional/anonymous_type_changes/v2/mylib.h b/src/tests/alpha/functional/anonymous_type_changes/v2/mylib.h deleted file mode 100644 index cae7434..0000000 --- a/src/tests/alpha/functional/anonymous_type_changes/v2/mylib.h +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -// Normal enum -typedef enum { - POWER_LOW, - POWER_MEDIUM, - POWER_HIGH -} PowerLevel; - -// Normal struct -typedef struct { - int voltage; - PowerLevel level; -} PowerConfig; - -// Struct with nested types -typedef struct { - int id; - char label[32]; - - // Nested enum - enum { - MODE_OFF, - MODE_ON, - MODE_STANDBY - } mode; - - enum { - MODE_POWER_SAVING, - MODE_PERFORMANCE, - } mode2; - - float y; - - // Nested struct - struct { - int year; - int month; - int day; - } manufactureDate; - - double x; - - struct test{ - int a; - char b; - }; - -} Device; - -// Struct with nested enum and struct -typedef struct { - char systemName[60]; - int deviceCount; - - struct { - Device devices[5]; - - enum { - STATUS_OK, - STATUS_FAIL - } systemStatus; - - struct { - int a; - int b; - - struct beta{ - int a; - int b; - }; - - enum{ - alpha, - beta - }; - - struct{ - int x; - double y; - }; - - struct{ - int a; - int b; - typedef struct{ - int a; - int b; - } omega; - } gamma; - - } alpha; - - typedef Device myDevice; - - typedef struct{ - int a; - float b; - } gamma; - - } systemDetails; - - int x; - - struct { - int ok; - }; - - int y; - - enum{ - alpha, - beta - }; - -} System; - - -enum{ - alpha, - beta -}; - - -struct{ - int a; - float b; -} alpha_beta; - -typedef Device i; - -typedef i k; - -int (*********** funcPtr )( float , float ); - -Device ***** *const* ** y; - -Device ** *const ** a [30][10][200][20]; - -int ***const*** omega; - -typedef Device******const******** mydefptr; - -typedef int myInt; - -typedef myInt asMyInt; \ No newline at end of file diff --git a/src/tests/alpha/functional/conftest.py b/src/tests/alpha/functional/conftest.py index 01c4235..cc15b79 100644 --- a/src/tests/alpha/functional/conftest.py +++ b/src/tests/alpha/functional/conftest.py @@ -20,7 +20,7 @@ def get_build_dir(): @pytest.fixture def binary_path(): """Returns the absolute path to the binary.""" - return os.path.join(get_build_dir(), "src/tests/alpha/src/alpha") + return os.path.join(get_build_dir(), "src/tests/alpha/alpha") @pytest.fixture def binary_args(request): @@ -36,7 +36,7 @@ def dependent_binary_args(request): curr_dir = os.path.dirname(request.fspath) prj_root1 = os.path.join(curr_dir, "v1") prj_root2 = os.path.join(curr_dir, "v2") - return [prj_root1, prj_root2, "mylib.h","-Iinclude", "--dump-ast-diff", "-r", "json"] + return [prj_root1, prj_root2, "mylib.h","-Iinclude"] @pytest.fixture def binary_args_c(request): @@ -44,4 +44,4 @@ def binary_args_c(request): curr_dir = os.path.dirname(request.fspath) prj_root1 = os.path.join(curr_dir, "v1") prj_root2 = os.path.join(curr_dir, "v2") - return [prj_root1, prj_root2, "mylib.h", "--lang", "c", "--dump-ast-diff", "-r", "json"] + return [prj_root1, prj_root2, "mylib.h", "--lang", "c"] diff --git a/src/tests/alpha/functional/enum_changes/__init__.py b/src/tests/alpha/functional/enum_changes/__init__.py deleted file mode 100644 index 21749a9..0000000 --- a/src/tests/alpha/functional/enum_changes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/alpha/functional/enum_changes/expected_output.json b/src/tests/alpha/functional/enum_changes/expected_output.json deleted file mode 100644 index b765d98..0000000 --- a/src/tests/alpha/functional/enum_changes/expected_output.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "children": [ - { - "dataType": "unsigned int", - "nodeType": "Enumerator", - "qualifiedName": "Color::C", - "tag": "added" - } - ], - "nodeType": "Enum", - "qualifiedName": "Color", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "unsigned int", - "nodeType": "Enumerator", - "qualifiedName": "Color1::G", - "tag": "removed" - } - ], - "nodeType": "Enum", - "qualifiedName": "Color1", - "tag": "modified" - } -] \ No newline at end of file diff --git a/src/tests/alpha/functional/enum_changes/test_alpha_enum_changes.py b/src/tests/alpha/functional/enum_changes/test_alpha_enum_changes.py deleted file mode 100644 index a68ad16..0000000 --- a/src/tests/alpha/functional/enum_changes/test_alpha_enum_changes.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause -import os -import json -import subprocess -from deepdiff import DeepDiff - - -def test_cpp_ast_diff(binary_path, binary_args, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} - -def test_c_ast_diff(binary_path, binary_args_c, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args_c, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} \ No newline at end of file diff --git a/src/tests/alpha/functional/enum_changes/v1/mylib.h b/src/tests/alpha/functional/enum_changes/v1/mylib.h deleted file mode 100644 index 65b911c..0000000 --- a/src/tests/alpha/functional/enum_changes/v1/mylib.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -enum Color { - A, - B -}; - -enum Color1 { - E, - F, - G -}; - -enum Color2 { - H, - I, - J -}; diff --git a/src/tests/alpha/functional/enum_changes/v2/mylib.h b/src/tests/alpha/functional/enum_changes/v2/mylib.h deleted file mode 100644 index 02c6c58..0000000 --- a/src/tests/alpha/functional/enum_changes/v2/mylib.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -// Add -enum Color { - A, - B, - C -}; - -// Remove -enum Color1 { - E, - F -}; - -// Change Order -enum Color2 { - H, - I, - J -}; \ No newline at end of file diff --git a/src/tests/alpha/functional/fatal_errors/expected_output.json b/src/tests/alpha/functional/fatal_errors/expected_output.json index 3702aed..631336b 100644 --- a/src/tests/alpha/functional/fatal_errors/expected_output.json +++ b/src/tests/alpha/functional/fatal_errors/expected_output.json @@ -1,92 +1,20 @@ { - "astDiff": [ - { - "children": [ - { - "dataType": "string_t", - "nodeType": "Field", - "qualifiedName": "Person::name" - }, - { - "dataType": "uint_t", - "nodeType": "Field", - "qualifiedName": "Person::age" - }, - { - "dataType": "float", - "nodeType": "Field", - "qualifiedName": "Person::height" - } - ], - "nodeType": "Struct", - "qualifiedName": "Person", - "tag": "removed" - }, - { - "children": [ - { - "dataType": "math_func_t", - "nodeType": "Parameter", - "qualifiedName": "apply_math::1" - }, - { - "dataType": "float", - "nodeType": "Parameter", - "qualifiedName": "apply_math::2" - }, - { - "dataType": "float", - "nodeType": "ReturnType", - "qualifiedName": "apply_math::(ReturnType)" - } - ], - "nodeType": "Function", - "qualifiedName": "apply_math", - "tag": "removed" - }, - { - "children": [ - { - "dataType": "operation_t", - "nodeType": "Parameter", - "qualifiedName": "perform_operation::1" - }, - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "perform_operation::2" - }, - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "perform_operation::3" - }, - { - "dataType": "int", - "nodeType": "ReturnType", - "qualifiedName": "perform_operation::(ReturnType)" - } - ], - "nodeType": "Function", - "qualifiedName": "perform_operation", - "tag": "removed" - } - ], + "astDiff": [], "headerResolutionFailures": [ { - "file": "/local/mnt/workspace/sw_sw_tools/API_Compatibility_Checker/src/tests/alpha/functional/fatal_errors/v1/include/types.h", + "file": "/local/mnt/workspace/sw_sw_tools/ARMOR_DEBUG/src/tests/alpha/functional/fatal_errors/v1/include/types.h", "header": "utils.h" }, { - "file": "/local/mnt/workspace/sw_sw_tools/API_Compatibility_Checker/src/tests/alpha/functional/fatal_errors/v1/mylib.h", + "file": "/local/mnt/workspace/sw_sw_tools/ARMOR_DEBUG/src/tests/alpha/functional/fatal_errors/v1/mylib.h", "header": "comm_def.h" }, { - "file": "/local/mnt/workspace/sw_sw_tools/API_Compatibility_Checker/src/tests/alpha/functional/fatal_errors/v2/include/types.h", + "file": "/local/mnt/workspace/sw_sw_tools/ARMOR_DEBUG/src/tests/alpha/functional/fatal_errors/v2/include/types.h", "header": "utils.h" }, { - "file": "/local/mnt/workspace/sw_sw_tools/API_Compatibility_Checker/src/tests/alpha/functional/fatal_errors/v2/mylib.h", + "file": "/local/mnt/workspace/sw_sw_tools/ARMOR_DEBUG/src/tests/alpha/functional/fatal_errors/v2/mylib.h", "header": "comm_def.h" } ], diff --git a/src/tests/alpha/functional/field_variable_changes/expected_output.json b/src/tests/alpha/functional/field_variable_changes/expected_output.json deleted file mode 100644 index c9aef2c..0000000 --- a/src/tests/alpha/functional/field_variable_changes/expected_output.json +++ /dev/null @@ -1,179 +0,0 @@ -{ - "astDiff": [ - { - "children": [ - { - "children": [ - { - "dataType": "const int", - "nodeType": "Field", - "qualifiedName": "Device::max_connections", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "Device::max_connections", - "tag": "added" - } - ], - "nodeType": "Field", - "qualifiedName": "Device::max_connections", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "volatile int", - "nodeType": "Field", - "qualifiedName": "Device::status", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "Device::status", - "tag": "added" - } - ], - "nodeType": "Field", - "qualifiedName": "Device::status", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "const volatile int", - "nodeType": "Field", - "qualifiedName": "Device::control_register", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "Device::control_register", - "tag": "added" - } - ], - "nodeType": "Field", - "qualifiedName": "Device::control_register", - "tag": "modified" - }, - { - "children": [ - { - "constexpr": true, - "dataType": "const int", - "nodeType": "Field", - "qualifiedName": "Device::MAX_BUFFER_SIZE", - "storageQualifier": "Static", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "Device::MAX_BUFFER_SIZE", - "tag": "added" - } - ], - "nodeType": "Field", - "qualifiedName": "Device::MAX_BUFFER_SIZE", - "tag": "modified" - }, - { - "children": [ - { - "constexpr": true, - "dataType": "const float", - "nodeType": "Field", - "qualifiedName": "Device::DEFAULT_TEMP", - "storageQualifier": "Static", - "tag": "removed" - }, - { - "dataType": "float", - "nodeType": "Field", - "qualifiedName": "Device::DEFAULT_TEMP", - "tag": "added" - } - ], - "nodeType": "Field", - "qualifiedName": "Device::DEFAULT_TEMP", - "tag": "modified" - } - ], - "nodeType": "Struct", - "qualifiedName": "Device", - "tag": "modified" - }, - { - "children": [ - { - "nodeType": "Variable", - "qualifiedName": "thread_counter", - "storageQualifier": "Extern", - "tag": "removed" - } - ], - "nodeType": "Variable", - "qualifiedName": "thread_counter", - "tag": "modified" - }, - { - "children": [ - { - "inline": true, - "nodeType": "Variable", - "qualifiedName": "inline_global", - "tag": "removed" - } - ], - "nodeType": "Variable", - "qualifiedName": "inline_global", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "const int", - "inline": true, - "nodeType": "Variable", - "qualifiedName": "inline_const_global", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Variable", - "qualifiedName": "inline_const_global", - "tag": "added" - } - ], - "nodeType": "Variable", - "qualifiedName": "inline_const_global", - "tag": "modified" - }, - { - "children": [ - { - "constexpr": true, - "dataType": "const int", - "nodeType": "Variable", - "qualifiedName": "array_size", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Variable", - "qualifiedName": "array_size", - "tag": "added" - } - ], - "nodeType": "Variable", - "qualifiedName": "array_size", - "tag": "modified" - } - ], - "headerResolutionFailures": [], - "parsed_status": 0, - "unparsed_status": null -} \ No newline at end of file diff --git a/src/tests/alpha/functional/field_variable_changes/v1/mylib.h b/src/tests/alpha/functional/field_variable_changes/v1/mylib.h deleted file mode 100644 index 0effd19..0000000 --- a/src/tests/alpha/functional/field_variable_changes/v1/mylib.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#include - -struct Device { - int id; - const int max_connections; - volatile int status; - mutable int cache_value; - const volatile int control_register; - float temperature; - char name[32]; - uint8_t* buffer; - const char* const firmware_version; - static const int VERSION = 1; - static constexpr int MAX_BUFFER_SIZE = 1024; - static constexpr float DEFAULT_TEMP = 25.0f; -}; - -inline constexpr int INLINE_CONSTANT = 200; -static constexpr double PI = 3.14159265359; -extern thread_local int thread_counter; -inline int inline_global = 42; -inline const int inline_const_global = 99; -constexpr int array_size = 10; diff --git a/src/tests/alpha/functional/field_variable_changes/v2/mylib.h b/src/tests/alpha/functional/field_variable_changes/v2/mylib.h deleted file mode 100644 index f9a576d..0000000 --- a/src/tests/alpha/functional/field_variable_changes/v2/mylib.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause -#include - -struct Device { - int id; - int max_connections; - int status; - int cache_value; - int control_register; - float temperature; - char name[32]; - uint8_t* buffer; - const char* const firmware_version; - static const int VERSION = 1; - int MAX_BUFFER_SIZE = 1024; - float DEFAULT_TEMP = 25.0f; -}; - -inline constexpr int INLINE_CONSTANT = 200; -static constexpr double PI = 3.14159265359; -thread_local int thread_counter; -int inline_global = 42; -int inline_const_global = 99; -int array_size = 10; diff --git a/src/tests/alpha/functional/function_changes/__init__.py b/src/tests/alpha/functional/function_changes/__init__.py deleted file mode 100644 index 21749a9..0000000 --- a/src/tests/alpha/functional/function_changes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/alpha/functional/function_changes/expected_output.json b/src/tests/alpha/functional/function_changes/expected_output.json deleted file mode 100644 index 2f250bb..0000000 --- a/src/tests/alpha/functional/function_changes/expected_output.json +++ /dev/null @@ -1,300 +0,0 @@ -[ - { - "children": [ - { - "dataType": "int", - "nodeType": "ReturnType", - "qualifiedName": "diag_lsm_comm_open::(ReturnType)" - } - ], - "nodeType": "Function", - "qualifiedName": "diag_lsm_comm_open", - "tag": "removed" - }, - { - "children": [ - { - "children": [ - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_comm_write::1", - "tag": "removed" - }, - { - "dataType": "float", - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_comm_write::1", - "tag": "added" - } - ], - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_comm_write::1", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "unsigned char *", - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_comm_write::2", - "tag": "removed" - }, - { - "dataType": "unsigned char *[10]", - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_comm_write::2", - "tag": "added" - } - ], - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_comm_write::2", - "tag": "modified" - } - ], - "nodeType": "Function", - "qualifiedName": "diag_lsm_comm_write", - "tag": "modified" - }, - { - "children": [ - { - "children": [ - { - "dataType": "int", - "nodeType": "ReturnType", - "qualifiedName": "diag_lsm_comm_ioctl::(ReturnType)", - "tag": "removed" - }, - { - "dataType": "double", - "nodeType": "ReturnType", - "qualifiedName": "diag_lsm_comm_ioctl::(ReturnType)", - "tag": "added" - } - ], - "nodeType": "ReturnType", - "qualifiedName": "diag_lsm_comm_ioctl::(ReturnType)", - "tag": "modified" - } - ], - "nodeType": "Function", - "qualifiedName": "diag_lsm_comm_ioctl", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "void *", - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_ioctl::3", - "tag": "removed" - } - ], - "nodeType": "Function", - "qualifiedName": "diag_lsm_ioctl", - "tag": "modified" - }, - { - "children": [ - { - "nodeType": "Function", - "qualifiedName": "sum", - "storageQualifier": "Extern", - "tag": "removed" - } - ], - "nodeType": "Function", - "qualifiedName": "sum", - "tag": "modified" - }, - { - "children": [ - { - "inline": true, - "nodeType": "Function", - "qualifiedName": "multiply", - "tag": "removed" - }, - { - "nodeType": "Function", - "qualifiedName": "multiply", - "storageQualifier": "Static", - "tag": "added" - } - ], - "nodeType": "Function", - "qualifiedName": "multiply", - "tag": "modified" - }, - { - "children": [ - { - "nodeType": "Function", - "qualifiedName": "divide", - "storageQualifier": "Static", - "tag": "removed" - }, - { - "inline": true, - "nodeType": "Function", - "qualifiedName": "divide", - "tag": "added" - } - ], - "nodeType": "Function", - "qualifiedName": "divide", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "unsigned int *[10]", - "nodeType": "Parameter", - "qualifiedName": "diag_send_data::4", - "tag": "added" - }, - { - "children": [ - { - "dataType": "unsigned int *[10]", - "nodeType": "Parameter", - "qualifiedName": "diag_send_data::3", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "diag_send_data::3", - "tag": "added" - } - ], - "nodeType": "Parameter", - "qualifiedName": "diag_send_data::3", - "tag": "modified" - } - ], - "nodeType": "Function", - "qualifiedName": "diag_send_data", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "unsigned int *[10]", - "nodeType": "Parameter", - "qualifiedName": "diag_get_data::4", - "tag": "added" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "diag_get_data::1", - "tag": "removed" - }, - { - "dataType": "unsigned char *", - "nodeType": "Parameter", - "qualifiedName": "diag_get_data::1", - "tag": "added" - } - ], - "nodeType": "Parameter", - "qualifiedName": "diag_get_data::1", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "unsigned int *[10]", - "nodeType": "Parameter", - "qualifiedName": "diag_get_data::3", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "diag_get_data::3", - "tag": "added" - } - ], - "nodeType": "Parameter", - "qualifiedName": "diag_get_data::3", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "int ****", - "nodeType": "ReturnType", - "qualifiedName": "diag_get_data::(ReturnType)", - "tag": "removed" - }, - { - "dataType": "int ******", - "nodeType": "ReturnType", - "qualifiedName": "diag_get_data::(ReturnType)", - "tag": "added" - } - ], - "nodeType": "ReturnType", - "qualifiedName": "diag_get_data::(ReturnType)", - "tag": "modified" - } - ], - "nodeType": "Function", - "qualifiedName": "diag_get_data", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "SQUARE::1" - }, - { - "dataType": "int", - "nodeType": "ReturnType", - "qualifiedName": "SQUARE::(ReturnType)" - } - ], - "nodeType": "Function", - "qualifiedName": "SQUARE", - "tag": "added" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_comm_ioctl_v2::1" - }, - { - "dataType": "unsigned long", - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_comm_ioctl_v2::2" - }, - { - "dataType": "void *", - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_comm_ioctl_v2::3" - }, - { - "dataType": "unsigned int", - "nodeType": "Parameter", - "qualifiedName": "diag_lsm_comm_ioctl_v2::4" - }, - { - "dataType": "int", - "nodeType": "ReturnType", - "qualifiedName": "diag_lsm_comm_ioctl_v2::(ReturnType)" - } - ], - "nodeType": "Function", - "qualifiedName": "diag_lsm_comm_ioctl_v2", - "tag": "added" - } -] \ No newline at end of file diff --git a/src/tests/alpha/functional/function_changes/test_alpha_function_changes.py b/src/tests/alpha/functional/function_changes/test_alpha_function_changes.py deleted file mode 100644 index a68ad16..0000000 --- a/src/tests/alpha/functional/function_changes/test_alpha_function_changes.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause -import os -import json -import subprocess -from deepdiff import DeepDiff - - -def test_cpp_ast_diff(binary_path, binary_args, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} - -def test_c_ast_diff(binary_path, binary_args_c, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args_c, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} \ No newline at end of file diff --git a/src/tests/alpha/functional/function_changes/v1/mylib.h b/src/tests/alpha/functional/function_changes/v1/mylib.h deleted file mode 100644 index e4ad967..0000000 --- a/src/tests/alpha/functional/function_changes/v1/mylib.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -#define SQUARE(x) ((x) * (x)) - -int diag_lsm_comm_open(void); - -int diag_lsm_open(void); - -int diag_lsm_comm_write(int fd, unsigned char *buf, int bytes, int flags); - -int diag_lsm_comm_ioctl(int fd, unsigned long request, void *buf, unsigned int len); - -double diag_lsm_ioctl(int fd, unsigned long request, void *buf); - -int extern sum(int a, int b); - -int inline multiply(int a, int b); - -int static divide(int a, int b); - -// Default call convetion is -int __stdcall call_add(int a, int b); - -float __fastcall dot_product(float a, float b); - -int __attribute__((swiftcall)) swift_func(int x); - -void diag_send_data(unsigned char *, int, unsigned int *buf[10]); - -int**** diag_get_data(int, int, unsigned int *buf[10]); \ No newline at end of file diff --git a/src/tests/alpha/functional/function_changes/v2/mylib.h b/src/tests/alpha/functional/function_changes/v2/mylib.h deleted file mode 100644 index 452157d..0000000 --- a/src/tests/alpha/functional/function_changes/v2/mylib.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -// Replacing macros with functio -int SQUARE(int x); - -//#same as original -int diag_lsm_open(void); - -//#param type change -int diag_lsm_comm_write(float fd, unsigned char *buf[10], int bytes, int flags); - -//return type change -double diag_lsm_comm_ioctl(int fd, unsigned long a, void *buf, unsigned int len); - -// #param removal -double diag_lsm_ioctl(int fd, unsigned long request); - -// adding new function (pass) -int diag_lsm_comm_ioctl_v2(int fd, unsigned long request, void *buf, unsigned int len); - -// removed return type modifier -int sum(int a, int b); - -// modified return type modifier -int static multiply(int a, int b); - -// modified return type modifier -int inline divide(int a, int b); - -int __attribute__((fastcall)) call_add(int a, int b); - -float __stdcall dot_product(float a, float b); - -int __vectorcall swift_func(int x); - - -void diag_send_data(unsigned char *, int, int, unsigned int *buf[10]); - -int****** diag_get_data(unsigned char *, int, int, unsigned int *buf[10]); \ No newline at end of file diff --git a/src/tests/alpha/functional/function_pointer_changes/__init__.py b/src/tests/alpha/functional/function_pointer_changes/__init__.py deleted file mode 100644 index 21749a9..0000000 --- a/src/tests/alpha/functional/function_pointer_changes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/alpha/functional/function_pointer_changes/expected_output.json b/src/tests/alpha/functional/function_pointer_changes/expected_output.json deleted file mode 100644 index 707f1cf..0000000 --- a/src/tests/alpha/functional/function_pointer_changes/expected_output.json +++ /dev/null @@ -1,128 +0,0 @@ -[ - { - "children": [ - { - "dataType": "cb_func_ptr", - "nodeType": "ReturnType", - "qualifiedName": "fun::(ReturnType)" - } - ], - "nodeType": "Function", - "qualifiedName": "fun", - "tag": "removed" - }, - { - "children": [ - { - "children": [ - { - "children": [ - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "fun_ptr_ok::1", - "tag": "removed" - }, - { - "dataType": "int **", - "nodeType": "Parameter", - "qualifiedName": "fun_ptr_ok::1", - "tag": "added" - } - ], - "nodeType": "Parameter", - "qualifiedName": "fun_ptr_ok::1", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "ReturnType", - "qualifiedName": "fun_ptr_ok::(ReturnType)", - "tag": "removed" - }, - { - "dataType": "float", - "nodeType": "ReturnType", - "qualifiedName": "fun_ptr_ok::(ReturnType)", - "tag": "added" - } - ], - "nodeType": "ReturnType", - "qualifiedName": "fun_ptr_ok::(ReturnType)", - "tag": "modified" - } - ], - "nodeType": "FunctionPointer", - "qualifiedName": "fun_ptr_ok", - "tag": "modified" - } - ], - "nodeType": "Variable", - "qualifiedName": "fun_ptr_ok", - "tag": "modified" - }, - { - "children": [ - { - "children": [ - { - "dataType": "unsigned char *****[100][20]", - "nodeType": "Parameter", - "qualifiedName": "cb_func_ptr::1" - }, - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "cb_func_ptr::2" - }, - { - "dataType": "void ********&&", - "nodeType": "Parameter", - "qualifiedName": "cb_func_ptr::3" - }, - { - "children": [ - { - "children": [ - { - "dataType": "int *********&", - "nodeType": "Parameter", - "qualifiedName": "cb_func_ptr::4::1" - }, - { - "dataType": "int *****[20]", - "nodeType": "Parameter", - "qualifiedName": "cb_func_ptr::4::2" - }, - { - "dataType": "int", - "nodeType": "ReturnType", - "qualifiedName": "cb_func_ptr::4::(ReturnType)" - } - ], - "dataType": "****************************const *&&", - "nodeType": "FunctionPointer", - "qualifiedName": "cb_func_ptr::4" - } - ], - "nodeType": "Parameter", - "qualifiedName": "cb_func_ptr::4" - }, - { - "dataType": "int", - "nodeType": "ReturnType", - "qualifiedName": "cb_func_ptr::(ReturnType)" - } - ], - "dataType": "***const **", - "nodeType": "FunctionPointer", - "qualifiedName": "cb_func_ptr" - } - ], - "nodeType": "Variable", - "qualifiedName": "cb_func_ptr", - "tag": "added" - } -] \ No newline at end of file diff --git a/src/tests/alpha/functional/function_pointer_changes/test_alpha_function_pointer_changes.py b/src/tests/alpha/functional/function_pointer_changes/test_alpha_function_pointer_changes.py deleted file mode 100644 index 0e4380d..0000000 --- a/src/tests/alpha/functional/function_pointer_changes/test_alpha_function_pointer_changes.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause - -import os -import json -import subprocess -from deepdiff import DeepDiff - - -def test_ast_diff(binary_path, binary_args, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} - #assert not os.path.exists(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json') - diff --git a/src/tests/alpha/functional/function_pointer_changes/v1/mylib.h b/src/tests/alpha/functional/function_pointer_changes/v1/mylib.h deleted file mode 100644 index 2d70fa6..0000000 --- a/src/tests/alpha/functional/function_pointer_changes/v1/mylib.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -typedef int(******const****cb_func_ptr)(unsigned char ********a[100][20], int len, void ********&&context_data, int (******************volatile************const*&&inner_ptr)(int *********&&a, int ***** arr[10])); - -typedef cb_func_ptr ok; - -cb_func_ptr fun(); - - -typedef int (*fun_ptr)(); - -fun_ptr not_fun(); - -int(*** *volatile **** *const *fun_ptr_ok)(int a, int b); - - -typedef struct{ - cb_func_ptr ok; - typedef int(**const**cb_func_ptr)(unsigned char **a, int len, void **&&context_data, int (**volatile***const*&&inner_ptr)(int **&&a, int **arr[10])); -} alpha; \ No newline at end of file diff --git a/src/tests/alpha/functional/function_pointer_changes/v2/mylib.h b/src/tests/alpha/functional/function_pointer_changes/v2/mylib.h deleted file mode 100644 index 9a127bd..0000000 --- a/src/tests/alpha/functional/function_pointer_changes/v2/mylib.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -int(***const**cb_func_ptr)(unsigned char *****a[100][20], int len, void ********&&context_data, int (****************************const*&&inner_ptr)(int *********&a, int ***** arr[20])); - -typedef int (*fun_ptr)(); - -fun_ptr not_fun(); - -float (*** *volatile **** *const *fun_ptr_ok)(int **a, int b); - - -typedef struct{ - typedef int(**const**cb_func_ptr)(unsigned char *a[10], int len, void **&&context_data, int (**volatile***const*&inner_ptr)(int **&&a, int *arr[10])); -} alpha; \ No newline at end of file diff --git a/src/tests/alpha/functional/global_variable_changes/__init__.py b/src/tests/alpha/functional/global_variable_changes/__init__.py deleted file mode 100644 index 21749a9..0000000 --- a/src/tests/alpha/functional/global_variable_changes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/alpha/functional/global_variable_changes/expected_output.json b/src/tests/alpha/functional/global_variable_changes/expected_output.json deleted file mode 100644 index 6ecbaa9..0000000 --- a/src/tests/alpha/functional/global_variable_changes/expected_output.json +++ /dev/null @@ -1,54 +0,0 @@ -[ - { - "children": [ - { - "dataType": "int", - "nodeType": "Variable", - "qualifiedName": "v1", - "tag": "removed" - }, - { - "dataType": "unsigned int", - "nodeType": "Variable", - "qualifiedName": "v1", - "tag": "added" - } - ], - "nodeType": "Variable", - "qualifiedName": "v1", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "float", - "nodeType": "Variable", - "qualifiedName": "v2", - "storageQualifier": "Static", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Variable", - "qualifiedName": "v2", - "storageQualifier": "Extern", - "tag": "added" - } - ], - "nodeType": "Variable", - "qualifiedName": "v2", - "tag": "modified" - }, - { - "dataType": "int", - "nodeType": "Variable", - "qualifiedName": "old", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Variable", - "qualifiedName": "new_var", - "tag": "added" - } -] \ No newline at end of file diff --git a/src/tests/alpha/functional/global_variable_changes/test_alpha_global_variable_changes.py b/src/tests/alpha/functional/global_variable_changes/test_alpha_global_variable_changes.py deleted file mode 100644 index a68ad16..0000000 --- a/src/tests/alpha/functional/global_variable_changes/test_alpha_global_variable_changes.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause -import os -import json -import subprocess -from deepdiff import DeepDiff - - -def test_cpp_ast_diff(binary_path, binary_args, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} - -def test_c_ast_diff(binary_path, binary_args_c, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args_c, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} \ No newline at end of file diff --git a/src/tests/alpha/functional/global_variable_changes/v1/mylib.h b/src/tests/alpha/functional/global_variable_changes/v1/mylib.h deleted file mode 100644 index 59a3f2e..0000000 --- a/src/tests/alpha/functional/global_variable_changes/v1/mylib.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -// Original global variable -int v1; - -// Original global variable with static linkage -static float v2; - -int old; diff --git a/src/tests/alpha/functional/global_variable_changes/v2/mylib.h b/src/tests/alpha/functional/global_variable_changes/v2/mylib.h deleted file mode 100644 index d6aa231..0000000 --- a/src/tests/alpha/functional/global_variable_changes/v2/mylib.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -// Change the type to unsigned int -unsigned int v1; - -// Change the linkage -extern int v2; - -// Add -int new_var; diff --git a/src/tests/alpha/functional/sanity/__init__.py b/src/tests/alpha/functional/sanity/__init__.py deleted file mode 100644 index 21749a9..0000000 --- a/src/tests/alpha/functional/sanity/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/alpha/functional/sanity/expected_output.json b/src/tests/alpha/functional/sanity/expected_output.json deleted file mode 100644 index bb8167e..0000000 --- a/src/tests/alpha/functional/sanity/expected_output.json +++ /dev/null @@ -1,119 +0,0 @@ -[ - { - "children": [ - { - "dataType": "_Bool", - "nodeType": "Variable", - "qualifiedName": "filter_enabled", - "tag": "removed" - }, - { - "dataType": "float", - "nodeType": "Variable", - "qualifiedName": "filter_enabled", - "tag": "added" - } - ], - "nodeType": "Variable", - "qualifiedName": "filter_enabled", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "void *", - "nodeType": "Field", - "qualifiedName": "diag_callback_tbl_t::context_data", - "tag": "removed" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "diag_callback_tbl_t::inited", - "tag": "removed" - }, - { - "dataType": "float", - "nodeType": "Field", - "qualifiedName": "diag_callback_tbl_t::inited", - "tag": "added" - } - ], - "nodeType": "Field", - "qualifiedName": "diag_callback_tbl_t::inited", - "tag": "modified" - } - ], - "nodeType": "Struct", - "qualifiedName": "diag_callback_tbl_t", - "tag": "modified" - }, - { - "children": [ - { - "children": [ - { - "children": [ - { - "children": [ - { - "dataType": "unsigned char *", - "nodeType": "Parameter", - "qualifiedName": "diag_uart_tbl_t::cb_func_ptr::1", - "tag": "removed" - }, - { - "dataType": "unsigned int *", - "nodeType": "Parameter", - "qualifiedName": "diag_uart_tbl_t::cb_func_ptr::1", - "tag": "added" - } - ], - "nodeType": "Parameter", - "qualifiedName": "diag_uart_tbl_t::cb_func_ptr::1", - "tag": "modified" - } - ], - "nodeType": "FunctionPointer", - "qualifiedName": "diag_uart_tbl_t::cb_func_ptr", - "tag": "modified" - } - ], - "nodeType": "Field", - "qualifiedName": "diag_uart_tbl_t::cb_func_ptr", - "tag": "modified" - } - ], - "nodeType": "Struct", - "qualifiedName": "diag_uart_tbl_t", - "tag": "modified" - }, - { - "children": [ - { - "children": [ - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "DALSYSPropertyVar::reserved", - "tag": "removed" - }, - { - "dataType": "int[2]", - "nodeType": "Field", - "qualifiedName": "DALSYSPropertyVar::reserved", - "tag": "added" - } - ], - "nodeType": "Field", - "qualifiedName": "DALSYSPropertyVar::reserved", - "tag": "modified" - } - ], - "nodeType": "Struct", - "qualifiedName": "DALSYSPropertyVar", - "tag": "modified" - } -] \ No newline at end of file diff --git a/src/tests/alpha/functional/sanity/test_alpha_sanity.py b/src/tests/alpha/functional/sanity/test_alpha_sanity.py deleted file mode 100644 index 7742917..0000000 --- a/src/tests/alpha/functional/sanity/test_alpha_sanity.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause - -import os -import json -import subprocess -from deepdiff import DeepDiff - - -def test_ast_diff(binary_path, binary_args, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} diff --git a/src/tests/alpha/functional/sanity/v1/mylib.h b/src/tests/alpha/functional/sanity/v1/mylib.h deleted file mode 100644 index 219c70c..0000000 --- a/src/tests/alpha/functional/sanity/v1/mylib.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -#ifndef DIAG_LSM_H -#define DIAG_LSM_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - F_DIAG_EVENT_REPORT, - F_DIAG_HW_ACCELERATION, - F_DIAG_MULTI_SIM_MASK, - F_DIAG_DIAGID_BASED_CMD_PKT, - F_DIAG_DYNAMIC_ATID, - F_DIAG_DIAGID_BASED_ASYNC_PKT, -} diag_apps_feature_support_def; - -extern int diag_use_dev_node; -extern bool filter_enabled; - -typedef enum { - DB_PARSER_STATE_OFF, - DB_PARSER_STATE_ON, - DB_PARSER_STATE_LIST, - DB_PARSER_STATE_OPEN, - DB_PARSER_STATE_READ, - DB_PARSER_STATE_CLOSE, - DB_PARSER_STATE_GUID_DOWNLOADED, -} qsr4_db_file_parser_state; - -typedef enum { - QSR4_INIT, - QSR4_THREAD_CREATE, - QSR4_KILL_THREADS, - QSR4_CLEANUP -} qsr4_init_state; - -typedef enum { - THREADS_KILL, - THREADS_CLEANUP -} feature_threads_cleanup; - -typedef enum { - FILE_TYPE_QMDL2, - FILE_TYPE_QDSS, - NUM_MDLOG_FILE_TYPES -} file_types; - -/* enum to handle packet processing status */ -enum pkt_status{ - PKT_PROCESS_TEST, - PKT_PROCESS_ONGOING, - PKT_PROCESS_DONE -}; - -/* enum defined to identify packets */ -typedef enum { - CMD_RESP = 0, - LOG_PKT, - MSG_PKT, - ENCRYPTED_PKT, - EVENT_PKT, - QTRACE_PKT, - MAX_PKT_SUPPORTED, -} dmux_pkt_supported; - -typedef struct { - int cmd_code; - int subsys_id; - int subsys_cmd_code; -} __attribute__ ((packed)) diag_pkt_header_t; - -struct diag_callback_tbl_t { - int inited; - int (*cb_func_ptr)(unsigned char *, int len, void *context_data); - void *context_data; -}; - -struct diag_uart_tbl_t { - int proc_type; - int pid; - int (*cb_func_ptr)(unsigned char *, int len, void *context_data); - void *context_data; -}; - -typedef struct WLCData { - int appType, appWeight, appAttr; - WLCData(int T, int W, int A) : appType(T), appWeight(W), appAttr(A) { } -} WLCData; - - -typedef struct DALSYSPropertyVar DALSYSPropertyVar; - -struct DALSYSPropertyVar -{ - int dwType; - int dwLen; - union - { - int *pbVal; - char *pszVal; - int dwVal; - int *pdwVal; - const void *pStruct; - }Val; - int reserved; /* ADDED: Reserved array */ -}; - -#ifdef __cplusplus -} -#endif - -#endif /* DIAG_LSM_H */ diff --git a/src/tests/alpha/functional/sanity/v2/mylib.h b/src/tests/alpha/functional/sanity/v2/mylib.h deleted file mode 100644 index 52777eb..0000000 --- a/src/tests/alpha/functional/sanity/v2/mylib.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -#ifndef DIAG_LSM_H -#define DIAG_LSM_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - F_DIAG_EVENT_REPORT, - F_DIAG_HW_ACCELERATION, - F_DIAG_MULTI_SIM_MASK, - F_DIAG_DIAGID_BASED_CMD_PKT, - F_DIAG_DYNAMIC_ATID -} diag_apps_feature_support_def; - -extern int diag_use_dev_node; -extern float filter_enabled; - -typedef enum { - DB_PARSER_STATE_OFF, - DB_PARSER_STATE_ON, - DB_PARSER_STATE_LIST, - DB_PARSER_STATE_OPEN, - DB_PARSER_STATE_READ, - DB_PARSER_STATE_CLOSE, - DB_PARSER_STATE_GUID_DOWNLOADED, -} qsr4_db_file_parser_state; - -typedef enum { - QSR4_INIT, - QSR4_THREAD_CREATE, - QSR4_KILL_THREADS, - QSR4_CLEANUP -} qsr4_init_state; - -typedef enum { - THREADS_KILL, - THREADS_CLEANUP -} feature_threads_cleanup; - -typedef enum { - FILE_TYPE_QMDL2, - FILE_TYPE_QDSS, - NUM_MDLOG_FILE_TYPES -} file_types; - -/* enum to handle packet processing status */ -enum pkt_status{ - PKT_PROCESS_TEST, - PKT_PROCESS_ONGOING, - PKT_PROCESS_DONE -}; - -/* enum defined to identify packets */ -typedef enum { - CMD_RESP = 0, - LOG_PKT, - MSG_PKT, - ENCRYPTED_PKT, - EVENT_PKT, - QTRACE_PKT, - MAX_PKT_SUPPORTED, -} dmux_pkt_supported; - -typedef struct { - int cmd_code; - int subsys_id; - int subsys_cmd_code; -} __attribute__ ((packed)) diag_pkt_header_t; - -struct diag_callback_tbl_t { - float inited; - int (*cb_func_ptr)(unsigned char *, int len, void *context_data); -}; - -struct diag_uart_tbl_t { - int proc_type; - int pid; - int (*cb_func_ptr)(unsigned int *, int len, void *context_data); - void *context_data; -}; - -typedef struct WLCData { - int appType, appWeight; - WLCData(int T, int A) : appType(T), appWeight(A) { } -} WLCData; - - -typedef struct DALSYSPropertyVar DALSYSPropertyVar; - -struct DALSYSPropertyVar -{ - int dwType; - int dwLen; - union - { - int *pbVal; - char *pszVal; - int dwVal; - int *pdwVal; - const void *pStruct; - int qwVal; /* ADDED: 64-bit value */ - float fVal; /* ADDED: Float value */ - }Val; - int reserved[2]; /* ADDED: Reserved array */ -}; - -#ifdef __cplusplus -} -#endif - -#endif /* DIAG_LSM_H */ diff --git a/src/tests/alpha/functional/struct_changes/__init__.py b/src/tests/alpha/functional/struct_changes/__init__.py deleted file mode 100644 index 21749a9..0000000 --- a/src/tests/alpha/functional/struct_changes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/alpha/functional/struct_changes/expected_output.json b/src/tests/alpha/functional/struct_changes/expected_output.json deleted file mode 100644 index bccdae3..0000000 --- a/src/tests/alpha/functional/struct_changes/expected_output.json +++ /dev/null @@ -1,99 +0,0 @@ -[ - { - "children": [ - { - "dataType": "char", - "nodeType": "Field", - "qualifiedName": "Record::status", - "tag": "removed" - }, - { - "dataType": "double", - "nodeType": "Field", - "qualifiedName": "Record::timestamp", - "tag": "added" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "Record::id", - "tag": "removed" - }, - { - "dataType": "long", - "nodeType": "Field", - "qualifiedName": "Record::id", - "tag": "added" - } - ], - "nodeType": "Field", - "qualifiedName": "Record::id", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "Record::diag_uart_tbl_t::pid", - "tag": "removed" - }, - { - "children": [ - { - "children": [ - { - "children": [ - { - "dataType": "int", - "nodeType": "ReturnType", - "qualifiedName": "Record::diag_uart_tbl_t::cb_func_ptr::(ReturnType)", - "tag": "removed" - }, - { - "dataType": "float", - "nodeType": "ReturnType", - "qualifiedName": "Record::diag_uart_tbl_t::cb_func_ptr::(ReturnType)", - "tag": "added" - } - ], - "nodeType": "ReturnType", - "qualifiedName": "Record::diag_uart_tbl_t::cb_func_ptr::(ReturnType)", - "tag": "modified" - } - ], - "nodeType": "FunctionPointer", - "qualifiedName": "Record::diag_uart_tbl_t::cb_func_ptr", - "tag": "modified" - } - ], - "nodeType": "Field", - "qualifiedName": "Record::diag_uart_tbl_t::cb_func_ptr", - "tag": "modified" - } - ], - "nodeType": "Struct", - "qualifiedName": "Record::diag_uart_tbl_t", - "tag": "modified" - } - ], - "nodeType": "Struct", - "qualifiedName": "Record", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "alpha::b", - "tag": "removed" - } - ], - "nodeType": "Struct", - "qualifiedName": "alpha", - "tag": "modified" - } -] \ No newline at end of file diff --git a/src/tests/alpha/functional/struct_changes/test_alpha_struct_changes.py b/src/tests/alpha/functional/struct_changes/test_alpha_struct_changes.py deleted file mode 100644 index a68ad16..0000000 --- a/src/tests/alpha/functional/struct_changes/test_alpha_struct_changes.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause -import os -import json -import subprocess -from deepdiff import DeepDiff - - -def test_cpp_ast_diff(binary_path, binary_args, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} - -def test_c_ast_diff(binary_path, binary_args_c, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args_c, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} \ No newline at end of file diff --git a/src/tests/alpha/functional/struct_changes/v1/mylib.h b/src/tests/alpha/functional/struct_changes/v1/mylib.h deleted file mode 100644 index d53affa..0000000 --- a/src/tests/alpha/functional/struct_changes/v1/mylib.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -struct Record { - - int id; - float value; - char status; - - struct diag_uart_tbl_t { - int proc_type; - int pid; - int (*cb_func_ptr)(unsigned char *, int len, void *context_data); - void *context_data; - }; - -}; - - -struct Vector{ - int x; - int y; -}; - - -struct __attribute__((packed)) Data{ - int a; - float b; -}; - -struct alpha{ - - int a; - int b; - - alpha(int a, int b); - - bool operator=(alpha a); - -}; \ No newline at end of file diff --git a/src/tests/alpha/functional/struct_changes/v2/mylib.h b/src/tests/alpha/functional/struct_changes/v2/mylib.h deleted file mode 100644 index 39d6f80..0000000 --- a/src/tests/alpha/functional/struct_changes/v2/mylib.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -// - Removed status field -// - Added timestamp field -// - Changed order of fields -// - Changed type of id from int to long -// - Removed int diag_uart_tbl_t -struct Record{ - - float value; // moved - long id; // changed type - double timestamp; // added - - struct diag_uart_tbl_t { - int proc_type; - float (*cb_func_ptr)(unsigned char *, int len, void *context_data); - void *context_data; - }; - -}; - -// - Changed Order -struct Vector{ - int y; - int x; -}; - - -//Changed Packing -struct Data{ - int a; - float b; -}; - - -struct alpha{ - - int a; - - alpha(int a, int b); - - bool operator=(alpha a); - -}; \ No newline at end of file diff --git a/src/tests/alpha/functional/template_changes/__init__.py b/src/tests/alpha/functional/template_changes/__init__.py deleted file mode 100644 index 21749a9..0000000 --- a/src/tests/alpha/functional/template_changes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/alpha/functional/template_changes/expected_output.json b/src/tests/alpha/functional/template_changes/expected_output.json deleted file mode 100644 index a45839e..0000000 --- a/src/tests/alpha/functional/template_changes/expected_output.json +++ /dev/null @@ -1,41 +0,0 @@ -[ - { - "children": [ - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "alpha::b", - "tag": "removed" - } - ], - "nodeType": "Struct", - "qualifiedName": "alpha", - "tag": "modified" - }, - { - "children": [ - { - "children": [ - { - "dataType": "const std::string &", - "nodeType": "Parameter", - "qualifiedName": "printMessage::1", - "tag": "removed" - }, - { - "dataType": "const char *", - "nodeType": "Parameter", - "qualifiedName": "printMessage::1", - "tag": "added" - } - ], - "nodeType": "Parameter", - "qualifiedName": "printMessage::1", - "tag": "modified" - } - ], - "nodeType": "Function", - "qualifiedName": "printMessage", - "tag": "modified" - } -] \ No newline at end of file diff --git a/src/tests/alpha/functional/template_changes/test_alpha_template_changes.py b/src/tests/alpha/functional/template_changes/test_alpha_template_changes.py deleted file mode 100644 index 7742917..0000000 --- a/src/tests/alpha/functional/template_changes/test_alpha_template_changes.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause - -import os -import json -import subprocess -from deepdiff import DeepDiff - - -def test_ast_diff(binary_path, binary_args, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} diff --git a/src/tests/alpha/functional/template_changes/v1/mylib.h b/src/tests/alpha/functional/template_changes/v1/mylib.h deleted file mode 100644 index fabb9e1..0000000 --- a/src/tests/alpha/functional/template_changes/v1/mylib.h +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -#include -#include -#include -#include -#include -#include -#include - -// Type aliases -using StringMap = std::map; -using IntVector = std::vector; -using StringCallback = std::function; - -// Template type aliases -template -using Dictionary = std::map; - -template -using UniquePtr = std::unique_ptr; - -// Templated variables with templated types -template -inline Dictionary empty_dictionary{}; - -// Constants -constexpr int MAX_SIZE = 100; -constexpr double PI = 3.14159265358979323846; - -// Enumerations -enum class Color { - Red, - Green, - Blue, - Yellow -}; - - -struct alpha{ - int a; - int b; -}; - -// Regular function declarations -void printMessage(const std::string& message); -int add(int a, int b); - -double calculateArea(double radius); -double calculateArea(double length, double breath); - -// Function template -template -T max(T a, T b) { - return (a > b) ? a : b; -} - -// Function template with multiple parameters -template -auto add(T a) -> decltype(a) { - return a; -} - -// Simplified - removed variadic template function - -// Simple class -class Point { -private: - double x; - double y; - -public: - Point(double x = 0.0, double y = 0.0); - double getX() const; - double getY() const; - double distance(const Point& other) const; -}; - -// Class template -template -class Container { -private: - std::vector elements; - -public: - Container() = default; - void add(const T& element); - void remove(size_t index, int a); - T& get(size_t index); - size_t size() const; -}; - -// Class template implementation -template -void Container::add(const T& element) { - elements.push_back(element); -} - -template -void Container::remove(size_t index, int a) { - if (index < elements.size()) { - elements.erase(elements.begin() + index); - } -} - -template -T& Container::get(size_t index) { - return elements.at(index); -} - -// Template with default parameter -template -class NumericValue { -private: - T value; - -public: - NumericValue(T val = T{}) : value(val) {} - void setValue(T val) { value = val; } -}; - -// Template specialization -// Simplified - removed class template specialization -template<> -class Container { -private: - std::vector elements; - -public: - Container() = default; - size_t size() const; -}; - -// Templated variable -template -constexpr T DEFAULT_VALUE = T{}; - -// Specialized templated variables -template<> -constexpr int DEFAULT_VALUE = 0; - -template<> -constexpr double DEFAULT_VALUE = 0.0; - -template<> -constexpr char DEFAULT_VALUE = '\0'; - -// Templated variable with multiple template parameters -template -inline Dictionary DEFAULT_MAP = {{DEFAULT_VALUE, DEFAULT_VALUE}}; - -// Class with templated fields -template -class Pair { -public: - U second; - - Pair(T f, U s) : second(s) {} - - // Template method within a template class - template - V convert() const { - return static_cast(second); - } -}; - -// Variable template for compile-time type checking -template -constexpr int is_numeric_v = std::is_arithmetic::value; - -// Template variable that depends on the type's properties -template -constexpr int type_size = sizeof(T); \ No newline at end of file diff --git a/src/tests/alpha/functional/template_changes/v2/mylib.h b/src/tests/alpha/functional/template_changes/v2/mylib.h deleted file mode 100644 index f939da5..0000000 --- a/src/tests/alpha/functional/template_changes/v2/mylib.h +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -#ifndef MYLIB_H -#define MYLIB_H - -#include -#include -#include -#include -#include -#include -#include - -// Type aliases -using StringMap = std::map; -using IntVector = std::vector; -using StringCallback = std::function; - -// Template type aliases -template -using Vector = std::vector; - -template -using Dictionary = std::map; - -template -using UniquePtr = std::unique_ptr; - -// Templated variables with templated types -template -inline Vector empty_vector{}; - -template -inline Dictionary empty_dictionary{}; - -template class Container = Vector> -inline Container empty_container{}; - -// Constants -constexpr int MAX_SIZE = 100; -constexpr double PI = 3.14159265358979323846; - -// Enumerations -enum class Color { - Red, - Green, - Blue, - Yellow -}; - -// Regular function declarations -void printMessage(const char* message); - -// Function template -template -T max(T a, T b) { - return (a > b) ? a : b; -} - -// Function template with multiple parameters -template -auto add(T a, U b) -> decltype(a + b) { - return a + b; -} - -// Simplified - removed variadic template function - -// Simple class -class Point { -private: - double x; - double y; - -public: - Point(double x = 0.0, double y = 0.0); - double getX() const; - double getY() const; - void setX(double x); - void setY(double y); - double distance(const Point& other) const; -}; - -// Class template -template -class Container { -private: - std::vector elements; - -public: - Container() = default; - void add(const T& element); - void remove(size_t index); - T& get(size_t index); - size_t size() const; - bool isEmpty() const; -}; - -// Class template implementation -template -void Container::add(const T& element) { - elements.push_back(element); -} - -template -void Container::remove(size_t index) { - if (index < elements.size()) { - elements.erase(elements.begin() + index); - } -} - -template -T& Container::get(size_t index) { - return elements.at(index); -} - -template -size_t Container::size() const { - return elements.size(); -} - -template -bool Container::isEmpty() const { - return elements.empty(); -} - -// Template with default parameter -template -class NumericValue { -private: - T value; - -public: - NumericValue(T val = T{}) : value(val) {} - T getValue() const { return value; } - void setValue(T val) { value = val; } -}; - -// Template specialization -// Simplified - removed class template specialization -template<> -class Container { -private: - std::vector elements; - -public: - Container() = default; - void add(bool element); - bool get(size_t index) const; - size_t size() const; -}; - -// Templated variable -template -constexpr T DEFAULT_VALUE = T{}; - -// Specialized templated variables -template<> -constexpr int DEFAULT_VALUE = 0; - -template<> -constexpr double DEFAULT_VALUE = 0.0; - -template<> -constexpr char DEFAULT_VALUE = '\0'; - -int add(int a, int b); - -// Templated variable with templated type -template -inline Vector DEFAULT_COLLECTION = Vector(3, DEFAULT_VALUE); - -// Templated variable with multiple template parameters -template -inline Dictionary DEFAULT_MAP = {{DEFAULT_VALUE, DEFAULT_VALUE}}; - -// Class with templated fields -template -class Pair { -public: - T first; - U second; - - Pair() : first(DEFAULT_VALUE), second(DEFAULT_VALUE) {} - Pair(T f, U s) : first(f), second(s) {} - - // Template method within a template class - template - V convert() const { - return static_cast(first + second); - } -}; - -struct alpha{ - int a; -}; - - -// Variable template for compile-time type checking -template -constexpr bool is_numeric_v = std::is_arithmetic::value; - -// Template variable that depends on the type's properties -template -constexpr size_t type_size = sizeof(T); - -// Templated variable with nested template types -template -inline std::pair, Dictionary> default_data_structure = { - Vector(2, DEFAULT_VALUE), - {{DEFAULT_VALUE, DEFAULT_VALUE}} -}; - -int add(int a, int b, int c); - -// Templated variable with conditional type -template -inline std::conditional_t, Vector, Dictionary> - type_appropriate_container = {}; - -double calculateArea(double radius); - -#endif // MYLIB_H \ No newline at end of file diff --git a/src/tests/alpha/functional/type_def_changes/__init__.py b/src/tests/alpha/functional/type_def_changes/__init__.py deleted file mode 100644 index 21749a9..0000000 --- a/src/tests/alpha/functional/type_def_changes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/alpha/functional/type_def_changes/expected_output.json b/src/tests/alpha/functional/type_def_changes/expected_output.json deleted file mode 100644 index 09a2b46..0000000 --- a/src/tests/alpha/functional/type_def_changes/expected_output.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "dataType": "int[0]", - "nodeType": "Variable", - "qualifiedName": "data", - "tag": "removed" - }, - { - "children": [ - { - "dataType": "struct alpha", - "nodeType": "Variable", - "qualifiedName": "alpha2", - "tag": "removed" - }, - { - "dataType": "struct alpha ***********[20]", - "nodeType": "Variable", - "qualifiedName": "alpha2", - "tag": "added" - } - ], - "nodeType": "Variable", - "qualifiedName": "alpha2", - "tag": "modified" - } -] \ No newline at end of file diff --git a/src/tests/alpha/functional/type_def_changes/test_alpha_type_def_changes.py b/src/tests/alpha/functional/type_def_changes/test_alpha_type_def_changes.py deleted file mode 100644 index a68ad16..0000000 --- a/src/tests/alpha/functional/type_def_changes/test_alpha_type_def_changes.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause -import os -import json -import subprocess -from deepdiff import DeepDiff - - -def test_cpp_ast_diff(binary_path, binary_args, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} - -def test_c_ast_diff(binary_path, binary_args_c, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args_c, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} \ No newline at end of file diff --git a/src/tests/alpha/functional/type_def_changes/v1/mylib.h b/src/tests/alpha/functional/type_def_changes/v1/mylib.h deleted file mode 100644 index 61091fb..0000000 --- a/src/tests/alpha/functional/type_def_changes/v1/mylib.h +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -#include - -// Normal enum -typedef enum { - POWER_LOW, - POWER_MEDIUM, - POWER_HIGH -} PowerLevel; - -// Normal struct -typedef struct { - int voltage; - PowerLevel level; -} PowerConfig; - -// Struct with nested types -typedef struct { - int id; - char label[32]; - - // Nested enum - typedef enum { - MODE_OFF, - MODE_ON, - MODE_STANDBY - } mode; - - // Nested struct - typedef struct { - int year; - int month; - int day; - } manufactureDate; - -} Device; - -// Struct with nested enum and struct -typedef struct { - char systemName[64]; - int deviceCount; - - typedef struct { - Device devices[10]; - - typedef enum { - STATUS_OK, - STATUS_FAIL, - STATUS_UNKNOWN - } systemStatus; - - } systemDetails; - -} System; - -typedef struct _telemetry telemetry; - -struct ok{ - int a; - int b; -}; - -typedef ok alias_ok; - -typedef struct _qurt_thread_attr { - unsigned short priority; - unsigned char autostack:1; - unsigned char group_id:6; - unsigned char reserved:1; - unsigned char bus_priority; - unsigned short timetest_id; - unsigned int stack_size; - void *stack_addr; - unsigned short detach_state; -} qurt_thread_attr_t; - - -DIAGPKT_REQ_DEFINE(DIAG_PUT_PERM_PROPERTY_F) - diag_guid_type guid; - int name[0]; - int size; - int data[0]; -DIAGPKT_REQ_END - - -typedef struct DALSYSPropertyVar DALSYSPropertyVar; - -struct DALSYSPropertyVar -{ - int dwType; - int dwLen; - union - { - int *pbVal; - int *pdwVal; - const void *pStruct; - int qwVal; /* ADDED: 64-bit value */ - float fVal; /* ADDED: Float value */ - }Val; - int reserved[2]; /* ADDED: Reserved array */ -}; - -struct alpha{ - int a; - int b; -} alpha2; - - -struct { - int a; - int b; -} beta; - -typedef struct zeta{ - int a; - int b; -} ********************const*** _zeta[20]; diff --git a/src/tests/alpha/functional/type_def_changes/v2/mylib.h b/src/tests/alpha/functional/type_def_changes/v2/mylib.h deleted file mode 100644 index 404ba0d..0000000 --- a/src/tests/alpha/functional/type_def_changes/v2/mylib.h +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -// Normal enum -typedef enum { - POWER_LOW, - POWER_MEDIUM, - POWER_HIGH -} PowerLevel; - -// Normal struct -typedef struct { - int voltage; - PowerLevel level; -} PowerConfig; - -// Struct with nested types -typedef struct { - int id; - char label[32]; - - // Nested enum - typedef enum { - MODE_OFF, - MODE_ON, - MODE_STANDBY - } mode; - - // Nested struct - typedef struct { - int year; - int month; - int day; - } manufactureDate; - -} Device; - -// Struct with nested enum and struct -typedef struct { - char systemName[63]; - int deviceCount; - - typedef struct { - Device devices[11]; - - typedef enum { - STATUS_OK, - STATUS_FAIL - } systemStatus; - - } systemDetails; - -} System; - -typedef struct telemetry telemetry; - -struct ok{ - int a; - int b; -}; - -typedef ok alias_ok; - - -typedef struct _qurt_thread_attr { - unsigned short priority; - unsigned char autostack:1; - unsigned char group_id:6; - unsigned short timetest_id; - unsigned int stack_size; - void *stack_addr; - unsigned short detach_state; -} qurt_thread_attr_t; - - -DIAGPKT_REQ_DEFINE(DIAG_PUT_PERM_PROPERTY_F) - diag_guid_type guid; - int name[0]; - int size; -DIAGPKT_REQ_END - - -typedef struct DALSYSPropertyVar _DALSYSPropertyVar; - -struct DALSYSPropertyVar -{ - int dwType; - int dwLen; - union - { - int *pbVal; - char *pszVal; - int dwVal; - int *pdwVal; - const void *pStruct; - int qwVal; /* ADDED: 64-bit value */ - float fVal; /* ADDED: Float value */ - }***********Val[20]; - int reserved[2]; /* ADDED: Reserved array */ -}; - - -struct alpha{ - int a; - int b; -} ***********alpha2[20]; - - -struct { - int a; - int b; -} *************beta[30]; - - -typedef struct zeta{ - int b; -} ******const*** _zeta[20]; diff --git a/src/tests/alpha/functional/union_changes/__init__.py b/src/tests/alpha/functional/union_changes/__init__.py deleted file mode 100644 index 21749a9..0000000 --- a/src/tests/alpha/functional/union_changes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/alpha/functional/union_changes/expected_output.json b/src/tests/alpha/functional/union_changes/expected_output.json deleted file mode 100644 index 3203675..0000000 --- a/src/tests/alpha/functional/union_changes/expected_output.json +++ /dev/null @@ -1,59 +0,0 @@ -[ - { - "children": [ - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "Data::i", - "tag": "removed" - }, - { - "dataType": "long", - "nodeType": "Field", - "qualifiedName": "Data::id", - "tag": "added" - }, - { - "children": [ - { - "dataType": "float", - "nodeType": "Field", - "qualifiedName": "Data::f", - "tag": "removed" - }, - { - "dataType": "double", - "nodeType": "Field", - "qualifiedName": "Data::f", - "tag": "added" - } - ], - "nodeType": "Field", - "qualifiedName": "Data::f", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "double", - "nodeType": "Field", - "qualifiedName": "Data::nested_union::value", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "Data::nested_union::key", - "tag": "added" - } - ], - "nodeType": "Union", - "qualifiedName": "Data::nested_union", - "tag": "modified" - } - ], - "nodeType": "Union", - "qualifiedName": "Data", - "tag": "modified" - } -] \ No newline at end of file diff --git a/src/tests/alpha/functional/union_changes/test_alpha_union_changes.py b/src/tests/alpha/functional/union_changes/test_alpha_union_changes.py deleted file mode 100644 index a68ad16..0000000 --- a/src/tests/alpha/functional/union_changes/test_alpha_union_changes.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause -import os -import json -import subprocess -from deepdiff import DeepDiff - - -def test_cpp_ast_diff(binary_path, binary_args, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} - -def test_c_ast_diff(binary_path, binary_args_c, request): - - test_dir = os.path.dirname(request.fspath) - - subprocess.run( - [binary_path] + binary_args_c, - check=True, - cwd=os.path.dirname(request.fspath) - ) - - print(test_dir) - - with open(f'{test_dir}/expected_output.json', 'r') as f: - expected_json = json.load(f) - - with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: - actual_json = json.load(f) - - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) - - assert diff == {} \ No newline at end of file diff --git a/src/tests/alpha/functional/union_changes/v1/mylib.h b/src/tests/alpha/functional/union_changes/v1/mylib.h deleted file mode 100644 index 9954544..0000000 --- a/src/tests/alpha/functional/union_changes/v1/mylib.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -union Data { - int i; - float f; - char label[10]; - - union nested_union { - int code; - double value; - }; -}; - - -union Alpha{ - int x; - int y; - union{ - int a; - int b; - }; -}; \ No newline at end of file diff --git a/src/tests/alpha/functional/union_changes/v2/mylib.h b/src/tests/alpha/functional/union_changes/v2/mylib.h deleted file mode 100644 index 32035f9..0000000 --- a/src/tests/alpha/functional/union_changes/v2/mylib.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause - -union Data { - double f; // changed type from float to double - char label[10]; // same - long id; // added new member - - union nested_union { - int code; - int key; // Removed value and Added key - }; - -}; - -// Changed order -union Alpha{ - int y; - int x; -}; \ No newline at end of file diff --git a/src/tests/alpha/src/main.cpp b/src/tests/alpha/src/main.cpp index 4f21742..1e66e7e 100644 --- a/src/tests/alpha/src/main.cpp +++ b/src/tests/alpha/src/main.cpp @@ -1,11 +1,8 @@ // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause - #include "options_handler.hpp" int main(int argc, const char **argv) { - if (!runArmorTool(argc, argv)) { - return 1; - } + runArmorTool(argc, argv); return 0; } \ No newline at end of file diff --git a/src/tests/alpha/src/options_handler.cpp b/src/tests/alpha/src/options_handler.cpp index 99a7fe8..9fae903 100644 --- a/src/tests/alpha/src/options_handler.cpp +++ b/src/tests/alpha/src/options_handler.cpp @@ -8,7 +8,7 @@ #include "CLI/CLI.hpp" #include "llvm/Support/raw_ostream.h" #include "options_handler.hpp" -#include "alpha/include/header_processor.hpp" +#include "header_processor.hpp" #include "logger.hpp" #ifndef TOOL_VERSION @@ -16,181 +16,80 @@ #endif LANG_OPTIONS stringToLangOption(const std::string& lang) { - // Convert to lowercase for case-insensitive comparison std::string lowerLang = lang; std::transform(lowerLang.begin(), lowerLang.end(), lowerLang.begin(), [](unsigned char c){ return std::tolower(c); }); - - if (lowerLang == LANG_C) { - return LANG_OPTIONS::C; - } else if (lowerLang == LANG_CPP) { - return LANG_OPTIONS::CPP; - } - return LANG_OPTIONS::CPP; // default to C++ -} - -bool filesAreDifferentUsingDiff(const std::string &file1, const std::string &file2) { - std::string command = "diff -q " + file1 + " " + file2 + " > /dev/null"; - return std::system(command.c_str()) != 0; + if (lowerLang == LANG_C) return LANG_OPTIONS::C; + if (lowerLang == LANG_CPP) return LANG_OPTIONS::CPP; + return LANG_OPTIONS::CPP; } bool runArmorTool(int argc, const char **argv) { - CLI::App app{"ARMOR"}; + CLI::App app{"ARMOR alpha — fatal parse error checker"}; std::string projectRoot1; std::string projectRoot2; std::vector headers; - std::string headerSubDir; - std::string reportFormat = "html"; - std::string language = LANG_CPP; // default to C++ - bool dumpAstDiff = false; - std::string debugLevel = ""; + std::string language = LANG_CPP; + std::string debugLevel; std::vector IncludePaths; - std::vector macros; std::string macroFlags; - auto fmt = std::make_shared(); - fmt->column_width(40); - app.formatter(fmt); - // Positional arguments - app.add_option("projectroot1", projectRoot1, "Path to the project root dir of the older version")->required(); - app.add_option("projectroot2", projectRoot2, "Path to the project root dir of the newer version")->required(); - app.add_option("headers", headers, - "List of header files to compare between the two versions.\n" - "\n" - "Header path interpretation depends on whether --header-dir is provided:\n" - "\n" - " With --header-dir:\n" - " Headers are treated as basenames (e.g., \"foo.h\") under the specified subdirectory.\n" - " Example:\n" - " --header-dir include/api foo.h bar.hpp\n" - "\n" - " • Without --header-dir:\n" - " Headers must be relative paths from the project root.\n" - " Example:\n" - " include/api/foo.h include/api/bar.hpp\n" - ); - // Optional arguments - app.add_option("--header-dir", headerSubDir, "Subdirectory under each project root containing headers"); - app.add_option("--report-format,-r", reportFormat, "Report format: html (default).\n" - "If json is provided, both html and json reports will be generated.") - ->check(CLI::IsMember({"html", "json"})); - app.add_option("--lang,-l", language, "Language mode: cpp (default) or c.\n" - "Use 'c' for C headers, 'cpp' for C++ headers.") - ->transform(CLI::IsMember({LANG_C, LANG_CPP}, CLI::ignore_case)); - app.add_flag("--dump-ast-diff", dumpAstDiff, "Dump AST diff JSON files for debugging"); - app.set_version_flag("--version,-v", TOOL_VERSION); - app.add_option("--log-level", debugLevel, "Set debug log level: ERROR, LOG, INFO (default), DEBUG") - ->check(CLI::IsMember({"ERROR", "LOG", "INFO", "DEBUG"})); + std::vector macros; - app.add_option("-I,--include-paths", IncludePaths, - "Include paths for header dependencies.\n" - "Example: -I path/to/include1 -I path/to/include2"); - app.add_option("-m,--macro-flags", macroFlags, - "Macro flags to be passed for headers.\n"); + app.add_option("projectroot1", projectRoot1, "Path to the baseline project root")->required(); + app.add_option("projectroot2", projectRoot2, "Path to the newer project root")->required(); + app.add_option("headers", headers, "Header files (relative to project root) to check"); + app.add_option("--lang,-l", language, "Language: cpp (default) or c") + ->transform(CLI::IsMember({LANG_C, LANG_CPP}, CLI::ignore_case)); + app.add_option("--log-level", debugLevel, "Log level: ERROR, LOG, INFO, DEBUG") + ->check(CLI::IsMember({"ERROR", "LOG", "INFO", "DEBUG"})); + app.add_option("-I,--include-paths", IncludePaths, "Extra include paths"); + app.add_option("-m,--macro-flags", macroFlags, "Macro flags"); + app.set_version_flag("--version,-v", TOOL_VERSION); CLI11_PARSE(app, argc, argv); + std::istringstream iss(macroFlags); std::string flag; - while (iss >> flag) { - macros.push_back(flag); - } + while (iss >> flag) macros.push_back(flag); DebugConfig& debugConfig = DebugConfig::getInstance(); debugConfig.initialize(); + if (debugLevel == "DEBUG") debugConfig.setLevel(DebugConfig::Level::DEBUG); + else if (debugLevel == "INFO") debugConfig.setLevel(DebugConfig::Level::INFO); + else if (debugLevel == "LOG") debugConfig.setLevel(DebugConfig::Level::WARNING); + else if (debugLevel == "ERROR") debugConfig.setLevel(DebugConfig::Level::ERROR); + else debugConfig.setLevel(DebugConfig::Level::NONE); - // Set level and announce (now goes to the file) - if (debugLevel == "DEBUG") { - debugConfig.setLevel(DebugConfig::Level::DEBUG); - armor::info() << "Debug level set to DEBUG"; - } else if (debugLevel == "INFO") { - debugConfig.setLevel(DebugConfig::Level::INFO); - armor::info() << "Debug level set to INFO"; - } else if (debugLevel == "WARNING") { - debugConfig.setLevel(DebugConfig::Level::WARNING); - armor::info() << "Debug level set to WARNING"; - } else if (debugLevel == "ERROR") { - debugConfig.setLevel(DebugConfig::Level::ERROR); - armor::info() << "Debug level set to ERROR"; - } - else{ - debugConfig.setLevel(DebugConfig::Level::NONE); - } - - // Convert language string to LANG_OPTIONS enum LANG_OPTIONS langOption = stringToLangOption(language); - armor::info() << "Language mode set to: " << language << "\n"; - bool processed = false; - std::vector headersToCompare; - if (!headers.empty()) { - for (const auto &header : headers) { - std::string file1, file2; - if (!headerSubDir.empty()) { - file1 = projectRoot1 + "/" + headerSubDir + "/" + header; - file2 = projectRoot2 + "/" + headerSubDir + "/" + header; - } else { - file1 = projectRoot1 + "/" + header; - file2 = projectRoot2 + "/" + header; - } - armor::user_print() << "Processing files: " << file1 << " " << file2; - if (!std::filesystem::exists(file1)) { - armor::user_error() << "Missing header in older version: " << file1; - } else if (!std::filesystem::exists(file2)) { - armor::user_error() << "Missing header in newer version: " << file2; - } else if (filesAreDifferentUsingDiff(file1, file2)) { - processHeaderPairAlpha(projectRoot1, file1, projectRoot2, file2, reportFormat, - IncludePaths, macros, langOption); - processed = true; - } - else { - armor::user_print() << "No differences found between: " << file1 << " and " << file2; - return true; - } - } + if (headers.empty()) { + armor::user_error() << "No headers specified. Usage: alpha \n"; + return false; } - else if (!headerSubDir.empty()) { - std::string dir1 = projectRoot1 + "/" + headerSubDir; - std::string dir2 = projectRoot2 + "/" + headerSubDir; - for (const auto &entry : std::filesystem::directory_iterator(dir1)) { - if (entry.path().extension() == ".h" || entry.path().extension() == ".hpp") { - headersToCompare.push_back(entry.path().filename().string()); - } - } - armor::user_print() << "List of headers to process:"; - for (const auto &h : headersToCompare) { - armor::user_print() << " " << h; + + for (const auto& header : headers) { + std::string file1 = projectRoot1 + "/" + header; + std::string file2 = projectRoot2 + "/" + header; + + if (!std::filesystem::exists(file1)) { + armor::user_error() << "Missing header in older version: " << file1 << "\n"; + continue; } - for (const auto &header : headersToCompare) { - std::string file1 = dir1 + "/" + header; - std::string file2 = dir2 + "/" + header; - armor::user_print() << "Processing files: " << file1 << " " << file2; - if (!std::filesystem::exists(file1)) { - armor::user_error() << "Missing header in older version: " << file1; - } - else if (!std::filesystem::exists(file2)) { - armor::user_error() << "Missing header in newer version: " << file2; - } - else if (filesAreDifferentUsingDiff(file1, file2)) { - processHeaderPairAlpha(projectRoot1, file1, projectRoot2, file2, reportFormat, - IncludePaths, macros, langOption); - processed = true; - } - else { - armor::user_print() << "No differences found between: " << file1 << " and " << file2; - return true; - } + if (!std::filesystem::exists(file2)) { + armor::user_error() << "Missing header in newer version: " << file2 << "\n"; + continue; } - } - if (processed && !dumpAstDiff) { - try { - std::filesystem::remove_all("debug_output/ast_diffs"); - } catch (const std::exception &e) { - armor::user_error() << "Failed to remove debug_output directory: " << e.what(); + + armor::user_print() << "Alpha checking: " << header << "\n"; + PARSING_STATUS status = armor::alpha::processHeaderPairAlpha( + projectRoot1, file1, projectRoot2, file2, + "json", IncludePaths, macros, langOption); + + if (status == FATAL_ERRORS) { + armor::user_error() << "Fatal parse errors detected in: " << header << "\n"; + } else { + armor::user_print() << "No fatal errors in: " << header << "\n"; } } - if (!processed && headers.empty() && headerSubDir.empty()) { - const std::string argv0 = argv[0] ? std::string(argv[0]) : std::string("armor"); - armor::user_error() << "Usage: " << argv0 << " ...\n" - << "Or use --header-dir to compare all headers in a subdirectory.\n" - << "Try '" << argv0 << " --help' for more information."; - } - return processed; + + return true; } diff --git a/src/tests/armor/src/CMakeLists.txt b/src/tests/armor/CMakeLists.txt similarity index 100% rename from src/tests/armor/src/CMakeLists.txt rename to src/tests/armor/CMakeLists.txt diff --git a/src/tests/armor/functional/alpha_parsing/expected_output.json b/src/tests/armor/functional/alpha_parsing/expected_output.json index 1d34cc3..781292e 100644 --- a/src/tests/armor/functional/alpha_parsing/expected_output.json +++ b/src/tests/armor/functional/alpha_parsing/expected_output.json @@ -1,233 +1,15 @@ -[ - { - "children": [ - { - "dataType": "const double", - "nodeType": "Variable", - "qualifiedName": "GLOBAL_PI", - "tag": "removed" - }, - { - "dataType": "const float", - "nodeType": "Variable", - "qualifiedName": "GLOBAL_PI", - "tag": "added" - } - ], - "nodeType": "Variable", - "qualifiedName": "GLOBAL_PI", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "const char[7]", - "nodeType": "Variable", - "qualifiedName": "GLOBAL_VERSION", - "tag": "removed" - }, - { - "dataType": "const char[10]", - "nodeType": "Variable", - "qualifiedName": "GLOBAL_VERSION", - "tag": "added" - } - ], - "nodeType": "Variable", - "qualifiedName": "GLOBAL_VERSION", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "isValidInput::2", - "tag": "added" - } - ], - "nodeType": "Function", - "qualifiedName": "isValidInput", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "logMessage::2", - "tag": "removed" - }, - { - "children": [ - { - "dataType": "const char *", - "nodeType": "Parameter", - "qualifiedName": "logMessage::1", - "tag": "removed" - }, - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "logMessage::1", - "tag": "added" - } - ], - "nodeType": "Parameter", - "qualifiedName": "logMessage::1", - "tag": "modified" - } - ], - "nodeType": "Function", - "qualifiedName": "logMessage", - "tag": "modified" - }, - { - "dataType": "_Bool", - "nodeType": "Variable", - "qualifiedName": "filter_enabled", - "tag": "removed" - }, - { - "children": [ - { - "dataType": "unsigned int", - "nodeType": "Enumerator", - "qualifiedName": "pkt_status::PKT_PROCESS_DONE", - "tag": "removed" - } - ], - "nodeType": "Enum", - "qualifiedName": "pkt_status", - "tag": "modified" - }, - { - "children": [ - { - "children": [ - { - "children": [ - { - "dataType": "void *", - "nodeType": "Parameter", - "qualifiedName": "diag_callback_tbl_t::cb_func_ptr::3", - "tag": "removed" - } - ], - "nodeType": "FunctionPointer", - "qualifiedName": "diag_callback_tbl_t::cb_func_ptr", - "tag": "modified" - } - ], - "nodeType": "Field", - "qualifiedName": "diag_callback_tbl_t::cb_func_ptr", - "tag": "modified" - } - ], - "nodeType": "Struct", - "qualifiedName": "diag_callback_tbl_t", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "diag_uart_tbl_t::a", - "tag": "added" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Field", - "qualifiedName": "diag_uart_tbl_t::pid", - "tag": "removed" - }, - { - "dataType": "float", - "nodeType": "Field", - "qualifiedName": "diag_uart_tbl_t::pid", - "tag": "added" - } - ], - "nodeType": "Field", - "qualifiedName": "diag_uart_tbl_t::pid", - "tag": "modified" - } - ], - "nodeType": "Struct", - "qualifiedName": "diag_uart_tbl_t", - "tag": "modified" - }, - { - "dataType": "const double", - "nodeType": "Variable", - "qualifiedName": "PI", - "tag": "removed" - }, - { - "children": [ - { - "dataType": "const int", - "nodeType": "Variable", - "qualifiedName": "PACKET_BUFFER_SIZE", - "tag": "removed" - }, - { - "dataType": "const float", - "nodeType": "Variable", - "qualifiedName": "PACKET_BUFFER_SIZE", - "tag": "added" - } - ], - "nodeType": "Variable", - "qualifiedName": "PACKET_BUFFER_SIZE", - "tag": "modified" - }, - { - "dataType": "const int", - "nodeType": "Variable", - "qualifiedName": "TIMEOUT_MS", - "tag": "removed" - }, - { - "children": [ - { - "dataType": "(un-resolved Type)", - "nodeType": "Field", - "qualifiedName": "alpha::data", - "tag": "removed" - } - ], - "nodeType": "Struct", - "qualifiedName": "alpha", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "add::3", - "tag": "added" - } - ], - "nodeType": "Function", - "qualifiedName": "add", - "tag": "modified" - }, - { - "children": [ - { - "dataType": "int", - "nodeType": "Parameter", - "qualifiedName": "getOptimalProcessor::2", - "tag": "added" - } - ], - "nodeType": "Function", - "qualifiedName": "getOptimalProcessor", - "tag": "modified" - } -] \ No newline at end of file +{ + "astDiff": [], + "headerResolutionFailures": [ + { + "file": "/local/mnt/workspace/sw_sw_tools/ARMOR_DEBUG/src/tests/armor/functional/alpha_parsing/v1/mylib.h", + "header": "custom_defs.h" + }, + { + "file": "/local/mnt/workspace/sw_sw_tools/ARMOR_DEBUG/src/tests/armor/functional/alpha_parsing/v2/mylib.h", + "header": "custom_defs.h" + } + ], + "parsed_status": 0, + "unparsed_status": null +} \ No newline at end of file diff --git a/src/tests/armor/functional/alpha_parsing/test_alpha_parsing.py b/src/tests/armor/functional/alpha_parsing/test_alpha_parsing.py index 7742917..10ae61d 100644 --- a/src/tests/armor/functional/alpha_parsing/test_alpha_parsing.py +++ b/src/tests/armor/functional/alpha_parsing/test_alpha_parsing.py @@ -1,6 +1,5 @@ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. # SPDX-License-Identifier: BSD-3-Clause - import os import json import subprocess @@ -25,6 +24,47 @@ def test_ast_diff(binary_path, binary_args, request): with open(f'{test_dir}/debug_output/ast_diffs/ast_diff_output_mylib.h.json', 'r') as f: actual_json = json.load(f) - diff = DeepDiff(expected_json, actual_json['astDiff'], ignore_order=True) + # Check all expected keys are present + expected_keys = set(expected_json.keys()) + actual_keys = set(actual_json.keys()) + assert expected_keys == actual_keys, f"Key mismatch. Expected: {expected_keys}, Actual: {actual_keys}" + + # Check astDiff + assert actual_json['astDiff'] == expected_json['astDiff'], "astDiff mismatch" + + # Check parsed_status and unparsed_status + assert actual_json['parsed_status'] == expected_json['parsed_status'], "parsed_status mismatch" + assert actual_json['unparsed_status'] == expected_json['unparsed_status'], "unparsed_status mismatch" - assert diff == {} + # Check headerResolutionFailures by comparing last 7 parts of paths + assert 'headerResolutionFailures' in actual_json, "headerResolutionFailures not found in output" + + header_failures_actual = actual_json['headerResolutionFailures'] + header_failures_expected = expected_json['headerResolutionFailures'] + + # Normalize expected failures by extracting last 7 parts + expected_normalized = [] + for failure in header_failures_expected: + path_parts = failure['file'].split('/') + last_8_parts = '/'.join(path_parts[-7:]) if len(path_parts) >= 7 else failure['file'] + expected_normalized.append({ + 'file': last_8_parts, + 'header': failure['header'] + }) + + # Normalize actual failures by extracting last 7 parts + actual_normalized = [] + for failure in header_failures_actual: + path_parts = failure['file'].split('/') + last_8_parts = '/'.join(path_parts[-7:]) if len(path_parts) >= 7 else failure['file'] + actual_normalized.append({ + 'file': last_8_parts, + 'header': failure['header'] + }) + + # Sort both lists for comparison + expected_normalized_sorted = sorted(expected_normalized, key=lambda x: (x['file'], x['header'])) + actual_normalized_sorted = sorted(actual_normalized, key=lambda x: (x['file'], x['header'])) + + assert expected_normalized_sorted == actual_normalized_sorted, \ + f"headerResolutionFailures mismatch.\nExpected: {expected_normalized_sorted}\nActual: {actual_normalized_sorted}" diff --git a/src/tests/armor/functional/conftest.py b/src/tests/armor/functional/conftest.py index 176fce7..e2f5dde 100644 --- a/src/tests/armor/functional/conftest.py +++ b/src/tests/armor/functional/conftest.py @@ -20,7 +20,7 @@ def get_build_dir(): @pytest.fixture def binary_path(): """Returns the absolute path to the binary.""" - return os.path.join(get_build_dir(), "src/tests/armor/src/armor_debug") + return os.path.join(get_build_dir(), "src/tests/armor/armor_debug") @pytest.fixture def binary_args(request): diff --git a/src/tests/armor/functional/lang_options/v1/mylib.h b/src/tests/armor/functional/lang_options/v1/mylib.h index 63b9915..6dcf7ca 100644 --- a/src/tests/armor/functional/lang_options/v1/mylib.h +++ b/src/tests/armor/functional/lang_options/v1/mylib.h @@ -1,10 +1,5 @@ // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause -/* Test header: valid C code using C++ keywords as identifiers */ - -/* --- Functions using C++ keywords as parameter names --- */ - -/* access/object keywords */ int fun_new(int new, int this); int fun_delete(int delete, int class); int fun_namespace(int namespace, int template); diff --git a/src/tests/armor/src/options_handler.cpp b/src/tests/armor/src/options_handler.cpp index d550956..6596e98 100644 --- a/src/tests/armor/src/options_handler.cpp +++ b/src/tests/armor/src/options_handler.cpp @@ -145,12 +145,12 @@ bool runArmorTool(int argc, const char **argv) { armor::user_error() << "Missing header in newer version: " << file2 << "\n"; } else if (filesAreDifferentUsingDiff(file1, file2)) { - PARSING_STATUS parsingStatus = processHeaderPairAlpha(projectRoot1, file1, projectRoot2, file2, reportFormat, + PARSING_STATUS parsingStatus = armor::alpha::processHeaderPairAlpha(projectRoot1, file1, projectRoot2, file2, reportFormat, IncludePaths, macros, langOption); switch (parsingStatus) { case NO_FATAL_ERRORS: armor::info() << "Processing Headers again via beta parser\n"; - processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, reportFormat, + armor::beta::processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, reportFormat, IncludePaths, macros, langOption); break; case FATAL_ERRORS: @@ -188,12 +188,12 @@ bool runArmorTool(int argc, const char **argv) { armor::user_error() << "Missing header in newer version: " << file2 << "\n"; } else if (filesAreDifferentUsingDiff(file1, file2)) { - PARSING_STATUS parsingStatus = processHeaderPairAlpha(projectRoot1, file1, projectRoot2, file2, reportFormat, + PARSING_STATUS parsingStatus = armor::alpha::processHeaderPairAlpha(projectRoot1, file1, projectRoot2, file2, reportFormat, IncludePaths, macros, langOption); switch (parsingStatus) { case NO_FATAL_ERRORS: armor::info() << "Processing Headers again via v2\n"; - processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, reportFormat, + armor::beta::processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, reportFormat, IncludePaths, macros, langOption); break; case FATAL_ERRORS: diff --git a/src/tests/beta/src/CMakeLists.txt b/src/tests/beta/CMakeLists.txt similarity index 96% rename from src/tests/beta/src/CMakeLists.txt rename to src/tests/beta/CMakeLists.txt index 2e88637..444e21b 100644 --- a/src/tests/beta/src/CMakeLists.txt +++ b/src/tests/beta/CMakeLists.txt @@ -24,7 +24,6 @@ target_compile_definitions(beta PRIVATE TESTING_ENABLED=1) # Include project headers target_include_directories(beta PRIVATE - ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/common/include ${CMAKE_SOURCE_DIR}/src/beta/include ${LLVM_INCLUDE_DIRS} diff --git a/src/tests/beta/__init__.py b/src/tests/beta/__init__.py index dc3cadc..21749a9 100644 --- a/src/tests/beta/__init__.py +++ b/src/tests/beta/__init__.py @@ -1,3 +1,2 @@ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. # SPDX-License-Identifier: BSD-3-Clause -# Make beta directory a Python package \ No newline at end of file diff --git a/src/tests/beta/functional/__init__.py b/src/tests/beta/functional/__init__.py index d920b29..21749a9 100644 --- a/src/tests/beta/functional/__init__.py +++ b/src/tests/beta/functional/__init__.py @@ -1,3 +1,2 @@ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. # SPDX-License-Identifier: BSD-3-Clause -# Make functional directory a Python package \ No newline at end of file diff --git a/src/tests/beta/functional/access_spec_decl_changes/__init__.py b/src/tests/beta/functional/access_spec_decl_changes/__init__.py index be9f146..21749a9 100644 --- a/src/tests/beta/functional/access_spec_decl_changes/__init__.py +++ b/src/tests/beta/functional/access_spec_decl_changes/__init__.py @@ -1,2 +1,2 @@ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file +# SPDX-License-Identifier: BSD-3-Clause diff --git a/src/tests/beta/functional/conftest.py b/src/tests/beta/functional/conftest.py index d33bbfe..8530c30 100644 --- a/src/tests/beta/functional/conftest.py +++ b/src/tests/beta/functional/conftest.py @@ -20,7 +20,7 @@ def get_build_dir(): @pytest.fixture def binary_path(): """Returns the absolute path to the binary.""" - return os.path.join(get_build_dir(), "src/tests/beta/src/beta") + return os.path.join(get_build_dir(), "src/tests/beta/beta") @pytest.fixture def binary_args(request): @@ -28,7 +28,7 @@ def binary_args(request): curr_dir = os.path.dirname(request.fspath) prj_root1 = os.path.join(curr_dir, "v1") prj_root2 = os.path.join(curr_dir, "v2") - return [prj_root1, prj_root2, "mylib.h", "--dump-ast-diff", "-r", "json"] + return [prj_root1, prj_root2, "mylib.h"] @pytest.fixture def binary_args_c(request): @@ -36,5 +36,5 @@ def binary_args_c(request): curr_dir = os.path.dirname(request.fspath) prj_root1 = os.path.join(curr_dir, "v1") prj_root2 = os.path.join(curr_dir, "v2") - return [prj_root1, prj_root2, "mylib.h", "--lang", "c", "--dump-ast-diff", "-r", "json"] + return [prj_root1, prj_root2, "mylib.h", "--lang", "c"] diff --git a/src/tests/beta/functional/cxx_node_caching/expected_output.json b/src/tests/beta/functional/cxx_node_caching/expected_output.json new file mode 100644 index 0000000..fcb1fd8 --- /dev/null +++ b/src/tests/beta/functional/cxx_node_caching/expected_output.json @@ -0,0 +1,298 @@ +{ + "astDiff": [ + { + "children": [ + { + "children": [ + { + "children": [ + { + "dataType": "int", + "nodeType": "Field", + "qualifiedName": "EmbeddedField::a", + "tag": "removed" + }, + { + "dataType": "long", + "nodeType": "Field", + "qualifiedName": "EmbeddedField::a", + "tag": "added" + } + ], + "nodeType": "Field", + "qualifiedName": "EmbeddedField::a", + "tag": "modified" + } + ], + "nodeType": "Struct", + "qualifiedName": "EmbeddedField", + "tag": "modified" + } + ], + "nodeType": "Struct", + "qualifiedName": "FieldOwner", + "tag": "modified" + }, + { + "children": [ + { + "children": [ + { + "dataType": "struct EmbeddedFieldNeverDefined *", + "nodeType": "Field", + "qualifiedName": "fptr", + "tag": "removed" + }, + { + "dataType": "struct EmbeddedFieldNeverDefined **", + "nodeType": "Field", + "qualifiedName": "fptr", + "tag": "added" + } + ], + "nodeType": "Field", + "qualifiedName": "fptr", + "tag": "modified" + } + ], + "nodeType": "Struct", + "qualifiedName": "FieldOwnerSad", + "tag": "modified" + }, + { + "children": [ + { + "children": [ + { + "dataType": "int", + "nodeType": "Field", + "qualifiedName": "RetOwnerHelper::val", + "tag": "removed" + }, + { + "dataType": "long", + "nodeType": "Field", + "qualifiedName": "RetOwnerHelper::val", + "tag": "added" + } + ], + "nodeType": "Field", + "qualifiedName": "RetOwnerHelper::val", + "tag": "modified" + } + ], + "nodeType": "Struct", + "qualifiedName": "RetOwnerHelper", + "tag": "modified" + }, + { + "children": [ + { + "children": [ + { + "dataType": "struct RetOwnerHelperSad *", + "nodeType": "ReturnType", + "qualifiedName": "retFnSad::(ReturnType)", + "tag": "removed" + }, + { + "dataType": "struct RetOwnerHelperSad **", + "nodeType": "ReturnType", + "qualifiedName": "retFnSad::(ReturnType)", + "tag": "added" + } + ], + "nodeType": "ReturnType", + "qualifiedName": "retFnSad::(ReturnType)", + "tag": "modified" + } + ], + "nodeType": "Function", + "qualifiedName": "retFnSad", + "tag": "modified" + }, + { + "children": [ + { + "children": [ + { + "dataType": "int", + "nodeType": "Field", + "qualifiedName": "VarHelper::val", + "tag": "removed" + }, + { + "dataType": "long", + "nodeType": "Field", + "qualifiedName": "VarHelper::val", + "tag": "added" + } + ], + "nodeType": "Field", + "qualifiedName": "VarHelper::val", + "tag": "modified" + } + ], + "nodeType": "Struct", + "qualifiedName": "VarHelper", + "tag": "modified" + }, + { + "children": [ + { + "dataType": "struct VarHelperSad *", + "nodeType": "Variable", + "qualifiedName": "varGlobalSad", + "tag": "removed" + }, + { + "dataType": "struct VarHelperSad **", + "nodeType": "Variable", + "qualifiedName": "varGlobalSad", + "tag": "added" + } + ], + "nodeType": "Variable", + "qualifiedName": "varGlobalSad", + "tag": "modified" + }, + { + "children": [ + { + "dataType": "int", + "nodeType": "Variable", + "qualifiedName": "interveningVar", + "tag": "removed" + }, + { + "dataType": "long", + "nodeType": "Variable", + "qualifiedName": "interveningVar", + "tag": "added" + } + ], + "nodeType": "Variable", + "qualifiedName": "interveningVar", + "tag": "modified" + }, + { + "children": [ + { + "children": [ + { + "dataType": "int", + "nodeType": "Field", + "qualifiedName": "AfterVarNotAdjacent::val", + "tag": "removed" + }, + { + "dataType": "long", + "nodeType": "Field", + "qualifiedName": "AfterVarNotAdjacent::val", + "tag": "added" + } + ], + "nodeType": "Field", + "qualifiedName": "AfterVarNotAdjacent::val", + "tag": "modified" + } + ], + "nodeType": "Struct", + "qualifiedName": "AfterVarNotAdjacent", + "tag": "modified" + }, + { + "children": [ + { + "dataType": "int", + "nodeType": "Variable", + "qualifiedName": "anotherInterveningVar", + "tag": "removed" + }, + { + "dataType": "long", + "nodeType": "Variable", + "qualifiedName": "anotherInterveningVar", + "tag": "added" + } + ], + "nodeType": "Variable", + "qualifiedName": "anotherInterveningVar", + "tag": "modified" + }, + { + "children": [ + { + "children": [ + { + "dataType": "int", + "nodeType": "Field", + "qualifiedName": "TdHelper::val", + "tag": "removed" + }, + { + "dataType": "long", + "nodeType": "Field", + "qualifiedName": "TdHelper::val", + "tag": "added" + } + ], + "nodeType": "Field", + "qualifiedName": "TdHelper::val", + "tag": "modified" + } + ], + "nodeType": "Struct", + "qualifiedName": "TdHelper", + "tag": "modified" + }, + { + "children": [ + { + "dataType": "struct TdHelperSad *", + "nodeType": "Typedef", + "qualifiedName": "TdHelperSad_t", + "tag": "removed" + }, + { + "dataType": "struct TdHelperSad **", + "nodeType": "Typedef", + "qualifiedName": "TdHelperSad_t", + "tag": "added" + } + ], + "nodeType": "Typedef", + "qualifiedName": "TdHelperSad_t", + "tag": "modified" + }, + { + "children": [ + { + "children": [ + { + "dataType": "int", + "nodeType": "Field", + "qualifiedName": "RedeclaredRetHelper::val", + "tag": "removed" + }, + { + "dataType": "long", + "nodeType": "Field", + "qualifiedName": "RedeclaredRetHelper::val", + "tag": "added" + } + ], + "nodeType": "Field", + "qualifiedName": "RedeclaredRetHelper::val", + "tag": "modified" + } + ], + "nodeType": "Struct", + "qualifiedName": "RedeclaredRetHelper", + "tag": "modified" + } + ], + "headerResolutionFailures": [], + "parsed_status": 2, + "unparsed_status": 0 +} \ No newline at end of file diff --git a/src/tests/alpha/functional/field_variable_changes/test_alpha_field_variable_changes.py b/src/tests/beta/functional/cxx_node_caching/test_cxx_node_caching.py similarity index 96% rename from src/tests/alpha/functional/field_variable_changes/test_alpha_field_variable_changes.py rename to src/tests/beta/functional/cxx_node_caching/test_cxx_node_caching.py index 8439441..20b8c37 100644 --- a/src/tests/alpha/functional/field_variable_changes/test_alpha_field_variable_changes.py +++ b/src/tests/beta/functional/cxx_node_caching/test_cxx_node_caching.py @@ -5,7 +5,6 @@ import subprocess from deepdiff import DeepDiff - def test_ast_diff(binary_path, binary_args, request): test_dir = os.path.dirname(request.fspath) @@ -26,4 +25,4 @@ def test_ast_diff(binary_path, binary_args, request): diff = DeepDiff(expected_json, actual_json, ignore_order=True) - assert diff == {} + assert diff == {} \ No newline at end of file diff --git a/src/tests/beta/functional/cxx_node_caching/v1/mylib.h b/src/tests/beta/functional/cxx_node_caching/v1/mylib.h new file mode 100644 index 0000000..34f7b61 --- /dev/null +++ b/src/tests/beta/functional/cxx_node_caching/v1/mylib.h @@ -0,0 +1,85 @@ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause +#pragma once + +// ============================================================ +// isInlineForwardDeclOfDeclType coverage: FieldDecl branch +// ============================================================ + +// -- Happy path: forward decl embedded, immediately followed by a field of that type -- +struct FieldOwner { + struct EmbeddedField* fptr; +}; +struct EmbeddedField { + int a; +}; + +// -- Sad path: forward decl never defined, still adjacent to field -- +struct FieldOwnerSad { + struct EmbeddedFieldNeverDefined* fptr; +}; + +// ============================================================ +// isInlineForwardDeclOfDeclType coverage: FunctionDecl (return type) branch +// ============================================================ + +// -- Happy path: forward decl immediately followed by function returning that type, later defined -- +struct RetOwnerHelper; +struct RetOwnerHelper* retFn(); +struct RetOwnerHelper { + int val; +}; + +// -- Sad path: forward decl immediately followed by function returning that type, never defined -- +struct RetOwnerHelperSad; +struct RetOwnerHelperSad* retFnSad(); + +// ============================================================ +// isInlineForwardDeclOfDeclType coverage: VarDecl branch +// ============================================================ + +// -- Happy path: forward decl immediately followed by a global var of that type, later defined -- +struct VarHelper; +VarHelper* varGlobal; +struct VarHelper { + int val; +}; + +// -- Sad path: forward decl immediately followed by a global var of that type, never defined -- +struct VarHelperSad; +VarHelperSad* varGlobalSad; + +// -- Sad path: adjacency broken by an intervening decl, so NOT treated as inline forward decl -- +int interveningVar; +struct AfterVarNotAdjacent; +int anotherInterveningVar; +struct AfterVarNotAdjacent* varGlobalNotAdjacent; +struct AfterVarNotAdjacent { + int val; +}; + +// ============================================================ +// isInlineForwardDeclOfDeclType coverage: TypedefDecl branch +// ============================================================ + +// -- Happy path: forward decl immediately followed by typedef of that type, later defined -- +struct TdHelper; +typedef struct TdHelper* TdHelper_t; +struct TdHelper { + int val; +}; + +// -- Sad path: forward decl immediately followed by typedef of that type, never defined -- +struct TdHelperSad; +typedef struct TdHelperSad* TdHelperSad_t; + +// ============================================================ +// Repeated forward decl still adjacent to the using decl on its last redecl +// ============================================================ + +struct RedeclaredRetHelper; +struct RedeclaredRetHelper; +struct RedeclaredRetHelper* redeclaredRetFn(); +struct RedeclaredRetHelper { + int val; +}; diff --git a/src/tests/beta/functional/cxx_node_caching/v2/mylib.h b/src/tests/beta/functional/cxx_node_caching/v2/mylib.h new file mode 100644 index 0000000..d160a55 --- /dev/null +++ b/src/tests/beta/functional/cxx_node_caching/v2/mylib.h @@ -0,0 +1,85 @@ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause +#pragma once + +// ============================================================ +// isInlineForwardDeclOfDeclType coverage: FieldDecl branch +// ============================================================ + +// -- Happy path: forward decl embedded, immediately followed by a field of that type -- +struct FieldOwner { + struct EmbeddedField* fptr; +}; +struct EmbeddedField { + long a; +}; + +// -- Sad path: forward decl never defined, still adjacent to field -- +struct FieldOwnerSad { + struct EmbeddedFieldNeverDefined** fptr; +}; + +// ============================================================ +// isInlineForwardDeclOfDeclType coverage: FunctionDecl (return type) branch +// ============================================================ + +// -- Happy path: forward decl immediately followed by function returning that type, later defined -- +struct RetOwnerHelper; +struct RetOwnerHelper* retFn(); +struct RetOwnerHelper { + long val; +}; + +// -- Sad path: forward decl immediately followed by function returning that type, never defined -- +struct RetOwnerHelperSad; +struct RetOwnerHelperSad** retFnSad(); + +// ============================================================ +// isInlineForwardDeclOfDeclType coverage: VarDecl branch +// ============================================================ + +// -- Happy path: forward decl immediately followed by a global var of that type, later defined -- +struct VarHelper; +VarHelper* varGlobal; +struct VarHelper { + long val; +}; + +// -- Sad path: forward decl immediately followed by a global var of that type, never defined -- +struct VarHelperSad; +VarHelperSad** varGlobalSad; + +// -- Sad path: adjacency broken by an intervening decl, so NOT treated as inline forward decl -- +long interveningVar; +struct AfterVarNotAdjacent; +long anotherInterveningVar; +struct AfterVarNotAdjacent* varGlobalNotAdjacent; +struct AfterVarNotAdjacent { + long val; +}; + +// ============================================================ +// isInlineForwardDeclOfDeclType coverage: TypedefDecl branch +// ============================================================ + +// -- Happy path: forward decl immediately followed by typedef of that type, later defined -- +struct TdHelper; +typedef struct TdHelper* TdHelper_t; +struct TdHelper { + long val; +}; + +// -- Sad path: forward decl immediately followed by typedef of that type, never defined -- +struct TdHelperSad; +typedef struct TdHelperSad** TdHelperSad_t; + +// ============================================================ +// Repeated forward decl still adjacent to the using decl on its last redecl +// ============================================================ + +struct RedeclaredRetHelper; +struct RedeclaredRetHelper; +struct RedeclaredRetHelper* redeclaredRetFn(); +struct RedeclaredRetHelper { + long val; +}; diff --git a/src/tests/beta/functional/flow_cxx_adv_template_categorisation/v2/mylib.h b/src/tests/beta/functional/flow_cxx_adv_template_categorisation/v2/mylib.h index 2cd4da9..85db0bc 100644 --- a/src/tests/beta/functional/flow_cxx_adv_template_categorisation/v2/mylib.h +++ b/src/tests/beta/functional/flow_cxx_adv_template_categorisation/v2/mylib.h @@ -1,4 +1,4 @@ /* * Copyright (c) 2026 Qualcomm Innovation Center, Inc. * SPDX-License-Identifier: BSD-3-Clause - */ + */ \ No newline at end of file diff --git a/src/tests/beta/functional/flow_cxx_categorisation/v2/mylib.h b/src/tests/beta/functional/flow_cxx_categorisation/v2/mylib.h index 2cd4da9..85db0bc 100644 --- a/src/tests/beta/functional/flow_cxx_categorisation/v2/mylib.h +++ b/src/tests/beta/functional/flow_cxx_categorisation/v2/mylib.h @@ -1,4 +1,4 @@ /* * Copyright (c) 2026 Qualcomm Innovation Center, Inc. * SPDX-License-Identifier: BSD-3-Clause - */ + */ \ No newline at end of file diff --git a/src/tests/beta/functional/flow_cxx_edge_categorisation/v2/mylib.h b/src/tests/beta/functional/flow_cxx_edge_categorisation/v2/mylib.h index 2cd4da9..85db0bc 100644 --- a/src/tests/beta/functional/flow_cxx_edge_categorisation/v2/mylib.h +++ b/src/tests/beta/functional/flow_cxx_edge_categorisation/v2/mylib.h @@ -1,4 +1,4 @@ /* * Copyright (c) 2026 Qualcomm Innovation Center, Inc. * SPDX-License-Identifier: BSD-3-Clause - */ + */ \ No newline at end of file diff --git a/src/tests/beta/functional/flow_cxx_forward_decl_categorisation/v2/mylib.h b/src/tests/beta/functional/flow_cxx_forward_decl_categorisation/v2/mylib.h index 2cd4da9..85db0bc 100644 --- a/src/tests/beta/functional/flow_cxx_forward_decl_categorisation/v2/mylib.h +++ b/src/tests/beta/functional/flow_cxx_forward_decl_categorisation/v2/mylib.h @@ -1,4 +1,4 @@ /* * Copyright (c) 2026 Qualcomm Innovation Center, Inc. * SPDX-License-Identifier: BSD-3-Clause - */ + */ \ No newline at end of file diff --git a/src/tests/beta/functional/flow_decl_init_categorisation/v2/mylib.h b/src/tests/beta/functional/flow_decl_init_categorisation/v2/mylib.h index 2cd4da9..85db0bc 100644 --- a/src/tests/beta/functional/flow_decl_init_categorisation/v2/mylib.h +++ b/src/tests/beta/functional/flow_decl_init_categorisation/v2/mylib.h @@ -1,4 +1,4 @@ /* * Copyright (c) 2026 Qualcomm Innovation Center, Inc. * SPDX-License-Identifier: BSD-3-Clause - */ + */ \ No newline at end of file diff --git a/src/tests/beta/functional/flow_macros_categorisation/v2/mylib.h b/src/tests/beta/functional/flow_macros_categorisation/v2/mylib.h index 2cd4da9..85db0bc 100644 --- a/src/tests/beta/functional/flow_macros_categorisation/v2/mylib.h +++ b/src/tests/beta/functional/flow_macros_categorisation/v2/mylib.h @@ -1,4 +1,4 @@ /* * Copyright (c) 2026 Qualcomm Innovation Center, Inc. * SPDX-License-Identifier: BSD-3-Clause - */ + */ \ No newline at end of file diff --git a/src/tests/beta/functional/struct_changes/v2/mylib.h b/src/tests/beta/functional/struct_changes/v2/mylib.h index 2274aa5..432b540 100644 --- a/src/tests/beta/functional/struct_changes/v2/mylib.h +++ b/src/tests/beta/functional/struct_changes/v2/mylib.h @@ -1,11 +1,5 @@ // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause - -// - Removed status field -// - Added timestamp field -// - Changed order of fields -// - Changed type of id from int to long -// - Removed int diag_uart_tbl_t struct Record{ float value; // moved diff --git a/src/tests/beta/src/options_handler.cpp b/src/tests/beta/src/options_handler.cpp index feb055d..474e76f 100644 --- a/src/tests/beta/src/options_handler.cpp +++ b/src/tests/beta/src/options_handler.cpp @@ -8,7 +8,7 @@ #include "CLI/CLI.hpp" #include "llvm/Support/raw_ostream.h" #include "options_handler.hpp" -#include "beta/include/header_processor.hpp" +#include "header_processor.hpp" #include "logger.hpp" #ifndef TOOL_VERSION @@ -16,184 +16,80 @@ #endif LANG_OPTIONS stringToLangOption(const std::string& lang) { - // Convert to lowercase for case-insensitive comparison std::string lowerLang = lang; std::transform(lowerLang.begin(), lowerLang.end(), lowerLang.begin(), [](unsigned char c){ return std::tolower(c); }); - - if (lowerLang == LANG_C) { - return LANG_OPTIONS::C; - } else if (lowerLang == LANG_CPP) { - return LANG_OPTIONS::CPP; - } - return LANG_OPTIONS::CPP; // default to C++ -} - -bool filesAreDifferentUsingDiff(const std::string &file1, const std::string &file2) { - std::string command = "diff -q " + file1 + " " + file2 + " > /dev/null"; - return std::system(command.c_str()) != 0; + if (lowerLang == LANG_C) return LANG_OPTIONS::C; + if (lowerLang == LANG_CPP) return LANG_OPTIONS::CPP; + return LANG_OPTIONS::CPP; } bool runArmorTool(int argc, const char **argv) { - CLI::App app{"ARMOR"}; + CLI::App app{"ARMOR beta — full AST diff test"}; std::string projectRoot1; std::string projectRoot2; std::vector headers; - std::string headerSubDir; - std::string reportFormat = "html"; - std::string language = LANG_CPP; // default to C++ - bool dumpAstDiff = false; - std::string debugLevel = ""; + std::string reportFormat = "json"; + std::string language = LANG_CPP; + std::string debugLevel; std::vector IncludePaths; - std::vector macros; std::string macroFlags; - auto fmt = std::make_shared(); - fmt->column_width(40); - app.formatter(fmt); - // Positional arguments - app.add_option("projectroot1", projectRoot1, "Path to the project root dir of the older version")->required(); - app.add_option("projectroot2", projectRoot2, "Path to the project root dir of the newer version")->required(); - app.add_option("headers", headers, - "List of header files to compare between the two versions.\n" - "\n" - "Header path interpretation depends on whether --header-dir is provided:\n" - "\n" - " With --header-dir:\n" - " Headers are treated as basenames (e.g., \"foo.h\") under the specified subdirectory.\n" - " Example:\n" - " --header-dir include/api foo.h bar.hpp\n" - "\n" - " • Without --header-dir:\n" - " Headers must be relative paths from the project root.\n" - " Example:\n" - " include/api/foo.h include/api/bar.hpp\n" - ); - // Optional arguments - app.add_option("--header-dir", headerSubDir, "Subdirectory under each project root containing headers"); - app.add_option("--report-format,-r", reportFormat, "Report format: html (default).\n" - "If json is provided, both html and json reports will be generated.") + std::vector macros; + + app.add_option("projectroot1", projectRoot1, "Path to the baseline project root")->required(); + app.add_option("projectroot2", projectRoot2, "Path to the newer project root")->required(); + app.add_option("headers", headers, "Header files (relative to project root) to compare"); + app.add_option("--report-format,-r", reportFormat, "Report format: html or json") ->check(CLI::IsMember({"html", "json"})); - app.add_option("--lang,-l", language, "Language mode: cpp (default) or c.\n" - "Use 'c' for C headers, 'cpp' for C++ headers.") - ->transform(CLI::IsMember({LANG_C, LANG_CPP}, CLI::ignore_case)); - app.add_flag("--dump-ast-diff", dumpAstDiff, "Dump AST diff JSON files for debugging"); - app.set_version_flag("--version,-v", TOOL_VERSION); - app.add_option("--log-level", debugLevel, "Set debug log level: ERROR, LOG, INFO (default), DEBUG") + app.add_option("--lang,-l", language, "Language: cpp (default) or c") + ->transform(CLI::IsMember({LANG_C, LANG_CPP}, CLI::ignore_case)); + app.add_option("--log-level", debugLevel, "Log level: ERROR, LOG, INFO, DEBUG") ->check(CLI::IsMember({"ERROR", "LOG", "INFO", "DEBUG"})); - - app.add_option("-I,--include-paths", IncludePaths, - "Include paths for header dependencies.\n" - "Example: -I path/to/include1 -I path/to/include2"); - app.add_option("-m,--macro-flags", macroFlags, - "Macro flags to be passed for headers.\n"); + app.add_option("-I,--include-paths", IncludePaths, "Extra include paths"); + app.add_option("-m,--macro-flags", macroFlags, "Macro flags"); + app.set_version_flag("--version,-v", TOOL_VERSION); CLI11_PARSE(app, argc, argv); + std::istringstream iss(macroFlags); std::string flag; - while (iss >> flag) { - macros.push_back(flag); - } + while (iss >> flag) macros.push_back(flag); DebugConfig& debugConfig = DebugConfig::getInstance(); debugConfig.initialize(); - // Set level and announce (now goes to the file) - if (debugLevel == "DEBUG") { - debugConfig.setLevel(DebugConfig::Level::DEBUG); - armor::info() << "Debug level set to DEBUG"; - } else if (debugLevel == "INFO") { - debugConfig.setLevel(DebugConfig::Level::INFO); - armor::info() << "Debug level set to INFO"; - } else if (debugLevel == "WARNING") { - debugConfig.setLevel(DebugConfig::Level::WARNING); - armor::info() << "Debug level set to WARNING"; - } else if (debugLevel == "ERROR") { - debugConfig.setLevel(DebugConfig::Level::ERROR); - armor::info() << "Debug level set to ERROR"; - } - else{ - debugConfig.setLevel(DebugConfig::Level::NONE); - } + if (debugLevel == "DEBUG") debugConfig.setLevel(DebugConfig::Level::DEBUG); + else if (debugLevel == "INFO") debugConfig.setLevel(DebugConfig::Level::INFO); + else if (debugLevel == "LOG") debugConfig.setLevel(DebugConfig::Level::WARNING); + else if (debugLevel == "ERROR") debugConfig.setLevel(DebugConfig::Level::ERROR); + else debugConfig.setLevel(DebugConfig::Level::NONE); - // Convert language string to LANG_OPTIONS enum LANG_OPTIONS langOption = stringToLangOption(language); - armor::info() << "Language mode set to: " << language << "\n"; - bool processed = false; - std::vector headersToCompare; - if (!headers.empty()) { - for (const auto &header : headers) { - std::string file1, file2; - if (!headerSubDir.empty()) { - file1 = projectRoot1 + "/" + headerSubDir + "/" + header; - file2 = projectRoot2 + "/" + headerSubDir + "/" + header; - } - else { - file1 = projectRoot1 + "/" + header; - file2 = projectRoot2 + "/" + header; - } - armor::user_print() << "Processing files: " << file1 << " " << file2; - if (!std::filesystem::exists(file1)) { - armor::user_error() << "Missing header in older version: " << file1; - } - else if (!std::filesystem::exists(file2)) { - armor::user_error() << "Missing header in newer version: " << file2; - } - else if (filesAreDifferentUsingDiff(file1, file2)) { - processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, reportFormat, - IncludePaths, macros, langOption); - processed = true; - } - else { - armor::user_print() << "No differences found between: " << file1 << " and " << file2; - return true; - } - } + if (headers.empty()) { + armor::user_error() << "No headers specified. Usage: beta \n"; + return false; } - else if (!headerSubDir.empty()) { - std::string dir1 = projectRoot1 + "/" + headerSubDir; - std::string dir2 = projectRoot2 + "/" + headerSubDir; - for (const auto &entry : std::filesystem::directory_iterator(dir1)) { - if (entry.path().extension() == ".h" || entry.path().extension() == ".hpp") { - headersToCompare.push_back(entry.path().filename().string()); - } - } - armor::user_print() << "List of headers to process:"; - for (const auto &h : headersToCompare) { - armor::user_print() << " " << h; - } - for (const auto &header : headersToCompare) { - std::string file1 = dir1 + "/" + header; - std::string file2 = dir2 + "/" + header; - armor::user_print() << "Processing files: " << file1 << " " << file2; - if (!std::filesystem::exists(file1)) { - armor::user_error() << "Missing header in older version: " << file1; - } - else if (!std::filesystem::exists(file2)) { - armor::user_error() << "Missing header in newer version: " << file2; - } - else if (filesAreDifferentUsingDiff(file1, file2)) { - processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, reportFormat, - IncludePaths, macros, langOption); - processed = true; - } - else { - armor::user_print() << "No differences found between: " << file1 << " and " << file2; - return true; - } + + bool processed = false; + for (const auto& header : headers) { + std::string file1 = projectRoot1 + "/" + header; + std::string file2 = projectRoot2 + "/" + header; + + armor::user_print() << "Processing: " << file1 << " vs " << file2 << "\n"; + + if (!std::filesystem::exists(file1)) { + armor::user_error() << "Missing header in older version: " << file1 << "\n"; + continue; } - } - if (processed && !dumpAstDiff) { - try { - std::filesystem::remove_all("debug_output/ast_diffs"); - } catch (const std::exception &e) { - armor::user_error() << "Failed to remove debug_output directory: " << e.what(); + if (!std::filesystem::exists(file2)) { + armor::user_error() << "Missing header in newer version: " << file2 << "\n"; + continue; } + + armor::beta::processHeaderPairBeta(projectRoot1, file1, projectRoot2, file2, + reportFormat, IncludePaths, macros, langOption); + processed = true; } - if (!processed && headers.empty() && headerSubDir.empty()) { - const std::string argv0 = argv[0] ? std::string(argv[0]) : std::string("armor"); - armor::user_error() << "Usage: " << argv0 << " ...\n" - << "Or use --header-dir to compare all headers in a subdirectory.\n" - << "Try '" << argv0 << " --help' for more information."; - } + return processed; } diff --git a/src/tests/common/CMakeLists.txt b/src/tests/common/CMakeLists.txt index e889354..e61fda3 100644 --- a/src/tests/common/CMakeLists.txt +++ b/src/tests/common/CMakeLists.txt @@ -18,8 +18,6 @@ add_executable(common_unit_tests target_include_directories(common_unit_tests PRIVATE ${CMAKE_SOURCE_DIR}/src/common/include - ${CMAKE_SOURCE_DIR}/src/alpha/include - ${CMAKE_SOURCE_DIR}/src/beta/include ${LLVM_INCLUDE_DIRS} ${CLANG_INCLUDE_DIRS} )