Commits

senex committed eec1a06

Resolved Feature request 3567217:
Now #defines, #includes, and #pragmas are parsed into

defines, includes, and pragmas lists that are part of the CppHeader class

Comments (0)

Files changed (2)

CppHeaderParser/CppHeaderParser.py

                 var['unresolved'] = True
                 if 'method' in var: var['method']['unresolved_parameters'] = True
                 #var['raw_type'] = var['raw_type'][2:]
+        
+        # Take care of #defines and #pragmas etc
+        trace_print("Processing precomp_macro_buf: %s"%self._precomp_macro_buf)
+        for m in self._precomp_macro_buf:
+            macro = m.replace("<CppHeaderParser_newline_temp_replacement>\\n", "\n")
+            try:
+                if macro.lower().startswith("#define"):
+                    trace_print("Adding #define %s"%macro)
+                    self.defines.append(macro.split(" ", 1)[1].strip())
+                elif macro.lower().startswith("#pragma"):
+                    trace_print("Adding #pragma %s"%macro)
+                    self.pragmas.append(macro.split(" ", 1)[1].strip())
+                elif macro.lower().startswith("#include"):
+                    trace_print("Adding #include %s"%macro)
+                    self.includes.append(macro.split(" ", 1)[1].strip())
+                else:
+                    debug_print("Cant detect what to do with precomp macro '%s'"%macro)
+            except: pass
+        self._precomp_macro_buf = None
+        
 
     def concrete_typedef( self, key ):
         if key not in self.typedefs:
         self.classes = Resolver.CLASSES
         #Functions that are not part of a class
         self.functions = []
+        
+        self.pragmas = []
+        self.defines = []
+        self.includes = []
+        self._precomp_macro_buf = [] #for internal purposes, will end up filling out pragmras and defines at the end
 
         self.enums = []
         self.global_enums = {}
         
         # Strip out template declarations
         headerFileStr = re.sub("template[\t ]*<[^>]*>", "", headerFileStr)
-        
+
         # Strip out #defines
         # Based from http://stackoverflow.com/questions/2424458/regular-expression-to-match-cs-multiline-preprocessor-statements
         matches = re.findall(r'(?m)^#[Dd][Ee][Ff][Ii][Nn][Ee] (?:.*\\\r?\n)*.*$', headerFileStr)
         for m in matches:
             #Keep the newlines so that linecount doesnt break
+            self._precomp_macro_buf.append(m)
             num_newlines = len(filter(lambda a: a=="\n", m))
-            headerFileStr = headerFileStr.replace(m, "\n" * num_newlines)
+            new_m = m.replace("\n", "<CppHeaderParser_newline_temp_replacement>\\n")
+            if (num_newlines > 1):
+                new_m += "\n"*(num_newlines)
+            headerFileStr = headerFileStr.replace(m, new_m)
                 
         #Filter out Extern "C" statements.  These are order dependent
         matches = re.findall(re.compile(r'extern[\t ]+"[Cc]"[\t \n\r]*{', re.DOTALL), headerFileStr)
                 if not tok: break
                 tok.value = TagStr(tok.value, lineno=tok.lineno)
                 if tok.type == 'NAME' and tok.value in self.IGNORE_NAMES: continue
-                if tok.type not in ('PRECOMP_MACRO', 'PRECOMP_MACRO_CONT'): self.stack.append( tok.value )
+                self.stack.append( tok.value )
                 curLine = tok.lineno
                 curChar = tok.lexpos
+                if (tok.type in ('PRECOMP_MACRO', 'PRECOMP_MACRO_CONT')):
+                    debug_print("PRECOMP: %s"%tok)
+                    self._precomp_macro_buf.append(tok.value)
+                    continue
                 if (tok.type == 'OPEN_BRACE'):
                     if len(self.nameStack) >= 2 and is_namespace(self.nameStack):    # namespace {} with no name used in boost, this sets default?
                         if self.nameStack[1] == "__IGNORED_NAMESPACE__CppHeaderParser__":#Used in filtering extern "C"

CppHeaderParser/test/test_CppHeaderParser.py

     def test_property(self):
         self.assertEqual(self.cppHeader.classes["Pear"]["properties"]["private"][0]["name"], "stem_property")
 
+
+
+# Bug 3567217
+class Macro_TestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.cppHeader = CppHeaderParser.CppHeader(r"""
+#include <string.h>
+#include "../../debug.h"
+
+#define ONE 1
+#define TWO_NUM_N_NAME "2 (TWO)"
+#pragma once
+
+#define DEBUG_PRINT(x)           \
+    printf("---------------\n"); \
+    printf("DEBUG: %d\n", x);    \
+    printf("---------------\n");""", "string")
+
+    def test_includes(self):
+        self.assertEqual(self.cppHeader.includes, ['<string.h>', '"../../debug.h"'])
+    
+    def test_pragmas(self):
+        self.assertEqual(self.cppHeader.pragmas, ['once'])
+        
+    def test_pragmas0(self):
+        self.assertEqual(self.cppHeader.defines[0], 'ONE 1')
+            
+    def test_pragmas1(self):
+        self.assertEqual(self.cppHeader.defines[1], 'TWO_NUM_N_NAME "2 (TWO)"')
+                
+    def test_pragmas2(self):
+        self.assertEqual(self.cppHeader.defines[2], 'DEBUG_PRINT(x)           \\\n    printf("---------------\\n"); \\\n    printf("DEBUG: %d\\n", x);    \\\n    printf("---------------\\n");')
+
 if __name__ == '__main__':
     unittest.main()
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.