(微软 VC++ 小组关于 c++ parser 对 intellisense 支持的一些讨论, 比较有意思)
Rebuilding Intellisense
Our first design decision involved both accuracy and scalability. We needed to decouple the Intellisense operations that require precise compilation information (e.g. getting parameter help for a function in the open cpp file) from the features that require large-scale indexes (e.g. jumping to a random symbol or listing all classes in a project).
Finally, we needed to re-invent our parsers. We quickly realized that the only reasonable solution for scalability was to populate our database incrementally . While this seems obvious at first, it goes against the basic compilation mechanism of C++ in which a small change to a header file can change the meaning of every source file that follows, and indeed every source file in a solution.
Although C++ is a “context sensitive” language in the strongest sense of the word, we were able to write a “context-free” parser for it that uses heuristics to parse C++ declarations with a high degree of accuracy.
Dev10 Is Just The Beginning
A good architecture for intellisense separates parsing from semantic analysis. Semantic analysis is expensive, so for intellisense you only want to do it for the one item the user is asking about.
We considered writing a new C++ front-end for intellisense. Thankfully we came to our senses – C++ is far too rich and complex. It would take much longer than one product cycle for that, and we needed something more expedient. So we “derived” our intellisense compiler from our command line C++ compiler through the liberal use of ifdefs in the code. We called the intellisense compiler FEACP, for “Front End Auto Complete Parser”. Our command line compiler is called C1XX, for “C++ phase 1” (turn the X’s sideways).
FEACP was a product success, but a testing and maintenance nightmare.
The lesson here is that supporting two different compilers in the same source base is only slightly smarter than supporting two completely separate compilers, and neither is a good choice for long-term maintainability
With the speed and capacity of modern machines we knew one compiler could service both code generation and intellisense for C++. What we lacked was a high-level internal representation of the source code. If we had that, we could query the representation to service intellisense requests, or lower it to produce machine code.
IntelliSense, Part 2 (The Future)
As Visual C++ has evolved over the years there has been tension between getting code information quickly and getting it accurately.
Also, there is a new parser for populating this store.
This parser will perform a file-based parse of the files in the solution in a way which is independent of any configuration or compile options and does not look inside included headers. Because of this, a change to a header will not cause a reparse of all the files that include it, which avoids one of the fundamental problems today.
The parser is also designed to be extremely resilient and will be able to handle ambiguous code, mismatched braces or parentheses, and supports a “hint” file. Due to the nature of C/C++ macros and because we aren’t parsing into headers, there is good bit of code that would be misunderstood. The hint file will contain definitions for certain macros that fundamentally change the parsing and therefore understanding of a file.
However, this style of parsing means that we don’t get completely accurate information in all cases, which is especially desirable in the Intellisense scenarios of auto-complete, parameter info, and quick info. To handle this, we will be doing a full parse of a translation unit (i.e. .cpp file) when it is opened in the IDE. This parse will be done in the fullest sense possible and will use all compile options and other configuration settings. All headers will be included and parsed in the exact context that they are being used for.
The database created from the file-based parse will be used for ClassView, CodeModel, NavBar, and other browsing based operations. In the case of “Find All References”, the database will be used to identify possible candidates and the full parser will then be used to positively identify the actual references.