- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试使用 Roslyn API 做一些基本的代码差异,但遇到了一些意想不到的问题。本质上,我有两段相同的代码,只是添加了一行。这应该只返回更改文本的行,但出于某种原因,它告诉我一切都已更改。我也试过只编辑一行而不是添加一行,但我得到了相同的结果。我希望能够将其应用于源文件的两个版本以识别两者之间的差异。这是我目前使用的代码:
SyntaxTree tree = SyntaxTree.ParseCompilationUnit(
@"using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(""Hello, World!"");
}
}
}");
var root = (CompilationUnitSyntax)tree.Root;
var compilation = Compilation.Create("HelloWorld")
.AddReferences(
new AssemblyFileReference(
typeof(object).Assembly.Location))
.AddSyntaxTrees(tree);
var model = compilation.GetSemanticModel(tree);
var nameInfo = model.GetSemanticInfo(root.Usings[0].Name);
var systemSymbol = (NamespaceSymbol)nameInfo.Symbol;
SyntaxTree tree2 = SyntaxTree.ParseCompilationUnit(
@"using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(""Hello, World!"");
Console.WriteLine(""jjfjjf"");
}
}
}");
var root2 = (CompilationUnitSyntax)tree2.Root;
var compilation2 = Compilation.Create("HelloWorld")
.AddReferences(
new AssemblyFileReference(
typeof(object).Assembly.Location))
.AddSyntaxTrees(tree2);
var model2 = compilation2.GetSemanticModel(tree2);
var nameInfo2 = model2.GetSemanticInfo(root2.Usings[0].Name);
var systemSymbol2 = (NamespaceSymbol)nameInfo2.Symbol;
foreach (TextSpan t in tree2.GetChangedSpans(tree))
{
Console.WriteLine(tree2.Text.GetText(t));
}
System
using System
Collections
Generic
using System
Linq
using System
Text
namespace HelloWorld
{
class Program
{
static
Main
args
{
Console
WriteLine
"Hello, World!"
Console.WriteLine("jjfjjf");
}
}
}
Press any key to continue . . .
最佳答案
布鲁斯·鲍顿的猜测是正确的。 GetChangedSpans 方法并不是一种通用的语法差异机制,用于在没有共享历史记录的两个语法树之间进行区分。相反,它旨在将通过编辑产生的两棵树变成公共(public)树,并确定树的哪些部分因编辑而不同。
如果您使用第一个解析树并将新语句作为编辑插入其中,那么您会看到一组小得多的更改。
如果我简要描述 Roslyn 词法分析器和解析器的工作原理,可能会有所帮助。
基本思想是词法生成的“语法标记”和解析器生成的“语法树”是不可变的。他们永远不会改变。因为它们永远不会改变,我们可以在新的解析树中重用以前的解析树的部分。 (具有此属性的数据结构通常称为“持久”数据结构。)
因为我们可以重用现有的部分,例如,我们可以对给定 token 的每个实例使用相同的值,比如 class
,出现在程序中。每个class
的长度和内容token 完全一样;唯一区分两种不同的东西 class
标记是它们的琐事,(围绕它们的间距和注释)和它们的位置,以及它们的父节点——包含标记的更大的语法节点。
当你解析一个文本块时,我们会以一种持久的、不可变的形式生成语法标记和语法树,我们称之为“绿色”形式。然后我们将绿色节点包裹在“红色”层中。绿色层对位置、 parent 等一无所知。红色层可以。 (这些异想天开的名字是因为当我们第一次在白板上绘制这个数据结构时,那些是我们使用的颜色。)当您对给定的语法树进行编辑时,我们会查看之前的语法树,识别更改的节点,然后仅在更改的主干上构建新节点。绿树的所有其他分支保持不变。
当比较两棵树时,基本上我们所做的是取绿色节点的集合差。如果其中一棵树是通过编辑另一棵树生成的,那么几乎所有的绿色节点都将相同,因为只重建了脊椎。树差异算法将识别更改的节点并计算出受影响的跨度。
如果两棵树没有共同的历史,那么它们唯一共同的绿色节点就是单个 token ,正如我之前所说,它们在任何地方都可以重复使用。每个更高级别的绿色语法节点将是不同的绿色节点,因此被树差异引擎视为不同,即使其文本相同。
此方法的目的是允许编辑器代码快速对文本缓冲区的哪些部分需要进行保守的猜测,例如,在编辑或撤消或诸如此类的事情之后重新着色。假设是这些树具有历史关系。目的不是提供通用的文本差异机制;已经有很多很棒的工具了。
例如,假设您已将第一个程序粘贴到编辑器中,然后突出显示整个内容,然后将第二个程序粘贴到编辑器中。人们可以合理地期望编辑器不会浪费时间试图找出粘贴的代码的哪些部分恰好与先前粘贴的代码相同。这可能非常昂贵,答案很可能是“不多”。相反,编辑器做出了保守的假设,即整个粘贴区域是全新的且完全不同的代码。它不会花任何时间尝试在旧代码和新代码之间进行对应;它重新解析并因此重新着色整个事物。
另一方面,如果您刚刚粘贴了单个不同的语句,那么编辑引擎会简单地将编辑插入到正确的位置。解析树将在可能的情况下重新使用现有的绿色节点重新生成,差异引擎将识别需要重新着色的跨度:具有不同绿色节点的跨度。
这一切都有意义吗?
更新:
哈,显然凯文和我都在相邻的办公室同时输入相同的答案。有点重复的努力,但我认为这两个答案对这种情况都有很好的看法。 :-)
关于c# - 使用 Roslyn CTP API 的代码差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8311671/
最初的问题是我有一个巨大的解决方案,其中项目有不同的选项(例如,x64 或 x86 配置、是否允许不安全代码等等)。我正在尝试使用 Roslyn (2.9.0) 通过 DEBUG x64 配置来编译\
当前的 .Net 编译器是完全独立的。 Roslyn 应该将它们组合成一个编译器。有谁知道这是否会引入在单个项目中使用多种语言的能力?或者甚至可能在单个文件/类中? 目前您能做的最好的事情就是在一个解
我已经开始使用 Roslyn 的语法和语义 API。还没有真正深入挖掘,但是语义 API 是否提供了任何代码优化,例如: 消除死代码,吊装或某种指针分析?或者其他分析? 我知道 roslyn 提供了
Roslyn 似乎提供了新的 API 来公开许多编译器内部数据结构以进行代码分析等。为此目的重写了 C# 和 VB 编译器。那么除了新的 API 之外,我还可以访问编译器源代码吗? 最佳答案 Rosl
我的解决方案在 roslyn 中构建正常,因此应该解析所有类型 我能够像这样获取在元数据程序集中定义的类型: string typeName = "MyCompany.MyLibrary.MyType
Roslyn 项目中的 CaaS(编译器即服务)是什么? 与当前 C# 4.0 编译器相比,使用 Roslyn 功能如何提高 C# 应用程序的性能? Roslyn-CTP 有哪些已知的限制/问题? 最
我们最近将构建系统从 VS 2013 升级到 2015 Update 2,构建时间显着增加。我们的构建环境是独立的,因此我们从包(使用 devpath)而不是从安装位置运行 MSBuild。查看日志,
我正在为 Roslyn 制作一个分析器。我正在做的是一种诊断,可以找到太长的方法。我想对任何被认为“太长”的内容进行可配置,最好是整个解决方案或项目的一种配置。解决这个问题的最佳方法是什么? 我想到的
如果我想在我的应用程序中支持脚本,是否 scriptcs提供比仅使用普通 Vanilla 的任何特殊优势 Roslyn脚本引擎? 最佳答案 不幸的是,目前还没有太多关于托管 scriptcs 的文档,
我创建了这个测试控制台应用程序,以使用 Roslyn 脚本引擎(在 Microsoft.CodeAnalysis.CSharp.Scripting nuget 包中)运行一些 C# 代码。
我对 stackoverflow 做了一些研究,但找不到我需要的结果。 我的问题是“如何使用 Roslyn 确定源文件的行代码位置”。 例如:我有一个源文件(名为:sample.cs)和它看起来像的内
来自 Visual Studio 2015 CTP5 包,如何获取当前的 Roslyn 工作区? 我在看 How to get reference to 'Roslyn' Workspace obje
我想在另一个非脚本 Roslyn 编译中将脚本作为动态程序集重用,但我终究无法弄清楚如何实现它。 例如,假设我以正常方式创建脚本,然后使用类似以下内容将脚本作为程序集发送到字节流: var compi
我使用 VS 2015 模板创建了一个 Roslyn 分析器。假设默认情况下启用了诊断,我的一切正常,包括单元测试。 如果我将DiagnosticDescriptor 上的isEnabledByDef
如何从 ITypeSymbol 获取基础类型对于 IEnumerable ?我明白了ITypeSymbol.OriginalDefinition包含指向 IEnumerable<> 的链接,但是我在哪
我有一个 VS 包项目,我需要从加载的 IVsSolution 访问 Roslyn 或 Microsoft.CodeAnalysis 的工作区或解决方案对象. 我需要知道如何实现这一目标? 我找到了t
我在做什么用一句话 查看分行 Update-1来自 Roslyn github repository ,构建 csc.exe,并使用我自己构建的 csc.exe 版本编译随机解决方案。 预期结果 我希
在我投入大量时间学习 roslyn 编译器服务之前,我想问一下 roslyn 是否可以实现以下场景。是否可以编译程序集而无需将任何内容写入磁盘并执行它?我基于元模型生成完整的解决方案,我想采用它并编译
我有一个带有两个输出 dll 的解决方案(实际上更多,但让我们保持简单)。项目“Special”引用项目“Common”。 我尝试编写一个代码生成器来解析“Special”中的一些文件,并将生成的 s
我创建了几个诊断分析器和代码修复。它们都按照预期在实验 hive 中工作。 我将它们构建为 Nuget 包,并添加到 VS2015 正常实例中的项目中。奇怪的是,分析器/代码修复组合之一可以正常工作,
我是一名优秀的程序员,十分优秀!