mirror of https://github.com/icsharpcode/ILSpy.git
969 changed files with 51916 additions and 113370 deletions
@ -1,2 +1,3 @@
@@ -1,2 +1,3 @@
|
||||
*.sln -crlf |
||||
*.csproj -crlf |
||||
*.cs text diff=csharp |
||||
*.sln text eol=crlf |
||||
*.csproj text eol=crlf |
||||
|
@ -1,5 +1,6 @@
@@ -1,5 +1,6 @@
|
||||
bin |
||||
obj |
||||
*.suo |
||||
/lib/*.dll |
||||
/ICSharpCode.NRefactory.Tests/PartCover/* |
||||
_ReSharper*/* |
||||
|
@ -1,27 +0,0 @@
@@ -1,27 +0,0 @@
|
||||
using System.Reflection; |
||||
using System.Runtime.CompilerServices; |
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("ICSharpCode.NRefactory.CSharp.AstVerifier")] |
||||
[assembly: AssemblyDescription("")] |
||||
[assembly: AssemblyConfiguration("")] |
||||
[assembly: AssemblyCompany("")] |
||||
[assembly: AssemblyProduct("")] |
||||
[assembly: AssemblyCopyright("mike")] |
||||
[assembly: AssemblyTrademark("")] |
||||
[assembly: AssemblyCulture("")] |
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")] |
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("")]
|
||||
|
@ -1,69 +0,0 @@
@@ -1,69 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<PropertyGroup> |
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
||||
<ProductVersion>10.0.0</ProductVersion> |
||||
<SchemaVersion>2.0</SchemaVersion> |
||||
<ProjectGuid>{961DADFA-7CE6-429F-BC22-47630D6DB826}</ProjectGuid> |
||||
<OutputType>Exe</OutputType> |
||||
<RootNamespace>ICSharpCode.NRefactory.CSharp.AstVerifier</RootNamespace> |
||||
<AssemblyName>AstVerifier</AssemblyName> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>full</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\Debug</OutputPath> |
||||
<DefineConstants>DEBUG;</DefineConstants> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
||||
<DebugType>none</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\Release</OutputPath> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'net_4_5_Debug|AnyCPU' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>full</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\Debug</OutputPath> |
||||
<DefineConstants>DEBUG;</DefineConstants> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'net_4_5_Release|AnyCPU' "> |
||||
<DebugType>none</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\Release</OutputPath> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
||||
</PropertyGroup> |
||||
<ItemGroup> |
||||
<Reference Include="System" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Compile Include="Main.cs" /> |
||||
<Compile Include="AssemblyInfo.cs" /> |
||||
</ItemGroup> |
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
||||
<ItemGroup> |
||||
<ProjectReference Include="..\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj"> |
||||
<Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project> |
||||
<Name>ICSharpCode.NRefactory.CSharp</Name> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> |
||||
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project> |
||||
<Name>ICSharpCode.NRefactory</Name> |
||||
</ProjectReference> |
||||
</ItemGroup> |
||||
</Project> |
@ -1,83 +0,0 @@
@@ -1,83 +0,0 @@
|
||||
using System; |
||||
using System.IO; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.AstVerifier |
||||
{ |
||||
class MainClass |
||||
{ |
||||
static bool IsMatch (string src1, string src2, out int i, out int j) |
||||
{ |
||||
i = 0; |
||||
j = 0; |
||||
while (i < src1.Length && j < src2.Length) { |
||||
char c1 = src1 [i]; |
||||
char c2 = src2 [j]; |
||||
if (char.IsWhiteSpace (c1)) { |
||||
i++; |
||||
continue; |
||||
} |
||||
if (char.IsWhiteSpace (c2)) { |
||||
j++; |
||||
continue; |
||||
} |
||||
if (c1 != c2) |
||||
return false; |
||||
i++; |
||||
j++; |
||||
} |
||||
while (i < src1.Length && char.IsWhiteSpace (src1[i])) { |
||||
i++; |
||||
} |
||||
while (j < src2.Length && char.IsWhiteSpace (src2[j])) { |
||||
j++; |
||||
} |
||||
|
||||
return i == src1.Length && j == src2.Length; |
||||
} |
||||
|
||||
public static void Main (string[] args) |
||||
{ |
||||
if (args.Length == 0) { |
||||
Console.WriteLine ("Usage: AstVerifier [-v|-verbose] [Directory]"); |
||||
return; |
||||
} |
||||
string directory = args[args.Length - 1]; |
||||
bool verboseOutput = args.Length > 1 && (args[0] == "-v" || args[0] == "-verbose"); |
||||
|
||||
try { |
||||
if (!Directory.Exists (directory)) { |
||||
Console.WriteLine ("Directory not found."); |
||||
return; |
||||
} |
||||
} catch (IOException) { |
||||
Console.WriteLine ("Exception while trying to access the directory."); |
||||
return; |
||||
} |
||||
int failed = 0, passed = 0; |
||||
Console.WriteLine ("search in " + directory); |
||||
foreach (var file in Directory.GetFileSystemEntries (directory, "*", SearchOption.AllDirectories)) { |
||||
if (!file.EndsWith (".cs")) |
||||
continue; |
||||
string text = File.ReadAllText (file); |
||||
var unit = SyntaxTree.Parse (text, file); |
||||
if (unit == null) |
||||
continue; |
||||
string generated = unit.GetText (); |
||||
int i, j; |
||||
if (!IsMatch (text, generated, out i, out j)) { |
||||
if (i > 0 && j > 0 && verboseOutput) { |
||||
Console.WriteLine ("fail :" + file + "----original:"); |
||||
Console.WriteLine (text.Substring (0, Math.Min (text.Length, i + 1))); |
||||
Console.WriteLine ("----generated:"); |
||||
Console.WriteLine (generated.Substring (0, Math.Min (generated.Length, j + 1))); |
||||
} |
||||
failed++; |
||||
} else { |
||||
passed++; |
||||
} |
||||
} |
||||
|
||||
Console.WriteLine ("{0} passed, {1} failed", passed, failed); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,157 @@
@@ -0,0 +1,157 @@
|
||||
//
|
||||
// LovalVariableDeclarationSpace.cs
|
||||
//
|
||||
// Author:
|
||||
// Simon Lindgren <simon.n.lindgren@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Simon Lindgren
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using ICSharpCode.NRefactory.Utils; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Analysis |
||||
{ |
||||
/// <summary>
|
||||
/// Represents a declaration space. (§3.3)
|
||||
/// </summary>
|
||||
public class LocalDeclarationSpace |
||||
{ |
||||
/// <summary>
|
||||
/// Maps from variable name to the declarations in this declaration space.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This maps from variable name
|
||||
/// </remarks>
|
||||
MultiDictionary<string, AstNode> declarations = new MultiDictionary<string, AstNode> (); |
||||
|
||||
public LocalDeclarationSpace() |
||||
{ |
||||
Children = new List<LocalDeclarationSpace> (); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The child declaration spaces.
|
||||
/// </summary>
|
||||
public IList<LocalDeclarationSpace> Children { |
||||
get; |
||||
private set; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The parent declaration space.
|
||||
/// </summary>
|
||||
/// <value>The parent.</value>
|
||||
public LocalDeclarationSpace Parent { |
||||
get; |
||||
private set; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The names declared in this declaration space, excluding child spaces.
|
||||
/// </summary>
|
||||
/// <value>The declared names.</value>
|
||||
public ICollection<string> DeclaredNames { |
||||
get { |
||||
return declarations.Keys; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Get all nodes declaring the name specified in <paramref name="name"/>.
|
||||
/// </summary>
|
||||
/// <returns>The declaring nodes.</returns>
|
||||
/// <param name="name">The declaration name.</param>
|
||||
public IEnumerable<AstNode> GetNameDeclarations(string name) |
||||
{ |
||||
return declarations [name].Concat(Children.SelectMany(child => child.GetNameDeclarations(name))); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Adds a child declaration space.
|
||||
/// </summary>
|
||||
/// <param name="child">The <see cref="LocalDeclarationSpace"/> to add.</param>
|
||||
public void AddChildSpace(LocalDeclarationSpace child) |
||||
{ |
||||
if (child == null) |
||||
throw new ArgumentNullException("child"); |
||||
if (Children.Contains(child)) |
||||
throw new InvalidOperationException("the child was already added"); |
||||
|
||||
Children.Add(child); |
||||
child.Parent = this; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Adds a new declaration to the declaration space.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the declared variable.</param>
|
||||
/// <param name="node">A node associated with the declaration.</param>
|
||||
public void AddDeclaration(string name, AstNode node) |
||||
{ |
||||
if (name == null) |
||||
throw new ArgumentNullException("name"); |
||||
if (node == null) |
||||
throw new ArgumentNullException("node"); |
||||
declarations.Add(name, node); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Determines if the name exists in the this declaration space.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if the name specified in <paramref name="name"/> is used in this variable declaration space, <c>false</c> otherwise.</returns>
|
||||
/// <param name="name">The name to look for.</param>
|
||||
/// <param name="includeChildren">When <c>true</c>, child declaration spaces are included in the search.</param>
|
||||
public bool ContainsName(string name, bool includeChildren) |
||||
{ |
||||
if (name == null) |
||||
throw new ArgumentNullException("name"); |
||||
|
||||
if (declarations.Keys.Contains(name)) |
||||
return true; |
||||
return includeChildren && Children.Any(child => child.ContainsName(name, true)); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Determines whether the name specified in <paramref name="name"/> is used in surrouding code.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if the name is used, <c>false</c> otherwise.</returns>
|
||||
/// <param name="name">The name to check.</param>
|
||||
/// <remarks>
|
||||
/// Contrary to <see cref="ContainsName"/>, this method also checks parent declaration spaces
|
||||
/// for name conflicts. Typically, this will be the right method to use when determining if a name can be used.
|
||||
/// </remarks>
|
||||
public bool IsNameUsed(string name) |
||||
{ |
||||
if (name == null) |
||||
throw new ArgumentNullException("name"); |
||||
|
||||
return IsNameUsedBySelfOrParent(name) || Children.Any(child => child.ContainsName(name, true)); |
||||
} |
||||
|
||||
bool IsNameUsedBySelfOrParent(string name) |
||||
{ |
||||
if (declarations.Keys.Contains(name)) |
||||
return true; |
||||
return Parent != null && Parent.IsNameUsedBySelfOrParent(name); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,138 @@
@@ -0,0 +1,138 @@
|
||||
//
|
||||
// LocalDeclarationSpaceVisitor.cs
|
||||
//
|
||||
// Author:
|
||||
// Simon Lindgren <simon.n.lindgren@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Simon Lindgren
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Analysis |
||||
{ |
||||
public class LocalDeclarationSpaceVisitor : DepthFirstAstVisitor |
||||
{ |
||||
LocalDeclarationSpace currentDeclarationSpace; |
||||
Dictionary<AstNode, LocalDeclarationSpace> nodeDeclarationSpaces = new Dictionary<AstNode, LocalDeclarationSpace>(); |
||||
|
||||
public LocalDeclarationSpace GetDeclarationSpace(AstNode node) |
||||
{ |
||||
if (node == null) |
||||
throw new ArgumentNullException("node"); |
||||
while (node != null) { |
||||
LocalDeclarationSpace declarationSpace; |
||||
if (nodeDeclarationSpaces.TryGetValue(node, out declarationSpace)) |
||||
return declarationSpace; |
||||
node = node.Parent; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
#region Visitor
|
||||
|
||||
void AddDeclaration(string name, AstNode node) |
||||
{ |
||||
if (currentDeclarationSpace != null) |
||||
currentDeclarationSpace.AddDeclaration(name, node); |
||||
} |
||||
|
||||
public override void VisitVariableInitializer(VariableInitializer variableInitializer) |
||||
{ |
||||
AddDeclaration(variableInitializer.Name, variableInitializer); |
||||
base.VisitVariableInitializer(variableInitializer); |
||||
} |
||||
|
||||
public override void VisitParameterDeclaration(ParameterDeclaration parameterDeclaration) |
||||
{ |
||||
AddDeclaration(parameterDeclaration.Name, parameterDeclaration); |
||||
base.VisitParameterDeclaration(parameterDeclaration); |
||||
} |
||||
|
||||
void VisitNewDeclarationSpace(AstNode node) |
||||
{ |
||||
var oldDeclarationSpace = currentDeclarationSpace; |
||||
currentDeclarationSpace = new LocalDeclarationSpace(); |
||||
if (oldDeclarationSpace != null) |
||||
oldDeclarationSpace.AddChildSpace(currentDeclarationSpace); |
||||
|
||||
VisitChildren(node); |
||||
|
||||
nodeDeclarationSpaces.Add(node, currentDeclarationSpace); |
||||
currentDeclarationSpace = oldDeclarationSpace; |
||||
} |
||||
|
||||
#region Declaration space creating nodes
|
||||
|
||||
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) |
||||
{ |
||||
VisitNewDeclarationSpace(methodDeclaration); |
||||
} |
||||
|
||||
public override void VisitBlockStatement(BlockStatement blockStatement) |
||||
{ |
||||
VisitNewDeclarationSpace(blockStatement); |
||||
} |
||||
|
||||
public override void VisitSwitchStatement(SwitchStatement switchStatement) |
||||
{ |
||||
VisitNewDeclarationSpace(switchStatement); |
||||
} |
||||
|
||||
public override void VisitForeachStatement(ForeachStatement foreachStatement) |
||||
{ |
||||
AddDeclaration(foreachStatement.VariableName, foreachStatement); |
||||
VisitNewDeclarationSpace(foreachStatement); |
||||
} |
||||
|
||||
public override void VisitForStatement(ForStatement forStatement) |
||||
{ |
||||
VisitNewDeclarationSpace(forStatement); |
||||
} |
||||
|
||||
public override void VisitUsingStatement(UsingStatement usingStatement) |
||||
{ |
||||
VisitNewDeclarationSpace(usingStatement); |
||||
} |
||||
|
||||
public override void VisitLambdaExpression(LambdaExpression lambdaExpression) |
||||
{ |
||||
VisitNewDeclarationSpace(lambdaExpression); |
||||
} |
||||
|
||||
public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) |
||||
{ |
||||
VisitNewDeclarationSpace(anonymousMethodExpression); |
||||
} |
||||
|
||||
public override void VisitEventDeclaration(EventDeclaration eventDeclaration) |
||||
{ |
||||
AddDeclaration(eventDeclaration.Name, eventDeclaration); |
||||
} |
||||
|
||||
public override void VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration) |
||||
{ |
||||
VisitNewDeclarationSpace(eventDeclaration); |
||||
} |
||||
|
||||
#endregion
|
||||
#endregion
|
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// NullValueAnalysis.cs
|
||||
//
|
||||
// Author:
|
||||
// Luís Reis <luiscubal@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Luís Reis
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Analysis |
||||
{ |
||||
/// <summary>
|
||||
/// Represents the null value status of a variable at a specific location.
|
||||
/// </summary>
|
||||
public enum NullValueStatus |
||||
{ |
||||
/// <summary>
|
||||
/// The value of the variable is unknown, possibly due to limitations
|
||||
/// of the null value analysis.
|
||||
/// </summary>
|
||||
Unknown = 0, |
||||
/// <summary>
|
||||
/// The value of the variable is unknown and even assigning it to a
|
||||
/// value won't change its state, since it has been captured by a lambda
|
||||
/// that may change it at any time (potentially even from a different thread).
|
||||
/// Only going out of scope and creating a new variable may change the value
|
||||
/// of this variable.
|
||||
/// </summary>
|
||||
CapturedUnknown, |
||||
/// <summary>
|
||||
/// This variable is potentially unassigned.
|
||||
/// </summary>
|
||||
Unassigned, |
||||
/// <summary>
|
||||
/// The value of the variable is provably null.
|
||||
/// </summary>
|
||||
DefinitelyNull, |
||||
/// <summary>
|
||||
/// The value of the variable might or might not be null
|
||||
/// </summary>
|
||||
PotentiallyNull, |
||||
/// <summary>
|
||||
/// The value of the variable is provably not null
|
||||
/// </summary>
|
||||
DefinitelyNotNull, |
||||
/// <summary>
|
||||
/// The position of this node is unreachable, therefore the value
|
||||
/// of the variable is not meaningful.
|
||||
/// Alternatively, it might mean no local variable exists with the requested name.
|
||||
/// </summary>
|
||||
UnreachableOrInexistent, |
||||
/// <summary>
|
||||
/// The analyser has encountered an error when attempting to find the value
|
||||
/// of this variable.
|
||||
/// </summary>
|
||||
Error |
||||
} |
||||
|
||||
public static class NullValueStatusExtensions |
||||
{ |
||||
public static bool IsDefiniteValue (this NullValueStatus self) { |
||||
return self == NullValueStatus.DefinitelyNull || self == NullValueStatus.DefinitelyNotNull; |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,691 @@
@@ -0,0 +1,691 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Threading; |
||||
using ICSharpCode.NRefactory.CSharp.Completion; |
||||
using System.Collections.ObjectModel; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Analysis |
||||
{ |
||||
/// <summary>
|
||||
/// C# Semantic highlighter.
|
||||
/// </summary>
|
||||
public abstract class SemanticHighlightingVisitor<TColor> : DepthFirstAstVisitor |
||||
{ |
||||
protected CancellationToken cancellationToken = default (CancellationToken); |
||||
|
||||
protected TColor defaultTextColor; |
||||
protected TColor referenceTypeColor; |
||||
protected TColor valueTypeColor; |
||||
protected TColor interfaceTypeColor; |
||||
protected TColor enumerationTypeColor; |
||||
protected TColor typeParameterTypeColor; |
||||
protected TColor delegateTypeColor; |
||||
|
||||
protected TColor methodCallColor; |
||||
protected TColor methodDeclarationColor; |
||||
|
||||
protected TColor eventDeclarationColor; |
||||
protected TColor eventAccessColor; |
||||
|
||||
protected TColor propertyDeclarationColor; |
||||
protected TColor propertyAccessColor; |
||||
|
||||
protected TColor fieldDeclarationColor; |
||||
protected TColor fieldAccessColor; |
||||
|
||||
protected TColor variableDeclarationColor; |
||||
protected TColor variableAccessColor; |
||||
|
||||
protected TColor parameterDeclarationColor; |
||||
protected TColor parameterAccessColor; |
||||
|
||||
protected TColor valueKeywordColor; |
||||
protected TColor externAliasKeywordColor; |
||||
protected TColor varKeywordTypeColor; |
||||
|
||||
/// <summary>
|
||||
/// Used for 'in' modifiers on type parameters.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 'in' may have a different color when used with 'foreach'.
|
||||
/// 'out' is not colored by semantic highlighting, as syntax highlighting can already detect it as a parameter modifier.
|
||||
/// </remarks>
|
||||
protected TColor parameterModifierColor; |
||||
|
||||
/// <summary>
|
||||
/// Used for inactive code (excluded by preprocessor or ConditionalAttribute)
|
||||
/// </summary>
|
||||
protected TColor inactiveCodeColor; |
||||
|
||||
protected TColor stringFormatItemColor; |
||||
|
||||
|
||||
protected TColor syntaxErrorColor; |
||||
|
||||
protected TextLocation regionStart; |
||||
protected TextLocation regionEnd; |
||||
|
||||
protected CSharpAstResolver resolver; |
||||
bool isInAccessorContainingValueParameter; |
||||
|
||||
protected abstract void Colorize(TextLocation start, TextLocation end, TColor color); |
||||
|
||||
#region Colorize helper methods
|
||||
protected void Colorize(Identifier identifier, ResolveResult rr) |
||||
{ |
||||
if (identifier.IsNull) |
||||
return; |
||||
if (rr.IsError) { |
||||
Colorize(identifier, syntaxErrorColor); |
||||
return; |
||||
} |
||||
if (rr is TypeResolveResult) { |
||||
if (blockDepth > 0 && identifier.Name == "var" && rr.Type.Kind != TypeKind.Null && rr.Type.Name != "var" ) { |
||||
Colorize(identifier, varKeywordTypeColor); |
||||
return; |
||||
} |
||||
|
||||
TColor color; |
||||
if (TryGetTypeHighlighting (rr.Type.Kind, out color)) { |
||||
Colorize(identifier, color); |
||||
} |
||||
return; |
||||
} |
||||
var mrr = rr as MemberResolveResult; |
||||
if (mrr != null) { |
||||
TColor color; |
||||
if (TryGetMemberColor (mrr.Member, out color)) { |
||||
Colorize(identifier, color); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if (rr is MethodGroupResolveResult) { |
||||
Colorize (identifier, methodCallColor); |
||||
return; |
||||
} |
||||
|
||||
var localResult = rr as LocalResolveResult; |
||||
if (localResult != null) { |
||||
if (localResult.Variable is IParameter) { |
||||
Colorize (identifier, parameterAccessColor); |
||||
} else { |
||||
Colorize (identifier, variableAccessColor); |
||||
} |
||||
} |
||||
|
||||
|
||||
VisitIdentifier(identifier); // un-colorize contextual keywords
|
||||
} |
||||
|
||||
protected void Colorize(AstNode node, TColor color) |
||||
{ |
||||
if (node.IsNull) |
||||
return; |
||||
Colorize(node.StartLocation, node.EndLocation, color); |
||||
} |
||||
#endregion
|
||||
|
||||
protected override void VisitChildren(AstNode node) |
||||
{ |
||||
for (var child = node.FirstChild; child != null; child = child.NextSibling) { |
||||
if (child.StartLocation < regionEnd && child.EndLocation > regionStart) |
||||
child.AcceptVisitor(this); |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Visit all children of <c>node</c> until (but excluding) <c>end</c>.
|
||||
/// If <c>end</c> is a null node, nothing will be visited.
|
||||
/// </summary>
|
||||
protected void VisitChildrenUntil(AstNode node, AstNode end) |
||||
{ |
||||
if (end.IsNull) |
||||
return; |
||||
Debug.Assert(node == end.Parent); |
||||
for (var child = node.FirstChild; child != end; child = child.NextSibling) { |
||||
cancellationToken.ThrowIfCancellationRequested(); |
||||
if (child.StartLocation < regionEnd && child.EndLocation > regionStart) |
||||
child.AcceptVisitor(this); |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Visit all children of <c>node</c> after (excluding) <c>start</c>.
|
||||
/// If <c>start</c> is a null node, all children will be visited.
|
||||
/// </summary>
|
||||
protected void VisitChildrenAfter(AstNode node, AstNode start) |
||||
{ |
||||
Debug.Assert(start.IsNull || start.Parent == node); |
||||
for (var child = (start.IsNull ? node.FirstChild : start.NextSibling); child != null; child = child.NextSibling) { |
||||
cancellationToken.ThrowIfCancellationRequested(); |
||||
if (child.StartLocation < regionEnd && child.EndLocation > regionStart) |
||||
child.AcceptVisitor(this); |
||||
} |
||||
} |
||||
|
||||
public override void VisitIdentifier(Identifier identifier) |
||||
{ |
||||
switch (identifier.Name) { |
||||
case "add": |
||||
case "async": |
||||
case "await": |
||||
case "get": |
||||
case "partial": |
||||
case "remove": |
||||
case "set": |
||||
case "where": |
||||
case "yield": |
||||
case "from": |
||||
case "select": |
||||
case "group": |
||||
case "into": |
||||
case "orderby": |
||||
case "join": |
||||
case "let": |
||||
case "on": |
||||
case "equals": |
||||
case "by": |
||||
case "ascending": |
||||
case "descending": |
||||
case "dynamic": |
||||
case "var": |
||||
// Reset color of contextual keyword to default if it's used as an identifier.
|
||||
// Note that this method does not get called when 'var' or 'dynamic' is used as a type,
|
||||
// because types get highlighted with valueTypeColor/referenceTypeColor instead.
|
||||
Colorize(identifier, defaultTextColor); |
||||
break; |
||||
case "global": |
||||
// Reset color of 'global' keyword to default unless its used as part of 'global::'.
|
||||
MemberType parentMemberType = identifier.Parent as MemberType; |
||||
if (parentMemberType == null || !parentMemberType.IsDoubleColon) |
||||
Colorize(identifier, defaultTextColor); |
||||
break; |
||||
} |
||||
// "value" is handled in VisitIdentifierExpression()
|
||||
// "alias" is handled in VisitExternAliasDeclaration()
|
||||
} |
||||
|
||||
public override void VisitSimpleType(SimpleType simpleType) |
||||
{ |
||||
var identifierToken = simpleType.IdentifierToken; |
||||
VisitChildrenUntil(simpleType, identifierToken); |
||||
Colorize(identifierToken, resolver.Resolve(simpleType, cancellationToken)); |
||||
VisitChildrenAfter(simpleType, identifierToken); |
||||
} |
||||
|
||||
public override void VisitMemberType(MemberType memberType) |
||||
{ |
||||
var memberNameToken = memberType.MemberNameToken; |
||||
VisitChildrenUntil(memberType, memberNameToken); |
||||
Colorize(memberNameToken, resolver.Resolve(memberType, cancellationToken)); |
||||
VisitChildrenAfter(memberType, memberNameToken); |
||||
} |
||||
|
||||
public override void VisitIdentifierExpression(IdentifierExpression identifierExpression) |
||||
{ |
||||
var identifier = identifierExpression.IdentifierToken; |
||||
VisitChildrenUntil(identifierExpression, identifier); |
||||
if (isInAccessorContainingValueParameter && identifierExpression.Identifier == "value") { |
||||
Colorize(identifier, valueKeywordColor); |
||||
} else { |
||||
Colorize(identifier, resolver.Resolve(identifierExpression, cancellationToken)); |
||||
} |
||||
VisitChildrenAfter(identifierExpression, identifier); |
||||
} |
||||
|
||||
public override void VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression) |
||||
{ |
||||
var memberNameToken = memberReferenceExpression.MemberNameToken; |
||||
VisitChildrenUntil(memberReferenceExpression, memberNameToken); |
||||
ResolveResult rr = resolver.Resolve(memberReferenceExpression, cancellationToken); |
||||
Colorize(memberNameToken, rr); |
||||
VisitChildrenAfter(memberReferenceExpression, memberNameToken); |
||||
} |
||||
|
||||
void HighlightStringFormatItems(PrimitiveExpression expr) |
||||
{ |
||||
if (!(expr.Value is string)) |
||||
return; |
||||
int line = expr.StartLocation.Line; |
||||
int col = expr.StartLocation.Column; |
||||
TextLocation start = TextLocation.Empty; |
||||
for (int i = 0; i < expr.LiteralValue.Length; i++) { |
||||
char ch = expr.LiteralValue [i]; |
||||
|
||||
if (NewLine.GetDelimiterType(ch, i + 1 < expr.LiteralValue.Length ? expr.LiteralValue [i + 1] : '\0') != UnicodeNewline.Unknown) { |
||||
line++; |
||||
col = 1; |
||||
continue; |
||||
} |
||||
|
||||
|
||||
if (ch == '{' && start.IsEmpty) { |
||||
char next = i + 1 < expr.LiteralValue.Length ? expr.LiteralValue [i + 1] : '\0'; |
||||
if (next == '{') { |
||||
i++; |
||||
col += 2; |
||||
continue; |
||||
} |
||||
start = new TextLocation(line, col); |
||||
} |
||||
col++; |
||||
if (ch == '}' &&!start.IsEmpty) { |
||||
char next = i + 1 < expr.LiteralValue.Length ? expr.LiteralValue [i + 1] : '\0'; |
||||
if (next == '}') { |
||||
i++; |
||||
col += 2; |
||||
continue; |
||||
} |
||||
Colorize(start, new TextLocation(line, col), stringFormatItemColor); |
||||
start = TextLocation.Empty; |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
public override void VisitInvocationExpression(InvocationExpression invocationExpression) |
||||
{ |
||||
Expression target = invocationExpression.Target; |
||||
if (target is IdentifierExpression || target is MemberReferenceExpression || target is PointerReferenceExpression) { |
||||
var invocationRR = resolver.Resolve(invocationExpression, cancellationToken) as CSharpInvocationResolveResult; |
||||
if (invocationRR != null) { |
||||
if (invocationExpression.Parent is ExpressionStatement && (IsInactiveConditionalMethod(invocationRR.Member) || IsEmptyPartialMethod(invocationRR.Member))) { |
||||
// mark the whole invocation statement as inactive code
|
||||
Colorize(invocationExpression.Parent, inactiveCodeColor); |
||||
return; |
||||
} |
||||
|
||||
Expression fmtArgumets; |
||||
IList<Expression> args; |
||||
if (invocationRR.Arguments.Count > 1 && FormatStringHelper.TryGetFormattingParameters(invocationRR, invocationExpression, out fmtArgumets, out args, null)) { |
||||
var expr = invocationExpression.Arguments.First() as PrimitiveExpression; |
||||
if (expr != null) |
||||
HighlightStringFormatItems(expr); |
||||
} |
||||
} |
||||
|
||||
VisitChildrenUntil(invocationExpression, target); |
||||
|
||||
// highlight the method call
|
||||
var identifier = target.GetChildByRole(Roles.Identifier); |
||||
VisitChildrenUntil(target, identifier); |
||||
if (invocationRR != null && !invocationRR.IsDelegateInvocation) { |
||||
Colorize(identifier, methodCallColor); |
||||
} else { |
||||
ResolveResult targetRR = resolver.Resolve(target, cancellationToken); |
||||
Colorize(identifier, targetRR); |
||||
} |
||||
VisitChildrenAfter(target, identifier); |
||||
VisitChildrenAfter(invocationExpression, target); |
||||
} else { |
||||
VisitChildren(invocationExpression); |
||||
} |
||||
} |
||||
|
||||
#region IsInactiveConditional helper methods
|
||||
bool IsInactiveConditionalMethod(IParameterizedMember member) |
||||
{ |
||||
if (member.SymbolKind != SymbolKind.Method || member.ReturnType.Kind != TypeKind.Void) |
||||
return false; |
||||
foreach (var baseMember in InheritanceHelper.GetBaseMembers(member, false)) { |
||||
if (IsInactiveConditional (baseMember.Attributes)) |
||||
return true; |
||||
} |
||||
return IsInactiveConditional(member.Attributes); |
||||
} |
||||
|
||||
static bool IsEmptyPartialMethod(IParameterizedMember member) |
||||
{ |
||||
if (member.SymbolKind != SymbolKind.Method || member.ReturnType.Kind != TypeKind.Void) |
||||
return false; |
||||
var method = (IMethod)member; |
||||
return method.IsPartial && !method.HasBody; |
||||
} |
||||
|
||||
bool IsInactiveConditional(IList<IAttribute> attributes) |
||||
{ |
||||
bool hasConditionalAttribute = false; |
||||
foreach (var attr in attributes) { |
||||
if (attr.AttributeType.Name == "ConditionalAttribute" && attr.AttributeType.Namespace == "System.Diagnostics" && attr.PositionalArguments.Count == 1) { |
||||
string symbol = attr.PositionalArguments[0].ConstantValue as string; |
||||
if (symbol != null) { |
||||
hasConditionalAttribute = true; |
||||
var cu = this.resolver.RootNode as SyntaxTree; |
||||
if (cu != null) { |
||||
if (cu.ConditionalSymbols.Contains(symbol)) |
||||
return false; // conditional is active
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return hasConditionalAttribute; |
||||
} |
||||
#endregion
|
||||
|
||||
public override void VisitExternAliasDeclaration (ExternAliasDeclaration externAliasDeclaration) |
||||
{ |
||||
var aliasToken = externAliasDeclaration.AliasToken; |
||||
VisitChildrenUntil(externAliasDeclaration, aliasToken); |
||||
Colorize (aliasToken, externAliasKeywordColor); |
||||
VisitChildrenAfter(externAliasDeclaration, aliasToken); |
||||
} |
||||
|
||||
public override void VisitAccessor(Accessor accessor) |
||||
{ |
||||
isInAccessorContainingValueParameter = accessor.Role != PropertyDeclaration.GetterRole; |
||||
try { |
||||
VisitChildren(accessor); |
||||
} finally { |
||||
isInAccessorContainingValueParameter = false; |
||||
} |
||||
} |
||||
|
||||
bool CheckInterfaceImplementation (EntityDeclaration entityDeclaration) |
||||
{ |
||||
var result = resolver.Resolve (entityDeclaration, cancellationToken) as MemberResolveResult; |
||||
if (result == null) |
||||
return false; |
||||
if (result.Member.ImplementedInterfaceMembers.Count == 0) { |
||||
Colorize (entityDeclaration.NameToken, syntaxErrorColor); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) |
||||
{ |
||||
var nameToken = methodDeclaration.NameToken; |
||||
VisitChildrenUntil(methodDeclaration, nameToken); |
||||
if (!methodDeclaration.PrivateImplementationType.IsNull) { |
||||
if (!CheckInterfaceImplementation (methodDeclaration)) { |
||||
VisitChildrenAfter(methodDeclaration, nameToken); |
||||
return; |
||||
} |
||||
} |
||||
Colorize(nameToken, methodDeclarationColor); |
||||
VisitChildrenAfter(methodDeclaration, nameToken); |
||||
} |
||||
|
||||
public override void VisitParameterDeclaration(ParameterDeclaration parameterDeclaration) |
||||
{ |
||||
var nameToken = parameterDeclaration.NameToken; |
||||
VisitChildrenUntil(parameterDeclaration, nameToken); |
||||
Colorize(nameToken, parameterDeclarationColor); |
||||
VisitChildrenAfter(parameterDeclaration, nameToken); |
||||
} |
||||
|
||||
public override void VisitEventDeclaration(EventDeclaration eventDeclaration) |
||||
{ |
||||
var nameToken = eventDeclaration.NameToken; |
||||
VisitChildrenUntil(eventDeclaration, nameToken); |
||||
Colorize(nameToken, eventDeclarationColor); |
||||
VisitChildrenAfter(eventDeclaration, nameToken); |
||||
} |
||||
|
||||
public override void VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration) |
||||
{ |
||||
var nameToken = eventDeclaration.NameToken; |
||||
VisitChildrenUntil(eventDeclaration, nameToken); |
||||
if (!eventDeclaration.PrivateImplementationType.IsNull) { |
||||
if (!CheckInterfaceImplementation (eventDeclaration)) { |
||||
VisitChildrenAfter(eventDeclaration, nameToken); |
||||
return; |
||||
} |
||||
} |
||||
Colorize(nameToken, eventDeclarationColor); |
||||
VisitChildrenAfter(eventDeclaration, nameToken); |
||||
} |
||||
|
||||
public override void VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration) |
||||
{ |
||||
var nameToken = propertyDeclaration.NameToken; |
||||
VisitChildrenUntil(propertyDeclaration, nameToken); |
||||
if (!propertyDeclaration.PrivateImplementationType.IsNull) { |
||||
if (!CheckInterfaceImplementation (propertyDeclaration)) { |
||||
VisitChildrenAfter(propertyDeclaration, nameToken); |
||||
return; |
||||
} |
||||
} |
||||
Colorize(nameToken, propertyDeclarationColor); |
||||
VisitChildrenAfter(propertyDeclaration, nameToken); |
||||
} |
||||
|
||||
public override void VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration) |
||||
{ |
||||
base.VisitIndexerDeclaration(indexerDeclaration); |
||||
if (!indexerDeclaration.PrivateImplementationType.IsNull) { |
||||
CheckInterfaceImplementation (indexerDeclaration); |
||||
} |
||||
} |
||||
|
||||
public override void VisitFieldDeclaration(FieldDeclaration fieldDeclaration) |
||||
{ |
||||
fieldDeclaration.ReturnType.AcceptVisitor (this); |
||||
foreach (var init in fieldDeclaration.Variables) { |
||||
Colorize (init.NameToken, fieldDeclarationColor); |
||||
init.Initializer.AcceptVisitor (this); |
||||
} |
||||
} |
||||
|
||||
public override void VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration) |
||||
{ |
||||
fixedFieldDeclaration.ReturnType.AcceptVisitor (this); |
||||
foreach (var init in fixedFieldDeclaration.Variables) { |
||||
Colorize (init.NameToken, fieldDeclarationColor); |
||||
init.CountExpression.AcceptVisitor (this); |
||||
} |
||||
} |
||||
|
||||
public override void VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration) |
||||
{ |
||||
HandleConstructorOrDestructor(constructorDeclaration); |
||||
} |
||||
|
||||
public override void VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration) |
||||
{ |
||||
HandleConstructorOrDestructor(destructorDeclaration); |
||||
} |
||||
|
||||
void HandleConstructorOrDestructor(AstNode constructorDeclaration) |
||||
{ |
||||
Identifier nameToken = constructorDeclaration.GetChildByRole(Roles.Identifier); |
||||
VisitChildrenUntil(constructorDeclaration, nameToken); |
||||
var currentTypeDef = resolver.GetResolverStateBefore(constructorDeclaration).CurrentTypeDefinition; |
||||
if (currentTypeDef != null && nameToken.Name == currentTypeDef.Name) { |
||||
TColor color; |
||||
if (TryGetTypeHighlighting (currentTypeDef.Kind, out color)) |
||||
Colorize(nameToken, color); |
||||
} |
||||
VisitChildrenAfter(constructorDeclaration, nameToken); |
||||
} |
||||
|
||||
bool TryGetMemberColor(IMember member, out TColor color) |
||||
{ |
||||
switch (member.SymbolKind) { |
||||
case SymbolKind.Field: |
||||
color = fieldAccessColor; |
||||
return true; |
||||
case SymbolKind.Property: |
||||
color = propertyAccessColor; |
||||
return true; |
||||
case SymbolKind.Event: |
||||
color = eventAccessColor; |
||||
return true; |
||||
case SymbolKind.Method: |
||||
color = methodCallColor; |
||||
return true; |
||||
case SymbolKind.Constructor: |
||||
case SymbolKind.Destructor: |
||||
return TryGetTypeHighlighting (member.DeclaringType.Kind, out color); |
||||
default: |
||||
color = default (TColor); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
TColor GetTypeHighlighting (ClassType classType) |
||||
{ |
||||
switch (classType) { |
||||
case ClassType.Class: |
||||
return referenceTypeColor; |
||||
case ClassType.Struct: |
||||
return valueTypeColor; |
||||
case ClassType.Interface: |
||||
return interfaceTypeColor; |
||||
case ClassType.Enum: |
||||
return enumerationTypeColor; |
||||
default: |
||||
throw new InvalidOperationException ("Unknown class type :" + classType); |
||||
} |
||||
} |
||||
|
||||
bool TryGetTypeHighlighting (TypeKind kind, out TColor color) |
||||
{ |
||||
switch (kind) { |
||||
case TypeKind.Class: |
||||
color = referenceTypeColor; |
||||
return true; |
||||
case TypeKind.Struct: |
||||
color = valueTypeColor; |
||||
return true; |
||||
case TypeKind.Interface: |
||||
color = interfaceTypeColor; |
||||
return true; |
||||
case TypeKind.Enum: |
||||
color = enumerationTypeColor; |
||||
return true; |
||||
case TypeKind.TypeParameter: |
||||
color = typeParameterTypeColor; |
||||
return true; |
||||
case TypeKind.Delegate: |
||||
color = delegateTypeColor; |
||||
return true; |
||||
case TypeKind.Unknown: |
||||
case TypeKind.Null: |
||||
color = syntaxErrorColor; |
||||
return true; |
||||
default: |
||||
color = default (TColor); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration) |
||||
{ |
||||
var nameToken = typeDeclaration.NameToken; |
||||
VisitChildrenUntil(typeDeclaration, nameToken); |
||||
Colorize(nameToken, GetTypeHighlighting (typeDeclaration.ClassType)); |
||||
VisitChildrenAfter(typeDeclaration, nameToken); |
||||
} |
||||
|
||||
public override void VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration) |
||||
{ |
||||
if (typeParameterDeclaration.Variance == VarianceModifier.Contravariant) |
||||
Colorize(typeParameterDeclaration.VarianceToken, parameterModifierColor); |
||||
|
||||
// bool isValueType = false;
|
||||
// if (typeParameterDeclaration.Parent != null) {
|
||||
// foreach (var constraint in typeParameterDeclaration.Parent.GetChildrenByRole(Roles.Constraint)) {
|
||||
// if (constraint.TypeParameter.Identifier == typeParameterDeclaration.Name) {
|
||||
// isValueType = constraint.BaseTypes.OfType<PrimitiveType>().Any(p => p.Keyword == "struct");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
var nameToken = typeParameterDeclaration.NameToken; |
||||
VisitChildrenUntil(typeParameterDeclaration, nameToken); |
||||
Colorize(nameToken, typeParameterTypeColor); /*isValueType ? valueTypeColor : referenceTypeColor*/ |
||||
VisitChildrenAfter(typeParameterDeclaration, nameToken); |
||||
} |
||||
|
||||
public override void VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration) |
||||
{ |
||||
var nameToken = delegateDeclaration.NameToken; |
||||
VisitChildrenUntil(delegateDeclaration, nameToken); |
||||
Colorize(nameToken, delegateTypeColor); |
||||
VisitChildrenAfter(delegateDeclaration, nameToken); |
||||
} |
||||
|
||||
public override void VisitVariableInitializer(VariableInitializer variableInitializer) |
||||
{ |
||||
var nameToken = variableInitializer.NameToken; |
||||
VisitChildrenUntil(variableInitializer, nameToken); |
||||
if (variableInitializer.Parent is FieldDeclaration) { |
||||
Colorize(nameToken, fieldDeclarationColor); |
||||
} else if (variableInitializer.Parent is EventDeclaration) { |
||||
Colorize(nameToken, eventDeclarationColor); |
||||
} else { |
||||
Colorize(nameToken, variableDeclarationColor); |
||||
} |
||||
VisitChildrenAfter(variableInitializer, nameToken); |
||||
} |
||||
|
||||
public override void VisitComment(Comment comment) |
||||
{ |
||||
if (comment.CommentType == CommentType.InactiveCode) { |
||||
Colorize(comment, inactiveCodeColor); |
||||
} |
||||
} |
||||
|
||||
public override void VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective) |
||||
{ |
||||
} |
||||
|
||||
public override void VisitAttribute(ICSharpCode.NRefactory.CSharp.Attribute attribute) |
||||
{ |
||||
ITypeDefinition attrDef = resolver.Resolve(attribute.Type, cancellationToken).Type.GetDefinition(); |
||||
if (attrDef != null && IsInactiveConditional(attrDef.Attributes)) { |
||||
Colorize(attribute, inactiveCodeColor); |
||||
} else { |
||||
VisitChildren(attribute); |
||||
} |
||||
} |
||||
|
||||
public override void VisitArrayInitializerExpression (ArrayInitializerExpression arrayInitializerExpression) |
||||
{ |
||||
foreach (var a in arrayInitializerExpression.Elements) { |
||||
var namedElement = a as NamedExpression; |
||||
if (namedElement != null) { |
||||
var result = resolver.Resolve (namedElement, cancellationToken); |
||||
if (result.IsError) |
||||
Colorize (namedElement.NameToken, syntaxErrorColor); |
||||
namedElement.Expression.AcceptVisitor (this); |
||||
} else { |
||||
a.AcceptVisitor (this); |
||||
} |
||||
} |
||||
} |
||||
|
||||
int blockDepth; |
||||
public override void VisitBlockStatement(BlockStatement blockStatement) |
||||
{ |
||||
blockDepth++; |
||||
base.VisitBlockStatement(blockStatement); |
||||
blockDepth--; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2013 Daniel Grunwald
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using System; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
/// <summary>
|
||||
/// Extension methods for the syntax tree.
|
||||
/// </summary>
|
||||
public static class SyntaxExtensions |
||||
{ |
||||
public static bool IsComparisonOperator(this OperatorType operatorType) |
||||
{ |
||||
switch (operatorType) { |
||||
case OperatorType.Equality: |
||||
case OperatorType.Inequality: |
||||
case OperatorType.GreaterThan: |
||||
case OperatorType.LessThan: |
||||
case OperatorType.GreaterThanOrEqual: |
||||
case OperatorType.LessThanOrEqual: |
||||
return true; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,216 @@
@@ -0,0 +1,216 @@
|
||||
//
|
||||
// CombineQueryExpressions.cs
|
||||
//
|
||||
// Modified by Luís Reis <luiscubal@gmail.com> (Copyright (C) 2013)
|
||||
//
|
||||
// Copyright header of the original version follows:
|
||||
//
|
||||
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
/// <summary>
|
||||
/// Combines query expressions and removes transparent identifiers.
|
||||
/// </summary>
|
||||
public class CombineQueryExpressions |
||||
{ |
||||
static readonly InvocationExpression castPattern = new InvocationExpression { |
||||
Target = new MemberReferenceExpression { |
||||
Target = new AnyNode("inExpr"), |
||||
MemberName = "Cast", |
||||
TypeArguments = { new AnyNode("targetType") } |
||||
}}; |
||||
|
||||
public string CombineQuery(AstNode node, AstNode rootQuery = null) |
||||
{ |
||||
if (rootQuery == null) { |
||||
rootQuery = node; |
||||
} |
||||
|
||||
QueryExpression query = node as QueryExpression; |
||||
if (query != null) { |
||||
string continuationIdentifier = null; |
||||
|
||||
foreach (var clause in query.Clauses) { |
||||
var continuation = clause as QueryContinuationClause; |
||||
if (continuation != null) { |
||||
CombineQuery(continuation.PrecedingQuery); |
||||
} |
||||
|
||||
var from = clause as QueryFromClause; |
||||
if (from != null) { |
||||
continuationIdentifier = CombineQuery(from.Expression, rootQuery); |
||||
} |
||||
} |
||||
|
||||
QueryFromClause fromClause = (QueryFromClause)query.Clauses.First(); |
||||
QueryExpression innerQuery = fromClause.Expression as QueryExpression; |
||||
if (innerQuery != null) { |
||||
continuationIdentifier = continuationIdentifier ?? ((QueryFromClause)innerQuery.Clauses.First()).Identifier; |
||||
|
||||
string transparentIdentifier; |
||||
if (TryRemoveTransparentIdentifier(query, fromClause, innerQuery, continuationIdentifier, out transparentIdentifier)) { |
||||
RemoveTransparentIdentifierReferences(rootQuery, transparentIdentifier); |
||||
} else if (fromClause.Type.IsNull) { |
||||
QueryContinuationClause continuation = new QueryContinuationClause(); |
||||
continuation.PrecedingQuery = innerQuery.Detach(); |
||||
continuation.Identifier = fromClause.Identifier; |
||||
fromClause.ReplaceWith(continuation); |
||||
} |
||||
|
||||
return transparentIdentifier; |
||||
} else { |
||||
Match m = castPattern.Match(fromClause.Expression); |
||||
if (m.Success) { |
||||
fromClause.Type = m.Get<AstType>("targetType").Single().Detach(); |
||||
fromClause.Expression = m.Get<Expression>("inExpr").Single().Detach(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause { |
||||
Expression = new AnonymousTypeCreateExpression { |
||||
Initializers = { |
||||
new AnyNode("nae1"), |
||||
new AnyNode("nae2") |
||||
} |
||||
} |
||||
}; |
||||
|
||||
bool TryRemoveTransparentIdentifier(QueryExpression query, QueryFromClause fromClause, QueryExpression innerQuery, string continuationIdentifier, out string transparentIdentifier) |
||||
{ |
||||
transparentIdentifier = fromClause.Identifier; |
||||
|
||||
Match match = selectTransparentIdentifierPattern.Match(innerQuery.Clauses.Last()); |
||||
if (!match.Success) |
||||
return false; |
||||
QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last(); |
||||
Expression nae1 = match.Get<Expression>("nae1").SingleOrDefault(); |
||||
string nae1Name = ExtractExpressionName(ref nae1); |
||||
if (nae1Name == null) |
||||
return false; |
||||
|
||||
Expression nae2 = match.Get<Expression>("nae2").SingleOrDefault(); |
||||
string nae2Name = ExtractExpressionName(ref nae2); |
||||
if (nae1Name == null) |
||||
return false; |
||||
|
||||
bool introduceLetClause = true; |
||||
var nae1Identifier = nae1 as IdentifierExpression; |
||||
var nae2Identifier = nae2 as IdentifierExpression; |
||||
if (nae1Identifier != null && nae2Identifier != null && nae1Identifier.Identifier == nae1Name && nae2Identifier.Identifier == nae2Name) { |
||||
introduceLetClause = false; |
||||
} |
||||
|
||||
if (nae1Name != continuationIdentifier) { |
||||
if (nae2Name == continuationIdentifier) { |
||||
//Members are in reversed order
|
||||
string tempName = nae1Name; |
||||
Expression tempNae = nae1; |
||||
|
||||
nae1Name = nae2Name; |
||||
nae1 = nae2; |
||||
nae2Name = tempName; |
||||
nae2 = tempNae; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
if (introduceLetClause && innerQuery.Clauses.OfType<QueryFromClause>().Any(from => from.Identifier == nae2Name)) { |
||||
return false; |
||||
} |
||||
if (introduceLetClause && innerQuery.Clauses.OfType<QueryJoinClause>().Any(join => join.JoinIdentifier == nae2Name)) { |
||||
return false; |
||||
} |
||||
|
||||
// from * in (from x in ... select new { x = x, y = expr }) ...
|
||||
// =>
|
||||
// from x in ... let y = expr ...
|
||||
fromClause.Remove(); |
||||
selectClause.Remove(); |
||||
// Move clauses from innerQuery to query
|
||||
QueryClause insertionPos = null; |
||||
foreach (var clause in innerQuery.Clauses) { |
||||
query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); |
||||
} |
||||
if (introduceLetClause) { |
||||
query.Clauses.InsertAfter(insertionPos, new QueryLetClause { Identifier = nae2Name, Expression = nae2.Detach() }); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Removes all occurrences of transparent identifiers
|
||||
/// </summary>
|
||||
void RemoveTransparentIdentifierReferences(AstNode node, string transparentIdentifier) |
||||
{ |
||||
foreach (AstNode child in node.Children) { |
||||
RemoveTransparentIdentifierReferences(child, transparentIdentifier); |
||||
} |
||||
MemberReferenceExpression mre = node as MemberReferenceExpression; |
||||
if (mre != null) { |
||||
IdentifierExpression ident = mre.Target as IdentifierExpression; |
||||
if (ident != null && ident.Identifier == transparentIdentifier) { |
||||
IdentifierExpression newIdent = new IdentifierExpression(mre.MemberName); |
||||
mre.TypeArguments.MoveTo(newIdent.TypeArguments); |
||||
newIdent.CopyAnnotationsFrom(mre); |
||||
newIdent.RemoveAnnotations<PropertyDeclaration>(); // remove the reference to the property of the anonymous type
|
||||
mre.ReplaceWith(newIdent); |
||||
return; |
||||
} else if (mre.MemberName == transparentIdentifier) { |
||||
var newVar = mre.Target.Detach(); |
||||
newVar.CopyAnnotationsFrom(mre); |
||||
newVar.RemoveAnnotations<PropertyDeclaration>(); // remove the reference to the property of the anonymous type
|
||||
mre.ReplaceWith(newVar); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
string ExtractExpressionName(ref Expression expr) |
||||
{ |
||||
NamedExpression namedExpr = expr as NamedExpression; |
||||
if (namedExpr != null) { |
||||
expr = namedExpr.Expression; |
||||
return namedExpr.Name; |
||||
} |
||||
|
||||
IdentifierExpression identifier = expr as IdentifierExpression; |
||||
if (identifier != null) { |
||||
return identifier.Identifier; |
||||
} |
||||
|
||||
MemberReferenceExpression memberRef = expr as MemberReferenceExpression; |
||||
if (memberRef != null) { |
||||
return memberRef.MemberName; |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,159 @@
@@ -0,0 +1,159 @@
|
||||
//
|
||||
// CSharpFormatter.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.Editor; |
||||
using System.Threading; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp.Refactoring; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
public enum FormattingMode { |
||||
OnTheFly, |
||||
Intrusive |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The C# Formatter generates a set of text replace actions to format a region in a C# document.
|
||||
/// </summary>
|
||||
public class CSharpFormatter |
||||
{ |
||||
readonly CSharpFormattingOptions policy; |
||||
readonly TextEditorOptions options; |
||||
|
||||
/// <summary>
|
||||
/// Gets the formatting policy the formatter uses.
|
||||
/// </summary>
|
||||
public CSharpFormattingOptions Policy { |
||||
get { |
||||
return policy; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the text editor options the formatter uses.
|
||||
/// Note: If none was specified TextEditorOptions.Default gets used.
|
||||
/// </summary>
|
||||
public TextEditorOptions TextEditorOptions { |
||||
get { |
||||
return options; |
||||
} |
||||
} |
||||
|
||||
List<DomRegion> formattingRegions = new List<DomRegion> (); |
||||
internal TextLocation lastFormattingLocation = new TextLocation(int.MaxValue, int.MaxValue); |
||||
|
||||
/// <summary>
|
||||
/// Gets the formatting regions. NOTE: Will get changed to IReadOnlyList.
|
||||
/// </summary>
|
||||
public IList<DomRegion> FormattingRegions { |
||||
get { |
||||
return formattingRegions; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the formatting mode. For on the fly formatting a lightweight formatting mode
|
||||
/// gives better results.
|
||||
/// </summary>
|
||||
public FormattingMode FormattingMode { |
||||
get; |
||||
set; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ICSharpCode.NRefactory.CSharp.CSharpFormatter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="policy">The formatting policy to use.</param>
|
||||
/// <param name="options">The text editor options (optional). Default is: TextEditorOptions.Default</param>
|
||||
public CSharpFormatter(CSharpFormattingOptions policy, TextEditorOptions options = null) |
||||
{ |
||||
if (policy == null) |
||||
throw new ArgumentNullException("policy"); |
||||
this.policy = policy; |
||||
this.options = options ?? TextEditorOptions.Default; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Format the specified document and gives back the formatted text as result.
|
||||
/// </summary>
|
||||
public string Format(IDocument document) |
||||
{ |
||||
return InternalFormat (new StringBuilderDocument (document.Text)); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Format the specified text and gives back the formatted text as result.
|
||||
/// </summary>
|
||||
public string Format(string text) |
||||
{ |
||||
return InternalFormat (new StringBuilderDocument (text)); |
||||
} |
||||
|
||||
string InternalFormat(IDocument document) |
||||
{ |
||||
var syntaxTree = SyntaxTree.Parse (document, document.FileName); |
||||
var changes = AnalyzeFormatting(document, syntaxTree); |
||||
changes.ApplyChanges(); |
||||
return document.Text; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Analyzes the formatting of a given document and syntax tree.
|
||||
/// </summary>
|
||||
/// <param name="document">Document.</param>
|
||||
/// <param name="syntaxTree">Syntax tree.</param>
|
||||
/// <param name="token">The cancellation token.</param>
|
||||
public FormattingChanges AnalyzeFormatting(IDocument document, SyntaxTree syntaxTree, CancellationToken token = default (CancellationToken)) |
||||
{ |
||||
if (document == null) |
||||
throw new ArgumentNullException("document"); |
||||
if (syntaxTree == null) |
||||
throw new ArgumentNullException("syntaxTree"); |
||||
var result = new FormattingChanges(document); |
||||
var visitor = new FormattingVisitor(this, document, result, token); |
||||
syntaxTree.AcceptVisitor(visitor); |
||||
return result; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Adds a region in the document that should be formatted.
|
||||
/// </summary>
|
||||
public void AddFormattingRegion (DomRegion region) |
||||
{ |
||||
formattingRegions.Add(region); |
||||
if (formattingRegions.Count == 1) { |
||||
lastFormattingLocation = region.End; |
||||
} else { |
||||
lastFormattingLocation = lastFormattingLocation < region.End ? region.End : lastFormattingLocation; |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
@ -0,0 +1,514 @@
@@ -0,0 +1,514 @@
|
||||
//
|
||||
// ConstructFixer.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.Editor; |
||||
using System.Text; |
||||
using System.Reflection; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
abstract class ConstructCompleter |
||||
{ |
||||
public abstract bool TryFix (ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset); |
||||
|
||||
protected AstNode GetLastNonErrorChild (AstNode node) |
||||
{ |
||||
var lastNode = node.LastChild; |
||||
|
||||
while (lastNode is ErrorNode) { |
||||
lastNode = lastNode.GetPrevNode(FormattingVisitor.NoWhitespacePredicate); |
||||
} |
||||
return lastNode; |
||||
} |
||||
} |
||||
|
||||
class TypeDeclarationCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var typeDeclaration = syntaxTree.GetNodeAt<TypeDeclaration>(location); |
||||
if (typeDeclaration != null) { |
||||
if (typeDeclaration.LBraceToken.IsNull && typeDeclaration.RBraceToken.IsNull) { |
||||
if (typeDeclaration.Members.Any()) |
||||
return false; |
||||
var lastNode = GetLastNonErrorChild (typeDeclaration); |
||||
if (lastNode == null) |
||||
return false; |
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (typeDeclaration, fixer.Options.ClassBraceStyle, false, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class DelegateDeclarationCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var typeDeclaration = syntaxTree.GetNodeAt<DelegateDeclaration>(location); |
||||
if (typeDeclaration != null) { |
||||
if (typeDeclaration.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (typeDeclaration); |
||||
if (lastNode == null) |
||||
return false; |
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, ");\n"); |
||||
newOffset += ");\n".Length; |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class MethodDeclarationCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var methodDeclaration = syntaxTree.GetNodeAt<MethodDeclaration>(location); |
||||
if (methodDeclaration != null) { |
||||
if (!methodDeclaration.LParToken.IsNull && methodDeclaration.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (methodDeclaration); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, ")\n\t{\t\t\n\t}"); |
||||
newOffset += ")\n\t{\t\t".Length; |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class IfStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var ifStatement = syntaxTree.GetNodeAt<IfElseStatement>(location); |
||||
if (ifStatement != null) { |
||||
if (!ifStatement.LParToken.IsNull && ifStatement.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (ifStatement); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (ifStatement, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class ForeachStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var ifStatement = syntaxTree.GetNodeAt<ForeachStatement>(location); |
||||
if (ifStatement != null) { |
||||
if (!ifStatement.LParToken.IsNull && ifStatement.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (ifStatement); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (ifStatement, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class WhileStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var ifStatement = syntaxTree.GetNodeAt<WhileStatement>(location); |
||||
if (ifStatement != null) { |
||||
if (!ifStatement.LParToken.IsNull && ifStatement.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (ifStatement); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (ifStatement, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class DoWhileStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<DoWhileStatement>(location); |
||||
if (stmt != null) { |
||||
if (!stmt.LParToken.IsNull && stmt.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (stmt); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, ");"); |
||||
newOffset = insertionOffset + 2; |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class FixedStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<FixedStatement>(location); |
||||
if (stmt != null) { |
||||
if (!stmt.LParToken.IsNull && stmt.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (stmt); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class SwitchStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var switchStatement = syntaxTree.GetNodeAt<SwitchStatement>(location); |
||||
if (switchStatement != null) { |
||||
if (!switchStatement.LParToken.IsNull && switchStatement.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (switchStatement); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (switchStatement, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class InvocationCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var invocationExpression = syntaxTree.GetNodeAt<InvocationExpression>(location); |
||||
|
||||
if (invocationExpression != null) { |
||||
if (!invocationExpression.LParToken.IsNull && invocationExpression.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (invocationExpression); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
|
||||
newOffset = insertionOffset; |
||||
|
||||
|
||||
var text = ")"; |
||||
newOffset++; |
||||
var expressionStatement = invocationExpression.Parent as ExpressionStatement; |
||||
if (expressionStatement != null) { |
||||
if (expressionStatement.SemicolonToken.IsNull) |
||||
text = ");"; |
||||
newOffset ++; |
||||
} |
||||
document.Insert(insertionOffset, text); |
||||
|
||||
|
||||
return true; |
||||
} |
||||
|
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class BreakStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<BreakStatement>(location); |
||||
|
||||
if (stmt != null && stmt.SemicolonToken.IsNull) { |
||||
// TODO !!!!
|
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class CheckedStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<CheckedExpression>(location); |
||||
|
||||
if (stmt != null && stmt.Parent is ExpressionStatement) { |
||||
var insertionOffset = document.GetOffset(stmt.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, false, ref newOffset)); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class UncheckedStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<UncheckedExpression>(location); |
||||
|
||||
if (stmt != null && stmt.Parent is ExpressionStatement) { |
||||
var insertionOffset = document.GetOffset(stmt.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, false, ref newOffset)); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class ExpressionStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var expressionStatement = syntaxTree.GetNodeAt<ExpressionStatement>(location); |
||||
|
||||
if (expressionStatement != null) { |
||||
int offset = document.GetOffset(expressionStatement.Expression.EndLocation); |
||||
if (expressionStatement.SemicolonToken.IsNull) { |
||||
document.Insert(offset, ";"); |
||||
newOffset = offset + 1; |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class LockStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<LockStatement>(location); |
||||
if (stmt != null) { |
||||
if (!stmt.LParToken.IsNull && stmt.RParToken.IsNull) { |
||||
var lastNode = GetLastNonErrorChild (stmt); |
||||
if (lastNode == null) |
||||
return false; |
||||
|
||||
var insertionOffset = document.GetOffset(lastNode.EndLocation); |
||||
document.Insert(insertionOffset, fixer.GenerateBody (stmt, fixer.Options.StatementBraceStyle, true, ref newOffset)); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class ReturnStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<ReturnStatement>(location); |
||||
|
||||
if (stmt != null && stmt.SemicolonToken.IsNull) { |
||||
var insertionOffset = document.GetOffset(stmt.EndLocation); |
||||
document.Insert(insertionOffset, ";"); |
||||
newOffset = insertionOffset + 1; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class YieldReturnStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<YieldReturnStatement>(location); |
||||
|
||||
if (stmt != null && stmt.SemicolonToken.IsNull) { |
||||
var insertionOffset = document.GetOffset(stmt.EndLocation); |
||||
document.Insert(insertionOffset, ";"); |
||||
newOffset = insertionOffset + 1; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
class ThrowStatementCompleter : ConstructCompleter |
||||
{ |
||||
public override bool TryFix(ConstructFixer fixer, SyntaxTree syntaxTree, IDocument document, TextLocation location, ref int newOffset) |
||||
{ |
||||
var stmt = syntaxTree.GetNodeAt<ThrowStatement>(location); |
||||
|
||||
if (stmt != null && stmt.SemicolonToken.IsNull) { |
||||
var insertionOffset = document.GetOffset(stmt.EndLocation); |
||||
document.Insert(insertionOffset, ";"); |
||||
newOffset = insertionOffset + 1; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
|
||||
public class ConstructFixer |
||||
{ |
||||
static readonly ConstructCompleter[] completer = { |
||||
new TypeDeclarationCompleter(), |
||||
new DelegateDeclarationCompleter (), |
||||
new MethodDeclarationCompleter (), |
||||
new IfStatementCompleter (), |
||||
new ForeachStatementCompleter (), |
||||
new WhileStatementCompleter (), |
||||
new LockStatementCompleter (), |
||||
new FixedStatementCompleter (), |
||||
new DoWhileStatementCompleter (), |
||||
new SwitchStatementCompleter (), |
||||
new BreakStatementCompleter (), |
||||
new ThrowStatementCompleter (), |
||||
new ReturnStatementCompleter (), |
||||
new YieldReturnStatementCompleter (), |
||||
new CheckedStatementCompleter (), |
||||
new UncheckedStatementCompleter (), |
||||
|
||||
new InvocationCompleter (), |
||||
new ExpressionStatementCompleter () |
||||
}; |
||||
|
||||
readonly CSharpFormattingOptions options; |
||||
readonly TextEditorOptions textEditorOptions; |
||||
|
||||
public CSharpFormattingOptions Options { |
||||
get { |
||||
return options; |
||||
} |
||||
} |
||||
|
||||
public ConstructFixer(CSharpFormattingOptions options, TextEditorOptions textEditorOptions) |
||||
{ |
||||
this.options = options; |
||||
this.textEditorOptions = textEditorOptions; |
||||
} |
||||
|
||||
|
||||
string GetIndent(AstNode node) |
||||
{ |
||||
if (node == null || node is SyntaxTree) |
||||
return ""; |
||||
if (node is BlockStatement || node is TypeDeclaration || node is NamespaceDeclaration) |
||||
return "\t" + GetIndent(node.Parent); |
||||
return GetIndent(node.Parent); |
||||
} |
||||
|
||||
internal string GenerateBody(AstNode node, BraceStyle braceStyle, bool addClosingBracket, ref int newOffset) |
||||
{ |
||||
StringBuilder result = new StringBuilder(); |
||||
if (addClosingBracket) |
||||
result.Append(")"); |
||||
var nodeIndent = GetIndent(node.Parent); |
||||
switch (braceStyle) { |
||||
case BraceStyle.DoNotChange: |
||||
case BraceStyle.BannerStyle: |
||||
case BraceStyle.EndOfLine: |
||||
result.Append(" "); |
||||
result.Append("{"); |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
break; |
||||
case BraceStyle.EndOfLineWithoutSpace: |
||||
result.Append("{"); |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
break; |
||||
case BraceStyle.NextLine: |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent); |
||||
result.Append("{"); |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
break; |
||||
case BraceStyle.NextLineShifted: |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
result.Append("{"); |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
break; |
||||
case BraceStyle.NextLineShifted2: |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t"); |
||||
result.Append("{"); |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent + "\t" + "\t"); |
||||
break; |
||||
} |
||||
|
||||
newOffset += result.Length; |
||||
result.Append(textEditorOptions.EolMarker); |
||||
result.Append(nodeIndent); |
||||
result.Append("}"); |
||||
|
||||
return result.ToString(); |
||||
} |
||||
|
||||
public bool TryFix (IDocument document, int offset, out int newOffset) |
||||
{ |
||||
newOffset = offset; |
||||
|
||||
var syntaxTree = SyntaxTree.Parse(document, "a.cs"); |
||||
var location = document.GetLocation(offset - 1); |
||||
foreach (var c in completer) { |
||||
if (c.TryFix(this, syntaxTree, document, location, ref newOffset)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,169 @@
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// CSharpFormatter.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.Editor; |
||||
using System.Threading; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp.Refactoring; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
/// <summary>
|
||||
/// The formatting changes are used to format a specific region inside a document and apply a minimal formatting
|
||||
/// changeset to a given document. This is useful for a text editor environment.
|
||||
/// </summary>
|
||||
public class FormattingChanges |
||||
{ |
||||
readonly IDocument document; |
||||
readonly internal List<TextReplaceAction> changes = new List<TextReplaceAction> (); |
||||
|
||||
internal FormattingChanges (IDocument document) |
||||
{ |
||||
if (document == null) |
||||
throw new ArgumentNullException("document"); |
||||
this.document = document; |
||||
} |
||||
|
||||
public int Count { |
||||
get { |
||||
return changes.Count; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Applies the changes to the input document.
|
||||
/// </summary>
|
||||
public void ApplyChanges() |
||||
{ |
||||
ApplyChanges(0, document.TextLength, document.Replace, (o, l, v) => document.GetText(o, l) == v); |
||||
} |
||||
|
||||
public void ApplyChanges(int startOffset, int length) |
||||
{ |
||||
ApplyChanges(startOffset, length, document.Replace, (o, l, v) => document.GetText(o, l) == v); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Applies the changes to the given Script instance.
|
||||
/// </summary>
|
||||
public void ApplyChanges(Script script) |
||||
{ |
||||
ApplyChanges(0, document.TextLength, script.Replace); |
||||
} |
||||
|
||||
public void ApplyChanges(int startOffset, int length, Script script) |
||||
{ |
||||
ApplyChanges(startOffset, length, script.Replace); |
||||
} |
||||
|
||||
public void ApplyChanges(int startOffset, int length, Action<int, int, string> documentReplace, Func<int, int, string, bool> filter = null) |
||||
{ |
||||
int endOffset = startOffset + length; |
||||
// Console.WriteLine ("apply:"+ startOffset + "->" + endOffset);
|
||||
// Console.WriteLine (document.Text.Substring (0, startOffset) + new string ('x',length) + document.Text.Substring (startOffset+ length));
|
||||
|
||||
TextReplaceAction previousChange = null; |
||||
int delta = 0; |
||||
var depChanges = new List<TextReplaceAction> (); |
||||
foreach (var change in changes.OrderBy(c => c.Offset)) { |
||||
if (previousChange != null) { |
||||
if (change.Equals(previousChange)) { |
||||
// ignore duplicate changes
|
||||
continue; |
||||
} |
||||
if (change.Offset < previousChange.Offset + previousChange.RemovalLength) { |
||||
throw new InvalidOperationException ("Detected overlapping changes " + change + "/" + previousChange); |
||||
} |
||||
} |
||||
previousChange = change; |
||||
bool skipChange = change.Offset + change.RemovalLength < startOffset || change.Offset > endOffset; |
||||
skipChange |= filter != null && filter(change.Offset + delta, change.RemovalLength, change.NewText); |
||||
skipChange &= !depChanges.Contains(change); |
||||
if (!skipChange) { |
||||
documentReplace(change.Offset + delta, change.RemovalLength, change.NewText); |
||||
delta += change.NewText.Length - change.RemovalLength; |
||||
if (change.DependsOn != null) { |
||||
depChanges.Add(change.DependsOn); |
||||
} |
||||
} |
||||
} |
||||
changes.Clear(); |
||||
} |
||||
|
||||
internal TextReplaceAction AddChange(int offset, int removedChars, string insertedText) |
||||
{ |
||||
if (offset < 0) |
||||
throw new ArgumentOutOfRangeException("offset", "Should be >= 0"); |
||||
if (offset >= document.TextLength) |
||||
throw new ArgumentOutOfRangeException("offset", "Should be < document.TextLength"); |
||||
if (removedChars < 0) |
||||
throw new ArgumentOutOfRangeException("removedChars", "Should be >= 0"); |
||||
if (removedChars > offset + document.TextLength) |
||||
throw new ArgumentOutOfRangeException("removedChars", "Tried to remove beyond end of text"); |
||||
if (removedChars == 0 && string.IsNullOrEmpty (insertedText)) |
||||
return null; |
||||
var action = new TextReplaceAction (offset, removedChars, insertedText); |
||||
changes.Add(action); |
||||
return action; |
||||
} |
||||
|
||||
internal sealed class TextReplaceAction |
||||
{ |
||||
internal readonly int Offset; |
||||
internal readonly int RemovalLength; |
||||
internal readonly string NewText; |
||||
internal TextReplaceAction DependsOn; |
||||
|
||||
public TextReplaceAction (int offset, int removalLength, string newText) |
||||
{ |
||||
this.Offset = offset; |
||||
this.RemovalLength = removalLength; |
||||
this.NewText = newText ?? string.Empty; |
||||
} |
||||
|
||||
public override bool Equals(object obj) |
||||
{ |
||||
TextReplaceAction other = obj as TextReplaceAction; |
||||
if (other == null) { |
||||
return false; |
||||
} |
||||
return this.Offset == other.Offset && this.RemovalLength == other.RemovalLength && this.NewText == other.NewText; |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return string.Format("[TextReplaceAction: Offset={0}, RemovalLength={1}, NewText={2}]", Offset, RemovalLength, NewText); |
||||
} |
||||
} |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue