/* * GDevelop Core * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights * reserved. This project is released under the MIT License. */ #if defined(GD_IDE_ONLY) #include "DependenciesAnalyzer.h" #include #include "GDCore/Events/Builtin/LinkEvent.h" #include "GDCore/Events/Event.h" #include "GDCore/Events/EventsList.h" #include "GDCore/Project/ExternalEvents.h" #include "GDCore/Project/Layout.h" #include "GDCore/Project/Project.h" #include "GDCore/Project/SourceFile.h" DependenciesAnalyzer::DependenciesAnalyzer(gd::Project& project_, gd::Layout& layout_) : project(project_), layout(&layout_), externalEvents(NULL) { parentScenes.push_back(layout->GetName()); } DependenciesAnalyzer::DependenciesAnalyzer(gd::Project& project_, gd::ExternalEvents& externalEvents_) : project(project_), layout(NULL), externalEvents(&externalEvents_) { parentExternalEvents.push_back(externalEvents->GetName()); } DependenciesAnalyzer::DependenciesAnalyzer(const DependenciesAnalyzer& parent) : parentScenes(parent.parentScenes), parentExternalEvents(parent.parentExternalEvents), project(parent.project), layout(NULL), externalEvents(NULL) {} bool DependenciesAnalyzer::Analyze() { if (layout) return Analyze(layout->GetEvents(), true); else if (externalEvents) return Analyze(externalEvents->GetEvents(), true); std::cout << "ERROR: DependenciesAnalyzer called without any layout or " "external events."; return false; } DependenciesAnalyzer::~DependenciesAnalyzer() {} bool DependenciesAnalyzer::Analyze(gd::EventsList& events, bool isOnTopLevel) { for (unsigned int i = 0; i < events.size(); ++i) { gd::LinkEvent* linkEvent = dynamic_cast(&events[i]); if (linkEvent) { DependenciesAnalyzer analyzer(*this); gd::String linked = linkEvent->GetTarget(); if (project.HasExternalEventsNamed(linked)) { if (std::find(parentExternalEvents.begin(), parentExternalEvents.end(), linked) != parentExternalEvents.end()) return false; // Circular dependency! externalEventsDependencies.insert( linked); // There is a direct dependency if (!isOnTopLevel) notTopLevelExternalEventsDependencies.insert(linked); analyzer.AddParentExternalEvents(linked); if (!analyzer.Analyze(project.GetExternalEvents(linked).GetEvents(), isOnTopLevel)) return false; } else if (project.HasLayoutNamed(linked)) { if (std::find(parentScenes.begin(), parentScenes.end(), linked) != parentScenes.end()) return false; // Circular dependency! scenesDependencies.insert(linked); // There is a direct dependency if (!isOnTopLevel) notTopLevelScenesDependencies.insert(linked); analyzer.AddParentScene(linked); if (!analyzer.Analyze(project.GetLayout(linked).GetEvents(), isOnTopLevel)) return false; } // Update with indirect dependencies. scenesDependencies.insert(analyzer.GetScenesDependencies().begin(), analyzer.GetScenesDependencies().end()); externalEventsDependencies.insert( analyzer.GetExternalEventsDependencies().begin(), analyzer.GetExternalEventsDependencies().end()); sourceFilesDependencies.insert( analyzer.GetSourceFilesDependencies().begin(), analyzer.GetSourceFilesDependencies().end()); notTopLevelScenesDependencies.insert( analyzer.GetNotTopLevelScenesDependencies().begin(), analyzer.GetNotTopLevelScenesDependencies().end()); notTopLevelExternalEventsDependencies.insert( analyzer.GetNotTopLevelExternalEventsDependencies().begin(), analyzer.GetNotTopLevelExternalEventsDependencies().end()); if (!isOnTopLevel) { notTopLevelScenesDependencies.insert( analyzer.GetScenesDependencies().begin(), analyzer.GetScenesDependencies().end()); notTopLevelExternalEventsDependencies.insert( analyzer.GetExternalEventsDependencies().begin(), analyzer.GetExternalEventsDependencies().end()); } } // Search for source files dependencies std::vector dependencies = events[i].GetSourceFileDependencies(); sourceFilesDependencies.insert(dependencies.begin(), dependencies.end()); const gd::String& associatedSourceFile = events[i].GetAssociatedGDManagedSourceFile(project); if (!associatedSourceFile.empty()) sourceFilesDependencies.insert(associatedSourceFile); // Analyze sub events dependencies if (events[i].CanHaveSubEvents()) { if (!Analyze(events[i].GetSubEvents(), false)) return false; } } return true; } gd::String DependenciesAnalyzer::ExternalEventsCanBeCompiledForAScene() { if (!externalEvents) { std::cout << "ERROR: ExternalEventsCanBeCompiledForAScene called without " "external events set!" << std::endl; return ""; } gd::String sceneName; for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) { // For each layout, compute the dependencies and the dependencies which are // not coming from a top level event. DependenciesAnalyzer analyzer(project, project.GetLayout(i)); if (!analyzer.Analyze()) continue; // Analyze failed -> Cyclic dependencies const std::set& dependencies = analyzer.GetExternalEventsDependencies(); const std::set& notTopLevelDependencies = analyzer.GetNotTopLevelExternalEventsDependencies(); // Check if the external events is a dependency, and that is is only present // as a link on the top level. if (dependencies.find(externalEvents->GetName()) != dependencies.end() && notTopLevelDependencies.find(externalEvents->GetName()) == notTopLevelDependencies.end()) { if (!sceneName.empty()) return ""; // External events can be compiled only if one scene is // including them. else sceneName = project.GetLayout(i).GetName(); } } return sceneName; // External events can be compiled and used for the scene. } #endif