Browse Source

Add new wrapper target to invoke the newly added clang-query tool.
It seems there is a bug in the rewriter that prevents it to save the source files with replacements out to disk, so at the moment nothing get changed yet in the source tree.
[ci only: Annotate]

Yao Wei Tjong 姚伟忠 10 years ago
parent
commit
dbd23c17a1

+ 1 - 0
CMake/Modules/Urho3D-CMake-common.cmake

@@ -260,6 +260,7 @@ if (URHO3D_CLANG_TOOLS)
     # Require C++11 standard and no precompiled-header
     # Require C++11 standard and no precompiled-header
     set (URHO3D_C++11 1)
     set (URHO3D_C++11 1)
     set (URHO3D_PCH 0)
     set (URHO3D_PCH 0)
+    set (URHO3D_LIB_TYPE SHARED)
     # Set build options that would maximise the AST of Urho3D library
     # Set build options that would maximise the AST of Urho3D library
     foreach (OPT URHO3D_ANGELSCRIPT URHO3D_LUA URHO3D_FILEWATCHER URHO3D_PROFILING URHO3D_LOGGING URHO3D_NAVIGATION URHO3D_NETWORK URHO3D_PHYSICS URHO3D_URHO2D URHO3D_DATABASE_SQLITE)
     foreach (OPT URHO3D_ANGELSCRIPT URHO3D_LUA URHO3D_FILEWATCHER URHO3D_PROFILING URHO3D_LOGGING URHO3D_NAVIGATION URHO3D_NETWORK URHO3D_PHYSICS URHO3D_URHO2D URHO3D_DATABASE_SQLITE)
         set (${OPT} 1)
         set (${OPT} 1)

+ 86 - 16
Source/Clang-Tools/Annotator/Annotator.cpp

@@ -22,7 +22,9 @@
 
 
 #include <clang/ASTMatchers/ASTMatchFinder.h>
 #include <clang/ASTMatchers/ASTMatchFinder.h>
 #include <clang/Tooling/CommonOptionsParser.h>
 #include <clang/Tooling/CommonOptionsParser.h>
-#include <clang/Tooling/Refactoring.h>
+#include <clang/Tooling/RefactoringCallbacks.h>
+
+#include <unordered_set>
 
 
 using namespace clang;
 using namespace clang;
 using namespace clang::ast_matchers;
 using namespace clang::ast_matchers;
@@ -45,18 +47,59 @@ static cl::extrahelp MoreHelp(
     "\n"
     "\n"
 );
 );
 
 
