diff --git a/simplecpp.cpp b/simplecpp.cpp index 25d0d3c3..fd327549 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -3109,15 +3109,13 @@ bool simplecpp::FileDataCache::getFileId(const std::string &path, FileID &id) #endif } -simplecpp::FileDataCache simplecpp::load(const simplecpp::TokenList &rawtokens, std::vector &filenames, const simplecpp::DUI &dui, simplecpp::OutputList *outputList) +simplecpp::FileDataCache simplecpp::load(const simplecpp::TokenList &rawtokens, std::vector &filenames, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, FileDataCache cache) { #ifdef SIMPLECPP_WINDOWS if (dui.clearIncludeCache) nonExistingFilesCache.clear(); #endif - FileDataCache cache; - std::list filelist; // -include files @@ -3173,15 +3171,21 @@ simplecpp::FileDataCache simplecpp::load(const simplecpp::TokenList &rawtokens, const bool systemheader = (htok->str()[0] == '<'); const std::string header(htok->str().substr(1U, htok->str().size() - 2U)); - FileData *const filedata = cache.get(sourcefile, header, dui, systemheader, filenames, outputList).first; - if (!filedata) + const auto loadResult = cache.get(sourcefile, header, dui, systemheader, filenames, outputList); + const bool loaded = loadResult.second; + + if (!loaded) + continue; + + FileData *const filedata = loadResult.first; + + if (!filedata->tokens.front()) continue; if (dui.removeComments) filedata->tokens.removeComments(); - if (filedata->tokens.front()) - filelist.push_back(filedata->tokens.front()); + filelist.push_back(filedata->tokens.front()); } return cache; diff --git a/simplecpp.h b/simplecpp.h index 76487d6c..8268fa8d 100644 --- a/simplecpp.h +++ b/simplecpp.h @@ -353,49 +353,6 @@ namespace simplecpp { bool removeComments; /** remove comment tokens from included files */ }; - SIMPLECPP_LIB long long characterLiteralToLL(const std::string& str); - - SIMPLECPP_LIB FileDataCache load(const TokenList &rawtokens, std::vector &filenames, const DUI &dui, OutputList *outputList = nullptr); - - /** - * Preprocess - * @todo simplify interface - * @param output TokenList that receives the preprocessing output - * @param rawtokens Raw tokenlist for top sourcefile - * @param files internal data of simplecpp - * @param cache output from simplecpp::load() - * @param dui defines, undefs, and include paths - * @param outputList output: list that will receive output messages - * @param macroUsage output: macro usage - * @param ifCond output: #if/#elif expressions - */ - SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector &files, FileDataCache &cache, const DUI &dui, OutputList *outputList = nullptr, std::list *macroUsage = nullptr, std::list *ifCond = nullptr); - - /** - * Deallocate data - */ - SIMPLECPP_LIB void cleanup(FileDataCache &cache); - - /** Simplify path */ - SIMPLECPP_LIB std::string simplifyPath(std::string path); - - /** Convert Cygwin path to Windows path */ - SIMPLECPP_LIB std::string convertCygwinToWindowsPath(const std::string &cygwinPath); - - /** Returns the C version a given standard */ - SIMPLECPP_LIB cstd_t getCStd(const std::string &std); - - /** Returns the C++ version a given standard */ - SIMPLECPP_LIB cppstd_t getCppStd(const std::string &std); - - /** Returns the __STDC_VERSION__ value for a given standard */ - SIMPLECPP_LIB std::string getCStdString(const std::string &std); - SIMPLECPP_LIB std::string getCStdString(cstd_t std); - - /** Returns the __cplusplus value for a given standard */ - SIMPLECPP_LIB std::string getCppStdString(const std::string &std); - SIMPLECPP_LIB std::string getCppStdString(cppstd_t std); - struct SIMPLECPP_LIB FileData { /** The canonical filename associated with this data */ std::string filename; @@ -503,8 +460,50 @@ namespace simplecpp { container_type mData; name_map_type mNameMap; id_map_type mIdMap; - }; + + SIMPLECPP_LIB long long characterLiteralToLL(const std::string& str); + + SIMPLECPP_LIB FileDataCache load(const TokenList &rawtokens, std::vector &filenames, const DUI &dui, OutputList *outputList = nullptr, FileDataCache cache = {}); + + /** + * Preprocess + * @todo simplify interface + * @param output TokenList that receives the preprocessing output + * @param rawtokens Raw tokenlist for top sourcefile + * @param files internal data of simplecpp + * @param cache output from simplecpp::load() + * @param dui defines, undefs, and include paths + * @param outputList output: list that will receive output messages + * @param macroUsage output: macro usage + * @param ifCond output: #if/#elif expressions + */ + SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector &files, FileDataCache &cache, const DUI &dui, OutputList *outputList = nullptr, std::list *macroUsage = nullptr, std::list *ifCond = nullptr); + + /** + * Deallocate data + */ + SIMPLECPP_LIB void cleanup(FileDataCache &cache); + + /** Simplify path */ + SIMPLECPP_LIB std::string simplifyPath(std::string path); + + /** Convert Cygwin path to Windows path */ + SIMPLECPP_LIB std::string convertCygwinToWindowsPath(const std::string &cygwinPath); + + /** Returns the C version a given standard */ + SIMPLECPP_LIB cstd_t getCStd(const std::string &std); + + /** Returns the C++ version a given standard */ + SIMPLECPP_LIB cppstd_t getCppStd(const std::string &std); + + /** Returns the __STDC_VERSION__ value for a given standard */ + SIMPLECPP_LIB std::string getCStdString(const std::string &std); + SIMPLECPP_LIB std::string getCStdString(cstd_t std); + + /** Returns the __cplusplus value for a given standard */ + SIMPLECPP_LIB std::string getCppStdString(const std::string &std); + SIMPLECPP_LIB std::string getCppStdString(cppstd_t std); } #if defined(_MSC_VER) diff --git a/test.cpp b/test.cpp index de9f250b..ccb653ca 100644 --- a/test.cpp +++ b/test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #define STRINGIZE_(x) #x @@ -2087,6 +2088,49 @@ static void systemInclude() ASSERT_EQUALS("", toString(outputList)); } +static void circularInclude() +{ + std::vector files; + simplecpp::FileDataCache cache; + + { + const char *const path = "test.h"; + const char code[] = + "#ifndef TEST_H\n" + "#define TEST_H\n" + "#include \"a/a.h\"\n" + "#endif\n" + ; + cache.insert({path, makeTokenList(code, files, path)}); + } + + { + const char *const path = "a/a.h"; + const char code[] = + "#ifndef A_H\n" + "#define A_H\n" + "#include \"../test.h\"\n" + "#endif\n" + ; + cache.insert({path, makeTokenList(code, files, path)}); + } + + simplecpp::OutputList outputList; + simplecpp::TokenList tokens2(files); + { + std::vector filenames; + const simplecpp::DUI dui; + + const char code[] = "#include \"test.h\"\n"; + const simplecpp::TokenList rawtokens = makeTokenList(code, files, "test.cpp"); + + cache = simplecpp::load(rawtokens, filenames, dui, &outputList, std::move(cache)); + simplecpp::preprocess(tokens2, rawtokens, files, cache, dui, &outputList); + } + + ASSERT_EQUALS("", toString(outputList)); +} + static void multiline1() { const char code[] = "#define A \\\n" @@ -3314,6 +3358,7 @@ int main(int argc, char **argv) TEST_CASE(missingHeader4); TEST_CASE(nestedInclude); TEST_CASE(systemInclude); + TEST_CASE(circularInclude); TEST_CASE(nullDirective1); TEST_CASE(nullDirective2);