TestCodeThe purpose of the generated software is to generateC #OrVB. NETSource codeFiles, and previous benchmarksC #OrVB. NETCompare the source code files. If the generated file is inconsistent with the reference file, it indicates that the software has potential coding errors (Bug).
The current method is to read the two files into the memory, one line and one line are compared word by word. Of course, to avoid space issues, the file has already deleted spaces. However, the problem with this method is that, in many cases, although the placement order of code lines in the source code files generated by the software is different, the functions are completely the same. For exampleVisual StudioWriteWinformProgramInInitializecomponent ()In the function, you can generate the code of the create button and then generate the code of the text box. The effect is exactly the same as that of the code of the create text box and then generate the code of the button.
Can this be done by reading two files into the memory, sorting the files by code lines, and then comparing them? This does not work either, because you cannot put the code that calls the constructor object after the code that uses the object.
Therefore, we want to determine whether we can compare the actualCodedomAnd BenchmarkCodedom? In general. NetIn the world, all the functions generated by code areCodedomTechnology.CodedomIn layman's terms, it is an abstract code tree.-Independent from anyProgramming LanguageWhich can be traversed using different language generators.CodedomTo generate source code files in different languages-RightCodedomFor more information, seeMsdnThe above description.
However, this scheme was rejected because many benchmark source code files have been generated in the file comparison mode during the testing of the previous versions. If you useCodedomTechnology, which means that the corresponding benchmark needs to be re-generated for the previous hundreds of benchmark source filesCodedom.
At this time, I want to use the compiler to analyze two source code files, and then compare the abstract syntax tree of the results to achieve similarCodedom. I have two compilers that support this solution. One isCsc.exeAnd the other isVisual StudioA compiler that supports real-time syntax highlighting.
To support real-time syntax highlighting and smart sensing,Visual StudioIn fact, the compiler is run in the background thread for real-time compilation. When syntax highlighting, intelligent sensing, and code refactoring are required,Visual StudioQuery the symbol table and abstract syntax tree saved in the background compiler to obtain relevant real-time information.
But this compiler is compiled with our daily work.C #(Here we useC #For example) compilerCsc.exeNot the same thing. The reason for this isVisual StudioImplement a compiler separately, because
1.In real-time syntax highlighting, smart sensing, and other functions. The compiler does not process a complete source code. This followsCsc.exeDifferent becauseCsc.exeComplete ProcessingC #Source code.
2.In addition,Csc.exeThe attitude of the compiler for syntax errors is different from that for the compiler that supports syntax highlighting,Csc.exeNo syntax errors can be tolerated, that is, once a syntax error occurs,Csc.exeYou can reject subsequent semantic analysis. However, the syntax highlighting compiler cannot. After all, when using it, the programmer is writing the source code, and there are many unfinished parts. Even if the source file code entered has many syntax errors, the syntax highlighting compiler must be able to continue to execute subsequent compilation tasks (such as semantic analysis ).
3.The syntax highlighting compiler also needs to implement the incremental compilation function, that is, the source code lines that will be added later are merged into the compiled code. For example, during debugging, you can define a variable in the "immediate" window, then, the calculation results of the variable and the existing variable of the program can be evaluated simultaneously in the same expression.
The following two. Net assemblyYesVisual StudioUsed to supportC #Real-time syntax highlighting and other functions (in fact, you also needWin32 C ++OfDLLFile, but this file will not be directly used by my program ):
1.Microsoft. visualstudio. CSHARP. Services. Language. dll
2.Microsoft. visualstudio. CSHARP. Services. Language. InterOP. dll
These two files are only installedVisual StudioYou canVisual StudioYou can alsoGACFind them.
Because the twoDLLNoVisual StudioPublicAPI, So they andVisual StudioThe binding is very tight, that is, you can onlyVisual StudioAnd cannot be used in other programs unless youVisual Studio SDKLihuVisual StudioAll provided obscure interfaces are implemented.
Therefore, my program hasVisual StudioPlug-in (Add in) In the formVisual StudioIn (I usedVisual Studio 2010) Create a newVisual Studio add-insProject:DLLFile reference. InExecImplement the corresponding logic in the function. The following is the relevant code:
Public VoidExec (StringCommandname, vscommandexecoption executeoption,Ref ObjectVarin,Ref ObjectVarout,Ref BoolHandled) { Handled =False; If(Executeoption = vscommandexecoption. vscommandexecoptiondodefault) { If(Commandname ="Myaddin1.connect. myaddin1") { //Implement custom Logic Testcsharpcompiler (); Handled =True; Return; } } } Private VoidTestcsharpcompiler () { //Get currentVisual StudioSolution,IfVisual StudioNo solutions yet //Is the default null solution VaRSolution = (solution2) _ applicationobject. solution; //Create a new"C #Command Line Program (C # console application)"Engineering VaRCstemplatepath = solution. getprojecttemplate ("Leleapplication.zip","CSHARP"); //Project name (Test Project) And save the project's folder path (D: \ temp \ test) Solution. addfromtemplate (cstemplatepath,@ "D: \ temp \ test","Test Project",False); VaRProject = solution. Projects. Item (1 ); //D: \ temp \ test. CS) Add to the newly created Project Project. projectitems. addfromfilecopy (@ "D: \ temp \ test. cs"); //Activate the Compiler VaRHost =NewIdecompilerhost (); VaRCompiler = host. createcompiler (project ); Sourcefile source =Null; //There are usually many files in the project. Find the source files you are interested in. //Because the abstract syntax tree of that file is what I want Foreach(VaRFileInCompiler. sourcefiles) { If(String. Compare (file. Key. value,@ "D: \ temp \ test. cs", Stringcomparison. Invariantcultureignorecase) = 0) { Source = file. value; Break; } } //Obtain the root node of the syntax tree, which is generally the namespace at the outermost layer of the source file. VaRTree = source. getparsetree (); Idecompilation compilation = (idecompilation) compiler. getcompilation (); //Get the node of the first namespace in the syntax tree Compilation. compiletypeornamespace (tree. rootnode ); VaRNode = tree. rootnodeAsNamespacedeclarationnode; //Obtain the class definitions, sub-namespaces, or other //Nodes that can be defined in the namespace Foreach(VaRChildInNode. namespacememberdeclarations. Root. Children) { If(ChildIsBinaryexpressionnode) { VaRBnode = ChildAsBinaryexpressionnode; VaRLeft = bnode. LeftAsClassdeclarationnode; VaRRight = bnode. RightAsClassdeclarationnode; Trace. writeline (left. identifier. Name. Text ); Trace. writeline (right. identifier. Name. Text ); } Else { Trace. writeline (child. asname (). Name. Text ); } } } |
The above code is only used for demonstration. The parsed source code (Test. CS) Has been included in the source file of the complete project below (the project file isVisual Studio 2010Format ):
/Files/killmyday/myaddinforast.zip