From f41e1c429d731e332a12764eac0a035da955daa6 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Tue, 7 Oct 2014 12:11:48 +0200 Subject: [PATCH] data: Added HeaderSearchPaths to Application- and ProjectSettings This change allows for parsing of a real codebase by specifying the system header search paths in ApplicationSettings.xml and the additional header search paths in ProjectSettings.xml. Both settings files are now documented in ApplicationSettings_template.xml and ProjectSettings_template.xml, which show all possible settings for each file. This change also fixes some parsing edge cases that occured. --- .gitignore | 2 + bin/app/data/ApplicationSettings.xml | 11 ------ bin/app/data/ApplicationSettings_template.xml | 23 +++++++++++ bin/app/data/ProjectSettings.xml | 4 -- bin/app/data/ProjectSettings_template.xml | 13 +++++++ bin/app/data/src/header.h | 6 +++ bin/test/data/SettingsTestSuite/settings.xml | 5 ++- bin/test/data/log/test_log.txt | 38 +++++++++--------- src/lib/ApplicationSettings.cpp | 5 +++ src/lib/ApplicationSettings.h | 4 ++ src/lib/Project.cpp | 16 +++++--- src/lib/ProjectSettings.cpp | 9 ++++- src/lib/ProjectSettings.h | 4 ++ src/lib/Settings.cpp | 14 +++++++ src/lib/Settings.h | 3 ++ src/lib/data/Storage.cpp | 24 +++++++++--- src/lib/data/parser/ParseLocation.cpp | 9 ++++- src/lib/data/parser/Parser.h | 5 ++- src/lib/data/parser/cxx/ASTVisitor.cpp | 17 +++++++- src/lib/data/parser/cxx/CxxParser.cpp | 39 ++++++++++++++++--- src/lib/data/parser/cxx/CxxParser.h | 5 ++- src/test/CxxParserTestSuite.h | 2 +- src/test/SettingsTestSuite.h | 10 +++++ 23 files changed, 211 insertions(+), 57 deletions(-) delete mode 100644 bin/app/data/ApplicationSettings.xml create mode 100644 bin/app/data/ApplicationSettings_template.xml delete mode 100644 bin/app/data/ProjectSettings.xml create mode 100644 bin/app/data/ProjectSettings_template.xml diff --git a/.gitignore b/.gitignore index 8bcbf534..c91565c4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,7 @@ /bin/test/data/log/ /bin/app/data/window_settings.ini +/bin/app/data/ApplicationSettings.xml +/bin/app/data/ProjectSettings.xml .DS_Store diff --git a/bin/app/data/ApplicationSettings.xml b/bin/app/data/ApplicationSettings.xml deleted file mode 100644 index f8aab3de..00000000 --- a/bin/app/data/ApplicationSettings.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - 4 - Courier - 12 - 235 235 235 255 - 215 230 240 100 - 210 240 70 100 - - diff --git a/bin/app/data/ApplicationSettings_template.xml b/bin/app/data/ApplicationSettings_template.xml new file mode 100644 index 00000000..b9144b1a --- /dev/null +++ b/bin/app/data/ApplicationSettings_template.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bin/app/data/ProjectSettings.xml b/bin/app/data/ProjectSettings.xml deleted file mode 100644 index 3ed67512..00000000 --- a/bin/app/data/ProjectSettings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - data/src - diff --git a/bin/app/data/ProjectSettings_template.xml b/bin/app/data/ProjectSettings_template.xml new file mode 100644 index 00000000..ad3a5dcb --- /dev/null +++ b/bin/app/data/ProjectSettings_template.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/bin/app/data/src/header.h b/bin/app/data/src/header.h index 8a14ee8e..a5a9abaf 100644 --- a/bin/app/data/src/header.h +++ b/bin/app/data/src/header.h @@ -1,3 +1,9 @@ +#include +#include +#include +#include +#include + const bool *abd(int abc, int bca); bool const *abc(int a, int b); diff --git a/bin/test/data/SettingsTestSuite/settings.xml b/bin/test/data/SettingsTestSuite/settings.xml index bd91952e..e9d468d4 100644 --- a/bin/test/data/SettingsTestSuite/settings.xml +++ b/bin/test/data/SettingsTestSuite/settings.xml @@ -5,6 +5,9 @@ 3.1416 Hello World! - data + + data + data/|src/ + diff --git a/bin/test/data/log/test_log.txt b/bin/test/data/log/test_log.txt index bc8a2184..c6e80470 100644 --- a/bin/test/data/log/test_log.txt +++ b/bin/test/data/log/test_log.txt @@ -1,4 +1,22 @@ ConfigManager.cpp ERROR: value path/to/nowhere is not present in config. +Token.cpp ERROR: Location Id was not referenced by this Token. +Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class +Edge.cpp ERROR: Nodes are not plain copies. +Storage.cpp INFO: class: A +Storage.cpp INFO: method: A::A +Storage.cpp INFO: global usage: A::A -> A::count +Storage.cpp INFO: method: A::getCount +Storage.cpp INFO: global usage: A::getCount -> A::count +Storage.cpp INFO: method: A::process +Storage.cpp INFO: field: A::count +Storage.cpp INFO: class: B +Storage.cpp INFO: inheritance: B : A +Storage.cpp INFO: method: B::process +Storage.cpp INFO: type usage: B::process -> int +Storage.cpp INFO: function: main +Storage.cpp INFO: type usage: main -> B +Storage.cpp INFO: call: main -> B::B +Storage.cpp INFO: call: main -> A::getCount Storage.cpp INFO: class: A Storage.cpp INFO: method: A::A Storage.cpp INFO: global usage: A::A -> A::count @@ -31,24 +49,6 @@ SearchIndex.cpp INFO: 237 A::A ^^^^ -Storage.cpp INFO: class: A -Storage.cpp INFO: method: A::A -Storage.cpp INFO: global usage: A::A -> A::count -Storage.cpp INFO: method: A::getCount -Storage.cpp INFO: global usage: A::getCount -> A::count -Storage.cpp INFO: method: A::process -Storage.cpp INFO: field: A::count -Storage.cpp INFO: class: B -Storage.cpp INFO: inheritance: B : A -Storage.cpp INFO: method: B::process -Storage.cpp INFO: type usage: B::process -> int -Storage.cpp INFO: function: main -Storage.cpp INFO: type usage: main -> B -Storage.cpp INFO: call: main -> B::B -Storage.cpp INFO: call: main -> A::getCount -Token.cpp ERROR: Location Id was not referenced by this Token. -Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class -Edge.cpp ERROR: Nodes are not plain copies. Settings.cpp WARNING: File for Settings not found. ConfigManager.cpp ERROR: value Bool is not present in config. ConfigManager.cpp ERROR: value Int is not present in config. @@ -64,7 +64,6 @@ ConfigManager.cpp ERROR: value Int is not present in config. ConfigManager.cpp ERROR: value Float is not present in config. ConfigManager.cpp ERROR: value String is not present in config. ConfigManager.cpp ERROR: value NewBool is not present in config. -Graph.cpp ERROR: Can't remove member edge, without removing the child node. Storage.cpp INFO: typedef: type -> int Storage.cpp INFO: class: Class Storage.cpp INFO: struct: Struct @@ -104,6 +103,7 @@ Storage.cpp INFO: global usage: isTrue -> global Storage.cpp INFO: function: isTrue Storage.cpp INFO: struct: Struct Storage.cpp INFO: type usage: isTrue -> Struct +Graph.cpp ERROR: Can't remove member edge, without removing the child node. TextAccess.cpp WARNING: Index 'firstLine' has to be lower or equal index 'lastLine', is 3 > 2 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 diff --git a/src/lib/ApplicationSettings.cpp b/src/lib/ApplicationSettings.cpp index 142b8c41..80c14764 100644 --- a/src/lib/ApplicationSettings.cpp +++ b/src/lib/ApplicationSettings.cpp @@ -16,6 +16,11 @@ ApplicationSettings::~ApplicationSettings() { } +std::vector ApplicationSettings::getHeaderSearchPaths() const +{ + return getValues("source/HeaderSearchPaths", ""); +} + int ApplicationSettings::getCodeTabWidth() const { return getValue("code/TabWidth", 4); diff --git a/src/lib/ApplicationSettings.h b/src/lib/ApplicationSettings.h index 3a513dc9..0a6d3fac 100644 --- a/src/lib/ApplicationSettings.h +++ b/src/lib/ApplicationSettings.h @@ -12,6 +12,10 @@ public: static std::shared_ptr getInstance(); ~ApplicationSettings(); + // source + std::vector getHeaderSearchPaths() const; + + // code int getCodeTabWidth() const; void setCodeTabWidth(int codeTabWidth); diff --git a/src/lib/Project.cpp b/src/lib/Project.cpp index d09f89f4..39b3bf2c 100644 --- a/src/lib/Project.cpp +++ b/src/lib/Project.cpp @@ -3,12 +3,12 @@ #include #include +#include "ApplicationSettings.h" #include "data/access/GraphAccessProxy.h" #include "data/access/LocationAccessProxy.h" #include "data/graph/Token.h" #include "data/parser/cxx/CxxParser.h" #include "utility/FileSystem.h" -#include "utility/logging/logging.h" #include "utility/messaging/type/MessageFinishedParsing.h" std::shared_ptr Project::create(GraphAccessProxy* graphAccessProxy, LocationAccessProxy* locationAccessProxy) @@ -49,7 +49,8 @@ void Project::clearStorage() void Project::parseCode() { - if (ProjectSettings::getInstance()->getSourcePath() != "") + std::string sourcePath = ProjectSettings::getInstance()->getSourcePath(); + if (sourcePath.size()) { std::vector extensions; extensions.push_back(".cpp"); @@ -57,16 +58,21 @@ void Project::parseCode() extensions.push_back(".h"); extensions.push_back(".hpp"); + // Add the SourcePath as HeaderSearchPath as well. + std::vector headerSearchPaths = ProjectSettings::getInstance()->getHeaderSearchPaths(); + headerSearchPaths.push_back(sourcePath); + CxxParser parser(m_storage.get()); parser.parseFiles( - FileSystem::getSourceFilesFromDirectory(ProjectSettings::getInstance()->getSourcePath(), extensions) + FileSystem::getSourceFilesFromDirectory(sourcePath, extensions), + ApplicationSettings::getInstance()->getHeaderSearchPaths(), + headerSearchPaths ); m_storage->logGraph(); m_storage->logLocations(); - MessageFinishedParsing message; - message.dispatch(); + MessageFinishedParsing().dispatch(); } } diff --git a/src/lib/ProjectSettings.cpp b/src/lib/ProjectSettings.cpp index a6e471c6..31710d0c 100644 --- a/src/lib/ProjectSettings.cpp +++ b/src/lib/ProjectSettings.cpp @@ -22,10 +22,15 @@ ProjectSettings::~ProjectSettings() std::string ProjectSettings::getSourcePath() const { - return getValue("SourcePath", ""); + return getValue("source/SourcePath", ""); } bool ProjectSettings::setSourcePath(const std::string& sourcePath) { - return setValue("SourcePath", sourcePath); + return setValue("source/SourcePath", sourcePath); +} + +std::vector ProjectSettings::getHeaderSearchPaths() const +{ + return getValues("source/HeaderSearchPaths", ""); } diff --git a/src/lib/ProjectSettings.h b/src/lib/ProjectSettings.h index 63677501..9f39f4e2 100644 --- a/src/lib/ProjectSettings.h +++ b/src/lib/ProjectSettings.h @@ -2,6 +2,7 @@ #define PROJECT_SETTINGS_H #include +#include #include "Settings.h" @@ -11,9 +12,12 @@ public: static std::shared_ptr getInstance(); ~ProjectSettings(); + // source std::string getSourcePath() const; bool setSourcePath(const std::string& sourcePath); + std::vector getHeaderSearchPaths() const; + private: ProjectSettings(); ProjectSettings(const ProjectSettings&); diff --git a/src/lib/Settings.cpp b/src/lib/Settings.cpp index f5565ece..a68f1cd9 100644 --- a/src/lib/Settings.cpp +++ b/src/lib/Settings.cpp @@ -3,6 +3,7 @@ #include "utility/FileSystem.h" #include "utility/logging/logging.h" #include "utility/text/TextAccess.h" +#include "utility/utilityString.h" Settings::Settings() { @@ -44,3 +45,16 @@ void Settings::clear() { m_config = ConfigManager::createEmpty(); } + +std::vector Settings::getValues(const std::string& key, std::string defaultValue) const +{ + std::string value = getValue(key, defaultValue); + + if (value.size()) + { + std::deque values = utility::split(value, '|'); + return std::vector(values.begin(), values.end()); + } + + return std::vector(); +} diff --git a/src/lib/Settings.h b/src/lib/Settings.h index c13c9f5f..d5ba19a5 100644 --- a/src/lib/Settings.h +++ b/src/lib/Settings.h @@ -3,6 +3,7 @@ #include #include +#include #include "utility/ConfigManager.h" @@ -20,6 +21,8 @@ protected: template T getValue(const std::string& key, T defaultValue) const; + std::vector getValues(const std::string& key, std::string defaultValue) const; + template bool setValue(const std::string& key, T value); diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index eccde6cd..7fd748fd 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -304,6 +304,12 @@ Id Storage::onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& f Node* functionNode = addNodeHierarchyWithDistinctSignature(Node::NODE_UNDEFINED_FUNCTION, function); Edge* edge = addTypeEdge(functionNode, Edge::EDGE_TYPE_USAGE, type); + if (!edge) + { + LOG_ERROR("Could not create type usage edge."); + return 0; + } + return edge->getId(); } @@ -598,13 +604,21 @@ TokenComponentAccess::AccessType Storage::convertAccessType(ParserClient::Access TokenComponentAccess* Storage::addAccess(Node* node, ParserClient::AccessType access) { - if (access != ACCESS_NONE) + if (access == ACCESS_NONE) { - std::shared_ptr ptr = std::make_shared(convertAccessType(access)); - node->getMemberEdge()->addComponentAccess(ptr); - return ptr.get(); + return nullptr; } - return nullptr; + + Edge* edge = node->getMemberEdge(); + if (!edge) + { + LOG_ERROR_STREAM(<< "Cannot assign access" << access << " to node " << node->getFullName() << " because it is not a child."); + return nullptr; + } + + std::shared_ptr ptr = std::make_shared(convertAccessType(access)); + edge->addComponentAccess(ptr); + return ptr.get(); } TokenComponentAbstraction::AbstractionType Storage::convertAbstractionType(ParserClient::AbstractionType abstraction) const diff --git a/src/lib/data/parser/ParseLocation.cpp b/src/lib/data/parser/ParseLocation.cpp index b2e9e27e..16957979 100644 --- a/src/lib/data/parser/ParseLocation.cpp +++ b/src/lib/data/parser/ParseLocation.cpp @@ -24,5 +24,12 @@ ParseLocation::ParseLocation( bool ParseLocation::isValid() const { - return startLineNumber > 0 && endLineNumber >= startLineNumber; + if (startLineNumber == endLineNumber) + { + return startLineNumber > 0 && startColumnNumber <= endColumnNumber; + } + else + { + return startLineNumber > 0 && startLineNumber < endLineNumber; + } } diff --git a/src/lib/data/parser/Parser.h b/src/lib/data/parser/Parser.h index 0843d310..78b30a10 100644 --- a/src/lib/data/parser/Parser.h +++ b/src/lib/data/parser/Parser.h @@ -15,7 +15,10 @@ public: Parser(ParserClient* client); virtual ~Parser(); - virtual void parseFiles(const std::vector& filePaths) = 0; + virtual void parseFiles( + const std::vector& filePaths, + const std::vector& systemHeaderSearchPaths, + const std::vector& headerSearchPaths) = 0; virtual void parseFile(std::shared_ptr textAccess) = 0; protected: diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index fe6e5fad..6999ec64 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -281,6 +281,12 @@ void ASTVisitor::VisitCallExprInDeclBody(clang::FunctionDecl* decl, clang::CallE // return nullptr; + if (!expr->getDirectCallee()) + { + // TODO: Save error at location. + return; + } + m_client->onCallParsed( getParseLocation(expr->getSourceRange()), getParseFunction(decl), @@ -290,6 +296,12 @@ void ASTVisitor::VisitCallExprInDeclBody(clang::FunctionDecl* decl, clang::CallE void ASTVisitor::VisitCallExprInDeclBody(clang::VarDecl* decl, clang::CallExpr* expr) { + if (!expr->getDirectCallee()) + { + // TODO: Save error at location. + return; + } + m_client->onCallParsed( getParseLocation(expr->getSourceRange()), getParseVariable(decl), @@ -478,7 +490,10 @@ std::vector ASTVisitor::getParameters(clang::FunctionDecl* decla for (unsigned i = 0; i < declaration->getNumParams(); i++) { clang::ParmVarDecl* paramDecl = declaration->getParamDecl(i); - parameters.push_back(getParseTypeUsage(paramDecl->getTypeSourceInfo()->getTypeLoc(), paramDecl->getType())); + if (paramDecl->getTypeSourceInfo()) + { + parameters.push_back(getParseTypeUsage(paramDecl->getTypeSourceInfo()->getTypeLoc(), paramDecl->getType())); + } } return parameters; diff --git a/src/lib/data/parser/cxx/CxxParser.cpp b/src/lib/data/parser/cxx/CxxParser.cpp index 5ecc6df3..64fa2c19 100644 --- a/src/lib/data/parser/cxx/CxxParser.cpp +++ b/src/lib/data/parser/cxx/CxxParser.cpp @@ -13,12 +13,41 @@ CxxParser::~CxxParser() { } -void CxxParser::parseFiles(const std::vector& filePaths) -{ - // Fake commandline flags passed to the programm. Everything after '--' will be interpreted by the ClangTool. +void CxxParser::parseFiles( + const std::vector& filePaths, + const std::vector& systemHeaderSearchPaths, + const std::vector& headerSearchPaths +){ + // Commandline flags passed to the programm. Everything after '--' will be interpreted by the ClangTool. + std::vector args; + args.push_back("app"); + args.push_back("--"); + + // verbose + // args.push_back("-v"); + // The option '-x c++' treats subsequent input files as C++. - const char* argv[] = { "app", "--", "-x", "c++" }; - int argc = 4; + args.push_back("-x"); + args.push_back("c++"); + + args.push_back("-std=c++11"); + + for (const std::string& path : systemHeaderSearchPaths) + { + args.push_back("-isystem" + path); + } + + for (const std::string& path : headerSearchPaths) + { + args.push_back("-I" + path); + } + + int argc = args.size(); + const char** argv = new const char*[argc]; + for (size_t i = 0; i < args.size(); i++) + { + argv[i] = args[i].c_str(); + } std::shared_ptr compilationDatabase( clang::tooling::FixedCompilationDatabase::loadFromCommandLine(argc, argv) diff --git a/src/lib/data/parser/cxx/CxxParser.h b/src/lib/data/parser/cxx/CxxParser.h index 08228c90..1853e846 100644 --- a/src/lib/data/parser/cxx/CxxParser.h +++ b/src/lib/data/parser/cxx/CxxParser.h @@ -9,7 +9,10 @@ public: CxxParser(ParserClient* client); ~CxxParser(); - virtual void parseFiles(const std::vector& filePaths); + virtual void parseFiles( + const std::vector& filePaths, + const std::vector& systemHeaderSearchPaths, + const std::vector& headerSearchPaths); virtual void parseFile(std::shared_ptr textAccess); }; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 77921730..50970f6d 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -981,7 +981,7 @@ public: std::vector filePaths; filePaths.push_back("data/CxxParserTestSuite/header.h"); filePaths.push_back("data/CxxParserTestSuite/code.cpp"); - parser.parseFiles(filePaths); + parser.parseFiles(filePaths, std::vector(), std::vector()); TS_ASSERT_EQUALS(client.typedefs.size(), 1); TS_ASSERT_EQUALS(client.classes.size(), 4); diff --git a/src/test/SettingsTestSuite.h b/src/test/SettingsTestSuite.h index c6c84d02..5a767820 100644 --- a/src/test/SettingsTestSuite.h +++ b/src/test/SettingsTestSuite.h @@ -117,6 +117,16 @@ public: TS_ASSERT_EQUALS(ProjectSettings::getInstance()->getSourcePath(), "data"); } + void test_load_header_search_paths_from_file() + { + ProjectSettings::getInstance()->load("data/SettingsTestSuite/settings.xml"); + std::vector paths = ProjectSettings::getInstance()->getHeaderSearchPaths(); + + TS_ASSERT_EQUALS(paths.size(), 2); + TS_ASSERT_EQUALS(paths[0], "data/"); + TS_ASSERT_EQUALS(paths[1], "src/"); + } + private: class TestSettings : public Settings