Merge release-2019 into master
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / gmxcpp.cpp
index b9cfd8a20bf846952536ddc9fe765bf14efd3404..d232b55dbf109e4f0aae681c6b3cc9999a114990 100644 (file)
@@ -49,6 +49,7 @@
 #include <algorithm>
 #include <memory>
 
+#include <unordered_set>
 #include <sys/types.h>
 
 #include "gromacs/utility/arrayref.h"
@@ -73,16 +74,16 @@ struct gmx_cpp
 {
     std::shared_ptr < std::vector < t_define>>    defines;
     std::shared_ptr < std::vector < std::string>> includes;
-
-    FILE             *fp = nullptr;
-    std::string       path;
-    std::string       cwd;
-    std::string       fn;
-    std::string       line;
-    int               line_nr;
-    std::vector<int>  ifdefs;
-    struct gmx_cpp   *child  = nullptr;
-    struct gmx_cpp   *parent = nullptr;
+    std::unordered_set<std::string> unmatched_defines;
+    FILE                           *fp = nullptr;
+    std::string                     path;
+    std::string                     cwd;
+    std::string                     fn;
+    std::string                     line;
+    int                             line_nr;
+    std::vector<int>                ifdefs;
+    struct gmx_cpp                 *child  = nullptr;
+    struct gmx_cpp                 *parent = nullptr;
 };
 
 static bool is_word_end(char c)
@@ -258,12 +259,14 @@ cpp_open_file(const char                                     *filenm,
                 {
                     std::string buf = cppopts[i] + 2;
                     buf.resize(ptr - cppopts[i] - 2);
-
                     add_define(cpp->defines.get(), buf, ptr + 1);
+                    cpp->unmatched_defines.insert(buf);
+
                 }
                 else
                 {
                     add_define(cpp->defines.get(), cppopts[i] + 2, "");
+                    cpp->unmatched_defines.insert(cppopts[i] + 2);
                 }
             }
             i++;
@@ -379,6 +382,14 @@ process_directive(gmx_cpp_t         *handlep,
             {
                 if (define.name == dval)
                 {
+                    // erase from unmatched_defines in original handle
+                    gmx_cpp_t root = handle;
+                    while (root->parent != nullptr)
+                    {
+                        root = root->parent;
+                    }
+                    root->unmatched_defines.erase(dval);
+
                     found = true;
                     break;
                 }
@@ -632,6 +643,14 @@ int cpp_read_line(gmx_cpp_t *handlep, int n, char buf[])
             }
             if (nn > 0)
             {
+                // Need to erase  unmatched define in original handle
+                gmx_cpp_t root = handle;
+                while (root->parent != nullptr)
+                {
+                    root = root->parent;
+                }
+                root->unmatched_defines.erase(define.name);
+
                 std::string  name;
                 const char  *ptr = buf;
                 const char  *ptr2;
@@ -743,3 +762,20 @@ char *cpp_error(gmx_cpp_t *handlep, int status)
 
     return gmx_strdup(buf);
 }
+
+std::string checkAndWarnForUnusedDefines(const gmx_cpp &handle)
+{
+    std::string warning;
+    if (!handle.unmatched_defines.empty())
+    {
+        warning = "The following macros were defined in the 'define' mdp field with the -D prefix, but "
+            "were not used in the topology:\n";
+        for (auto &str : handle.unmatched_defines)
+        {
+            warning += ("    " + str + "\n");
+        }
+        warning += "If you haven't made a spelling error, either use the macro you defined, "
+            "or don't define the macro";
+    }
+    return warning;
+}