没有合适的资源?快使用搜索试试~ 我知道了~
理论计算机科学电子笔记107(2004)57-69www.elsevier.com/locate/entcsEclipse中的重构感知版本控制Ulf Asklund2隆德大学瑞典隆德摘要为了在团队开发环境中完全支持重构,我们实现了一个重构感知存储库提供程序,作为Eclipse中Java开发工具的扩展插件。版本控制系统将重构视为描述为语义操作的第一类更改,而不是分散在源代码树上的结果更改集。我们还介绍了重构感知的合并,它合并重构以及传统的变化,利用重构的语义来检测和解决合并冲突。它还确保在合并之后保留重构的语义含义关键词:重构,版本控制,合并,Eclipse,软件配置管理1介绍重构是一种安全有效的方法,可以以可控的方式提高代码质量。重构不同于传统的改变,因为它们保证语义上有效并具有语义意义,例如,在重命名变量之后,该特定变量的所有使用仍然应该引用相同的变量。重构是安全的,因为在重构之前必须满足一组先决条件。以确保所需的源代码转换有效。重构是有效的,因为适当的工具支持使开发人员能够在一个操作中应用大量相关的更改,这些更改分散在整个源代码树中。由于重构在本质上是全局的,例如。重命名1电子邮件:torbjorn. cs.lth.se2 电子邮件:ulf. cs.lth.se1571-0661 © 2004 Elsevier B. V.根据CC BY-NC-ND许可证开放访问。doi:10.1016/j.entcs.2004.02.04858T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)57一个类可以忽略任何其他类,因为重命名的类在整个源代码树中最常见,工具支持将显著提高这些操作的速度。这些好处适用于单用户环境中的重构,但是传统团队开发存储库提供者的引入由于工具支持不足而减少了上述好处。当合并来自多个开发人员的代码时,每个分支的前提条件都已经检查过了,但合并后的源代码树却没有。因此,对于合并树,可能不满足确保安全重构的在合并过程中,源自重构的更改被视为许多不相关的小更改,开发人员可能必须手动合并这些更改,以防合并协议由于重构仅应用于合并的分支之一,而不是两个涉及的版本,因此合并的结果可能不包括重构的语义含义。在没有应用重构的分支中的改变可能违反先决条件,禁止重构执行,或者新引入的代码应该被重构拒绝,例如,添加在并行分支中重命名的方法的调用应该被改变为使用新名称而不是旧名称。我们注意到传统工具在为团队开发提供版本控制和合并支持方面存在三个主要缺陷• 开发人员不能从重构的角度来看待文件的两个版本之间的差异,而只能将其视为所产生的单独的、不相关的更改。这是因为重构的语义在存储库中时丢失了。• 在团队开发期间使用重构时,缺乏对重构感知合并的支持,即应用于一个分支的重构的语义含义在合并期间不能容易地转移到另一个分支。• 当源代码元素被重构时缺乏可跟踪性,例如,移动和重命名的代码块在版本历史中无法追溯到它们的起源,而是被视为不相关的删除和添加操作。为了更好地支持团队开发环境中的重构,我们开发了一个重构感知存储库提供程序的模型这个提供者存储和检索传统的变化和整个重构,这使得两个版本之间的差异的重构方面的表现此外,当两个分支合并时,此语义知识用于更好地检测潜在冲突,并(在可能的情况下)自动合并其结果是,一些意外合并和错误合并冲突的情况现在可以正确地自动合并,T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)5759冲突更经常地被检测到并且更好地呈现给开发者。我们已经在原型中实现了这个模型的一部分,作为Eclipse中Java开发工具的扩展插件。目前,原型支持重构感知的自动合并两个重构(重命名和移动)与手动更改。本文其余部分的结构如下。第2节介绍了重构和各种合并策略。重构感知的合并和重构感知的版本控制这两个概念将在第3节和第4节中通过示例进行介绍和激发。第5节概述了支持重构感知版本控制的版本控制模型和合并策略。在第6节中给出了在Eclipse中集成该模型和策略的经验。第7节介绍了相关工作,第8节总结了本文,并讨论了一些未来的工作。2预赛2.1重构重构[1]是保留程序语义但改进源代码的高级源代码更改,例如。提取方法中的公共代码以避免代码重复。每个重构都有一组先决条件,在执行该重构时,这些先决条件必须为真,以确保代码转换产生语义上等效的程序,例如,在执行提取方法重构时,可能还不存在具有所选名称的方法。以下操作是Eclipse中可用的典型重构,也将用于说明本文中提出的改进版本控制:rename重命名类、字段或方法声明以及同一实体的所有用法。当重命名方法时,必须考虑多态性和重写。先决条件包括检查新名称是否已在使用中或被另一个声明隐藏。像rename类这样的refactoring,既改变声明又改变使用位置,通常会涉及到分散在整个代码库中的大量更改。move将字段或方法从一个类移动到另一个类。先决条件确保移动不会违反可见性和调用使用站点的覆盖2.2版本控制和历史跟踪版本控制用于跟踪文档的演变,并比较文档的任何两个版本。文档内容的每个稳定问题60T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)57被认为是一个版本,通常由开发人员显式创建。一个版本最重要的属性是它的不变性,也就是说,当一个版本被冻结时,它的内容永远不能被修改。版本可以以不同的方式组织。当按顺序组织时,它们通常被称为修订,而被组织为平行开发线的版本被称为分支。两个文档之间的差异通常表示为一系列添加、更改和删除操作,这些操作也用于重新创建文档的旧版本。2.3合并合并是将对一个文档所做的更改并行合并到一个统一版本中的任务。不兼容的并行更改会导致必须手动解决的合并冲突。以下技术代表了现有技术的现状,并且彼此正交,因此可以以任何组合使用。有关软件合并的全面调查,请参见[7]。2.3.1文本、句法或语义合并合并工具之间的一个重要区别是文档的表示方式文档的文本表示将每个文档视为一个XML结构。最常见的方法是将文档分成单行文本,然后在这些行上执行合并。由于这种粒度,对同一行的并行更改不能很好地处理,因为即使希望对同一行进行两次修改的组合,也只能选择这些行中的一条。更好的方法是考虑文档的语法结构。这在语法定义明确的编程语言中尤其强大。软件文档最常见的结构化表示是与所用编程语言的上下文无关语法相匹配的解析树。合并工具可以检测上下文无关的连接符,并确保合并的结果在语法上正确。一个更先进的方法是考虑所用语言的静态语义。目标是检测语义合并冲突,这些冲突在合并时会生成静态语义编译时错误或意外的运行时行为。这种方法通常依赖于复杂的数学形式,并且当前的实现不适用于成熟的语言。2.3.2基于状态、更改或操作的合并合并工具之间的另一个区别是合并期间在基于状态的合并中,只有原始文档和T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)5761考虑两个同时改变的版本的最终结果。基于更改的合并工具使用有关对文档所做的确切更改的信息。这些更改通常与集成开发环境中采取的操作相对应。额外的信息可以用于改进的冲突检测。基于操作的合并是基于更改的合并的一种特殊情况,它将更改建模为显式转换。3重构感知合并合并工具的主要目标是找到并行进行的独立更改,然后自动合并它们。从属更改会导致需要手动解决的合并冲突。在一个简单的基于行的合并工具中,只有对同一行所做的更改才被认为是独立的,而结构化合并工具则认为对同一节点所做的更改是独立的。虽然肯定有用,但这种类型的依赖性检测无法检测某些依赖性,并且也检测到一些非预期的依赖性。由于重构的语义和意图是明确定义的,因此这些信息可以用于执行更智能的合并,从而更好地反映开发人员的意图。下面的例子,在Java [2]代码上运行,说明了重构感知合并工具可以改进当前最先进的合并行为的场景,并将结果与传统的合并进行比较3.1自动重构感知合并而不是意外合并两个版本的自动合并不能保证具有开发人员预期的语义行为。下面的示例说明了重构感知合并如何执行自动重构感知合并,以便在重命名方法时更好地反映开发人员的意图,同时在另一个类中添加对同一方法的调用,如图1所示。重命名重构的语义表明,声明以及所选实体的所有使用都将被重命名。因此,重构感知的合并将确保并行分支中添加的调用传统的合并执行自动合并,但添加的调用仍然具有旧的类名,因此导致编译时错误,而不是语义正确的程序。3.2自动重构感知合并而不是合并配置在某些情况下,传统的合并冲突可以使用重构感知合并来自动解决。考虑将方法从一个62T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)57添加方法sub(),以替代方法pull()在Stack传统合并错误pop()改进的语义合并图1.方法并并行添加对同一方法的调用类到另一个类,例如将一个方法拉到一个超类,并并行地改变同一个方法。传统的合并工具将单个移动操作视为与更改操作并行完成的两个不相关的删除和添加操作。删除和更改操作将删除相同的代码T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)5763从而在自动合并加法操作时导致冲突。重构感知的合并可以检测到要移动的更改方法,并在将其移动到新位置之前将更改应用于该方法传统合并中的合并冲突被自动重构感知合并所取代。3.3重构合并配置而不是意外合并重构的先决条件可用于检测自动传统合并在语义上不正确的情况。这样的错误作为合并冲突比作为编译时错误更好地解决。源自重构前置条件的合并冲突通常会导致大量的编译时错误,这将在3.4节中讨论。考虑将一个方法从超类拉到它的一个子类中,同时在超类中添加对同一方法的使用。下拉方法重构的前提条件是,只有当该方法的所有调用都是通过静态限定为子类的引用完成时,该方法才可以移动到子类中。添加的调用违反了这些先决条件,与传统合并执行的语义不正确的自动合并相比,重构感知合并将检测到合并冲突。3.4单个重构合并并发症而不是大量错误一次重构通常代表了大量的更改,而前提条件保证所有这些更改都可以作为一个事务应用。从开发人员的角度来看,通过将源自合并的错误检测为合并冲突而不是编译时错误,通常可以减少所经历的错误的数量。考虑内联方法,即用方法体替换所有调用位置,同时更改该方法中使用的属性的可见性。 内联的先决条件规定,内联方法体中使用的所有属性必须从所有方法调用站点可见。 重构感知的合并会将其检测为合并冲突,并向开发人员显示为单个错误,而传统的合并会合并更改,并且在方法已内联的每个方法调用站点处都会出现编译时错误4重构感知历史跟踪历史跟踪涉及到对每个版本化元素(如Java类、方法和字段)的演化具有完全的可跟踪性。传统版本-64T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)57控制系统放松了对所做重构的可跟踪性当比较两个版本时,语义上有意义的重构不会被显示出来,而只会显示其结果的变化。4.1即使在结构变化的背景下,为了保持元素演化的完全可跟踪性,重要的是更改导致更改操作,而不是不相关的删除和添加操作。因此,重命名字段应该导致更改操作,而不是删除该字段并使用新名称添加无关的字段。类似的问题源于几次重构改变了版本树的结构,这通常被认为是两个不相关的删除和添加操作,因此历史记录丢失,如上所述。上述情况的典型示例是提取方法。许多重构乍一看似乎保留了树结构,实际上执行了结构变化。如果类节点按其名称排序,则重命名类可能会导致结构变化。 因此,在本发明中,重要的是,版本增量包含重构信息,以便能够保持尽可能完整的历史可追溯性4.2更多描述性历史重构的一个重要好处是经常被忽视的是为改进源代码的常见高级更改定义了一个术语这些重构名称也可以用来提供更多描述性的历史跟踪。指示元素被重命名比更传统的对定义的不相关更改更具描述性,并且该元素的所有使用都分散在源代码中5版本模型和合并策略版本模型被设计为从集成开发环境中现有的重构功能中受益因此,使用客户端-服务器模型,其中服务器的唯一责任是存储版本化数据的结构化因此,服务器不需要知道重构或所使用的合并策略,而客户端可以重用IDE中的现有基础设施来应用重构和先决条件检查。T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)57655.1使用节点标识进行使用结构化版本控制是很自然的,因为编程语言在结构上是分层的。我们让树节点表示语言的抽象语法树,节点内容包含具有完整布局和注释的具体语法每个节点都有一个不可变的ID,这个ID使得跟踪节点的历史变得很容易,即使它已经被移动,或者它的内容或类型发生了变化。节点标识使我们能够描述独立于并行非冲突重构的重构增量。例如,如果一个方法的主体发生了变化,然后在一个分支中移动,而即使其内容和位置发生变化,节点ID也不会改变5.2重构是第一个类的改变我们存储重构操作本身,而不是将重构的结果存储为一组具体的更改,例如,我们存储操作重命名节点N,而不是对声明节点N和使用相同声明的所有节点的单个更改。 这样我们不仅可以把一个可能很大的集合同时还存储所需的语义。这确保了程序员对源代码的手动更改被存储为传统的删除、添加和更改操作,但使用节点标识来指定被删除的节点。由于在执行重构时节点标识被保留,因此这些更改在结构更改后仍然可以应用,例如,即使在移动了已删除的方法之后,也可以定位已5.3重构感知合并重构感知合并工具有两个主要任务:检测语义合并冲突,如果可能的话,执行自动重构感知合并。合并分几步完成。首先,合并传统的更改,并检测源自这些更改的合并冲突。然后,检查重构先决条件以检测将通过将重构应用于合并版本而引起的可能的语义合并冲突如果先决条件成立,合并将继续进行自动重构感知合并。首先应用传统的更改,然后再进行重构。这确保了所有传统的改变都被重构引起的整个源转换所影响。因为节点标识总是被保留的,无论是对于传统的更改还是当执行重构时,66T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)57结构改变可以成功地与其他改变合并,例如,即使在移动了被改变的方法之后,也可以定位(和改变)被改变的方法主体。6在Eclipse我们实现了一个插件,它将重构感知存储库提供程序添加到Eclipse中的Java开发工具(JDT)中,以进行概念验证。当前的实现支持重命名和移动重构的重构感知自动合并。我们相信这种方法足够通用,可以扩展到其他重构。目标是在JDT中重用尽可能多的基础设施,同时实现第5节中描述的版本控制模型。6.1模型Java开发工具提供了Java项目的高级结构化表示,称为Java模型,其中节点是包、编译单元、类、类成员等的句柄。这些句柄用于重构操作以选择目标元素,也用于报告已删除的元素。该模型中的节点标识在重构过程中不被保留,由于我们的模型需要不可变的节点标识,我们选择创建一个单独的Java模型(进一步称为RAJM -重构感知Java模型),它复制JavaModel并在重构过程中保留节点标识。手动更改直接复制到RAJM中。我们注册一个Java元素-ChangedObject,以便在JavaModel发生更改时接收事件。这些被报告为传统的添加、删除、更改和移动增量。添加和删除报告更改一直到类型成员,而更改和移动似乎只报告更改到受约束的编译单元。因此,我们将整个编译单元与RAJM进行比较,以找到实际的更改,然后将其存储在RAJM中。重构应该更仔细地跟踪。重构引起的一系列变化例如,当执行移动时,在Java模型中进行的删除和添加操作应该转换为真正的移动到RAJM中的已删除节点为了检测重构何时执行,我们在当前API中添加了自己的钩子(这些钩子将在即将发布的3.0中提供,以支持第三方插件参与重构)。通过这种方式,我们增加了在重构启动时通知观察者的可能性T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)5767并以这种方式将模型更改绑定到某个重构。 在RAJM中,每个重构都有自己的规则来将Java模型操作转换为RAJM。为什么不直接将这些转换添加到现有的重构实现中呢?看起来我们需要大量的语义知识来在版本模型中复制这些转换。然而,许多重构对实际结构的净影响很小或没有净影响,并且有时提供被重构节点的信息。例如,重命名重构不改变结构,而只改变节点内容,而移动元素重构提供对源和目标位置元素的访问。也就是说,实际的转换是删除和添加操作的匹配,将它们转换为一个移动。由于我们使用RAJM的JavaModel结构,最细粒度的元素是类型成员,因此节点内容可能是整个方法体。更合适的解决方案是使用底层AST作为复制的结构。然而,JavaModel仍然需要用于重构参数,并且比AST节点更方便地访问其语法源范围。需要重构参数来表示重构增量和节点内容的源范围。我们当前的实现复制了JavaModel,并依赖于方法体的传统合并,同时仍然演示了中心概念。6.2三角洲我们存储两种不同类型的增量,手动更改的增量和重构的增量。两个重构或两个显式版本之间的每一组手动更改都存储为单个增量,由对显式节点ID进行操作的常规添加、删除和更改操作组成。每次重构都会产生一个单独的增量,用于存储操作和使用的参数.由于JavaModel句柄用于选择目标元素并在重构中报告已删除的元素,因此每个参数首先从JavaModel句柄转换为不可变的节点ID。这样,即使节点已移动或其内容已更改,也可以将增量应用于所需的目标节点。7相关工作在合并版本时使用静态语义信息并不是一个新的想法,但在几种语义合并方法中使用,例如[3]。我们的方法不同之处在于,我们将语义合并限制在重构中,不仅语义定义良好,而且从开发人员的角度来看,68T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)57是很好理解的。通过将重构存储为第一个类更改,我们的系统类似于基于操作的合并[5]和面向更改的版本控制[4]。然而,这些方法并没有考虑像重构这样的高级操作以及为操作定义的严格语义行为在[8]和[6]中描述了检测和合并软件中重命名实体的两种方法在[8]中,描述了具有嵌套块结构的语言的通用重命名检测,并使用上下文信息实现。但是,这种方法在面向对象语言上不起作用。在[6]中,使用基于统计规则的方法来检测重命名的实体。这两种方法都没有试图将这些想法推广到其他语义敏感的变化。8结论和今后的工作我们已经介绍了重构感知的版本控制和重构感知的合并,这两种技术可以更好地支持团队开发过程中的重构重构感知的版本控制将重构视为描述为语义动作的第一类更改,而不是分散在源代码树上的结果更改集。支持重构的分支合并支持重构和传统更改的自动语义合并。重构的语义含义既用于在合并期间检测语义合并冲突,又用于确保在合并之后也保留语义含义下面的场景说明了重构感知版本控制工具的改进:• 自动重构感知合并而不是意外合并• 自动重构感知合并而不是合并配置• 重构合并配置而不是意外合并• 单个重构合并并发症而不是大量错误该技术已经实现了扩展一个通用的语法合并与重构感知合并支持Java在原型插件的Java开发工具在Eclipse环境中。由于该技术使用了现有的重构支持,我们相信它适合于集成在任何支持重构和版本控制的集成开发环境中。有很多有趣的方法来继续这项研究。交互式合并我们希望进一步研究如何使用合并冲突的改进检测来简化解决冲突所需的交互式合并。可见差异改进的版本历史跟踪将在第二节中讨论T. 埃克曼,U.Asklund/Electronic Notes in Theoretical Computer Science 107(2004)5769第4部分为版本差异的图形可视化提供了进一步的挑战。更多的重构目前重命名和移动重构已经实现,但我们计划实现更多的重构,以验证该方法是否足够通用。版本模型粒度当前的实现使用Java模型来检测源代码树的更改以及模型到版本的更改。由于Java模型中的最细粒度是在类型成员级别,因此我们计划使用抽象语法树将粒度改进到表达式。引用[1] Fowler,M.,“重构:改进现有代码的设计”,Addison-Wesley Longman出版公司,股份有限公司、1999年[2] Gosling,J.,B. 乔伊,G。Steele和G.Bracha,两千[3] Horwitz,S.,识别程序的两个版本之间的语义和文本差异,在:ACM SIGPLAN 1990年编程语言设计和实现会议论文集(1990年),pp。234-245。[4] Lie,A.,R. Conradi,T. M. Didriksen和E.- A. 软件工程数据库中的面向变更的版本控制,SIGSOFT Softw。Eng. Notes14(1989),pp. 56比65[5] Lippe,E.和N. van Oosterom,基于操作的合并,在:ACM SIGSOFT软件开发环境研讨会论文集(1992年),pp. 78比87[6] Malpohl,G.,J. J.Hunt和W. F. Tichy,重命名检测,自动化软件工程,2000年,pp. 73比80[7] Mens,T.,A state-of-the-art survey on software merging,IEEE Transactions on SoftwareEngineering28(2002),pp. 449-462.[8] Westfechtel,B.,面向结构的软件文档修订合并,见:第三届软件配置管理国际研讨会论文集(1991年),pp. 68比79
下载后可阅读完整内容,剩余1页未读,立即下载
cpongm
- 粉丝: 5
- 资源: 2万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- Java集合ArrayList实现字符串管理及效果展示
- 实现2D3D相机拾取射线的关键技术
- LiveLy-公寓管理门户:创新体验与技术实现
- 易语言打造的快捷禁止程序运行小工具
- Microgateway核心:实现配置和插件的主端口转发
- 掌握Java基本操作:增删查改入门代码详解
- Apache Tomcat 7.0.109 Windows版下载指南
- Qt实现文件系统浏览器界面设计与功能开发
- ReactJS新手实验:搭建与运行教程
- 探索生成艺术:几个月创意Processing实验
- Django框架下Cisco IOx平台实战开发案例源码解析
- 在Linux环境下配置Java版VTK开发环境
- 29街网上城市公司网站系统v1.0:企业建站全面解决方案
- WordPress CMB2插件的Suggest字段类型使用教程
- TCP协议实现的Java桌面聊天客户端应用
- ANR-WatchDog: 检测Android应用无响应并报告异常
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功