diff --git a/ICSharpCode.Editor/TextChangeEventArgs.cs b/ICSharpCode.Editor/TextChangeEventArgs.cs index cacf70aa09..a0320ace03 100644 --- a/ICSharpCode.Editor/TextChangeEventArgs.cs +++ b/ICSharpCode.Editor/TextChangeEventArgs.cs @@ -39,7 +39,7 @@ namespace ICSharpCode.Editor } /// - /// The text that was inserted. + /// The text that was removed. /// public string RemovedText { get { return removedText; } diff --git a/ICSharpCode.NRefactory.Demo/CSDemo.cs b/ICSharpCode.NRefactory.Demo/CSDemo.cs index ded7aeac74..a65040678a 100644 --- a/ICSharpCode.NRefactory.Demo/CSDemo.cs +++ b/ICSharpCode.NRefactory.Demo/CSDemo.cs @@ -282,10 +282,12 @@ namespace ICSharpCode.NRefactory.Demo FindReferences fr = new FindReferences(); int referenceCount = 0; - fr.ReferenceFound += delegate { referenceCount++; }; + FoundReferenceCallback callback = delegate(AstNode matchNode, ResolveResult result) { + referenceCount++; + }; var searchScopes = fr.GetSearchScopes(entity); - navigator = new CompositeResolveVisitorNavigator(searchScopes.ToArray()); + navigator = new CompositeResolveVisitorNavigator(searchScopes.Select(s => s.GetNavigator(callback)).ToArray()); visitor = new ResolveVisitor(resolver, parsedFile, navigator); visitor.Scan(compilationUnit); diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CompositeResolveVisitorNavigator.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CompositeResolveVisitorNavigator.cs index ec84362a91..4378267497 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/CompositeResolveVisitorNavigator.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/CompositeResolveVisitorNavigator.cs @@ -25,8 +25,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { IResolveVisitorNavigator[] navigators; - public CompositeResolveVisitorNavigator(IResolveVisitorNavigator[] navigators) + public CompositeResolveVisitorNavigator(params IResolveVisitorNavigator[] navigators) { + if (navigators == null) + throw new ArgumentNullException("navigators"); this.navigators = navigators; } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/FindReferenceSearchScope.cs b/ICSharpCode.NRefactory/CSharp/Resolver/FindReferenceSearchScope.cs new file mode 100644 index 0000000000..80cc8d7934 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Resolver/FindReferenceSearchScope.cs @@ -0,0 +1,51 @@ +// Copyright (c) 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 ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.Resolver +{ + /// + /// Represents a scope in which references are searched. + /// + public interface IFindReferenceSearchScope + { + /// + /// Gets the search term. Only files that contain this identifier need to be parsed. + /// Can return null if all files need to be parsed. + /// + string SearchTerm { get; } + + /// + /// Gets the accessibility that defines the search scope. + /// + Accessibility Accessibility { get; } + + /// + /// Gets the top-level entity that defines the search scope. + /// + ITypeDefinition TopLevelTypeDefinition { get; } + + /// + /// Creates a navigator that can find references to this entity and reports + /// them to the specified callback. + /// + IResolveVisitorNavigator GetNavigator(FoundReferenceCallback callback); + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/FindReferences.cs b/ICSharpCode.NRefactory/CSharp/Resolver/FindReferences.cs index b8d27e32fd..8773852fed 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/FindReferences.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/FindReferences.cs @@ -26,6 +26,8 @@ using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.CSharp.Resolver { + public delegate void FoundReferenceCallback(AstNode astNode, ResolveResult result); + /// /// 'Find references' implementation. /// @@ -36,21 +38,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// public sealed class FindReferences { - CancellationToken cancellationToken; - + #region Properties /// - /// Callback that is invoked whenever a reference is found. + /// Gets/Sets the cancellation token. /// - public event Action ReferenceFound; - - #region Constructor - public FindReferences(CancellationToken cancellationToken = default(CancellationToken)) - { - this.cancellationToken = cancellationToken; - } - #endregion + public CancellationToken CancellationToken { get; set; } - #region Properties /// /// Gets/Sets whether to find type references even if an alias is being used. /// @@ -104,28 +97,32 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region class SearchScope - public abstract class SearchScope : IResolveVisitorNavigator + abstract class SearchScope : IResolveVisitorNavigator, IFindReferenceSearchScope { protected string searchTerm; internal Accessibility accessibility; internal ITypeDefinition topLevelTypeDefinition; - internal FindReferences findReferences; - /// - /// Gets the search term. Only files that contain this identifier need to be parsed. - /// Can return null if all files need to be parsed. - /// - public string SearchTerm { get { return searchTerm; } } + FoundReferenceCallback callback; - /// - /// Gets the accessibility that defines the search scope. - /// - public Accessibility Accessibility { get { return accessibility; } } + IResolveVisitorNavigator IFindReferenceSearchScope.GetNavigator(FoundReferenceCallback callback) + { + SearchScope n = (SearchScope)MemberwiseClone(); + n.callback = callback; + return n; + } + + string IFindReferenceSearchScope.SearchTerm { + get { return searchTerm; } + } - /// - /// Gets the top-level entity that defines the search scope. - /// - public ITypeDefinition TopLevelTypeDefinition { get { return topLevelTypeDefinition; } } + Accessibility IFindReferenceSearchScope.Accessibility { + get { return accessibility; } + } + + ITypeDefinition IFindReferenceSearchScope.TopLevelTypeDefinition { + get { return topLevelTypeDefinition; } + } internal abstract bool CanMatch(AstNode node); internal abstract bool IsMatch(ResolveResult rr); @@ -156,15 +153,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver protected void ReportMatch(AstNode node, ResolveResult result) { - var referenceFound = findReferences.ReferenceFound; - if (referenceFound != null) - referenceFound(node, result); + if (callback != null) + callback(node, result); } } #endregion #region GetSearchScopes - public IList GetSearchScopes(IEntity entity) + public IList GetSearchScopes(IEntity entity) { if (entity == null) throw new ArgumentNullException("entity"); @@ -205,19 +201,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver additionalScope = new FindChainedConstructorReferences(ctor); break; case EntityType.Destructor: - return EmptyList.Instance; + return EmptyList.Instance; default: throw new ArgumentException("Unknown entity type " + entity.EntityType); } if (scope.accessibility == Accessibility.None) scope.accessibility = effectiveAccessibility; scope.topLevelTypeDefinition = topLevelTypeDefinition; - scope.findReferences = this; if (additionalScope != null) { if (additionalScope.accessibility == Accessibility.None) additionalScope.accessibility = effectiveAccessibility; additionalScope.topLevelTypeDefinition = topLevelTypeDefinition; - additionalScope.findReferences = this; return new[] { scope, additionalScope }; } else { return new[] { scope }; @@ -229,7 +223,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// /// Gets the file names that possibly contain references to the element being searched for. /// - public IEnumerable GetInterestingFileNames(SearchScope searchScope, ITypeResolveContext context) + public IList GetInterestingFileNames(IFindReferenceSearchScope searchScope, IEnumerable allTypes, ITypeResolveContext context) { IEnumerable interestingTypes; if (searchScope.TopLevelTypeDefinition != null) { @@ -239,41 +233,41 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver interestingTypes = new [] { searchScope.TopLevelTypeDefinition.GetDefinition() }; break; case Accessibility.Protected: - interestingTypes = GetInterestingTypesProtected(context, searchScope.TopLevelTypeDefinition); + interestingTypes = GetInterestingTypesProtected(allTypes, context, searchScope.TopLevelTypeDefinition); break; case Accessibility.Internal: - interestingTypes = GetInterestingTypesInternal(context, searchScope.TopLevelTypeDefinition.ProjectContent); + interestingTypes = GetInterestingTypesInternal(allTypes, context, searchScope.TopLevelTypeDefinition.ProjectContent); break; case Accessibility.ProtectedAndInternal: - interestingTypes = GetInterestingTypesProtected(context, searchScope.TopLevelTypeDefinition) - .Intersect(GetInterestingTypesInternal(context, searchScope.TopLevelTypeDefinition.ProjectContent)); + interestingTypes = GetInterestingTypesProtected(allTypes, context, searchScope.TopLevelTypeDefinition) + .Intersect(GetInterestingTypesInternal(allTypes, context, searchScope.TopLevelTypeDefinition.ProjectContent)); break; case Accessibility.ProtectedOrInternal: - interestingTypes = GetInterestingTypesProtected(context, searchScope.TopLevelTypeDefinition) - .Union(GetInterestingTypesInternal(context, searchScope.TopLevelTypeDefinition.ProjectContent)); + interestingTypes = GetInterestingTypesProtected(allTypes, context, searchScope.TopLevelTypeDefinition) + .Union(GetInterestingTypesInternal(allTypes, context, searchScope.TopLevelTypeDefinition.ProjectContent)); break; default: - interestingTypes = context.GetTypes(); + interestingTypes = allTypes; break; } } else { - interestingTypes = context.GetTypes(); + interestingTypes = allTypes; } return (from typeDef in interestingTypes from part in typeDef.GetParts() where part.ParsedFile != null select part.ParsedFile.FileName - ).Distinct(Platform.FileNameComparer); + ).Distinct(Platform.FileNameComparer).ToList(); } - IEnumerable GetInterestingTypesProtected(ITypeResolveContext context, ITypeDefinition referencedTypeDefinition) + IEnumerable GetInterestingTypesProtected(IEnumerable allTypes, ITypeResolveContext context, ITypeDefinition referencedTypeDefinition) { - return referencedTypeDefinition.GetSubTypeDefinitions(context); + return allTypes.Where(t => t.IsDerivedFrom(referencedTypeDefinition, context)); } - IEnumerable GetInterestingTypesInternal(ITypeResolveContext context, IProjectContent referencedProjectContent) + IEnumerable GetInterestingTypesInternal(IEnumerable allTypes, ITypeResolveContext context, IProjectContent referencedProjectContent) { - return context.GetTypes().Where(t => referencedProjectContent.InternalsVisibleTo(t.ProjectContent, context)); + return allTypes.Where(t => referencedProjectContent.InternalsVisibleTo(t.ProjectContent, context)); } #endregion @@ -285,11 +279,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// The type system representation of the file being searched. /// The compilation unit of the file being searched. /// The type resolve context to use for resolving the file. - public void FindReferencesInFile(SearchScope searchScope, CSharpParsedFile parsedFile, CompilationUnit compilationUnit, ITypeResolveContext context) + /// Callback used to report the references that were found. + public void FindReferencesInFile(IFindReferenceSearchScope searchScope, CSharpParsedFile parsedFile, CompilationUnit compilationUnit, + ITypeResolveContext context, FoundReferenceCallback callback) { if (searchScope == null) throw new ArgumentNullException("searchScope"); - FindReferencesInFile(new[] { searchScope }, parsedFile, compilationUnit, context); + FindReferencesInFile(new[] { searchScope }, parsedFile, compilationUnit, context, callback); } /// @@ -299,7 +295,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// The type system representation of the file being searched. /// The compilation unit of the file being searched. /// The type resolve context to use for resolving the file. - public void FindReferencesInFile(IList searchScopes, CSharpParsedFile parsedFile, CompilationUnit compilationUnit, ITypeResolveContext context) + /// Callback used to report the references that were found. + public void FindReferencesInFile(IList searchScopes, CSharpParsedFile parsedFile, CompilationUnit compilationUnit, + ITypeResolveContext context, FoundReferenceCallback callback) { if (searchScopes == null) throw new ArgumentNullException("searchScopes"); @@ -309,21 +307,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver throw new ArgumentNullException("compilationUnit"); if (context == null) throw new ArgumentNullException("context"); - cancellationToken.ThrowIfCancellationRequested(); + this.CancellationToken.ThrowIfCancellationRequested(); if (searchScopes.Count == 0) return; - foreach (SearchScope scope in searchScopes) { - if (scope.findReferences != this) - throw new ArgumentException("Cannot use a search scope that was created by another FindReferences instance"); - } using (var ctx = context.Synchronize()) { IResolveVisitorNavigator navigator; if (searchScopes.Count == 1) - navigator = searchScopes[0]; + navigator = searchScopes[0].GetNavigator(callback); else - navigator = new CompositeResolveVisitorNavigator(searchScopes.ToArray()); + navigator = new CompositeResolveVisitorNavigator(searchScopes.Select(s => s.GetNavigator(callback)).ToArray()); navigator = new DetectSkippableNodesNavigator(navigator, compilationUnit); - CSharpResolver resolver = new CSharpResolver(ctx, cancellationToken); + CSharpResolver resolver = new CSharpResolver(ctx, this.CancellationToken); ResolveVisitor v = new ResolveVisitor(resolver, parsedFile, navigator); v.Scan(compilationUnit); } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/LocalResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/LocalResolveResult.cs index ef056230f9..57779ab2a6 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/LocalResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/LocalResolveResult.cs @@ -68,5 +68,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { return string.Format("[LocalResolveResult {0}]", variable); } + + public override DomRegion GetDefinitionRegion() + { + return variable.Region; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs index baaf504d7d..b47b4764c0 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/MemberResolveResult.cs @@ -92,5 +92,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { return string.Format("[{0} {1}]", GetType().Name, member); } + + public override DomRegion GetDefinitionRegion() + { + return member.Region; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveAtLocation.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveAtLocation.cs index 3b003e4882..d32f45cf5e 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveAtLocation.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveAtLocation.cs @@ -32,6 +32,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver CancellationToken cancellationToken = default(CancellationToken)) { AstNode node = cu.GetNodeAt(location); + if (node == null) + return null; AstNode resolvableNode; if (node is Identifier) { resolvableNode = node.Parent; diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveResult.cs index 9f31e05720..40a9931e69 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveResult.cs @@ -63,5 +63,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { return Enumerable.Empty(); } + + public virtual DomRegion GetDefinitionRegion() + { + return DomRegion.Empty; + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/TypeResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/TypeResolveResult.cs index 1336357ba6..79815d6565 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/TypeResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/TypeResolveResult.cs @@ -30,5 +30,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver : base(type) { } + + public override DomRegion GetDefinitionRegion() + { + ITypeDefinition def = this.Type.GetDefinition(); + if (def != null) + return def.Region; + else + return DomRegion.Empty; + } } } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 5d0087768b..4d7ea32385 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -104,6 +104,7 @@ + diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs index 6b10615b5f..0189d3cca1 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs @@ -38,7 +38,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public class SimpleProjectContent : AbstractAnnotatable, IProjectContent, ISerializable, IDeserializationCallback { readonly TypeStorage types = new TypeStorage(); - readonly ReaderWriterLockSlim readerWriterLock = new ReaderWriterLockSlim(); + readonly ReaderWriterLockSlim readerWriterLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); readonly Dictionary fileDict = new Dictionary(Platform.FileNameComparer); #region Constructor