Skip to content
Browse files

Add IParsedFile to type system.

  • Loading branch information...
1 parent be5139a commit 94b4130aa9ee483453588c2a62272ded33823734 @dgrunwald dgrunwald committed Jun 10, 2011
View
2 ICSharpCode.NRefactory.Demo/CSDemo.cs
@@ -180,7 +180,7 @@ void ResolveButtonClick(object sender, EventArgs e)
SimpleProjectContent project = new SimpleProjectContent();
TypeSystemConvertVisitor convertVisitor = new TypeSystemConvertVisitor(project, "dummy.cs");
compilationUnit.AcceptVisitor(convertVisitor, null);
- project.UpdateProjectContent(null, convertVisitor.ParsedFile.TopLevelTypeDefinitions, null, null);
+ project.UpdateProjectContent(null, convertVisitor.ParsedFile);
List<ITypeResolveContext> projects = new List<ITypeResolveContext>();
projects.Add(project);
View
5 ICSharpCode.NRefactory/CSharp/Analysis/MinimalResolveContext.cs
@@ -112,5 +112,10 @@ void IDisposable.Dispose()
{
// exit from Synchronize() block
}
+
+ IParsedFile IProjectContent.GetFile(string fileName)
+ {
+ return null;
+ }
}
}
View
40 ICSharpCode.NRefactory/CSharp/Parser/ParsedFile.cs
@@ -12,7 +12,7 @@ namespace ICSharpCode.NRefactory.CSharp
/// <summary>
/// Represents a file that was parsed and converted for the type system.
/// </summary>
- public sealed class ParsedFile : AbstractFreezable
+ public sealed class ParsedFile : AbstractFreezable, IParsedFile
{
readonly string fileName;
readonly UsingScope rootUsingScope;
@@ -51,6 +51,10 @@ public ParsedFile(string fileName, UsingScope rootUsingScope)
get { return usingScopes; }
}
+ public IProjectContent ProjectContent {
+ get { return rootUsingScope.ProjectContent; }
+ }
+
public IList<ITypeDefinition> TopLevelTypeDefinitions {
get { return topLevelTypeDefinitions; }
}
@@ -70,9 +74,37 @@ public UsingScope GetUsingScope(AstLocation location)
public ITypeDefinition GetTopLevelTypeDefinition(AstLocation location)
{
- foreach (ITypeDefinition typeDef in topLevelTypeDefinitions) {
- if (typeDef.Region.IsInside(location.Line, location.Column))
- return typeDef;
+ return FindEntity(topLevelTypeDefinitions, location);
+ }
+
+ public ITypeDefinition GetTypeDefinition(AstLocation location)
+ {
+ ITypeDefinition parent = null;
+ ITypeDefinition type = GetTopLevelTypeDefinition(location);
+ while (type != null) {
+ parent = type;
+ type = FindEntity(parent.InnerClasses, location);
+ }
+ return parent;
+ }
+
+ public IMember GetMember(AstLocation location)
+ {
+ ITypeDefinition type = GetTypeDefinition(location);
+ if (type == null)
+ return null;
+ return FindEntity(type.Methods, location)
+ ?? FindEntity(type.Fields, location)
+ ?? FindEntity(type.Properties, location)
+ ?? (IMember)FindEntity(type.Events, location);
+ }
+
+ static T FindEntity<T>(IList<T> list, AstLocation location) where T : class, IEntity
+ {
+ // This could be improved using a binary search
+ foreach (T entity in list) {
+ if (entity.Region.IsInside(location.Line, location.Column))
+ return entity;
}
return null;
}
View
49 ICSharpCode.NRefactory/CSharp/Refactoring/TypeSystemAstBuilder.cs
@@ -116,8 +116,6 @@ AstType ConvertTypeDefinition(ITypeDefinition typeDef, IList<IType> typeArgument
if (typeDef.DeclaringTypeDefinition != null) {
// Handle nested types
result.Target = ConvertTypeDefinition(typeDef.DeclaringTypeDefinition, typeArguments);
- result.MemberName = typeDef.Name;
- AddTypeArguments(result, typeArguments, OuterTypeParameterCount(typeDef), typeDef.TypeParameterCount);
} else {
// Handle top-level types
if (string.IsNullOrEmpty(typeDef.Namespace)) {
@@ -126,9 +124,9 @@ AstType ConvertTypeDefinition(ITypeDefinition typeDef, IList<IType> typeArgument
} else {
result.Target = ConvertNamespace(typeDef.Namespace);
}
- result.MemberName = typeDef.Name;
- AddTypeArguments(result, typeArguments, 0, typeDef.TypeParameterCount);
}
+ result.MemberName = typeDef.Name;
+ AddTypeArguments(result, typeArguments, OuterTypeParameterCount(typeDef), typeDef.TypeParameterCount);
return result;
}
@@ -173,24 +171,37 @@ void AddTypeArguments(AstType result, IList<IType> typeArguments, int startIndex
AstType ConvertNamespace(string ns)
{
- string[] parts = ns.Split('.');
- AstType result;
- if (IsValidNamespace(parts[0])) {
- result = new SimpleType(parts[0]);
- } else {
- result = new MemberType {
- Target = new SimpleType("global"),
- IsDoubleColon = true,
- MemberName = parts[0]
- };
+ if (resolver != null) {
+ // Look if there's an alias to the target namespace
+ for (UsingScope usingScope = resolver.UsingScope; usingScope != null; usingScope = usingScope.Parent) {
+ foreach (var pair in usingScope.UsingAliases) {
+ // maybe add some caching? we're resolving all aliases N times when converting a namespace name with N parts
+ NamespaceResolveResult nrr = pair.Value.ResolveNamespace(resolver.Context);
+ if (nrr != null && nrr.NamespaceName == ns)
+ return new SimpleType(pair.Key);
+ }
+ }
}
- for (int i = 1; i < parts.Length; i++) {
- result = new MemberType {
- Target = result,
- MemberName = parts[i]
+
+ int pos = ns.LastIndexOf('.');
+ if (pos < 0) {
+ if (IsValidNamespace(ns)) {
+ return new SimpleType(ns);
+ } else {
+ return new MemberType {
+ Target = new SimpleType("global"),
+ IsDoubleColon = true,
+ MemberName = ns
+ };
+ }
+ } else {
+ string parentNamespace = ns.Substring(0, pos);
+ string localNamespace = ns.Substring(pos + 1);
+ return new MemberType {
+ Target = ConvertNamespace(parentNamespace),
+ MemberName = localNamespace
};
}
- return result;
}
bool IsValidNamespace(string firstNamespacePart)
View
2 ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
@@ -255,6 +255,7 @@
<Compile Include="TypeSystem\IntersectionType.cs" />
<Compile Include="TypeSystem\IParameter.cs" />
<Compile Include="TypeSystem\IParameterizedMember.cs" />
+ <Compile Include="TypeSystem\IParsedFile.cs" />
<Compile Include="TypeSystem\IProjectContent.cs" />
<Compile Include="TypeSystem\IProperty.cs" />
<Compile Include="TypeSystem\ISupportsInterning.cs" />
@@ -330,6 +331,7 @@
<Compile Include="Utils\EmptyList.cs" />
<Compile Include="Utils\ExtensionMethods.cs" />
<Compile Include="Utils\GraphVizGraph.cs" />
+ <Compile Include="Utils\Platform.cs" />
<Compile Include="Utils\TreeTraversal.cs" />
<Compile Include="CSharp\Ast\ComposedType.cs" />
<Compile Include="CSharp\Ast\Expressions\DirectionExpression.cs" />
View
5 ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
@@ -151,6 +151,11 @@ public void Dispose()
// Disposing the synchronization context has no effect
}
+ public IParsedFile GetFile(string fileName)
+ {
+ return null;
+ }
+
string IDocumentationProvider.GetDocumentation(IEntity entity)
{
if (documentationProvider != null)
View
53 ICSharpCode.NRefactory/TypeSystem/IParsedFile.cs
@@ -0,0 +1,53 @@
+// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT license (for details please see \doc\license.txt)
+
+using System;
+using System.Collections.Generic;
+using ICSharpCode.NRefactory.CSharp;
+
+namespace ICSharpCode.NRefactory.TypeSystem
+{
+ /// <summary>
+ /// Represents a single file that was parsed.
+ /// </summary>
+ public interface IParsedFile : IFreezable
+ {
+ /// <summary>
+ /// Gets the parent project content.
+ /// </summary>
+ IProjectContent ProjectContent { get; }
+
+ /// <summary>
+ /// Returns the full path of the file.
+ /// </summary>
+ string FileName { get; }
+
+ /// <summary>
+ /// Gets all top-level type definitions.
+ /// </summary>
+ IList<ITypeDefinition> TopLevelTypeDefinitions { get; }
+
+ /// <summary>
+ /// Gets all assembly attributes that are defined in this file.
+ /// </summary>
+ IList<IAttribute> AssemblyAttributes { get; }
+
+ /// <summary>
+ /// Gets the top-level type defined at the specified location.
+ /// Returns null if no type is defined at that location.
+ /// </summary>
+ ITypeDefinition GetTopLevelTypeDefinition(AstLocation location);
+
+ /// <summary>
+ /// Gets the type (potentially a nested type) defined at the specified location.
+ /// Returns null if no type is defined at that location.
+ /// </summary>
+ ITypeDefinition GetTypeDefinition(AstLocation location);
+
+ /// <summary>
+ /// Gets the member defined at the specified location.
+ /// Returns null if no member is defined at that location.
+ /// </summary>
+ IMember GetMember(AstLocation location);
+ }
+}
View
14 ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs
@@ -15,7 +15,15 @@ namespace ICSharpCode.NRefactory.TypeSystem
#endif
public interface IProjectContent : ITypeResolveContext
{
+ /// <summary>
+ /// Gets the list of all assembly attributes in the project.
+ /// </summary>
IList<IAttribute> AssemblyAttributes { get; }
+
+ /// <summary>
+ /// Gets a parsed file by its file name.
+ /// </summary>
+ IParsedFile GetFile(string fileName);
}
#if WITH_CONTRACTS
@@ -28,6 +36,12 @@ abstract class IProjectContentContract : ITypeResolveContextContract, IProjectCo
return null;
}
}
+
+ IParsedFile IProjectContent.GetFile(string fileName)
+ {
+ Contract.Requires(fileName != null);
+ return;
+ }
}
#endif
}
View
44 ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs
@@ -27,6 +27,7 @@ public sealed class SimpleProjectContent : IProjectContent
readonly TypeStorage types = new TypeStorage();
readonly ReaderWriterLockSlim readerWriterLock = new ReaderWriterLockSlim();
+ readonly Dictionary<string, IParsedFile> fileDict = new Dictionary<string, IParsedFile>(Platform.FileNameComparer);
#region AssemblyAttributes
readonly List<IAttribute> assemblyAttributes = new List<IAttribute>(); // mutable assembly attribute storage
@@ -35,13 +36,14 @@ public sealed class SimpleProjectContent : IProjectContent
/// <inheritdoc/>
public IList<IAttribute> AssemblyAttributes {
- get { return readOnlyAssemblyAttributes; }
+ get { return readOnlyAssemblyAttributes; }
}
void AddRemoveAssemblyAttributes(ICollection<IAttribute> addedAttributes, ICollection<IAttribute> removedAttributes)
{
// API uses ICollection instead of IEnumerable to discourage users from evaluating
// the list inside the lock (this method is called inside the write lock)
+ // [[not an issue anymore; the user now passes IParsedFile]]
bool hasChanges = false;
if (removedAttributes != null && removedAttributes.Count > 0) {
if (assemblyAttributes.RemoveAll(removedAttributes.Contains) > 0)
@@ -80,31 +82,35 @@ void RemoveType(ITypeDefinition typeDefinition)
#region UpdateProjectContent
/// <summary>
- /// Removes oldTypes from the project, adds newTypes.
- /// Removes oldAssemblyAttributes, adds newAssemblyAttributes.
+ /// Removes types and attributes from oldFile from the project, and adds those from newFile.
/// </summary>
/// <remarks>
/// The update is done inside a write lock; when other threads access this project content
/// from within a <c>using (Synchronize())</c> block, they will not see intermediate (inconsistent) state.
/// </remarks>
- public void UpdateProjectContent(ICollection<ITypeDefinition> oldTypes = null,
- ICollection<ITypeDefinition> newTypes = null,
- ICollection<IAttribute> oldAssemblyAttributes = null,
- ICollection<IAttribute> newAssemblyAttributes = null)
+ public void UpdateProjectContent(IParsedFile oldFile, IParsedFile newFile)
{
+ if (oldFile != null && newFile != null) {
+ if (!Platform.FileNameComparer.Equals(oldFile.FileName, newFile.FileName))
+ throw new ArgumentException("When both oldFile and newFile are specified, they must use the same file name.");
+ }
readerWriterLock.EnterWriteLock();
try {
- if (oldTypes != null) {
- foreach (var element in oldTypes) {
+ if (oldFile != null) {
+ foreach (var element in oldFile.TopLevelTypeDefinitions) {
RemoveType(element);
}
+ if (newFile == null) {
+ fileDict.Remove(oldFile.FileName);
+ }
}
- if (newTypes != null) {
- foreach (var element in newTypes) {
+ if (newFile != null) {
+ foreach (var element in newFile.TopLevelTypeDefinitions) {
AddType(element);
}
+ fileDict[newFile.FileName] = newFile;
}
- AddRemoveAssemblyAttributes(oldAssemblyAttributes, newAssemblyAttributes);
+ AddRemoveAssemblyAttributes(oldFile != null ? oldFile.AssemblyAttributes : null, newFile != null ? newFile.AssemblyAttributes : null);
} finally {
readerWriterLock.ExitWriteLock();
}
@@ -164,6 +170,20 @@ public string GetNamespace(string nameSpace, StringComparer nameComparer)
readerWriterLock.ExitReadLock();
}
}
+
+ public IParsedFile GetFile(string fileName)
+ {
+ readerWriterLock.EnterReadLock();
+ try {
+ IParsedFile file;
+ if (fileDict.TryGetValue(fileName, out file))
+ return file;
+ else
+ return null;
+ } finally {
+ readerWriterLock.ExitReadLock();
+ }
+ }
#endregion
#region Synchronization
View
25 ICSharpCode.NRefactory/Utils/Platform.cs
@@ -0,0 +1,25 @@
+// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT license (for details please see \doc\license.txt)
+
+using System;
+
+namespace ICSharpCode.NRefactory.Utils
+{
+ /// <summary>
+ /// Platform-specific code.
+ /// </summary>
+ static class Platform
+ {
+ public static StringComparer FileNameComparer {
+ get {
+ switch (Environment.OSVersion.Platform) {
+ case PlatformID.Unix:
+ case PlatformID.MacOSX:
+ return StringComparer.Ordinal;
+ default:
+ return StringComparer.OrdinalIgnoreCase;
+ }
+ }
+ }
+ }
+}

0 comments on commit 94b4130

Please sign in to comment.
Something went wrong with that request. Please try again.