-static cl::OptionCategory AnnotatorCategory("Annotator options");
+static cl::OptionCategory annotatorCategory("Annotator options");
+
+// ClangTool only takes a reference to the array list without owning it, so we need to keep the filtered list ourselves
+class PathFilter
+{
+public:
+    template <typename Fn>
+    PathFilter(const std::vector<std::string> sourcePaths, Fn fn)
+    {
+        std::copy_if(sourcePaths.begin(), sourcePaths.end(), std::back_inserter(pathList_), fn);
+    }
+
+    std::vector<std::string> GetPathList() {
+        return pathList_;
+    }
+
+private:
+    std::vector<std::string> pathList_;
+};
+
+static std::unordered_set<std::string> classNames_;
+
+class ExtractCallback : public MatchFinder::MatchCallback
+{
+public :
+    virtual void run(const MatchFinder::MatchResult& result)
+    {
+        auto className = result.Nodes.getNodeAs<StringLiteral>("className");
+        if (className)
+            classNames_.insert(className->getString());
+    }
+
+    virtual void onStartOfTranslationUnit()
+    {
+        outs() << '.';      // Sending a heart beat
+    }
+};
+
+static std::unordered_set<std::string> annotatedClassNames_;
 
 
-class BindingCallback : public MatchFinder::MatchCallback
+class AnnotateCallback : public RefactoringCallback
 {
 {
 public :
 public :
     virtual void run(const MatchFinder::MatchResult& result)
     virtual void run(const MatchFinder::MatchResult& result)
     {
     {
-        ASTContext* context = result.Context;
-        const StringLiteral* stringLiteral = result.Nodes.getNodeAs<StringLiteral>("StringLiteral");
-        if (stringLiteral)
-            // TODO: Store the exposed class name in a global hashset
-            outs() << stringLiteral->getString() << "\n";
+        auto className = result.Nodes.getNodeAs<RecordDecl>("className");
+        if (className && annotatedClassNames_.find(className->getName()) == annotatedClassNames_.end() &&
+            classNames_.find(className->getName()) == classNames_.end())
+        {
+            Replacement replacement(*result.SourceManager, className->getLocStart(), 0, "!!!TODO: WIP");
+            getReplacements().insert(replacement);
+            annotatedClassNames_.insert(className->getName());
+        }
     }
     }
 
 
     virtual void onStartOfTranslationUnit()
     virtual void onStartOfTranslationUnit()
@@ -67,25 +110,52 @@ public :
 
 
 int main(int argc, const char** argv)
 int main(int argc, const char** argv)
 {
 {
-    CommonOptionsParser OptionsParser(argc, argv, AnnotatorCategory);
-    ClangTool bindingExtractor(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());
-    RefactoringTool annotator(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());
-    BindingCallback bindingCallback;
+    // Parse the arguments and pass them to the the internal sub-tools
+    CommonOptionsParser optionsParser(argc, argv, annotatorCategory);
+    PathFilter bindingPathFilter
+        (optionsParser.getSourcePathList(), [](const std::string& path) { return path.find("API.cpp") != std::string::npos; });
+    PathFilter nonBindingPathFilter
+        (optionsParser.getSourcePathList(), [](const std::string& path) { return path.find("API.cpp") == std::string::npos; });
+    ClangTool bindingExtractor(optionsParser.getCompilations(), bindingPathFilter.GetPathList());
+    RefactoringTool annotator(optionsParser.getCompilations(), nonBindingPathFilter.GetPathList());
+
+    // Setup finder to match against AST nodes from existing AngelScript binding source files
+    ExtractCallback extractCallback;
     MatchFinder bindingFinder;
     MatchFinder bindingFinder;
+    // Find exposed class names (they are registered through RegisterObjectType(), RegisterRefCounted(), RegisterObject(), etc)
     bindingFinder.addMatcher(
     bindingFinder.addMatcher(
         memberCallExpr(
         memberCallExpr(
             callee(
             callee(
                 methodDecl(hasName("RegisterObjectType"))),
                 methodDecl(hasName("RegisterObjectType"))),
-            hasArgument(0, stringLiteral().bind("StringLiteral"))), &bindingCallback);
+            hasArgument(0, stringLiteral().bind("className"))), &extractCallback);
     bindingFinder.addMatcher(
     bindingFinder.addMatcher(
         callExpr(
         callExpr(
             hasDeclaration(
             hasDeclaration(
                 functionDecl(hasParameter(1, hasName("className")))),
                 functionDecl(hasParameter(1, hasName("className")))),
-            hasArgument(1, stringLiteral().bind("StringLiteral"))), &bindingCallback);
+            hasArgument(1, stringLiteral().bind("className"))), &extractCallback);
+
+    // Setup finder to match against AST nodes for annotating Urho3D library source files
+    AnnotateCallback annotateCallback;
     MatchFinder annotateFinder;
     MatchFinder annotateFinder;
+    // Find exported class declaration with Urho3D namespace
+    annotateFinder.addMatcher(
+        recordDecl(
+#ifndef _MSC_VER
+            hasAttr(attr::Visibility),
+#else
+            hasAttr(attr::DLLExport),
+#endif
+            matchesName("Urho3D::")).bind("className"), &annotateCallback);
+
+    // Unbuffered stdout stream to keep the Travis-CI's log flowing and thus prevent it from killing a potentially long running job
+    outs().SetUnbuffered();
+
+    // Success when both sub-tools are run successfully
     return (outs() << "Extracting", true) &&
     return (outs() << "Extracting", true) &&
            bindingExtractor.run(newFrontendActionFactory(&bindingFinder).get()) == EXIT_SUCCESS &&
            bindingExtractor.run(newFrontendActionFactory(&bindingFinder).get()) == EXIT_SUCCESS &&
-           (outs() << "\nAnnotating", true) &&
+           (outs() << "\nExtracted " << classNames_.size() << " bound class names\n"
+            << "Annotating", true) &&
            annotator.runAndSave(newFrontendActionFactory(&annotateFinder).get()) == EXIT_SUCCESS &&
            annotator.runAndSave(newFrontendActionFactory(&annotateFinder).get()) == EXIT_SUCCESS &&
-           (outs() << "\n", true) ? EXIT_SUCCESS : EXIT_FAILURE;
+           (outs() << "\nAnnotated " << annotatedClassNames_.size() << " exported class names as non-scriptable\n", true) ?
+        EXIT_SUCCESS : EXIT_FAILURE;
 }
 }

+ 5 - 0
Source/Clang-Tools/CMakeLists.txt

@@ -58,6 +58,11 @@ list (APPEND LIBS ${LLVM_SYSLIBS})
 add_subdirectory (Annotator)
 add_subdirectory (Annotator)
 
 
 # List of targets
 # List of targets
+add_custom_target (ast-query
+    COMMAND ${CMAKE_COMMAND} -E echo "Building AST for query, please be patient..."
+    COMMAND ${BINDIR}clang-query -p ${CMAKE_BINARY_DIR} $$option ${SOURCES}
+    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/Source/Urho3D
+    COMMENT "Executing clang-query on Urho3D library source files")
 add_custom_target (ast
 add_custom_target (ast
     COMMAND ${CMAKE_COMMAND} -E echo "Usage: option=-help make ast"
     COMMAND ${CMAKE_COMMAND} -E echo "Usage: option=-help make ast"
     COMMAND ${BINDIR}clang-check -p ${CMAKE_BINARY_DIR} $$option ${SOURCES}
     COMMAND ${BINDIR}clang-check -p ${CMAKE_BINARY_DIR} $$option ${SOURCES}

+ 5 - 0
Source/Urho3D/CMakeLists.txt

@@ -115,6 +115,11 @@ endif ()
 if (MSVC)
 if (MSVC)
     set (PRE_EXPORT_HEADER "\n#pragma warning(disable: 4251)\n#pragma warning(disable: 4275)\n")
     set (PRE_EXPORT_HEADER "\n#pragma warning(disable: 4251)\n#pragma warning(disable: 4275)\n")
 endif ()
 endif ()
+if (URHO3D_CLANG_TOOLS)
+    set (POST_EXPORT_HEADER "\n#define NONSCRIPTABLE __attribute__((annotate(\"nonscriptable\")))\n")
+else ()
+    set (POST_EXPORT_HEADER "\n#define NONSCRIPTABLE\n")
+endif ()
 generate_export_header (${TARGET_NAME} ${URHO3D_LIB_TYPE} EXPORT_MACRO_NAME URHO3D_API EXPORT_FILE_NAME Urho3D.h.new)
 generate_export_header (${TARGET_NAME} ${URHO3D_LIB_TYPE} EXPORT_MACRO_NAME URHO3D_API EXPORT_FILE_NAME Urho3D.h.new)
 execute_process (COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/Urho3D.h.new ${CMAKE_CURRENT_BINARY_DIR}/Urho3D.h)
 execute_process (COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/Urho3D.h.new ${CMAKE_CURRENT_BINARY_DIR}/Urho3D.h)
 file (REMOVE ${CMAKE_CURRENT_BINARY_DIR}/Urho3D.h.new)
 file (REMOVE ${CMAKE_CURRENT_BINARY_DIR}/Urho3D.h.new)