Menu

Issue with #pragma once and different paths to the same header

Tal
2024-07-30
2024-08-06
  • Tal

    Tal - 2024-07-30

    I noticed that header path resolving, to not including "#pragma once" header twice, isn't working by comparing full paths.

    For example, if I have a file "dir/a.h":

    #pragma once
    //...
    

    And "dir/a.cpp":

    #include "dir/a.h"
    #include "a.h"
    

    Then when I run cppcheck -I$PWD dir/a.cpp, cppcheck includes the "dir/a.h" twice - path resolving works, but fullpath comparing doesn't, so that the #pragma once comment doesn't avoid the header to be included twice.

    I believe that the algorithm for #pragma once resolution should just be to compare the two absolute paths of the file.

    Thanks

     
  • Tal

    Tal - 2024-08-05

    I have found the place in the code that needed to be fixed(in simplecpp), and here is my rough fix that I'm sure that is not clean (uncomment commented lines to see the difference between absolute/non-absolute paths that are consider to be different):

    diff --git externals/simplecpp/simplecpp.cpp externals/simplecpp/simplecpp.cpp
    index 47bb78f8cf17..a418b379b203 100755
    --- externals/simplecpp/simplecpp.cpp
    +++ externals/simplecpp/simplecpp.cpp
    @@ -42,6 +42,8 @@
     #ifdef SIMPLECPP_WINDOWS
     #include <windows.h>
     #undef ERROR
    +#else
    +#include <unistd.h>
     #endif
    
     #if __cplusplus >= 201103L
    @@ -3020,7 +3022,7 @@ private:
     static NonExistingFilesCache nonExistingFilesCache;
    
     #endif
    -
    +#include <iostream>
     static std::string openHeader(std::ifstream &f, const std::string &path)
     {
         std::string simplePath = simplecpp::simplifyPath(path);
    @@ -3029,19 +3031,39 @@ static std::string openHeader(std::ifstream &f, const std::string &path)
             return "";  // file is known not to exist, skip expensive file open call
     #endif
         f.open(simplePath.c_str());
    -    if (f.is_open())
    +    if (f.is_open()) {
    +        //std::cout << "importing header with simple path: " << simplePath << std::endl;
             return simplePath;
    +    }
     #ifdef SIMPLECPP_WINDOWS
         nonExistingFilesCache.add(simplePath);
     #endif
         return "";
     }
    
    +static std::string currentDirectory() {
    +#ifdef SIMPLECPP_WINDOWS
    +    TCHAR NPath[MAX_PATH];
    +    GetCurrentDirectory(MAX_PATH, NPath);
    +    return NPath;
    +#else
    +    const std::size_t size = 1024;
    +    char the_path[size];
    +    getcwd(the_path, size);
    +    return the_path;
    +#endif
    +}
    +
     static std::string getRelativeFileName(const std::string &sourcefile, const std::string &header)
     {
    +    std::string path;
         if (sourcefile.find_first_of("\\/") != std::string::npos)
    -        return simplecpp::simplifyPath(sourcefile.substr(0, sourcefile.find_last_of("\\/") + 1U) + header);
    -    return simplecpp::simplifyPath(header);
    +        path = sourcefile.substr(0, sourcefile.find_last_of("\\/") + 1U) + header;
    +    else
    +        path = header;
    +    if (!isAbsolutePath(path))
    +        path = currentDirectory() + "/" + path;
    +    return simplecpp::simplifyPath(path);
     }
    
     static std::string openHeaderRelative(std::ifstream &f, const std::string &sourcefile, const std::string &header)
    @@ -3052,6 +3074,8 @@ static std::string openHeaderRelative(std::ifstream &f, const std::string &sourc
     static std::string getIncludePathFileName(const std::string &includePath, const std::string &header)
     {
         std::string path = includePath;
    +    if (!isAbsolutePath(includePath))
    +        path = currentDirectory() + "/" + path;
         if (!path.empty() && path[path.size()-1U]!='/' && path[path.size()-1U]!='\\')
             path += '/';
         return path + header;
    @@ -3091,7 +3115,8 @@ static std::string getFileName(const std::map<std::string, simplecpp::TokenList
             return "";
         }
         if (isAbsolutePath(header)) {
    -        return (filedata.find(header) != filedata.end()) ? simplecpp::simplifyPath(header) : "";
    +   const std::string simplifiedHeaderPath = simplecpp::simplifyPath(header);
    +        return (filedata.find(simplifiedHeaderPath) != filedata.end()) ? simplifiedHeaderPath : "";
         }
    
         if (!systemheader) {
    @@ -3114,7 +3139,11 @@ static std::string getFileName(const std::map<std::string, simplecpp::TokenList
    
     static bool hasFile(const std::map<std::string, simplecpp::TokenList *> &filedata, const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader)
     {
    -    return !getFileName(filedata, sourcefile, header, dui, systemheader).empty();
    +    const std::string fileName = getFileName(filedata, sourcefile, header, dui, systemheader);
    +    //if (fileName.empty()) {
    +        //std::cout << "first time see this header: " << fileName << std::endl;
    +    //}
    +    return !fileName.empty();
     }
    
     std::map<std::string, simplecpp::TokenList*> simplecpp::load(const simplecpp::TokenList &rawtokens, std::vector<std::string> &filenames, const simplecpp::DUI &dui, simplecpp::OutputList *outputList)
    @@ -3656,6 +3685,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
                             macros.erase(tok->str());
                     }
                 } else if (ifstates.top() == True && rawtok->str() == PRAGMA && rawtok->next && rawtok->next->str() == ONCE && sameline(rawtok,rawtok->next)) {
    +                //std::cout << "insert pragma once for: " << rawtok->location.file() << std::endl;
                     pragmaOnce.insert(rawtok->location.file());
                 }
                 rawtok = gotoNextLine(rawtok);
    
     
  • CHR

    CHR - 2024-08-05

    You should probably open an issue/PR here: https://github.com/danmar/simplecpp/

     
    • Tal

      Tal - 2024-08-06
       
      👍
      1

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.